import React, { useState } from 'react'; import { fireEvent, getByText, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { axe } from 'jest-axe'; import { Button } from '@leafygreen-ui/button'; import { Icon } from '@leafygreen-ui/icon'; import { typeIs } from '@leafygreen-ui/lib'; import { H1 } from '@leafygreen-ui/typography'; import { SegmentedControlOption } from '../SegmentedControlOption/SegmentedControlOption'; import { SegmentedControl } from './SegmentedControl'; const testClassName = 'test-class-name'; const renderNewContainer = () => { const rendered = render( Apple } > Banana , ); const apple = getByText(rendered.container, 'Apple').closest( 'button', ) as Element; const banana = getByText(rendered.container, 'Banana').closest( 'button', ) as Element; return { ...rendered, apple, banana, }; }; const ExternallyControlledExample = () => { const [selected, setSelected] = useState('foo'); return (
{ setSelected(val); }} > Foo Bar
); }; const getComponentFromContainer = (container: HTMLElement) => { const { firstChild: component } = container; if (!typeIs.element(component)) { throw new Error( `Could not find segmented control container element in: ${container.outerHTML}`, ); } return component; }; describe('packages/segmented-control', () => { describe('a11y', () => { // Segmented Control needs to be accessible, but this should not block our React 18 migration work. // https://jira.mongodb.org/browse/LG-2922 // eslint-disable-next-line jest/no-disabled-tests test.skip('does not have basic accessibility issues', async () => { const { container } = renderNewContainer(); const component = getComponentFromContainer(container); const results = await axe(component); expect(results).toHaveNoViolations(); }); test('tab should focus and unfocus the segmented control', () => { const { apple, banana } = renderNewContainer(); expect(apple).not.toHaveFocus(); expect(banana).not.toHaveFocus(); userEvent.tab(); expect(apple).toHaveFocus(); expect(banana).not.toHaveFocus(); userEvent.tab(); expect(apple).not.toHaveFocus(); expect(banana).not.toHaveFocus(); }); test('arrow keys should set focus on the next/previous option', () => { const { apple, banana } = renderNewContainer(); userEvent.tab(); expect(apple).toHaveFocus(); userEvent.type(apple, '{arrowright}'); expect(banana).toHaveFocus(); userEvent.type(banana, '{arrowright}'); expect(apple).toHaveFocus(); userEvent.type(apple, '{arrowleft}'); expect(banana).toHaveFocus(); userEvent.type(banana, '{arrowleft}'); expect(apple).toHaveFocus(); }); test('enter key should select an option', () => { const { apple, banana } = renderNewContainer(); userEvent.tab(); userEvent.type(apple, '{arrowright}'); expect(banana).toHaveFocus(); userEvent.type(banana, '{enter}'); expect(banana).toHaveAttribute('aria-selected', 'true'); }); }); describe('render', () => { test('renders the provided className in classList', () => { const { container } = renderNewContainer(); const component = getComponentFromContainer(container); expect(component.classList).toContain(testClassName); }); test('defaults to first option when no default value is provided', () => { const { apple } = renderNewContainer(); expect(apple).toHaveAttribute('aria-selected', 'true'); }); test('Sets the clicked option to `checked`', () => { const { banana } = renderNewContainer(); userEvent.click(banana); expect(banana).toHaveAttribute('aria-selected', 'true'); }); test('sets default value when provided', async () => { const { container } = render( Apple Banana , ); const banana = getByText(container, 'Banana').closest('button'); expect(banana).toHaveAttribute('aria-selected', 'true'); }); test('glyph', () => { const { getByTestId } = renderNewContainer(); expect(getByTestId('glyph')).toBeInTheDocument(); }); test('warning if LeafyGreen UI Glyph is not passed as Glyph', () => { const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); render( You caught me}> Apple Banana Orange , ); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith( 'Please provide a LeafyGreen UI Icon or Glyph component.', ); spy.mockClear(); }); }); describe('when uncontrolled', () => { test('clicking a new option changes the selected option', () => { const { apple, banana } = renderNewContainer(); userEvent.click(banana); expect(banana).toHaveAttribute('aria-selected', 'true'); userEvent.click(apple); expect(apple).toHaveAttribute('aria-selected', 'true'); }); }); describe('when controlled', () => { test('changing the "value" prop changes the selected option', () => { const testControlledComponent = (value: string) => { return ( Apple } > Banana ); }; const { container, rerender } = render(testControlledComponent('banana')); const banana = getByText(container, 'Banana').closest('button'); const apple = getByText(container, 'Apple').closest('button'); expect(banana).toHaveAttribute('aria-selected', 'true'); rerender(testControlledComponent('apple')); expect(apple).toHaveAttribute('aria-selected', 'true'); }); test('when controlled externally', () => { const { container } = render(); const foo = getByText(container, 'Foo').closest('button'); const bar = getByText(container, 'Bar').closest('button'); const button = getByText(container, 'Select Bar').closest('button'); expect(foo).toHaveAttribute('aria-selected', 'true'); fireEvent.click(button!); expect(bar).toHaveAttribute('aria-selected', 'true'); fireEvent.click(foo!); expect(foo).toHaveAttribute('aria-selected', 'true'); }); }); });