141 lines
4.4 KiB
TypeScript
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),
|
|
}),
|
|
});
|
|
});
|
|
});
|