Files
Epicnabbo-Catalogus-Updated…/src/features/housekeeping/foundation/preferences/repository.test.ts
T

141 lines
4.4 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
const drizzleMocks = vi.hoisted(() => ({
eq: vi.fn((column: unknown, value: unknown) => ({ column, value })),
}));
vi.mock("drizzle-orm", async (importOriginal) => ({
...(await importOriginal<typeof import("drizzle-orm")>()),
eq: drizzleMocks.eq,
}));
import { HousekeepingUserPreferences } from "@/lib/db";
import { createDrizzleHousekeepingPreferencesStorage } from "@/lib/housekeeping-preferences-repository";
import {
createHousekeepingPreferencesRepository,
type HousekeepingPreferencesStorage,
} from "./repository";
import { defaultHousekeepingPreferences } from "./schema";
describe("housekeeping preferences repository", () => {
it("returns a fresh default when no row exists", async () => {
const storage: HousekeepingPreferencesStorage = {
findByUserId: vi.fn().mockResolvedValue(null),
upsert: vi.fn(),
};
const repository = createHousekeepingPreferencesRepository(storage);
expect(await repository.read(42)).toEqual(defaultHousekeepingPreferences());
expect(storage.findByUserId).toHaveBeenCalledWith(42);
});
it("reads validated JSON and writes the schema-versioned payload through the injected adapter", async () => {
const value = {
...defaultHousekeepingPreferences(),
pinnedRouteIds: ["people.users"],
};
const storage: HousekeepingPreferencesStorage = {
findByUserId: vi.fn().mockResolvedValue({
schemaVersion: 1,
payload: JSON.stringify(value),
}),
upsert: vi.fn(),
};
const repository = createHousekeepingPreferencesRepository(storage);
expect(await repository.read(42)).toEqual(value);
await repository.upsert(42, value);
expect(storage.upsert).toHaveBeenCalledWith({
userId: 42,
schemaVersion: 1,
payload: JSON.stringify(value),
});
});
it("returns a fresh default for malformed or incompatible stored values", async () => {
const storage: HousekeepingPreferencesStorage = {
findByUserId: vi
.fn()
.mockResolvedValueOnce({ schemaVersion: 1, payload: "{broken" })
.mockResolvedValueOnce({ schemaVersion: 2, payload: "{}" })
.mockResolvedValueOnce({
schemaVersion: 1,
payload: JSON.stringify({ schemaVersion: 1 }),
}),
upsert: vi.fn(),
};
const repository = createHousekeepingPreferencesRepository(storage);
await expect(repository.read(42)).resolves.toEqual(
defaultHousekeepingPreferences(),
);
await expect(repository.read(42)).resolves.toEqual(
defaultHousekeepingPreferences(),
);
await expect(repository.read(42)).resolves.toEqual(
defaultHousekeepingPreferences(),
);
});
it("preserves genuine storage failures instead of treating them as corrupt preferences", async () => {
const storage: HousekeepingPreferencesStorage = {
findByUserId: vi
.fn()
.mockRejectedValue(new Error("database unavailable")),
upsert: vi.fn(),
};
await expect(
createHousekeepingPreferencesRepository(storage).read(42),
).rejects.toThrow("database unavailable");
});
it("uses the preferences table and user ID for the typed Drizzle read and upsert", async () => {
const limit = vi.fn().mockResolvedValue([]);
const where = vi.fn().mockReturnValue({ limit });
const from = vi.fn().mockReturnValue({ where });
const select = vi.fn().mockReturnValue({ from });
const onDuplicateKeyUpdate = vi.fn().mockResolvedValue(undefined);
const values = vi.fn().mockReturnValue({ onDuplicateKeyUpdate });
const insert = vi.fn().mockReturnValue({ values });
const storage = createDrizzleHousekeepingPreferencesStorage({
select,
insert,
} as never);
const value = defaultHousekeepingPreferences();
await storage.findByUserId(42);
await storage.upsert({
userId: 42,
schemaVersion: 1,
payload: JSON.stringify(value),
});
expect(select).toHaveBeenCalledWith({
schemaVersion: HousekeepingUserPreferences.schemaVersion,
payload: HousekeepingUserPreferences.payload,
});
expect(from).toHaveBeenCalledWith(HousekeepingUserPreferences);
expect(drizzleMocks.eq).toHaveBeenCalledWith(
HousekeepingUserPreferences.userId,
42,
);
expect(where).toHaveBeenCalledWith({
column: HousekeepingUserPreferences.userId,
value: 42,
});
expect(values).toHaveBeenCalledWith({
userId: 42,
schemaVersion: 1,
payload: JSON.stringify(value),
});
expect(onDuplicateKeyUpdate).toHaveBeenCalledWith({
set: expect.objectContaining({
schemaVersion: 1,
payload: JSON.stringify(value),
updatedAt: expect.any(Date),
}),
});
});
});