Files
headlessui/packages/@headlessui-vue/src/components/dialog/dialog.test.ts
T
Jordan Pittman 89fd4b202e Update minimum Vue to 3.2 (#1072)
* Remove vercel json file

* Don't use provide/inject outside of setup

* Upgrade minimum vue version

* Mark vue as an external

* Update lockfile

* WIP move render functions into setup

* WIP

* WIP

* Use setup returning render fns for tests
2022-01-27 13:49:26 -05:00

1163 lines
31 KiB
TypeScript

import { defineComponent, ref, nextTick, h, ComponentOptionsWithoutProps } from 'vue'
import { render } from '../../test-utils/vue-testing-library'
import { Dialog, DialogOverlay, DialogTitle, DialogDescription } from './dialog'
import { TransitionRoot } from '../transitions/transition'
import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs'
import {
DialogState,
assertDialog,
assertDialogDescription,
assertDialogOverlay,
assertDialogTitle,
getDialog,
getDialogOverlay,
getByText,
assertActiveElement,
getDialogs,
getDialogOverlays,
} from '../../test-utils/accessibility-assertions'
import { click, press, Keys } from '../../test-utils/interactions'
import { html } from '../../test-utils/html'
// @ts-expect-error
global.IntersectionObserver = class FakeIntersectionObserver {
observe() {}
disconnect() {}
}
afterAll(() => jest.restoreAllMocks())
let TabSentinel = defineComponent({
name: 'TabSentinel',
template: html` <div :tabindex="0"></div> `,
})
jest.mock('../../hooks/use-id')
beforeAll(() => {
jest.spyOn(window, 'requestAnimationFrame').mockImplementation(setImmediate as any)
jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(clearImmediate as any)
})
afterAll(() => jest.restoreAllMocks())
function renderTemplate(input: string | ComponentOptionsWithoutProps) {
let defaultComponents = { Dialog, DialogOverlay, DialogTitle, DialogDescription, TabSentinel }
if (typeof input === 'string') {
return render(defineComponent({ template: input, components: defaultComponents }))
}
return render(
defineComponent(
Object.assign({}, input, {
components: { ...defaultComponents, ...input.components },
}) as Parameters<typeof defineComponent>[0]
)
)
}
describe('Safe guards', () => {
it.each([
['DialogOverlay', DialogOverlay],
['DialogTitle', DialogTitle],
])(
'should error when we are using a <%s /> without a parent <Dialog />',
suppressConsoleLogs((name, Component) => {
expect(() => render(Component)).toThrowError(
`<${name} /> is missing a parent <Dialog /> component.`
)
expect.hasAssertions()
})
)
it(
'should be possible to render a Dialog without crashing',
suppressConsoleLogs(async () => {
renderTemplate(
`
<Dialog :open="false" @close="() => {}">
<button>Trigger</button>
<DialogOverlay />
<DialogTitle />
<p>Contents</p>
<DialogDescription />
</Dialog>
`
)
assertDialog({
state: DialogState.InvisibleUnmounted,
attributes: { id: 'headlessui-dialog-1' },
})
})
)
})
describe('Rendering', () => {
describe('Dialog', () => {
it(
'should complain when an `open` prop is missing',
suppressConsoleLogs(async () => {
expect(() =>
renderTemplate(
`
<Dialog as="div" @close="() => {}" />
`
)
).toThrowErrorMatchingInlineSnapshot(
`"You forgot to provide an \`open\` prop to the \`Dialog\`."`
)
expect.hasAssertions()
})
)
it(
'should complain when an `open` prop is not a boolean',
suppressConsoleLogs(async () => {
expect(() =>
renderTemplate(
`
<Dialog as="div" :open="null" @close="() => {}" />
`
)
).toThrowErrorMatchingInlineSnapshot(
`"You provided an \`open\` prop to the \`Dialog\`, but the value is not a boolean. Received: null"`
)
expect.hasAssertions()
})
)
it(
'should be possible to render a Dialog using a render prop',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="setIsOpen(true)">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen" v-slot="data">
<pre>{{JSON.stringify(data)}}</pre>
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
assertDialog({ state: DialogState.InvisibleUnmounted })
await click(document.getElementById('trigger'))
assertDialog({ state: DialogState.Visible, textContent: JSON.stringify({ open: true }) })
})
)
it('should be possible to pass props to the Dialog itself', async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="setIsOpen(true)">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen" class="relative bg-blue-500">
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
assertDialog({ state: DialogState.InvisibleUnmounted })
await click(document.getElementById('trigger'))
assertDialog({ state: DialogState.Visible, attributes: { class: 'relative bg-blue-500' } })
})
it('should be possible to always render the Dialog if we provide it a `static` prop (and enable focus trapping based on `open`)', async () => {
let focusCounter = jest.fn()
renderTemplate({
template: `
<div>
<button>Trigger</button>
<Dialog :open="true" @close="() => {}" static>
<p>Contents</p>
<TabSentinel @focus="focusCounter" />
</Dialog>
</div>
`,
setup() {
return { focusCounter }
},
})
await new Promise<void>(nextTick)
// Let's verify that the Dialog is already there
expect(getDialog()).not.toBe(null)
expect(focusCounter).toHaveBeenCalledTimes(1)
})
it('should be possible to always render the Dialog if we provide it a `static` prop (and disable focus trapping based on `open`)', async () => {
let focusCounter = jest.fn()
renderTemplate({
template: `
<div>
<button>Trigger</button>
<Dialog :open="false" @close="() => {}" static>
<p>Contents</p>
<TabSentinel @focus="focusCounter" />
</Dialog>
</div>
`,
setup() {
return { focusCounter }
},
})
await new Promise<void>(nextTick)
// Let's verify that the Dialog is already there
expect(getDialog()).not.toBe(null)
expect(focusCounter).toHaveBeenCalledTimes(0)
})
it('should be possible to use a different render strategy for the Dialog', async () => {
let focusCounter = jest.fn()
renderTemplate({
template: `
<div>
<button id="trigger" @click="isOpen = !isOpen">Trigger</button>
<Dialog :open="isOpen" @close="setIsOpen" :unmount="false">
<TabSentinel @focus="focusCounter" />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
focusCounter,
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
await new Promise<void>(nextTick)
assertDialog({ state: DialogState.InvisibleHidden })
expect(focusCounter).toHaveBeenCalledTimes(0)
// Let's open the Dialog, to see if it is not hidden anymore
await click(document.getElementById('trigger'))
expect(focusCounter).toHaveBeenCalledTimes(1)
assertDialog({ state: DialogState.Visible })
// Let's close the Dialog
await press(Keys.Escape)
expect(focusCounter).toHaveBeenCalledTimes(1)
assertDialog({ state: DialogState.InvisibleHidden })
})
it(
'should add a scroll lock to the html tag',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
<input id="a" type="text" />
<input id="b" type="text" />
<input id="c" type="text" />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
// No overflow yet
expect(document.documentElement.style.overflow).toBe('')
let btn = document.getElementById('trigger')
// Open the dialog
await click(btn)
// Expect overflow
expect(document.documentElement.style.overflow).toBe('hidden')
})
)
})
describe('DialogOverlay', () => {
it(
'should be possible to render DialogOverlay using a render prop',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
<DialogOverlay v-slot="data">{{JSON.stringify(data)}}</DialogOverlay>
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
assertDialogOverlay({
state: DialogState.InvisibleUnmounted,
attributes: { id: 'headlessui-dialog-overlay-2' },
})
await click(document.getElementById('trigger'))
assertDialogOverlay({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-overlay-2' },
textContent: JSON.stringify({ open: true }),
})
})
)
})
describe('DialogTitle', () => {
it(
'should be possible to render DialogTitle using a render prop',
suppressConsoleLogs(async () => {
renderTemplate(
`
<Dialog :open="true" @close="() => {}">
<DialogTitle v-slot="data">{{JSON.stringify(data)}}</DialogTitle>
<TabSentinel />
</Dialog>
`
)
await new Promise<void>(nextTick)
assertDialog({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-1' },
})
assertDialogTitle({
state: DialogState.Visible,
textContent: JSON.stringify({ open: true }),
})
})
)
})
describe('DialogDescription', () => {
it(
'should be possible to render DialogDescription using a render prop',
suppressConsoleLogs(async () => {
renderTemplate(
`
<Dialog :open="true" @close="() => {}">
<DialogDescription v-slot="data">{{JSON.stringify(data)}}</DialogDescription>
<TabSentinel />
</Dialog>
`
)
await new Promise<void>(nextTick)
assertDialog({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-1' },
})
assertDialogDescription({
state: DialogState.Visible,
textContent: JSON.stringify({ open: true }),
})
})
)
})
})
describe('Composition', () => {
it(
'should be possible to open the Dialog via a Transition component',
suppressConsoleLogs(async () => {
renderTemplate({
components: { TransitionRoot },
template: `
<TransitionRoot show>
<Dialog @close="() => {}">
<DialogDescription v-slot="data">{{JSON.stringify(data)}}</DialogDescription>
<TabSentinel />
</Dialog>
</Transition>
`,
})
await new Promise<void>(nextTick)
assertDialog({ state: DialogState.Visible })
assertDialogDescription({
state: DialogState.Visible,
textContent: JSON.stringify({ open: true }),
})
})
)
it(
'should be possible to close the Dialog via a Transition component',
suppressConsoleLogs(async () => {
renderTemplate({
components: { TransitionRoot },
template: `
<TransitionRoot :show="false">
<Dialog @close="() => {}">
<DialogDescription v-slot="data">{{JSON.stringify(data)}}</DialogDescription>
<TabSentinel />
</Dialog>
</Transition>
`,
})
assertDialog({ state: DialogState.InvisibleUnmounted })
})
)
})
describe('Keyboard interactions', () => {
describe('`Escape` key', () => {
it(
'should be possible to close the dialog with Escape',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
Contents
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
assertDialog({ state: DialogState.InvisibleUnmounted })
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-1' },
})
// Close dialog
await press(Keys.Escape)
// Verify it is close
assertDialog({ state: DialogState.InvisibleUnmounted })
})
)
it(
'should be possible to close the dialog with Escape, when a field is focused',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
Contents
<input id="name" />
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
assertDialog({ state: DialogState.InvisibleUnmounted })
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-1' },
})
// Close dialog
await press(Keys.Escape)
// Verify it is close
assertDialog({ state: DialogState.InvisibleUnmounted })
})
)
it(
'should not be possible to close the dialog with Escape, when a field is focused but cancels the event',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
Contents
<input
id="name"
@keydown="cancel"
/>
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
cancel(event: KeyboardEvent) {
event.preventDefault()
event.stopPropagation()
},
}
},
})
assertDialog({ state: DialogState.InvisibleUnmounted })
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({
state: DialogState.Visible,
attributes: { id: 'headlessui-dialog-1' },
})
// Try to close the dialog
await press(Keys.Escape)
// Verify it is still open
assertDialog({ state: DialogState.Visible })
})
)
})
})
describe('Mouse interactions', () => {
it(
'should be possible to close a Dialog using a click on the DialogOverlay',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
<DialogOverlay />
Contents
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click to close
await click(getDialogOverlay())
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
})
)
it(
'should not close the Dialog when clicking on contents of the Dialog.Overlay',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button id="trigger" @click="toggleOpen">
Trigger
</button>
<Dialog :open="isOpen" @close="setIsOpen">
<DialogOverlay>
<button>hi</button>
</DialogOverlay>
Contents
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
toggleOpen() {
isOpen.value = !isOpen.value
},
}
},
})
// Open dialog
await click(document.getElementById('trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click on an element inside the overlay
await click(getByText('hi'))
// Verify it is still open
assertDialog({ state: DialogState.Visible })
})
)
it(
'should be possible to close the dialog, and re-focus the button when we click outside on the body element',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button @click="isOpen = !isOpen">Trigger</button>
<Dialog :open="isOpen" @close="setIsOpen">
Contents
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
// Open dialog
await click(getByText('Trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click the body to close
await click(document.body)
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify the button is focused
assertActiveElement(getByText('Trigger'))
})
)
it(
'should be possible to close the dialog, and keep focus on the focusable element',
suppressConsoleLogs(async () => {
renderTemplate({
template: `
<div>
<button>Hello</button>
<button @click="isOpen = !isOpen">Trigger</button>
<Dialog v-if="true" :open="isOpen" @close="setIsOpen">
Contents
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(false)
return {
isOpen,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
// Open dialog
await click(getByText('Trigger'))
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Click the button to close (outside click)
await click(getByText('Hello'))
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify the button is focused
assertActiveElement(getByText('Hello'))
})
)
it(
'should stop propagating click events when clicking on the Dialog.Overlay',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
renderTemplate({
template: `
<div @click="wrapperFn">
<Dialog v-if="true" :open="isOpen" @close="setIsOpen">
Contents
<DialogOverlay />
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(true)
return {
isOpen,
wrapperFn,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
// Click the Dialog.Overlay to close the Dialog
await click(getDialogOverlay())
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)
it(
'should be possible to submit a form inside a Dialog',
suppressConsoleLogs(async () => {
let submitFn = jest.fn()
renderTemplate({
template: `
<Dialog v-if="true" :open="isOpen" @close="setIsOpen">
<form @submit.prevent="submitFn">
<input type="hidden" value="abc" />
<button type="submit">Submit</button>
</form>
<TabSentinel />
</Dialog>
`,
setup() {
let isOpen = ref(true)
return {
isOpen,
submitFn,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Submit the form
await click(getByText('Submit'))
// Verify that the submitFn function has been called
expect(submitFn).toHaveBeenCalledTimes(1)
})
)
it(
'should stop propagating click events when clicking on an element inside the Dialog',
suppressConsoleLogs(async () => {
let wrapperFn = jest.fn()
renderTemplate({
template: `
<div @click="wrapperFn">
<Dialog v-if="true" :open="isOpen" @close="setIsOpen">
Contents
<button @click="setIsOpen(false)">Inside</button>
<TabSentinel />
</Dialog>
</div>
`,
setup() {
let isOpen = ref(true)
return {
isOpen,
wrapperFn,
setIsOpen(value: boolean) {
isOpen.value = value
},
}
},
})
// Verify it is open
assertDialog({ state: DialogState.Visible })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
// Click the button inside the the Dialog
await click(getByText('Inside'))
// Verify it is closed
assertDialog({ state: DialogState.InvisibleUnmounted })
// Verify that the wrapper function has not been called yet
expect(wrapperFn).toHaveBeenCalledTimes(0)
})
)
})
describe('Nesting', () => {
let Nested = defineComponent({
components: { Dialog, DialogOverlay },
emits: ['close'],
props: ['level'],
setup(props, { emit }) {
let showChild = ref(false)
function onClose() {
emit('close', false)
}
return () => {
let level = props.level ?? 1
return h(Dialog, { open: true, onClose: onClose }, () => [
h(DialogOverlay),
h('div', [
h('p', `Level: ${level}`),
h(
'button',
{
onClick: () => (showChild.value = true),
},
`Open ${level + 1} a`
),
h(
'button',
{
onClick: () => (showChild.value = true),
},
`Open ${level + 1} b`
),
h(
'button',
{
onClick: () => (showChild.value = true),
},
`Open ${level + 1} c`
),
]),
showChild.value &&
h(Nested, {
onClose: () => (showChild.value = false),
level: level + 1,
}),
])
}
},
})
it.each`
strategy | action
${'with `Escape`'} | ${() => press(Keys.Escape)}
${'with `Outside Click`'} | ${() => click(document.body)}
${'with `Click on Dialog.Overlay`'} | ${() => click(getDialogOverlays().pop()!)}
`(
'should be possible to open nested Dialog components and close them $strategy',
async ({ action }) => {
renderTemplate({
components: { Nested },
template: `
<button @click="isOpen = true">Open 1</button>
<Nested v-if="isOpen" @close="isOpen = false" />
`,
setup() {
let isOpen = ref(false)
return { isOpen }
},
})
// Verify we have no open dialogs
expect(getDialogs()).toHaveLength(0)
// Open Dialog 1
await click(getByText('Open 1'))
// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)
// Verify that the `Open 2 a` has focus
assertActiveElement(getByText('Open 2 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 a'))
// Open Dialog 2 via the second button
await click(getByText('Open 2 b'))
// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)
// Verify that the `Open 3 a` has focus
assertActiveElement(getByText('Open 3 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 a'))
// Close the top most Dialog
await action()
// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)
// Verify that the `Open 2 b` button got focused again
assertActiveElement(getByText('Open 2 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 b'))
// Open Dialog 2 via button b
await click(getByText('Open 2 b'))
// Verify that the `Open 3 a` has focus
assertActiveElement(getByText('Open 3 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 a'))
// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)
// Open Dialog 3 via button c
await click(getByText('Open 3 c'))
// Verify that the `Open 4 a` has focus
assertActiveElement(getByText('Open 4 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 4 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 4 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 4 a'))
// Verify that we have 3 open dialogs
expect(getDialogs()).toHaveLength(3)
// Close the top most Dialog
await action()
// Verify that the `Open 3 c` button got focused again
assertActiveElement(getByText('Open 3 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 3 c'))
// Verify that we have 2 open dialogs
expect(getDialogs()).toHaveLength(2)
// Close the top most Dialog
await action()
// Verify that we have 1 open dialog
expect(getDialogs()).toHaveLength(1)
// Verify that the `Open 2 b` button got focused again
assertActiveElement(getByText('Open 2 b'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 c'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 a'))
// Verify that we can tab around
await press(Keys.Tab)
assertActiveElement(getByText('Open 2 b'))
// Close the top most Dialog
await action()
// Verify that we have 0 open dialogs
expect(getDialogs()).toHaveLength(0)
// Verify that the `Open 1` button got focused again
assertActiveElement(getByText('Open 1'))
}
)
})