From 6af4b2a3b6ffb6c12b35dcc3ce0f0d0e1a9c5855 Mon Sep 17 00:00:00 2001 From: Ryan Gossiaux Date: Mon, 27 Dec 2021 15:51:43 -0800 Subject: [PATCH] Add initial RadioGroup tests Basically all the ones that aren't annoying to write --- .../radio-group/_ManagedRadioGroup.svelte | 8 + .../radio-group/radio-group.test.ts | 843 ++++++++++++++++++ 2 files changed, 851 insertions(+) create mode 100644 src/lib/components/radio-group/_ManagedRadioGroup.svelte create mode 100644 src/lib/components/radio-group/radio-group.test.ts diff --git a/src/lib/components/radio-group/_ManagedRadioGroup.svelte b/src/lib/components/radio-group/_ManagedRadioGroup.svelte new file mode 100644 index 0000000..49793ab --- /dev/null +++ b/src/lib/components/radio-group/_ManagedRadioGroup.svelte @@ -0,0 +1,8 @@ + + + (value = e.detail)} on:change> + + diff --git a/src/lib/components/radio-group/radio-group.test.ts b/src/lib/components/radio-group/radio-group.test.ts new file mode 100644 index 0000000..318c95c --- /dev/null +++ b/src/lib/components/radio-group/radio-group.test.ts @@ -0,0 +1,843 @@ +import { assertActiveElement, assertFocusable, assertNotFocusable, assertRadioGroupLabel, getByText, getRadioGroupOptions } from "$lib/test-utils/accessibility-assertions"; +import { render } from "@testing-library/svelte"; +import { RadioGroup, RadioGroupLabel, RadioGroupOption } from "."; +import { suppressConsoleLogs } from "$lib/test-utils/suppress-console-logs"; +import TestRenderer from "$lib/test-utils/TestRenderer.svelte"; +import { click, Keys, press, shift } from "$lib/test-utils/interactions"; +import Button from "$lib/internal/elements/Button.svelte"; +import ManagedRadioGroup from "./_ManagedRadioGroup.svelte"; + +let id = 0; +jest.mock('../../hooks/use-id', () => { + return { + useId: jest.fn(() => ++id), + } +}) + +beforeEach(() => id = 0) +beforeAll(() => { + // jest.spyOn(window, 'requestAnimationFrame').mockImplementation(setImmediate as any) + // jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(clearImmediate as any) +}) +afterAll(() => jest.restoreAllMocks()) + +describe('Safe guards', () => { + it.each([['RadioGroupOption', RadioGroupOption]])( + 'should error when we are using a <%s /> without a parent ', + suppressConsoleLogs((name, Component) => { + expect(() => render(Component)).toThrowError( + `<${name} /> is missing a parent component.` + ) + }) + ) + + it( + 'should be possible to render a RadioGroup without crashing', + suppressConsoleLogs(async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + assertRadioGroupLabel({ textContent: 'Pizza Delivery' }) + }) + ) + + it('should be possible to render a RadioGroup without options and without crashing', () => { + render(RadioGroup, { value: undefined }) + }) +}) + +describe('Rendering', () => { + it('should be possible to render a RadioGroup, where the first element is tabbable (value is undefined)', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + expect(getRadioGroupOptions()).toHaveLength(3) + + assertFocusable(getByText('Pickup')) + assertNotFocusable(getByText('Home delivery')) + assertNotFocusable(getByText('Dine in')) + }) + + it('should be possible to render a RadioGroup, where the first element is tabbable (value is null)', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: null, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + expect(getRadioGroupOptions()).toHaveLength(3) + + assertFocusable(getByText('Pickup')) + assertNotFocusable(getByText('Home delivery')) + assertNotFocusable(getByText('Dine in')) + }) + + it('should be possible to render a RadioGroup with an active value', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: "home-delivery", onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + expect(getRadioGroupOptions()).toHaveLength(3) + + assertNotFocusable(getByText('Pickup')) + assertFocusable(getByText('Home delivery')) + assertNotFocusable(getByText('Dine in')) + }) + + // it('should guarantee the radio option order after a few unmounts', async () => { + // function Example() { + // let [showFirst, setShowFirst] = useState(false) + // let [active, setActive] = useState() + + // return ( + // <> + // + // + // Pizza Delivery + // {showFirst && Pickup} + // Home delivery + // Dine in + // + // + // ) + // } + + // render() + + // await click(getByText('Toggle')) // Render the pickup again + + // await press(Keys.Tab) // Focus first element + // assertActiveElement(getByText('Pickup')) + + // await press(Keys.ArrowUp) // Loop around + // assertActiveElement(getByText('Dine in')) + + // await press(Keys.ArrowUp) // Up again + // assertActiveElement(getByText('Home delivery')) + // }) + + // it('should be possible to disable a RadioGroup', async () => { + // let changeFn = jest.fn() + + // function Example() { + // let [disabled, setDisabled] = useState(true) + // return ( + // <> + // + // + // Pizza Delivery + // Pickup + // Home delivery + // Dine in + // + // {JSON.stringify} + // + // + // + // ) + // } + + // render() + + // // Try to click one a few options + // await click(getByText('Pickup')) + // await click(getByText('Dine in')) + + // // Verify that the RadioGroup.Option gets the disabled state + // expect(document.querySelector('[data-value="render-prop"]')).toHaveTextContent( + // JSON.stringify({ + // checked: false, + // disabled: true, + // active: false, + // }) + // ) + + // // Make sure that the onChange handler never got called + // expect(changeFn).toHaveBeenCalledTimes(0) + + // // Make sure that all the options get an `aria-disabled` + // let options = getRadioGroupOptions() + // expect(options).toHaveLength(4) + // for (let option of options) expect(option).toHaveAttribute('aria-disabled', 'true') + + // // Toggle the disabled state + // await click(getByText('Toggle')) + + // // Verify that the RadioGroup.Option gets the disabled state + // expect(document.querySelector('[data-value="render-prop"]')).toHaveTextContent( + // JSON.stringify({ + // checked: false, + // disabled: false, + // active: false, + // }) + // ) + + // // Try to click one a few options + // await click(getByText('Pickup')) + + // // Make sure that the onChange handler got called + // expect(changeFn).toHaveBeenCalledTimes(1) + // }) + + // it('should be possible to disable a RadioGroup.Option', async () => { + // let changeFn = jest.fn() + + // function Example() { + // let [disabled, setDisabled] = useState(true) + // return ( + // <> + // + // + // Pizza Delivery + // Pickup + // Home delivery + // Dine in + // + // {JSON.stringify} + // + // + // + // ) + // } + + // render() + + // // Try to click the disabled option + // await click(document.querySelector('[data-value="render-prop"]')) + + // // Verify that the RadioGroup.Option gets the disabled state + // expect(document.querySelector('[data-value="render-prop"]')).toHaveTextContent( + // JSON.stringify({ + // checked: false, + // disabled: true, + // active: false, + // }) + // ) + + // // Make sure that the onChange handler never got called + // expect(changeFn).toHaveBeenCalledTimes(0) + + // // Make sure that the option with value "render-prop" gets an `aria-disabled` + // let options = getRadioGroupOptions() + // expect(options).toHaveLength(4) + // for (let option of options) { + // if (option.dataset.value) { + // expect(option).toHaveAttribute('aria-disabled', 'true') + // } else { + // expect(option).not.toHaveAttribute('aria-disabled') + // } + // } + + // // Toggle the disabled state + // await click(getByText('Toggle')) + + // // Verify that the RadioGroup.Option gets the disabled state + // expect(document.querySelector('[data-value="render-prop"]')).toHaveTextContent( + // JSON.stringify({ + // checked: false, + // disabled: false, + // active: false, + // }) + // ) + + // // Try to click one a few options + // await click(document.querySelector('[data-value="render-prop"]')) + + // // Make sure that the onChange handler got called + // expect(changeFn).toHaveBeenCalledTimes(1) + // }) + // }) + +}) + +describe('Keyboard interactions', () => { + describe('`Tab` key', () => { + it('should be possible to tab to the first item', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + }) + + it('should not change the selected element on focus', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: changeFn }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(0) + }) + + it('should be possible to tab to the active item', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: "home-delivery", onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + await press(Keys.Tab) + + assertActiveElement(getByText('Home delivery')) + }) + + it('should not change the selected element on focus (when selecting the active item)', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: "home-delivery", onChange: changeFn }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + ] + }) + + await press(Keys.Tab) + + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenCalledTimes(0) + }) + + it('should be possible to tab out of the radio group (no selected value)', async () => { + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + await press(Keys.Tab) + assertActiveElement(getByText('Before')) + + await press(Keys.Tab) + assertActiveElement(getByText('Pickup')) + + await press(Keys.Tab) + assertActiveElement(getByText('After')) + }) + + it('should be possible to tab out of the radio group (selected value)', async () => { + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: "home-delivery", onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + await press(Keys.Tab) + assertActiveElement(getByText('Before')) + + await press(Keys.Tab) + assertActiveElement(getByText('Home delivery')) + + await press(Keys.Tab) + assertActiveElement(getByText('After')) + }) + }) + + describe('`Shift+Tab` key', () => { + it('should be possible to tab to the first item', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + + assertActiveElement(getByText('Pickup')) + }) + + it('should not change the selected element on focus', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: undefined, onChange: changeFn }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(0) + }) + + it('should be possible to tab to the active item', async () => { + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: "home-delivery", onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + + assertActiveElement(getByText('Home delivery')) + }) + + it('should not change the selected element on focus (when selecting the active item)', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [RadioGroup, { value: "home-delivery", onChange: changeFn }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"] + ] + }) + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenCalledTimes(0) + }) + + it('should be possible to tab out of the radio group (no selected value)', async () => { + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + assertActiveElement(getByText('Pickup')) + + await press(shift(Keys.Tab)) + assertActiveElement(getByText('Before')) + }) + + it('should be possible to tab out of the radio group (selected value)', async () => { + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: "home-delivery", onChange: console.log }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + getByText('After')?.focus() + + await press(shift(Keys.Tab)) + assertActiveElement(getByText('Home delivery')) + + await press(shift(Keys.Tab)) + assertActiveElement(getByText('Before')) + }) + }) + + describe('`ArrowLeft` key', () => { + it('should go to the previous item when pressing the ArrowLeft key', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.ArrowLeft) // Loop around + assertActiveElement(getByText('Dine in')) + + await press(Keys.ArrowLeft) + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenCalledTimes(2) + expect(changeFn).toHaveBeenNthCalledWith(1, 'dine-in') + expect(changeFn).toHaveBeenNthCalledWith(2, 'home-delivery') + }) + }) + + describe('`ArrowUp` key', () => { + it('should go to the previous item when pressing the ArrowUp key', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.ArrowUp) // Loop around + assertActiveElement(getByText('Dine in')) + + await press(Keys.ArrowUp) + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenCalledTimes(2) + expect(changeFn).toHaveBeenNthCalledWith(1, 'dine-in') + expect(changeFn).toHaveBeenNthCalledWith(2, 'home-delivery') + }) + }) + + describe('`ArrowRight` key', () => { + it('should go to the next item when pressing the ArrowRight key', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.ArrowRight) + assertActiveElement(getByText('Home delivery')) + + await press(Keys.ArrowRight) + assertActiveElement(getByText('Dine in')) + + await press(Keys.ArrowRight) // Loop around + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(3) + expect(changeFn).toHaveBeenNthCalledWith(1, 'home-delivery') + expect(changeFn).toHaveBeenNthCalledWith(2, 'dine-in') + expect(changeFn).toHaveBeenNthCalledWith(3, 'pickup') + }) + }) + + describe('`ArrowDown` key', () => { + it('should go to the next item when pressing the ArrowDown key', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.ArrowDown) + assertActiveElement(getByText('Home delivery')) + + await press(Keys.ArrowDown) + assertActiveElement(getByText('Dine in')) + + await press(Keys.ArrowDown) // Loop around + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(3) + expect(changeFn).toHaveBeenNthCalledWith(1, 'home-delivery') + expect(changeFn).toHaveBeenNthCalledWith(2, 'dine-in') + expect(changeFn).toHaveBeenNthCalledWith(3, 'pickup') + }) + }) + + describe('`Space` key', () => { + it('should select the current option when pressing space', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.Space) + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(1) + expect(changeFn).toHaveBeenNthCalledWith(1, 'pickup') + }) + + it('should select the current option only once when pressing space', async () => { + let changeFn = jest.fn() + + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [ManagedRadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + // Focus the "Before" button + await press(Keys.Tab) + + // Focus the RadioGroup + await press(Keys.Tab) + + assertActiveElement(getByText('Pickup')) + + await press(Keys.Space) + await press(Keys.Space) + await press(Keys.Space) + await press(Keys.Space) + await press(Keys.Space) + assertActiveElement(getByText('Pickup')) + + expect(changeFn).toHaveBeenCalledTimes(1) + expect(changeFn).toHaveBeenNthCalledWith(1, 'pickup') + }) + }) +}) + +describe('Mouse interactions', () => { + it('should be possible to change the current radio group value when clicking on a radio option', async () => { + let changeFn = jest.fn() + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [RadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + await click(getByText('Home delivery')) + + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenNthCalledWith(1, 'home-delivery') + }) + + it('should be a no-op when clicking on the same item', async () => { + let changeFn = jest.fn() + + render( + TestRenderer, { + allProps: [ + [Button, {}, "Before"], + [ManagedRadioGroup, { value: undefined, onChange: (e: CustomEvent) => changeFn(e.detail) }, [ + [RadioGroupLabel, {}, "Pizza Delivery"], + [RadioGroupOption, { value: "pickup" }, "Pickup"], + [RadioGroupOption, { value: "home-delivery" }, "Home delivery"], + [RadioGroupOption, { value: "dine-in" }, "Dine in"], + ]], + [Button, {}, "After"], + ] + }) + + await click(getByText('Home delivery')) + await click(getByText('Home delivery')) + await click(getByText('Home delivery')) + await click(getByText('Home delivery')) + + assertActiveElement(getByText('Home delivery')) + + expect(changeFn).toHaveBeenCalledTimes(1) + }) +})