338 lines
9.0 KiB
TypeScript
338 lines
9.0 KiB
TypeScript
import React, { useState } from 'react'
|
|
import { render } from '@testing-library/react'
|
|
|
|
import { Switch } from './switch'
|
|
import {
|
|
SwitchState,
|
|
assertSwitch,
|
|
getSwitch,
|
|
assertActiveElement,
|
|
getSwitchLabel,
|
|
} from '../../test-utils/accessibility-assertions'
|
|
import { press, click, Keys } from '../../test-utils/interactions'
|
|
|
|
jest.mock('../../hooks/use-id')
|
|
|
|
describe('Safe guards', () => {
|
|
it('should be possible to render a Switch without crashing', () => {
|
|
render(<Switch checked={false} onChange={console.log} />)
|
|
})
|
|
})
|
|
|
|
describe('Rendering', () => {
|
|
it('should be possible to render an (on) Switch using a render prop', () => {
|
|
render(
|
|
<Switch checked={true} onChange={console.log}>
|
|
{({ checked }) => <span>{checked ? 'On' : 'Off'}</span>}
|
|
</Switch>
|
|
)
|
|
|
|
assertSwitch({ state: SwitchState.On, textContent: 'On' })
|
|
})
|
|
|
|
it('should be possible to render an (off) Switch using a render prop', () => {
|
|
render(
|
|
<Switch checked={false} onChange={console.log}>
|
|
{({ checked }) => <span>{checked ? 'On' : 'Off'}</span>}
|
|
</Switch>
|
|
)
|
|
|
|
assertSwitch({ state: SwitchState.Off, textContent: 'Off' })
|
|
})
|
|
|
|
it('should be possible to render an (on) Switch using an `as` prop', () => {
|
|
render(<Switch as="span" checked={true} onChange={console.log} />)
|
|
assertSwitch({ state: SwitchState.On, tag: 'span' })
|
|
})
|
|
|
|
it('should be possible to render an (off) Switch using an `as` prop', () => {
|
|
render(<Switch as="span" checked={false} onChange={console.log} />)
|
|
assertSwitch({ state: SwitchState.Off, tag: 'span' })
|
|
})
|
|
|
|
it('should be possible to use the switch contents as the label', () => {
|
|
render(
|
|
<Switch checked={false} onChange={console.log}>
|
|
<span>Enable notifications</span>
|
|
</Switch>
|
|
)
|
|
assertSwitch({ state: SwitchState.Off, label: 'Enable notifications' })
|
|
})
|
|
})
|
|
|
|
describe('Render composition', () => {
|
|
it('should be possible to render a Switch.Group, Switch and Switch.Label', () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch checked={false} onChange={console.log} />
|
|
<Switch.Label>Enable notifications</Switch.Label>
|
|
</Switch.Group>
|
|
)
|
|
|
|
assertSwitch({ state: SwitchState.Off, label: 'Enable notifications' })
|
|
})
|
|
|
|
it('should be possible to render a Switch.Group, Switch and Switch.Label (before the Switch)', () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch.Label>Label B</Switch.Label>
|
|
<Switch checked={false} onChange={console.log}>
|
|
Label A
|
|
</Switch>
|
|
</Switch.Group>
|
|
)
|
|
|
|
// Warning! Using aria-label or aria-labelledby will hide any descendant content from assistive
|
|
// technologies.
|
|
//
|
|
// Thus: Label A should not be part of the "label" in this case
|
|
assertSwitch({ state: SwitchState.Off, label: 'Label B' })
|
|
})
|
|
|
|
it('should be possible to render a Switch.Group, Switch and Switch.Label (after the Switch)', () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch checked={false} onChange={console.log}>
|
|
Label A
|
|
</Switch>
|
|
<Switch.Label>Label B</Switch.Label>
|
|
</Switch.Group>
|
|
)
|
|
|
|
// Warning! Using aria-label or aria-labelledby will hide any descendant content from assistive
|
|
// technologies.
|
|
//
|
|
// Thus: Label A should not be part of the "label" in this case
|
|
assertSwitch({ state: SwitchState.Off, label: 'Label B' })
|
|
})
|
|
|
|
it('should be possible to render a Switch.Group, Switch and Switch.Description (before the Switch)', async () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch.Description>This is an important feature</Switch.Description>
|
|
<Switch checked={false} onChange={console.log} />
|
|
</Switch.Group>
|
|
)
|
|
|
|
assertSwitch({ state: SwitchState.Off, description: 'This is an important feature' })
|
|
})
|
|
|
|
it('should be possible to render a Switch.Group, Switch and Switch.Description (after the Switch)', () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch checked={false} onChange={console.log} />
|
|
<Switch.Description>This is an important feature</Switch.Description>
|
|
</Switch.Group>
|
|
)
|
|
|
|
assertSwitch({ state: SwitchState.Off, description: 'This is an important feature' })
|
|
})
|
|
|
|
it('should be possible to render a Switch.Group, Switch, Switch.Label and Switch.Description', () => {
|
|
render(
|
|
<Switch.Group>
|
|
<Switch.Label>Label A</Switch.Label>
|
|
<Switch checked={false} onChange={console.log} />
|
|
<Switch.Description>This is an important feature</Switch.Description>
|
|
</Switch.Group>
|
|
)
|
|
|
|
assertSwitch({
|
|
state: SwitchState.Off,
|
|
label: 'Label A',
|
|
description: 'This is an important feature',
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Keyboard interactions', () => {
|
|
describe('`Space` key', () => {
|
|
it('should be possible to toggle the Switch with Space', async () => {
|
|
let handleChange = jest.fn()
|
|
function Example() {
|
|
let [state, setState] = useState(false)
|
|
return (
|
|
<Switch
|
|
checked={state}
|
|
onChange={value => {
|
|
setState(value)
|
|
handleChange(value)
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
|
|
render(<Example />)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Focus the switch
|
|
getSwitch()?.focus()
|
|
|
|
// Toggle
|
|
await press(Keys.Space)
|
|
|
|
// Ensure state is on
|
|
assertSwitch({ state: SwitchState.On })
|
|
|
|
// Toggle
|
|
await press(Keys.Space)
|
|
|
|
// Ensure state is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
})
|
|
})
|
|
|
|
describe('`Enter` key', () => {
|
|
it('should not be possible to use Enter to toggle the Switch', async () => {
|
|
let handleChange = jest.fn()
|
|
render(<Switch checked={false} onChange={handleChange} />)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Focus the switch
|
|
getSwitch()?.focus()
|
|
|
|
// Try to toggle
|
|
await press(Keys.Enter)
|
|
|
|
expect(handleChange).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('`Tab` key', () => {
|
|
it('should be possible to tab away from the Switch', async () => {
|
|
render(
|
|
<div>
|
|
<Switch checked={false} onChange={console.log} />
|
|
<button id="btn">Other element</button>
|
|
</div>
|
|
)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Focus the switch
|
|
getSwitch()?.focus()
|
|
|
|
// Expect the switch to be active
|
|
assertActiveElement(getSwitch())
|
|
|
|
// Toggle
|
|
await press(Keys.Tab)
|
|
|
|
// Expect the button to be active
|
|
assertActiveElement(document.getElementById('btn'))
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Mouse interactions', () => {
|
|
it('should be possible to toggle the Switch with a click', async () => {
|
|
let handleChange = jest.fn()
|
|
function Example() {
|
|
let [state, setState] = useState(false)
|
|
return (
|
|
<Switch
|
|
checked={state}
|
|
onChange={value => {
|
|
setState(value)
|
|
handleChange(value)
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
|
|
render(<Example />)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Toggle
|
|
await click(getSwitch())
|
|
|
|
// Ensure state is on
|
|
assertSwitch({ state: SwitchState.On })
|
|
|
|
// Toggle
|
|
await click(getSwitch())
|
|
|
|
// Ensure state is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
})
|
|
|
|
it('should be possible to toggle the Switch with a click on the Label', async () => {
|
|
let handleChange = jest.fn()
|
|
function Example() {
|
|
let [state, setState] = useState(false)
|
|
return (
|
|
<Switch.Group>
|
|
<Switch
|
|
checked={state}
|
|
onChange={value => {
|
|
setState(value)
|
|
handleChange(value)
|
|
}}
|
|
/>
|
|
<Switch.Label>The label</Switch.Label>
|
|
</Switch.Group>
|
|
)
|
|
}
|
|
|
|
render(<Example />)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Toggle
|
|
await click(getSwitchLabel())
|
|
|
|
// Ensure the switch is focused
|
|
assertActiveElement(getSwitch())
|
|
|
|
// Ensure state is on
|
|
assertSwitch({ state: SwitchState.On })
|
|
|
|
// Toggle
|
|
await click(getSwitchLabel())
|
|
|
|
// Ensure the switch is focused
|
|
assertActiveElement(getSwitch())
|
|
|
|
// Ensure state is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
})
|
|
|
|
it('should not be possible to toggle the Switch with a click on the Label (passive)', async () => {
|
|
let handleChange = jest.fn()
|
|
function Example() {
|
|
let [state, setState] = useState(false)
|
|
return (
|
|
<Switch.Group>
|
|
<Switch
|
|
checked={state}
|
|
onChange={value => {
|
|
setState(value)
|
|
handleChange(value)
|
|
}}
|
|
/>
|
|
<Switch.Label passive>The label</Switch.Label>
|
|
</Switch.Group>
|
|
)
|
|
}
|
|
|
|
render(<Example />)
|
|
|
|
// Ensure checkbox is off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
|
|
// Toggle
|
|
await click(getSwitchLabel())
|
|
|
|
// Ensure state is still off
|
|
assertSwitch({ state: SwitchState.Off })
|
|
})
|
|
})
|