115 lines
3.5 KiB
TypeScript
115 lines
3.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import {
|
|
completedAtFromOnboardingPayload,
|
|
isValidOnboardingLedgerEvent,
|
|
normalizeOnboardingEventType,
|
|
} from "../src/events/onboarding-ledger.js";
|
|
|
|
const now = "2026-06-28T00:00:00.000Z";
|
|
|
|
assert.equal(normalizeOnboardingEventType("user_onboarding_completed"), "user.onboarding.completed");
|
|
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({
|
|
type: "onboarding.completed",
|
|
payload: {},
|
|
}),
|
|
true,
|
|
"explicit completion event should satisfy onboarding status",
|
|
);
|
|
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({
|
|
type: "user.onboarding.completed",
|
|
payload: {},
|
|
}),
|
|
true,
|
|
"user completion event should satisfy onboarding status",
|
|
);
|
|
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({
|
|
type: "profile.onboarding.completed",
|
|
payload: {},
|
|
}),
|
|
true,
|
|
"profile completion event should satisfy onboarding status",
|
|
);
|
|
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({
|
|
type: "onboarding.snapshot.saved",
|
|
payload: { onboarding: { current_step: 2 } },
|
|
}),
|
|
false,
|
|
"intermediate snapshots must not bypass onboarding",
|
|
);
|
|
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({
|
|
type: "onboarding.snapshot.saved",
|
|
payload: { onboarding: { completed_at: now } },
|
|
}),
|
|
true,
|
|
"completion snapshots should satisfy onboarding status",
|
|
);
|
|
|
|
assert.equal(
|
|
completedAtFromOnboardingPayload({
|
|
preferences: { onboarding: { completed_at: now } },
|
|
}),
|
|
now,
|
|
"completion timestamp should be extracted from preferences snapshot",
|
|
);
|
|
|
|
assert.equal(
|
|
completedAtFromOnboardingPayload({
|
|
completedAt: "not-a-date",
|
|
})?.endsWith("Z"),
|
|
true,
|
|
"invalid completion timestamps should normalize to a valid ISO timestamp",
|
|
);
|
|
|
|
// ── Regression: underscore completion aliases must be valid (reset deletes them) ──
|
|
// The reset only reopens the gate if EVERY alias form that isValidOnboardingLedgerEvent
|
|
// accepts is also in the reset delete scope. Pin both sides agree per alias.
|
|
for (const underscore of ["onboarding_completed", "user_onboarding_completed", "profile_onboarding_completed"]) {
|
|
const dotted = normalizeOnboardingEventType(underscore);
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({ type: underscore, payload: {} }),
|
|
true,
|
|
`${underscore} should satisfy onboarding status (normalized to ${dotted})`,
|
|
);
|
|
}
|
|
|
|
// ── Regression: completedAtFromOnboardingPayload paths mirrored by reset SQL ──
|
|
// resetOnboardingLedger's jsonb predicate checks top-level completed_at/completedAt
|
|
// and onboarding.completed_at/completedAt. Pin that the JS helper (used for status
|
|
// validity) agrees a snapshot carrying any of these is a completion snapshot.
|
|
for (const [label, payload] of [
|
|
["top-level completed_at", { completed_at: now }],
|
|
["top-level completedAt", { completedAt: now }],
|
|
["onboarding.completed_at", { onboarding: { completed_at: now } }],
|
|
["onboarding.completedAt", { onboarding: { completedAt: now } }],
|
|
] as const) {
|
|
assert.equal(
|
|
completedAtFromOnboardingPayload(payload),
|
|
now,
|
|
`completion timestamp extracted from ${label}`,
|
|
);
|
|
assert.equal(
|
|
isValidOnboardingLedgerEvent({ type: "onboarding.snapshot.saved", payload }),
|
|
true,
|
|
`snapshot with ${label} is a completion snapshot`,
|
|
);
|
|
}
|
|
|
|
// ── Regression: intermediate snapshots (no completion marker) stay invalid ──
|
|
assert.equal(
|
|
completedAtFromOnboardingPayload({ onboarding: { current_step: 2 } }),
|
|
undefined,
|
|
"intermediate snapshot has no completion timestamp",
|
|
);
|
|
console.log("onboarding-ledger tests passed");
|
|
process.exit(0);
|