Skip to content

Commit d4de509

Browse files
committed
refactor: tweaks
1 parent 6daaf9d commit d4de509

14 files changed

+101
-129
lines changed

src/helpers/accessibility.ts

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
import { AccessibilityState, AccessibilityValue, StyleSheet } from 'react-native';
1+
import {
2+
AccessibilityRole,
3+
AccessibilityState,
4+
AccessibilityValue,
5+
Role,
6+
StyleSheet,
7+
} from 'react-native';
28
import { ReactTestInstance } from 'react-test-renderer';
39
import { getHostSiblings, getUnsafeRootElement } from './component-tree';
410
import { getHostComponentNames, isHostSwitch, isHostText } from './host-component-names';
511
import { getTextContent } from './text-content';
12+
import { isTextInputEditable } from './text-input';
613

714
type IsInaccessibleOptions = {
815
cache?: WeakMap<ReactTestInstance, boolean>;
@@ -78,7 +85,7 @@ function isSubtreeInaccessible(element: ReactTestInstance): boolean {
7885
// iOS: accessibilityViewIsModal or aria-modal
7986
// See: https://reactnative.dev/docs/accessibility#accessibilityviewismodal-ios
8087
const hostSiblings = getHostSiblings(element);
81-
if (hostSiblings.some((sibling) => getAccessibilityViewIsModal(sibling))) {
88+
if (hostSiblings.some((sibling) => computeAriaModal(sibling))) {
8289
return true;
8390
}
8491

@@ -115,7 +122,7 @@ export function isAccessibilityElement(element: ReactTestInstance | null): boole
115122
* @param element
116123
* @returns
117124
*/
118-
export function getAccessibilityRole(element: ReactTestInstance) {
125+
export function getRole(element: ReactTestInstance): Role | AccessibilityRole {
119126
const explicitRole = element.props.role ?? element.props.accessibilityRole;
120127
if (explicitRole) {
121128
return explicitRole;
@@ -128,45 +135,30 @@ export function getAccessibilityRole(element: ReactTestInstance) {
128135
return 'none';
129136
}
130137

131-
export function getAccessibilityViewIsModal(element: ReactTestInstance) {
138+
export function computeAriaModal(element: ReactTestInstance): boolean | undefined {
132139
return element.props['aria-modal'] ?? element.props.accessibilityViewIsModal;
133140
}
134141

135-
export function getAccessibilityLabel(element: ReactTestInstance): string | undefined {
142+
export function computeAriaLabel(element: ReactTestInstance): string | undefined {
136143
return element.props['aria-label'] ?? element.props.accessibilityLabel;
137144
}
138145

139-
export function getAccessibilityLabelledBy(element: ReactTestInstance): string | undefined {
146+
export function computeAriaLabelledBy(element: ReactTestInstance): string | undefined {
140147
return element.props['aria-labelledby'] ?? element.props.accessibilityLabelledBy;
141148
}
142149

143-
export function computeAccessibilityState(element: ReactTestInstance): AccessibilityState {
144-
const busy = computeA11yBusy(element);
145-
const checked = computeA11yChecked(element);
146-
const disabled = computeA11Disabled(element);
147-
const expanded = computeA11yExpanded(element);
148-
const selected = computeA11ySelected(element);
149-
150-
return {
151-
busy,
152-
checked,
153-
disabled,
154-
expanded,
155-
selected,
156-
};
157-
}
158-
159-
export function computeA11yBusy(element: ReactTestInstance): AccessibilityState['busy'] {
160-
const props = element.props;
161-
return props['aria-busy'] ?? props.accessibilityState?.busy;
150+
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#busy-state
151+
export function computeAriaBusy({ props }: ReactTestInstance): boolean {
152+
return props['aria-busy'] ?? props.accessibilityState?.busy ?? false;
162153
}
163154

164-
export function computeA11yChecked(element: ReactTestInstance): AccessibilityState['checked'] {
155+
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#checked-state
156+
export function computeAriaChecked(element: ReactTestInstance): AccessibilityState['checked'] {
165157
if (isHostSwitch(element)) {
166158
return element.props.value;
167159
}
168160

169-
const role = getAccessibilityRole(element);
161+
const role = getRole(element);
170162
if (role !== 'checkbox' && role !== 'radio') {
171163
return undefined;
172164
}
@@ -175,22 +167,27 @@ export function computeA11yChecked(element: ReactTestInstance): AccessibilitySta
175167
return props['aria-checked'] ?? props.accessibilityState?.checked;
176168
}
177169

178-
export function computeA11Disabled(element: ReactTestInstance): AccessibilityState['disabled'] {
179-
const props = element.props;
180-
return props['aria-disabled'] ?? props.accessibilityState?.disabled;
170+
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#disabled-state
171+
export function computeAriaDisabled(element: ReactTestInstance): boolean {
172+
if (isHostSwitch(element)) {
173+
return !isTextInputEditable(element);
174+
}
175+
176+
const { props } = element;
177+
return props['aria-disabled'] ?? props.accessibilityState?.disabled ?? false;
181178
}
182179

183-
export function computeA11yExpanded(element: ReactTestInstance): AccessibilityState['expanded'] {
184-
const props = element.props;
180+
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#expanded-state
181+
export function computeAriaExpanded({ props }: ReactTestInstance): boolean | undefined {
185182
return props['aria-expanded'] ?? props.accessibilityState?.expanded;
186183
}
187184

188-
export function computeA11ySelected(element: ReactTestInstance): AccessibilityState['selected'] {
189-
const props = element.props;
190-
return props['aria-selected'] ?? props.accessibilityState?.selected;
185+
// See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#selected-state
186+
export function computeAriaSelected({ props }: ReactTestInstance): boolean {
187+
return props['aria-selected'] ?? props.accessibilityState?.selected ?? false;
191188
}
192189

193-
export function computeAccessibilityValue(element: ReactTestInstance): AccessibilityValue {
190+
export function computeAriaValue(element: ReactTestInstance): AccessibilityValue {
194191
const {
195192
accessibilityValue,
196193
'aria-valuemax': ariaValueMax,
@@ -208,12 +205,12 @@ export function computeAccessibilityValue(element: ReactTestInstance): Accessibi
208205
}
209206

210207
export function computeAccessibleName(element: ReactTestInstance): string | undefined {
211-
const label = getAccessibilityLabel(element);
208+
const label = computeAriaLabel(element);
212209
if (label) {
213210
return label;
214211
}
215212

216-
const labelElementId = getAccessibilityLabelledBy(element);
213+
const labelElementId = computeAriaLabelledBy(element);
217214
if (labelElementId) {
218215
const rootElement = getUnsafeRootElement(element);
219216
const labelElement = rootElement?.findByProps({ nativeID: labelElementId });
Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import { AccessibilityState } from 'react-native';
21
import { ReactTestInstance } from 'react-test-renderer';
3-
import { accessibilityStateKeys, computeAccessibilityState } from '../accessibility';
2+
import {
3+
computeAriaBusy,
4+
computeAriaChecked,
5+
computeAriaDisabled,
6+
computeAriaExpanded,
7+
computeAriaSelected,
8+
} from '../accessibility';
49

510
// This type is the same as AccessibilityState from `react-native` package
611
// It is re-declared here due to issues with migration from `@types/react-native` to
@@ -14,32 +19,25 @@ export interface AccessibilityStateMatcher {
1419
expanded?: boolean;
1520
}
1621

17-
/**
18-
* Default accessibility state values based on experiments using accessibility
19-
* inspector/screen reader on iOS and Android.
20-
*
21-
* @see https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State
22-
*/
23-
const defaultState: AccessibilityState = {
24-
disabled: false,
25-
selected: false,
26-
checked: undefined,
27-
busy: false,
28-
expanded: undefined,
29-
};
30-
3122
export function matchAccessibilityState(
3223
node: ReactTestInstance,
3324
matcher: AccessibilityStateMatcher,
3425
) {
35-
const state = computeAccessibilityState(node);
36-
return accessibilityStateKeys.every((key) => matchState(matcher, state, key));
37-
}
26+
if (matcher.busy !== undefined && matcher.busy !== computeAriaBusy(node)) {
27+
return false;
28+
}
29+
if (matcher.checked !== undefined && matcher.checked !== computeAriaChecked(node)) {
30+
return false;
31+
}
32+
if (matcher.disabled !== undefined && matcher.disabled !== computeAriaDisabled(node)) {
33+
return false;
34+
}
35+
if (matcher.expanded !== undefined && matcher.expanded !== computeAriaExpanded(node)) {
36+
return false;
37+
}
38+
if (matcher.selected !== undefined && matcher.selected !== computeAriaSelected(node)) {
39+
return false;
40+
}
3841

39-
function matchState(
40-
matcher: AccessibilityStateMatcher,
41-
state: AccessibilityState | undefined,
42-
key: keyof AccessibilityState,
43-
) {
44-
return matcher[key] === undefined || matcher[key] === (state?.[key] ?? defaultState[key]);
42+
return true;
4543
}

src/helpers/matchers/match-accessibility-value.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ReactTestInstance } from 'react-test-renderer';
2-
import { computeAccessibilityValue } from '../accessibility';
2+
import { computeAriaValue } from '../accessibility';
33
import { TextMatch } from '../../matches';
44
import { matchStringProp } from './match-string-prop';
55

@@ -14,7 +14,7 @@ export function matchAccessibilityValue(
1414
node: ReactTestInstance,
1515
matcher: AccessibilityValueMatcher,
1616
): boolean {
17-
const value = computeAccessibilityValue(node);
17+
const value = computeAriaValue(node);
1818
return (
1919
(matcher.min === undefined || matcher.min === value?.min) &&
2020
(matcher.max === undefined || matcher.max === value?.max) &&

src/helpers/matchers/match-label-text.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ReactTestInstance } from 'react-test-renderer';
22
import { matches, TextMatch, TextMatchOptions } from '../../matches';
3-
import { getAccessibilityLabel, getAccessibilityLabelledBy } from '../accessibility';
3+
import { computeAriaLabel, computeAriaLabelledBy } from '../accessibility';
44
import { findAll } from '../find-all';
55
import { matchTextContent } from './match-text-content';
66

@@ -12,7 +12,7 @@ export function matchLabelText(
1212
) {
1313
return (
1414
matchAccessibilityLabel(element, expectedText, options) ||
15-
matchAccessibilityLabelledBy(root, getAccessibilityLabelledBy(element), expectedText, options)
15+
matchAccessibilityLabelledBy(root, computeAriaLabelledBy(element), expectedText, options)
1616
);
1717
}
1818

@@ -21,7 +21,7 @@ function matchAccessibilityLabel(
2121
extpectedLabel: TextMatch,
2222
options: TextMatchOptions,
2323
) {
24-
return matches(extpectedLabel, getAccessibilityLabel(element), options.normalizer, options.exact);
24+
return matches(extpectedLabel, computeAriaLabel(element), options.normalizer, options.exact);
2525
}
2626

2727
function matchAccessibilityLabelledBy(

src/matchers/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
export { toBeBusy } from './to-be-busy';
22
export { toBeChecked } from './to-be-checked';
3-
export { toBeCollapsed } from './to-be-collapsed';
43
export { toBeDisabled, toBeEnabled } from './to-be-disabled';
54
export { toBeEmptyElement } from './to-be-empty-element';
6-
export { toBeExpanded } from './to-be-expanded';
5+
export { toBeExpanded, toBeCollapsed } from './to-be-expanded';
76
export { toBeOnTheScreen } from './to-be-on-the-screen';
87
export { toBePartiallyChecked } from './to-be-partially-checked';
98
export { toBeSelected } from './to-be-selected';

src/matchers/to-be-busy.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { ReactTestInstance } from 'react-test-renderer';
22
import { matcherHint } from 'jest-matcher-utils';
3-
import { computeA11yBusy } from '../helpers/accessibility';
3+
import { computeAriaBusy } from '../helpers/accessibility';
44
import { checkHostElement, formatElement } from './utils';
55

66
export function toBeBusy(this: jest.MatcherContext, element: ReactTestInstance) {
77
checkHostElement(element, toBeBusy, this);
88

99
return {
10-
pass: computeA11yBusy(element) === true,
10+
pass: computeAriaBusy(element),
1111
message: () => {
1212
const matcher = matcherHint(`${this.isNot ? '.not' : ''}.toBeBusy`, 'element', '');
1313
return [

src/matchers/to-be-checked.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import type { ReactTestInstance } from 'react-test-renderer';
22
import { matcherHint } from 'jest-matcher-utils';
3-
import {
4-
getAccessibilityRole,
5-
isAccessibilityElement,
6-
computeA11yChecked,
7-
} from '../helpers/accessibility';
3+
import { getRole, isAccessibilityElement, computeAriaChecked } from '../helpers/accessibility';
84
import { ErrorWithStack } from '../helpers/errors';
95
import { isHostSwitch } from '../helpers/host-component-names';
106
import { checkHostElement, formatElement } from './utils';
@@ -20,7 +16,7 @@ export function toBeChecked(this: jest.MatcherContext, element: ReactTestInstanc
2016
}
2117

2218
return {
23-
pass: computeA11yChecked(element) === true,
19+
pass: computeAriaChecked(element) === true,
2420
message: () => {
2521
const is = this.isNot ? 'is' : 'is not';
2622
return [
@@ -38,6 +34,6 @@ function isSupportedAccessibilityElement(element: ReactTestInstance) {
3834
return false;
3935
}
4036

41-
const role = getAccessibilityRole(element);
37+
const role = getRole(element);
4238
return role === 'checkbox' || role === 'radio';
4339
}

src/matchers/to-be-collapsed.tsx

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/matchers/to-be-disabled.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import type { ReactTestInstance } from 'react-test-renderer';
22
import { matcherHint } from 'jest-matcher-utils';
3-
import { isHostTextInput } from '../helpers/host-component-names';
4-
import { isTextInputEditable } from '../helpers/text-input';
3+
import { computeAriaDisabled } from '../helpers/accessibility';
54
import { getHostParent } from '../helpers/component-tree';
65
import { checkHostElement, formatElement } from './utils';
76

87
export function toBeDisabled(this: jest.MatcherContext, element: ReactTestInstance) {
98
checkHostElement(element, toBeDisabled, this);
109

11-
const isDisabled = isElementDisabled(element) || isAncestorDisabled(element);
10+
const isDisabled = computeAriaDisabled(element) || isAncestorDisabled(element);
1211

1312
return {
1413
pass: isDisabled,
@@ -27,7 +26,7 @@ export function toBeDisabled(this: jest.MatcherContext, element: ReactTestInstan
2726
export function toBeEnabled(this: jest.MatcherContext, element: ReactTestInstance) {
2827
checkHostElement(element, toBeEnabled, this);
2928

30-
const isEnabled = !isElementDisabled(element) && !isAncestorDisabled(element);
29+
const isEnabled = !computeAriaDisabled(element) && !isAncestorDisabled(element);
3130

3231
return {
3332
pass: isEnabled,
@@ -43,20 +42,11 @@ export function toBeEnabled(this: jest.MatcherContext, element: ReactTestInstanc
4342
};
4443
}
4544

46-
function isElementDisabled(element: ReactTestInstance) {
47-
if (isHostTextInput(element) && !isTextInputEditable(element)) {
48-
return true;
49-
}
50-
51-
const { accessibilityState, 'aria-disabled': ariaDisabled } = element.props;
52-
return ariaDisabled ?? accessibilityState?.disabled ?? false;
53-
}
54-
5545
function isAncestorDisabled(element: ReactTestInstance): boolean {
5646
const parent = getHostParent(element);
5747
if (parent == null) {
5848
return false;
5949
}
6050

61-
return isElementDisabled(parent) || isAncestorDisabled(parent);
51+
return computeAriaDisabled(parent) || isAncestorDisabled(parent);
6252
}

0 commit comments

Comments
 (0)