import { render, screen, fireEvent, act } from '@testing-library/react';
import { vi, beforeEach, afterEach, test, expect } from 'vitest';
import Tooltips, { tipFor } from './Tooltips.jsx';
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
const over = (el) => act(() => { fireEvent.pointerOver(el); vi.advanceTimersByTime(600); });
function setup() {
render(
<>
>,
);
}
test('shows a data-tip after a short pause, and hides when the pointer leaves', () => {
setup();
const btn = screen.getByLabelText('Search');
over(btn);
expect(screen.getByRole('tooltip')).toHaveTextContent('Search (/)');
expect(btn).toHaveAttribute('aria-describedby', 'app-tooltip');
act(() => { fireEvent.pointerOut(btn); });
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
expect(btn).not.toHaveAttribute('aria-describedby');
});
test('does not appear before the pause', () => {
setup();
act(() => { fireEvent.pointerOver(screen.getByLabelText('Search')); vi.advanceTimersByTime(100); });
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('an icon-only button shows its label', () => {
setup();
over(screen.getByLabelText('Close'));
expect(screen.getByRole('tooltip')).toHaveTextContent('Close');
});
test('a title is shown in the app style and the browser\'s own tooltip is turned off', () => {
setup();
const btn = screen.getByText('โ');
over(btn);
expect(screen.getByRole('tooltip')).toHaveTextContent('Out a level (Shift+Tab)');
expect(btn).not.toHaveAttribute('title');
expect(btn).toHaveAttribute('aria-label', 'Out a level (Shift+Tab)'); // a screen reader still gets its name
});
test('a button that already says what it is gets no tooltip, and neither does a disabled one', () => {
setup();
over(screen.getByText('Save changes'));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
over(screen.getByLabelText('Nothing'));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('clicking, scrolling or Escape dismisses it', () => {
setup();
const btn = screen.getByLabelText('Search');
over(btn);
act(() => { fireEvent.pointerDown(btn); });
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
over(btn);
act(() => { fireEvent.keyDown(document, { key: 'Escape' }); });
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
over(btn);
act(() => { fireEvent.scroll(window); });
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('nothing shows on a device without hover (touch)', () => {
vi.stubGlobal('matchMedia', () => ({ matches: false }));
setup();
over(screen.getByLabelText('Search'));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
vi.unstubAllGlobals();
});
test('tipFor ignores things that are not elements', () => {
expect(tipFor(null)).toBe('');
expect(tipFor(document.createTextNode('x'))).toBe('');
});