Extract onboarding flow step resolution and async runner logic into a dedicated module for better separation of concerns and maintainability. Refactor context/provider to use new helpers and simplify settings modal control. Add unit tests for onboarding step resolution and async runner coalescing. Update e2e helpers and selectors for onboarding modals. Adjust environment file handling for CI and Docker contexts. - Add .dockerignore for build hygiene - Refactor onboarding context and modal logic - Add src/lib/client/onboarding-flow.ts with core onboarding helpers - Add onboarding-flow unit tests - Update Playwright config and scripts for CI env loading - Improve test selectors for claim modal - Update .gitignore to exclude all .env* except .env.example This change increases onboarding logic modularity and reliability, and improves CI/test environment handling.
107 lines
2.7 KiB
TypeScript
107 lines
2.7 KiB
TypeScript
import { expect, test } from '@playwright/test';
|
|
|
|
import { createCoalescedAsyncRunner, resolveNextOnboardingStep } from '../../src/lib/client/onboarding-flow';
|
|
|
|
test.describe('onboarding flow resolver', () => {
|
|
test('resolves deterministic order with privacy first', () => {
|
|
const step = resolveNextOnboardingStep({
|
|
privacyRequired: true,
|
|
privacyAccepted: false,
|
|
claimEligible: true,
|
|
claimHasData: true,
|
|
migrationRequired: true,
|
|
changelogPending: true,
|
|
});
|
|
|
|
expect(step).toBe('privacy');
|
|
});
|
|
|
|
test('resolves claim after privacy is accepted', () => {
|
|
const step = resolveNextOnboardingStep({
|
|
privacyRequired: true,
|
|
privacyAccepted: true,
|
|
claimEligible: true,
|
|
claimHasData: true,
|
|
migrationRequired: true,
|
|
changelogPending: true,
|
|
});
|
|
|
|
expect(step).toBe('claim');
|
|
});
|
|
|
|
test('resolves migration when no claim is needed', () => {
|
|
const step = resolveNextOnboardingStep({
|
|
privacyRequired: true,
|
|
privacyAccepted: true,
|
|
claimEligible: true,
|
|
claimHasData: false,
|
|
migrationRequired: true,
|
|
changelogPending: true,
|
|
});
|
|
|
|
expect(step).toBe('migration');
|
|
});
|
|
|
|
test('resolves changelog when prior steps are clear', () => {
|
|
const step = resolveNextOnboardingStep({
|
|
privacyRequired: true,
|
|
privacyAccepted: true,
|
|
claimEligible: true,
|
|
claimHasData: false,
|
|
migrationRequired: false,
|
|
changelogPending: true,
|
|
});
|
|
|
|
expect(step).toBe('changelog');
|
|
});
|
|
|
|
test('resolves done when no steps are pending (auth and no-auth parity)', () => {
|
|
const authStep = resolveNextOnboardingStep({
|
|
privacyRequired: true,
|
|
privacyAccepted: true,
|
|
claimEligible: true,
|
|
claimHasData: false,
|
|
migrationRequired: false,
|
|
changelogPending: false,
|
|
});
|
|
const noAuthStep = resolveNextOnboardingStep({
|
|
privacyRequired: false,
|
|
privacyAccepted: false,
|
|
claimEligible: false,
|
|
claimHasData: false,
|
|
migrationRequired: false,
|
|
changelogPending: false,
|
|
});
|
|
|
|
expect(authStep).toBe('done');
|
|
expect(noAuthStep).toBe('done');
|
|
});
|
|
});
|
|
|
|
test.describe('coalesced onboarding runner', () => {
|
|
test('coalesces concurrent triggers into one extra rerun', async () => {
|
|
let runs = 0;
|
|
let nestedRequested = false;
|
|
|
|
const run = createCoalescedAsyncRunner(async () => {
|
|
runs += 1;
|
|
if (!nestedRequested) {
|
|
nestedRequested = true;
|
|
await run();
|
|
}
|
|
});
|
|
|
|
await run();
|
|
expect(runs).toBe(2);
|
|
});
|
|
|
|
test('does not rerun when no trigger arrives during execution', async () => {
|
|
let runs = 0;
|
|
const run = createCoalescedAsyncRunner(async () => {
|
|
runs += 1;
|
|
});
|
|
|
|
await run();
|
|
expect(runs).toBe(1);
|
|
});
|
|
});
|