test(07-00): add failing stubs for VALID-01 and UX-01
- Add VALID-01 describe block with 7 tests: Azure account name (reject uppercase, reject <3 chars, accept valid), S3 region (reject spaces, accept valid), GCS project_number (reject non-digits, accept valid) - Add UX-01 describe block with 5 tests: ⓘ button presence on sas_url, SFTP auth section, OneDrive token; tooltip show/hide toggle - 9 new tests fail (RED state — validate property and tooltipText not on FieldDef yet) - 3 new acceptance tests pass (absence-of-error condition already met before implementation) - All 147 pre-existing tests still pass (zero regressions)
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
// Covers BACK-01: Azure Blob config form — account + SAS/Key toggle, both values preserved
|
// Covers BACK-01: Azure Blob config form — account + SAS/Key toggle, both values preserved
|
||||||
// Covers BACK-02: Amazon S3 config form — access_key_id, secret_access_key, region
|
// Covers BACK-02: Amazon S3 config form — access_key_id, secret_access_key, region
|
||||||
// Covers BACK-03: S3-Compatible config form — same as S3 plus endpoint field
|
// Covers BACK-03: S3-Compatible config form — same as S3 plus endpoint field
|
||||||
|
// Covers VALID-01: Format validation stubs (RED — validate property not implemented yet)
|
||||||
|
// Covers UX-01: Tooltip toggle stubs (RED — tooltipText property not implemented yet)
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
@@ -227,4 +229,174 @@ describe('RemoteConfigStep', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('VALID-01 — format validation', () => {
|
||||||
|
// RED stubs — validate property not on FieldDef yet; no regex chaining in buildZodSchema()
|
||||||
|
// These tests will fail until Plan 07-01 implements format validation
|
||||||
|
|
||||||
|
// Azure account name tests
|
||||||
|
it('rejects account name with uppercase letters', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/storage account name/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.clear(screen.getByLabelText(/storage account name/i));
|
||||||
|
await user.type(screen.getByLabelText(/storage account name/i), 'MyStorage');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/3.{1,5}24 lowercase alphanumeric/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects account name shorter than 3 characters', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/storage account name/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.clear(screen.getByLabelText(/storage account name/i));
|
||||||
|
await user.type(screen.getByLabelText(/storage account name/i), 'ab');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/3.{1,5}24 lowercase alphanumeric/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid account name (no format error)', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/storage account name/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.type(screen.getByLabelText(/storage account name/i), 'mystorageaccount');
|
||||||
|
// Fill SAS URL field so form can submit without other required-field errors
|
||||||
|
await user.type(screen.getByLabelText(/sas url/i), 'https://mystorage.blob.core.windows.net/?sv=test');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText(/3.{1,5}24 lowercase alphanumeric/i)).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// S3 region tests
|
||||||
|
it('rejects S3 region with invalid format (spaces)', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('s3');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/region/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.type(screen.getByLabelText(/region/i), 'us east 1');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/valid aws region format/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid S3 region (no format error)', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('s3');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/region/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// Fill all required S3 fields so form can submit
|
||||||
|
await user.type(screen.getByLabelText(/access key id/i), 'AKIAIOSFODNN7EXAMPLE');
|
||||||
|
await user.type(screen.getByLabelText(/secret access key/i), 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY');
|
||||||
|
await user.type(screen.getByLabelText(/region/i), 'us-east-1');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText(/valid aws region format/i)).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// GCS project_number tests
|
||||||
|
it('rejects GCS project_number with non-digits', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('gcs' as BackendType);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/project number/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.type(screen.getByLabelText(/project number/i), 'abc');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/digits only/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid GCS project_number (no format error)', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('gcs' as BackendType);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/project number/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.type(screen.getByLabelText(/project number/i), '123456789');
|
||||||
|
await user.click(screen.getByRole('button', { name: /next/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText(/digits only/i)).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('UX-01 — contextual tooltips', () => {
|
||||||
|
// RED stubs — tooltipText not on FieldDef yet; no ⓘ buttons rendered
|
||||||
|
// These tests will fail until Plan 07-02 implements tooltip toggle
|
||||||
|
|
||||||
|
it('renders ⓘ button on azureblob sas_url field', async () => {
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/sas url/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// ⓘ button does not exist yet — will throw "Unable to find role 'button'"
|
||||||
|
expect(screen.getByRole('button', { name: /more info about sas url/i })).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows tooltip panel when ⓘ is clicked on sas_url', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/sas url/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// ⓘ button does not exist yet — getByRole will throw
|
||||||
|
await user.click(screen.getByRole('button', { name: /more info about sas url/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
// Tooltip text should be visible after clicking ⓘ
|
||||||
|
expect(screen.getByText(/shared access signature/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hides tooltip panel when ⓘ is clicked again', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderWithBackend('azureblob');
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/sas url/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// ⓘ button does not exist yet — getByRole will throw
|
||||||
|
await user.click(screen.getByRole('button', { name: /more info about sas url/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/shared access signature/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
await user.click(screen.getByRole('button', { name: /more info about sas url/i }));
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByText(/shared access signature/i)).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders ⓘ button on SFTP auth method section', async () => {
|
||||||
|
renderWithBackend('sftp' as BackendType);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/host/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// ⓘ button does not exist yet — will throw "Unable to find role 'button'"
|
||||||
|
expect(screen.getByRole('button', { name: /more info about authentication/i })).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders ⓘ button on OneDrive token field', async () => {
|
||||||
|
renderWithBackend('onedrive' as BackendType);
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByLabelText(/oauth token/i)).toBeDefined();
|
||||||
|
});
|
||||||
|
// ⓘ button does not exist yet — will throw "Unable to find role 'button'"
|
||||||
|
// Note: this matches any "more info about X" button on the OneDrive form
|
||||||
|
expect(screen.getByRole('button', { name: /more info about oauth token/i })).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user