---
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)