test(03-03): add failing tests for BackendSelectionStep (WIZD-01, WIZD-04)
- Replace expect.fail stubs with real test assertions - Tests cover card render order, card click dispatch, name validation - RED: component file does not exist yet
This commit is contained in:
@@ -2,49 +2,109 @@
|
|||||||
// Covers WIZD-01: card grid renders Azure Blob, Amazon S3, S3-Compatible (Azure first)
|
// Covers WIZD-01: card grid renders Azure Blob, Amazon S3, S3-Compatible (Azure first)
|
||||||
// Covers WIZD-04: remote name field validates alphanumeric/dash/underscore
|
// Covers WIZD-04: remote name field validates alphanumeric/dash/underscore
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
|
import { WizardProvider } from '../../store/context';
|
||||||
|
import { BackendSelectionStep } from './BackendSelectionStep';
|
||||||
|
|
||||||
|
function renderStep() {
|
||||||
|
return render(
|
||||||
|
<WizardProvider>
|
||||||
|
<BackendSelectionStep />
|
||||||
|
</WizardProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
describe('BackendSelectionStep', () => {
|
describe('BackendSelectionStep', () => {
|
||||||
describe('WIZD-01: backend card grid', () => {
|
describe('WIZD-01: backend card grid', () => {
|
||||||
it('renders Azure Blob Storage card', () => {
|
it('renders Azure Blob Storage card', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
expect(screen.getByText('Azure Blob Storage')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders Amazon S3 card', () => {
|
it('renders Amazon S3 card', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
expect(screen.getByText('Amazon S3')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders S3-Compatible card', () => {
|
it('renders S3-Compatible card', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
expect(screen.getByText('S3-Compatible')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Azure Blob is listed before S3 in DOM order', () => {
|
it('Azure Blob is listed before S3 in DOM order', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
const buttons = screen.getAllByRole('button');
|
||||||
|
// Find Azure and S3 buttons by their accessible names
|
||||||
|
const azureIdx = buttons.findIndex(b => b.textContent?.includes('Azure Blob Storage'));
|
||||||
|
const s3Idx = buttons.findIndex(b => b.textContent?.includes('Amazon S3'));
|
||||||
|
expect(azureIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(s3Idx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(azureIdx).toBeLessThan(s3Idx);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clicking a backend card dispatches SET_BACKEND_TYPE and SET_STEP', () => {
|
it('clicking a backend card dispatches SET_BACKEND_TYPE and SET_STEP', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
// Fill in a valid remote name first
|
||||||
|
const nameInput = screen.getByRole('textbox');
|
||||||
|
fireEvent.change(nameInput, { target: { value: 'my-remote' } });
|
||||||
|
// Click the Azure card — if navigation dispatches SET_STEP(1), component may unmount
|
||||||
|
// We verify no validation error appears (meaning dispatch proceeded)
|
||||||
|
const azureButton = screen.getAllByRole('button').find(b => b.textContent?.includes('Azure Blob Storage'))!;
|
||||||
|
expect(azureButton).toBeDefined();
|
||||||
|
fireEvent.click(azureButton);
|
||||||
|
// After successful navigation step fires, no validation alert should be present
|
||||||
|
expect(screen.queryByRole('alert')).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('WIZD-04: remote name field', () => {
|
describe('WIZD-04: remote name field', () => {
|
||||||
it('renders remote name input at the top of the step', () => {
|
it('renders remote name input at the top of the step', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
const nameInput = screen.getByRole('textbox');
|
||||||
|
expect(nameInput).toBeDefined();
|
||||||
|
// Verify input appears before backend cards in DOM
|
||||||
|
const container = nameInput.closest('form') ?? document.body;
|
||||||
|
const allButtons = container.querySelectorAll('button');
|
||||||
|
const inputPosition = Array.from(container.querySelectorAll('input, button')).indexOf(nameInput as HTMLInputElement);
|
||||||
|
const firstButtonPosition = Array.from(container.querySelectorAll('input, button')).indexOf(allButtons[0]);
|
||||||
|
expect(inputPosition).toBeLessThan(firstButtonPosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows no error before first Next attempt', () => {
|
it('shows no error before first Next attempt', () => {
|
||||||
expect.fail('not yet implemented');
|
renderStep();
|
||||||
|
// No alert role should be present on initial render
|
||||||
|
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', () => {
|
||||||
expect.fail('not yet implemented');
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts alphanumeric, dashes, and underscores', () => {
|
it('accepts alphanumeric, dashes, and underscores', () => {
|
||||||
expect.fail('not yet implemented');
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects names with spaces or special characters', () => {
|
it('rejects names with spaces or special characters', () => {
|
||||||
expect.fail('not yet implemented');
|
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user