// @vitest-environment jsdom
import { describe, it, expect, vi, afterEach } from 'vitest';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import Modal from '../../components/ui/Modal';
describe('Modal', () => {
afterEach(() => cleanup());
it('renders nothing when open is false', () => {
const { container } = render(
{}} title="Test">
body
);
expect(container.querySelector('[role="dialog"]')).toBeNull();
});
it('renders dialog with correct ARIA shape when open', () => {
render(
{}}
title="My Title"
description="My description"
>
body
);
const dialog = screen.getByRole('dialog');
expect(dialog.getAttribute('aria-modal')).toBe('true');
expect(dialog.getAttribute('aria-labelledby')).toBeTruthy();
expect(dialog.getAttribute('aria-describedby')).toBeTruthy();
expect(screen.getByText('My Title')).toBeTruthy();
expect(screen.getByText('My description')).toBeTruthy();
});
it('omits aria-describedby when no description is provided', () => {
render(
{}} title="t">
b
);
const dialog = screen.getByRole('dialog');
expect(dialog.getAttribute('aria-describedby')).toBeNull();
});
it('calls onClose on ESC keydown', () => {
const onClose = vi.fn();
render(
b
);
fireEvent.keyDown(document, { key: 'Escape' });
expect(onClose).toHaveBeenCalledTimes(1);
});
it('does NOT call onClose on ESC when closeOnEsc is false', () => {
const onClose = vi.fn();
render(
b
);
fireEvent.keyDown(document, { key: 'Escape' });
expect(onClose).not.toHaveBeenCalled();
});
it('calls onClose on backdrop click', () => {
const onClose = vi.fn();
render(
b
);
fireEvent.click(screen.getByRole('dialog'));
expect(onClose).toHaveBeenCalledTimes(1);
});
it('does NOT call onClose on backdrop click when closeOnBackdrop is false', () => {
const onClose = vi.fn();
render(
b
);
fireEvent.click(screen.getByRole('dialog'));
expect(onClose).not.toHaveBeenCalled();
});
it('renders a built-in close button with aria-label="Close" that triggers onClose', () => {
const onClose = vi.fn();
render(
b
);
const closeBtn = screen.getByRole('button', { name: /close/i });
fireEvent.click(closeBtn);
expect(onClose).toHaveBeenCalledTimes(1);
});
it('hides the built-in close button when hideCloseButton is true', () => {
render(
{}} title="t" hideCloseButton>
b
);
expect(
screen.queryByRole('button', { name: /close/i })
).toBeNull();
});
it('locks body-scroll when open and restores on close', () => {
const { rerender } = render(
{}} title="t">
b
);
expect(document.body.style.overflow).toBe('hidden');
rerender(
{}} title="t">
b
);
expect(document.body.style.overflow).toBe('');
});
});