FAS 1b: Progressive onboarding (3-layer flow)
- Add PROGRESSIVE_ONBOARDING feature flag to KNOWN_FLAGS - Add onboarding_step column to users table (a/b/c) - New backend endpoints: - GET /v1/onboarding/status – check current step + feature flag - POST /v1/onboarding/quick-start – complete Step A (goal + precision) - POST /v1/onboarding/complete-b – complete Step B (diet, allergens, household) - POST /v1/onboarding/complete-c – complete Step C (health profile) - POST /v1/onboarding/skip – GDPR-friendly skip - Refactor mobile onboarding screen into 3 progressive layers - Update auth store with onboardingStep state - Update tab layout to only block on Step A - Update registration to set onboardingStep='a' - Add i18n keys for Step B/C titles across all 12 locales - Add Zod validation schemas (quickStartInputSchema, onboardingStatusSchema) - Add tests for validation and feature flag - Preserve existing /v1/me/onboarding for backward compatibility - Migration: 0004_progressive_onboarding.sql
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { quickStartInputSchema, onboardingStatusSchema } from "@app/validation";
|
||||
import { parse, ApiError } from "../src/lib/errors.js";
|
||||
|
||||
describe("progressive onboarding validering (FAS 1b)", () => {
|
||||
it("quick-start accepterar mål och precision", () => {
|
||||
const result = parse(quickStartInputSchema, {
|
||||
primaryGoal: "lose_weight",
|
||||
precisionMode: "exact",
|
||||
});
|
||||
expect(result.primaryGoal).toBe("lose_weight");
|
||||
expect(result.precisionMode).toBe("exact");
|
||||
});
|
||||
|
||||
it("quick-start är valfri – endast precision får default", () => {
|
||||
const result = parse(quickStartInputSchema, {});
|
||||
expect(result.primaryGoal).toBeUndefined();
|
||||
expect(result.precisionMode).toBe("simple");
|
||||
});
|
||||
|
||||
it("quick-start avvisar ogiltigt mål", () => {
|
||||
expect(() =>
|
||||
parse(quickStartInputSchema, { primaryGoal: "invalid_goal" }),
|
||||
).toThrowError(ApiError);
|
||||
});
|
||||
|
||||
it("quick-start avvisar ogiltig precision", () => {
|
||||
expect(() =>
|
||||
parse(quickStartInputSchema, { precisionMode: "medium" }),
|
||||
).toThrowError(ApiError);
|
||||
});
|
||||
|
||||
it("onboarding-status schema validerar korrekt struktur", () => {
|
||||
const valid = {
|
||||
step: "b",
|
||||
onboardingCompleted: false,
|
||||
hasHousehold: true,
|
||||
hasHealthProfile: false,
|
||||
hasPreferences: true,
|
||||
};
|
||||
const result = parse(onboardingStatusSchema, valid);
|
||||
expect(result.step).toBe("b");
|
||||
expect(result.hasHousehold).toBe(true);
|
||||
});
|
||||
|
||||
it("onboarding-status avvisar ogiltig steg", () => {
|
||||
expect(() =>
|
||||
parse(onboardingStatusSchema, {
|
||||
step: "d",
|
||||
onboardingCompleted: false,
|
||||
hasHousehold: false,
|
||||
hasHealthProfile: false,
|
||||
hasPreferences: false,
|
||||
}),
|
||||
).toThrowError(ApiError);
|
||||
});
|
||||
});
|
||||
|
||||
describe("progressive onboarding feature flag", () => {
|
||||
it("PROGRESSIVE_ONBOARDING finns i KNOWN_FLAGS", async () => {
|
||||
const { KNOWN_FLAGS } = await import("@app/feature-flags");
|
||||
expect(KNOWN_FLAGS.PROGRESSIVE_ONBOARDING).toBe("progressive_onboarding");
|
||||
});
|
||||
|
||||
it("bucketFor ger stabil hash 0–99", async () => {
|
||||
const { bucketFor } = await import("@app/feature-flags");
|
||||
const b1 = bucketFor("progressive_onboarding", "user-123");
|
||||
const b2 = bucketFor("progressive_onboarding", "user-123");
|
||||
expect(b1).toBe(b2);
|
||||
expect(b1).toBeGreaterThanOrEqual(0);
|
||||
expect(b1).toBeLessThan(100);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user