-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Expand file tree
/
Copy pathKbd.test.tsx
More file actions
165 lines (143 loc) · 5.59 KB
/
Copy pathKbd.test.tsx
File metadata and controls
165 lines (143 loc) · 5.59 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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright (c) Meta Platforms, Inc. and affiliates.
/**
* @file Kbd.test.tsx
* @input Uses React Testing Library, Kbd
* @output Tests for Kbd component
*
* Note: Tests run in jsdom which reports a non-Mac platform,
* so `mod` resolves to "Ctrl" rather than "\u2318" after the layout effect.
*/
import {render, screen} from '@testing-library/react';
import {describe, it, expect, afterEach} from 'vitest';
import {Kbd} from './Kbd';
describe('Kbd', () => {
const originalPlatform = navigator.platform;
afterEach(() => {
// Restore platform after any test that spoofs it \u2014 ensures no
// test pollution even if an assertion fails mid-test.
Object.defineProperty(navigator, 'platform', {
value: originalPlatform,
configurable: true,
});
delete (navigator as {userAgentData?: unknown}).userAgentData;
});
it('renders a single key', () => {
render(<Kbd keys="k" />);
const kbd = screen.getByText('K');
expect(kbd.tagName).toBe('KBD');
});
it('renders multiple keys separated by +', () => {
render(<Kbd keys="mod+k" />);
// In jsdom (non-Mac), mod renders as "Ctrl"
expect(screen.getByText('Ctrl')).toBeInTheDocument();
expect(screen.getByText('K')).toBeInTheDocument();
});
it('renders mod as Ctrl on non-Mac platforms', () => {
// jsdom is a non-Mac environment, so mod \u2192 Ctrl
render(<Kbd keys="mod" />);
expect(screen.getByText('Ctrl')).toBeInTheDocument();
});
it('renders mod as \u2318 on Mac platforms', () => {
Object.defineProperty(navigator, 'platform', {
value: 'MacIntel',
configurable: true,
});
render(<Kbd keys="mod" />);
expect(screen.getByText('\u2318')).toBeInTheDocument(); // \u2318
});
it('reads a blank userAgentData.platform as unknown, not as non-Mac', () => {
// Builds that rewrite their client-hints identity expose the key with an
// empty value; navigator.platform is the only surface left that answers.
Object.defineProperty(navigator, 'userAgentData', {
value: {platform: ''},
configurable: true,
});
Object.defineProperty(navigator, 'platform', {
value: 'MacIntel',
configurable: true,
});
render(<Kbd keys="mod" />);
expect(screen.getByText('\u2318')).toBeInTheDocument();
});
it('maps modifier keys to symbols', () => {
render(<Kbd keys="ctrl+alt+shift+k" />);
expect(screen.getByText('\u2303')).toBeInTheDocument(); // \u2303
expect(screen.getByText('\u2325')).toBeInTheDocument(); // \u2325
expect(screen.getByText('\u21E7')).toBeInTheDocument(); // \u21E7
expect(screen.getByText('K')).toBeInTheDocument();
});
it('maps special keys', () => {
render(<Kbd keys="enter" />);
expect(screen.getByText('\u21B5')).toBeInTheDocument(); // \u21B5
});
it('renders escape as text', () => {
render(<Kbd keys="escape" />);
expect(screen.getByText('Esc')).toBeInTheDocument();
});
it('exposes a spoken accessible name and hides the glyphs (obs-1)', () => {
render(<Kbd keys="mod+shift+k" />);
// The wrapper carries a screen-reader name built from spoken key labels
// (jsdom is non-Mac, so mod → "Control").
const img = screen.getByRole('img');
expect(img).toHaveAttribute('aria-label', 'Control + Shift + K');
// The visual glyph elements are hidden from assistive tech.
const glyphs = img.querySelectorAll('kbd');
glyphs.forEach(g => expect(g).toHaveAttribute('aria-hidden', 'true'));
expect(img).not.toHaveAttribute('aria-hidden');
});
it('uses "Command" in the accessible name for mod on Mac', () => {
Object.defineProperty(navigator, 'platform', {
value: 'MacIntel',
configurable: true,
});
render(<Kbd keys="mod+k" />);
expect(screen.getByRole('img')).toHaveAttribute(
'aria-label',
'Command + K',
);
});
it('uppercases unknown keys', () => {
render(<Kbd keys="f1" />);
expect(screen.getByText('F1')).toBeInTheDocument();
});
it('handles whitespace around keys', () => {
render(<Kbd keys="mod + k" />);
// In jsdom (non-Mac), mod renders as "Ctrl"
expect(screen.getByText('Ctrl')).toBeInTheDocument();
expect(screen.getByText('K')).toBeInTheDocument();
});
it('renders astryx-* class names for theme targeting', () => {
const {container} = render(<Kbd keys="k" />);
const wrapper = container.firstChild as HTMLElement;
expect(wrapper.className).toContain('astryx-kbd');
});
it('renders "plus" as a literal + key', () => {
render(<Kbd keys="shift+plus" />);
expect(screen.getByText('⇧')).toBeInTheDocument();
expect(screen.getByText('+')).toBeInTheDocument();
});
it('keeps the computed role and aria-label when unrelated rest props are spread', () => {
render(<Kbd keys="mod+k" data-testid="kbd" id="shortcut" />);
const el = screen.getByTestId('kbd');
// Pass-through attributes land on the wrapper...
expect(el).toHaveAttribute('id', 'shortcut');
// ...without disturbing the computed accessibility contract.
expect(el).toHaveAttribute('role', 'img');
expect(el).toHaveAttribute('aria-label', 'Control + K');
});
it('computed role and aria-label win over consumer-passed overrides', () => {
// Contract props the component computes must not be clobbered by
// pass-through attributes: {...rest} is spread before role/aria-label.
render(
<Kbd
keys="mod+k"
role="presentation"
aria-label="custom"
data-testid="kbd"
/>,
);
const el = screen.getByTestId('kbd');
expect(el).toHaveAttribute('role', 'img');
expect(el).toHaveAttribute('aria-label', 'Control + K');
});
});