mirror of
https://github.com/callstack/react-native-testing-library.git
synced 2026-09-18 23:09:04 +08:00
feat: byA11yState matcher (#260)
* feat: byA11yState matcher * Kick CI * Update src/helpers/a11yAPI.js Co-Authored-By: Michał Pierzchała <thymikee@gmail.com> * Correct types Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
This commit is contained in:
@@ -9,11 +9,12 @@ const BUTTON_ROLE = 'button';
|
||||
const TEXT_LABEL = 'cool text';
|
||||
const TEXT_HINT = 'static text';
|
||||
const TEXT_ROLE = 'link';
|
||||
const NO_MATCHES_TEXT = 'not-existent-element';
|
||||
// Little hack to make all the methods happy with type
|
||||
const NO_MATCHES_TEXT: any = 'not-existent-element';
|
||||
const NO_INSTANCES_FOUND = 'No instances found';
|
||||
const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances';
|
||||
|
||||
const Typography = ({ children, ...rest }) => {
|
||||
const Typography = ({ children, ...rest }: any) => {
|
||||
return <Text {...rest}>{children}</Text>;
|
||||
};
|
||||
|
||||
@@ -31,6 +32,7 @@ class Button extends React.Component<any> {
|
||||
accessibilityLabel={TEXT_LABEL}
|
||||
accessibilityRole={TEXT_ROLE}
|
||||
accessibilityStates={['selected']}
|
||||
accessibilityState={{ expanded: false, selected: true }}
|
||||
>
|
||||
{this.props.children}
|
||||
</Typography>
|
||||
@@ -47,6 +49,7 @@ function Section() {
|
||||
accessibilityLabel={TEXT_LABEL}
|
||||
accessibilityRole={TEXT_ROLE}
|
||||
accessibilityStates={['selected', 'disabled']}
|
||||
accessibilityState={{ expanded: false }}
|
||||
>
|
||||
Title
|
||||
</Typography>
|
||||
@@ -159,3 +162,43 @@ test('getAllByA11yStates, queryAllByA11yStates', () => {
|
||||
expect(() => getAllByA11yStates([])).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(queryAllByA11yStates(NO_MATCHES_TEXT)).toEqual([]);
|
||||
});
|
||||
|
||||
test('getByA11yState, queryByA11yState', () => {
|
||||
const { getByA11yState, queryByA11yState } = render(<Section />);
|
||||
|
||||
expect(getByA11yState({ selected: true }).props.accessibilityState).toEqual({
|
||||
selected: true,
|
||||
expanded: false,
|
||||
});
|
||||
expect(
|
||||
queryByA11yState({ selected: true })?.props.accessibilityState
|
||||
).toEqual({
|
||||
selected: true,
|
||||
expanded: false,
|
||||
});
|
||||
|
||||
expect(() => getByA11yState({ disabled: true })).toThrow(NO_INSTANCES_FOUND);
|
||||
expect(queryByA11yState({ disabled: true })).toEqual(null);
|
||||
|
||||
expect(() => getByA11yState({ expanded: false })).toThrow(
|
||||
FOUND_TWO_INSTANCES
|
||||
);
|
||||
expect(() => queryByA11yState({ expanded: false })).toThrow(
|
||||
FOUND_TWO_INSTANCES
|
||||
);
|
||||
});
|
||||
|
||||
test('getAllByA11yState, queryAllByA11yState', () => {
|
||||
const { getAllByA11yState, queryAllByA11yState } = render(<Section />);
|
||||
|
||||
expect(getAllByA11yState({ selected: true }).length).toEqual(1);
|
||||
expect(queryAllByA11yState({ selected: true }).length).toEqual(1);
|
||||
|
||||
expect(() => getAllByA11yState({ disabled: true })).toThrow(
|
||||
NO_INSTANCES_FOUND
|
||||
);
|
||||
expect(queryAllByA11yState({ disabled: true })).toEqual([]);
|
||||
|
||||
expect(getAllByA11yState({ expanded: false }).length).toEqual(2);
|
||||
expect(queryAllByA11yState({ expanded: false }).length).toEqual(2);
|
||||
});
|
||||
|
||||
+57
-28
@@ -1,37 +1,48 @@
|
||||
// @flow
|
||||
import makeQuery from './makeQuery';
|
||||
import type { A11yRole, A11yStates, A11yState } from '../types.flow';
|
||||
|
||||
type QueryFn = (string | RegExp) => ReactTestInstance | null;
|
||||
type QueryAllFn = (string | RegExp) => Array<ReactTestInstance> | [];
|
||||
type GetFn = (string | RegExp) => ReactTestInstance;
|
||||
type GetAllFn = (string | RegExp) => Array<ReactTestInstance>;
|
||||
type ArrayQueryFn = (string | Array<string>) => ReactTestInstance | null;
|
||||
type ArrayQueryAllFn = (
|
||||
string | Array<string>
|
||||
) => Array<ReactTestInstance> | [];
|
||||
type ArrayGetFn = (string | Array<string>) => ReactTestInstance;
|
||||
type ArrayGetAllFn = (string | Array<string>) => Array<ReactTestInstance>;
|
||||
type GetReturn = ReactTestInstance;
|
||||
type GetAllReturn = Array<ReactTestInstance>;
|
||||
type QueryReturn = ReactTestInstance | null;
|
||||
type QueryAllReturn = Array<ReactTestInstance> | [];
|
||||
|
||||
type A11yAPI = {|
|
||||
getByA11yLabel: GetFn,
|
||||
getAllByA11yLabel: GetAllFn,
|
||||
queryByA11yLabel: QueryFn,
|
||||
queryAllByA11yLabel: QueryAllFn,
|
||||
getByA11yHint: GetFn,
|
||||
getAllByA11yHint: GetAllFn,
|
||||
queryByA11yHint: QueryFn,
|
||||
queryAllByA11yHint: QueryAllFn,
|
||||
getByA11yRole: GetFn,
|
||||
getAllByA11yRole: GetAllFn,
|
||||
queryByA11yRole: QueryFn,
|
||||
queryAllByA11yRole: QueryAllFn,
|
||||
getByA11yStates: ArrayGetFn,
|
||||
getAllByA11yStates: ArrayGetAllFn,
|
||||
queryByA11yStates: ArrayQueryFn,
|
||||
queryAllByA11yStates: ArrayQueryAllFn,
|
||||
// Label
|
||||
getByA11yLabel: (string | RegExp) => GetReturn,
|
||||
getAllByA11yLabel: (string | RegExp) => GetAllReturn,
|
||||
queryByA11yLabel: (string | RegExp) => QueryReturn,
|
||||
queryAllByA11yLabel: (string | RegExp) => QueryAllReturn,
|
||||
|
||||
// Hint
|
||||
getByA11yHint: (string | RegExp) => GetReturn,
|
||||
getAllByA11yHint: (string | RegExp) => GetAllReturn,
|
||||
queryByA11yHint: (string | RegExp) => QueryReturn,
|
||||
queryAllByA11yHint: (string | RegExp) => QueryAllReturn,
|
||||
|
||||
// Role
|
||||
getByA11yRole: (A11yRole | RegExp) => GetReturn,
|
||||
getAllByA11yRole: (A11yRole | RegExp) => GetAllReturn,
|
||||
queryByA11yRole: (A11yRole | RegExp) => QueryReturn,
|
||||
queryAllByA11yRole: (A11yRole | RegExp) => QueryAllReturn,
|
||||
|
||||
// States
|
||||
getByA11yStates: (A11yStates | Array<A11yStates>) => GetReturn,
|
||||
getAllByA11yStates: (A11yStates | Array<A11yStates>) => GetAllReturn,
|
||||
queryByA11yStates: (A11yStates | Array<A11yStates>) => QueryReturn,
|
||||
queryAllByA11yStates: (A11yStates | Array<A11yStates>) => QueryAllReturn,
|
||||
|
||||
// State
|
||||
getByA11yState: A11yState => GetReturn,
|
||||
getAllByA11yState: A11yState => GetAllReturn,
|
||||
queryByA11yState: A11yState => QueryReturn,
|
||||
queryAllByA11yState: A11yState => QueryAllReturn,
|
||||
|};
|
||||
|
||||
export function matchStringValue(prop?: string, matcher: string | RegExp) {
|
||||
export function matchStringValue(
|
||||
prop?: string,
|
||||
matcher: string | RegExp
|
||||
): boolean {
|
||||
if (!prop) {
|
||||
return false;
|
||||
}
|
||||
@@ -46,7 +57,7 @@ export function matchStringValue(prop?: string, matcher: string | RegExp) {
|
||||
export function matchArrayValue(
|
||||
prop?: Array<string>,
|
||||
matcher: string | Array<string>
|
||||
) {
|
||||
): boolean {
|
||||
if (!prop || matcher.length === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -58,6 +69,14 @@ export function matchArrayValue(
|
||||
return !matcher.some(e => !prop.includes(e));
|
||||
}
|
||||
|
||||
export function matchObject<T: {}>(prop?: T, matcher: T): boolean {
|
||||
return prop
|
||||
? Object.keys(matcher).length !== 0 &&
|
||||
Object.keys(prop).length !== 0 &&
|
||||
!Object.keys(matcher).some(key => prop[key] !== matcher[key])
|
||||
: false;
|
||||
}
|
||||
|
||||
const a11yAPI = (instance: ReactTestInstance): A11yAPI =>
|
||||
({
|
||||
...makeQuery(
|
||||
@@ -100,6 +119,16 @@ const a11yAPI = (instance: ReactTestInstance): A11yAPI =>
|
||||
},
|
||||
matchArrayValue
|
||||
)(instance),
|
||||
...makeQuery(
|
||||
'accessibilityState',
|
||||
{
|
||||
getBy: ['getByA11yState', 'getByAccessibilityState'],
|
||||
getAllBy: ['getAllByA11yState', 'getAllByAccessibilityState'],
|
||||
queryBy: ['queryByA11yState', 'queryByAccessibilityState'],
|
||||
queryAllBy: ['queryAllByA11yState', 'queryAllByAccessibilityState'],
|
||||
},
|
||||
matchObject
|
||||
)(instance),
|
||||
}: any);
|
||||
|
||||
export default a11yAPI;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// @flow
|
||||
|
||||
export type A11yRole =
|
||||
| 'none'
|
||||
| 'button'
|
||||
| 'link'
|
||||
| 'search'
|
||||
| 'image'
|
||||
| 'keyboardkey'
|
||||
| 'text'
|
||||
| 'adjustable'
|
||||
| 'imagebutton'
|
||||
| 'header'
|
||||
| 'summary'
|
||||
| 'alert'
|
||||
| 'checkbox'
|
||||
| 'combobox'
|
||||
| 'menu'
|
||||
| 'menubar'
|
||||
| 'menuitem'
|
||||
| 'progressbar'
|
||||
| 'radio'
|
||||
| 'radiogroup'
|
||||
| 'scrollbar'
|
||||
| 'spinbutton'
|
||||
| 'switch'
|
||||
| 'tab'
|
||||
| 'tablist'
|
||||
| 'timer'
|
||||
| 'toolbar';
|
||||
|
||||
export type A11yState = {|
|
||||
disabled?: boolean,
|
||||
selected?: boolean,
|
||||
checked?: boolean | 'mixed',
|
||||
busy?: boolean,
|
||||
expanded?: boolean,
|
||||
|};
|
||||
|
||||
export type A11yStates =
|
||||
| 'disabled'
|
||||
| 'selected'
|
||||
| 'checked'
|
||||
| 'unchecked'
|
||||
| 'busy'
|
||||
| 'expanded'
|
||||
| 'collapsed'
|
||||
| 'hasPopup';
|
||||
@@ -137,32 +137,37 @@ const queryByA11yHint: ReactTestInstance = tree.queryByA11yHint('label');
|
||||
const queryAllByA11yHint: Array<ReactTestInstance> = tree.queryAllByA11yHint(
|
||||
'label'
|
||||
);
|
||||
const getByA11yRole: ReactTestInstance = tree.getByA11yRole('label');
|
||||
const getByA11yRole: ReactTestInstance = tree.getByA11yRole('button');
|
||||
const getAllByA11yRole: Array<ReactTestInstance> = tree.getAllByA11yRole(
|
||||
'label'
|
||||
'button'
|
||||
);
|
||||
const queryByA11yRole: ReactTestInstance = tree.queryByA11yRole('label');
|
||||
const queryByA11yRole: ReactTestInstance = tree.queryByA11yRole('button');
|
||||
const queryAllByA11yRole: Array<ReactTestInstance> = tree.queryAllByA11yRole(
|
||||
'label'
|
||||
'button'
|
||||
);
|
||||
const getByA11yStates: ReactTestInstance = tree.getByA11yStates('label');
|
||||
const getByA11yStatesArray: ReactTestInstance = tree.getByA11yStates(['label']);
|
||||
const getByA11yStates: ReactTestInstance = tree.getByA11yStates('selected');
|
||||
const getByA11yStatesArray: ReactTestInstance = tree.getByA11yStates(['selected']);
|
||||
const getAllByA11yStates: Array<ReactTestInstance> = tree.getAllByA11yStates(
|
||||
'label'
|
||||
'selected'
|
||||
);
|
||||
const getAllByA11yStatesArray: Array<
|
||||
ReactTestInstance
|
||||
> = tree.getAllByA11yStates(['label']);
|
||||
const queryByA11yStates: ReactTestInstance = tree.queryByA11yStates('label');
|
||||
> = tree.getAllByA11yStates(['selected']);
|
||||
const queryByA11yStates: ReactTestInstance = tree.queryByA11yStates('selected');
|
||||
const queryByA11yStatesArray: ReactTestInstance = tree.queryByA11yStates([
|
||||
'label',
|
||||
'selected',
|
||||
]);
|
||||
const queryAllByA11yStates: Array<
|
||||
ReactTestInstance
|
||||
> = tree.queryAllByA11yStates('label');
|
||||
> = tree.queryAllByA11yStates('selected');
|
||||
const queryAllByA11yStatesArray: Array<
|
||||
ReactTestInstance
|
||||
> = tree.queryAllByA11yStates(['label']);
|
||||
> = tree.queryAllByA11yStates(['selected']);
|
||||
|
||||
const getByA11yState: ReactTestInstance = tree.getByA11yState({ busy: true });
|
||||
const getAllByA11yState: Array<ReactTestInstance> = tree.getAllByA11yState({ busy: true });
|
||||
const queryByA11yState: ReactTestInstance = tree.queryByA11yState({ busy: true });
|
||||
const queryAllByA11yState: Array<ReactTestInstance> = tree.queryAllByA11yState({ busy: true });
|
||||
|
||||
const debugFn = tree.debug();
|
||||
const debugFnWithMessage = tree.debug('my message');
|
||||
|
||||
Vendored
+36
-28
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { AccessibilityState, AccessibilityStates, AccessibilityRole } from 'react-native';
|
||||
import { ReactTestInstance, ReactTestRendererJSON } from 'react-test-renderer';
|
||||
|
||||
export interface GetByAPI {
|
||||
@@ -49,35 +50,42 @@ export interface QueryByAPI {
|
||||
) => Array<ReactTestInstance> | [];
|
||||
}
|
||||
|
||||
type QueryFn = (text: string | RegExp) => ReactTestInstance | null;
|
||||
type QueryAllFn = (text: string | RegExp) => Array<ReactTestInstance> | [];
|
||||
type GetFn = (text: string | RegExp) => ReactTestInstance;
|
||||
type GetAllFn = (text: string | RegExp) => Array<ReactTestInstance>;
|
||||
type ArrayQueryFn = (text: string | Array<string>) => ReactTestInstance | null;
|
||||
type ArrayQueryAllFn = (
|
||||
text: string | Array<string>
|
||||
) => Array<ReactTestInstance> | [];
|
||||
type ArrayGetFn = (text: string | Array<string>) => ReactTestInstance;
|
||||
type ArrayGetAllFn = (text: string | Array<string>) => Array<ReactTestInstance>;
|
||||
type GetReturn = ReactTestInstance;
|
||||
type GetAllReturn = Array<ReactTestInstance>;
|
||||
type QueryReturn = ReactTestInstance | null;
|
||||
type QueryAllReturn = Array<ReactTestInstance> | [];
|
||||
|
||||
export interface A11yAPI {
|
||||
getByA11yLabel: GetFn;
|
||||
getAllByA11yLabel: GetAllFn;
|
||||
queryByA11yLabel: QueryFn;
|
||||
queryAllByA11yLabel: QueryAllFn;
|
||||
getByA11yHint: GetFn;
|
||||
getAllByA11yHint: GetAllFn;
|
||||
queryByA11yHint: QueryFn;
|
||||
queryAllByA11yHint: QueryAllFn;
|
||||
getByA11yRole: GetFn;
|
||||
getAllByA11yRole: GetAllFn;
|
||||
queryByA11yRole: QueryFn;
|
||||
queryAllByA11yRole: QueryAllFn;
|
||||
getByA11yStates: ArrayGetFn;
|
||||
getAllByA11yStates: ArrayGetAllFn;
|
||||
queryByA11yStates: ArrayQueryFn;
|
||||
queryAllByA11yStates: ArrayQueryAllFn;
|
||||
}
|
||||
type A11yAPI = {
|
||||
// Label
|
||||
getByA11yLabel: (matcher: string | RegExp) => GetReturn,
|
||||
getAllByA11yLabel: (matcher: string | RegExp) => GetAllReturn,
|
||||
queryByA11yLabel: (matcher: string | RegExp) => QueryReturn,
|
||||
queryAllByA11yLabel: (matcher: string | RegExp) => QueryAllReturn,
|
||||
|
||||
// Hint
|
||||
getByA11yHint: (matcher: string | RegExp) => GetReturn,
|
||||
getAllByA11yHint: (matcher: string | RegExp) => GetAllReturn,
|
||||
queryByA11yHint: (matcher: string | RegExp) => QueryReturn,
|
||||
queryAllByA11yHint: (matcher: string | RegExp) => QueryAllReturn,
|
||||
|
||||
// Role
|
||||
getByA11yRole: (matcher: AccessibilityRole | RegExp) => GetReturn,
|
||||
getAllByA11yRole: (matcher: AccessibilityRole | RegExp) => GetAllReturn,
|
||||
queryByA11yRole: (matcher: AccessibilityRole | RegExp) => QueryReturn,
|
||||
queryAllByA11yRole: (matcher: AccessibilityRole | RegExp) => QueryAllReturn,
|
||||
|
||||
// States
|
||||
getByA11yStates: (matcher: AccessibilityStates | Array<AccessibilityStates>) => GetReturn,
|
||||
getAllByA11yStates: (matcher: AccessibilityStates | Array<AccessibilityStates>) => GetAllReturn,
|
||||
queryByA11yStates: (matcher: AccessibilityStates | Array<AccessibilityStates>) => QueryReturn,
|
||||
queryAllByA11yStates: (matcher: AccessibilityStates | Array<AccessibilityStates>) => QueryAllReturn,
|
||||
|
||||
// State
|
||||
getByA11yState: (matcher: AccessibilityState) => GetReturn,
|
||||
getAllByA11yState: (matcher: AccessibilityState) => GetAllReturn,
|
||||
queryByA11yState: (matcher: AccessibilityState) => QueryReturn,
|
||||
queryAllByA11yState: (matcher: AccessibilityState) => QueryAllReturn,
|
||||
};
|
||||
|
||||
export interface Thenable {
|
||||
then: (resolve: () => any, reject?: () => any) => any;
|
||||
|
||||
Reference in New Issue
Block a user