diff --git a/src/App.test.tsx b/src/App.test.tsx index bbd341c..624fe27 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -7,34 +7,7 @@ import App from './App'; import { WizardProvider } from './store/context'; import { useWizard } from './store/context'; -// Helper: renders App and navigates to a given step via dispatch -function renderAtStep(targetStep: number) { - // We wrap App's WizardProvider with an outer one and use a sibling to dispatch - // Actually App already has its own WizardProvider, so we can't inject state from outside. - // Instead, we render a standalone shell that mimics App but accepts a step override. - function TestShell() { - const { state, dispatch } = useWizard(); - React.useEffect(() => { - if (targetStep > 0) { - if (targetStep >= 1) { - dispatch({ type: 'SET_BACKEND_TYPE', payload: 'azureblob' }); - } - dispatch({ type: 'SET_STEP', payload: targetStep }); - } - }, [dispatch]); - return ; - } - - return render( - - - - ); -} - -// Import the internal WizardShell logic by re-exporting from App — or replicate it here -// Since App has WizardProvider + WizardShell baked in, we test App directly for step 0 -// and use a custom shell for steps 1 and 2. +// Helper: renders a wizard shell at a given step (bypassing App's own WizardProvider) import { BackendSelectionStep } from './components/wizard/BackendSelectionStep'; import { RemoteConfigStep } from './components/wizard/RemoteConfigStep'; import { DeploymentStep } from './components/wizard/DeploymentStep'; @@ -57,23 +30,48 @@ function AppContent({ state }: { state: WizardState }) { ); } +function renderAtStep(targetStep: number) { + function TestShell() { + const { state, dispatch } = useWizard(); + React.useEffect(() => { + if (targetStep >= 1) { + dispatch({ type: 'SET_BACKEND_TYPE', payload: 'azureblob' }); + } + if (targetStep > 0) { + dispatch({ type: 'SET_STEP', payload: targetStep }); + } + }, [dispatch]); + return ; + } + + return render( + + + + ); +} + describe('App — step routing', () => { it('renders BackendSelectionStep when currentStep is 0', () => { render(); // BackendSelectionStep renders "Step 1: Select Backend" const heading = screen.getByText(/Select Backend/); expect(heading).toBeDefined(); - // StepIndicator should be visible with Backend label - const backendLabel = screen.getByText(/Backend/); - expect(backendLabel).toBeDefined(); + // StepIndicator should be visible — Backend is the active step + const stepNav = screen.getByRole('navigation', { name: /Wizard steps/i }); + expect(stepNav).toBeDefined(); }); it('renders RemoteConfigStep when currentStep is 1', async () => { renderAtStep(1); - // RemoteConfigStep renders a heading with "Remote Config" or backend-specific label - // Wait for the step to render - const heading = await screen.findByText(/Remote Config|Configure/); - expect(heading).toBeDefined(); + // RemoteConfigStep renders "Step 2: Configure {backend name}" + // Use getAllByText to handle multiple matches (StepIndicator also contains "Remote Config") + const headings = await screen.findAllByText(/Configure/); + // At least one heading with "Configure" from RemoteConfigStep + expect(headings.length).toBeGreaterThanOrEqual(1); + // The h2 specifically should say "Step 2: Configure Azure Blob Storage" + const h2 = headings.find((el) => el.tagName === 'H2'); + expect(h2).toBeDefined(); }); it('renders DeploymentStep when currentStep is 2', async () => { diff --git a/src/App.tsx b/src/App.tsx index 4784599..6dc4e53 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,45 @@ // src/App.tsx +// Step router — renders the correct step component based on currentStep. +// StepIndicator renders above each step as persistent breadcrumb navigation. + +import { useWizard } from './store/context'; import { WizardProvider } from './store/context'; +import { StepIndicator } from './components/wizard/StepIndicator'; +import { BackendSelectionStep } from './components/wizard/BackendSelectionStep'; +import { RemoteConfigStep } from './components/wizard/RemoteConfigStep'; +import { DeploymentStep } from './components/wizard/DeploymentStep'; + +function WizardShell() { + const { state } = useWizard(); + + const steps = [ + , + // Key on backendType to force remount when backend changes — prevents stale form values + , + , + ]; + + // Guard: clamp to valid range (phase 4 will add step 3 for review/download) + const stepIndex = Math.min(state.currentStep, steps.length - 1); + const CurrentStep = steps[stepIndex]; + + return ( +
+
+

Ready2Blob

+ +
+ {CurrentStep} +
+
+
+ ); +} export default function App() { return ( -
-

Ready2Blob

-
+
); }