import { useCallback, FormEvent } from 'react' import { Button, Form, FormControl } from 'react-bootstrap' import { Select, SelectProps, } from '../../../../frontend/js/shared/components/select' const testData = [1, 2, 3].map(index => ({ key: index, value: `Demo item ${index}`, sub: `Subtitle ${index}`, })) type RenderProps = Partial> & { onSubmit?: (formData: object) => void } function render(props: RenderProps) { const submitHandler = (event: FormEvent) => { event.preventDefault() if (props.onSubmit) { const formData = new FormData(event.target as HTMLFormElement) // a plain object is more convenient to work later with assertions props.onSubmit(Object.fromEntries(formData.entries())) } } cy.mount(
', function () { describe('initial rendering', function () { it('renders default text', function () { render({ defaultText: 'Choose an item' }) cy.findByTestId('spinner').should('not.exist') cy.findByText('Choose an item') }) it('renders default item', function () { render({ defaultItem: testData[2] }) cy.findByText('Demo item 3') }) it('default item takes precedence over default text', function () { render({ defaultText: 'Choose an item', defaultItem: testData[2] }) cy.findByText('Demo item 3') }) it('renders label', function () { render({ defaultText: 'Choose an item', label: 'test label', optionalLabel: false, }) cy.findByText('test label') cy.findByText('(Optional)').should('not.exist') }) it('renders optional label', function () { render({ defaultText: 'Choose an item', label: 'test label', optionalLabel: true, }) cy.findByText('test label') cy.findByText('(Optional)') }) it('renders a spinner while loading when there is a label', function () { render({ defaultText: 'Choose an item', label: 'test label', loading: true, }) cy.findByTestId('spinner') }) it('does not render a spinner while loading if there is no label', function () { render({ defaultText: 'Choose an item', loading: true, }) cy.findByTestId('spinner').should('not.exist') }) }) describe('items rendering', function () { it('renders all items', function () { render({ defaultText: 'Choose an item' }) cy.findByText('Choose an item').click() cy.findByText('Demo item 1') cy.findByText('Demo item 2') cy.findByText('Demo item 3') }) it('renders subtitles', function () { render({ defaultText: 'Choose an item', itemToSubtitle: x => String(x?.sub), }) cy.findByText('Choose an item').click() cy.findByText('Subtitle 1') cy.findByText('Subtitle 2') cy.findByText('Subtitle 3') }) }) describe('item selection', function () { it('cannot select an item when disabled', function () { render({ defaultText: 'Choose an item', disabled: true }) cy.findByText('Choose an item').click() cy.findByText('Demo item 1').should('not.exist') cy.findByText('Demo item 2').should('not.exist') cy.findByText('Demo item 3').should('not.exist') cy.findByText('Choose an item') }) it('renders only the selected item after selection', function () { render({ defaultText: 'Choose an item' }) cy.findByText('Choose an item').click() cy.findByText('Demo item 1') cy.findByText('Demo item 2') cy.findByText('Demo item 3').click() cy.findByText('Choose an item').should('not.exist') cy.findByText('Demo item 1').should('not.exist') cy.findByText('Demo item 2').should('not.exist') cy.findByText('Demo item 3') }) it('invokes callback after selection', function () { const selectionHandler = cy.stub().as('selectionHandler') render({ defaultText: 'Choose an item', onSelectedItemChanged: selectionHandler, }) cy.findByText('Choose an item').click() cy.findByText('Demo item 2').click() cy.get('@selectionHandler').should( 'have.been.calledOnceWith', testData[1] ) }) }) describe('when the form is submitted', function () { it('populates FormData with the default selected item', function () { const submitHandler = cy.stub().as('submitHandler') render({ defaultItem: testData[1], onSubmit: submitHandler }) cy.findByText('submit').click() cy.get('@submitHandler').should('have.been.calledOnceWith', { select_control: 'Demo item 2', }) }) it('populates FormData with the selected item', function () { const submitHandler = cy.stub().as('submitHandler') render({ defaultItem: testData[1], onSubmit: submitHandler }) cy.findByText('Demo item 2').click() // open dropdown cy.findByText('Demo item 3').click() // choose a different item cy.findByText('submit').click() cy.get('@submitHandler').should('have.been.calledOnceWith', { select_control: 'Demo item 3', }) }) it('does not populate FormData when no item is selected', function () { const submitHandler = cy.stub().as('submitHandler') render({ defaultText: 'Choose an item', onSubmit: submitHandler }) cy.findByText('submit').click() cy.get('@submitHandler').should('have.been.calledOnceWith', {}) }) }) describe('with react-bootstrap forms', function () { type FormWithSelectProps = { onSubmit: (formData: object) => void } const FormWithSelect = ({ onSubmit }: FormWithSelectProps) => { const selectComponent = useCallback( () => (