From e9168424b489aae0520584881c1694e899db39e7 Mon Sep 17 00:00:00 2001 From: Shaswat Prabhat Date: Thu, 20 Oct 2022 21:30:17 +0530 Subject: [PATCH 01/11] Add queryOptions to labelText and hintText --- src/queries/hintText.ts | 64 +++++++++++++++++++++++----------------- src/queries/labelText.ts | 34 ++++++++++++++------- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/queries/hintText.ts b/src/queries/hintText.ts index a7a28c1cc..1242371cc 100644 --- a/src/queries/hintText.ts +++ b/src/queries/hintText.ts @@ -1,6 +1,5 @@ import type { ReactTestInstance } from 'react-test-renderer'; -import { TextMatch } from '../matches'; -import { matchStringProp } from '../helpers/matchers/matchStringProp'; +import { matches, TextMatch } from '../matches'; import { makeQueries } from './makeQueries'; import type { FindAllByQuery, @@ -10,16 +9,27 @@ import type { QueryAllByQuery, QueryByQuery, } from './makeQueries'; +import { TextMatchOptions } from './text'; + +const getNodeByHintText = ( + node: ReactTestInstance, + text: TextMatch, + options: TextMatchOptions = {} +) => { + const { exact, normalizer } = options; + return matches(text, node.props.accessibilityHint, normalizer, exact); +}; const queryAllByHintText = ( instance: ReactTestInstance -): ((hint: TextMatch) => Array) => - function queryAllByA11yHintFn(hint) { - return instance.findAll( - (node) => - typeof node.type === 'string' && - matchStringProp(node.props.accessibilityHint, hint) - ); +): (( + hint: TextMatch, + queryOptions?: TextMatchOptions +) => Array) => + function queryAllByA11yHintFn(hint, queryOptions) { + return instance + .findAll((node) => getNodeByHintText(node, hint, queryOptions)) + .filter((element) => typeof element.type === 'string'); }; const getMultipleError = (hint: TextMatch) => @@ -34,28 +44,28 @@ const { getBy, getAllBy, queryBy, queryAllBy, findBy, findAllBy } = makeQueries( ); export type ByHintTextQueries = { - getByHintText: GetByQuery; - getAllByHintText: GetAllByQuery; - queryByHintText: QueryByQuery; - queryAllByHintText: QueryAllByQuery; - findByHintText: FindByQuery; - findAllByHintText: FindAllByQuery; + getByHintText: GetByQuery; + getAllByHintText: GetAllByQuery; + queryByHintText: QueryByQuery; + queryAllByHintText: QueryAllByQuery; + findByHintText: FindByQuery; + findAllByHintText: FindAllByQuery; // a11yHint aliases - getByA11yHint: GetByQuery; - getAllByA11yHint: GetAllByQuery; - queryByA11yHint: QueryByQuery; - queryAllByA11yHint: QueryAllByQuery; - findByA11yHint: FindByQuery; - findAllByA11yHint: FindAllByQuery; + getByA11yHint: GetByQuery; + getAllByA11yHint: GetAllByQuery; + queryByA11yHint: QueryByQuery; + queryAllByA11yHint: QueryAllByQuery; + findByA11yHint: FindByQuery; + findAllByA11yHint: FindAllByQuery; // accessibilityHint aliases - getByAccessibilityHint: GetByQuery; - getAllByAccessibilityHint: GetAllByQuery; - queryByAccessibilityHint: QueryByQuery; - queryAllByAccessibilityHint: QueryAllByQuery; - findByAccessibilityHint: FindByQuery; - findAllByAccessibilityHint: FindAllByQuery; + getByAccessibilityHint: GetByQuery; + getAllByAccessibilityHint: GetAllByQuery; + queryByAccessibilityHint: QueryByQuery; + queryAllByAccessibilityHint: QueryAllByQuery; + findByAccessibilityHint: FindByQuery; + findAllByAccessibilityHint: FindAllByQuery; }; export const bindByHintTextQueries = ( diff --git a/src/queries/labelText.ts b/src/queries/labelText.ts index 8142222bb..2af6ede4f 100644 --- a/src/queries/labelText.ts +++ b/src/queries/labelText.ts @@ -1,6 +1,5 @@ import type { ReactTestInstance } from 'react-test-renderer'; -import { TextMatch } from '../matches'; -import { matchStringProp } from '../helpers/matchers/matchStringProp'; +import { matches, TextMatch } from '../matches'; import { makeQueries } from './makeQueries'; import type { FindAllByQuery, @@ -10,15 +9,28 @@ import type { QueryAllByQuery, QueryByQuery, } from './makeQueries'; +import { TextMatchOptions } from './text'; + +const getNodeByLabelText = ( + node: ReactTestInstance, + text: TextMatch, + options: TextMatchOptions = {} +) => { + const { exact, normalizer } = options; + return matches(text, node.props.accessibilityLabel, normalizer, exact); +}; const queryAllByLabelText = ( instance: ReactTestInstance -): ((text: TextMatch) => Array) => - function queryAllByLabelTextFn(text) { +): (( + text: TextMatch, + queryOptions?: TextMatchOptions +) => Array) => + function queryAllByLabelTextFn(text, queryOptions?: TextMatchOptions) { return instance.findAll( (node) => typeof node.type === 'string' && - matchStringProp(node.props.accessibilityLabel, text) + getNodeByLabelText(node, text, queryOptions) ); }; @@ -34,12 +46,12 @@ const { getBy, getAllBy, queryBy, queryAllBy, findBy, findAllBy } = makeQueries( ); export type ByLabelTextQueries = { - getByLabelText: GetByQuery; - getAllByLabelText: GetAllByQuery; - queryByLabelText: QueryByQuery; - queryAllByLabelText: QueryAllByQuery; - findByLabelText: FindByQuery; - findAllByLabelText: FindAllByQuery; + getByLabelText: GetByQuery; + getAllByLabelText: GetAllByQuery; + queryByLabelText: QueryByQuery; + queryAllByLabelText: QueryAllByQuery; + findByLabelText: FindByQuery; + findAllByLabelText: FindAllByQuery; }; export const bindByLabelTextQueries = ( From a62e68182c0e03ba654ae908ad51724e2507e6b3 Mon Sep 17 00:00:00 2001 From: Shaswat Prabhat Date: Thu, 20 Oct 2022 21:59:03 +0530 Subject: [PATCH 02/11] Add tests for hintText and string check --- src/queries/__tests__/text.test.tsx | 21 +++++++++++++++++++++ src/queries/hintText.ts | 8 +++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/queries/__tests__/text.test.tsx b/src/queries/__tests__/text.test.tsx index 6f5c435b6..2ff87d47c 100644 --- a/src/queries/__tests__/text.test.tsx +++ b/src/queries/__tests__/text.test.tsx @@ -342,6 +342,27 @@ describe('supports TextMatch options', () => { expect(getAllByTestId('test', { exact: false })).toHaveLength(2); }); + test('getByHintText, getByHintText', () => { + const { getByHintText, getAllByHintText } = render( + + + + + ); + expect(getByHintText('id', { exact: false })).toBeTruthy(); + expect(getAllByHintText('test', { exact: false })).toHaveLength(2); + }); + test('getByHintText, getByHintText and exact = true', () => { + const { queryByHintText, getAllByHintText } = render( + + + + + ); + expect(queryByHintText('id', { exact: true })).toBeNull(); + expect(getAllByHintText('test', { exact: true })).toHaveLength(1); + }); + test('with TextMatch option exact === false text search is NOT case sensitive', () => { const { getByText, getAllByText } = render( diff --git a/src/queries/hintText.ts b/src/queries/hintText.ts index 1242371cc..bf9a33193 100644 --- a/src/queries/hintText.ts +++ b/src/queries/hintText.ts @@ -27,9 +27,11 @@ const queryAllByHintText = ( queryOptions?: TextMatchOptions ) => Array) => function queryAllByA11yHintFn(hint, queryOptions) { - return instance - .findAll((node) => getNodeByHintText(node, hint, queryOptions)) - .filter((element) => typeof element.type === 'string'); + return instance.findAll( + (node) => + typeof node.type === 'string' && + getNodeByHintText(node, hint, queryOptions) + ); }; const getMultipleError = (hint: TextMatch) => From 4466d73fb8571fb818bb9c0b74d8f53424198605 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 20 Oct 2022 19:15:42 +0200 Subject: [PATCH 03/11] Update src/queries/__tests__/text.test.tsx --- src/queries/__tests__/text.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/queries/__tests__/text.test.tsx b/src/queries/__tests__/text.test.tsx index 2ff87d47c..f8fa7a0d1 100644 --- a/src/queries/__tests__/text.test.tsx +++ b/src/queries/__tests__/text.test.tsx @@ -352,6 +352,7 @@ describe('supports TextMatch options', () => { expect(getByHintText('id', { exact: false })).toBeTruthy(); expect(getAllByHintText('test', { exact: false })).toHaveLength(2); }); + test('getByHintText, getByHintText and exact = true', () => { const { queryByHintText, getAllByHintText } = render( From 564b9730fa3a49b9ebc931663242de9add116b2c Mon Sep 17 00:00:00 2001 From: Shaswat Prabhat Date: Fri, 21 Oct 2022 09:15:33 +0530 Subject: [PATCH 04/11] Move Hinttext tests to hintText.test.tsx --- src/queries/__tests__/hintText.test.tsx | 24 +++++++++++++++++++++++- src/queries/__tests__/text.test.tsx | 22 ---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/queries/__tests__/hintText.test.tsx b/src/queries/__tests__/hintText.test.tsx index 6e5ddb5e7..9a7585920 100644 --- a/src/queries/__tests__/hintText.test.tsx +++ b/src/queries/__tests__/hintText.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { TouchableOpacity, Text } from 'react-native'; +import { TouchableOpacity, Text, View } from 'react-native'; import { render } from '../..'; const BUTTON_HINT = 'click this button'; @@ -84,3 +84,25 @@ test('getAllByA11yHint, queryAllByA11yHint, findAllByA11yHint', async () => { getNoInstancesFoundMessage(NO_MATCHES_TEXT) ); }); + +test('getByHintText, getByHintText', () => { + const { getByHintText, getAllByHintText } = render( + + + + + ); + expect(getByHintText('id', { exact: false })).toBeTruthy(); + expect(getAllByHintText('test', { exact: false })).toHaveLength(2); +}); + +test('getByHintText, getByHintText and exact = true', () => { + const { queryByHintText, getAllByHintText } = render( + + + + + ); + expect(queryByHintText('id', { exact: true })).toBeNull(); + expect(getAllByHintText('test', { exact: true })).toHaveLength(1); +}); diff --git a/src/queries/__tests__/text.test.tsx b/src/queries/__tests__/text.test.tsx index f8fa7a0d1..6f5c435b6 100644 --- a/src/queries/__tests__/text.test.tsx +++ b/src/queries/__tests__/text.test.tsx @@ -342,28 +342,6 @@ describe('supports TextMatch options', () => { expect(getAllByTestId('test', { exact: false })).toHaveLength(2); }); - test('getByHintText, getByHintText', () => { - const { getByHintText, getAllByHintText } = render( - - - - - ); - expect(getByHintText('id', { exact: false })).toBeTruthy(); - expect(getAllByHintText('test', { exact: false })).toHaveLength(2); - }); - - test('getByHintText, getByHintText and exact = true', () => { - const { queryByHintText, getAllByHintText } = render( - - - - - ); - expect(queryByHintText('id', { exact: true })).toBeNull(); - expect(getAllByHintText('test', { exact: true })).toHaveLength(1); - }); - test('with TextMatch option exact === false text search is NOT case sensitive', () => { const { getByText, getAllByText } = render( From 5ce03b71e12650813c82da46470d171c8a707524 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 21 Oct 2022 12:49:04 +0200 Subject: [PATCH 05/11] fix: matchers using global regexes --- src/matches.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/matches.ts b/src/matches.ts index 388038ad8..48478498c 100644 --- a/src/matches.ts +++ b/src/matches.ts @@ -18,6 +18,8 @@ export function matches( ? normalizedText === normalizedMatcher : normalizedText.toLowerCase().includes(normalizedMatcher.toLowerCase()); } else { + // Reset state for global regexes: https://stackoverflow.com/a/1520839/484499 + matcher.lastIndex = 0; return matcher.test(normalizedText); } } From ef0ca158dec35ed6e2813449e5984dea7e253eb1 Mon Sep 17 00:00:00 2001 From: Shaswat Prabhat Date: Wed, 26 Oct 2022 20:53:28 +0530 Subject: [PATCH 06/11] Add tests for labeltext with exact set to false --- src/queries/__tests__/labelText.test.tsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/queries/__tests__/labelText.test.tsx b/src/queries/__tests__/labelText.test.tsx index 8b9dc54e1..4d28d42d7 100644 --- a/src/queries/__tests__/labelText.test.tsx +++ b/src/queries/__tests__/labelText.test.tsx @@ -93,3 +93,24 @@ test('getAllByLabelText, queryAllByLabelText, findAllByLabelText', async () => { getNoInstancesFoundMessage(NO_MATCHES_TEXT) ); }); + +test('getAllByLabelText, queryAllByLabelText, findAllByLabelText with exact as false', async () => { + const { getAllByLabelText, queryAllByLabelText, findAllByLabelText } = render( +
+ ); + + expect(getAllByLabelText(TEXT_LABEL, { exact: false })).toHaveLength(2); + expect(queryAllByLabelText(/cool/g, { exact: false })).toHaveLength(3); + + expect(() => getAllByLabelText(NO_MATCHES_TEXT)).toThrow( + getNoInstancesFoundMessage(NO_MATCHES_TEXT) + ); + expect(queryAllByLabelText(NO_MATCHES_TEXT, { exact: false })).toEqual([]); + + await expect( + findAllByLabelText(TEXT_LABEL, { exact: false }) + ).resolves.toHaveLength(2); + await expect( + findAllByLabelText(NO_MATCHES_TEXT, { exact: false }) + ).rejects.toThrow(getNoInstancesFoundMessage(NO_MATCHES_TEXT)); +}); From d4cbb454924d8d327c2e2df7fad16a08833c2b1f Mon Sep 17 00:00:00 2001 From: Shaswat Prabhat Date: Wed, 26 Oct 2022 20:57:31 +0530 Subject: [PATCH 07/11] Update flow types for the label and hint queries --- typings/index.flow.js | 66 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/typings/index.flow.js b/typings/index.flow.js index 2c8c35710..58dd07a28 100644 --- a/typings/index.flow.js +++ b/typings/index.flow.js @@ -210,12 +210,26 @@ type ByRoleOptions = { interface A11yAPI { // Label - getByLabelText: (matcher: TextMatch) => GetReturn; - getAllByLabelText: (matcher: TextMatch) => GetAllReturn; - queryByLabelText: (matcher: TextMatch) => QueryReturn; - queryAllByLabelText: (matcher: TextMatch) => QueryAllReturn; + getByLabelText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetReturn; + getAllByLabelText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetAllReturn; + queryByLabelText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryReturn; + queryAllByLabelText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryAllReturn; findByLabelText: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions ) => FindReturn; findAllByLabelText: ( @@ -224,28 +238,56 @@ interface A11yAPI { ) => FindAllReturn; // Hint - getByA11yHint: (matcher: TextMatch) => GetReturn; - getByHintText: (matcher: TextMatch) => GetReturn; - getAllByA11yHint: (matcher: TextMatch) => GetAllReturn; - getAllByHintText: (matcher: TextMatch) => GetAllReturn; - queryByA11yHint: (matcher: TextMatch) => QueryReturn; - queryByHintText: (matcher: TextMatch) => QueryReturn; - queryAllByA11yHint: (matcher: TextMatch) => QueryAllReturn; - queryAllByHintText: (matcher: TextMatch) => QueryAllReturn; + getByA11yHint: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetReturn; + getByHintText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetReturn; + getAllByA11yHint: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetAllReturn; + getAllByHintText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => GetAllReturn; + queryByA11yHint: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryReturn; + queryByHintText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryReturn; + queryAllByA11yHint: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryAllReturn; + queryAllByHintText: ( + matcher: TextMatch, + queryOptions?: TextMatchOptions + ) => QueryAllReturn; findByA11yHint: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, waitForOptions?: WaitForOptions ) => FindReturn; findByHintText: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, waitForOptions?: WaitForOptions ) => FindReturn; findAllByA11yHint: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; findAllByHintText: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; From 7310d15b00b7b9f440dc2e1610a40c415c01d570 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 31 Oct 2022 09:39:12 +0100 Subject: [PATCH 08/11] Flow type tweaks --- typings/index.flow.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/typings/index.flow.js b/typings/index.flow.js index 58dd07a28..0f1282bfd 100644 --- a/typings/index.flow.js +++ b/typings/index.flow.js @@ -212,63 +212,63 @@ interface A11yAPI { // Label getByLabelText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetReturn; getAllByLabelText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetAllReturn; queryByLabelText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryReturn; queryAllByLabelText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryAllReturn; findByLabelText: ( matcher: TextMatch, queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions ) => FindReturn; findAllByLabelText: ( matcher: TextMatch, + queryOptions?: TextMatchOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; // Hint getByA11yHint: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetReturn; getByHintText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetReturn; getAllByA11yHint: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetAllReturn; getAllByHintText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => GetAllReturn; queryByA11yHint: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryReturn; queryByHintText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryReturn; queryAllByA11yHint: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryAllReturn; queryAllByHintText: ( matcher: TextMatch, - queryOptions?: TextMatchOptions + options?: TextMatchOptions ) => QueryAllReturn; findByA11yHint: ( matcher: TextMatch, @@ -295,24 +295,24 @@ interface A11yAPI { getByRole: (matcher: A11yRole | RegExp, role?: ByRoleOptions) => GetReturn; getAllByRole: ( matcher: A11yRole | RegExp, - role?: ByRoleOptions + options?: ByRoleOptions ) => GetAllReturn; queryByRole: ( matcher: A11yRole | RegExp, - role?: ByRoleOptions + options?: ByRoleOptions ) => QueryReturn; queryAllByRole: ( matcher: A11yRole | RegExp, - role?: ByRoleOptions + options?: ByRoleOptions ) => QueryAllReturn; findByRole: ( matcher: A11yRole | RegExp, - role?: ByRoleOptions, + queryOptions?: ByRoleOptions, waitForOptions?: WaitForOptions ) => FindReturn; findAllByRole: ( matcher: A11yRole | RegExp, - role?: ByRoleOptions, + queryOptions?: ByRoleOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; From ad5749e4f7c26bd0433ce1c8ee7b53701746303c Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 31 Oct 2022 09:41:46 +0100 Subject: [PATCH 09/11] Update labelText.test.tsx --- src/queries/__tests__/labelText.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries/__tests__/labelText.test.tsx b/src/queries/__tests__/labelText.test.tsx index 4d28d42d7..9a39a1b48 100644 --- a/src/queries/__tests__/labelText.test.tsx +++ b/src/queries/__tests__/labelText.test.tsx @@ -102,7 +102,7 @@ test('getAllByLabelText, queryAllByLabelText, findAllByLabelText with exact as f expect(getAllByLabelText(TEXT_LABEL, { exact: false })).toHaveLength(2); expect(queryAllByLabelText(/cool/g, { exact: false })).toHaveLength(3); - expect(() => getAllByLabelText(NO_MATCHES_TEXT)).toThrow( + expect(() => getAllByLabelText(NO_MATCHES_TEXT, { exact: false })).toThrow( getNoInstancesFoundMessage(NO_MATCHES_TEXT) ); expect(queryAllByLabelText(NO_MATCHES_TEXT, { exact: false })).toEqual([]); From 9252947eb0c83de611915c22b531804a2fbe8d17 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 31 Oct 2022 09:58:30 +0100 Subject: [PATCH 10/11] chore: bring back waitForOptions compatibility --- src/queries/__tests__/labelText.test.tsx | 31 ++++++++++- src/queries/makeQueries.ts | 69 +++++++++++++++++++----- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/src/queries/__tests__/labelText.test.tsx b/src/queries/__tests__/labelText.test.tsx index 9a39a1b48..68564fa02 100644 --- a/src/queries/__tests__/labelText.test.tsx +++ b/src/queries/__tests__/labelText.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { TouchableOpacity, Text } from 'react-native'; +import { View, Text, TouchableOpacity } from 'react-native'; import { render } from '../..'; const BUTTON_LABEL = 'cool button'; @@ -114,3 +114,32 @@ test('getAllByLabelText, queryAllByLabelText, findAllByLabelText with exact as f findAllByLabelText(NO_MATCHES_TEXT, { exact: false }) ).rejects.toThrow(getNoInstancesFoundMessage(NO_MATCHES_TEXT)); }); + +describe('findBy options deprecations', () => { + let warnSpy: jest.SpyInstance; + 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 view = render(); + await expect( + view.findByLabelText('Some Text', options) + ).rejects.toBeTruthy(); + + setTimeout( + () => view.rerender(), + 20 + ); + await expect(view.findByLabelText('Some Text')).resolves.toBeTruthy(); + + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('Use of option "timeout"') + ); + }, 20000); +}); diff --git a/src/queries/makeQueries.ts b/src/queries/makeQueries.ts index 5e02bcb88..a309d10fa 100644 --- a/src/queries/makeQueries.ts +++ b/src/queries/makeQueries.ts @@ -25,13 +25,15 @@ export type QueryAllByQuery = ( export type FindByQuery = ( predicate: Predicate, - options?: Options, + // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. + options?: Options & WaitForOptions, waitForOptions?: WaitForOptions ) => Promise; export type FindAllByQuery = ( predicate: Predicate, - options?: Options, + // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. + options?: Options & WaitForOptions, waitForOptions?: WaitForOptions ) => Promise; @@ -46,6 +48,41 @@ export type UnboundQueries = { findAllBy: UnboundQuery>; }; +const deprecatedKeys: (keyof WaitForOptions)[] = [ + 'timeout', + 'interval', + 'stackTraceError', +]; + +// The WaitForOptions has been moved to the second option param of findBy* methods with the adding of TextMatchOptions +// To make the migration easier and avoid a breaking change, keep reading this options from the first param but warn +function extractDeprecatedWaitForOptions(options?: WaitForOptions) { + if (!options) { + return undefined; + } + + const waitForOptions: WaitForOptions = { + timeout: options.timeout, + interval: options.interval, + stackTraceError: options.stackTraceError, + }; + + deprecatedKeys.forEach((key) => { + const option = options[key]; + if (option) { + // eslint-disable-next-line no-console + console.warn( + `Use of option "${key}" in a findBy* query options (2nd parameter) is deprecated. Please pass this option in the waitForOptions (3rd parameter). +Example: + + findByText(text, {}, { ${key}: ${option.toString()} })` + ); + } + }); + + return waitForOptions; +} + export function makeQueries( queryAllByQuery: UnboundQuery>, getMissingError: (predicate: Predicate, options?: Options) => string, @@ -101,26 +138,30 @@ export function makeQueries( function findAllByQuery(instance: ReactTestInstance) { return function findAllFn( predicate: Predicate, - queryOptions?: Options, - waitForOptions?: WaitForOptions + queryOptions?: Options & WaitForOptions, + waitForOptions: WaitForOptions = {} ) { - return waitFor( - () => getAllByQuery(instance)(predicate, queryOptions), - waitForOptions - ); + const deprecatedWaitForOptions = + extractDeprecatedWaitForOptions(queryOptions); + return waitFor(() => getAllByQuery(instance)(predicate, queryOptions), { + ...deprecatedWaitForOptions, + ...waitForOptions, + }); }; } function findByQuery(instance: ReactTestInstance) { return function findFn( predicate: Predicate, - queryOptions?: Options, - waitForOptions?: WaitForOptions + queryOptions?: Options & WaitForOptions, + waitForOptions: WaitForOptions = {} ) { - return waitFor( - () => getByQuery(instance)(predicate, queryOptions), - waitForOptions - ); + const deprecatedWaitForOptions = + extractDeprecatedWaitForOptions(queryOptions); + return waitFor(() => getByQuery(instance)(predicate, queryOptions), { + ...deprecatedWaitForOptions, + ...waitForOptions, + }); }; } From 363da3c75ffd3a8f0016b223ef3198dbc38f759e Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 31 Oct 2022 11:28:53 +0100 Subject: [PATCH 11/11] docs: update docs --- website/docs/Queries.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/website/docs/Queries.md b/website/docs/Queries.md index 2b39059af..733e7dcf0 100644 --- a/website/docs/Queries.md +++ b/website/docs/Queries.md @@ -193,7 +193,11 @@ In the spirit of [the guiding principles](https://testing-library.com/docs/guidi ```ts getByLabelText( - text: TextMatch + text: TextMatch, + options?: { + exact?: boolean; + normalizer?: (text: string) => string; + } ): ReactTestInstance; ``` @@ -214,7 +218,11 @@ const element = screen.getByLabelText('my-label'); ```ts getByHintText( - hint: TextMatch + hint: TextMatch, + options?: { + exact?: boolean; + normalizer?: (text: string) => string; + } ): ReactTestInstance; ```