-
Notifications
You must be signed in to change notification settings - Fork 202
Expand file tree
/
Copy pathHighContrastToggle.test.tsx
More file actions
105 lines (92 loc) · 3.69 KB
/
Copy pathHighContrastToggle.test.tsx
File metadata and controls
105 lines (92 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* HighContrastToggle tests
*
* Cover:
* 1. Renders a role="switch" button.
* 2. aria-checked reflects the current contrast mode.
* 3. Clicking the button calls toggleContrast.
* 4. axe-core reports no accessibility violations in normal mode.
* 5. axe-core reports no accessibility violations in high-contrast mode.
*
* Note on contrast ratio verification:
* jsdom does not compute CSS custom property values, so pixel-level contrast
* ratios cannot be verified here. The token values chosen in index.css are
* documented with their computed ratios and can be audited with a real
* browser run of axe-core (e.g. via Playwright + @axe-core/playwright).
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import axe from 'axe-core';
import { HighContrastToggle } from './HighContrastToggle';
import {
ContrastProvider,
type ContrastMode,
} from '../context/ContrastContext';
// ── Helper: ensure attribute is clean between tests ──────────────────────────
beforeEach(() => {
document.documentElement.removeAttribute('data-contrast');
});
// ── Helper: render the toggle inside a real provider ─────────────────────────
function renderToggle(preloadedMode?: ContrastMode) {
if (preloadedMode) {
window.localStorage.setItem(
'creditra-contrast',
JSON.stringify(preloadedMode),
);
}
return render(
<ContrastProvider>
<HighContrastToggle />
</ContrastProvider>,
);
}
// ── Tests ────────────────────────────────────────────────────────────────────
describe('HighContrastToggle', () => {
it('renders a switch button', () => {
renderToggle();
expect(screen.getByRole('switch')).toBeInTheDocument();
});
it('aria-checked is false when mode is normal', () => {
renderToggle('normal');
expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'false');
});
it('aria-checked is true when mode is high', () => {
renderToggle('high');
expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'true');
});
it('clicking the switch toggles the mode from normal to high', async () => {
renderToggle('normal');
expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'false');
await userEvent.click(screen.getByRole('switch'));
expect(screen.getByRole('switch')).toHaveAttribute('aria-checked', 'true');
expect(document.documentElement.getAttribute('data-contrast')).toBe('high');
});
it('passes axe audit in normal-contrast mode', async () => {
const { container } = renderToggle('normal');
const results = await axe.run(container);
expect(results.violations).toHaveLength(0);
});
it('passes axe audit in high-contrast mode', async () => {
const { container } = renderToggle('high');
const results = await axe.run(container);
expect(results.violations).toHaveLength(0);
});
it('renders compact variant without label group', () => {
render(
<ContrastProvider>
<HighContrastToggle compact />
</ContrastProvider>,
);
expect(
screen.queryByText('High Contrast'),
).not.toBeInTheDocument();
// The switch still exists
expect(screen.getByRole('switch')).toBeInTheDocument();
// compact variant has aria-label directly on button
expect(screen.getByRole('switch')).toHaveAttribute(
'aria-label',
'Toggle high contrast mode',
);
});
});