import React from 'react';
import { render, fireEvent, cleanup, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SchemaRenderer, Schema } from './SchemaRenderer';
import { componentTypes } from '../ComponentMapper';
import { templateTypes } from '../TemplateMapper';
import { validatorTypes } from '../ValidatorMapper';
describe('SchemaRenderer', () => {
afterEach(() => {
jest.resetAllMocks();
cleanup();
});
const handleCancel = jest.fn();
const handleSubmit = jest.fn();
const baseSchema: Schema = {
title: 'title',
description: 'description',
type: templateTypes.FORM,
fields: [],
};
describe('Basic Form', () => {
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.INPUT,
name: 'name',
labelText: 'Name',
isRequired: true,
},
],
};
it('should render header and description', () => {
const { getByText } = render(
);
expect(getByText('title')).toBeVisible();
expect(getByText('description')).toBeVisible();
expect(getByText('Cancel').parentElement).toBeDisabled();
});
it('should trigger cancel event when user clicks the Cancel button', () => {
const { getByText, getByLabelText } = render(
);
act(() => {
fireEvent.change(getByLabelText('Name'), {
target: { value: 'my name' },
});
});
expect(getByText('Cancel').parentElement).not.toBeDisabled();
act(() => {
userEvent.click(getByText('Cancel'));
expect(handleCancel).toHaveBeenCalled();
});
});
it('should trigger submit with the data', () => {
const { getByLabelText, getByText } = render(
);
act(() => {
fireEvent.change(getByLabelText('Name'), {
target: { value: 'my name' },
});
fireEvent.click(getByText('Submit'));
});
expect(handleSubmit).toHaveBeenCalledWith(
{ name: 'my name' },
expect.any(Object),
expect.any(Function)
);
});
it('should render custom label for cancel and submit button', () => {
const customLabelsSchema = {
...schema,
submitLabel: 'Custom Submit Label',
cancelLabel: 'Custom Cancel Label',
};
const { getByText } = render(
);
expect(getByText('Custom Submit Label')).toBeVisible();
expect(getByText('Custom Cancel Label')).toBeVisible();
});
});
describe('Checkbox', () => {
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.CHECKBOX,
name: 'checkbox',
label: 'Checkbox',
options: [
{
labelText: 'Option 1',
value: '1',
},
{
labelText: 'Option 2',
value: '2',
},
{
labelText: 'Option 3',
value: '3',
},
],
required: true,
validate: [
{
type: validatorTypes.REQUIRED,
},
],
},
],
};
it('should render checkboxes', () => {
const { getByLabelText, getByText } = render(
);
fireEvent.click(getByLabelText('Option 1'));
fireEvent.click(getByLabelText('Option 3'));
fireEvent.click(getByText('Submit'));
expect(handleSubmit).toHaveBeenCalledWith(
{ checkbox: ['1', '3'] },
expect.any(Object),
expect.any(Function)
);
});
it('should trigger validation', () => {
const { getByText } = render(
);
fireEvent.click(getByText('Submit'));
expect(getByText('Required')).toBeVisible();
});
});
describe('Custom', () => {
it('renders custom component', () => {
const CustomComponentSimple = ({ labelText }: any) => <>{labelText}>;
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.CUSTOM,
name: 'custom',
labelText: 'This is the content of custom component',
customComponent: CustomComponentSimple,
},
],
};
const { getByText } = render(
);
expect(
getByText('This is the content of custom component')
).toBeVisible();
});
it('supports interaction', () => {
const CustomComponentComplex = ({ input }: any) => (
);
const handleSubmit = jest.fn();
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.CUSTOM,
name: 'text',
customComponent: CustomComponentComplex,
},
],
};
const { getByTestId, getByText } = render(
);
expect(getByTestId('input')).toHaveValue('initial input');
act(() => {
fireEvent.change(getByTestId('input'), {
target: { value: 'updated input' },
});
fireEvent.click(getByText('Submit'));
});
expect(handleSubmit).toHaveBeenCalledWith(
{
text: 'updated input',
},
expect.any(Object),
expect.any(Function)
);
});
});
describe('Toggle', () => {
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.TOGGLE,
name: 'toggle',
labelText: 'Toggle',
initialValue: false,
},
],
};
it('should render Toggle', async () => {
const { getByLabelText, getByText } = render(
);
expect(getByLabelText('Toggle')).toBeInTheDocument();
fireEvent.click(getByText('Submit'));
expect(handleSubmit).toHaveBeenCalledWith(
{ toggle: false },
expect.any(Object),
expect.any(Function)
);
});
});
describe('Radio', () => {
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.RADIO,
name: 'radio',
labelText: 'Radio',
options: [
{
labelText: 'Option 1',
value: '1',
},
{
labelText: 'Option 2',
value: '2',
},
{
labelText: 'Option 3',
value: '3',
},
],
required: true,
validate: [
{
type: validatorTypes.REQUIRED,
},
],
},
],
};
it('should render radio buttons', () => {
const { getByLabelText, getByText, getAllByRole } = render(
);
expect(getByText('Radio')).toBeVisible();
expect(getAllByRole('radio')).toHaveLength(3);
fireEvent.click(getByLabelText('Option 3'));
fireEvent.click(getByText('Submit'));
expect(handleSubmit).toHaveBeenCalledWith(
{ radio: '3' },
expect.any(Object),
expect.any(Function)
);
});
it('should trigger validation', () => {
const { getByText } = render(
);
fireEvent.click(getByText('Submit'));
expect(getByText('Required')).toBeVisible();
});
});
describe('FieldArray', () => {
const schema = {
...baseSchema,
fields: [
{
component: componentTypes.FIELD_ARRAY,
description: 'This is a form array',
name: 'fieldArray',
minItems: 1,
maxItems: 3,
noItemsMessage: 'There are currently no items',
defaultItem: {
key: 'key',
value: 'value',
},
validate: [
{
type: validatorTypes.MIN_ITEMS,
threshold: 1,
},
{
type: validatorTypes.REQUIRED,
},
],
fields: [
{
component: componentTypes.INPUT,
name: 'key',
labelText: 'Key',
validate: [
{
type: validatorTypes.REQUIRED,
},
],
},
{
component: componentTypes.INPUT,
name: 'value',
labelText: 'Value',
validate: [
{
type: validatorTypes.REQUIRED,
},
],
},
],
},
],
};
it('should render FieldArray', () => {
const { getByText, getAllByRole, getByLabelText } = render(
);
expect(getByText('This is a form array')).toBeVisible();
expect(getByText('There are currently no items')).toBeVisible();
act(() => {
fireEvent.click(getAllByRole('button')[0]);
});
expect(getByText('Key')).toBeVisible();
expect(getByText('Value')).toBeVisible();
// expect(queryByText('There are currently no items')).not.toBeInTheDocument;
act(() => {
fireEvent.change(getByLabelText('Key'), { target: { value: 'key' } });
fireEvent.change(getByLabelText('Value'), {
target: { value: 'value' },
});
fireEvent.click(getByText('Submit'));
});
expect(handleSubmit).toHaveBeenCalledWith(
{
fieldArray: [
{
key: 'key',
value: 'value',
},
],
},
expect.any(Object),
expect.any(Function)
);
});
});
});