feat(03-03): implement BackendSelectionStep (WIZD-01, WIZD-04)
- Remote name field with zod validation (mode: onSubmit, reValidateMode: onChange)
- Three backend cards in popularity order: Azure Blob, Amazon S3, S3-Compatible
- Card click validates name first; dispatches SET_REMOTE_NAME + SET_BACKEND_TYPE + SET_REMOTE_PARAMS({}) + SET_STEP(1)
- Does NOT dispatch RESET — preserves deployment options
- All 10 BackendSelectionStep tests GREEN
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// 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';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { WizardProvider } from '../../store/context';
|
||||
import { BackendSelectionStep } from './BackendSelectionStep';
|
||||
|
||||
@@ -76,35 +76,41 @@ describe('BackendSelectionStep', () => {
|
||||
expect(screen.queryByRole('alert')).toBeNull();
|
||||
});
|
||||
|
||||
it('shows inline error after first Next attempt with invalid name', () => {
|
||||
it('shows inline error after first Next attempt with invalid name', async () => {
|
||||
renderStep();
|
||||
// Click a card without filling in name — triggers validation
|
||||
const azureButton = screen.getAllByRole('button').find(b => b.textContent?.includes('Azure Blob Storage'))!;
|
||||
fireEvent.click(azureButton);
|
||||
// Error should appear
|
||||
expect(screen.getByRole('alert')).toBeDefined();
|
||||
expect(screen.getByText(/required/i)).toBeDefined();
|
||||
// Error should appear after async validation
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('alert')).toBeDefined();
|
||||
expect(screen.getByText(/required/i)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts alphanumeric, dashes, and underscores', () => {
|
||||
it('accepts alphanumeric, dashes, and underscores', async () => {
|
||||
renderStep();
|
||||
const nameInput = screen.getByRole('textbox');
|
||||
fireEvent.change(nameInput, { target: { value: 'my-remote_01' } });
|
||||
const azureButton = screen.getAllByRole('button').find(b => b.textContent?.includes('Azure Blob Storage'))!;
|
||||
fireEvent.click(azureButton);
|
||||
// Valid name — no alert should appear
|
||||
expect(screen.queryByRole('alert')).toBeNull();
|
||||
// Valid name — no alert should appear (wait briefly to confirm no error appears)
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByRole('alert')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects names with spaces or special characters', () => {
|
||||
it('rejects names with spaces or special characters', async () => {
|
||||
renderStep();
|
||||
const nameInput = screen.getByRole('textbox');
|
||||
fireEvent.change(nameInput, { target: { value: 'my remote!' } });
|
||||
const azureButton = screen.getAllByRole('button').find(b => b.textContent?.includes('Azure Blob Storage'))!;
|
||||
fireEvent.click(azureButton);
|
||||
// Invalid name — alert should appear
|
||||
expect(screen.getByRole('alert')).toBeDefined();
|
||||
expect(screen.getByText(/letters, numbers, dashes/i)).toBeDefined();
|
||||
// Invalid name — alert should appear after async validation
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('alert')).toBeDefined();
|
||||
expect(screen.getByText(/letters, numbers, dashes/i)).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user