diff --git a/src/helpers/__tests__/accessiblity.test.tsx b/src/helpers/__tests__/accessiblity.test.tsx index bd54403d1..a58c96658 100644 --- a/src/helpers/__tests__/accessiblity.test.tsx +++ b/src/helpers/__tests__/accessiblity.test.tsx @@ -1,28 +1,34 @@ import React from 'react'; import { View, Text, TextInput } from 'react-native'; -import { render, isInaccessible } from '../..'; +import { render, isHiddenFromAccessibility, isInaccessible } from '../..'; test('returns false for accessible elements', () => { expect( - isInaccessible(render().getByTestId('subject')) + isHiddenFromAccessibility( + render().getByTestId('subject') + ) ).toBe(false); expect( - isInaccessible( + isHiddenFromAccessibility( render(Hello).getByTestId('subject') ) ).toBe(false); expect( - isInaccessible( + isHiddenFromAccessibility( render().getByTestId('subject') ) ).toBe(false); }); +test('returns true for hidden elements', () => { + expect(isHiddenFromAccessibility(null)).toBe(true); +}); + test('detects elements with accessibilityElementsHidden prop', () => { const view = render(); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects nested elements with accessibilityElementsHidden prop', () => { @@ -31,7 +37,7 @@ test('detects nested elements with accessibilityElementsHidden prop', () => { ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects deeply nested elements with accessibilityElementsHidden prop', () => { @@ -44,14 +50,14 @@ test('detects deeply nested elements with accessibilityElementsHidden prop', () ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects elements with importantForAccessibility="no-hide-descendants" prop', () => { const view = render( ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects nested elements with importantForAccessibility="no-hide-descendants" prop', () => { @@ -60,12 +66,12 @@ test('detects nested elements with importantForAccessibility="no-hide-descendant ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects elements with display=none', () => { const view = render(); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects nested elements with display=none', () => { @@ -74,7 +80,7 @@ test('detects nested elements with display=none', () => { ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects deeply nested elements with display=none', () => { @@ -87,7 +93,7 @@ test('detects deeply nested elements with display=none', () => { ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects elements with display=none with complex style', () => { @@ -97,12 +103,12 @@ test('detects elements with display=none with complex style', () => { style={[{ display: 'flex' }, [{ display: 'flex' }], { display: 'none' }]} /> ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('is not trigged by opacity = 0', () => { const view = render(); - expect(isInaccessible(view.getByTestId('subject'))).toBe(false); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(false); }); test('detects siblings of element with accessibilityViewIsModal prop', () => { @@ -112,7 +118,7 @@ test('detects siblings of element with accessibilityViewIsModal prop', () => { ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('detects deeply nested siblings of element with accessibilityViewIsModal prop', () => { @@ -126,7 +132,7 @@ test('detects deeply nested siblings of element with accessibilityViewIsModal pr ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(true); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(true); }); test('is not triggered for element with accessibilityViewIsModal prop', () => { @@ -135,7 +141,7 @@ test('is not triggered for element with accessibilityViewIsModal prop', () => { ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(false); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(false); }); test('is not triggered for child of element with accessibilityViewIsModal prop', () => { @@ -146,7 +152,7 @@ test('is not triggered for child of element with accessibilityViewIsModal prop', ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(false); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(false); }); test('is not triggered for descendent of element with accessibilityViewIsModal prop', () => { @@ -161,5 +167,9 @@ test('is not triggered for descendent of element with accessibilityViewIsModal p ); - expect(isInaccessible(view.getByTestId('subject'))).toBe(false); + expect(isHiddenFromAccessibility(view.getByTestId('subject'))).toBe(false); +}); + +test('has isInaccessible alias', () => { + expect(isInaccessible).toBe(isHiddenFromAccessibility); }); diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index 9ab4df787..15c6ef4e2 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -16,7 +16,7 @@ export const accessibilityStateKeys: AccessibilityStateKey[] = [ 'expanded', ]; -export function isInaccessible( +export function isHiddenFromAccessibility( element: ReactTestInstance | null, { cache }: IsInaccessibleOptions = {} ): boolean { @@ -43,13 +43,10 @@ export function isInaccessible( return false; } -export function isSubtreeInaccessible( - element: ReactTestInstance | null -): boolean { - if (element == null) { - return true; - } +/** RTL-compatitibility alias for `isHiddenFromAccessibility` */ +export const isInaccessible = isHiddenFromAccessibility; +function isSubtreeInaccessible(element: ReactTestInstance): boolean { // iOS: accessibilityElementsHidden // See: https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios if (element.props.accessibilityElementsHidden) { diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index 779b8f0b4..a29357cf6 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -1,6 +1,6 @@ import { ReactTestInstance } from 'react-test-renderer'; import { getConfig } from '../config'; -import { isInaccessible } from './accessiblity'; +import { isHiddenFromAccessibility } from './accessiblity'; interface FindAllOptions { hidden?: boolean; @@ -19,5 +19,7 @@ export function findAll( } const cache = new WeakMap(); - return results.filter((element) => !isInaccessible(element, { cache })); + return results.filter( + (element) => !isHiddenFromAccessibility(element, { cache }) + ); } diff --git a/src/pure.ts b/src/pure.ts index 00ed3d5ea..2996c6cd1 100644 --- a/src/pure.ts +++ b/src/pure.ts @@ -1,14 +1,19 @@ -import act from './act'; -import cleanup from './cleanup'; -import fireEvent from './fireEvent'; -import render from './render'; -import waitFor from './waitFor'; -import waitForElementToBeRemoved from './waitForElementToBeRemoved'; -import { within, getQueriesForElement } from './within'; -import { getDefaultNormalizer } from './matches'; -import { renderHook } from './renderHook'; -import { screen } from './screen'; -import { isInaccessible } from './helpers/accessiblity'; +export { default as act } from './act'; +export { default as cleanup } from './cleanup'; +export { default as fireEvent } from './fireEvent'; +export { default as render } from './render'; +export { default as waitFor } from './waitFor'; +export { default as waitForElementToBeRemoved } from './waitForElementToBeRemoved'; +export { within, getQueriesForElement } from './within'; + +export { configure, resetToDefaults } from './config'; +export { + isHiddenFromAccessibility, + isInaccessible, +} from './helpers/accessiblity'; +export { getDefaultNormalizer } from './matches'; +export { renderHook } from './renderHook'; +export { screen } from './screen'; export type { RenderOptions, @@ -17,16 +22,3 @@ export type { } from './render'; export type { RenderHookOptions, RenderHookResult } from './renderHook'; export type { Config } from './config'; - -export { act }; -export { cleanup }; -export { configure, resetToDefaults } from './config'; -export { fireEvent }; -export { render }; -export { waitFor }; -export { waitForElementToBeRemoved }; -export { within, getQueriesForElement }; -export { getDefaultNormalizer }; -export { renderHook }; -export { screen }; -export { isInaccessible }; diff --git a/typings/index.flow.js b/typings/index.flow.js index a639c13a1..7f30bad3d 100644 --- a/typings/index.flow.js +++ b/typings/index.flow.js @@ -472,13 +472,20 @@ declare module '@testing-library/react-native' { declare export var act: (callback: () => void) => Thenable; declare export var within: (instance: ReactTestInstance) => Queries; declare export var getQueriesForElement: ( - instance: ReactTestInstance + element: ReactTestInstance ) => Queries; declare export var getDefaultNormalizer: ( normalizerConfig?: NormalizerConfig ) => NormalizerFn; + declare export var isHiddenFromAccessibility: ( + element: ReactTestInstance | null + ) => boolean; + declare export var isInaccessible: ( + element: ReactTestInstance | null + ) => boolean; + declare type RenderHookResult = { rerender: (props: Props) => void, result: { current: Result }, diff --git a/website/docs/API.md b/website/docs/API.md index d7151b1cf..e8b76b5a6 100644 --- a/website/docs/API.md +++ b/website/docs/API.md @@ -57,7 +57,7 @@ title: API - [`RNTL_SKIP_AUTO_CLEANUP`](#rntl_skip_auto_cleanup) - [`RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS`](#rntl_skip_auto_detect_fake_timers) - [Accessibility](#accessibility) - - [`isInaccessible`](#isinaccessible) + - [`isHiddenFromAccessibility`](#ishiddenfromaccessibility) This page gathers public API of React Native Testing Library along with usage examples. @@ -825,16 +825,20 @@ $ RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS=true jest ## Accessibility -### `isInaccessible` +### `isHiddenFromAccessibility` ```ts -function isInaccessible(element: ReactTestInstance | null): boolean {} +function isHiddenFromAccessibility( + element: ReactTestInstance | null +): boolean {} ``` -Checks if given element is hidden from assistive technology, e.g. screen readers. +Also available as `isInaccessible()` alias for React Testing Library compatibility. + +Checks if given element is hidden from assistive technology, e.g. screen readers. :::note -Like [`isInaccessible`](https://testing-library.com/docs/dom-testing-library/api-accessibility/#isinaccessible) function from [DOM Testing Library](https://testing-library.com/docs/dom-testing-library/intro) this function considers both accessibility elements and presentational elements (regular `View`s) to be accessible, unless they are hidden in terms of host platform. +Like [`isInaccessible`](https://testing-library.com/docs/dom-testing-library/api-accessibility/#isinaccessible) function from DOM Testing Library this function considers both accessibility elements and presentational elements (regular `View`s) to be accessible, unless they are hidden in terms of host platform. This covers only part of [ARIA notion of Accessiblity Tree](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion), as ARIA excludes both hidden and presentational elements from the Accessibility Tree. ::: diff --git a/website/docs/Queries.md b/website/docs/Queries.md index 430311c6f..337cc08b4 100644 --- a/website/docs/Queries.md +++ b/website/docs/Queries.md @@ -382,7 +382,7 @@ All queries have the `hidden` option which enables them to respect accessibility You can configure the default value with the [`configure` function](API.md#configure). -An element is considered to be hidden from accessibility based on [`isInaccessible()`](./API.md#isinaccessible) function result. +An element is considered to be hidden from accessibility based on [`isHiddenFromAccessibility()`](./API.md#ishiddenfromaccessibility) function. **Examples**