import { Checkbox , CheckboxGroup } from "@components/checkbox" ; import { act , waitFor } from "@testing-library/react" ; import { ToggleButton } from "@components/button" ; import { createRef } from "react" ; import { renderWithTheme } from "@jest-utils" ; import userEvent from "@testing-library/user-event" ; function getInput ( element ) { return element . querySelector ( "input" ) ; } test ( "when autofocus is true, the first checkbox is focused on render" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup autoFocus > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . toHaveFocus ( ) ) ; } ) ; test ( "when autofocus is true and the checkbox group is disabled, no checkboxes of the group are focused on render" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup autoFocus disabled > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . not . toHaveFocus ( ) ) ; } ) ; test ( "when autofocus is true and the first checkbox is disabled, the next checkbox is focused on render" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup autoFocus > < Checkbox data - testid = "checkbox" disabled value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . not . toHaveFocus ( ) ) ; await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 1 ] ) ) . toHaveFocus ( ) ) ; } ) ; test ( "when autofocus is true and there is a default value, the first checkbox is focused on render" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup autoFocus defaultValue = { [ "2" ] } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . toHaveFocus ( ) ) ; } ) ; test ( "when autofocus is specified with a delay, the first checkbox is focused after the delay" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup autoFocus = { 10 } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . not . toHaveFocus ( ) ; await waitFor ( ( ) => expect ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) . toHaveFocus ( ) ) ; } ) ; test ( "when a checkbox value is not provided, the value is autogenerated" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < Checkbox data - testid = "checkbox" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" > 3 < /Checkbox> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 1 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 2 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ "0" , "1" , "2" ] ) ) ; } ) ; test ( "when a checkbox group elements are not checkbox, their role is \"checkbox\"" , async ( ) => { const { getAllByTestId } = renderWithTheme ( < CheckboxGroup > < ToggleButton data - testid = "checkbox" value = "1" > 1 < /ToggleButton> < ToggleButton data - testid = "checkbox" value = "2" > 2 < /ToggleButton> < ToggleButton data - testid = "checkbox" value = "3" > 3 < /ToggleButton> < /CheckboxGroup>); await waitFor ( ( ) => expect ( getAllByTestId ( "checkbox" ) [ 0 ] ) . toHaveAttribute ( "role" , "checkbox" ) ) ; await waitFor ( ( ) => expect ( getAllByTestId ( "checkbox" ) [ 1 ] ) . toHaveAttribute ( "role" , "checkbox" ) ) ; await waitFor ( ( ) => expect ( getAllByTestId ( "checkbox" ) [ 2 ] ) . toHaveAttribute ( "role" , "checkbox" ) ) ; } ) ; test ( "call onChange when a single checkbox is selected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ "1" ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 1 ) ) ; } ) ; test ( "call onChange when multiple checkbox are selected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); const buttons = getAllByTestId ( "checkbox" ) ; act ( ( ) => { userEvent . click ( getInput ( buttons [ 0 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( buttons [ 2 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ "1" , "3" ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 2 ) ) ; } ) ; test ( "call onChange when a checkbox is unselected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); const buttons = getAllByTestId ( "checkbox" ) ; act ( ( ) => { userEvent . click ( getInput ( buttons [ 0 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( buttons [ 2 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( buttons [ 0 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ "3" ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 3 ) ) ; } ) ; test ( "pass an empty array when no checkbox are selected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < Checkbox data - testid = "checkbox" value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 2 ) ) ; } ) ; test ( "call the checkbox onValueChange handler when a checkbox is selected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup > < Checkbox data - testid = "checkbox" onValueChange = { handler } value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , true ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 1 ) ) ; } ) ; test ( "call the checkbox onChange handler when a checkbox is selected" , async ( ) => { const handler = jest . fn ( ) ; const { getAllByTestId } = renderWithTheme ( < CheckboxGroup > < Checkbox data - testid = "checkbox" onChange = { handler } value = "1" > 1 < /Checkbox> < Checkbox data - testid = "checkbox" value = "2" > 2 < /Checkbox> < Checkbox data - testid = "checkbox" value = "3" > 3 < /Checkbox> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getInput ( getAllByTestId ( "checkbox" ) [ 0 ] ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , true ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 1 ) ) ; } ) ; test ( "ref is a DOM element" , async ( ) => { const ref = createRef < HTMLElement > ( ) ; renderWithTheme ( < CheckboxGroup ref = { ref } > < Checkbox value = "1" > 1 < /Checkbox> < Checkbox value = "2" > 2 < /Checkbox> < Checkbox value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( ref . current ) . not . toBeNull ( ) ) ; await waitFor ( ( ) => expect ( ref . current instanceof HTMLElement ) . toBeTruthy ( ) ) ; await waitFor ( ( ) => expect ( ref . current . tagName ) . toBe ( "DIV" ) ) ; await waitFor ( ( ) => expect ( ref . current . getAttribute ( "role" ) ) . toBe ( "group" ) ) ; } ) ; test ( "when using a callback ref, ref is a DOM element" , async ( ) => { let refNode = null ; renderWithTheme ( < CheckboxGroup ref = { node => { refNode = node ; } } > < Checkbox value = "1" > 1 < /Checkbox> < Checkbox value = "2" > 2 < /Checkbox> < Checkbox value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( refNode ) . not . toBeNull ( ) ) ; await waitFor ( ( ) => expect ( refNode instanceof HTMLElement ) . toBeTruthy ( ) ) ; await waitFor ( ( ) => expect ( refNode . tagName ) . toBe ( "DIV" ) ) ; await waitFor ( ( ) => expect ( refNode . getAttribute ( "role" ) ) . toBe ( "group" ) ) ; } ) ; test ( "set ref once" , async ( ) => { const handler = jest . fn ( ) ; renderWithTheme ( < CheckboxGroup ref = { handler } > < Checkbox value = "1" > 1 < /Checkbox> < Checkbox value = "2" > 2 < /Checkbox> < Checkbox value = "3" > 3 < /Checkbox> < /CheckboxGroup>); await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 1 ) ) ; } ) ; describe ( "with toggle buttons" , ( ) => { test ( "a toggled button have aria-checked set to \"true\"" , async ( ) => { const { getByTestId } = renderWithTheme ( < CheckboxGroup > < ToggleButton data - testid = "button-1" value = "1" > 1 < /ToggleButton> < ToggleButton value = "2" > 2 < /ToggleButton> < ToggleButton value = "3" > 3 < /ToggleButton> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getByTestId ( "button-1" ) ) ; } ) ; await waitFor ( ( ) => expect ( getByTestId ( "button-1" ) ) . toHaveAttribute ( "aria-checked" , "true" ) ) ; } ) ; test ( "call onChange when a button is toggled" , async ( ) => { const handler = jest . fn ( ) ; const { getByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < ToggleButton data - testid = "button-1" value = "1" > 1 < /ToggleButton> < ToggleButton value = "2" > 2 < /ToggleButton> < ToggleButton value = "3" > 3 < /ToggleButton> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getByTestId ( "button-1" ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ "1" ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 1 ) ) ; } ) ; test ( "call onChange when a button is untoggled" , async ( ) => { const handler = jest . fn ( ) ; const { getByTestId } = renderWithTheme ( < CheckboxGroup onChange = { handler } > < ToggleButton data - testid = "button-1" value = "1" > 1 < /ToggleButton> < ToggleButton value = "2" > 2 < /ToggleButton> < ToggleButton value = "3" > 3 < /ToggleButton> < /CheckboxGroup>); act ( ( ) => { userEvent . click ( getByTestId ( "button-1" ) ) ; } ) ; act ( ( ) => { userEvent . click ( getByTestId ( "button-1" ) ) ; } ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenLastCalledWith ( expect . anything ( ) , [ ] ) ) ; await waitFor ( ( ) => expect ( handler ) . toHaveBeenCalledTimes ( 2 ) ) ; } ) ; } ) ;