Skip to content

Commit f0fee35

Browse files
feat: toBeVisible matcher (#1465)
* feat: add toBeVisible matcher * test(toBeVisible): improve snapshot matching * chore: detect Modal as host component * chore: fix tests to host component names * refactor: merge accessibility related code with existing utils * chore: add comments * refactor: tweak unit test * chore: fix test * refactor: tweaks --------- Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
1 parent b428cc5 commit f0fee35

File tree

11 files changed

+401
-2
lines changed

11 files changed

+401
-2
lines changed

src/__tests__/config.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ test('resetToDefaults() resets config to defaults', () => {
3535

3636
test('resetToDefaults() resets internal config to defaults', () => {
3737
configureInternal({
38-
hostComponentNames: { text: 'A', textInput: 'A', switch: 'A' },
38+
hostComponentNames: { text: 'A', textInput: 'A', switch: 'A', modal: 'A' },
3939
});
4040
expect(getConfig().hostComponentNames).toEqual({
4141
text: 'A',
4242
textInput: 'A',
4343
switch: 'A',
44+
modal: 'A',
4445
});
4546

4647
resetToDefaults();

src/__tests__/host-component-names.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ describe('getHostComponentNames', () => {
2121
text: 'banana',
2222
textInput: 'banana',
2323
switch: 'banana',
24+
modal: 'banana',
2425
},
2526
});
2627

2728
expect(getHostComponentNames()).toEqual({
2829
text: 'banana',
2930
textInput: 'banana',
3031
switch: 'banana',
32+
modal: 'banana',
3133
});
3234
});
3335

@@ -40,6 +42,7 @@ describe('getHostComponentNames', () => {
4042
text: 'Text',
4143
textInput: 'TextInput',
4244
switch: 'RCTSwitch',
45+
modal: 'Modal',
4346
});
4447
expect(getConfig().hostComponentNames).toBe(hostComponentNames);
4548
});
@@ -68,6 +71,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
6871
text: 'Text',
6972
textInput: 'TextInput',
7073
switch: 'RCTSwitch',
74+
modal: 'Modal',
7175
});
7276
});
7377

@@ -77,6 +81,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
7781
text: 'banana',
7882
textInput: 'banana',
7983
switch: 'banana',
84+
modal: 'banana',
8085
},
8186
});
8287

@@ -86,6 +91,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
8691
text: 'banana',
8792
textInput: 'banana',
8893
switch: 'banana',
94+
modal: 'banana',
8995
});
9096
});
9197

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type HostComponentNames = {
2424
text: string;
2525
textInput: string;
2626
switch: string;
27+
modal: string;
2728
};
2829

2930
export type InternalConfig = Config & {

src/helpers/__tests__/accessiblity.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,32 @@ describe('isHiddenFromAccessibility', () => {
4141
expect(isHiddenFromAccessibility(null)).toBe(true);
4242
});
4343

44+
test('detects elements with aria-hidden prop', () => {
45+
const view = render(<View testID="subject" aria-hidden />);
46+
expect(
47+
isHiddenFromAccessibility(
48+
view.getByTestId('subject', {
49+
includeHiddenElements: true,
50+
})
51+
)
52+
).toBe(true);
53+
});
54+
55+
test('detects nested elements with aria-hidden prop', () => {
56+
const view = render(
57+
<View aria-hidden>
58+
<View testID="subject" />
59+
</View>
60+
);
61+
expect(
62+
isHiddenFromAccessibility(
63+
view.getByTestId('subject', {
64+
includeHiddenElements: true,
65+
})
66+
)
67+
).toBe(true);
68+
});
69+
4470
test('detects elements with accessibilityElementsHidden prop', () => {
4571
const view = render(<View testID="subject" accessibilityElementsHidden />);
4672
expect(

src/helpers/accessiblity.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ function isSubtreeInaccessible(element: ReactTestInstance): boolean {
6262
return false;
6363
}
6464

65+
if (element.props['aria-hidden']) {
66+
return true;
67+
}
68+
6569
// iOS: accessibilityElementsHidden
6670
// See: https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios
6771
if (element.props.accessibilityElementsHidden) {

src/helpers/host-component-names.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { ReactTestInstance } from 'react-test-renderer';
3-
import { Switch, Text, TextInput, View } from 'react-native';
3+
import { Modal, Switch, Text, TextInput, View } from 'react-native';
44
import { configureInternal, getConfig, HostComponentNames } from '../config';
55
import { renderWithAct } from '../render-act';
66
import { HostTestInstance } from './component-tree';
@@ -35,13 +35,15 @@ function detectHostComponentNames(): HostComponentNames {
3535
<Text testID="text">Hello</Text>
3636
<TextInput testID="textInput" />
3737
<Switch testID="switch" />
38+
<Modal testID="modal" />
3839
</View>
3940
);
4041

4142
return {
4243
text: getByTestId(renderer.root, 'text').type as string,
4344
textInput: getByTestId(renderer.root, 'textInput').type as string,
4445
switch: getByTestId(renderer.root, 'switch').type as string,
46+
modal: getByTestId(renderer.root, 'modal').type as string,
4547
};
4648
} catch (error) {
4749
const errorMessage =
@@ -86,3 +88,13 @@ export function isHostTextInput(
8688
): element is HostTestInstance {
8789
return element?.type === getHostComponentNames().textInput;
8890
}
91+
92+
/**
93+
* Checks if the given element is a host Modal.
94+
* @param element The element to check.
95+
*/
96+
export function isHostModal(
97+
element?: ReactTestInstance | null
98+
): element is HostTestInstance {
99+
return element?.type === getHostComponentNames().modal;
100+
}

0 commit comments

Comments
 (0)