97 lines
3.3 KiB
TypeScript
97 lines
3.3 KiB
TypeScript
import { describe, expect, it, beforeAll, afterAll } from "vitest";
|
|
import { eq, inArray } from "drizzle-orm";
|
|
import {
|
|
createDatabase,
|
|
closeDatabase,
|
|
markMilestone,
|
|
getActivationState,
|
|
schema,
|
|
} from "@app/database";
|
|
|
|
describe("activation", () => {
|
|
const { db } = createDatabase();
|
|
const emails = ["act-test-1@example.invalid", "act-test-2@example.invalid"];
|
|
const inviteCodes = ["ACT123", "ACT223"];
|
|
|
|
async function cleanup() {
|
|
await db
|
|
.delete(schema.householdMembers)
|
|
.where(
|
|
inArray(
|
|
schema.householdMembers.householdId,
|
|
db
|
|
.select({ id: schema.households.id })
|
|
.from(schema.households)
|
|
.where(inArray(schema.households.inviteCode, inviteCodes)),
|
|
),
|
|
);
|
|
await db.delete(schema.households).where(inArray(schema.households.inviteCode, inviteCodes));
|
|
await db.delete(schema.users).where(inArray(schema.users.email, emails));
|
|
}
|
|
|
|
beforeAll(cleanup);
|
|
afterAll(async () => {
|
|
await cleanup();
|
|
await closeDatabase();
|
|
});
|
|
|
|
it("marks first scan and activates household", async () => {
|
|
const [user] = await db
|
|
.insert(schema.users)
|
|
.values({ email: emails[0]!, displayName: "Act" })
|
|
.returning();
|
|
const [household] = await db
|
|
.insert(schema.households)
|
|
.values({ name: "Act family", inviteCode: inviteCodes[0]! })
|
|
.returning();
|
|
await db.insert(schema.householdMembers).values({
|
|
householdId: household.id,
|
|
userId: user.id,
|
|
role: "owner",
|
|
});
|
|
|
|
const r1 = await markMilestone(db, household.id, "firstScanCompletedAt");
|
|
expect(r1.wasNew).toBe(true);
|
|
expect(r1.activatedNow).toBe(false);
|
|
|
|
await markMilestone(db, household.id, "fifthItemConfirmedAt");
|
|
await markMilestone(db, household.id, "firstRecipeRecommendationViewedAt");
|
|
const r2 = await markMilestone(db, household.id, "firstRecipeSavedOrStartedAt");
|
|
expect(r2.activatedNow).toBe(true);
|
|
|
|
const state = await getActivationState(db, household.id);
|
|
expect(state.activatedAt).not.toBeNull();
|
|
expect(state.valueConfirmedAt).toBeNull();
|
|
|
|
await markMilestone(db, household.id, "firstCookingSessionCompletedAt");
|
|
const r3 = await markMilestone(db, household.id, "inventoryUpdatedAfterCookingAt");
|
|
expect(r3.valueConfirmedNow).toBe(true);
|
|
|
|
const state2 = await getActivationState(db, household.id);
|
|
expect(state2.valueConfirmedAt).not.toBeNull();
|
|
});
|
|
|
|
it("idempotent: does not move timestamps backward", async () => {
|
|
const [user] = await db
|
|
.insert(schema.users)
|
|
.values({ email: emails[1]!, displayName: "Act2" })
|
|
.returning();
|
|
const [household] = await db
|
|
.insert(schema.households)
|
|
.values({ name: "Act2 family", inviteCode: inviteCodes[1]! })
|
|
.returning();
|
|
await db.insert(schema.householdMembers).values({
|
|
householdId: household.id,
|
|
userId: user.id,
|
|
role: "owner",
|
|
});
|
|
|
|
await markMilestone(db, household.id, "firstScanCompletedAt");
|
|
const state1 = await getActivationState(db, household.id);
|
|
await new Promise((r) => setTimeout(r, 20));
|
|
await markMilestone(db, household.id, "firstScanCompletedAt");
|
|
const state2 = await getActivationState(db, household.id);
|
|
expect(state2.firstScanCompletedAt?.getTime()).toBe(state1.firstScanCompletedAt?.getTime());
|
|
});
|
|
});
|