From ea68aa1eb2e55d41a48b4b1a96235da8ef7f464f Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Thu, 2 Dec 2021 20:29:52 +0530 Subject: [PATCH 01/14] fix: remove unwanted files --- src/__tests__/a11yAPI.test.js | 48 +++++++++++++++++++++++++++++ src/helpers/a11yAPI.js | 33 ++++++++++++-------- src/helpers/makeA11yQuery.js | 57 ++++++++++++++++++++++++++--------- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js index 7e348bdd0..929b6734e 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.js @@ -7,6 +7,8 @@ const BUTTON_LABEL = 'cool button'; const BUTTON_HINT = 'click this button'; const TEXT_LABEL = 'cool text'; const TEXT_HINT = 'static text'; +const SINGLE_OCCURANCE = 'more words'; +const TWO_OCCURANCE = 'cooler text'; // Little hack to make all the methods happy with type const NO_MATCHES_TEXT: any = 'not-existent-element'; const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances'; @@ -70,6 +72,22 @@ function Section() { ); } +function ButtonsWithText() { + return ( + <> + + {TWO_OCCURANCE} + + + {TWO_OCCURANCE} + + + {SINGLE_OCCURANCE} + + + ); +} + test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => { const { getByA11yLabel, queryByA11yLabel, findByA11yLabel } = render(
@@ -192,6 +210,34 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => { await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); }); +test('getByA11yRole, queryByA11yRole, findByA11yRole with name', async () => { + const { getByA11yRole, queryByA11yRole, findByA11yRole } = render( + + ); + + expect(() => getByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + FOUND_TWO_INSTANCES + ); + getByA11yRole(/button/g, { name: SINGLE_OCCURANCE }); + + expect(queryByA11yRole(/button/g, { name: NO_MATCHES_TEXT })).toBeNull(); + expect(() => queryByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + FOUND_TWO_INSTANCES + ); + + await findByA11yRole('button', { + name: SINGLE_OCCURANCE, + }); + await expect( + findByA11yRole('button', { ...waitForOptions, name: NO_MATCHES_TEXT }) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole', 'button')); + await expect( + findByA11yRole('button', { + name: TWO_OCCURANCE, + }) + ).rejects.toThrow(FOUND_TWO_INSTANCES); +}); + test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render(
@@ -211,6 +257,8 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); }); +test.todo('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name'); + // TODO: accessibilityStates was removed from RN 0.62 test.skip('getByA11yStates, queryByA11yStates', () => { const { getByA11yStates, queryByA11yStates } = render(
); diff --git a/src/helpers/a11yAPI.js b/src/helpers/a11yAPI.js index 1f9c84608..99a1d44f2 100644 --- a/src/helpers/a11yAPI.js +++ b/src/helpers/a11yAPI.js @@ -10,6 +10,15 @@ type QueryAllReturn = Array; type FindReturn = Promise; type FindAllReturn = Promise; +type QueryOptions = { + name: string | RegExp, +}; + +export type WaitForOptionsWithName = { + ...WaitForOptions, + ...$Exact, +}; + export type A11yAPI = {| // Label getByA11yLabel: (string | RegExp) => GetReturn, @@ -40,18 +49,18 @@ export type A11yAPI = {| findAllByHintText: (string | RegExp, ?WaitForOptions) => FindAllReturn, // Role - getByA11yRole: (A11yRole | RegExp) => GetReturn, - getByRole: (A11yRole | RegExp) => GetReturn, - getAllByA11yRole: (A11yRole | RegExp) => GetAllReturn, - getAllByRole: (A11yRole | RegExp) => GetAllReturn, - queryByA11yRole: (A11yRole | RegExp) => QueryReturn, - queryByRole: (A11yRole | RegExp) => QueryReturn, - queryAllByA11yRole: (A11yRole | RegExp) => QueryAllReturn, - queryAllByRole: (A11yRole | RegExp) => QueryAllReturn, - findByA11yRole: (A11yRole, ?WaitForOptions) => FindReturn, - findByRole: (A11yRole, ?WaitForOptions) => FindReturn, - findAllByA11yRole: (A11yRole, ?WaitForOptions) => FindAllReturn, - findAllByRole: (A11yRole, ?WaitForOptions) => FindAllReturn, + getByA11yRole: (A11yRole | RegExp, ?QueryOptions, ?QueryOptions) => GetReturn, + getByRole: (A11yRole | RegExp, ?QueryOptions) => GetReturn, + getAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => GetAllReturn, + getAllByRole: (A11yRole | RegExp, ?QueryOptions) => GetAllReturn, + queryByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, + queryByRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, + queryAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, + queryAllByRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, + findByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, + findByRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, + findAllByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, + findAllByRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, // States getByA11yStates: (A11yStates | Array) => GetReturn, diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index fff34e8f9..b1ccd1b17 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -1,6 +1,7 @@ // @flow import waitFor from '../waitFor'; -import type { WaitForOptions } from '../waitFor'; +import { getQueriesForElement } from '../within'; +import type { WaitForOptionsWithName } from './a11yAPI'; import { ErrorWithStack, prepareErrorMessage, @@ -26,6 +27,10 @@ type QueryNames = { findAllBy: Array, }; +type QueryOptions = { + name: string | RegExp, +}; + const makeA11yQuery = ( name: string, queryNames: QueryNames, @@ -33,8 +38,19 @@ const makeA11yQuery = ( ): ((instance: ReactTestInstance) => { ... }) => ( instance: ReactTestInstance ) => { - const getBy = (matcher: M) => { + const getBy = (matcher: M, options?: QueryOptions) => { try { + if (options?.name) { + return instance.find((node) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + if (!matchesRole) return false; + + return !!getQueriesForElement(node).queryByText(options.name); + }); + } + return instance.find( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) ); @@ -46,10 +62,23 @@ const makeA11yQuery = ( } }; - const getAllBy = (matcher: M) => { - const results = instance.findAll( - (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) - ); + const getAllBy = (matcher: M, options?: QueryOptions) => { + let results = []; + + if (options?.name) { + results = instance.find((node) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + if (!matchesRole) return false; + + return !!getQueriesForElement(node).queryByText(options.name); + }); + } else { + results = instance.findAll( + (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) + ); + } if (results.length === 0) { throw new ErrorWithStack( @@ -61,28 +90,28 @@ const makeA11yQuery = ( return results; }; - const queryBy = (matcher: M) => { + const queryBy = (matcher: M, options?: QueryOptions) => { try { - return getBy(matcher); + return getBy(matcher, options); } catch (error) { return createQueryByError(error, queryBy); } }; - const queryAllBy = (matcher: M) => { + const queryAllBy = (matcher: M, options?: QueryOptions) => { try { - return getAllBy(matcher); + return getAllBy(matcher, options); } catch (error) { return []; } }; - const findBy = (matcher: M, waitForOptions?: WaitForOptions) => { - return waitFor(() => getBy(matcher), waitForOptions); + const findBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { + return waitFor(() => getBy(matcher, waitForOptions)); }; - const findAllBy = (matcher: M, waitForOptions?: WaitForOptions) => { - return waitFor(() => getAllBy(matcher), waitForOptions); + const findAllBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { + return waitFor(() => getAllBy(matcher, waitForOptions)); }; return { From 28a342cc15511f2ec312c319f65815d7d5e489b1 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:14:02 +0530 Subject: [PATCH 02/14] deduplicate code for matching name --- src/helpers/makeA11yQuery.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index b1ccd1b17..ca797a13a 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -38,17 +38,23 @@ const makeA11yQuery = ( ): ((instance: ReactTestInstance) => { ... }) => ( instance: ReactTestInstance ) => { + const filterWithName = ( + node: ReactTestInstance, + options: QueryOptions, + matcher: M + ) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + return ( + matchesRole && !!getQueriesForElement(node).queryByText(options.name) + ); + }; + const getBy = (matcher: M, options?: QueryOptions) => { try { if (options?.name) { - return instance.find((node) => { - const matchesRole = - isNodeValid(node) && matcherFn(node.props[name], matcher); - - if (!matchesRole) return false; - - return !!getQueriesForElement(node).queryByText(options.name); - }); + return instance.find((node) => filterWithName(node, options, matcher)); } return instance.find( @@ -66,14 +72,7 @@ const makeA11yQuery = ( let results = []; if (options?.name) { - results = instance.find((node) => { - const matchesRole = - isNodeValid(node) && matcherFn(node.props[name], matcher); - - if (!matchesRole) return false; - - return !!getQueriesForElement(node).queryByText(options.name); - }); + results = instance.find((node) => filterWithName(node, options, matcher)); } else { results = instance.findAll( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) From 0713c9561313315110261c92a945fd4b704662fb Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:57:38 +0530 Subject: [PATCH 03/14] adds tests for ...AllbyRole second arg --- src/__tests__/a11yAPI.test.js | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js index 929b6734e..20e2c7405 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.js @@ -7,7 +7,7 @@ const BUTTON_LABEL = 'cool button'; const BUTTON_HINT = 'click this button'; const TEXT_LABEL = 'cool text'; const TEXT_HINT = 'static text'; -const SINGLE_OCCURANCE = 'more words'; +const ONE_OCCURANCE = 'more words'; const TWO_OCCURANCE = 'cooler text'; // Little hack to make all the methods happy with type const NO_MATCHES_TEXT: any = 'not-existent-element'; @@ -82,7 +82,7 @@ function ButtonsWithText() { {TWO_OCCURANCE} - {SINGLE_OCCURANCE} + {ONE_OCCURANCE} ); @@ -204,9 +204,9 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => { const asyncButton = await findByA11yRole('button'); expect(asyncButton.props.accessibilityRole).toEqual('button'); - await expect(findByA11yRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( - getNoInstancesFoundMessage('accessibilityRole') - ); + await expect( + findByA11yRole(NO_MATCHES_TEXT, {}, waitForOptions) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); }); @@ -215,18 +215,18 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole with name', async () => { ); - expect(() => getByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + expect(() => getByA11yRole('button', { name: TWO_OCCURANCE })).toThrow( FOUND_TWO_INSTANCES ); - getByA11yRole(/button/g, { name: SINGLE_OCCURANCE }); + getByA11yRole('button', { name: ONE_OCCURANCE }); - expect(queryByA11yRole(/button/g, { name: NO_MATCHES_TEXT })).toBeNull(); - expect(() => queryByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + expect(queryByA11yRole('button', { name: NO_MATCHES_TEXT })).toBeNull(); + expect(() => queryByA11yRole('button', { name: TWO_OCCURANCE })).toThrow( FOUND_TWO_INSTANCES ); await findByA11yRole('button', { - name: SINGLE_OCCURANCE, + name: ONE_OCCURANCE, }); await expect( findByA11yRole('button', { ...waitForOptions, name: NO_MATCHES_TEXT }) @@ -253,11 +253,31 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { await expect(findAllByA11yRole('link')).resolves.toHaveLength(2); await expect( - findAllByA11yRole(NO_MATCHES_TEXT, waitForOptions) + findAllByA11yRole(NO_MATCHES_TEXT, {}, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); }); -test.todo('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name'); +test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name', async () => { + const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render( + + ); + + expect(getAllByA11yRole('button', { name: TWO_OCCURANCE })).toHaveLength(2); + expect(getAllByA11yRole('button', { name: ONE_OCCURANCE })).toHaveLength(1); + expect(queryAllByA11yRole('button', { name: TWO_OCCURANCE })).toHaveLength(2); + + expect(() => getAllByA11yRole('button', { name: NO_MATCHES_TEXT })).toThrow( + getNoInstancesFoundMessage('accessibilityRole', 'button') + ); + expect(queryAllByA11yRole('button', { name: NO_MATCHES_TEXT })).toEqual([]); + + await expect( + findAllByA11yRole('button', { name: TWO_OCCURANCE }) + ).resolves.toHaveLength(2); + await expect( + findAllByA11yRole('button', { name: NO_MATCHES_TEXT }) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole', 'button')); +}); // TODO: accessibilityStates was removed from RN 0.62 test.skip('getByA11yStates, queryByA11yStates', () => { From 1360487de587ec116508b9025b4643a261b3301f Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:59:00 +0530 Subject: [PATCH 04/14] update param to accept arity of 3 with waitFor as last arg --- src/helpers/a11yAPI.js | 22 ++++++++++------------ src/helpers/makeA11yQuery.js | 35 ++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/helpers/a11yAPI.js b/src/helpers/a11yAPI.js index 99a1d44f2..63d17c007 100644 --- a/src/helpers/a11yAPI.js +++ b/src/helpers/a11yAPI.js @@ -10,15 +10,9 @@ type QueryAllReturn = Array; type FindReturn = Promise; type FindAllReturn = Promise; -type QueryOptions = { - name: string | RegExp, +export type QueryOptions = { + name?: string | RegExp, }; - -export type WaitForOptionsWithName = { - ...WaitForOptions, - ...$Exact, -}; - export type A11yAPI = {| // Label getByA11yLabel: (string | RegExp) => GetReturn, @@ -57,10 +51,14 @@ export type A11yAPI = {| queryByRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, queryAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, queryAllByRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, - findByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, - findByRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, - findAllByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, - findAllByRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, + findByA11yRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindReturn, + findByRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindReturn, + findAllByA11yRole: ( + A11yRole, + ?QueryOptions, + ?WaitForOptions + ) => FindAllReturn, + findAllByRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindAllReturn, // States getByA11yStates: (A11yStates | Array) => GetReturn, diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index ca797a13a..8041dc89f 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -1,7 +1,8 @@ // @flow import waitFor from '../waitFor'; import { getQueriesForElement } from '../within'; -import type { WaitForOptionsWithName } from './a11yAPI'; +import type { WaitForOptions } from '../waitFor'; +import type { QueryOptions } from './a11yAPI'; import { ErrorWithStack, prepareErrorMessage, @@ -27,10 +28,6 @@ type QueryNames = { findAllBy: Array, }; -type QueryOptions = { - name: string | RegExp, -}; - const makeA11yQuery = ( name: string, queryNames: QueryNames, @@ -51,10 +48,12 @@ const makeA11yQuery = ( ); }; - const getBy = (matcher: M, options?: QueryOptions) => { + const getBy = (matcher: M, queryOptions?: QueryOptions) => { try { - if (options?.name) { - return instance.find((node) => filterWithName(node, options, matcher)); + if (queryOptions?.name) { + return instance.find((node) => + filterWithName(node, queryOptions, matcher) + ); } return instance.find( @@ -72,7 +71,9 @@ const makeA11yQuery = ( let results = []; if (options?.name) { - results = instance.find((node) => filterWithName(node, options, matcher)); + results = instance.findAll((node) => + filterWithName(node, options, matcher) + ); } else { results = instance.findAll( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) @@ -105,12 +106,20 @@ const makeA11yQuery = ( } }; - const findBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { - return waitFor(() => getBy(matcher, waitForOptions)); + const findBy = ( + matcher: M, + queryOptions?: QueryOptions, + waitForOptions?: WaitForOptions + ) => { + return waitFor(() => getBy(matcher, queryOptions), waitForOptions); }; - const findAllBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { - return waitFor(() => getAllBy(matcher, waitForOptions)); + const findAllBy = ( + matcher: M, + queryOptions: QueryOptions, + waitForOptions?: WaitForOptions + ) => { + return waitFor(() => getAllBy(matcher, queryOptions), waitForOptions); }; return { From f1e2c6842fb24e2d214521ae734dca5189870c21 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Thu, 2 Dec 2021 20:29:52 +0530 Subject: [PATCH 05/14] fix: remove unwanted files --- src/__tests__/a11yAPI.test.js | 48 +++++++++++++++++++++++++++++ src/helpers/a11yAPI.js | 33 ++++++++++++-------- src/helpers/makeA11yQuery.js | 57 ++++++++++++++++++++++++++--------- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js index 7e348bdd0..929b6734e 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.js @@ -7,6 +7,8 @@ const BUTTON_LABEL = 'cool button'; const BUTTON_HINT = 'click this button'; const TEXT_LABEL = 'cool text'; const TEXT_HINT = 'static text'; +const SINGLE_OCCURANCE = 'more words'; +const TWO_OCCURANCE = 'cooler text'; // Little hack to make all the methods happy with type const NO_MATCHES_TEXT: any = 'not-existent-element'; const FOUND_TWO_INSTANCES = 'Expected 1 but found 2 instances'; @@ -70,6 +72,22 @@ function Section() { ); } +function ButtonsWithText() { + return ( + <> + + {TWO_OCCURANCE} + + + {TWO_OCCURANCE} + + + {SINGLE_OCCURANCE} + + + ); +} + test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => { const { getByA11yLabel, queryByA11yLabel, findByA11yLabel } = render(
@@ -192,6 +210,34 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => { await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); }); +test('getByA11yRole, queryByA11yRole, findByA11yRole with name', async () => { + const { getByA11yRole, queryByA11yRole, findByA11yRole } = render( + + ); + + expect(() => getByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + FOUND_TWO_INSTANCES + ); + getByA11yRole(/button/g, { name: SINGLE_OCCURANCE }); + + expect(queryByA11yRole(/button/g, { name: NO_MATCHES_TEXT })).toBeNull(); + expect(() => queryByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + FOUND_TWO_INSTANCES + ); + + await findByA11yRole('button', { + name: SINGLE_OCCURANCE, + }); + await expect( + findByA11yRole('button', { ...waitForOptions, name: NO_MATCHES_TEXT }) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole', 'button')); + await expect( + findByA11yRole('button', { + name: TWO_OCCURANCE, + }) + ).rejects.toThrow(FOUND_TWO_INSTANCES); +}); + test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render(
@@ -211,6 +257,8 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); }); +test.todo('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name'); + // TODO: accessibilityStates was removed from RN 0.62 test.skip('getByA11yStates, queryByA11yStates', () => { const { getByA11yStates, queryByA11yStates } = render(
); diff --git a/src/helpers/a11yAPI.js b/src/helpers/a11yAPI.js index 1f9c84608..99a1d44f2 100644 --- a/src/helpers/a11yAPI.js +++ b/src/helpers/a11yAPI.js @@ -10,6 +10,15 @@ type QueryAllReturn = Array; type FindReturn = Promise; type FindAllReturn = Promise; +type QueryOptions = { + name: string | RegExp, +}; + +export type WaitForOptionsWithName = { + ...WaitForOptions, + ...$Exact, +}; + export type A11yAPI = {| // Label getByA11yLabel: (string | RegExp) => GetReturn, @@ -40,18 +49,18 @@ export type A11yAPI = {| findAllByHintText: (string | RegExp, ?WaitForOptions) => FindAllReturn, // Role - getByA11yRole: (A11yRole | RegExp) => GetReturn, - getByRole: (A11yRole | RegExp) => GetReturn, - getAllByA11yRole: (A11yRole | RegExp) => GetAllReturn, - getAllByRole: (A11yRole | RegExp) => GetAllReturn, - queryByA11yRole: (A11yRole | RegExp) => QueryReturn, - queryByRole: (A11yRole | RegExp) => QueryReturn, - queryAllByA11yRole: (A11yRole | RegExp) => QueryAllReturn, - queryAllByRole: (A11yRole | RegExp) => QueryAllReturn, - findByA11yRole: (A11yRole, ?WaitForOptions) => FindReturn, - findByRole: (A11yRole, ?WaitForOptions) => FindReturn, - findAllByA11yRole: (A11yRole, ?WaitForOptions) => FindAllReturn, - findAllByRole: (A11yRole, ?WaitForOptions) => FindAllReturn, + getByA11yRole: (A11yRole | RegExp, ?QueryOptions, ?QueryOptions) => GetReturn, + getByRole: (A11yRole | RegExp, ?QueryOptions) => GetReturn, + getAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => GetAllReturn, + getAllByRole: (A11yRole | RegExp, ?QueryOptions) => GetAllReturn, + queryByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, + queryByRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, + queryAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, + queryAllByRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, + findByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, + findByRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, + findAllByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, + findAllByRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, // States getByA11yStates: (A11yStates | Array) => GetReturn, diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index fff34e8f9..b1ccd1b17 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -1,6 +1,7 @@ // @flow import waitFor from '../waitFor'; -import type { WaitForOptions } from '../waitFor'; +import { getQueriesForElement } from '../within'; +import type { WaitForOptionsWithName } from './a11yAPI'; import { ErrorWithStack, prepareErrorMessage, @@ -26,6 +27,10 @@ type QueryNames = { findAllBy: Array, }; +type QueryOptions = { + name: string | RegExp, +}; + const makeA11yQuery = ( name: string, queryNames: QueryNames, @@ -33,8 +38,19 @@ const makeA11yQuery = ( ): ((instance: ReactTestInstance) => { ... }) => ( instance: ReactTestInstance ) => { - const getBy = (matcher: M) => { + const getBy = (matcher: M, options?: QueryOptions) => { try { + if (options?.name) { + return instance.find((node) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + if (!matchesRole) return false; + + return !!getQueriesForElement(node).queryByText(options.name); + }); + } + return instance.find( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) ); @@ -46,10 +62,23 @@ const makeA11yQuery = ( } }; - const getAllBy = (matcher: M) => { - const results = instance.findAll( - (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) - ); + const getAllBy = (matcher: M, options?: QueryOptions) => { + let results = []; + + if (options?.name) { + results = instance.find((node) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + if (!matchesRole) return false; + + return !!getQueriesForElement(node).queryByText(options.name); + }); + } else { + results = instance.findAll( + (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) + ); + } if (results.length === 0) { throw new ErrorWithStack( @@ -61,28 +90,28 @@ const makeA11yQuery = ( return results; }; - const queryBy = (matcher: M) => { + const queryBy = (matcher: M, options?: QueryOptions) => { try { - return getBy(matcher); + return getBy(matcher, options); } catch (error) { return createQueryByError(error, queryBy); } }; - const queryAllBy = (matcher: M) => { + const queryAllBy = (matcher: M, options?: QueryOptions) => { try { - return getAllBy(matcher); + return getAllBy(matcher, options); } catch (error) { return []; } }; - const findBy = (matcher: M, waitForOptions?: WaitForOptions) => { - return waitFor(() => getBy(matcher), waitForOptions); + const findBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { + return waitFor(() => getBy(matcher, waitForOptions)); }; - const findAllBy = (matcher: M, waitForOptions?: WaitForOptions) => { - return waitFor(() => getAllBy(matcher), waitForOptions); + const findAllBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { + return waitFor(() => getAllBy(matcher, waitForOptions)); }; return { From 30644cbdb17a7e86b5d2b46a7099f0e233592894 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:14:02 +0530 Subject: [PATCH 06/14] deduplicate code for matching name --- src/helpers/makeA11yQuery.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index b1ccd1b17..ca797a13a 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -38,17 +38,23 @@ const makeA11yQuery = ( ): ((instance: ReactTestInstance) => { ... }) => ( instance: ReactTestInstance ) => { + const filterWithName = ( + node: ReactTestInstance, + options: QueryOptions, + matcher: M + ) => { + const matchesRole = + isNodeValid(node) && matcherFn(node.props[name], matcher); + + return ( + matchesRole && !!getQueriesForElement(node).queryByText(options.name) + ); + }; + const getBy = (matcher: M, options?: QueryOptions) => { try { if (options?.name) { - return instance.find((node) => { - const matchesRole = - isNodeValid(node) && matcherFn(node.props[name], matcher); - - if (!matchesRole) return false; - - return !!getQueriesForElement(node).queryByText(options.name); - }); + return instance.find((node) => filterWithName(node, options, matcher)); } return instance.find( @@ -66,14 +72,7 @@ const makeA11yQuery = ( let results = []; if (options?.name) { - results = instance.find((node) => { - const matchesRole = - isNodeValid(node) && matcherFn(node.props[name], matcher); - - if (!matchesRole) return false; - - return !!getQueriesForElement(node).queryByText(options.name); - }); + results = instance.find((node) => filterWithName(node, options, matcher)); } else { results = instance.findAll( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) From cf0726fd256fa731babc9e52dd953981d04aa8b3 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:57:38 +0530 Subject: [PATCH 07/14] adds tests for ...AllbyRole second arg --- src/__tests__/a11yAPI.test.js | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js index 929b6734e..20e2c7405 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.js @@ -7,7 +7,7 @@ const BUTTON_LABEL = 'cool button'; const BUTTON_HINT = 'click this button'; const TEXT_LABEL = 'cool text'; const TEXT_HINT = 'static text'; -const SINGLE_OCCURANCE = 'more words'; +const ONE_OCCURANCE = 'more words'; const TWO_OCCURANCE = 'cooler text'; // Little hack to make all the methods happy with type const NO_MATCHES_TEXT: any = 'not-existent-element'; @@ -82,7 +82,7 @@ function ButtonsWithText() { {TWO_OCCURANCE} - {SINGLE_OCCURANCE} + {ONE_OCCURANCE} ); @@ -204,9 +204,9 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => { const asyncButton = await findByA11yRole('button'); expect(asyncButton.props.accessibilityRole).toEqual('button'); - await expect(findByA11yRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( - getNoInstancesFoundMessage('accessibilityRole') - ); + await expect( + findByA11yRole(NO_MATCHES_TEXT, {}, waitForOptions) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); }); @@ -215,18 +215,18 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole with name', async () => { ); - expect(() => getByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + expect(() => getByA11yRole('button', { name: TWO_OCCURANCE })).toThrow( FOUND_TWO_INSTANCES ); - getByA11yRole(/button/g, { name: SINGLE_OCCURANCE }); + getByA11yRole('button', { name: ONE_OCCURANCE }); - expect(queryByA11yRole(/button/g, { name: NO_MATCHES_TEXT })).toBeNull(); - expect(() => queryByA11yRole(/button/g, { name: TWO_OCCURANCE })).toThrow( + expect(queryByA11yRole('button', { name: NO_MATCHES_TEXT })).toBeNull(); + expect(() => queryByA11yRole('button', { name: TWO_OCCURANCE })).toThrow( FOUND_TWO_INSTANCES ); await findByA11yRole('button', { - name: SINGLE_OCCURANCE, + name: ONE_OCCURANCE, }); await expect( findByA11yRole('button', { ...waitForOptions, name: NO_MATCHES_TEXT }) @@ -253,11 +253,31 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { await expect(findAllByA11yRole('link')).resolves.toHaveLength(2); await expect( - findAllByA11yRole(NO_MATCHES_TEXT, waitForOptions) + findAllByA11yRole(NO_MATCHES_TEXT, {}, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); }); -test.todo('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name'); +test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name', async () => { + const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render( + + ); + + expect(getAllByA11yRole('button', { name: TWO_OCCURANCE })).toHaveLength(2); + expect(getAllByA11yRole('button', { name: ONE_OCCURANCE })).toHaveLength(1); + expect(queryAllByA11yRole('button', { name: TWO_OCCURANCE })).toHaveLength(2); + + expect(() => getAllByA11yRole('button', { name: NO_MATCHES_TEXT })).toThrow( + getNoInstancesFoundMessage('accessibilityRole', 'button') + ); + expect(queryAllByA11yRole('button', { name: NO_MATCHES_TEXT })).toEqual([]); + + await expect( + findAllByA11yRole('button', { name: TWO_OCCURANCE }) + ).resolves.toHaveLength(2); + await expect( + findAllByA11yRole('button', { name: NO_MATCHES_TEXT }) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole', 'button')); +}); // TODO: accessibilityStates was removed from RN 0.62 test.skip('getByA11yStates, queryByA11yStates', () => { From 9c490c75757dcd4555b02049175b43e75be0fb7d Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Tue, 7 Dec 2021 01:59:00 +0530 Subject: [PATCH 08/14] update param to accept arity of 3 with waitFor as last arg --- src/helpers/a11yAPI.js | 22 ++++++++++------------ src/helpers/makeA11yQuery.js | 35 ++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/helpers/a11yAPI.js b/src/helpers/a11yAPI.js index 99a1d44f2..63d17c007 100644 --- a/src/helpers/a11yAPI.js +++ b/src/helpers/a11yAPI.js @@ -10,15 +10,9 @@ type QueryAllReturn = Array; type FindReturn = Promise; type FindAllReturn = Promise; -type QueryOptions = { - name: string | RegExp, +export type QueryOptions = { + name?: string | RegExp, }; - -export type WaitForOptionsWithName = { - ...WaitForOptions, - ...$Exact, -}; - export type A11yAPI = {| // Label getByA11yLabel: (string | RegExp) => GetReturn, @@ -57,10 +51,14 @@ export type A11yAPI = {| queryByRole: (A11yRole | RegExp, ?QueryOptions) => QueryReturn, queryAllByA11yRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, queryAllByRole: (A11yRole | RegExp, ?QueryOptions) => QueryAllReturn, - findByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, - findByRole: (A11yRole, ?WaitForOptionsWithName) => FindReturn, - findAllByA11yRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, - findAllByRole: (A11yRole, ?WaitForOptionsWithName) => FindAllReturn, + findByA11yRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindReturn, + findByRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindReturn, + findAllByA11yRole: ( + A11yRole, + ?QueryOptions, + ?WaitForOptions + ) => FindAllReturn, + findAllByRole: (A11yRole, ?QueryOptions, ?WaitForOptions) => FindAllReturn, // States getByA11yStates: (A11yStates | Array) => GetReturn, diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index ca797a13a..8041dc89f 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -1,7 +1,8 @@ // @flow import waitFor from '../waitFor'; import { getQueriesForElement } from '../within'; -import type { WaitForOptionsWithName } from './a11yAPI'; +import type { WaitForOptions } from '../waitFor'; +import type { QueryOptions } from './a11yAPI'; import { ErrorWithStack, prepareErrorMessage, @@ -27,10 +28,6 @@ type QueryNames = { findAllBy: Array, }; -type QueryOptions = { - name: string | RegExp, -}; - const makeA11yQuery = ( name: string, queryNames: QueryNames, @@ -51,10 +48,12 @@ const makeA11yQuery = ( ); }; - const getBy = (matcher: M, options?: QueryOptions) => { + const getBy = (matcher: M, queryOptions?: QueryOptions) => { try { - if (options?.name) { - return instance.find((node) => filterWithName(node, options, matcher)); + if (queryOptions?.name) { + return instance.find((node) => + filterWithName(node, queryOptions, matcher) + ); } return instance.find( @@ -72,7 +71,9 @@ const makeA11yQuery = ( let results = []; if (options?.name) { - results = instance.find((node) => filterWithName(node, options, matcher)); + results = instance.findAll((node) => + filterWithName(node, options, matcher) + ); } else { results = instance.findAll( (node) => isNodeValid(node) && matcherFn(node.props[name], matcher) @@ -105,12 +106,20 @@ const makeA11yQuery = ( } }; - const findBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { - return waitFor(() => getBy(matcher, waitForOptions)); + const findBy = ( + matcher: M, + queryOptions?: QueryOptions, + waitForOptions?: WaitForOptions + ) => { + return waitFor(() => getBy(matcher, queryOptions), waitForOptions); }; - const findAllBy = (matcher: M, waitForOptions?: WaitForOptionsWithName) => { - return waitFor(() => getAllBy(matcher, waitForOptions)); + const findAllBy = ( + matcher: M, + queryOptions: QueryOptions, + waitForOptions?: WaitForOptions + ) => { + return waitFor(() => getAllBy(matcher, queryOptions), waitForOptions); }; return { From 48c4e3b11facdf49b86500dd6b0cf969bceece80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 10 Jan 2022 12:24:30 +0100 Subject: [PATCH 09/14] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19850db34..60e7c20b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@testing-library/react-native", - "version": "9.0.0", + "version": "9.0.0-alpha.0", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", "main": "build/index.js", "typings": "./typings/index.d.ts", From 949d559fc9a3c34eb9bbf8c397f81d410256db4b Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Wed, 30 Mar 2022 16:19:46 +0530 Subject: [PATCH 10/14] adds compulsory type for `filterWithName` function --- src/helpers/makeA11yQuery.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index 8041dc89f..58dcbbb47 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -2,13 +2,16 @@ import waitFor from '../waitFor'; import { getQueriesForElement } from '../within'; import type { WaitForOptions } from '../waitFor'; -import type { QueryOptions } from './a11yAPI'; import { ErrorWithStack, prepareErrorMessage, createQueryByError, } from './errors'; +type QueryOptions = { + name: string | RegExp, +}; + function isNodeValid(node: ReactTestInstance) { return typeof node.type === 'string'; } From 29c2d6f5fbcb60565c4a2afc6b94f8106b858958 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Wed, 30 Mar 2022 17:23:49 +0530 Subject: [PATCH 11/14] support backward compatibility for findBy* - adds tests for deprecations - change second param on findBy queries --- src/__tests__/a11yAPI.test.js | 69 +++++++++++++++++++++++++++-------- src/helpers/makeA11yQuery.js | 59 ++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.js index 20e2c7405..9055893a7 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.js @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { TouchableOpacity, Text } from 'react-native'; +import { TouchableOpacity, Text, View } from 'react-native'; import { render } from '..'; const BUTTON_LABEL = 'cool button'; @@ -110,10 +110,10 @@ test('getByA11yLabel, queryByA11yLabel, findByA11yLabel', async () => { const asyncButton = await findByA11yLabel(BUTTON_LABEL); expect(asyncButton.props.accessibilityLabel).toEqual(BUTTON_LABEL); await expect( - findByA11yLabel(NO_MATCHES_TEXT, waitForOptions) + findByA11yLabel(NO_MATCHES_TEXT, {}, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityLabel')); - await expect(findByA11yLabel(TEXT_LABEL, waitForOptions)).rejects.toThrow( + await expect(findByA11yLabel(TEXT_LABEL, {}, waitForOptions)).rejects.toThrow( FOUND_TWO_INSTANCES ); }); @@ -158,10 +158,10 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => { const asyncButton = await findByA11yHint(BUTTON_HINT); expect(asyncButton.props.accessibilityHint).toEqual(BUTTON_HINT); - await expect(findByA11yHint(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( - getNoInstancesFoundMessage('accessibilityHint') - ); - await expect(findByA11yHint(TEXT_HINT, waitForOptions)).rejects.toThrow( + await expect( + findByA11yHint(NO_MATCHES_TEXT, {}, waitForOptions) + ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityHint')); + await expect(findByA11yHint(TEXT_HINT, {}, waitForOptions)).rejects.toThrow( FOUND_TWO_INSTANCES ); }); @@ -229,7 +229,7 @@ test('getByA11yRole, queryByA11yRole, findByA11yRole with name', async () => { name: ONE_OCCURANCE, }); await expect( - findByA11yRole('button', { ...waitForOptions, name: NO_MATCHES_TEXT }) + findByA11yRole('button', { name: NO_MATCHES_TEXT }, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole', 'button')); await expect( findByA11yRole('button', { @@ -257,6 +257,39 @@ test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); }); +describe('findBy options deprecations', () => { + let warnSpy; + beforeEach(() => { + warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + afterEach(() => { + warnSpy.mockRestore(); + }); + + test('findByText queries warn on deprecated use of WaitForOptions', async () => { + const options = { timeout: 10 }; + // mock implementation to avoid warning in the test suite + const { rerender, findByText } = render(); + await expect(findByText('Some Text', options)).rejects.toBeTruthy(); + + setTimeout( + () => + rerender( + + Some Text + + ), + 20 + ); + + await expect(findByText('Some Text')).resolves.toBeTruthy(); + + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('Use of option "timeout"') + ); + }, 20000); +}); + test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole with name', async () => { const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render( @@ -358,7 +391,7 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => { expanded: false, }); await expect( - findByA11yState({ disabled: true }, waitForOptions) + findByA11yState({ disabled: true }, {}, waitForOptions) ).rejects.toThrow( getNoInstancesFoundMessage( 'accessibilityState', @@ -367,7 +400,7 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => { ) ); await expect( - findByA11yState({ expanded: false }, waitForOptions) + findByA11yState({ expanded: false }, {}, waitForOptions) ).rejects.toThrow(FOUND_TWO_INSTANCES); }); @@ -393,7 +426,7 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => { await expect(findAllByA11yState({ selected: true })).resolves.toHaveLength(1); await expect( - findAllByA11yState({ disabled: true }, waitForOptions) + findAllByA11yState({ disabled: true }, {}, waitForOptions) ).rejects.toThrow( getNoInstancesFoundMessage( 'accessibilityState', @@ -433,12 +466,14 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => { min: 40, max: 60, }); - await expect(findByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow( + await expect( + findByA11yValue({ min: 50 }, {}, waitForOptions) + ).rejects.toThrow( getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false) ); - await expect(findByA11yValue({ max: 60 }, waitForOptions)).rejects.toThrow( - FOUND_TWO_INSTANCES - ); + await expect( + findByA11yValue({ max: 60 }, {}, waitForOptions) + ).rejects.toThrow(FOUND_TWO_INSTANCES); }); test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { @@ -458,7 +493,9 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { expect(getAllByA11yValue({ max: 60 })).toHaveLength(2); await expect(findAllByA11yValue({ min: 40 })).resolves.toHaveLength(1); - await expect(findAllByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow( + await expect( + findAllByA11yValue({ min: 50 }, {}, waitForOptions) + ).rejects.toThrow( getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false) ); await expect(findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2); diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.js index 58dcbbb47..8c6b18b1f 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.js @@ -8,10 +8,6 @@ import { createQueryByError, } from './errors'; -type QueryOptions = { - name: string | RegExp, -}; - function isNodeValid(node: ReactTestInstance) { return typeof node.type === 'string'; } @@ -22,6 +18,39 @@ function makeAliases(aliases: Array, query: Function) { .reduce((acc, query) => ({ ...acc, ...query }), {}); } +// The WaitForOptions has been moved to the third param of findBy* methods with the addition of QueryOptions. +// To make the migration easier and to avoid a breaking change, keep reading these options from second param +// but warn. +const deprecatedKeys: $Keys[] = [ + 'timeout', + 'interval', + 'stackTraceError', +]; +const warnDeprectedWaitForOptionsUsage = (queryOptions?: WaitForOptions) => { + if (queryOptions) { + const waitForOptions: WaitForOptions = { + timeout: queryOptions.timeout, + interval: queryOptions.interval, + stackTraceError: queryOptions.stackTraceError, + }; + deprecatedKeys.forEach((key) => { + if (queryOptions[key]) { + // eslint-disable-next-line no-console + console.warn( + `Use of option "${key}" in a findBy* query's second parameter, QueryOptions, is deprecated. Please pass this option in the third, WaitForOptions, parameter. +Example: + findByText(text, {}, { ${key}: ${queryOptions[key].toString()} })` + ); + } + }); + return waitForOptions; + } +}; + +type QueryOptions = { + name: string | RegExp, +}; + type QueryNames = { getBy: Array, getAllBy: Array, @@ -112,17 +141,31 @@ const makeA11yQuery = ( const findBy = ( matcher: M, queryOptions?: QueryOptions, - waitForOptions?: WaitForOptions + waitForOptions?: WaitForOptions = {} ) => { - return waitFor(() => getBy(matcher, queryOptions), waitForOptions); + const deprecatedWaitForOptions = warnDeprectedWaitForOptionsUsage( + queryOptions + ); + + return waitFor(() => getBy(matcher, queryOptions), { + ...deprecatedWaitForOptions, + ...waitForOptions, + }); }; const findAllBy = ( matcher: M, queryOptions: QueryOptions, - waitForOptions?: WaitForOptions + waitForOptions?: WaitForOptions = {} ) => { - return waitFor(() => getAllBy(matcher, queryOptions), waitForOptions); + const deprecatedWaitForOptions = warnDeprectedWaitForOptionsUsage( + queryOptions + ); + + return waitFor(() => getAllBy(matcher, queryOptions), { + ...deprecatedWaitForOptions, + ...waitForOptions, + }); }; return { From a5f168cc1faac1f8eec5af992bf01a81bc7652e1 Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Wed, 30 Mar 2022 19:02:45 +0530 Subject: [PATCH 12/14] migrate flow types to ts --- src/helpers/a11yAPI.ts | 60 +++++++++++++++++++++++++++++++----- src/helpers/makeA11yQuery.ts | 6 ++-- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/helpers/a11yAPI.ts b/src/helpers/a11yAPI.ts index 4b9f42e53..c5b4c0ffc 100644 --- a/src/helpers/a11yAPI.ts +++ b/src/helpers/a11yAPI.ts @@ -1,5 +1,5 @@ import type { ReactTestInstance } from 'react-test-renderer'; -import type { AccessibilityRole, AccessibilityState } from 'react-native'; +import type { AccessibilityState } from 'react-native'; import type { WaitForOptions } from '../waitFor'; import type { TextMatch } from '../matches'; import makeA11yQuery from './makeA11yQuery'; @@ -11,6 +11,34 @@ type A11yValue = { now?: number; text?: string; }; +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'; type GetReturn = ReactTestInstance; type GetAllReturn = Array; @@ -19,6 +47,10 @@ type QueryAllReturn = Array; type FindReturn = Promise; type FindAllReturn = Promise; +export type QueryOptions = { + name?: string | RegExp; +}; + export type A11yAPI = { // Label getByLabelText: (label: TextMatch) => GetReturn; @@ -61,16 +93,30 @@ export type A11yAPI = { ) => FindAllReturn; // Role - getByRole: (role: AccessibilityRole | RegExp) => GetReturn; - getAllByRole: (role: AccessibilityRole | RegExp) => GetAllReturn; - queryByRole: (role: AccessibilityRole | RegExp) => QueryReturn; - queryAllByRole: (role: AccessibilityRole | RegExp) => QueryAllReturn; + getByRole: ( + role: A11yRole | RegExp, + queryOptions?: QueryOptions + ) => GetReturn; + getAllByRole: ( + role: A11yRole | RegExp, + queryOptions?: QueryOptions + ) => GetAllReturn; + queryByRole: ( + role: A11yRole | RegExp, + queryOptions?: QueryOptions + ) => QueryReturn; + queryAllByRole: ( + role: A11yRole | RegExp, + queryOptions?: QueryOptions + ) => QueryAllReturn; findByRole: ( - role: AccessibilityRole, + role: A11yRole, + queryOptions?: QueryOptions & WaitForOptions, waitForOptions?: WaitForOptions ) => FindReturn; findAllByRole: ( - role: AccessibilityRole, + role: A11yRole, + queryOptions?: QueryOptions & WaitForOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; diff --git a/src/helpers/makeA11yQuery.ts b/src/helpers/makeA11yQuery.ts index a258f0fe6..913212307 100644 --- a/src/helpers/makeA11yQuery.ts +++ b/src/helpers/makeA11yQuery.ts @@ -48,7 +48,7 @@ Example: }; type QueryOptions = { - name: string | RegExp, + name: string | RegExp; }; type QueryNames = { @@ -64,9 +64,7 @@ const makeA11yQuery =

( name: string, queryNames: QueryNames, matcherFn: (prop: P, value: M) => boolean -): ((instance: ReactTestInstance) => { ... }) => ( - instance: ReactTestInstance -) => { +) => (instance: ReactTestInstance) => { const filterWithName = ( node: ReactTestInstance, options: QueryOptions, From 9ff3136c6c04eb0e9528723a46703f1b4898e82c Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Wed, 30 Mar 2022 23:36:21 +0530 Subject: [PATCH 13/14] making ts compiler happy --- src/helpers/makeA11yQuery.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/helpers/makeA11yQuery.ts b/src/helpers/makeA11yQuery.ts index 913212307..5fa7d5b99 100644 --- a/src/helpers/makeA11yQuery.ts +++ b/src/helpers/makeA11yQuery.ts @@ -21,7 +21,7 @@ function makeAliases(aliases: Array, query: Function) { // The WaitForOptions has been moved to the third param of findBy* methods with the addition of QueryOptions. // To make the migration easier and to avoid a breaking change, keep reading these options from second param // but warn. -const deprecatedKeys: $Keys[] = [ +const deprecatedKeys: (keyof WaitForOptions)[] = [ 'timeout', 'interval', 'stackTraceError', @@ -39,7 +39,7 @@ const warnDeprectedWaitForOptionsUsage = (queryOptions?: WaitForOptions) => { console.warn( `Use of option "${key}" in a findBy* query's second parameter, QueryOptions, is deprecated. Please pass this option in the third, WaitForOptions, parameter. Example: - findByText(text, {}, { ${key}: ${queryOptions[key].toString()} })` + findByText(text, {}, { ${key}: ${queryOptions[key]} })` ); } }); @@ -138,8 +138,8 @@ const makeA11yQuery =

( const findBy = ( matcher: M, - queryOptions?: QueryOptions, - waitForOptions?: WaitForOptions = {} + queryOptions?: QueryOptions & WaitForOptions, + waitForOptions?: WaitForOptions ) => { const deprecatedWaitForOptions = warnDeprectedWaitForOptionsUsage( queryOptions @@ -153,8 +153,8 @@ const makeA11yQuery =

( const findAllBy = ( matcher: M, - queryOptions: QueryOptions, - waitForOptions?: WaitForOptions = {} + queryOptions?: QueryOptions & WaitForOptions, + waitForOptions?: WaitForOptions ) => { const deprecatedWaitForOptions = warnDeprectedWaitForOptionsUsage( queryOptions From b6abc2fff0c10570a0a37dc613801152f8cc0eeb Mon Sep 17 00:00:00 2001 From: Kiran Jd Date: Thu, 31 Mar 2022 00:06:30 +0530 Subject: [PATCH 14/14] undo changes to other APIs --- src/__tests__/a11yAPI.test.tsx | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/__tests__/a11yAPI.test.tsx b/src/__tests__/a11yAPI.test.tsx index 745d82b8c..aa39de144 100644 --- a/src/__tests__/a11yAPI.test.tsx +++ b/src/__tests__/a11yAPI.test.tsx @@ -109,10 +109,10 @@ test('getByLabelText, queryByLabelText, findByLabelText', async () => { const asyncButton = await findByLabelText(BUTTON_LABEL); expect(asyncButton.props.accessibilityLabel).toEqual(BUTTON_LABEL); await expect( - findByLabelText(NO_MATCHES_TEXT, {}, waitForOptions) + findByLabelText(NO_MATCHES_TEXT, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityLabel')); - await expect(findByLabelText(TEXT_LABEL, {}, waitForOptions)).rejects.toThrow( + await expect(findByLabelText(TEXT_LABEL, waitForOptions)).rejects.toThrow( FOUND_TWO_INSTANCES ); }); @@ -157,10 +157,10 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => { const asyncButton = await findByA11yHint(BUTTON_HINT); expect(asyncButton.props.accessibilityHint).toEqual(BUTTON_HINT); - await expect( - findByA11yHint(NO_MATCHES_TEXT, {}, waitForOptions) - ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityHint')); - await expect(findByA11yHint(TEXT_HINT, {}, waitForOptions)).rejects.toThrow( + await expect(findByA11yHint(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( + getNoInstancesFoundMessage('accessibilityHint') + ); + await expect(findByA11yHint(TEXT_HINT, waitForOptions)).rejects.toThrow( FOUND_TWO_INSTANCES ); }); @@ -225,7 +225,7 @@ test('getAllByRole, queryAllByRole, findAllByRole', async () => { }); describe('findBy options deprecations', () => { - let warnSpy; + let warnSpy: jest.SpyInstance; beforeEach(() => { warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); }); @@ -359,7 +359,7 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => { expanded: false, }); await expect( - findByA11yState({ disabled: true }, {}, waitForOptions) + findByA11yState({ disabled: true }, waitForOptions) ).rejects.toThrow( getNoInstancesFoundMessage( 'accessibilityState', @@ -368,7 +368,7 @@ test('getByA11yState, queryByA11yState, findByA11yState', async () => { ) ); await expect( - findByA11yState({ expanded: false }, {}, waitForOptions) + findByA11yState({ expanded: false }, waitForOptions) ).rejects.toThrow(FOUND_TWO_INSTANCES); }); @@ -394,7 +394,7 @@ test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => { await expect(findAllByA11yState({ selected: true })).resolves.toHaveLength(1); await expect( - findAllByA11yState({ disabled: true }, {}, waitForOptions) + findAllByA11yState({ disabled: true }, waitForOptions) ).rejects.toThrow( getNoInstancesFoundMessage( 'accessibilityState', @@ -434,14 +434,12 @@ test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => { min: 40, max: 60, }); - await expect( - findByA11yValue({ min: 50 }, {}, waitForOptions) - ).rejects.toThrow( + await expect(findByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow( getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false) ); - await expect( - findByA11yValue({ max: 60 }, {}, waitForOptions) - ).rejects.toThrow(FOUND_TWO_INSTANCES); + await expect(findByA11yValue({ max: 60 }, waitForOptions)).rejects.toThrow( + FOUND_TWO_INSTANCES + ); }); test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { @@ -461,9 +459,7 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { expect(getAllByA11yValue({ max: 60 })).toHaveLength(2); await expect(findAllByA11yValue({ min: 40 })).resolves.toHaveLength(1); - await expect( - findAllByA11yValue({ min: 50 }, {}, waitForOptions) - ).rejects.toThrow( + await expect(findAllByA11yValue({ min: 50 }, waitForOptions)).rejects.toThrow( getNoInstancesFoundMessage('accessibilityValue', '{"min": 50}', false) ); await expect(findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2);