import { type Mock, type SpyInstance, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { axe } from 'vitest-axe'
import type { DOMWrapper, VueWrapper } from '@vue/test-utils'
import { mount } from '@vue/test-utils'
import { defineComponent, nextTick } from 'vue'
import { DialogClose, DialogContent, DialogOverlay, DialogRoot, DialogTitle, DialogTrigger } from '.'
import { findByText, fireEvent, render } from '@testing-library/vue'
const OPEN_TEXT = 'Open'
const CLOSE_TEXT = 'Close'
const TITLE_TEXT = 'Title'
const NoLabelDialogTest = defineComponent({
components: { DialogRoot, DialogTrigger, DialogOverlay, DialogContent, DialogClose },
template: `
${OPEN_TEXT}
${CLOSE_TEXT}
`,
})
const UndefinedDescribedByDialog = defineComponent({
components: { DialogRoot, DialogTrigger, DialogOverlay, DialogContent, DialogClose, DialogTitle },
template: `
${OPEN_TEXT}
${TITLE_TEXT}
${CLOSE_TEXT}
`,
})
function renderAndClickDialogTrigger(Dialog: any) {
fireEvent.click(render(Dialog).getByText(OPEN_TEXT))
}
const DialogTest = defineComponent({
components: { DialogRoot, DialogTrigger, DialogOverlay, DialogContent, DialogClose, DialogTitle },
template: `
${OPEN_TEXT}
${TITLE_TEXT}
${CLOSE_TEXT}
`,
})
describe('given a default Dialog', () => {
let wrapper: VueWrapper>
let trigger: DOMWrapper
let closeButton: HTMLElement
let consoleWarnMock: SpyInstance
let consoleWarnMockFunction: Mock
beforeEach(() => {
document.body.innerHTML = ''
wrapper = mount(DialogTest, { attachTo: document.body })
trigger = wrapper.find('button')
consoleWarnMockFunction = vi.fn()
consoleWarnMock = vi.spyOn(console, 'warn').mockImplementation(consoleWarnMockFunction)
})
afterEach(() => {
consoleWarnMock.mockRestore()
consoleWarnMockFunction.mockClear
})
it('should pass axe accessibility tests', async () => {
expect(await axe(document.body)).toHaveNoViolations()
// open modal
wrapper.find('button').element.click()
await nextTick()
expect(await axe(document.body)).toHaveNoViolations()
})
describe('after clicking the trigger', () => {
beforeEach(async () => {
fireEvent.click(trigger.element)
closeButton = await findByText(document.body, CLOSE_TEXT)
})
describe('when no description has been provided', () => {
it('should warn to the console', () => {
expect(consoleWarnMockFunction).toHaveBeenCalledTimes(1)
})
})
describe('when no title has been provided', () => {
beforeEach(() => {
document.body.innerHTML = ''
})
it('should warn to the console', () => {
renderAndClickDialogTrigger(NoLabelDialogTest)
expect(consoleWarnMockFunction).toHaveBeenCalledTimes(1)
})
})
describe('when aria-describedby is set to undefined', () => {
beforeEach(() => {
document.body.innerHTML = ''
})
it('should not warn to the console', () => {
consoleWarnMockFunction.mockClear()
renderAndClickDialogTrigger(UndefinedDescribedByDialog)
expect(consoleWarnMockFunction).not.toHaveBeenCalled()
})
})
it('should open the content', () => {
expect(document.body.innerHTML).toContain(closeButton.innerHTML)
})
it('should focus the close button', () => {
expect(closeButton).toBe(document.activeElement)
})
describe('when pressing escape', () => {
beforeEach(() => {
fireEvent.keyDown(document.activeElement!, { key: 'Escape' })
})
it('should close the content', () => {
expect(document.body.innerHTML).not.toContain(closeButton.innerHTML)
})
it('should focus trigger', async () => {
expect(document.activeElement).toBe(trigger.element)
})
})
})
})