@kadconsulting/dry
Version:
KAD Reusable Component Library
126 lines • 6.77 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import RepeatableForm from './RepeatableForm';
// Mock child components
jest.mock('../index', () => ({
Accordion: ({ children, parentContent, onDelete, onOpenStateChange, initialOpenState, }) => (_jsxs("div", { "data-testid": 'accordion', "data-open": initialOpenState, children: [_jsx("div", { children: parentContent }), _jsx("button", { onClick: () => onOpenStateChange(!initialOpenState), children: "Toggle" }), _jsx("button", { onClick: onDelete, children: "Delete" }), initialOpenState && children] })),
TextInput: ({ Label, value, onChange, inputType }) => (_jsx("input", { type: inputType, placeholder: Label, value: value, onChange: onChange, "data-testid": `input-${Label}` })),
Textarea: ({ label, value, onChange }) => (_jsx("textarea", { placeholder: label, value: value, onChange: onChange, "data-testid": `textarea-${label}` })),
Button: ({ children, onClick, buttonType }) => (_jsx("button", { onClick: onClick, "data-button-type": buttonType, children: children })),
}));
const defaultFields = [
{ name: 'name', label: 'Name', type: 'text' },
{ name: 'description', label: 'Description', type: 'textarea' },
{ name: 'quantity', label: 'Quantity', type: 'number' },
];
const defaultProps = {
fields: defaultFields,
initialState: [
{
name: 'Initial Entry',
description: 'Initial Description',
quantity: '1',
},
],
onStateChange: jest.fn(),
};
describe('RepeatableForm', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('renders with initial state', () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
expect(screen.getByText('Entry 1')).toBeInTheDocument();
expect(screen.getByTestId('input-Name')).toHaveValue('Initial Entry');
expect(screen.getByTestId('textarea-Description')).toHaveValue('Initial Description');
expect(screen.getByTestId('input-Quantity')).toHaveValue('1');
});
it('adds a new entry when "Add New Entry" is clicked', async () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
await userEvent.click(screen.getByText('Add New Entry'));
expect(screen.getAllByTestId('accordion')).toHaveLength(2);
expect(screen.getByText('Entry 2')).toBeInTheDocument();
});
it('removes an entry when delete button is clicked', async () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
await userEvent.click(screen.getByText('Add New Entry'));
expect(screen.getAllByTestId('accordion')).toHaveLength(2);
await userEvent.click(screen.getAllByText('Delete')[0]);
expect(screen.getAllByTestId('accordion')).toHaveLength(1);
});
it('updates form state when input changes', async () => {
const onStateChange = jest.fn();
render(_jsx(RepeatableForm, { ...defaultProps, onStateChange: onStateChange }));
await userEvent.type(screen.getByTestId('input-Name'), ' Updated');
expect(onStateChange).toHaveBeenCalledWith([
{
name: 'Initial Entry Updated',
description: 'Initial Description',
quantity: '1',
},
]);
});
it('handles different input types correctly', async () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
await userEvent.type(screen.getByTestId('input-Quantity'), '5');
expect(screen.getByTestId('input-Quantity')).toHaveValue('15');
});
it('toggles accordion open/close state', async () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
const accordion = screen.getByTestId('accordion');
expect(accordion).toHaveAttribute('data-open', 'true');
await userEvent.click(screen.getByText('Toggle'));
expect(accordion).toHaveAttribute('data-open', 'false');
});
it('opens newly added entry and closes others', async () => {
render(_jsx(RepeatableForm, { ...defaultProps }));
await userEvent.click(screen.getByText('Add New Entry'));
const accordions = screen.getAllByTestId('accordion');
expect(accordions[0]).toHaveAttribute('data-open', 'false');
expect(accordions[1]).toHaveAttribute('data-open', 'true');
});
it('maintains state correctly after multiple add/remove operations', async () => {
const onStateChange = jest.fn();
render(_jsx(RepeatableForm, { ...defaultProps, onStateChange: onStateChange }));
await userEvent.click(screen.getByText('Add New Entry'));
await userEvent.click(screen.getByText('Add New Entry'));
await userEvent.click(screen.getAllByText('Delete')[1]);
expect(screen.getAllByTestId('accordion')).toHaveLength(2);
expect(onStateChange).toHaveBeenCalledTimes(3);
});
it('handles empty initial state', () => {
render(_jsx(RepeatableForm, { ...defaultProps, initialState: [] }));
expect(screen.queryByTestId('accordion')).not.toBeInTheDocument();
});
it('renders with correct CSS classes and inline styles', () => {
const { container } = render(_jsx(RepeatableForm, { ...defaultProps, className: 'custom-class', style: { marginTop: '10px' } }));
const formElement = container.firstChild;
expect(formElement).toHaveClass('dry-repeatableform');
expect(formElement).toHaveClass('custom-class');
expect(formElement).toHaveStyle('margin-top: 10px');
});
it('calls onStateChange with correct data structure when adding new entry', async () => {
const onStateChange = jest.fn();
render(_jsx(RepeatableForm, { ...defaultProps, onStateChange: onStateChange }));
await userEvent.click(screen.getByText('Add New Entry'));
expect(onStateChange).toHaveBeenCalledWith([
{
name: 'Initial Entry',
description: 'Initial Description',
quantity: '1',
},
{ name: '', description: '', quantity: '' },
]);
});
it('passes any downstream data-* attribute(s)', () => {
const testValue = 'test-value';
render(_jsx(RepeatableForm, { ...defaultProps, "data-test": testValue }));
expect(screen.getByTestId('accordion')).toHaveAttribute('data-test', testValue);
});
it('supports downstream @testing-library `screen.getByTestId`', () => {
render(_jsx(RepeatableForm, { ...defaultProps, "data-testid": 'test-id' }));
expect(screen.getByTestId('test-id')).toBeInTheDocument();
});
});
//# sourceMappingURL=RepeatableForm.test.js.map