0
# Role Utilities
1
2
Work with ARIA roles and the accessibility tree to understand how assistive technologies perceive your UI.
3
4
## getRoles
5
6
Get all ARIA roles in a container mapped to their elements.
7
8
```typescript
9
function getRoles(container: HTMLElement): {
10
[index: string]: HTMLElement[];
11
};
12
```
13
14
Usage:
15
```javascript
16
import {getRoles} from '@testing-library/dom';
17
18
// Get all roles
19
const roles = getRoles(document.body);
20
// { button: [<button>, <button>], heading: [<h1>], link: [<a>, <a>] }
21
22
// Check specific role
23
const mainRoles = getRoles(document.body);
24
if (mainRoles.button) {
25
console.log(`Found ${mainRoles.button.length} buttons`);
26
}
27
28
// Get all elements with specific role
29
const allButtons = getRoles(document.body).button || [];
30
allButtons.forEach(button => console.log('Button:', button.textContent));
31
32
// In specific container
33
const nav = screen.getByRole('navigation');
34
const navRoles = getRoles(nav);
35
```
36
37
## logRoles
38
39
Log all roles with their elements to console.
40
41
```typescript
42
function logRoles(
43
container: HTMLElement,
44
options?: {hidden?: boolean}
45
): string;
46
```
47
48
Usage:
49
```javascript
50
import {logRoles, screen} from '@testing-library/dom';
51
52
// Log all roles
53
logRoles(document.body);
54
// Output:
55
// button:
56
// <button>Submit</button>
57
// heading:
58
// <h1>Welcome</h1>
59
60
// Include hidden elements
61
logRoles(document.body, {hidden: true});
62
63
// Capture output
64
const output = logRoles(document.body);
65
```
66
67
## isInaccessible
68
69
Check if element is inaccessible (hidden from screen readers).
70
71
```typescript
72
function isInaccessible(element: Element): boolean;
73
```
74
75
Usage:
76
```javascript
77
import {isInaccessible, screen} from '@testing-library/dom';
78
79
// Check accessibility
80
const button = screen.getByRole('button');
81
console.log('Is inaccessible:', isInaccessible(button)); // false
82
83
const hiddenDiv = document.getElementById('hidden-content');
84
console.log('Is inaccessible:', isInaccessible(hiddenDiv)); // true
85
86
// Filter accessible elements
87
const allElements = Array.from(document.querySelectorAll('*'));
88
const accessibleElements = allElements.filter(el => !isInaccessible(el));
89
90
// Validate in tests
91
test('content is accessible', () => {
92
const mainContent = document.getElementById('main-content');
93
expect(isInaccessible(mainContent)).toBe(false);
94
});
95
```
96
97
## computeHeadingLevel
98
99
Get heading level (1-6) from tag or aria-level.
100
101
```typescript
102
function computeHeadingLevel(element: Element): number | undefined;
103
```
104
105
Usage:
106
```javascript
107
import {computeHeadingLevel, screen} from '@testing-library/dom';
108
109
// From tag
110
const heading = document.querySelector('h1');
111
console.log(computeHeadingLevel(heading)); // 1
112
113
// From aria-level
114
const customHeading = document.querySelector('[role="heading"][aria-level="3"]');
115
console.log(computeHeadingLevel(customHeading)); // 3
116
117
// Validate heading hierarchy
118
test('proper structure', () => {
119
const headings = screen.getAllByRole('heading');
120
const levels = headings.map(computeHeadingLevel);
121
122
expect(levels[0]).toBe(1); // First heading is h1
123
124
// No skipped levels
125
for (let i = 1; i < levels.length; i++) {
126
expect(levels[i]).toBeLessThanOrEqual(levels[i - 1] + 1);
127
}
128
});
129
130
// Filter by level
131
const allHeadings = screen.getAllByRole('heading');
132
const h1Headings = allHeadings.filter(h => computeHeadingLevel(h) === 1);
133
const h2Headings = allHeadings.filter(h => computeHeadingLevel(h) === 2);
134
```
135
136
## Common Patterns
137
138
### Understanding Available Roles
139
140
```javascript
141
import {getRoles, logRoles} from '@testing-library/dom';
142
143
// Quick overview
144
logRoles(document.body);
145
146
// Or programmatically
147
const roles = getRoles(document.body);
148
Object.keys(roles).forEach(roleName => {
149
console.log(`${roleName}: ${roles[roleName].length} elements`);
150
});
151
```
152
153
### Debugging Query Failures
154
155
```javascript
156
import {logRoles, screen} from '@testing-library/dom';
157
158
test('find button', () => {
159
try {
160
screen.getByRole('button', {name: /submit/i});
161
} catch (error) {
162
console.log('Available roles:');
163
logRoles(document.body);
164
throw error;
165
}
166
});
167
```
168
169
### Validating Accessibility
170
171
```javascript
172
import {getRoles, isInaccessible} from '@testing-library/dom';
173
174
test('navigation is accessible', () => {
175
const nav = document.querySelector('nav');
176
expect(isInaccessible(nav)).toBe(false);
177
178
const roles = getRoles(nav);
179
expect(roles.link).toBeDefined();
180
expect(roles.link.length).toBeGreaterThan(0);
181
});
182
```
183
184
### Comprehensive Accessibility Check
185
186
```javascript
187
import {getRoles, isInaccessible, logRoles} from '@testing-library/dom';
188
189
function validateAccessibility(container) {
190
console.log('=== Accessibility Report ===');
191
192
logRoles(container);
193
194
const allElements = container.querySelectorAll('*');
195
const inaccessibleCount = Array.from(allElements)
196
.filter(isInaccessible).length;
197
198
console.log(`
199
Total elements: ${allElements.length}
200
Inaccessible: ${inaccessibleCount}
201
Accessible: ${allElements.length - inaccessibleCount}
202
`);
203
204
const roles = getRoles(container);
205
const interactiveRoles = ['button', 'link', 'textbox', 'combobox'];
206
const interactiveCount = interactiveRoles.reduce((sum, role) => {
207
return sum + (roles[role]?.length || 0);
208
}, 0);
209
210
console.log(`Interactive elements: ${interactiveCount}`);
211
212
return {
213
totalElements: allElements.length,
214
inaccessibleCount,
215
interactiveCount,
216
roles: Object.keys(roles)
217
};
218
}
219
```
220
221