Skip to content

Commit 3f32966

Browse files
committed
refactor: support "switch" role
1 parent cdb1492 commit 3f32966

File tree

5 files changed

+81
-14
lines changed

5 files changed

+81
-14
lines changed

src/helpers/accessibility.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,17 @@ export function computeAriaBusy({ props }: ReactTestInstance): boolean {
159159

160160
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#checked-state
161161
export function computeAriaChecked(element: ReactTestInstance): AccessibilityState['checked'] {
162+
const { props } = element;
163+
162164
if (isHostSwitch(element)) {
163-
return element.props.value;
165+
return props.value;
164166
}
165167

166168
const role = getRole(element);
167-
if (role !== 'checkbox' && role !== 'radio') {
169+
if (!rolesSupportingCheckedState[role]) {
168170
return undefined;
169171
}
170172

171-
const props = element.props;
172173
return props['aria-checked'] ?? props.accessibilityState?.checked;
173174
}
174175

@@ -226,3 +227,11 @@ export function computeAccessibleName(element: ReactTestInstance): string | unde
226227

227228
return getTextContent(element);
228229
}
230+
231+
type RoleSupportMap = Partial<Record<Role | AccessibilityRole, true>>;
232+
233+
export const rolesSupportingCheckedState: RoleSupportMap = {
234+
checkbox: true,
235+
radio: true,
236+
switch: true,
237+
};

src/matchers/__tests__/to-be-checked.test.tsx

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ test('toBeCheck() with Switch', () => {
7979
`);
8080
});
8181

82-
test('toBeCheck() with checkbox role', () => {
82+
test('toBeCheck() with "checkbox" role', () => {
8383
renderViewsWithRole('checkbox');
8484

8585
const checked = screen.getByTestId('checkbox-checked');
@@ -149,7 +149,7 @@ test('toBeCheck() with checkbox role', () => {
149149
`);
150150
});
151151

152-
test('toBeCheck() with radio role', () => {
152+
test('toBeCheck() with "radio" role', () => {
153153
renderViewsWithRole('radio');
154154

155155
const checked = screen.getByTestId('radio-checked');
@@ -202,17 +202,70 @@ test('toBeCheck() with radio role', () => {
202202
`);
203203
});
204204

205+
test('toBeCheck() with "switch" role', () => {
206+
renderViewsWithRole('switch');
207+
208+
const checked = screen.getByTestId('switch-checked');
209+
const unchecked = screen.getByTestId('switch-unchecked');
210+
const defaultView = screen.getByTestId('switch-default');
211+
212+
expect(checked).toBeChecked();
213+
expect(unchecked).not.toBeChecked();
214+
expect(defaultView).not.toBeChecked();
215+
216+
expect(() => expect(checked).not.toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
217+
"expect(element).not.toBeChecked()
218+
219+
Received element is checked:
220+
<View
221+
accessibilityRole="switch"
222+
accessibilityState={
223+
{
224+
"checked": true,
225+
}
226+
}
227+
accessible={true}
228+
testID="switch-checked"
229+
/>"
230+
`);
231+
expect(() => expect(unchecked).toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
232+
"expect(element).toBeChecked()
233+
234+
Received element is not checked:
235+
<View
236+
accessibilityRole="switch"
237+
accessibilityState={
238+
{
239+
"checked": false,
240+
}
241+
}
242+
accessible={true}
243+
testID="switch-unchecked"
244+
/>"
245+
`);
246+
expect(() => expect(defaultView).toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
247+
"expect(element).toBeChecked()
248+
249+
Received element is not checked:
250+
<View
251+
accessibilityRole="switch"
252+
accessible={true}
253+
testID="switch-default"
254+
/>"
255+
`);
256+
});
257+
205258
test('throws error for invalid role', () => {
206259
renderViewsWithRole('adjustable');
207260

208261
const checked = screen.getByTestId('adjustable-checked');
209262
const unchecked = screen.getByTestId('adjustable-unchecked');
210263

211264
expect(() => expect(checked).toBeChecked()).toThrowErrorMatchingInlineSnapshot(
212-
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
265+
`"toBeChecked() works only on host "Switch" elements or accessibility elements with "checkbox", "radio" or "switch" role."`,
213266
);
214267
expect(() => expect(unchecked).not.toBeChecked()).toThrowErrorMatchingInlineSnapshot(
215-
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
268+
`"toBeChecked() works only on host "Switch" elements or accessibility elements with "checkbox", "radio" or "switch" role."`,
216269
);
217270
});
218271

@@ -221,6 +274,6 @@ test('throws error for non-accessibility element', () => {
221274

222275
const view = screen.getByTestId('test');
223276
expect(() => expect(view).toBeChecked()).toThrowErrorMatchingInlineSnapshot(
224-
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
277+
`"toBeChecked() works only on host "Switch" elements or accessibility elements with "checkbox", "radio" or "switch" role."`,
225278
);
226279
});

src/matchers/to-be-checked.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { ReactTestInstance } from 'react-test-renderer';
22
import { matcherHint } from 'jest-matcher-utils';
3-
import { computeAriaChecked, getRole, isAccessibilityElement } from '../helpers/accessibility';
3+
import {
4+
computeAriaChecked,
5+
getRole,
6+
isAccessibilityElement,
7+
rolesSupportingCheckedState,
8+
} from '../helpers/accessibility';
49
import { ErrorWithStack } from '../helpers/errors';
510
import { isHostSwitch } from '../helpers/host-component-names';
611
import { checkHostElement, formatElement } from './utils';
@@ -10,7 +15,7 @@ export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstanc
1015

1116
if (!isHostSwitch(element) && !isSupportedAccessibilityElement(element)) {
1217
throw new ErrorWithStack(
13-
`toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role.`,
18+
`toBeChecked() works only on host "Switch" elements or accessibility elements with "checkbox", "radio" or "switch" role.`,
1419
toBeChecked,
1520
);
1621
}
@@ -35,5 +40,5 @@ function isSupportedAccessibilityElement(element: ReactTestInstance) {
3540
}
3641

3742
const role = getRole(element);
38-
return role === 'checkbox' || role === 'radio';
43+
return rolesSupportingCheckedState[role];
3944
}

website/docs/12.x/docs/api/jest-matchers.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ These allow you to assert whether the given element is checked or partially chec
140140

141141
:::note
142142

143-
- `toBeChecked()` matcher works only on elements with the `checkbox` or `radio` role.
144-
- `toBePartiallyChecked()` matcher works only on elements with the `checkbox` role.
143+
- `toBeChecked()` matcher works only on `Switch` host elements and accessibility elements with `checkbox`, `radio` or `switch` role.
144+
- `toBePartiallyChecked()` matcher works only on elements with `checkbox` role.
145145

146146
:::
147147

website/docs/12.x/docs/migration/jest-matchers.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ New [`toHaveAccessibleName()`](docs/api/jest-matchers#tohaveaccessiblename) has
7171
You should be aware of the following details:
7272

7373
- [`toBeEnabled()` / `toBeDisabled()`](docs/api/jest-matchers#tobeenabled) matchers also check the disabled state for the element's ancestors and not only the element itself. This is the same as in legacy Jest Native matchers of the same name but differs from the removed `toHaveAccessibilityState()` matcher.
74-
- [`toBeChecked()`](docs/api/jest-matchers#tobechecked) matcher supports only elements with a `checkbox` or `radio` role
74+
- [`toBeChecked()`](docs/api/jest-matchers#tobechecked) matcher supports only elements with a `checkbox`, `radio` and 'switch' role
7575
- [`toBePartiallyChecked()`](docs/api/jest-matchers#tobechecked) matcher supports only elements with `checkbox` role

0 commit comments

Comments
 (0)