feat(03-05): wire App.tsx step router and make App.test GREEN
- App.tsx: WizardShell routes to BackendSelectionStep/RemoteConfigStep/DeploymentStep - App.tsx: StepIndicator renders above every step as persistent breadcrumb - App.tsx: RemoteConfigStep keyed on backendType to force remount on backend change - App.test.tsx: all 3 WIZD-02 tests GREEN (step 0, 1, 2 routing verified) - Full suite: 87 tests GREEN across 11 test files
This commit is contained in:
+33
-35
@@ -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 <AppContent state={state} />;
|
||||
}
|
||||
|
||||
return render(
|
||||
<WizardProvider>
|
||||
<TestShell />
|
||||
</WizardProvider>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 <AppContent state={state} />;
|
||||
}
|
||||
|
||||
return render(
|
||||
<WizardProvider>
|
||||
<TestShell />
|
||||
</WizardProvider>
|
||||
);
|
||||
}
|
||||
|
||||
describe('App — step routing', () => {
|
||||
it('renders BackendSelectionStep when currentStep is 0', () => {
|
||||
render(<App />);
|
||||
// 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 () => {
|
||||
|
||||
+36
-3
@@ -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 = [
|
||||
<BackendSelectionStep key="backend" />,
|
||||
// Key on backendType to force remount when backend changes — prevents stale form values
|
||||
<RemoteConfigStep key={state.remote.backendType ?? 'none'} />,
|
||||
<DeploymentStep key="deployment" />,
|
||||
];
|
||||
|
||||
// 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 (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col items-center py-12 px-4">
|
||||
<div className="w-full max-w-2xl">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-8 text-center">Ready2Blob</h1>
|
||||
<StepIndicator />
|
||||
<div className="mt-8">
|
||||
{CurrentStep}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<WizardProvider>
|
||||
<div className="p-4">
|
||||
<h1 className="text-2xl font-bold">Ready2Blob</h1>
|
||||
</div>
|
||||
<WizardShell />
|
||||
</WizardProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user