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 0000000000000..bb51de42edf6c --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/ColorSwatch/useColorSwatch.test.tsx @@ -0,0 +1,95 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +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('uses the default size and shape', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref)); + + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses the size and shape from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useColorSwatch_unstable(props, ref), { + wrapper: createWrapper({ shape: 'circular', size: 'large' }), + }); + + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('prefers the size and shape props over context', () => { + const ref = React.createRef(); + const { result } = renderHook( + () => 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(props, ref), { + wrapper: createWrapper({ requestSelectionChange }), + }); + + 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 0000000000000..df5c19eacd98d --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/EmptySwatch/useEmptySwatch.test.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +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('uses the default size and shape', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref)); + + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses the size and shape from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useEmptySwatch_unstable({}, ref), { + wrapper: createWrapper({ shape: 'circular', size: 'large' }), + }); + + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + 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: 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 new file mode 100644 index 0000000000000..dba680ca09b92 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/ImageSwatch/useImageSwatch.test.tsx @@ -0,0 +1,88 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +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('uses the default size and shape', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref)); + + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBe('square'); + }); + + it('uses the size and shape from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useImageSwatch_unstable(props, ref), { + wrapper: createWrapper({ shape: 'circular', size: 'large' }), + }); + + expect(result.current.size).toBe('large'); + expect(result.current.shape).toBe('circular'); + }); + + it('prefers the size and shape from context over props', () => { + const ref = React.createRef(); + const { result } = renderHook( + () => 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(props, ref), { + wrapper: createWrapper({ requestSelectionChange }), + }); + + 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 0000000000000..0dde4482f4966 --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPicker/useSwatchPicker.test.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useSwatchPicker_unstable } from './useSwatchPicker'; + +describe('useSwatchPicker', () => { + it('uses the default size, shape and spacing', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPicker_unstable({}, ref)); + + expect(result.current.size).toBe('medium'); + expect(result.current.shape).toBeUndefined(); + expect(result.current.spacing).toBe('medium'); + }); + + it('uses the size, shape and spacing props', () => { + const ref = React.createRef(); + const { result } = renderHook(() => + 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'); + }); + + 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 0000000000000..8ec74ef1478bb --- /dev/null +++ b/packages/react-components/react-swatch-picker/library/src/components/SwatchPickerRow/useSwatchPickerRow.test.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { SwatchPickerProvider, swatchPickerContextDefaultValue } from '../../contexts/swatchPicker'; +import { useSwatchPickerRow_unstable } from './useSwatchPickerRow'; + +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + +describe('useSwatchPickerRow', () => { + 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 the spacing from context', () => { + const ref = React.createRef(); + const { result } = renderHook(() => useSwatchPickerRow_unstable({}, ref), { wrapper }); + + expect(result.current.spacing).toBe('small'); + }); +});