diff --git a/docs/Queries.md b/docs/Queries.md index 39861aa23..9753dcc83 100644 --- a/docs/Queries.md +++ b/docs/Queries.md @@ -83,6 +83,63 @@ const { getByTestId } = render(); const element = getByTestId('unique-id'); ``` +### `ByA11yLabel`, `ByAccessibilityLabel` + +> getByA11yLabel, getAllByA11yLabel, queryByA11yLabel, queryAllByA11yLabel +> getByAccessibilityLabel, getAllByAccessibilityLabel, queryByAccessibilityLabel, queryAllByAccessibilityLabel + +Returns a `ReactTestInstance` with matching `accessibilityLabel` prop. + +```jsx +import { render } from 'react-native-testing-library'; + +const { getByA11yLabel } = render(); +const element = getByA11yLabel('my-label'); +``` + +### `ByA11yHint`, `ByAccessibilityHint` + +> getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint +> getByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint + +Returns a `ReactTestInstance` with matching `accessibilityHint` prop. + +```jsx +import { render } from 'react-native-testing-library'; + +const { getByA11yHint } = render(); +const element = getByA11yHint('my-hint'); +``` + +### `ByA11yStates`, `ByAccessibilityStates` + +> getByA11yStates, getAllByA11yStates, queryByA11yStates, queryAllByA11yStates +> getByAccessibilityStates, getAllByAccessibilityStates, queryByAccessibilityStates, queryAllByAccessibilityStates + +Returns a `ReactTestInstance` with matching `accessibilityStates` prop. + +```jsx +import { render } from 'react-native-testing-library'; + +const { getByA11yStates } = render(); +const element = getByA11yStates(['checked']); +const element2 = getByA11yStates('checked'); +``` + +### `ByA11yRole`, `ByAccessibilityRole` + +> getByA11yRole, getAllByA11yRole, queryByA11yRole, queryAllByA11yRole +> getByAccessibilityRole, getAllByAccessibilityRole, queryByAccessibilityRole, queryAllByAccessibilityRole + +Returns a `ReactTestInstance` with matching `accessibilityRole` prop. + +```jsx +import { render } from 'react-native-testing-library'; + +const { getByA11yRole } = render(); +const element = getByA11yRole('button'); +``` + ## Unit testing helpers > Use sparingly and responsibly, escape hatches here diff --git a/package.json b/package.json index 72e9ccd98..67fc3e669 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@callstack/eslint-config": "^6.0.0", "@types/react": "^16.7.11", "@types/react-test-renderer": "^16.0.3", + "@typescript-eslint/eslint-plugin": "^1.9.0", "babel-jest": "^24.7.1", "chalk": "^2.4.1", "conventional-changelog-cli": "^2.0.11", diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js new file mode 100644 index 000000000..0abde5913 --- /dev/null +++ b/src/__tests__/a11yAPI.test.js @@ -0,0 +1,162 @@ +// @flow +import React from 'react'; +import { TouchableOpacity, Text } from 'react-native'; +import { render } from '..'; + +const BUTTON_LABEL = 'cool button'; +const BUTTON_HINT = 'click this button'; +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'; + +const NO_INSTANCES_FOUND = 'No instances found'; +const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances'; + +const Typography = ({ children, ...rest }) => { + return {children}; +}; + +class Button extends React.Component<*> { + render() { + return ( + + + {this.props.children} + + + ); + } +} + +function Section() { + return ( + <> + + Title + + + + ); +} + +test('getByA11yLabel, queryByA11yLabel', () => { + const { getByA11yLabel, queryByA11yLabel } = render(
); + + expect(getByA11yLabel(BUTTON_LABEL).props.accessibilityLabel).toEqual( + BUTTON_LABEL + ); + const button = queryByA11yLabel(/button/g); + expect(button && button.props.accessibilityLabel).toEqual(BUTTON_LABEL); + expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryByA11yLabel(NO_MATCHES_TEXT)).toBeNull(); + + expect(() => getByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); +}); + +test('getAllByA11yLabel, queryAllByA11yLabel', () => { + const { getAllByA11yLabel, queryAllByA11yLabel } = render(
); + + expect(getAllByA11yLabel(TEXT_LABEL)).toHaveLength(2); + expect(queryAllByA11yLabel(/cool/g)).toHaveLength(3); + expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryAllByA11yLabel(NO_MATCHES_TEXT)).toEqual([]); +}); + +test('getByA11yHint, queryByA11yHint', () => { + const { getByA11yHint, queryByA11yHint } = render(
); + + expect(getByA11yHint(BUTTON_HINT).props.accessibilityHint).toEqual( + BUTTON_HINT + ); + const button = queryByA11yHint(/button/g); + expect(button && button.props.accessibilityHint).toEqual(BUTTON_HINT); + expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryByA11yHint(NO_MATCHES_TEXT)).toBeNull(); + + expect(() => getByA11yHint(TEXT_HINT)).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByA11yHint(TEXT_HINT)).toThrow(FOUND_TWO_INSTANCES); +}); + +test('getAllByA11yHint, queryAllByA11yHint', () => { + const { getAllByA11yHint, queryAllByA11yHint } = render(
); + + expect(getAllByA11yHint(TEXT_HINT)).toHaveLength(2); + expect(queryAllByA11yHint(/static/g)).toHaveLength(2); + expect(() => getAllByA11yHint(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryAllByA11yHint(NO_MATCHES_TEXT)).toEqual([]); +}); + +test('getByA11yRole, queryByA11yRole', () => { + const { getByA11yRole, queryByA11yRole } = render(
); + + expect(getByA11yRole('button').props.accessibilityRole).toEqual('button'); + const button = queryByA11yRole(/button/g); + expect(button && button.props.accessibilityRole).toEqual('button'); + expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryByA11yRole(NO_MATCHES_TEXT)).toBeNull(); + + expect(() => getByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES); +}); + +test('getAllByA11yRole, queryAllByA11yRole', () => { + const { getAllByA11yRole, queryAllByA11yRole } = render(
); + + expect(getAllByA11yRole('link')).toHaveLength(2); + expect(queryAllByA11yRole(/ink/g)).toHaveLength(2); + expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryAllByA11yRole(NO_MATCHES_TEXT)).toEqual([]); +}); + +test('getByA11yStates, queryByA11yStates', () => { + const { getByA11yStates, queryByA11yStates } = render(
); + + expect(getByA11yStates('disabled').props.accessibilityStates).toEqual([ + 'selected', + 'disabled', + ]); + const disabled = queryByA11yStates(['disabled']); + expect(disabled && disabled.props.accessibilityStates).toMatchObject([ + 'selected', + 'disabled', + ]); + const disabledSelected = queryByA11yStates(['selected', 'disabled']); + expect( + disabledSelected && disabledSelected.props.accessibilityStates + ).toEqual(['selected', 'disabled']); + + expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow(NO_INSTANCES_FOUND); + expect(queryByA11yStates(NO_MATCHES_TEXT)).toBeNull(); + expect(queryByA11yStates([])).toBeNull(); + + expect(() => getByA11yStates('selected')).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByA11yStates('selected')).toThrow(FOUND_TWO_INSTANCES); +}); + +test('getAllByA11yStates, queryAllByA11yStates', () => { + const { getAllByA11yStates, queryAllByA11yStates } = render(
); + + expect(getAllByA11yStates('selected')).toHaveLength(3); + expect(queryAllByA11yStates(['selected'])).toHaveLength(3); + + expect(() => getAllByA11yStates([])).toThrow(NO_INSTANCES_FOUND); + expect(queryAllByA11yStates(NO_MATCHES_TEXT)).toEqual([]); +}); diff --git a/src/helpers/a11yAPI.js b/src/helpers/a11yAPI.js new file mode 100644 index 000000000..e5e239b68 --- /dev/null +++ b/src/helpers/a11yAPI.js @@ -0,0 +1,102 @@ +// @flow +import makeQuery from './makeQuery'; + +type QueryFn = (string | RegExp) => ReactTestInstance | null; +type GetFn = (string | RegExp) => ReactTestInstance; +type GetAllFn = (string | RegExp) => Array | []; +type ArrayQueryFn = (string | Array) => ReactTestInstance | null; +type ArrayGetFn = (string | Array) => ReactTestInstance; +type ArrayGetAllFn = (string | Array) => Array | []; + +type A11yAPI = { + getByA11yLabel: GetFn, + getAllByA11yLabel: GetAllFn, + queryByA11yLabel: QueryFn, + queryAllByA11yLabel: GetAllFn, + getByA11yHint: GetFn, + getAllByA11yHint: GetAllFn, + queryByA11yHint: QueryFn, + queryAllByA11yHint: GetAllFn, + getByA11yRole: GetFn, + getAllByA11yRole: GetAllFn, + queryByA11yRole: QueryFn, + queryAllByA11yRole: GetAllFn, + getByA11yStates: ArrayGetFn, + getAllByA11yStates: ArrayGetAllFn, + queryByA11yStates: ArrayQueryFn, + queryAllByA11yStates: ArrayGetAllFn, +}; + +export function matchStringValue(prop?: string, matcher: string | RegExp) { + if (!prop) { + return false; + } + + if (typeof matcher === 'string') { + return prop === matcher; + } + + return Boolean(prop.match(matcher)); +} + +export function matchArrayValue( + prop?: Array, + matcher: string | Array +) { + if (!prop || matcher.length === 0) { + return false; + } + + if (typeof matcher === 'string') { + return prop.includes(matcher); + } + + // $FlowFixMe - callback is sync hence prop exists + return !matcher.some(e => !prop.includes(e)); +} + +const a11yAPI = (instance: ReactTestInstance): A11yAPI => + ({ + ...makeQuery( + 'accessibilityLabel', + { + getBy: ['getByA11yLabel', 'getByAccessibilityLabel'], + getAllBy: ['getAllByA11yLabel', 'getAllByAccessibilityLabel'], + queryBy: ['queryByA11yLabel', 'queryByAccessibilityLabel'], + queryAllBy: ['queryAllByA11yLabel', 'queryAllByAccessibilityLabel'], + }, + matchStringValue + )(instance), + ...makeQuery( + 'accessibilityHint', + { + getBy: ['getByA11yHint', 'getByAccessibilityHint'], + getAllBy: ['getAllByA11yHint', 'getAllByAccessibilityHint'], + queryBy: ['queryByA11yHint', 'queryByAccessibilityHint'], + queryAllBy: ['queryAllByA11yHint', 'queryAllByAccessibilityHint'], + }, + matchStringValue + )(instance), + ...makeQuery( + 'accessibilityRole', + { + getBy: ['getByA11yRole', 'getByAccessibilityRole'], + getAllBy: ['getAllByA11yRole', 'getAllByAccessibilityRole'], + queryBy: ['queryByA11yRole', 'queryByAccessibilityRole'], + queryAllBy: ['queryAllByA11yRole', 'queryAllByAccessibilityRole'], + }, + matchStringValue + )(instance), + ...makeQuery( + 'accessibilityStates', + { + getBy: ['getByA11yStates', 'getByAccessibilityStates'], + getAllBy: ['getAllByA11yStates', 'getAllByAccessibilityStates'], + queryBy: ['queryByA11yStates', 'queryByAccessibilityStates'], + queryAllBy: ['queryAllByA11yStates', 'queryAllByAccessibilityStates'], + }, + matchArrayValue + )(instance), + }: any); + +export default a11yAPI; diff --git a/src/helpers/errors.js b/src/helpers/errors.js index c0369cbc2..4ae33d220 100644 --- a/src/helpers/errors.js +++ b/src/helpers/errors.js @@ -38,3 +38,14 @@ export const logDeprecationWarning = ( warned[deprecatedFnName] = true; }; + +export const prepareErrorMessage = (error: Error) => + // Strip info about custom predicate + error.message.replace(/ matching custom predicate[^]*/gm, ''); + +export const createQueryByError = (error: Error, callsite: Function) => { + if (error.message.includes('No instances found')) { + return null; + } + throw new ErrorWithStack(error.message, callsite); +}; diff --git a/src/helpers/getByAPI.js b/src/helpers/getByAPI.js index 28685ff29..c8fe5c429 100644 --- a/src/helpers/getByAPI.js +++ b/src/helpers/getByAPI.js @@ -5,6 +5,7 @@ import { ErrorWithStack, createLibraryNotSupportedError, logDeprecationWarning, + prepareErrorMessage, } from './errors'; const filterNodeByType = (node, type) => node.type === type; @@ -53,10 +54,6 @@ const getTextInputNodeByPlaceholder = (node, placeholder) => { } }; -const prepareErrorMessage = error => - // Strip info about custom predicate - error.message.replace(/ matching custom predicate[^]*/gm, ''); - export const getByName = (instance: ReactTestInstance) => function getByNameFn(name: string | React.ComponentType<*>) { logDeprecationWarning('getByName', 'getByType'); diff --git a/src/helpers/makeQuery.js b/src/helpers/makeQuery.js new file mode 100644 index 000000000..059a853b2 --- /dev/null +++ b/src/helpers/makeQuery.js @@ -0,0 +1,76 @@ +// @flow +import { + ErrorWithStack, + prepareErrorMessage, + createQueryByError, +} from './errors'; + +function isNodeValid(node: ReactTestInstance) { + return typeof node.type === 'string'; +} + +function makeAliases(aliases: Array, query: Function) { + return aliases + .map(alias => ({ [alias]: query })) + .reduce((acc, query) => ({ ...acc, ...query }), {}); +} + +type QueryNames = { + getBy: Array, + getAllBy: Array, + queryBy: Array, + queryAllBy: Array, +}; + +const makeQuery = ( + name: string, + queryNames: QueryNames, + matcherFn: (prop: P, value: M) => boolean +) => (instance: ReactTestInstance) => { + const getBy = (matcher: M) => { + try { + return instance.find( + node => isNodeValid(node) && matcherFn(node.props[name], matcher) + ); + } catch (error) { + throw new ErrorWithStack(prepareErrorMessage(error), getBy); + } + }; + + const getAllBy = (matcher: M) => { + const results = instance.findAll( + node => isNodeValid(node) && matcherFn(node.props[name], matcher) + ); + + if (results.length === 0) { + throw new ErrorWithStack('No instances found', getAllBy); + } + + return results; + }; + + const queryBy = (matcher: M) => { + try { + return getBy(matcher); + } catch (error) { + return createQueryByError(error, queryBy); + } + }; + + const queryAllBy = (matcher: M) => { + try { + return getAllBy(matcher); + } catch (error) { + return []; + } + }; + + return { + ...makeAliases(queryNames.getBy, getBy), + ...makeAliases(queryNames.getAllBy, getAllBy), + ...makeAliases(queryNames.queryBy, queryBy), + ...makeAliases(queryNames.queryAllBy, queryAllBy), + }; +}; + +export default makeQuery; diff --git a/src/helpers/queryByAPI.js b/src/helpers/queryByAPI.js index a5ef80622..8ca7dbff5 100644 --- a/src/helpers/queryByAPI.js +++ b/src/helpers/queryByAPI.js @@ -13,14 +13,7 @@ import { getAllByPlaceholder, getAllByProps, } from './getByAPI'; -import { ErrorWithStack, logDeprecationWarning } from './errors'; - -const createQueryByError = (error: Error, callsite: Function) => { - if (error.message.includes('No instances found')) { - return null; - } - throw new ErrorWithStack(error.message, callsite); -}; +import { logDeprecationWarning, createQueryByError } from './errors'; export const queryByName = (instance: ReactTestInstance) => function queryByNameFn(name: string | React.ComponentType<*>) { diff --git a/src/render.js b/src/render.js index 8b1c0445d..91a62fac8 100644 --- a/src/render.js +++ b/src/render.js @@ -4,6 +4,7 @@ import TestRenderer, { type ReactTestRenderer } from 'react-test-renderer'; // e import act from './act'; import { getByAPI } from './helpers/getByAPI'; import { queryByAPI } from './helpers/queryByAPI'; +import a11yAPI from './helpers/a11yAPI'; import debugShallow from './helpers/debugShallow'; import debugDeep from './helpers/debugDeep'; @@ -26,6 +27,7 @@ export default function render( return { ...getByAPI(instance), ...queryByAPI(instance), + ...a11yAPI(instance), update: updateWithAct(renderer), rerender: updateWithAct(renderer), // alias for `update` unmount: renderer.unmount, diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx index 00da9207b..cd14058c1 100644 --- a/typings/__tests__/index.test.tsx +++ b/typings/__tests__/index.test.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import * as React from 'react'; import { ReactTestInstance } from 'react-test-renderer'; import { @@ -39,8 +40,12 @@ const getByTypeWithRequiredProps: ReactTestInstance = tree.getByType( ); const getByTextString: ReactTestInstance = tree.getByText(''); const getByTextRegExp: ReactTestInstance = tree.getByText(/View/g); -const getByPlaceholderString: ReactTestInstance = tree.getByPlaceholder('my placeholder'); -const getByPlaceholderRegExp: ReactTestInstance = tree.getByPlaceholder(/placeholder/g); +const getByPlaceholderString: ReactTestInstance = tree.getByPlaceholder( + 'my placeholder' +); +const getByPlaceholderRegExp: ReactTestInstance = tree.getByPlaceholder( + /placeholder/g +); const getByProps: ReactTestInstance = tree.getByProps({ value: 2 }); const getByTestId: ReactTestInstance = tree.getByTestId('test-id'); const getAllByNameString: Array = tree.getAllByName('View'); @@ -73,28 +78,72 @@ const queryByTextRegExp: ReactTestInstance | null = tree.queryByText(/View/g); const queryByPlaceholderString: ReactTestInstance | null = tree.queryByText( 'my placeholder' ); -const queryByPlaceholderRegExp: ReactTestInstance | null = tree.queryByText(/placeholder/g); +const queryByPlaceholderRegExp: ReactTestInstance | null = tree.queryByText( + /placeholder/g +); const queryByProps: ReactTestInstance | null = tree.queryByProps({ value: 2 }); const queryByTestId: ReactTestInstance | null = tree.queryByTestId('test-id'); -const queryAllByNameString: Array = tree.getAllByName( +const queryAllByNameString: Array = tree.queryAllByName( 'View' ); -const queryAllByNameConstructor: Array = tree.getAllByName( +const queryAllByNameConstructor: Array = tree.queryAllByName( View ); -const queryAllByType: Array = tree.getAllByType(View); +const queryAllByType: Array = tree.queryAllByType(View); const queryAllByTypeWithRequiredProps: Array< ReactTestInstance -> = tree.getAllByType(ElementWithRequiredProps); +> = tree.queryAllByType(ElementWithRequiredProps); const queryAllByTextString: Array = tree.queryAllByText( 'View' ); const queryAllByTextRegExp: Array = tree.queryAllByText( /View/g ); -const queryAllByProps: Array = tree.getAllByProps({ - value: 2, -}); + +// Accessibility queries +const getByA11yLabel: ReactTestInstance = tree.getByA11yLabel('label'); +const getAllByA11yLabel: Array = tree.getAllByA11yLabel( + 'label' +); +const queryByA11yLabel: ReactTestInstance = tree.queryByA11yLabel('label'); +const queryAllByA11yLabel: Array = tree.queryAllByA11yLabel( + 'label' +); +const getByA11yHint: ReactTestInstance = tree.getByA11yHint('label'); +const getAllByA11yHint: Array = tree.getAllByA11yHint( + 'label' +); +const queryByA11yHint: ReactTestInstance = tree.queryByA11yHint('label'); +const queryAllByA11yHint: Array = tree.queryAllByA11yHint( + 'label' +); +const getByA11yRole: ReactTestInstance = tree.getByA11yRole('label'); +const getAllByA11yRole: Array = tree.getAllByA11yRole( + 'label' +); +const queryByA11yRole: ReactTestInstance = tree.queryByA11yRole('label'); +const queryAllByA11yRole: Array = tree.queryAllByA11yRole( + 'label' +); +const getByA11yStates: ReactTestInstance = tree.getByA11yStates('label'); +const getByA11yStatesArray: ReactTestInstance = tree.getByA11yStates(['label']); +const getAllByA11yStates: Array = tree.getAllByA11yStates( + 'label' +); +const getAllByA11yStatesArray: Array< + ReactTestInstance +> = tree.getAllByA11yStates(['label']); +const queryByA11yStates: ReactTestInstance = tree.queryByA11yStates('label'); +const queryByA11yStatesArray: ReactTestInstance = tree.queryByA11yStates([ + 'label', +]); +const queryAllByA11yStates: Array< + ReactTestInstance +> = tree.queryAllByA11yStates('label'); +const queryAllByA11yStatesArray: Array< + ReactTestInstance +> = tree.queryAllByA11yStates(['label']); + const debugFn = tree.debug(); const debugFnWithMessage = tree.debug('my message'); diff --git a/typings/index.d.ts b/typings/index.d.ts index 8838dd271..af96bf17c 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -11,7 +11,9 @@ export interface GetByAPI { getAllByName: (name: React.ReactType | string) => Array; getAllByType:

(type: React.ComponentType

) => Array; getAllByText: (text: string | RegExp) => Array; - getAllByPlaceholder: (placeholder: string | RegExp) => Array; + getAllByPlaceholder: ( + placeholder: string | RegExp + ) => Array; getAllByProps: (props: Record) => Array; } @@ -19,29 +21,63 @@ export interface QueryByAPI { queryByName: (name: React.ReactType | string) => ReactTestInstance | null; queryByType:

(type: React.ComponentType

) => ReactTestInstance | null; queryByText: (name: string | RegExp) => ReactTestInstance | null; - queryByPlaceholder: (placeholder: string | RegExp) => ReactTestInstance | null; + queryByPlaceholder: ( + placeholder: string | RegExp + ) => ReactTestInstance | null; queryByProps: (props: Record) => ReactTestInstance | null; queryByTestId: (testID: string) => ReactTestInstance | null; - queryAllByName: (name: React.ReactType | string) => Array | []; + queryAllByName: ( + name: React.ReactType | string + ) => Array | []; queryAllByType:

( type: React.ComponentType

) => Array | []; queryAllByText: (text: string | RegExp) => Array | []; - queryAllByPlaceholder: (placeholder: string | RegExp) => Array | []; + queryAllByPlaceholder: ( + placeholder: string | RegExp + ) => Array | []; queryAllByProps: ( props: Record ) => Array | []; } +type QueryFn = (text: string | RegExp) => ReactTestInstance | null; +type GetFn = (text: string | RegExp) => ReactTestInstance; +type GetAllFn = (text: string | RegExp) => Array | []; +type ArrayQueryFn = (text: string | Array) => ReactTestInstance | null; +type ArrayGetFn = (text: string | Array) => ReactTestInstance; +type ArrayGetAllFn = ( + text: string | Array +) => Array | []; + +export interface A11yAPI { + getByA11yLabel: GetFn; + getAllByA11yLabel: GetAllFn; + queryByA11yLabel: QueryFn; + queryAllByA11yLabel: GetAllFn; + getByA11yHint: GetFn; + getAllByA11yHint: GetAllFn; + queryByA11yHint: QueryFn; + queryAllByA11yHint: GetAllFn; + getByA11yRole: GetFn; + getAllByA11yRole: GetAllFn; + queryByA11yRole: QueryFn; + queryAllByA11yRole: GetAllFn; + getByA11yStates: ArrayGetFn; + getAllByA11yStates: ArrayGetAllFn; + queryByA11yStates: ArrayQueryFn; + queryAllByA11yStates: ArrayGetAllFn; +} + export interface Thenable { - then: (resolve: () => any, reject?: () => any) => any, + then: (resolve: () => any, reject?: () => any) => any; } export interface RenderOptions { createNodeMock: (element: React.ReactElement) => any; } -export interface RenderAPI extends GetByAPI, QueryByAPI { +export interface RenderAPI extends GetByAPI, QueryByAPI, A11yAPI { update(nextElement: React.ReactElement): void; rerender(nextElement: React.ReactElement): void; unmount(nextElement?: React.ReactElement): void; diff --git a/yarn.lock b/yarn.lock index 5b18d772b..b7bb95fce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1080,6 +1080,44 @@ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916" integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw== +"@typescript-eslint/eslint-plugin@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.9.0.tgz#29d73006811bf2563b88891ceeff1c5ea9c8d9c6" + integrity sha512-FOgfBorxjlBGpDIw+0LaZIXRX6GEEUfzj8LXwaQIUCp+gDOvkI+1WgugJ7SmWiISqK9Vj5r8S7NDKO/LB+6X9A== + dependencies: + "@typescript-eslint/experimental-utils" "1.9.0" + "@typescript-eslint/parser" "1.9.0" + eslint-utils "^1.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^2.0.1" + requireindex "^1.2.0" + tsutils "^3.7.0" + +"@typescript-eslint/experimental-utils@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.9.0.tgz#a92777d0c92d7bc8627abd7cdb06cdbcaf2b39e8" + integrity sha512-1s2dY9XxBwtS9IlSnRIlzqILPyeMly5tz1bfAmQ84Ul687xBBve5YsH5A5EKeIcGurYYqY2w6RkHETXIwnwV0A== + dependencies: + "@typescript-eslint/typescript-estree" "1.9.0" + +"@typescript-eslint/parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.9.0.tgz#5796cbfcb9a3a5757aeb671c1ac88d7a94a95962" + integrity sha512-CWgC1XrQ34H/+LwAU7vY5xteZDkNqeAkeidEpJnJgkKu0yqQ3ZhQ7S+dI6MX4vmmM1TKRbOrKuXc6W0fIHhdbA== + dependencies: + "@typescript-eslint/experimental-utils" "1.9.0" + "@typescript-eslint/typescript-estree" "1.9.0" + eslint-scope "^4.0.0" + eslint-visitor-keys "^1.0.0" + +"@typescript-eslint/typescript-estree@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.9.0.tgz#5d6d49be936e96fb0f859673480f89b070a5dd9b" + integrity sha512-7Eg0TEQpCkTsEwsl1lIzd6i7L3pJLQFWesV08dS87bNz0NeSjbL78gNAP1xCKaCejkds4PhpLnZkaAjx9SU8OA== + dependencies: + lodash.unescape "4.0.1" + semver "5.5.0" + JSONStream@^1.0.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -2705,7 +2743,7 @@ eslint-scope@3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^4.0.3: +eslint-scope@^4.0.0, eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== @@ -4890,6 +4928,11 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -6687,6 +6730,11 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +requireindex@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" + integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -6873,6 +6921,11 @@ semver-diff@^2.0.0: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" +semver@5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== + semver@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" @@ -7429,10 +7482,17 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" +tsutils@^3.7.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.10.0.tgz#6f1c95c94606e098592b0dff06590cf9659227d6" + integrity sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"