From abf891b86e395acd23fe27bd0783f0bab2a896b2 Mon Sep 17 00:00:00 2001 From: Krastan Dimitrov Date: Thu, 6 Jul 2023 14:50:58 -0500 Subject: [PATCH 1/7] Add prop to render to skip componentnamesconfig --- src/render.tsx | 6 +++++- src/renderHook.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/render.tsx b/src/render.tsx index de8a41600..b7621dd22 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -17,6 +17,7 @@ export type RenderOptions = { wrapper?: React.ComponentType; createNodeMock?: (element: React.ReactElement) => any; unstable_validateStringsRenderedWithinText?: boolean; + skipHostComponentNamesConfiguration?: boolean; }; export type RenderResult = ReturnType; @@ -31,9 +32,12 @@ export default function render( wrapper: Wrapper, createNodeMock, unstable_validateStringsRenderedWithinText, + skipHostComponentNamesConfiguration = false, }: RenderOptions = {} ) { - configureHostComponentNamesIfNeeded(); + if (skipHostComponentNamesConfiguration === false) { + configureHostComponentNamesIfNeeded(); + } if (unstable_validateStringsRenderedWithinText) { return renderWithStringValidation(component, { diff --git a/src/renderHook.tsx b/src/renderHook.tsx index ada485dc4..dc85d1109 100644 --- a/src/renderHook.tsx +++ b/src/renderHook.tsx @@ -39,7 +39,7 @@ export function renderHook( const { rerender: baseRerender, unmount } = render( // @ts-expect-error since option can be undefined, initialProps can be undefined when it should'nt , - { wrapper } + { wrapper, skipHostComponentNamesConfiguration: true } ); function rerender(rerenderCallbackProps: Props) { From dcc1295cea2f8ea03aa50e11529e69546123ead7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:18:37 +0200 Subject: [PATCH 2/7] refactor: render internal with extra options --- src/render.tsx | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/render.tsx b/src/render.tsx index b7621dd22..c87575db6 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -13,12 +13,11 @@ import { renderWithAct } from './render-act'; import { setRenderResult, screen } from './screen'; import { getQueriesForElement } from './within'; -export type RenderOptions = { +export interface RenderOptions { wrapper?: React.ComponentType; createNodeMock?: (element: React.ReactElement) => any; unstable_validateStringsRenderedWithinText?: boolean; - skipHostComponentNamesConfiguration?: boolean; -}; +} export type RenderResult = ReturnType; @@ -27,15 +26,29 @@ export type RenderResult = ReturnType; * to assert on the output. */ export default function render( + component: React.ReactElement, + options: RenderOptions = {} +) { + return renderInternal(component, { + ...options, + detectHostComponentNames: true, + }); +} + +export interface RenderInternalOptions extends RenderOptions { + detectHostComponentNames?: boolean; +} + +export function renderInternal( component: React.ReactElement, { wrapper: Wrapper, createNodeMock, unstable_validateStringsRenderedWithinText, - skipHostComponentNamesConfiguration = false, - }: RenderOptions = {} + detectHostComponentNames = false, + }: RenderInternalOptions = {} ) { - if (skipHostComponentNamesConfiguration === false) { + if (detectHostComponentNames) { configureHostComponentNamesIfNeeded(); } From fd459567d150b15c0fe9568fd5e3e9decec67c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:21:32 +0200 Subject: [PATCH 3/7] refactor: apply renderInternal to renderHook --- src/renderHook.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/renderHook.tsx b/src/renderHook.tsx index dc85d1109..f50973e25 100644 --- a/src/renderHook.tsx +++ b/src/renderHook.tsx @@ -1,6 +1,6 @@ import React from 'react'; import type { ComponentType } from 'react'; -import render from './render'; +import { renderInternal } from './render'; export type RenderHookResult = { rerender: (props: Props) => void; @@ -36,10 +36,13 @@ export function renderHook( return null; } - const { rerender: baseRerender, unmount } = render( + const { rerender: baseRerender, unmount } = renderInternal( // @ts-expect-error since option can be undefined, initialProps can be undefined when it should'nt , - { wrapper, skipHostComponentNamesConfiguration: true } + { + wrapper, + detectHostComponentNames: false, + } ); function rerender(rerenderCallbackProps: Props) { From c3d1ce0bf32f093d5c224026ca1835d7c1e7afee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:29:44 +0200 Subject: [PATCH 4/7] chore: add tests to check for single render --- src/__tests__/renderHook.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/__tests__/renderHook.test.tsx b/src/__tests__/renderHook.test.tsx index 6e9f231a5..51c4e2696 100644 --- a/src/__tests__/renderHook.test.tsx +++ b/src/__tests__/renderHook.test.tsx @@ -1,4 +1,5 @@ import React, { ReactNode } from 'react'; +import TestRenderer from 'react-test-renderer'; import { renderHook } from '../pure'; test('gives comitted result', () => { @@ -94,3 +95,20 @@ test('props type is inferred correctly when initial props is explicitly undefine expect(result.current).toBe(6); }); + +/** + * This test makes sure that calling renderHook does + * not try to detect host component names in any form. + * But since there are numerous methods that could trigger that + * we check the count of renders using React Test Renderers. + */ +test('does render only once', () => { + jest.spyOn(TestRenderer, 'create'); + + renderHook(() => { + const [state, setState] = React.useState(1); + return [state, setState]; + }); + + expect(TestRenderer.create).toHaveBeenCalledTimes(1); +}); From 5b972aca044d2e636dd5fcc214cbb788f1bbc32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:33:28 +0200 Subject: [PATCH 5/7] refactor: simplify code --- src/render.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/render.tsx b/src/render.tsx index c87575db6..05c6e0671 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -22,17 +22,14 @@ export interface RenderOptions { export type RenderResult = ReturnType; /** - * Renders test component deeply using react-test-renderer and exposes helpers + * Renders test component deeply using React Test Renderer and exposes helpers * to assert on the output. */ export default function render( component: React.ReactElement, options: RenderOptions = {} ) { - return renderInternal(component, { - ...options, - detectHostComponentNames: true, - }); + return renderInternal(component, options); } export interface RenderInternalOptions extends RenderOptions { @@ -45,7 +42,7 @@ export function renderInternal( wrapper: Wrapper, createNodeMock, unstable_validateStringsRenderedWithinText, - detectHostComponentNames = false, + detectHostComponentNames = true, }: RenderInternalOptions = {} ) { if (detectHostComponentNames) { From 52aeea89bb7bf13e89c5bd6d727e9e5d6ae1a8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:52:09 +0200 Subject: [PATCH 6/7] refactor: finishing touches --- src/__tests__/render.test.tsx | 11 ++++++++++- src/helpers/accessiblity.ts | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/__tests__/render.test.tsx b/src/__tests__/render.test.tsx index 61010e565..1546b42b9 100644 --- a/src/__tests__/render.test.tsx +++ b/src/__tests__/render.test.tsx @@ -1,6 +1,7 @@ /* eslint-disable no-console */ import * as React from 'react'; import { View, Text, TextInput, Pressable } from 'react-native'; +import { getConfig, resetToDefaults } from '../config'; import { render, screen, fireEvent, RenderAPI } from '..'; const PLACEHOLDER_FRESHNESS = 'Add custom freshness'; @@ -242,6 +243,14 @@ test('RenderAPI type', () => { test('returned output can be spread using rest operator', () => { // Next line should not throw // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { rerender, ...rest } = render(); + const { rerender, ...rest } = render(); expect(rest).toBeTruthy(); }); + +test('render calls detects host component names', () => { + resetToDefaults(); + expect(getConfig().hostComponentNames).toBeUndefined(); + + render(); + expect(getConfig().hostComponentNames).not.toBeUndefined(); +}); diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index 6fa73f49f..e1687c295 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -6,6 +6,7 @@ import { import { ReactTestInstance } from 'react-test-renderer'; import { getConfig } from '../config'; import { getHostSiblings } from './component-tree'; +import { getHostComponentNames } from './host-component-names'; type IsInaccessibleOptions = { cache?: WeakMap; @@ -99,8 +100,7 @@ export function isAccessibilityElement( return element.props.accessible; } - const hostComponentNames = getConfig().hostComponentNames; - + const hostComponentNames = getHostComponentNames(); return ( element?.type === hostComponentNames?.text || element?.type === hostComponentNames?.textInput || From e85d68592bd91142a9e333ada76ce4db67621c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 21 Jul 2023 12:55:45 +0200 Subject: [PATCH 7/7] chore: fix lint --- src/helpers/accessiblity.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index e1687c295..99a4af60e 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -4,7 +4,6 @@ import { StyleSheet, } from 'react-native'; import { ReactTestInstance } from 'react-test-renderer'; -import { getConfig } from '../config'; import { getHostSiblings } from './component-tree'; import { getHostComponentNames } from './host-component-names';