From b2a29b171a2a4ea1d398b60b83ab47952aa86dc7 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 28 Mar 2024 18:14:36 +0100 Subject: [PATCH] fix: find by timeout with detached screen (#1576) * fix: improve error findBy* error message when screen is not beign attached. * fix: detect detached screen and display proper error message. * chore: improve error message * chore: update link * chore: update snapshots --- src/queries/__tests__/find-by.test.tsx | 22 ++++++++++++++++++++++ src/queries/make-queries.ts | 4 ++++ src/screen.ts | 13 +++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/queries/__tests__/find-by.test.tsx diff --git a/src/queries/__tests__/find-by.test.tsx b/src/queries/__tests__/find-by.test.tsx new file mode 100644 index 00000000..c018d97f --- /dev/null +++ b/src/queries/__tests__/find-by.test.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import { View } from 'react-native'; +import { render, screen } from '../..'; +import { clearRenderResult } from '../../screen'; + +test('findByTestId detects screen being detached', async () => { + render(); + + const promise = screen.findByTestId('not-exists', {}, { timeout: 50 }); + + // Detach screen + clearRenderResult(); + + await expect(promise).rejects.toThrowErrorMatchingInlineSnapshot(` + "Unable to find an element with testID: not-exists + + Screen is no longer attached. Check your test for "findBy*" or "waitFor" calls that have not been awaited. + + We recommend enabling "eslint-plugin-testing-library" to catch these issues at build time: + https://callstack.github.io/react-native-testing-library/docs/getting-started#eslint-plugin" + `); +}); diff --git a/src/queries/make-queries.ts b/src/queries/make-queries.ts index e5b9cca0..fa89b284 100644 --- a/src/queries/make-queries.ts +++ b/src/queries/make-queries.ts @@ -87,6 +87,10 @@ function formatErrorMessage(message: string, printElementTree: boolean) { return message; } + if (screen.isDetached) { + return `${message}\n\nScreen is no longer attached. Check your test for "findBy*" or "waitFor" calls that have not been awaited.\n\nWe recommend enabling "eslint-plugin-testing-library" to catch these issues at build time:\nhttps://callstack.github.io/react-native-testing-library/docs/getting-started#eslint-plugin`; + } + const json = screen.toJSON(); if (!json) { return message; diff --git a/src/screen.ts b/src/screen.ts index 6787e1c7..1fcbd3e2 100644 --- a/src/screen.ts +++ b/src/screen.ts @@ -12,7 +12,12 @@ const notImplementedDebug = () => { }; notImplementedDebug.shallow = notImplemented; -const defaultScreen: RenderResult = { +interface Screen extends RenderResult { + isDetached?: boolean; +} + +const defaultScreen: Screen = { + isDetached: true, get root(): ReactTestInstance { throw new Error(SCREEN_ERROR); }, @@ -112,10 +117,10 @@ const defaultScreen: RenderResult = { findAllByText: notImplemented, }; -export let screen: RenderResult = defaultScreen; +export let screen: Screen = defaultScreen; -export function setRenderResult(output: RenderResult) { - screen = output; +export function setRenderResult(renderResult: RenderResult) { + screen = renderResult; } export function clearRenderResult() {