73 lines
3.1 KiB
TypeScript
73 lines
3.1 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import { ONBOARDING_STORAGE_KEY } from "@/components/OnboardingWizard";
|
|
import {
|
|
ONBOARDING_ARC_ENTRY_STEP,
|
|
STORYBOOK_COMPANY_ID,
|
|
clearOnboardingDraft,
|
|
readOnboardingDraft,
|
|
seedOnboardingDraft,
|
|
} from "./onboardingDraft";
|
|
|
|
afterEach(() => {
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
describe("storybook onboarding draft", () => {
|
|
// The leak this exists to stop: `localStorage` is per-origin and shared by
|
|
// every story in a session, so a seeded draft left behind makes the *next*
|
|
// story restore a saved step instead of the one it asked for. The reviewer
|
|
// then sees a screen they did not click on, which reads as a wizard bug.
|
|
it("leaves nothing behind once cleared", () => {
|
|
seedOnboardingDraft();
|
|
expect(readOnboardingDraft()).not.toBeNull();
|
|
|
|
clearOnboardingDraft();
|
|
expect(readOnboardingDraft()).toBeNull();
|
|
expect(window.localStorage.getItem(ONBOARDING_STORAGE_KEY)).toBeNull();
|
|
});
|
|
|
|
// The wizard captures `entryStep` from this draft once, at mount, and offers
|
|
// Back only while `currentStep > entryStep`. Seeding a later step is therefore
|
|
// not a shortcut to it — it is a step that can never show its Back button.
|
|
it("enters the arc at its first step, so later steps can be walked into", () => {
|
|
seedOnboardingDraft();
|
|
expect(readOnboardingDraft()?.step).toBe(ONBOARDING_ARC_ENTRY_STEP);
|
|
});
|
|
|
|
// `createdAgentId` is what `launchStateIncomplete` checks. Filling it in
|
|
// before the hire would paint over the guard step 5 is supposed to show when
|
|
// it is reached without an agent.
|
|
it("does not claim an agent exists before the hire", () => {
|
|
seedOnboardingDraft();
|
|
expect(readOnboardingDraft()?.createdAgentId).toBe("");
|
|
});
|
|
|
|
// A run standing on step 3 has not reached the connect step, so it cannot
|
|
// have chosen a source there. Seeding one is not a harmless head start: the
|
|
// step reads a saved `adapterType` as "already picked", and every arc story
|
|
// opened with Claude Code selected and its sign-in panel already showing —
|
|
// the preselection the step was changed to stop doing, restored by the
|
|
// fixture. Stories that need a source click one, the way a customer does.
|
|
it("does not claim a model source was chosen before the connect step", () => {
|
|
seedOnboardingDraft();
|
|
expect(readOnboardingDraft()).not.toHaveProperty("adapterType");
|
|
});
|
|
|
|
// `restoreOnboardingState` treats restoring as an authorization decision and
|
|
// throws the whole blob away when the saved company is not one the account
|
|
// owns. Seeding a company the fixtures do not report would silently restore
|
|
// nothing, and every story would quietly fall back to its `initialStep`.
|
|
it("names the company the fixtures report as owned", () => {
|
|
seedOnboardingDraft();
|
|
expect(readOnboardingDraft()?.createdCompanyId).toBe(STORYBOOK_COMPANY_ID);
|
|
});
|
|
|
|
it("survives a malformed value without throwing", () => {
|
|
window.localStorage.setItem(ONBOARDING_STORAGE_KEY, "{not json");
|
|
expect(readOnboardingDraft()).toBeNull();
|
|
});
|
|
});
|