Files
kawa 3155491315 docs(03-04): complete RemoteConfigStep plan
- SUMMARY.md created with TDD commits, deviations, decisions
- STATE.md updated: progress 92%, decisions, session
- ROADMAP.md updated: phase 3 4/5 summaries complete
2026-03-27 09:40:25 +01:00

130 lines
6.3 KiB
Markdown

---
phase: 03-wizard-ui
plan: "04"
subsystem: ui
tags: [react, react-hook-form, zod, vitest, testing-library]
# Dependency graph
requires:
- phase: 03-wizard-ui-01
provides: WizardProvider, useWizard, WizardState with remote.backendType/params
- phase: 03-wizard-ui-02
provides: FieldRenderer, AzureAuthToggle, PasswordField components
- phase: 01-foundation
provides: BACKEND_REGISTRY, BACKEND_SCHEMAS, BackendType
provides:
- RemoteConfigStep component — registry-driven form for azureblob, s3, s3-compatible backends
affects: 03-wizard-ui-05
# Tech tracking
tech-stack:
added: ["@testing-library/user-event"]
patterns:
- "registry-driven form rendering via BACKEND_REGISTRY[backendType] loop"
- "useEffect guard for null backendType redirect to avoid hooks order violation"
- "unconditional fallback schema to satisfy rules-of-hooks before early return"
key-files:
created:
- src/components/wizard/RemoteConfigStep.tsx
modified:
- src/components/wizard/RemoteConfigStep.test.tsx
- package.json
key-decisions:
- "[03-04] useEffect guard for null backendType instead of dispatch-in-render — prevents React hooks order violation"
- "[03-04] Fallback schema (azureblob) used when backendType is null to keep useForm call unconditional"
- "[03-04] Tests use toBeDefined() consistently with rest of codebase — no @testing-library/jest-dom needed"
patterns-established:
- "RemoteConfigStep: azureblob renders account via FieldRenderer + AzureAuthToggle for key/sas_url; S3/S3-compat loop full registry"
- "Key on backendType in parent to force full remount on backend change (documented in plan context)"
requirements-completed: [BACK-01, BACK-02, BACK-03]
# Metrics
duration: 3min
completed: 2026-03-27
---
# Phase 3 Plan 04: RemoteConfigStep Summary
**Registry-driven backend config form with azureblob/s3/s3-compatible switching, AzureAuthToggle for key/SAS URL, and touch-then-live validation via react-hook-form**
## Performance
- **Duration:** 3 min
- **Started:** 2026-03-27T08:35:50Z
- **Completed:** 2026-03-27T08:38:45Z
- **Tasks:** 1 (TDD: 2 commits — test RED then feat GREEN)
- **Files modified:** 3
## Accomplishments
- BACK-01: Azure Blob form — `account` FieldRenderer + `AzureAuthToggle` (key + sas_url both always registered, only active one visible)
- BACK-02: S3 form — full BACKEND_REGISTRY loop, provider hidden by FieldRenderer, access_key_id/secret_access_key/region fields
- BACK-03: S3-compatible form — same as S3 plus endpoint field; all 8 tests GREEN
## Task Commits
Each task was committed atomically:
1. **RED: RemoteConfigStep tests (failing)** - `a57b2ea` (test)
2. **GREEN: RemoteConfigStep implementation** - `45bcc0c` (feat)
_TDD tasks have two commits: failing test then passing implementation_
## Files Created/Modified
- `src/components/wizard/RemoteConfigStep.tsx` - Step 1 registry-driven backend config form; azureblob special-cased with AzureAuthToggle, S3/S3-compat use full registry loop
- `src/components/wizard/RemoteConfigStep.test.tsx` - 8 tests covering BACK-01/02/03; uses renderWithBackend helper that dispatches SET_BACKEND_TYPE via useEffect
- `package.json` + `package-lock.json` - added @testing-library/user-event for value retention test
## Decisions Made
- **useEffect guard instead of dispatch-in-render:** The original plan template had `dispatch({ type: 'SET_STEP', payload: 0 })` directly in the render path (before hooks). Moved to `useEffect` to prevent React's "cannot update during render" warning and hooks order violation.
- **Unconditional fallback schema:** `useForm` must be called unconditionally per hooks rules. When `backendType` is null, falls back to `BACKEND_SCHEMAS['azureblob']` schema, then returns `null` after all hooks have run.
- **`toBeDefined()` not `toBeInTheDocument()`:** Consistent with existing test files in the project; avoids needing @testing-library/jest-dom matchers setup.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] Installed missing @testing-library/user-event**
- **Found during:** Task 1 RED phase (test file import)
- **Issue:** Test file imports `userEvent` from `@testing-library/user-event` which was not installed
- **Fix:** Ran `npm install --save-dev @testing-library/user-event`
- **Files modified:** package.json, package-lock.json
- **Verification:** Import resolved, tests ran
- **Committed in:** a57b2ea (RED test commit)
**2. [Rule 1 - Bug] Moved guard dispatch from render to useEffect**
- **Found during:** Task 1 GREEN phase (first test run)
- **Issue:** Plan template showed `dispatch({ type: 'SET_STEP', payload: 0 })` inline in render before `useForm` hook call, causing React "Cannot update a component while rendering a different component" warning and hooks order violation
- **Fix:** Guard dispatch moved to `useEffect([backendType, dispatch])`, fallback schema used to keep `useForm` unconditional, early `return null` placed after all hooks
- **Files modified:** src/components/wizard/RemoteConfigStep.tsx
- **Verification:** No React warnings, all 8 tests GREEN
- **Committed in:** 45bcc0c (feat commit)
**3. [Rule 1 - Bug] Tests rewritten to use `toBeDefined()` instead of `toBeInTheDocument()`**
- **Found during:** Task 1 GREEN phase (test execution)
- **Issue:** Tests used `toBeInTheDocument()` which is a @testing-library/jest-dom matcher not configured in this project; project uses `toBeDefined()` throughout
- **Fix:** Rewrote all assertions to `toBeDefined()` and direct value checks (`input.value === ...`)
- **Files modified:** src/components/wizard/RemoteConfigStep.test.tsx
- **Verification:** All 8 tests GREEN without jest-dom matchers
- **Committed in:** 45bcc0c (feat commit, updated test file)
---
**Total deviations:** 3 auto-fixed (1 blocking dependency, 2 bugs in plan template code)
**Impact on plan:** All auto-fixes required for correctness. No scope creep.
## Issues Encountered
- React hooks rules violation in plan's suggested guard pattern — resolved by moving dispatch to useEffect and using unconditional fallback schema
## Next Phase Readiness
- RemoteConfigStep complete and tested; keying on backendType for remount documented
- Plan 05 can integrate RemoteConfigStep into App.tsx with `key={state.remote.backendType}`
- App.test.tsx and StepIndicator.test.tsx stubs remain RED as expected (wave 0, Plan 05 responsibility)
---
*Phase: 03-wizard-ui*
*Completed: 2026-03-27*