Skip to content

Commit

Permalink
RTL migration: controls (#602)
Browse files Browse the repository at this point in the history
* Migrate paginator

* Add comment

* Remove unused import

* Migrate tab-bar
  • Loading branch information
chawes13 authored Aug 7, 2023
1 parent c69b700 commit fef7199
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 105 deletions.
1 change: 1 addition & 0 deletions src/controls/paginator/page-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function PageLink({ className, active, onClick, children, ...rest }) {
return (
<li className={classnames(className, { active: active })}>
<a
role="link"
onClick={onClick}
onKeyPress={triggerOnKeys(onClick, ENTER_KEY_CODE)} // keyboard interaction requirement
aria-current={active ? 'page' : false}
Expand Down
3 changes: 3 additions & 0 deletions test/controls/color-picker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import React from 'react'
import { mount } from 'enzyme'
import { ColorPicker } from '../../src/'

// TODO: Migrate after incoming change to use a button instead of a div
// https://github.com/LaunchPadLab/lp-components/pull/596

test('ColorPicker toggles expanded when swatch is clicked', () => {
const wrapper = mount(<ColorPicker />)
expect(wrapper.find('.popover').exists()).toBe(false)
Expand Down
105 changes: 56 additions & 49 deletions test/controls/paginator/paginator.test.js
Original file line number Diff line number Diff line change
@@ -1,99 +1,106 @@
import React from 'react'
import { mount } from 'enzyme'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Paginator } from '../../../src/'

test('Previous button renders unless value is min', () => {
const wrapper = mount(<Paginator value={5} min={1} max={10} />)
expect(wrapper.find('.prev').exists()).toBe(true)
wrapper.setProps({ value: 1 })
expect(wrapper.find('.prev').exists()).toBe(false)
test('Previous control renders unless value is min', () => {
const { rerender } = render(<Paginator value={5} min={1} max={10} />)
expect(screen.getByRole('link', { name: /previous page/i })).toBeInTheDocument()
rerender(<Paginator value={1} min={1} max={10} />)
expect(screen.queryByRole('link', { name: /previous page/i })).not.toBeInTheDocument()
})

test('Next button renders unless value is max', () => {
const wrapper = mount(<Paginator value={5} min={1} max={10} />)
expect(wrapper.find('.next').exists()).toBe(true)
wrapper.setProps({ value: 10 })
expect(wrapper.find('.next').exists()).toBe(false)
test('Next control renders unless value is max', () => {
const { rerender } = render(<Paginator value={5} min={1} max={10} />)
expect(screen.getByRole('link', { name: /next page/i })).toBeInTheDocument()
rerender(<Paginator value={10} min={1} max={10} />)
expect(screen.queryByRole('link', { name: /next page/i })).not.toBeInTheDocument()
})

test('Button with current value is marked as active', () => {
const wrapper = mount(<Paginator value={5} min={1} max={10} />)
expect(wrapper.find('.active').text()).toBe('5')
test('Control with current value is marked as active', () => {
render(<Paginator value={5} min={1} max={10} />)
expect(screen.getByText(5).parentElement).toHaveClass('active')
})

test('Button click sets value', () => {
test('Control click sets value', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()

render(
<Paginator value={5} min={1} max={10} onChange={onChange} />
)
wrapper.find('li > a').at(2).simulate('click')
await user.click(screen.getAllByRole('link').at(2))
expect(onChange).toHaveBeenCalledWith(4)
})

test('Previous button decrements value', () => {
test('Previous control decrements value', async () => {
const onChange = jest.fn()
const wrapper = mount(
<Paginator value={5} min={1} max={10} onChange={onChange} />
const user = userEvent.setup()
const currentValue = 5
render(
<Paginator value={currentValue} min={1} max={10} onChange={onChange} />
)
wrapper.find('li > a').first().simulate('click')
expect(onChange).toHaveBeenCalledWith(4)
await user.click(screen.getByRole('link', { name: /previous page/i }))
expect(onChange).toHaveBeenCalledWith(currentValue - 1)
})

test('Next button increments value', () => {
test('Next control increments value', async () => {
const onChange = jest.fn()
const wrapper = mount(
<Paginator value={5} min={1} max={10} onChange={onChange} />
const user = userEvent.setup()
const currentValue = 5
render(
<Paginator value={currentValue} min={1} max={10} onChange={onChange} />
)
wrapper.find('li > a').last().simulate('click')
expect(onChange).toHaveBeenCalledWith(6)
await user.click(screen.getByRole('link', { name: /next page/i }))
expect(onChange).toHaveBeenCalledWith(currentValue + 1)
})

test('Min button sets value to min', () => {
test('Min control sets value to min', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<Paginator value={5} min={1} max={10} onChange={onChange} />
)
wrapper.find('li > a').at(1).simulate('click')
await user.click(screen.getByRole('link', { name: /page 1$/ }))
expect(onChange).toHaveBeenCalledWith(1)
})

test('Max button sets value to max', () => {
test('Max control sets value to max', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<Paginator value={5} min={1} max={10} onChange={onChange} />
)
wrapper.find('li > a').at(5).simulate('click')
await user.click(screen.getByRole('link', { name: /page 10$/ }))
expect(onChange).toHaveBeenCalledWith(10)
})

test('Current page is indicated via aria-current', () => {
const wrapper = mount(<Paginator value={5} min={1} max={10} />)
expect(wrapper.find('.active > a').prop('aria-current')).toBe('page')
expect(wrapper.find('a').not('.active').first().prop('aria-current')).toBe(
false
)
render(<Paginator value={5} min={1} max={10} />)
expect(screen.getByText(5)).toHaveAttribute('aria-current', 'page')
expect(screen.getByText(1)).toHaveAttribute('aria-current', 'false')
})

test('Destination is indicated via aria-label', () => {
const wrapper = mount(<Paginator value={5} min={1} max={10} />)
expect(wrapper.find('.active > a').prop('aria-label')).toBe('Go to page 5')
render(<Paginator value={5} min={1} max={10} />)
expect(screen.getByLabelText('Go to page 5')).toBeInTheDocument()
})

test('Page button is triggered via click or enter', () => {
test('Page control is triggered via click or enter', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<Paginator value={5} min={1} max={10} onChange={onChange} />
)
const link = wrapper.find('li > a').at(2)
link.simulate('click')
link.simulate('keypress', { keyCode: 13 })

expect(onChange).toHaveBeenCalledTimes(2)
await user.click(screen.getByLabelText('Go to page 1'))
await user.keyboard('{Enter}')
expect(onChange).toHaveBeenNthCalledWith(1, 1)
expect(onChange).toHaveBeenNthCalledWith(2, 1)
})

test('Can accept custom delimiter', () => {
const wrapper = mount(
render(
<Paginator value={1} min={1} max={10} delimiter="foo" />
)
expect(wrapper.find('.delimiter').contains('foo')).toBe(true)
expect(screen.getByText('foo')).toBeInTheDocument()
})
100 changes: 44 additions & 56 deletions test/controls/tab-bar.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { mount } from 'enzyme'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { TabBar } from '../../src/'

const defaultOptions = ['Home', 'Account']
Expand All @@ -9,107 +10,94 @@ const objectOptions = [
]

test('TabBar defaults to horizontal alignment', () => {
const wrapper = mount(<TabBar options={defaultOptions} value="home" />)
expect(wrapper.find('ul').hasClass('horizontal-tabs')).toEqual(true)
render(<TabBar options={defaultOptions} value="home" />)
expect(screen.getByRole('tablist')).toHaveAttribute('aria-orientation', 'horizontal')
})

test('TabBar aligns vertically with vertical option', () => {
const wrapper = mount(
render(
<TabBar options={defaultOptions} vertical={true} value="home" />
)
expect(wrapper.find('ul').hasClass('vertical-tabs')).toEqual(true)
expect(screen.getByRole('tablist')).toHaveAttribute('aria-orientation', 'vertical')
})

test('TabBar renders defaultOptions', () => {
const wrapper = mount(<TabBar options={defaultOptions} value="home" />)
expect(wrapper.find('li').first().text()).toEqual('Home')
expect(wrapper.find('li').last().text()).toEqual('Account')
render(<TabBar options={defaultOptions} value="home" />)
expect(screen.getByText('Home')).toBeInTheDocument()
expect(screen.getByText('Account')).toBeInTheDocument()
})

test('TabBar renders objectOptions', () => {
const wrapper = mount(<TabBar options={objectOptions} value="home" />)
expect(wrapper.find('li').first().text()).toEqual('Home')
expect(wrapper.find('li').last().text()).toEqual('Account')
render(<TabBar options={objectOptions} value="home" />)
expect(screen.getByText('Home')).toBeInTheDocument()
expect(screen.getByText('Account')).toBeInTheDocument()
})

test('TabBar adds Active class', () => {
const wrapper = mount(<TabBar options={objectOptions} value="home" />)
expect(wrapper.find('li').first().hasClass('active')).toEqual(true)
render(<TabBar options={objectOptions} value="home" />)
expect(screen.getByText('Home').parentElement).toHaveClass('active')
})

test('TabBar calls onChange', () => {
test('TabBar calls onChange', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<TabBar options={objectOptions} value="home" onChange={onChange} />
)
wrapper.find('li > a').first().simulate('click')
expect(onChange).toHaveBeenCalledWith('home')
await user.click(screen.getByText(objectOptions[0].key))
expect(onChange).toHaveBeenCalledWith(objectOptions[0].value)
})

test('TabBar passes down custom className to ul', () => {
const wrapper = mount(
render(
<TabBar options={objectOptions} value="home" className="custom" />
)
expect(wrapper.find('ul').hasClass('custom')).toEqual(true)
expect(screen.getByRole('tablist')).toHaveClass('tabs', 'custom')
})

test('TabBar passes down custom activeClassName to li', () => {
const wrapper = mount(
render(
<TabBar options={objectOptions} value="home" activeClassName="custom" />
)
expect(wrapper.find('li').first().hasClass('custom')).toEqual(true)
const homeTab = screen.getByText('Home')
expect(homeTab.parentElement).toHaveClass('custom')
expect(homeTab.parentElement).not.toHaveClass('active')
})

test('TabBar assigns appropriate aria roles', () => {
const wrapper = mount(<TabBar options={defaultOptions} value="home" />)
expect(wrapper.find('ul').prop('role')).toBe('tablist')
expect(wrapper.find('li > a').every('[role="tab"]')).toBe(true)
})

test('TabBar assigns appropriate aria orientation', () => {
const horizontalWrapper = mount(
<TabBar options={defaultOptions} vertical={false} value="home" />
)
const verticalWrapper = mount(
<TabBar options={defaultOptions} vertical value="home" />
)

expect(
horizontalWrapper.find('[role="tablist"]').prop('aria-orientation')
).toBe('horizontal')
expect(
verticalWrapper.find('[role="tablist"]').prop('aria-orientation')
).toBe('vertical')
render(<TabBar options={defaultOptions} value="home" />)
expect(screen.getByRole('tablist')).toBeInTheDocument()
expect(screen.getAllByRole('tab').length).toBe(defaultOptions.length)
})

test('TabBar assigns unique id to tab', () => {
const wrapper = mount(<TabBar options={defaultOptions} value="home" />)
expect(wrapper.find('li > a').first().prop('id')).toContain(
defaultOptions[0].toLowerCase()
)
render(<TabBar options={defaultOptions} value="home" />)
expect(screen.getByText('Home')).toHaveAttribute('id', 'tab-' + defaultOptions[0].toLowerCase())
})

test('Inactive tabs are explicitly removed from the natural tab order', () => {
const wrapper = mount(<TabBar options={defaultOptions} value="home" />)
expect(
wrapper.find('li').not('.active').find('a').every('[tabIndex="-1"]')
).toBe(true)
render(<TabBar options={defaultOptions} value="home" />)
expect(screen.getByText('Account')).toHaveAttribute('tabIndex', '-1')
})

test('Tab to show is triggered via Enter', () => {
test('Tab to show is triggered via Enter', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<TabBar options={objectOptions} value="home" onChange={onChange} />
)
wrapper.find('li > a').first().simulate('keyPress', { keyCode: 13 })
expect(onChange).toHaveBeenCalledWith('home')
screen.getByText(objectOptions[1].key).focus()
await user.keyboard('{Enter}')
expect(onChange).toHaveBeenCalledWith(objectOptions[1].value)
})

test('Tab to show is triggered via Space', () => {
test('Tab to show is triggered via Space', async () => {
const onChange = jest.fn()
const wrapper = mount(
const user = userEvent.setup()
render(
<TabBar options={objectOptions} value="home" onChange={onChange} />
)
wrapper.find('li > a').first().simulate('keyPress', { keyCode: 32 })
expect(onChange).toHaveBeenCalledWith('home')
screen.getByText(objectOptions[1].key).focus()
await user.keyboard('[Space]')
expect(onChange).toHaveBeenCalledWith(objectOptions[1].value)
})

0 comments on commit fef7199

Please sign in to comment.