Skip to content

Commit

Permalink
feat: toBeVisible matcher (#1465)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
thiagobrez and mdjastrzebski committed Aug 25, 2023
1 parent b428cc5 commit f0fee35
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ test('resetToDefaults() resets config to defaults', () => {

test('resetToDefaults() resets internal config to defaults', () => {
configureInternal({
hostComponentNames: { text: 'A', textInput: 'A', switch: 'A' },
hostComponentNames: { text: 'A', textInput: 'A', switch: 'A', modal: 'A' },
});
expect(getConfig().hostComponentNames).toEqual({
text: 'A',
textInput: 'A',
switch: 'A',
modal: 'A',
});

resetToDefaults();
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/host-component-names.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ describe('getHostComponentNames', () => {
text: 'banana',
textInput: 'banana',
switch: 'banana',
modal: 'banana',
},
});

expect(getHostComponentNames()).toEqual({
text: 'banana',
textInput: 'banana',
switch: 'banana',
modal: 'banana',
});
});

Expand All @@ -40,6 +42,7 @@ describe('getHostComponentNames', () => {
text: 'Text',
textInput: 'TextInput',
switch: 'RCTSwitch',
modal: 'Modal',
});
expect(getConfig().hostComponentNames).toBe(hostComponentNames);
});
Expand Down Expand Up @@ -68,6 +71,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
text: 'Text',
textInput: 'TextInput',
switch: 'RCTSwitch',
modal: 'Modal',
});
});

Expand All @@ -77,6 +81,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
text: 'banana',
textInput: 'banana',
switch: 'banana',
modal: 'banana',
},
});

Expand All @@ -86,6 +91,7 @@ describe('configureHostComponentNamesIfNeeded', () => {
text: 'banana',
textInput: 'banana',
switch: 'banana',
modal: 'banana',
});
});

Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type HostComponentNames = {
text: string;
textInput: string;
switch: string;
modal: string;
};

export type InternalConfig = Config & {
Expand Down
26 changes: 26 additions & 0 deletions src/helpers/__tests__/accessiblity.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,32 @@ describe('isHiddenFromAccessibility', () => {
expect(isHiddenFromAccessibility(null)).toBe(true);
});

test('detects elements with aria-hidden prop', () => {
const view = render(<View testID="subject" aria-hidden />);
expect(
isHiddenFromAccessibility(
view.getByTestId('subject', {
includeHiddenElements: true,
})
)
).toBe(true);
});

test('detects nested elements with aria-hidden prop', () => {
const view = render(
<View aria-hidden>
<View testID="subject" />
</View>
);
expect(
isHiddenFromAccessibility(
view.getByTestId('subject', {
includeHiddenElements: true,
})
)
).toBe(true);
});

test('detects elements with accessibilityElementsHidden prop', () => {
const view = render(<View testID="subject" accessibilityElementsHidden />);
expect(
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/accessiblity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ function isSubtreeInaccessible(element: ReactTestInstance): boolean {
return false;
}

if (element.props['aria-hidden']) {
return true;
}

// iOS: accessibilityElementsHidden
// See: https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios
if (element.props.accessibilityElementsHidden) {
Expand Down
14 changes: 13 additions & 1 deletion src/helpers/host-component-names.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { ReactTestInstance } from 'react-test-renderer';
import { Switch, Text, TextInput, View } from 'react-native';
import { Modal, Switch, Text, TextInput, View } from 'react-native';
import { configureInternal, getConfig, HostComponentNames } from '../config';
import { renderWithAct } from '../render-act';
import { HostTestInstance } from './component-tree';
Expand Down Expand Up @@ -35,13 +35,15 @@ function detectHostComponentNames(): HostComponentNames {
<Text testID="text">Hello</Text>
<TextInput testID="textInput" />
<Switch testID="switch" />
<Modal testID="modal" />
</View>
);

return {
text: getByTestId(renderer.root, 'text').type as string,
textInput: getByTestId(renderer.root, 'textInput').type as string,
switch: getByTestId(renderer.root, 'switch').type as string,
modal: getByTestId(renderer.root, 'modal').type as string,
};
} catch (error) {
const errorMessage =
Expand Down Expand Up @@ -86,3 +88,13 @@ export function isHostTextInput(
): element is HostTestInstance {
return element?.type === getHostComponentNames().textInput;
}

/**
* Checks if the given element is a host Modal.
* @param element The element to check.
*/
export function isHostModal(
element?: ReactTestInstance | null
): element is HostTestInstance {
return element?.type === getHostComponentNames().modal;
}

0 comments on commit f0fee35

Please sign in to comment.