Skip to content

Commit

Permalink
Merge pull request #537 from department-of-veterans-affairs/feature/4…
Browse files Browse the repository at this point in the history
…31-narin-checkbox-unit-tests

[Tests] Checkbox, CheckboxGroup, FormText
  • Loading branch information
narin authored Oct 17, 2024
2 parents df9933e + ea47b9b commit 247d774
Show file tree
Hide file tree
Showing 7 changed files with 601 additions and 3 deletions.
3 changes: 2 additions & 1 deletion packages/components/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ src/components/*/*.stories.tsx
src/components/*/*.test.tsx
src/utils/hooks/useWebStorybookColorScheme.ts
src/utils/storybook.tsx
src/App.tsx
src/utils/jest.tsx
src/App.tsx
174 changes: 174 additions & 0 deletions packages/components/src/components/Checkbox/Checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import 'react-native'
import { fireEvent, render, screen } from '@testing-library/react-native'
import React from 'react'

import { Checkbox } from './Checkbox'
import { getIcon, getIconName } from '../../utils/jest'

const mockedColorScheme = jest.fn()

jest.mock('react-native/Libraries/Utilities/useColorScheme', () => {
return {
default: mockedColorScheme,
}
})

describe('Checkbox', () => {
const onPressSpy = jest.fn()

const commonProps = {
header: 'Header text',
description: 'Description text',
hint: 'Hint text',
label: 'Label text',
testID: 'testCheckbox',
onPress: onPressSpy,
}

const errorMsg = 'Error text'

describe('Basic tests', () => {
it('initializes correctly', () => {
render(<Checkbox {...commonProps} />)
expect(screen.getByTestId('testCheckbox')).toBeTruthy()
})

it('renders header, description, hint, icon, and label text', async () => {
render(<Checkbox {...commonProps} />)
expect(screen.getByText('Header text')).toBeOnTheScreen()
expect(screen.getByText('Description text')).toBeOnTheScreen()
expect(screen.getByText('Label text')).toBeOnTheScreen()
expect(screen.getByText('Hint text')).toBeOnTheScreen()
expect(screen.queryByText('(*Required)')).not.toBeOnTheScreen()
expect(await getIconName(screen)).toBe('CheckBoxOutlineBlank')
})

it('renders error message', () => {
render(<Checkbox {...commonProps} error={errorMsg} />)
expect(screen.getByText('Error text')).toBeOnTheScreen()
})

it('renders required indicator next to label', async () => {
render(<Checkbox {...commonProps} required />)
expect(screen.getByText('Label text (*Required)')).toBeOnTheScreen()
})

it('renders checked icon', async () => {
render(<Checkbox {...commonProps} checked />)
expect(await getIconName(screen)).toBe('CheckBox')
})

it('renders indeterminate icon', async () => {
render(<Checkbox {...commonProps} indeterminate />)
expect(await getIconName(screen)).toBe('IndeterminateCheckBox')
})

it('overrides checked if indeterminate', async () => {
render(<Checkbox {...commonProps} indeterminate checked />)
expect(await getIconName(screen)).toBe('IndeterminateCheckBox')
})

it('fires onPress', async () => {
render(<Checkbox {...commonProps} />)
fireEvent.press(screen.getByRole('checkbox'))
expect(onPressSpy).toHaveBeenCalled()
})
})

describe('Styling', () => {
describe('Light mode', () => {
it('icon color (unchecked)', async () => {
render(<Checkbox {...commonProps} />)
const icon = await getIcon(screen)
expect(icon.props.fill).toEqual('#565c65')
})

it('icon color (checked)', async () => {
render(<Checkbox {...commonProps} checked />)
const icon = await getIcon(screen)
expect(icon.props.fill).toEqual('#005ea2')
})

it('tiled variant styling (unchecked)', async () => {
render(<Checkbox {...commonProps} tile />)

expect(screen.getByRole('checkbox')).toHaveStyle({
borderWidth: 2,
borderRadius: 4,
padding: 12,
paddingRight: 16,
borderColor: '#a9aeb1',
backgroundColor: '#ffffff',
})

const icon = await getIcon(screen)
expect(icon.props.fill).toEqual('#565c65')
})

it('tiled variant styling (checked)', async () => {
render(<Checkbox {...commonProps} tile checked />)
expect(screen.getByRole('checkbox')).toHaveStyle({
borderWidth: 2,
borderRadius: 4,
padding: 12,
paddingRight: 16,
borderColor: '#005ea2',
backgroundColor: '#ecf1f7',
})

const icon = await getIcon(screen)
expect(icon.props.fill).toEqual('#005ea2')
})

it('error state', () => {
render(<Checkbox {...commonProps} error={errorMsg} />)

expect(screen.root).toHaveStyle({
paddingLeft: 16,
borderColor: '#b50909',
borderLeftWidth: 4,
})
})
})

describe('Dark mode', () => {
it('tiled variant styling (unchecked)', () => {
mockedColorScheme.mockImplementation(() => 'dark')

render(<Checkbox {...commonProps} tile />)
expect(screen.getByRole('checkbox')).toHaveStyle({
borderWidth: 2,
borderRadius: 4,
padding: 12,
paddingRight: 16,
borderColor: '#565c65',
backgroundColor: '#2e2e2e',
})
})

it('tiled variant styling (checked)', () => {
mockedColorScheme.mockImplementation(() => 'dark')

render(<Checkbox {...commonProps} tile checked />)
expect(screen.getByRole('checkbox')).toHaveStyle({
borderWidth: 2,
borderRadius: 4,
padding: 12,
paddingRight: 16,
borderColor: '#58b4ff',
backgroundColor: '#252f3e',
})
})

it('error state', () => {
render(<Checkbox {...commonProps} error={errorMsg} />)

expect(screen.root).toHaveStyle({
paddingLeft: 16,
borderColor: '#fb5a47',
borderLeftWidth: 4,
})
})
})
})
})
3 changes: 2 additions & 1 deletion packages/components/src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const Checkbox: FC<CheckboxProps> = ({
indeterminate,
onPress,
required,
testID,
tile,
}) => {
const theme = useTheme()
Expand Down Expand Up @@ -116,7 +117,7 @@ export const Checkbox: FC<CheckboxProps> = ({

return (
<ComponentWrapper>
<View style={containerStyle}>
<View style={containerStyle} testID={testID}>
<Header text={header} />
{header && <Spacer size="xs" />}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import 'react-native'
import { fireEvent, render, screen } from '@testing-library/react-native'
import React from 'react'

import { CheckboxGroup } from './CheckboxGroup'

const mockedColorScheme = jest.fn()

jest.mock('react-native/Libraries/Utilities/useColorScheme', () => {
return {
default: mockedColorScheme,
}
})

describe('CheckboxGroup', () => {
const onSelectionChangeSpy = jest.fn()

const items = [
{ text: 'Option 1', description: 'Description for option 1' },
{
text: 'Option 2',
a11yLabel: 'Accessibility override for option 2',
value: '2',
description: {
text: 'Description for option 2',
a11yLabel: 'Accessibility override for description',
},
testID: 'testCheckbox',
},
{ text: 'Option 3' },
{ text: 'Option 4' },
{ text: 'Option 5' },
{ text: 'Option 6' },
]

const stringItems = ['String Option 1', 'String Option 2', 'String Option 3']

const commonProps = {
header: 'Header text',
hint: 'Hint text',
items,
selectedItems: ['2', 'Option 4'],
testID: 'testCheckboxGroup',
onSelectionChange: onSelectionChangeSpy,
}

const errorMsg = 'Error text'

describe('Basic tests', () => {
it('initializes correctly', () => {
render(<CheckboxGroup {...commonProps} />)
expect(screen.getByTestId('testCheckboxGroup')).toBeTruthy()
})

it('renders header, hint, and checkboxes', () => {
render(<CheckboxGroup {...commonProps} />)
const checkboxes = screen.queryAllByRole('checkbox')

expect(screen.getByTestId('testCheckboxGroup')).toBeTruthy()
expect(screen.getByText('Header text')).toBeOnTheScreen()
expect(screen.getByText('Hint text')).toBeOnTheScreen()
expect(screen.queryByText('(*Required)')).not.toBeOnTheScreen()

expect(checkboxes.length).toBe(6)
})

it('renders header, hint, and array of strings and set strings as a11y labels', () => {
render(<CheckboxGroup {...commonProps} items={stringItems} />)
const checkboxes = screen.queryAllByRole('checkbox')

expect(screen.getByTestId('testCheckboxGroup')).toBeTruthy()
expect(screen.getByText('Header text')).toBeOnTheScreen()
expect(screen.getByText('Hint text')).toBeOnTheScreen()
expect(screen.queryByText('(*Required)')).not.toBeOnTheScreen()

expect(checkboxes.length).toBe(3)

expect(screen.getByText('String Option 1')).toBeOnTheScreen()
expect(screen.getByText('String Option 2')).toBeOnTheScreen()
expect(screen.getByText('String Option 3')).toBeOnTheScreen()

expect(screen.getByLabelText('String Option 1')).toBeOnTheScreen()
expect(screen.getByLabelText('String Option 2')).toBeOnTheScreen()
expect(screen.getByLabelText('String Option 3')).toBeOnTheScreen()
})

it('renders error message', () => {
render(<CheckboxGroup {...commonProps} error={errorMsg} />)
expect(screen.getByText('Error text')).toBeOnTheScreen()
})

it('renders required indicator', async () => {
render(<CheckboxGroup {...commonProps} required />)
expect(screen.getByText('Header text (*Required)')).toBeOnTheScreen()
})

it('should mark selectedItems as checked', () => {
render(<CheckboxGroup {...commonProps} />)
const checkboxes = screen.queryAllByRole('checkbox')
expect(checkboxes[0].props.accessibilityState.checked).toBe(false)
expect(checkboxes[1].props.accessibilityState.checked).toBe(true)
expect(checkboxes[2].props.accessibilityState.checked).toBe(false)
expect(checkboxes[3].props.accessibilityState.checked).toBe(true)
expect(checkboxes[4].props.accessibilityState.checked).toBe(false)
expect(checkboxes[5].props.accessibilityState.checked).toBe(false)
})
})

describe('onPress behavior', () => {
it('should pass updated selectedItems on check', () => {
render(<CheckboxGroup {...commonProps} />)
const checkboxes = screen.queryAllByRole('checkbox')

// simulate check 'Option 1'
fireEvent.press(checkboxes[0])
expect(onSelectionChangeSpy).toHaveBeenCalledWith([
'2',
'Option 4',
'Option 1',
])
})

it('should pass updated selectedItems on uncheck', () => {
render(<CheckboxGroup {...commonProps} />)
const checkboxes = screen.queryAllByRole('checkbox')

// simulate uncheck '2', leaving just 'Option 4' selected
fireEvent.press(checkboxes[1])
expect(onSelectionChangeSpy).toHaveBeenLastCalledWith(['Option 4'])
})
})

describe('Error state', () => {
it('light mode styling', () => {
render(<CheckboxGroup {...commonProps} error={errorMsg} />)

expect(screen.root).toHaveStyle({
paddingLeft: 16,
borderColor: '#b50909',
borderLeftWidth: 4,
})
})

it('dark mode styling', () => {
mockedColorScheme.mockImplementation(() => 'dark')
render(<CheckboxGroup {...commonProps} error={errorMsg} />)

expect(screen.root).toHaveStyle({
paddingLeft: 16,
borderColor: '#fb5a47',
borderLeftWidth: 4,
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const CheckboxGroup: FC<CheckboxGroupProps> = ({
hint,
onSelectionChange,
required,
testID,
tile,
}) => {
const theme = useTheme()
Expand Down Expand Up @@ -127,7 +128,7 @@ export const CheckboxGroup: FC<CheckboxGroupProps> = ({

return (
<ComponentWrapper>
<View style={containerStyle}>
<View style={containerStyle} testID={testID}>
<Header text={header} required={required} />
{header && <Spacer size="xs" />}

Expand Down
Loading

0 comments on commit 247d774

Please sign in to comment.