Skip to content

Commit cdb1492

Browse files
committed
feat: implement support for Switch toBeChecked
refactor: tweaks refactor: update tests chore: add Switch test chore: more tests refactor: self code review
1 parent 22ec13d commit cdb1492

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

src/helpers/accessibility.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import {
77
} from 'react-native';
88
import { ReactTestInstance } from 'react-test-renderer';
99
import { getHostSiblings, getUnsafeRootElement } from './component-tree';
10-
import { getHostComponentNames, isHostText, isHostTextInput } from './host-component-names';
10+
import {
11+
getHostComponentNames,
12+
isHostSwitch,
13+
isHostText,
14+
isHostTextInput,
15+
} from './host-component-names';
1116
import { getTextContent } from './text-content';
1217
import { isTextInputEditable } from './text-input';
1318

@@ -154,6 +159,10 @@ export function computeAriaBusy({ props }: ReactTestInstance): boolean {
154159

155160
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#checked-state
156161
export function computeAriaChecked(element: ReactTestInstance): AccessibilityState['checked'] {
162+
if (isHostSwitch(element)) {
163+
return element.props.value;
164+
}
165+
157166
const role = getRole(element);
158167
if (role !== 'checkbox' && role !== 'radio') {
159168
return undefined;

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

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { type AccessibilityRole, View } from 'react-native';
2+
import { type AccessibilityRole, Switch, View } from 'react-native';
33
import render from '../../render';
44
import { screen } from '../../screen';
55
import '../extend-expect';
@@ -30,6 +30,55 @@ function renderViewsWithRole(role: AccessibilityRole) {
3030
);
3131
}
3232

33+
test('toBeCheck() with Switch', () => {
34+
render(
35+
<>
36+
<Switch testID="checked" value={true} />
37+
<Switch testID="unchecked" value={false} />
38+
<Switch testID="default" />
39+
</>,
40+
);
41+
42+
const checked = screen.getByTestId('checked');
43+
const unchecked = screen.getByTestId('unchecked');
44+
const defaultView = screen.getByTestId('default');
45+
46+
expect(checked).toBeChecked();
47+
expect(unchecked).not.toBeChecked();
48+
expect(defaultView).not.toBeChecked();
49+
50+
expect(() => expect(checked).not.toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
51+
"expect(element).not.toBeChecked()
52+
53+
Received element is checked:
54+
<RCTSwitch
55+
accessibilityRole="switch"
56+
testID="checked"
57+
value={true}
58+
/>"
59+
`);
60+
expect(() => expect(unchecked).toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
61+
"expect(element).toBeChecked()
62+
63+
Received element is not checked:
64+
<RCTSwitch
65+
accessibilityRole="switch"
66+
testID="unchecked"
67+
value={false}
68+
/>"
69+
`);
70+
expect(() => expect(defaultView).toBeChecked()).toThrowErrorMatchingInlineSnapshot(`
71+
"expect(element).toBeChecked()
72+
73+
Received element is not checked:
74+
<RCTSwitch
75+
accessibilityRole="switch"
76+
testID="default"
77+
value={false}
78+
/>"
79+
`);
80+
});
81+
3382
test('toBeCheck() with checkbox role', () => {
3483
renderViewsWithRole('checkbox');
3584

@@ -160,10 +209,10 @@ test('throws error for invalid role', () => {
160209
const unchecked = screen.getByTestId('adjustable-unchecked');
161210

162211
expect(() => expect(checked).toBeChecked()).toThrowErrorMatchingInlineSnapshot(
163-
`"toBeChecked() works only on accessibility elements with "checkbox" or "radio" role."`,
212+
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
164213
);
165214
expect(() => expect(unchecked).not.toBeChecked()).toThrowErrorMatchingInlineSnapshot(
166-
`"toBeChecked() works only on accessibility elements with "checkbox" or "radio" role."`,
215+
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
167216
);
168217
});
169218

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

173222
const view = screen.getByTestId('test');
174223
expect(() => expect(view).toBeChecked()).toThrowErrorMatchingInlineSnapshot(
175-
`"toBeChecked() works only on accessibility elements with "checkbox" or "radio" role."`,
224+
`"toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role."`,
176225
);
177226
});

src/matchers/to-be-checked.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import type { ReactTestInstance } from 'react-test-renderer';
22
import { matcherHint } from 'jest-matcher-utils';
33
import { computeAriaChecked, getRole, isAccessibilityElement } from '../helpers/accessibility';
44
import { ErrorWithStack } from '../helpers/errors';
5+
import { isHostSwitch } from '../helpers/host-component-names';
56
import { checkHostElement, formatElement } from './utils';
67

78
export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstance) {
89
checkHostElement(element, toBeChecked, this);
910

10-
if (!hasValidAccessibilityRole(element)) {
11+
if (!isHostSwitch(element) && !isSupportedAccessibilityElement(element)) {
1112
throw new ErrorWithStack(
12-
`toBeChecked() works only on accessibility elements with "checkbox" or "radio" role.`,
13+
`toBeChecked() works only on "Switch" elements or accessibility elements with "checkbox" or "radio" role.`,
1314
toBeChecked,
1415
);
1516
}
@@ -28,7 +29,7 @@ export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstanc
2829
};
2930
}
3031

31-
function hasValidAccessibilityRole(element: ReactTestInstance) {
32+
function isSupportedAccessibilityElement(element: ReactTestInstance) {
3233
if (!isAccessibilityElement(element)) {
3334
return false;
3435
}

src/queries/__tests__/accessibility-state.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,14 +477,14 @@ describe('aria-checked prop', () => {
477477
});
478478

479479
test('supports aria-checked="mixed" prop', () => {
480-
render(<View accessible accessibilityRole="checkbox" aria-checked="mixed" />);
480+
render(<View accessible role="checkbox" aria-checked="mixed" />);
481481
expect(screen.getByAccessibilityState({ checked: 'mixed' })).toBeTruthy();
482482
expect(screen.queryByAccessibilityState({ checked: true })).toBeNull();
483483
expect(screen.queryByAccessibilityState({ checked: false })).toBeNull();
484484
});
485485

486486
test('supports default aria-checked prop', () => {
487-
render(<View accessible accessibilityRole="checkbox" />);
487+
render(<View accessible role="checkbox" />);
488488
expect(screen.getByAccessibilityState({})).toBeTruthy();
489489
expect(screen.queryByAccessibilityState({ checked: true })).toBeNull();
490490
expect(screen.queryByAccessibilityState({ checked: false })).toBeNull();

src/queries/__tests__/role.test.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TouchableOpacity,
88
TouchableWithoutFeedback,
99
View,
10+
Switch,
1011
} from 'react-native';
1112
import { render, screen } from '../..';
1213

@@ -426,7 +427,7 @@ describe('supports accessibility states', () => {
426427
expect(screen.queryByRole('checkbox', { checked: 'mixed' })).toBe(null);
427428
});
428429

429-
it('returns `mixed` checkboxes', () => {
430+
test('returns `mixed` checkboxes', () => {
430431
render(
431432
<TouchableOpacity accessibilityRole="checkbox" accessibilityState={{ checked: 'mixed' }} />,
432433
);
@@ -508,6 +509,14 @@ describe('supports accessibility states', () => {
508509
expect(screen.queryByRole('checkbox', { checked: false })).toBe(null);
509510
});
510511

512+
test('supports "Switch" component', () => {
513+
render(<Switch value={true} />);
514+
515+
expect(screen.getByRole('switch', { checked: true })).toBeTruthy();
516+
expect(screen.queryByRole('switch', { checked: false })).toBe(null);
517+
expect(screen.queryByRole('switch', { checked: 'mixed' })).toBe(null);
518+
});
519+
511520
test('supports aria-checked={true} prop', () => {
512521
render(<View accessible role="checkbox" aria-checked={true} />);
513522
expect(screen.getByRole('checkbox', { checked: true })).toBeTruthy();

0 commit comments

Comments
 (0)