Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||
import { useState } from 'react'
|
||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||
|
||
import Modal from '@/components/modals/Modal'
|
||
|
||
function mockMatchMedia(matches: boolean) {
|
||
Object.defineProperty(window, 'matchMedia', {
|
||
writable: true,
|
||
configurable: true,
|
||
value: vi.fn().mockImplementation((query: string) => ({
|
||
matches: matches && query === '(max-width: 768px)',
|
||
media: query,
|
||
onchange: null,
|
||
addListener: () => {},
|
||
removeListener: () => {},
|
||
addEventListener: () => {},
|
||
removeEventListener: () => {},
|
||
dispatchEvent: () => false,
|
||
})),
|
||
})
|
||
}
|
||
|
||
afterEach(cleanup)
|
||
|
||
beforeEach(() => {
|
||
mockMatchMedia(false)
|
||
})
|
||
|
||
function ModalHarness() {
|
||
const [isOpen, setIsOpen] = useState(false)
|
||
|
||
return (
|
||
<>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setIsOpen(true)
|
||
}}
|
||
>
|
||
باز کردن
|
||
</button>
|
||
<Modal
|
||
hideFooter
|
||
isOpen={isOpen}
|
||
title="ویرایش"
|
||
onOpenChange={setIsOpen}
|
||
>
|
||
<button type="button">عملیات مودال</button>
|
||
</Modal>
|
||
</>
|
||
)
|
||
}
|
||
|
||
describe('Modal', () => {
|
||
it('contains focus, closes with Escape, and restores focus to its trigger', async () => {
|
||
render(<ModalHarness />)
|
||
|
||
const trigger = screen.getByRole('button', { name: 'باز کردن' })
|
||
|
||
trigger.focus()
|
||
fireEvent.click(trigger)
|
||
|
||
const dialog = await screen.findByRole('dialog', { name: 'ویرایش' })
|
||
|
||
await waitFor(() => expect(dialog).toContainElement(document.activeElement as HTMLElement))
|
||
|
||
trigger.focus()
|
||
await waitFor(() => expect(dialog).toContainElement(document.activeElement as HTMLElement))
|
||
|
||
fireEvent.keyDown(document.activeElement as HTMLElement, { key: 'Escape' })
|
||
|
||
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument())
|
||
await waitFor(() => expect(trigger).toHaveFocus())
|
||
})
|
||
|
||
it('opens as a bottom sheet on mobile by default', async () => {
|
||
mockMatchMedia(true)
|
||
|
||
render(<ModalHarness />)
|
||
fireEvent.click(screen.getByRole('button', { name: 'باز کردن' }))
|
||
|
||
const dialog = await screen.findByRole('dialog', { name: 'ویرایش' })
|
||
|
||
expect(dialog.className).toContain('mt-auto')
|
||
expect(dialog.className).toContain('rounded-b-none')
|
||
expect(dialog.className).toContain('max-h-full')
|
||
expect(dialog.className).not.toContain('--keyboard-inset')
|
||
})
|
||
})
|