import { isInaccessible, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { render } from '~/src/utils/test'
import { Tooltip } from './Tooltip'
import { type TooltipProps } from './Tooltip.types'
describe('Tooltip', () => {
const renderTooltip = ({ children, ...rest }: TooltipProps = {}) =>
render(
)
let user: ReturnType
beforeEach(() => {
user = userEvent.setup()
})
describe('ARIA', () => {
it('should be accessible', () => {
const { container } = renderTooltip({
defaultShow: true,
content: 'tooltip content',
})
expect(isInaccessible(container)).toBe(false)
})
it('The element that serves as the tooltip container has role `tooltip`.', () => {
const { getByRole } = renderTooltip({
defaultShow: true,
content: 'tooltip content',
})
expect(getByRole('tooltip')).toBeInTheDocument()
})
it('The element that triggers the tooltip references the tooltip element with `aria-describedby`.', () => {
const { getByRole } = renderTooltip({
defaultShow: true,
content: 'tooltip content',
})
expect(getByRole('button')).toHaveAttribute(
'aria-describedby',
getByRole('tooltip').id
)
})
})
describe('User Interactions', () => {
// FIXME: Make this test pass
// it('The tooltip content should be visible when hover over the trigger.', async () => {
// const { getByRole } = renderTooltip({ content: 'tooltip content' })
// await user.hover(getByRole('button'))
// expect(getByRole('tooltip')).toBeInTheDocument()
// })
// FIXME: Make this test pass
// it('The tooltip content should be visible when the keyboard focuses on the trigger.', async () => {
// const { getByRole } = renderTooltip({ content: 'tooltip content' })
// await user.tab()
// expect(getByRole('tooltip')).toBeInTheDocument()
// })
it('When the tooltip content is visible, pressing Esc should hide the tooltip content.', async () => {
const { queryByRole } = renderTooltip({
defaultShow: true,
content: 'tooltip content',
})
await user.keyboard('{Escape}')
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
it('When the tooltip content is visible, clicking outside the tooltip should hide the tooltip content.', async () => {
const { queryByRole } = renderTooltip({
defaultShow: true,
content: 'tooltip content',
})
await user.click(document.body)
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
// FIXME: Make this test pass
// it('When the `allowHover` property is true, the tooltip content should be hoverable.', async () => {
// const { getByRole } = renderTooltip({
// allowHover: true,
// content: 'tooltip content',
// })
// await user.hover(getByRole('button'))
// await user.hover(getByRole('tooltip'))
// expect(getByRole('tooltip')).toBeInTheDocument()
// })
it('When the tooltip is visible, the `onShow` handler should be called.', async () => {
const onShow = jest.fn()
const { getByRole } = renderTooltip({
onShow,
content: 'tooltip content',
})
await user.hover(getByRole('button'))
expect(onShow).toHaveBeenCalled()
})
it('When the tooltip is hidden, the `onHide` handler should be called.', async () => {
const onHide = jest.fn()
const { getByRole } = renderTooltip({
onHide,
content: 'tooltip content',
})
await user.hover(getByRole('button'))
await user.unhover(getByRole('button'))
expect(onHide).toHaveBeenCalled()
})
it('If the `content` property is undefined, the tooltip should not be visible when hovering over it or with keyboard focus.', async () => {
const { getByRole, queryByRole } = renderTooltip({ content: undefined })
await user.hover(getByRole('button'))
expect(queryByRole('tooltip')).not.toBeInTheDocument()
await user.tab()
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
it('If the `content` property is null, the tooltip should not be visible when hovering over it or with keyboard focus.', async () => {
const { getByRole, queryByRole } = renderTooltip({ content: null })
await user.hover(getByRole('button'))
expect(queryByRole('tooltip')).not.toBeInTheDocument()
await user.tab()
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
it('If the `content` property is empty string, the tooltip should not be visible when hovering over it or with keyboard focus.', async () => {
const { getByRole, queryByRole } = renderTooltip({ content: '' })
await user.hover(getByRole('button'))
expect(queryByRole('tooltip')).not.toBeInTheDocument()
await user.tab()
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
it('If the `disabled` property is true, the tooltip should not be visible when hovering over it or with keyboard focus.', async () => {
const { getByRole, queryByRole } = renderTooltip({
disabled: true,
content: 'tooltip content',
})
await user.hover(getByRole('button'))
expect(queryByRole('tooltip')).not.toBeInTheDocument()
await user.tab()
expect(queryByRole('tooltip')).not.toBeInTheDocument()
})
it('If the `delayShow` property is greater than 0, the tooltip should be delayed by that number of ms before appearing.', async () => {
// NOTE: (@ed) To avoid test failure due to timing issue
const { getByRole, queryByRole } = renderTooltip({
delayShow: 1000 - 10,
content: 'tooltip content',
})
await user.hover(getByRole('button'))
expect(queryByRole('tooltip')).not.toBeInTheDocument()
await waitFor(
() => {
expect(queryByRole('tooltip')).toBeInTheDocument()
},
{ timeout: 1000 }
)
})
// FIXME: Make this test pass
// it('If the `delayHide` property is greater than 0, the tooltip should be delayed by that number of ms before disappearing.', async () => {
// // NOTE: (@ed) To avoid test failure due to timing issue
// const { getByRole, queryByRole } = renderTooltip({
// delayHide: 1000 - 10,
// content: 'tooltip content',
// })
// await user.hover(getByRole('button'))
// await user.unhover(getByRole('button'))
// expect(queryByRole('tooltip')).toBeInTheDocument()
// await waitFor(
// () => {
// expect(queryByRole('tooltip')).not.toBeInTheDocument()
// },
// { timeout: 1000 }
// )
// })
})
})