--- phase: 03-wizard-ui plan: "01" type: execute wave: 1 depends_on: [] files_modified: - vite.config.ts - src/App.test.tsx - src/components/wizard/BackendSelectionStep.test.tsx - src/components/wizard/RemoteConfigStep.test.tsx - src/components/wizard/StepIndicator.test.tsx autonomous: true requirements: - WIZD-01 - WIZD-02 - WIZD-03 - WIZD-04 - BACK-01 - BACK-02 - BACK-03 must_haves: truths: - "Vitest runs React component tests without 'document is not defined' errors" - "All four test stub files exist and fail RED with descriptive 'not yet implemented' messages" - "npx vitest run exits non-zero (tests fail) confirming stubs are RED" artifacts: - path: "vite.config.ts" provides: "jsdom test environment config" contains: "test: { environment: 'jsdom'" - path: "src/App.test.tsx" provides: "Wave 0 stub for WIZD-02 step routing" - path: "src/components/wizard/BackendSelectionStep.test.tsx" provides: "Wave 0 stubs for WIZD-01, WIZD-04" - path: "src/components/wizard/RemoteConfigStep.test.tsx" provides: "Wave 0 stubs for BACK-01, BACK-02, BACK-03" - path: "src/components/wizard/StepIndicator.test.tsx" provides: "Wave 0 stubs for WIZD-03" key_links: - from: "vite.config.ts" to: "src/**/*.test.tsx" via: "test.environment: 'jsdom'" pattern: "environment.*jsdom" --- Set up the Wave 0 test infrastructure: configure Vitest for jsdom component testing and create failing test stubs for all Phase 3 wizard components. Purpose: Establish the RED baseline before implementation — tests must fail in a descriptive way so Plans 03–05 can drive to GREEN. Output: Updated vite.config.ts and four test stub files. @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-wizard-ui/03-CONTEXT.md @.planning/phases/03-wizard-ui/03-RESEARCH.md @.planning/phases/03-wizard-ui/03-VALIDATION.md From src/store/types.ts: ```typescript export interface WizardState { currentStep: number; remote: { name: string; backendType: BackendType | null; params: Record; }; deployment: { includeInstall: boolean; configPath: 'machine-wide' | 'user-profile'; scriptTargets: ('intune' | 'rmm')[]; }; } export type WizardAction = | { type: 'SET_STEP'; payload: number } | { type: 'SET_BACKEND_TYPE'; payload: BackendType } | { type: 'SET_REMOTE_NAME'; payload: string } | { type: 'SET_REMOTE_PARAMS'; payload: Record } | { type: 'SET_DEPLOYMENT'; payload: Partial } | { type: 'RESET' }; ``` From src/schemas/registry.ts: ```typescript export type BackendType = 'azureblob' | 's3' | 's3-compatible'; ``` From src/store/context.tsx: ```typescript export function useWizard(): WizardContextValue; export function WizardProvider({ children }: { children: React.ReactNode }): JSX.Element; ``` Task 1: Configure Vitest jsdom environment in vite.config.ts vite.config.ts Update vite.config.ts to add a `test` block inside `defineConfig`. The existing config has only `plugins: [react(), tailwindcss()]`. Add: ```typescript import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [react(), tailwindcss()], test: { environment: 'jsdom', passWithNoTests: true, }, }); ``` Do NOT add `/// ` — this is not needed with vitest ^4.x when using `test` config inside `defineConfig`. The `passWithNoTests: true` is already established project convention (see STATE.md decision from Phase 01-01). npx vitest run --reporter=verbose 2>&1 | head -20 Vitest starts without "document is not defined" errors. If no test files exist yet the suite exits 0 due to passWithNoTests: true. Task 2: Create Wave 0 test stubs (RED baseline for all 7 requirements) src/App.test.tsx, src/components/wizard/BackendSelectionStep.test.tsx, src/components/wizard/RemoteConfigStep.test.tsx, src/components/wizard/StepIndicator.test.tsx Create the `src/components/wizard/` directory (it does not exist yet). Create four test stub files. Each stub imports the component it will test and throws a todo error — this gives RED tests with clear names rather than import errors. NOTE: The component files do NOT exist yet. Import them anyway. Vitest will fail at import with "Cannot find module" — this is the correct RED state. **src/App.test.tsx** ```typescript // @vitest-environment jsdom // Covers WIZD-02: App renders the correct step component for currentStep 0, 1, 2 import { describe, it, expect } from 'vitest'; describe('App — step routing', () => { it('renders BackendSelectionStep when currentStep is 0', () => { expect.fail('not yet implemented'); }); it('renders RemoteConfigStep when currentStep is 1', () => { expect.fail('not yet implemented'); }); it('renders DeploymentStep when currentStep is 2', () => { expect.fail('not yet implemented'); }); }); ``` **src/components/wizard/BackendSelectionStep.test.tsx** ```typescript // @vitest-environment jsdom // Covers WIZD-01: card grid renders Azure Blob, Amazon S3, S3-Compatible (Azure first) // Covers WIZD-04: remote name field validates alphanumeric/dash/underscore import { describe, it, expect } from 'vitest'; describe('BackendSelectionStep', () => { describe('WIZD-01: backend card grid', () => { it('renders Azure Blob Storage card', () => { expect.fail('not yet implemented'); }); it('renders Amazon S3 card', () => { expect.fail('not yet implemented'); }); it('renders S3-Compatible card', () => { expect.fail('not yet implemented'); }); it('Azure Blob is listed before S3 in DOM order', () => { expect.fail('not yet implemented'); }); it('clicking a backend card dispatches SET_BACKEND_TYPE and SET_STEP', () => { expect.fail('not yet implemented'); }); }); describe('WIZD-04: remote name field', () => { it('renders remote name input at the top of the step', () => { expect.fail('not yet implemented'); }); it('shows no error before first Next attempt', () => { expect.fail('not yet implemented'); }); it('shows inline error after first Next attempt with invalid name', () => { expect.fail('not yet implemented'); }); it('accepts alphanumeric, dashes, and underscores', () => { expect.fail('not yet implemented'); }); it('rejects names with spaces or special characters', () => { expect.fail('not yet implemented'); }); }); }); ``` **src/components/wizard/RemoteConfigStep.test.tsx** ```typescript // @vitest-environment jsdom // Covers BACK-01: Azure Blob config form — account + SAS/Key toggle, both values preserved // Covers BACK-02: Amazon S3 config form — access_key_id, secret_access_key, region // Covers BACK-03: S3-Compatible config form — same as S3 plus endpoint field import { describe, it, expect } from 'vitest'; describe('RemoteConfigStep', () => { describe('BACK-01: Azure Blob form', () => { it('renders Storage Account Name field', () => { expect.fail('not yet implemented'); }); it('shows SAS URL field by default (default auth method)', () => { expect.fail('not yet implemented'); }); it('switching auth toggle to Access Key shows key field and hides SAS URL', () => { expect.fail('not yet implemented'); }); it('switching auth toggle does not clear the hidden field value', () => { expect.fail('not yet implemented'); }); }); describe('BACK-02: Amazon S3 form', () => { it('renders access_key_id field', () => { expect.fail('not yet implemented'); }); it('renders secret_access_key field', () => { expect.fail('not yet implemented'); }); it('renders region field', () => { expect.fail('not yet implemented'); }); }); describe('BACK-03: S3-Compatible form', () => { it('renders endpoint field in addition to S3 fields', () => { expect.fail('not yet implemented'); }); }); }); ``` **src/components/wizard/StepIndicator.test.tsx** ```typescript // @vitest-environment jsdom // Covers WIZD-03: going back preserves remote.params; deployment options are untouched import { describe, it, expect } from 'vitest'; describe('StepIndicator', () => { describe('WIZD-03: back navigation preserves state', () => { it('clicking a completed step dispatches SET_STEP', () => { expect.fail('not yet implemented'); }); it('clicking back to step 0 dispatches SET_REMOTE_PARAMS({}) to clear params', () => { expect.fail('not yet implemented'); }); it('clicking back to step 0 does NOT dispatch RESET (deployment preserved)', () => { expect.fail('not yet implemented'); }); it('step 0 shows as active when currentStep is 0', () => { expect.fail('not yet implemented'); }); it('completed steps are clickable', () => { expect.fail('not yet implemented'); }); }); }); ``` npx vitest run --reporter=verbose 2>&1 | tail -30 All four test files exist. Vitest runs and reports failures (RED). The failures are either "Cannot find module" (acceptable — component files not yet created) or "not yet implemented" (from expect.fail). No passing tests exist yet. vite.config.ts has jsdom environment. Run after both tasks complete: ```bash npx vitest run --reporter=verbose 2>&1 ``` Expected: Vitest runs (no "document is not defined"), tests fail RED with module-not-found or "not yet implemented" errors, suite reports failures. The key outcome is that jsdom works and tests are scaffolded. - vite.config.ts has `test: { environment: 'jsdom', passWithNoTests: true }` - Four test files exist under src/ with descriptive failing test names - `npx vitest run` runs without crashing the vitest process itself (failures are expected) - Test names directly trace to requirements (WIZD-01, WIZD-02, WIZD-03, WIZD-04, BACK-01, BACK-02, BACK-03) After completion, create `.planning/phases/03-wizard-ui/03-01-SUMMARY.md`