import { render, screen } from '@testing-library/react' import React from 'react' import { Description, Field, Fieldset, Label } from '..' import { assertActiveElement, assertDisabledish, assertLinkedWithDescription, assertLinkedWithLabel, getControl, getDescriptions, getLabel, getLabels, } from './accessibility-assertions' import { click } from './interactions' import { suppressConsoleLogs } from './suppress-console-logs' export function commonControlScenarios(Control: React.ComponentType) { describe('Rendering composition', () => { describe('Inside `Field`', () => { it('should mark the control as disabled, if the `Field` is disabled', () => { render( ) assertDisabledish(getControl()) }) it('should link a control and a `Label` when inside a `Field`', () => { render( ) assertLinkedWithLabel(getControl(), getLabels()) }) it('should link a control and multiple `Label` components when inside a `Field`', () => { render( ) assertLinkedWithLabel(getControl(), getLabels()) }) it('should link a control and a `Description` when inside a `Field`', () => { render( My Description ) assertLinkedWithDescription(getControl(), getDescriptions()) }) it('should link a control and multiple `Description` components when inside a `Field`', () => { render( My Description #1 My Description #2 My Description #3 ) assertLinkedWithDescription(getControl(), getDescriptions()) }) it('should link a control with a `Label` and a `Description` when inside a `Field`', () => { render( My Description ) assertLinkedWithDescription(getControl(), getDescriptions()) assertLinkedWithLabel(getControl(), getLabels()) }) }) }) describe('Mouse interactions', () => { describe('Inside `Field`', () => { it('should be possible to click a `Label`, and focus the control when in a `Field`', async () => { render( ) assertActiveElement(document.body) await click(getLabel()) assertActiveElement(getControl()) }) it('should not be possible to click a `Label`, if the `Label` has the `passive` prop', async () => { render( ) assertActiveElement(document.body) await click(getLabel()) assertActiveElement(document.body) }) it('should not be possible to click a `Label` and focus the control, if the control is disabled', async () => { render( ) assertActiveElement(document.body) await click(getLabel()) assertActiveElement(document.body) }) it('should not be possible to click a `Label` and focus the control, if the `Field` is disabled', async () => { render( ) assertActiveElement(document.body) await click(getLabel()) assertActiveElement(document.body) }) }) describe('Inside `Fieldset`', () => { it('should not be possible to click a `Label` and focus the control, if the `Fieldset` is disabled', async () => { render(
) assertActiveElement(document.body) await click(getLabel()) assertActiveElement(document.body) }) }) }) } export function commonFormScenarios( Control: React.ComponentType, { performUserInteraction, }: { performUserInteraction: (control: HTMLElement | null) => PromiseLike } ) { describe('Form compatibility', () => { it('should render native (hidden) form elements for the control', () => { render(
) expect(document.querySelector('[name=foo]')).toBeInTheDocument() }) it('should submit the form with all the data', async () => { let formDataMock = jest.fn() render(
{ e.preventDefault() formDataMock(new FormData(e.target as HTMLFormElement)) }} > ) // Submit form await click(screen.getByText('Submit')) // Ensure the form was submitted with the `foo` input present expect(formDataMock.mock.calls[0][0].has('foo')).toBe(true) }) it('should not submit the data if the control is disabled', async () => { let submits = jest.fn() function Example() { return (
{ event.preventDefault() submits([...new FormData(event.currentTarget).entries()]) }} > ) } render() // Submit the form await click(screen.getByText('Submit')) // Verify that the form has been submitted expect(submits).toHaveBeenLastCalledWith([ ['foo', 'bar'], // The only available field ]) }) it( 'should reset the control when the form is reset', suppressConsoleLogs(async () => { let formDataMock = jest.fn() render(
{ e.preventDefault() formDataMock(new FormData(e.target as HTMLFormElement)) }} >
) // Submit the form to get the initial state of the form await click(screen.getByText('Submit')) let formState = Object.fromEntries(formDataMock.mock.calls[0][0]) // Make changes to the control await performUserInteraction(getControl()) // Submit form await click(screen.getByText('Submit')) // Ensure the form was, and the values are different let newFormState = Object.fromEntries(formDataMock.mock.calls[1][0]) expect(newFormState).not.toEqual(formState) // Reset the form await click(screen.getByText('Reset')) // Ensure the form was reset await click(screen.getByText('Submit')) // Ensure the form state looks like the initial state let resetFormState = Object.fromEntries(formDataMock.mock.calls[2][0]) expect(resetFormState).toEqual(formState) }) ) }) } export function commonRenderingScenarios( Control: React.ComponentType, { getElement }: { getElement: () => HTMLElement | null } ) { describe('Rendering', () => { it('should render a control', async () => { render() expect(getElement()).toBeInTheDocument() }) it('should have an `id` attached', () => { render() expect(getElement()).toHaveAttribute('id') }) it('should be possible to override the `id`', () => { render() expect(getElement()).toHaveAttribute('id', 'foo') }) }) }