import React from 'react';
import {
createMockDomain,
createTestForm,
render,
renderInDarkMode,
renderInLightMode,
screen
} from '../../test-utils';
import {CollectionEditForm} from './CollectionEditForm';
// Mock the TagsContext
jest.mock('../../Tags', () => ({
TagsContext: {
_currentValue: {
SingleTag: ({name}) => {name}
}
},
}));
// Mock Common components
jest.mock('../Common', () => ({
...jest.requireActual('../Common'),
WROLModeMessage: ({content}) =>
{content}
,
}));
describe('CollectionEditForm', () => {
const mockCollection = createMockDomain();
describe('Form Rendering', () => {
it('renders children and Save button', () => {
const form = createTestForm(mockCollection);
render(
Form fields here
);
expect(screen.getByTestId('child-content')).toBeInTheDocument();
expect(screen.getByRole('button', {name: /save/i})).toBeInTheDocument();
});
it('renders title when provided', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.getByRole('heading', {level: 1})).toHaveTextContent('Edit Domain: example.com');
});
it('renders WROL mode message when provided', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.getByTestId('wrol-mode-message')).toHaveTextContent('Editing disabled in WROL Mode');
});
it('renders action buttons when provided', () => {
const form = createTestForm(mockCollection);
render(
Delete}
>
Form content
);
expect(screen.getByTestId('delete-button')).toBeInTheDocument();
});
it('renders appliedTagName when provided', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.getByTestId('applied-tag')).toHaveTextContent('News');
});
it('does not render appliedTagName when not provided', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.queryByTestId('applied-tag')).not.toBeInTheDocument();
});
});
describe('Save/Cancel Actions', () => {
it('shows Cancel button when onCancel provided', () => {
const form = createTestForm(mockCollection);
const mockOnCancel = jest.fn();
render(
Form content
);
expect(screen.getByRole('button', {name: /cancel/i})).toBeInTheDocument();
});
it('does not show Cancel button when onCancel not provided', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.queryByRole('button', {name: /cancel/i})).not.toBeInTheDocument();
});
it('disables Save button when form is disabled', () => {
const form = createTestForm(mockCollection, {
overrides: {disabled: true}
});
render(
Form content
);
expect(screen.getByRole('button', {name: /save/i})).toBeDisabled();
});
it('disables Cancel button when form is disabled', () => {
const form = createTestForm(mockCollection, {
overrides: {disabled: true}
});
const mockOnCancel = jest.fn();
render(
Form content
);
expect(screen.getByRole('button', {name: /cancel/i})).toBeDisabled();
});
});
describe('Error States', () => {
it('displays form-level errors', () => {
const form = createTestForm(mockCollection, {
overrides: {error: 'Something went wrong'}
});
render(
Form content
);
expect(screen.getByText(/something went wrong/i)).toBeInTheDocument();
});
it('does not display error message when no error', () => {
const form = createTestForm(mockCollection);
render(
Form content
);
expect(screen.queryByText(/error/i)).not.toBeInTheDocument();
});
});
describe('Form Submission', () => {
it('calls form.onSubmit when Save button is clicked', () => {
const form = createTestForm(mockCollection);
form.onSubmit = jest.fn();
render(
Form content
);
screen.getByRole('button', {name: /save/i}).click();
expect(form.onSubmit).toHaveBeenCalled();
});
});
describe('Theme Integration', () => {
// Panel/Header are token-driven (see ui/Surfaces.tsx): their colors come from CSS
// variables scoped on `[data-theme]`, not from JS branching on the theme. There is
// no more "inverted" prop/class to assert on -- just that the same markup renders
// in both modes.
it('renders a token-driven Panel in dark mode', () => {
const form = createTestForm(mockCollection);
const {container} = renderInDarkMode(
Form content
);
expect(container.querySelector('.wrolpi-panel')).toBeInTheDocument();
});
it('renders a token-driven Panel in light mode', () => {
const form = createTestForm(mockCollection);
const {container} = renderInLightMode(
Form content
);
expect(container.querySelector('.wrolpi-panel')).toBeInTheDocument();
});
it('renders a token-driven Header for the title', () => {
const form = createTestForm(mockCollection);
const {container} = renderInDarkMode(
Form content
);
const header = container.querySelector('.wrolpi-header');
expect(header).toBeInTheDocument();
expect(header).toHaveTextContent('Test Collection');
});
});
describe('CSS Classes', () => {
it('puts its actions in a button row, and leaves their margins alone', () => {
/*
* `action-button-spacing` was `margin-top: 1em` on Cancel alone, matching the same
* margin the three calling pages stamped on each of their action buttons -- so every
* button in this row sat 1em below the Save beside it, which has none. The row spaces
* and wraps them now, and nothing in it carries a margin of its own.
*/
const form = createTestForm(mockCollection);
const mockOnCancel = jest.fn();
const {container} = render(
Form content
);
const cancelButton = screen.getByRole('button', {name: /cancel/i});
const row = container.querySelector('.wrolpi-button-row');
expect(row).toBeInTheDocument();
expect(row).toContainElement(cancelButton);
expect(row).toContainElement(screen.getByRole('button', {name: /save/i}));
expect(cancelButton).not.toHaveClass('action-button-spacing');
});
});
});