79 lines
2.6 KiB
JavaScript
79 lines
2.6 KiB
JavaScript
import { QueryClient } from "@tanstack/react-query";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import {
|
|
createQueryCacheAdapter,
|
|
createQueryClient,
|
|
} from "../../src/adapters/query-cache/tanstack-query-cache.js";
|
|
import { canonicalize } from "../../src/contracts/query-keys.js";
|
|
|
|
const queryKeys = Object.freeze({
|
|
all: () => Object.freeze(["entity", 1]),
|
|
list: (filters = {}) =>
|
|
Object.freeze(["entity", 1, "list", canonicalize(filters)]),
|
|
/** @param {string} entityId */
|
|
detail: (entityId) =>
|
|
Object.freeze(["entity", 1, "detail", String(entityId)]),
|
|
});
|
|
|
|
describe("query key registry", () => {
|
|
it("canonicalizes filter order into the same stable key", () => {
|
|
expect(queryKeys.list({ page: 1, status: "open" })).toEqual(
|
|
queryKeys.list({ status: "open", page: 1 }),
|
|
);
|
|
});
|
|
|
|
it("contains no raw URL or token material", () => {
|
|
expect(JSON.stringify(queryKeys.detail("entity-1"))).toBe(
|
|
'["entity",1,"detail","entity-1"]',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("TanStack QueryCachePort adapter", () => {
|
|
it("reads, writes, and invalidates only the declared namespace", async () => {
|
|
const client = createQueryClient();
|
|
const adapter = createQueryCacheAdapter(client);
|
|
const listKey = queryKeys.list({ page: 1 });
|
|
const otherKey = ["other", 1];
|
|
|
|
expect(adapter.write(listKey, [{ id: "resource-1" }])).toEqual({ ok: true });
|
|
expect(adapter.write(otherKey, "preserved")).toEqual({ ok: true });
|
|
expect(adapter.read(listKey)).toMatchObject({
|
|
ok: true,
|
|
value: [{ id: "resource-1" }],
|
|
});
|
|
|
|
await adapter.invalidate(queryKeys.all());
|
|
expect(client.getQueryState(listKey)?.isInvalidated).toBe(true);
|
|
expect(client.getQueryState(otherKey)?.isInvalidated).toBe(false);
|
|
});
|
|
|
|
it("normalizes adapter exceptions without raw key data", async () => {
|
|
const client = new QueryClient();
|
|
vi.spyOn(client, "invalidateQueries").mockRejectedValue(new Error("secret-key"));
|
|
const record = vi.fn();
|
|
const adapter = createQueryCacheAdapter(client, {
|
|
diagnostics: { record },
|
|
});
|
|
const result = await adapter.invalidate(["resource", "sensitive-filter"]);
|
|
|
|
expect(result).toMatchObject({
|
|
ok: false,
|
|
error: { kind: "QUERY_CACHE_FAILURE" },
|
|
});
|
|
expect(JSON.stringify(result)).not.toContain("sensitive-filter");
|
|
expect(record).toHaveBeenCalledWith({
|
|
level: "warn",
|
|
eventId: "cache.operation.failed",
|
|
context: {
|
|
operation: "invalidate",
|
|
error_kind: "QUERY_CACHE_FAILURE",
|
|
},
|
|
});
|
|
expect(JSON.stringify(record.mock.calls)).not.toMatch(
|
|
/sensitive-filter|secret-key/,
|
|
);
|
|
});
|
|
});
|