From 3fd07382681d9d1139d7f3a6d46b3ab6993b673d Mon Sep 17 00:00:00 2001 From: pierrezimmermann Date: Mon, 10 Jul 2023 11:12:28 +0200 Subject: [PATCH 1/9] refactor: type all queries to return host components --- src/helpers/component-tree.ts | 6 +++++- src/helpers/findAll.ts | 15 +++++++++------ src/helpers/matchers/matchLabelText.ts | 1 - src/queries/a11yState.ts | 8 ++------ src/queries/a11yValue.ts | 8 ++------ src/queries/displayValue.ts | 5 +---- src/queries/hintText.ts | 9 ++------- src/queries/labelText.ts | 4 +--- src/queries/makeQueries.ts | 13 +++++++------ src/queries/placeholderText.ts | 5 +---- src/queries/role.ts | 3 +-- src/queries/testId.ts | 9 ++------- src/queries/text.ts | 2 +- 13 files changed, 34 insertions(+), 54 deletions(-) diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index 3d3ea03eb..4c5ec63eb 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -1,10 +1,14 @@ import { ReactTestInstance } from 'react-test-renderer'; +export type HostReactTestInstance = ReactTestInstance & { type: string }; + /** * Checks if the given element is a host element. * @param element The element to check. */ -export function isHostElement(element?: ReactTestInstance | null) { +export function isHostElement( + element?: ReactTestInstance | null +): element is HostReactTestInstance { return typeof element?.type === 'string'; } diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index 4204a9096..49613b96f 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -1,6 +1,8 @@ import { ReactTestInstance } from 'react-test-renderer'; import { getConfig } from '../config'; import { isHiddenFromAccessibility } from './accessiblity'; +import { isHostElement } from './component-tree'; +import type { HostReactTestInstance } from './component-tree'; interface FindAllOptions { /** Match elements hidden from accessibility */ @@ -17,7 +19,7 @@ export function findAll( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -) { +): Array { const results = findAllInternal(root, predicate, options); const includeHiddenElements = @@ -41,11 +43,11 @@ function findAllInternal( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -): Array { - const results: ReactTestInstance[] = []; +): Array { + const results: HostReactTestInstance[] = []; // Match descendants first but do not add them to results yet. - const matchingDescendants: ReactTestInstance[] = []; + const matchingDescendants: HostReactTestInstance[] = []; root.children.forEach((child) => { if (typeof child === 'string') { return; @@ -54,9 +56,10 @@ function findAllInternal( }); if ( + isHostElement(root) && + predicate(root) && // When matchDeepestOnly = true: add current element only if no descendants match - (!options?.matchDeepestOnly || matchingDescendants.length === 0) && - predicate(root) + (!options?.matchDeepestOnly || matchingDescendants.length === 0) ) { results.push(root); } diff --git a/src/helpers/matchers/matchLabelText.ts b/src/helpers/matchers/matchLabelText.ts index 8058f2904..19c21669c 100644 --- a/src/helpers/matchers/matchLabelText.ts +++ b/src/helpers/matchers/matchLabelText.ts @@ -43,7 +43,6 @@ function matchAccessibilityLabelledBy( findAll( root, (node) => - typeof node.type === 'string' && node.props.nativeID === nativeId && matchTextContent(node, text, options) ).length > 0 diff --git a/src/queries/a11yState.ts b/src/queries/a11yState.ts index f9a61d164..80a759035 100644 --- a/src/queries/a11yState.ts +++ b/src/queries/a11yState.ts @@ -19,15 +19,11 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yState = ( instance: ReactTestInstance -): (( - matcher: AccessibilityStateMatcher, - queryOptions?: CommonQueryOptions -) => Array) => +): QueryAllByQuery => function queryAllByA11yStateFn(matcher, queryOptions) { return findAll( instance, - (node) => - typeof node.type === 'string' && matchAccessibilityState(node, matcher), + (node) => matchAccessibilityState(node, matcher), queryOptions ); }; diff --git a/src/queries/a11yValue.ts b/src/queries/a11yValue.ts index f77881cff..753778548 100644 --- a/src/queries/a11yValue.ts +++ b/src/queries/a11yValue.ts @@ -19,15 +19,11 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yValue = ( instance: ReactTestInstance -): (( - value: AccessibilityValueMatcher, - queryOptions?: CommonQueryOptions -) => Array) => +): QueryAllByQuery => function queryAllByA11yValueFn(value, queryOptions) { return findAll( instance, - (node) => - typeof node.type === 'string' && matchAccessibilityValue(node, value), + (node) => matchAccessibilityValue(node, value), queryOptions ); }; diff --git a/src/queries/displayValue.ts b/src/queries/displayValue.ts index 7ceef802f..44db16f93 100644 --- a/src/queries/displayValue.ts +++ b/src/queries/displayValue.ts @@ -33,10 +33,7 @@ const getTextInputNodeByDisplayValue = ( const queryAllByDisplayValue = ( instance: ReactTestInstance -): (( - displayValue: TextMatch, - queryOptions?: ByDisplayValueOptions -) => Array) => +): QueryAllByQuery => function queryAllByDisplayValueFn(displayValue, queryOptions) { return findAll( instance, diff --git a/src/queries/hintText.ts b/src/queries/hintText.ts index bcc55a4e8..d59d5133d 100644 --- a/src/queries/hintText.ts +++ b/src/queries/hintText.ts @@ -25,16 +25,11 @@ const getNodeByHintText = ( const queryAllByHintText = ( instance: ReactTestInstance -): (( - hint: TextMatch, - queryOptions?: ByHintTextOptions -) => Array) => +): QueryAllByQuery => function queryAllByA11yHintFn(hint, queryOptions) { return findAll( instance, - (node) => - typeof node.type === 'string' && - getNodeByHintText(node, hint, queryOptions), + (node) => getNodeByHintText(node, hint, queryOptions), queryOptions ); }; diff --git a/src/queries/labelText.ts b/src/queries/labelText.ts index 7b5fba156..9def35a9c 100644 --- a/src/queries/labelText.ts +++ b/src/queries/labelText.ts @@ -19,9 +19,7 @@ function queryAllByLabelText(instance: ReactTestInstance) { return (text: TextMatch, queryOptions?: ByLabelTextOptions) => { return findAll( instance, - (node) => - typeof node.type === 'string' && - matchLabelText(instance, node, text, queryOptions), + (node) => matchLabelText(instance, node, text, queryOptions), queryOptions ); }; diff --git a/src/queries/makeQueries.ts b/src/queries/makeQueries.ts index a698fa402..d6734f347 100644 --- a/src/queries/makeQueries.ts +++ b/src/queries/makeQueries.ts @@ -5,40 +5,41 @@ import type { WaitForOptions } from '../waitFor'; import format from '../helpers/format'; import { screen } from '../screen'; import { defaultMapProps } from '../helpers/format-default'; +import type { HostReactTestInstance } from '../helpers/component-tree'; export type GetByQuery = ( predicate: Predicate, options?: Options -) => ReactTestInstance; +) => HostReactTestInstance; export type GetAllByQuery = ( predicate: Predicate, options?: Options -) => ReactTestInstance[]; +) => HostReactTestInstance[]; export type QueryByQuery = ( predicate: Predicate, options?: Options -) => ReactTestInstance | null; +) => HostReactTestInstance | null; export type QueryAllByQuery = ( predicate: Predicate, options?: Options -) => ReactTestInstance[]; +) => HostReactTestInstance[]; export type FindByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. options?: Options & WaitForOptions, waitForOptions?: WaitForOptions -) => Promise; +) => Promise; export type FindAllByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. options?: Options & WaitForOptions, waitForOptions?: WaitForOptions -) => Promise; +) => Promise; type UnboundQuery = (instance: ReactTestInstance) => Query; diff --git a/src/queries/placeholderText.ts b/src/queries/placeholderText.ts index 613dc0e84..43dfc5bed 100644 --- a/src/queries/placeholderText.ts +++ b/src/queries/placeholderText.ts @@ -31,10 +31,7 @@ const getTextInputNodeByPlaceholderText = ( const queryAllByPlaceholderText = ( instance: ReactTestInstance -): (( - placeholder: TextMatch, - queryOptions?: ByPlaceholderTextOptions -) => Array) => +): QueryAllByQuery => function queryAllByPlaceholderFn(placeholder, queryOptions) { return findAll( instance, diff --git a/src/queries/role.ts b/src/queries/role.ts index 7baa326fe..8f45508f0 100644 --- a/src/queries/role.ts +++ b/src/queries/role.ts @@ -61,13 +61,12 @@ const matchAccessibilityValueIfNeeded = ( const queryAllByRole = ( instance: ReactTestInstance -): ((role: TextMatch, options?: ByRoleOptions) => Array) => +): QueryAllByQuery => function queryAllByRoleFn(role, options) { return findAll( instance, (node) => // run the cheapest checks first, and early exit to avoid unneeded computations - typeof node.type === 'string' && isAccessibilityElement(node) && matchStringProp(node.props.accessibilityRole, role) && matchAccessibleStateIfNeeded(node, options) && diff --git a/src/queries/testId.ts b/src/queries/testId.ts index c33122b91..8ab9b2316 100644 --- a/src/queries/testId.ts +++ b/src/queries/testId.ts @@ -25,16 +25,11 @@ const getNodeByTestId = ( const queryAllByTestId = ( instance: ReactTestInstance -): (( - testId: TextMatch, - queryOptions?: ByTestIdOptions -) => Array) => +): QueryAllByQuery => function queryAllByTestIdFn(testId, queryOptions) { return findAll( instance, - (node) => - typeof node.type === 'string' && - getNodeByTestId(node, testId, queryOptions), + (node) => getNodeByTestId(node, testId, queryOptions), queryOptions ); }; diff --git a/src/queries/text.ts b/src/queries/text.ts index 425f0153c..cf563ea33 100644 --- a/src/queries/text.ts +++ b/src/queries/text.ts @@ -19,7 +19,7 @@ type ByTextOptions = CommonQueryOptions & TextMatchOptions; const queryAllByText = ( instance: ReactTestInstance -): ((text: TextMatch, options?: ByTextOptions) => Array) => +): QueryAllByQuery => function queryAllByTextFn(text, options = {}) { return findAll( instance, From f658e44e3f2034a6195b2626d24586e1c81d2db5 Mon Sep 17 00:00:00 2001 From: pierrezimmermann Date: Sun, 16 Jul 2023 10:51:05 +0200 Subject: [PATCH 2/9] refactor: use brackets syntax for array types over Array --- src/helpers/findAll.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index 49613b96f..a7688384e 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -19,7 +19,7 @@ export function findAll( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -): Array { +): HostReactTestInstance[] { const results = findAllInternal(root, predicate, options); const includeHiddenElements = @@ -43,7 +43,7 @@ function findAllInternal( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -): Array { +): HostReactTestInstance[] { const results: HostReactTestInstance[] = []; // Match descendants first but do not add them to results yet. From d8fd603ca191578906dcb2fb76689eb91eb8d1a9 Mon Sep 17 00:00:00 2001 From: pierrezimmermann Date: Sun, 16 Jul 2023 10:52:24 +0200 Subject: [PATCH 3/9] refactor: change order of checks in findAll for perf --- src/helpers/findAll.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index a7688384e..1b95f9edc 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -56,10 +56,10 @@ function findAllInternal( }); if ( - isHostElement(root) && - predicate(root) && // When matchDeepestOnly = true: add current element only if no descendants match - (!options?.matchDeepestOnly || matchingDescendants.length === 0) + (!options?.matchDeepestOnly || matchingDescendants.length === 0) && + isHostElement(root) && + predicate(root) ) { results.push(root); } From 460a7afb188796ff1ed9d21e704ebb96e68dadd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 28 Jul 2023 14:50:14 +0200 Subject: [PATCH 4/9] refactor: hide host instance from public API --- src/helpers/component-tree.ts | 17 +++++++++-------- src/helpers/findAll.ts | 3 +-- src/queries/makeQueries.ts | 13 ++++++------- src/render.tsx | 2 +- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index 4c5ec63eb..cdfe46816 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -1,5 +1,8 @@ import { ReactTestInstance } from 'react-test-renderer'; +/** + * ReactTestInstance referring to host element. + */ export type HostReactTestInstance = ReactTestInstance & { type: string }; /** @@ -18,7 +21,7 @@ export function isHostElement( */ export function getHostParent( element: ReactTestInstance | null -): ReactTestInstance | null { +): HostReactTestInstance | null { if (element == null) { return null; } @@ -41,12 +44,12 @@ export function getHostParent( */ export function getHostChildren( element: ReactTestInstance | null -): ReactTestInstance[] { +): HostReactTestInstance[] { if (element == null) { return []; } - const hostChildren: ReactTestInstance[] = []; + const hostChildren: HostReactTestInstance[] = []; element.children.forEach((child) => { if (typeof child !== 'object') { @@ -72,10 +75,8 @@ export function getHostChildren( */ export function getHostSelves( element: ReactTestInstance | null -): ReactTestInstance[] { - return typeof element?.type === 'string' - ? [element] - : getHostChildren(element); +): HostReactTestInstance[] { + return isHostElement(element) ? [element] : getHostChildren(element); } /** @@ -84,7 +85,7 @@ export function getHostSelves( */ export function getHostSiblings( element: ReactTestInstance | null -): ReactTestInstance[] { +): HostReactTestInstance[] { const hostParent = getHostParent(element); const hostSelves = getHostSelves(element); return getHostChildren(hostParent).filter( diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index 1b95f9edc..02c7a7c52 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -1,8 +1,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { getConfig } from '../config'; import { isHiddenFromAccessibility } from './accessiblity'; -import { isHostElement } from './component-tree'; -import type { HostReactTestInstance } from './component-tree'; +import { HostReactTestInstance, isHostElement } from './component-tree'; interface FindAllOptions { /** Match elements hidden from accessibility */ diff --git a/src/queries/makeQueries.ts b/src/queries/makeQueries.ts index d6734f347..a698fa402 100644 --- a/src/queries/makeQueries.ts +++ b/src/queries/makeQueries.ts @@ -5,41 +5,40 @@ import type { WaitForOptions } from '../waitFor'; import format from '../helpers/format'; import { screen } from '../screen'; import { defaultMapProps } from '../helpers/format-default'; -import type { HostReactTestInstance } from '../helpers/component-tree'; export type GetByQuery = ( predicate: Predicate, options?: Options -) => HostReactTestInstance; +) => ReactTestInstance; export type GetAllByQuery = ( predicate: Predicate, options?: Options -) => HostReactTestInstance[]; +) => ReactTestInstance[]; export type QueryByQuery = ( predicate: Predicate, options?: Options -) => HostReactTestInstance | null; +) => ReactTestInstance | null; export type QueryAllByQuery = ( predicate: Predicate, options?: Options -) => HostReactTestInstance[]; +) => ReactTestInstance[]; export type FindByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. options?: Options & WaitForOptions, waitForOptions?: WaitForOptions -) => Promise; +) => Promise; export type FindAllByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. options?: Options & WaitForOptions, waitForOptions?: WaitForOptions -) => Promise; +) => Promise; type UnboundQuery = (instance: ReactTestInstance) => Query; diff --git a/src/render.tsx b/src/render.tsx index 05c6e0671..abe150f06 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -117,7 +117,7 @@ function buildRenderResult( rerender: update, // alias for `update` toJSON: renderer.toJSON, debug: debug(instance, renderer), - get root() { + get root(): ReactTestInstance { return getHostChildren(instance)[0]; }, UNSAFE_root: instance, From 003ed6b1beef7b79ef59e447b000f36fb2c3da4c Mon Sep 17 00:00:00 2001 From: pierrezimmermann Date: Fri, 4 Aug 2023 16:37:01 +0200 Subject: [PATCH 5/9] refactor: make sure all queries return host elements --- src/queries/a11yState.ts | 4 ++-- src/queries/a11yValue.ts | 4 ++-- src/queries/displayValue.ts | 4 ++-- src/queries/hintText.ts | 4 ++-- src/queries/makeQueries.ts | 8 +++++++- src/queries/placeholderText.ts | 4 ++-- src/queries/role.ts | 4 ++-- src/queries/testId.ts | 4 ++-- src/queries/text.ts | 4 ++-- 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/queries/a11yState.ts b/src/queries/a11yState.ts index 80a759035..e27efe395 100644 --- a/src/queries/a11yState.ts +++ b/src/queries/a11yState.ts @@ -6,7 +6,7 @@ import { AccessibilityStateMatcher, matchAccessibilityState, } from '../helpers/matchers/accessibilityState'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yState = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByA11yStateFn(matcher, queryOptions) { return findAll( instance, diff --git a/src/queries/a11yValue.ts b/src/queries/a11yValue.ts index 753778548..5ebf408d9 100644 --- a/src/queries/a11yValue.ts +++ b/src/queries/a11yValue.ts @@ -6,7 +6,7 @@ import { AccessibilityValueMatcher, matchAccessibilityValue, } from '../helpers/matchers/accessibilityValue'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yValue = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByA11yValueFn(value, queryOptions) { return findAll( instance, diff --git a/src/queries/displayValue.ts b/src/queries/displayValue.ts index 44db16f93..dfec089d0 100644 --- a/src/queries/displayValue.ts +++ b/src/queries/displayValue.ts @@ -3,7 +3,7 @@ import { filterNodeByType } from '../helpers/filterNodeByType'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; import { getHostComponentNames } from '../helpers/host-component-names'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -33,7 +33,7 @@ const getTextInputNodeByDisplayValue = ( const queryAllByDisplayValue = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByDisplayValueFn(displayValue, queryOptions) { return findAll( instance, diff --git a/src/queries/hintText.ts b/src/queries/hintText.ts index d59d5133d..6de38afc6 100644 --- a/src/queries/hintText.ts +++ b/src/queries/hintText.ts @@ -1,7 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -25,7 +25,7 @@ const getNodeByHintText = ( const queryAllByHintText = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByA11yHintFn(hint, queryOptions) { return findAll( instance, diff --git a/src/queries/makeQueries.ts b/src/queries/makeQueries.ts index a698fa402..9facfcbab 100644 --- a/src/queries/makeQueries.ts +++ b/src/queries/makeQueries.ts @@ -5,6 +5,7 @@ import type { WaitForOptions } from '../waitFor'; import format from '../helpers/format'; import { screen } from '../screen'; import { defaultMapProps } from '../helpers/format-default'; +import { HostReactTestInstance } from '../helpers/component-tree'; export type GetByQuery = ( predicate: Predicate, @@ -26,6 +27,11 @@ export type QueryAllByQuery = ( options?: Options ) => ReactTestInstance[]; +export type InternalQueryAllByQuery = ( + predicate: Predicate, + options?: Options +) => HostReactTestInstance[]; + export type FindByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. @@ -112,7 +118,7 @@ function appendElementTreeToError(error: Error) { } export function makeQueries( - queryAllByQuery: UnboundQuery>, + queryAllByQuery: UnboundQuery>, getMissingError: (predicate: Predicate, options?: Options) => string, getMultipleError: (predicate: Predicate, options?: Options) => string ): UnboundQueries { diff --git a/src/queries/placeholderText.ts b/src/queries/placeholderText.ts index 43dfc5bed..cf94fdf6b 100644 --- a/src/queries/placeholderText.ts +++ b/src/queries/placeholderText.ts @@ -3,7 +3,7 @@ import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; import { filterNodeByType } from '../helpers/filterNodeByType'; import { getHostComponentNames } from '../helpers/host-component-names'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -31,7 +31,7 @@ const getTextInputNodeByPlaceholderText = ( const queryAllByPlaceholderText = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByPlaceholderFn(placeholder, queryOptions) { return findAll( instance, diff --git a/src/queries/role.ts b/src/queries/role.ts index 8f45508f0..f07c7ea88 100644 --- a/src/queries/role.ts +++ b/src/queries/role.ts @@ -16,7 +16,7 @@ import { import { matchStringProp } from '../helpers/matchers/matchStringProp'; import type { TextMatch } from '../matches'; import { getQueriesForElement } from '../within'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -61,7 +61,7 @@ const matchAccessibilityValueIfNeeded = ( const queryAllByRole = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByRoleFn(role, options) { return findAll( instance, diff --git a/src/queries/testId.ts b/src/queries/testId.ts index 8ab9b2316..ef971d42b 100644 --- a/src/queries/testId.ts +++ b/src/queries/testId.ts @@ -1,7 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -25,7 +25,7 @@ const getNodeByTestId = ( const queryAllByTestId = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByTestIdFn(testId, queryOptions) { return findAll( instance, diff --git a/src/queries/text.ts b/src/queries/text.ts index cf563ea33..6158009b9 100644 --- a/src/queries/text.ts +++ b/src/queries/text.ts @@ -4,7 +4,7 @@ import { findAll } from '../helpers/findAll'; import { getHostComponentNames } from '../helpers/host-component-names'; import { matchTextContent } from '../helpers/matchers/matchTextContent'; import { TextMatch, TextMatchOptions } from '../matches'; -import { makeQueries } from './makeQueries'; +import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ type ByTextOptions = CommonQueryOptions & TextMatchOptions; const queryAllByText = ( instance: ReactTestInstance -): QueryAllByQuery => +): InternalQueryAllByQuery => function queryAllByTextFn(text, options = {}) { return findAll( instance, From 6b5fcf63fd282e665e7dec99b34ff93d0347d195 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 11 Aug 2023 15:46:01 +0200 Subject: [PATCH 6/9] Revert "refactor: make sure all queries return host elements" This reverts commit 979f92a83e43b04a30c979445633896ec3496769. --- src/queries/a11yState.ts | 4 ++-- src/queries/a11yValue.ts | 4 ++-- src/queries/displayValue.ts | 4 ++-- src/queries/hintText.ts | 4 ++-- src/queries/makeQueries.ts | 8 +------- src/queries/placeholderText.ts | 4 ++-- src/queries/role.ts | 4 ++-- src/queries/testId.ts | 4 ++-- src/queries/text.ts | 4 ++-- 9 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/queries/a11yState.ts b/src/queries/a11yState.ts index e27efe395..80a759035 100644 --- a/src/queries/a11yState.ts +++ b/src/queries/a11yState.ts @@ -6,7 +6,7 @@ import { AccessibilityStateMatcher, matchAccessibilityState, } from '../helpers/matchers/accessibilityState'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yState = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByA11yStateFn(matcher, queryOptions) { return findAll( instance, diff --git a/src/queries/a11yValue.ts b/src/queries/a11yValue.ts index 5ebf408d9..753778548 100644 --- a/src/queries/a11yValue.ts +++ b/src/queries/a11yValue.ts @@ -6,7 +6,7 @@ import { AccessibilityValueMatcher, matchAccessibilityValue, } from '../helpers/matchers/accessibilityValue'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ import { CommonQueryOptions } from './options'; const queryAllByA11yValue = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByA11yValueFn(value, queryOptions) { return findAll( instance, diff --git a/src/queries/displayValue.ts b/src/queries/displayValue.ts index dfec089d0..44db16f93 100644 --- a/src/queries/displayValue.ts +++ b/src/queries/displayValue.ts @@ -3,7 +3,7 @@ import { filterNodeByType } from '../helpers/filterNodeByType'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; import { getHostComponentNames } from '../helpers/host-component-names'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -33,7 +33,7 @@ const getTextInputNodeByDisplayValue = ( const queryAllByDisplayValue = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByDisplayValueFn(displayValue, queryOptions) { return findAll( instance, diff --git a/src/queries/hintText.ts b/src/queries/hintText.ts index 6de38afc6..d59d5133d 100644 --- a/src/queries/hintText.ts +++ b/src/queries/hintText.ts @@ -1,7 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -25,7 +25,7 @@ const getNodeByHintText = ( const queryAllByHintText = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByA11yHintFn(hint, queryOptions) { return findAll( instance, diff --git a/src/queries/makeQueries.ts b/src/queries/makeQueries.ts index 9facfcbab..a698fa402 100644 --- a/src/queries/makeQueries.ts +++ b/src/queries/makeQueries.ts @@ -5,7 +5,6 @@ import type { WaitForOptions } from '../waitFor'; import format from '../helpers/format'; import { screen } from '../screen'; import { defaultMapProps } from '../helpers/format-default'; -import { HostReactTestInstance } from '../helpers/component-tree'; export type GetByQuery = ( predicate: Predicate, @@ -27,11 +26,6 @@ export type QueryAllByQuery = ( options?: Options ) => ReactTestInstance[]; -export type InternalQueryAllByQuery = ( - predicate: Predicate, - options?: Options -) => HostReactTestInstance[]; - export type FindByQuery = ( predicate: Predicate, // Remove `& WaitForOptions` when all queries have been migrated to support 2nd arg query options. @@ -118,7 +112,7 @@ function appendElementTreeToError(error: Error) { } export function makeQueries( - queryAllByQuery: UnboundQuery>, + queryAllByQuery: UnboundQuery>, getMissingError: (predicate: Predicate, options?: Options) => string, getMultipleError: (predicate: Predicate, options?: Options) => string ): UnboundQueries { diff --git a/src/queries/placeholderText.ts b/src/queries/placeholderText.ts index cf94fdf6b..43dfc5bed 100644 --- a/src/queries/placeholderText.ts +++ b/src/queries/placeholderText.ts @@ -3,7 +3,7 @@ import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; import { filterNodeByType } from '../helpers/filterNodeByType'; import { getHostComponentNames } from '../helpers/host-component-names'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -31,7 +31,7 @@ const getTextInputNodeByPlaceholderText = ( const queryAllByPlaceholderText = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByPlaceholderFn(placeholder, queryOptions) { return findAll( instance, diff --git a/src/queries/role.ts b/src/queries/role.ts index f07c7ea88..8f45508f0 100644 --- a/src/queries/role.ts +++ b/src/queries/role.ts @@ -16,7 +16,7 @@ import { import { matchStringProp } from '../helpers/matchers/matchStringProp'; import type { TextMatch } from '../matches'; import { getQueriesForElement } from '../within'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -61,7 +61,7 @@ const matchAccessibilityValueIfNeeded = ( const queryAllByRole = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByRoleFn(role, options) { return findAll( instance, diff --git a/src/queries/testId.ts b/src/queries/testId.ts index ef971d42b..8ab9b2316 100644 --- a/src/queries/testId.ts +++ b/src/queries/testId.ts @@ -1,7 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -25,7 +25,7 @@ const getNodeByTestId = ( const queryAllByTestId = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByTestIdFn(testId, queryOptions) { return findAll( instance, diff --git a/src/queries/text.ts b/src/queries/text.ts index 6158009b9..cf563ea33 100644 --- a/src/queries/text.ts +++ b/src/queries/text.ts @@ -4,7 +4,7 @@ import { findAll } from '../helpers/findAll'; import { getHostComponentNames } from '../helpers/host-component-names'; import { matchTextContent } from '../helpers/matchers/matchTextContent'; import { TextMatch, TextMatchOptions } from '../matches'; -import { InternalQueryAllByQuery, makeQueries } from './makeQueries'; +import { makeQueries } from './makeQueries'; import type { FindAllByQuery, FindByQuery, @@ -19,7 +19,7 @@ type ByTextOptions = CommonQueryOptions & TextMatchOptions; const queryAllByText = ( instance: ReactTestInstance -): InternalQueryAllByQuery => +): QueryAllByQuery => function queryAllByTextFn(text, options = {}) { return findAll( instance, From 18f8997e9e9bb200de17e70661417c17add7e1f5 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 11 Aug 2023 15:59:12 +0200 Subject: [PATCH 7/9] chore: rename to HostTestInstance --- src/helpers/component-tree.ts | 14 +++++++------- src/helpers/findAll.ts | 10 +++++----- src/queries/testId.ts | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index cdfe46816..46993e956 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -3,7 +3,7 @@ import { ReactTestInstance } from 'react-test-renderer'; /** * ReactTestInstance referring to host element. */ -export type HostReactTestInstance = ReactTestInstance & { type: string }; +export type HostTestInstance = ReactTestInstance & { type: string }; /** * Checks if the given element is a host element. @@ -11,7 +11,7 @@ export type HostReactTestInstance = ReactTestInstance & { type: string }; */ export function isHostElement( element?: ReactTestInstance | null -): element is HostReactTestInstance { +): element is HostTestInstance { return typeof element?.type === 'string'; } @@ -21,7 +21,7 @@ export function isHostElement( */ export function getHostParent( element: ReactTestInstance | null -): HostReactTestInstance | null { +): HostTestInstance | null { if (element == null) { return null; } @@ -44,12 +44,12 @@ export function getHostParent( */ export function getHostChildren( element: ReactTestInstance | null -): HostReactTestInstance[] { +): HostTestInstance[] { if (element == null) { return []; } - const hostChildren: HostReactTestInstance[] = []; + const hostChildren: HostTestInstance[] = []; element.children.forEach((child) => { if (typeof child !== 'object') { @@ -75,7 +75,7 @@ export function getHostChildren( */ export function getHostSelves( element: ReactTestInstance | null -): HostReactTestInstance[] { +): HostTestInstance[] { return isHostElement(element) ? [element] : getHostChildren(element); } @@ -85,7 +85,7 @@ export function getHostSelves( */ export function getHostSiblings( element: ReactTestInstance | null -): HostReactTestInstance[] { +): HostTestInstance[] { const hostParent = getHostParent(element); const hostSelves = getHostSelves(element); return getHostChildren(hostParent).filter( diff --git a/src/helpers/findAll.ts b/src/helpers/findAll.ts index 02c7a7c52..20c7c08a1 100644 --- a/src/helpers/findAll.ts +++ b/src/helpers/findAll.ts @@ -1,7 +1,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { getConfig } from '../config'; import { isHiddenFromAccessibility } from './accessiblity'; -import { HostReactTestInstance, isHostElement } from './component-tree'; +import { HostTestInstance, isHostElement } from './component-tree'; interface FindAllOptions { /** Match elements hidden from accessibility */ @@ -18,7 +18,7 @@ export function findAll( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -): HostReactTestInstance[] { +): HostTestInstance[] { const results = findAllInternal(root, predicate, options); const includeHiddenElements = @@ -42,11 +42,11 @@ function findAllInternal( root: ReactTestInstance, predicate: (element: ReactTestInstance) => boolean, options?: FindAllOptions -): HostReactTestInstance[] { - const results: HostReactTestInstance[] = []; +): HostTestInstance[] { + const results: HostTestInstance[] = []; // Match descendants first but do not add them to results yet. - const matchingDescendants: HostReactTestInstance[] = []; + const matchingDescendants: HostTestInstance[] = []; root.children.forEach((child) => { if (typeof child === 'string') { return; diff --git a/src/queries/testId.ts b/src/queries/testId.ts index 8ab9b2316..d5a0af7fc 100644 --- a/src/queries/testId.ts +++ b/src/queries/testId.ts @@ -14,13 +14,13 @@ import type { CommonQueryOptions } from './options'; type ByTestIdOptions = CommonQueryOptions & TextMatchOptions; -const getNodeByTestId = ( +const matchTestId = ( node: ReactTestInstance, - testID: TextMatch, + testId: TextMatch, options: TextMatchOptions = {} ) => { const { exact, normalizer } = options; - return matches(testID, node.props.testID, normalizer, exact); + return matches(testId, node.props.testID, normalizer, exact); }; const queryAllByTestId = ( @@ -29,7 +29,7 @@ const queryAllByTestId = ( function queryAllByTestIdFn(testId, queryOptions) { return findAll( instance, - (node) => getNodeByTestId(node, testId, queryOptions), + (node) => matchTestId(node, testId, queryOptions), queryOptions ); }; From a8bd44496dd7ac62a714b68627e4ae809e6660dd Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 11 Aug 2023 16:36:54 +0200 Subject: [PATCH 8/9] refactor: remove flierNodeByType --- src/fireEvent.ts | 2 +- src/helpers/filterNodeByType.ts | 7 ------- src/helpers/host-component-names.tsx | 27 +++++++++++++++++++++++++-- src/queries/displayValue.ts | 16 ++++++---------- src/queries/placeholderText.ts | 14 +++++--------- src/queries/text.ts | 7 ++----- 6 files changed, 39 insertions(+), 34 deletions(-) delete mode 100644 src/helpers/filterNodeByType.ts diff --git a/src/fireEvent.ts b/src/fireEvent.ts index bdc6a5276..68746e300 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -7,9 +7,9 @@ import { ScrollViewProps, } from 'react-native'; import act from './act'; -import { isPointerEventEnabled } from './helpers/pointer-events'; import { isHostElement } from './helpers/component-tree'; import { isHostTextInput } from './helpers/host-component-names'; +import { isPointerEventEnabled } from './helpers/pointer-events'; type EventHandler = (...args: unknown[]) => unknown; diff --git a/src/helpers/filterNodeByType.ts b/src/helpers/filterNodeByType.ts deleted file mode 100644 index 1330d41c5..000000000 --- a/src/helpers/filterNodeByType.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ReactTestInstance } from 'react-test-renderer'; -import * as React from 'react'; - -export const filterNodeByType = ( - node: ReactTestInstance | React.ReactElement, - type: React.ElementType | string -) => node.type === type; diff --git a/src/helpers/host-component-names.tsx b/src/helpers/host-component-names.tsx index 3fd339b0d..eb1c57223 100644 --- a/src/helpers/host-component-names.tsx +++ b/src/helpers/host-component-names.tsx @@ -3,6 +3,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { Switch, Text, TextInput, View } from 'react-native'; import { configureInternal, getConfig, HostComponentNames } from '../config'; import { renderWithAct } from '../render-act'; +import { HostTestInstance } from './component-tree'; const userConfigErrorMessage = `There seems to be an issue with your configuration that prevents React Native Testing Library from working correctly. Please check if you are using compatible versions of React Native and React Native Testing Library.`; @@ -66,10 +67,32 @@ function getByTestId(instance: ReactTestInstance, testID: string) { return nodes[0]; } -export function isHostText(element?: ReactTestInstance) { +/** + * Checks if the given element is a host Text. + * @param element The element to check. + */ +export function isHostText( + element?: ReactTestInstance | null +): element is HostTestInstance { return element?.type === getHostComponentNames().text; } -export function isHostTextInput(element?: ReactTestInstance) { +/** + * Checks if the given element is a host TextInput. + * @param element The element to check. + */ +export function isHostTextInput( + element?: ReactTestInstance | null +): element is HostTestInstance { return element?.type === getHostComponentNames().textInput; } + +/** + * Checks if the given element is a host Switch. + * @param element The element to check. + */ +export function isHostSwitch( + element?: ReactTestInstance | null +): element is HostTestInstance { + return element?.type === getHostComponentNames().switch; +} diff --git a/src/queries/displayValue.ts b/src/queries/displayValue.ts index 44db16f93..d521dbf36 100644 --- a/src/queries/displayValue.ts +++ b/src/queries/displayValue.ts @@ -1,8 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; -import { filterNodeByType } from '../helpers/filterNodeByType'; import { findAll } from '../helpers/findAll'; +import { isHostTextInput } from '../helpers/host-component-names'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { getHostComponentNames } from '../helpers/host-component-names'; import { makeQueries } from './makeQueries'; import type { FindAllByQuery, @@ -16,19 +15,15 @@ import type { CommonQueryOptions } from './options'; type ByDisplayValueOptions = CommonQueryOptions & TextMatchOptions; -const getTextInputNodeByDisplayValue = ( +const matchDisplayValue = ( node: ReactTestInstance, value: TextMatch, options: TextMatchOptions = {} ) => { const { exact, normalizer } = options; - const nodeValue = - node.props.value !== undefined ? node.props.value : node.props.defaultValue; + const nodeValue = node.props.value ?? node.props.defaultValue; - return ( - filterNodeByType(node, getHostComponentNames().textInput) && - matches(value, nodeValue, normalizer, exact) - ); + return matches(value, nodeValue, normalizer, exact); }; const queryAllByDisplayValue = ( @@ -38,7 +33,8 @@ const queryAllByDisplayValue = ( return findAll( instance, (node) => - getTextInputNodeByDisplayValue(node, displayValue, queryOptions), + isHostTextInput(node) && + matchDisplayValue(node, displayValue, queryOptions), queryOptions ); }; diff --git a/src/queries/placeholderText.ts b/src/queries/placeholderText.ts index 43dfc5bed..5967f5ccd 100644 --- a/src/queries/placeholderText.ts +++ b/src/queries/placeholderText.ts @@ -1,8 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/findAll'; import { matches, TextMatch, TextMatchOptions } from '../matches'; -import { filterNodeByType } from '../helpers/filterNodeByType'; -import { getHostComponentNames } from '../helpers/host-component-names'; +import { isHostTextInput } from '../helpers/host-component-names'; import { makeQueries } from './makeQueries'; import type { FindAllByQuery, @@ -16,17 +15,13 @@ import type { CommonQueryOptions } from './options'; type ByPlaceholderTextOptions = CommonQueryOptions & TextMatchOptions; -const getTextInputNodeByPlaceholderText = ( +const matchPlaceholderText = ( node: ReactTestInstance, placeholder: TextMatch, options: TextMatchOptions = {} ) => { const { exact, normalizer } = options; - - return ( - filterNodeByType(node, getHostComponentNames().textInput) && - matches(placeholder, node.props.placeholder, normalizer, exact) - ); + return matches(placeholder, node.props.placeholder, normalizer, exact); }; const queryAllByPlaceholderText = ( @@ -36,7 +31,8 @@ const queryAllByPlaceholderText = ( return findAll( instance, (node) => - getTextInputNodeByPlaceholderText(node, placeholder, queryOptions), + isHostTextInput(node) && + matchPlaceholderText(node, placeholder, queryOptions), queryOptions ); }; diff --git a/src/queries/text.ts b/src/queries/text.ts index cf563ea33..0cb9ede3a 100644 --- a/src/queries/text.ts +++ b/src/queries/text.ts @@ -1,7 +1,6 @@ import type { ReactTestInstance } from 'react-test-renderer'; -import { filterNodeByType } from '../helpers/filterNodeByType'; import { findAll } from '../helpers/findAll'; -import { getHostComponentNames } from '../helpers/host-component-names'; +import { isHostText } from '../helpers/host-component-names'; import { matchTextContent } from '../helpers/matchers/matchTextContent'; import { TextMatch, TextMatchOptions } from '../matches'; import { makeQueries } from './makeQueries'; @@ -23,9 +22,7 @@ const queryAllByText = ( function queryAllByTextFn(text, options = {}) { return findAll( instance, - (node) => - filterNodeByType(node, getHostComponentNames().text) && - matchTextContent(node, text, options), + (node) => isHostText(node) && matchTextContent(node, text, options), { ...options, matchDeepestOnly: true, From 99ee1904a0f80b79f93657b20b9d3021510fd5ce Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 11 Aug 2023 16:47:25 +0200 Subject: [PATCH 9/9] chore: fix codecov --- src/helpers/host-component-names.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/helpers/host-component-names.tsx b/src/helpers/host-component-names.tsx index eb1c57223..d378424c3 100644 --- a/src/helpers/host-component-names.tsx +++ b/src/helpers/host-component-names.tsx @@ -86,13 +86,3 @@ export function isHostTextInput( ): element is HostTestInstance { return element?.type === getHostComponentNames().textInput; } - -/** - * Checks if the given element is a host Switch. - * @param element The element to check. - */ -export function isHostSwitch( - element?: ReactTestInstance | null -): element is HostTestInstance { - return element?.type === getHostComponentNames().switch; -}