Fas 1b punkt 6: First Scan Coach + aktiveringsmätning
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
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());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user