From 5ca7d4aa20e2bca452764a8d98c903d1c9e9ab2d Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Thu, 6 Aug 2026 17:44:30 +0200 Subject: [PATCH 1/2] test(react-swatch-picker): add hook state coverage --- .../ColorSwatch/useColorSwatch.test.tsx | 101 ++++++++++++++++++ .../EmptySwatch/useEmptySwatch.test.tsx | 64 +++++++++++ .../ImageSwatch/useImageSwatch.test.tsx | 100 +++++++++++++++++ .../SwatchPicker/useSwatchPicker.test.tsx | 58 ++++++++++ .../useSwatchPickerRow.test.tsx | 37 +++++++ 5 files changed, 360 insertions(+) create mode 100644 packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx create mode 100644 packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx create mode 100644 packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx create mode 100644 packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx create mode 100644 packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx diff --git a/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx new file mode 100644 index 00000000000000..541e7469bf65c0 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx @@ -0,0 +1,101 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { useColorSwatch_unstable } from './useColorSwatch'; + +describe('useColorSwatch', () => { + it('returns the default state', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref)); + + expect(result.current.color).toBe('#ff0000'); + expect(result.current.value).toBe('red'); + expect(result.current.selected).toBe(false); + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses state from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + expect(result.current.selected).toBe(true); + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-selected']).toBe(true); + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('prefers props over context', () => { + const ref = React.createRef(); + const { result } = renderHook( + () => useColorSwatch_unstable({ color: '#ff0000', shape: 'rounded', size: 'extra-small', value: 'red' }, ref), + { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }, + ); + + expect(result.current.size).toBe('extra-small'); + expect(result.current.shape).toBe('rounded'); + }); + + it('forwards requested selection changes', () => { + const requestSelectionChange = jest.fn(); + const event = {} as React.MouseEvent; + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + act(() => result.current.root.onClick?.(event)); + + expect(requestSelectionChange).toHaveBeenCalledTimes(1); + expect(requestSelectionChange).toHaveBeenCalledWith(event, { + selectedValue: 'red', + selectedSwatch: '#ff0000', + }); + }); +}); diff --git a/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx new file mode 100644 index 00000000000000..1725f5abd5e8b3 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { useEmptySwatch_unstable } from './useEmptySwatch'; + +describe('useEmptySwatch', () => { + it('returns the default state', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref)); + + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses state from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-checked']).toBeUndefined(); + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('prefers props over context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({ shape: 'rounded', size: 'extra-small' }, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + expect(result.current.size).toBe('extra-small'); + expect(result.current.shape).toBe('rounded'); + }); +}); diff --git a/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx new file mode 100644 index 00000000000000..4e76f86b30869d --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx @@ -0,0 +1,100 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { useImageSwatch_unstable } from './useImageSwatch'; + +describe('useImageSwatch', () => { + it('returns the default state', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref)); + + expect(result.current.value).toBe('image'); + expect(result.current.selected).toBe(false); + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses state from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + expect(result.current.selected).toBe(true); + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-selected']).toBe(true); + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('uses context over props', () => { + const ref = React.createRef(); + const { result } = renderHook( + () => useImageSwatch_unstable({ shape: 'rounded', size: 'extra-small', src: 'image.png', value: 'image' }, ref), + { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }, + ); + + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('forwards requested selection changes', () => { + const requestSelectionChange = jest.fn(); + const event = {} as React.MouseEvent; + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + act(() => result.current.root.onClick?.(event)); + + expect(requestSelectionChange).toHaveBeenCalledTimes(1); + expect(requestSelectionChange).toHaveBeenCalledWith(event, { + selectedValue: 'image', + selectedSwatch: 'image.png', + }); + }); +}); diff --git a/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx new file mode 100644 index 00000000000000..3893c24f83c662 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useSwatchPicker_unstable } from './useSwatchPicker'; + +describe('useSwatchPicker', () => { + it('returns the default state', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({}, ref)); + + expect(result.current.isGrid).toBe(false); + expect(result.current.root.role).toBe('radiogroup'); + expect(result.current.root).toHaveProperty('data-tabster', expect.any(String)); + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBeUndefined(); + expect(result.current.spacing).toBe('medium'); + }); + + it('returns state based on props', () => { + const ref = React.createRef(); + const { result } = renderHook(() => + useSwatchPicker_unstable( + { + defaultSelectedValue: 'red', + layout: 'grid', + shape: 'circular', + size: 'large', + spacing: 'small', + }, + ref, + ), + ); + + expect(result.current.isGrid).toBe(true); + expect(result.current.root.role).toBe('grid'); + expect(result.current.selectedValue).toBe('red'); + expect(result.current.shape).toBe('circular'); + expect(result.current.size).toBe('large'); + expect(result.current.spacing).toBe('small'); + }); + + it('forwards requested selection changes', () => { + const onSelectionChange = jest.fn(); + const event = {} as React.MouseEvent; + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({ onSelectionChange }, ref)); + + act(() => result.current.requestSelectionChange(event, { selectedValue: 'red', selectedSwatch: '#ff0000' })); + + expect(result.current.selectedValue).toBe('red'); + expect(onSelectionChange).toHaveBeenCalledTimes(1); + expect(onSelectionChange).toHaveBeenCalledWith(event, { + type: 'click', + event, + selectedValue: 'red', + selectedSwatch: '#ff0000', + }); + }); +}); diff --git a/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx new file mode 100644 index 00000000000000..b571f9aae00867 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { useSwatchPickerRow_unstable } from './useSwatchPickerRow'; + +describe('useSwatchPickerRow', () => { + it('returns the default state', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref)); + + expect(result.current.root.role).toBe('row'); + expect(result.current.spacing).toBe('medium'); + }); + + it('uses spacing from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref), { + wrapper: ({ children }: { children: React.ReactNode }) => ( + + {children} + + ), + }); + + expect(result.current.root.role).toBe('row'); + expect(result.current.spacing).toBe('small'); + }); +}); From 3cb1ea9489634a66ea18faaec05119093e7504ce Mon Sep 17 00:00:00 2001 From: Dmytro Kirpa Date: Thu, 6 Aug 2026 20:58:32 +0200 Subject: [PATCH 2/2] test(react-swatch-picker): scope hook tests to public hooks Split coarse state assertions into single-concern cases and replace inline context providers with a shared wrapper helper. --- .../ColorSwatch/useColorSwatch.test.tsx | 114 +++++++++--------- .../EmptySwatch/useEmptySwatch.test.tsx | 66 +++++----- .../ImageSwatch/useImageSwatch.test.tsx | 106 ++++++++-------- .../SwatchPicker/useSwatchPicker.test.tsx | 58 ++++++--- .../useSwatchPickerRow.test.tsx | 36 +++--- 5 files changed, 187 insertions(+), 193 deletions(-) diff --git a/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx index 541e7469bf65c0..bb51de42edf6cf 100644 --- a/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx +++ b/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx @@ -1,93 +1,87 @@ import * as React from 'react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { SwatchPickerProvider, swatchPickerContextDefaultValue } from '../../contexts/swatchPicker'; +import type { SwatchPickerContextValue } from '../../contexts/swatchPicker'; import { useColorSwatch_unstable } from './useColorSwatch'; +const props = { color: '#ff0000', value: 'red' }; + +const createWrapper = + (value: Partial) => + ({ children }: { children: React.ReactNode }) => + {children}; + describe('useColorSwatch', () => { - it('returns the default state', () => { + it('uses the default size and shape', () => { const ref = React.createRef(); - const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref)); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref)); - expect(result.current.color).toBe('#ff0000'); - expect(result.current.value).toBe('red'); - expect(result.current.selected).toBe(false); - expect(result.current.root.role).toBe('radio'); - expect(result.current.root['aria-checked']).toBe(false); expect(result.current.size).toBe('medium'); expect(result.current.shape).toBe('square'); }); - it('uses state from context', () => { + it('uses the size and shape from context', () => { const ref = React.createRef(); - const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + const { result } = renderHook(() => useColorSwatch_unstable(props, ref), { + wrapper: createWrapper({ shape: 'circular', size: 'large' }), }); - expect(result.current.selected).toBe(true); - expect(result.current.root.role).toBe('gridcell'); - expect(result.current.root['aria-selected']).toBe(true); expect(result.current.size).toBe('large'); expect(result.current.shape).toBe('circular'); }); - it('prefers props over context', () => { + it('prefers the size and shape props over context', () => { const ref = React.createRef(); const { result } = renderHook( - () => useColorSwatch_unstable({ color: '#ff0000', shape: 'rounded', size: 'extra-small', value: 'red' }, ref), - { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), - }, + () => useColorSwatch_unstable({ ...props, shape: 'rounded', size: 'extra-small' }, ref), + { wrapper: createWrapper({ shape: 'circular', size: 'large' }) }, ); expect(result.current.size).toBe('extra-small'); expect(result.current.shape).toBe('rounded'); }); + it('uses the radio role outside of a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref)); + + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + }); + + it('uses the gridcell role inside a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref), { + wrapper: createWrapper({ isGrid: true }), + }); + + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-selected']).toBe(false); + }); + + it('uses the selected value from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref), { + wrapper: createWrapper({ selectedValue: 'red' }), + }); + + expect(result.current.selected).toBe(true); + expect(result.current.root['aria-checked']).toBe(true); + }); + + it('renders a disabled icon by default', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref)); + + expect(result.current.disabledIcon?.children).toBeDefined(); + }); + it('forwards requested selection changes', () => { const requestSelectionChange = jest.fn(); const event = {} as React.MouseEvent; const ref = React.createRef(); - const { result } = renderHook(() => useColorSwatch_unstable({ color: '#ff0000', value: 'red' }, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + const { result } = renderHook(() => useColorSwatch_unstable(props, ref), { + wrapper: createWrapper({ requestSelectionChange }), }); act(() => result.current.root.onClick?.(event)); diff --git a/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx index 1725f5abd5e8b3..df5c19eacd98d4 100644 --- a/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx +++ b/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx @@ -1,64 +1,58 @@ import * as React from 'react'; import { renderHook } from '@testing-library/react-hooks'; -import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { SwatchPickerProvider, swatchPickerContextDefaultValue } from '../../contexts/swatchPicker'; +import type { SwatchPickerContextValue } from '../../contexts/swatchPicker'; import { useEmptySwatch_unstable } from './useEmptySwatch'; +const createWrapper = + (value: Partial) => + ({ children }: { children: React.ReactNode }) => + {children}; + describe('useEmptySwatch', () => { - it('returns the default state', () => { + it('uses the default size and shape', () => { const ref = React.createRef(); const { result } = renderHook(() => useEmptySwatch_unstable({}, ref)); - expect(result.current.root.role).toBe('radio'); - expect(result.current.root['aria-checked']).toBe(false); expect(result.current.size).toBe('medium'); expect(result.current.shape).toBe('square'); }); - it('uses state from context', () => { + it('uses the size and shape from context', () => { const ref = React.createRef(); const { result } = renderHook(() => useEmptySwatch_unstable({}, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + wrapper: createWrapper({ shape: 'circular', size: 'large' }), }); - expect(result.current.root.role).toBe('gridcell'); - expect(result.current.root['aria-checked']).toBeUndefined(); expect(result.current.size).toBe('large'); expect(result.current.shape).toBe('circular'); }); - it('prefers props over context', () => { + it('prefers the size and shape props over context', () => { const ref = React.createRef(); const { result } = renderHook(() => useEmptySwatch_unstable({ shape: 'rounded', size: 'extra-small' }, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + wrapper: createWrapper({ shape: 'circular', size: 'large' }), }); expect(result.current.size).toBe('extra-small'); expect(result.current.shape).toBe('rounded'); }); + + it('uses the radio role outside of a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref)); + + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + }); + + it('uses the gridcell role inside a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref), { + wrapper: createWrapper({ isGrid: true }), + }); + + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-checked']).toBeUndefined(); + }); }); diff --git a/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx index 4e76f86b30869d..dba680ca09b92a 100644 --- a/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx +++ b/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx @@ -1,92 +1,80 @@ import * as React from 'react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { SwatchPickerProvider, swatchPickerContextDefaultValue } from '../../contexts/swatchPicker'; +import type { SwatchPickerContextValue } from '../../contexts/swatchPicker'; import { useImageSwatch_unstable } from './useImageSwatch'; +const props = { src: 'image.png', value: 'image' }; + +const createWrapper = + (value: Partial) => + ({ children }: { children: React.ReactNode }) => + {children}; + describe('useImageSwatch', () => { - it('returns the default state', () => { + it('uses the default size and shape', () => { const ref = React.createRef(); - const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref)); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref)); - expect(result.current.value).toBe('image'); - expect(result.current.selected).toBe(false); - expect(result.current.root.role).toBe('radio'); - expect(result.current.root['aria-checked']).toBe(false); expect(result.current.size).toBe('medium'); expect(result.current.shape).toBe('square'); }); - it('uses state from context', () => { + it('uses the size and shape from context', () => { const ref = React.createRef(); - const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + const { result } = renderHook(() => useImageSwatch_unstable(props, ref), { + wrapper: createWrapper({ shape: 'circular', size: 'large' }), }); - expect(result.current.selected).toBe(true); - expect(result.current.root.role).toBe('gridcell'); - expect(result.current.root['aria-selected']).toBe(true); expect(result.current.size).toBe('large'); expect(result.current.shape).toBe('circular'); }); - it('uses context over props', () => { + it('prefers the size and shape from context over props', () => { const ref = React.createRef(); const { result } = renderHook( - () => useImageSwatch_unstable({ shape: 'rounded', size: 'extra-small', src: 'image.png', value: 'image' }, ref), - { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), - }, + () => useImageSwatch_unstable({ ...props, shape: 'rounded', size: 'extra-small' }, ref), + { wrapper: createWrapper({ shape: 'circular', size: 'large' }) }, ); expect(result.current.size).toBe('large'); expect(result.current.shape).toBe('circular'); }); + it('uses the radio role outside of a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref)); + + expect(result.current.root.role).toBe('radio'); + expect(result.current.root['aria-checked']).toBe(false); + }); + + it('uses the gridcell role inside a grid', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref), { + wrapper: createWrapper({ isGrid: true }), + }); + + expect(result.current.root.role).toBe('gridcell'); + expect(result.current.root['aria-selected']).toBe(false); + }); + + it('uses the selected value from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref), { + wrapper: createWrapper({ selectedValue: 'image' }), + }); + + expect(result.current.selected).toBe(true); + expect(result.current.root['aria-checked']).toBe(true); + }); + it('forwards requested selection changes', () => { const requestSelectionChange = jest.fn(); const event = {} as React.MouseEvent; const ref = React.createRef(); - const { result } = renderHook(() => useImageSwatch_unstable({ src: 'image.png', value: 'image' }, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), + const { result } = renderHook(() => useImageSwatch_unstable(props, ref), { + wrapper: createWrapper({ requestSelectionChange }), }); act(() => result.current.root.onClick?.(event)); diff --git a/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx index 3893c24f83c662..0dde4482f49660 100644 --- a/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx @@ -3,39 +3,61 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { useSwatchPicker_unstable } from './useSwatchPicker'; describe('useSwatchPicker', () => { - it('returns the default state', () => { + it('uses the default size, shape and spacing', () => { const ref = React.createRef(); const { result } = renderHook(() => useSwatchPicker_unstable({}, ref)); - expect(result.current.isGrid).toBe(false); - expect(result.current.root.role).toBe('radiogroup'); - expect(result.current.root).toHaveProperty('data-tabster', expect.any(String)); expect(result.current.size).toBe('medium'); expect(result.current.shape).toBeUndefined(); expect(result.current.spacing).toBe('medium'); }); - it('returns state based on props', () => { + it('uses the size, shape and spacing props', () => { const ref = React.createRef(); const { result } = renderHook(() => - useSwatchPicker_unstable( - { - defaultSelectedValue: 'red', - layout: 'grid', - shape: 'circular', - size: 'large', - spacing: 'small', - }, - ref, - ), + useSwatchPicker_unstable({ shape: 'circular', size: 'large', spacing: 'small' }, ref), ); + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + expect(result.current.spacing).toBe('small'); + }); + + it('uses the radiogroup role by default', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({}, ref)); + + expect(result.current.isGrid).toBe(false); + expect(result.current.root.role).toBe('radiogroup'); + }); + + it('uses the grid role for the grid layout', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({ layout: 'grid' }, ref)); + expect(result.current.isGrid).toBe(true); expect(result.current.root.role).toBe('grid'); + }); + + it('applies arrow navigation attributes by default', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({}, ref)); + + expect(result.current.root).toHaveProperty('data-tabster', expect.any(String)); + }); + + it('does not apply arrow navigation attributes when focusMode is tab', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({ focusMode: 'tab' }, ref)); + + expect(result.current.root).not.toHaveProperty('data-tabster'); + }); + + it('uses the default selected value', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({ defaultSelectedValue: 'red' }, ref)); + expect(result.current.selectedValue).toBe('red'); - expect(result.current.shape).toBe('circular'); - expect(result.current.size).toBe('large'); - expect(result.current.spacing).toBe('small'); }); it('forwards requested selection changes', () => { diff --git a/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx b/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx index b571f9aae00867..8ec74ef1478bb7 100644 --- a/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx @@ -1,37 +1,33 @@ import * as React from 'react'; import { renderHook } from '@testing-library/react-hooks'; -import { SwatchPickerProvider } from '../../contexts/swatchPicker'; +import { SwatchPickerProvider, swatchPickerContextDefaultValue } from '../../contexts/swatchPicker'; import { useSwatchPickerRow_unstable } from './useSwatchPickerRow'; +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + describe('useSwatchPickerRow', () => { - it('returns the default state', () => { + it('uses the row role', () => { const ref = React.createRef(); const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref)); expect(result.current.root.role).toBe('row'); + }); + + it('uses the default spacing', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref)); + expect(result.current.spacing).toBe('medium'); }); - it('uses spacing from context', () => { + it('uses the spacing from context', () => { const ref = React.createRef(); - const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref), { - wrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} - - ), - }); + const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref), { wrapper }); - expect(result.current.root.role).toBe('row'); expect(result.current.spacing).toBe('small'); }); });