From 398f09a1c92d462a8202dd743610af85fdfa7a96 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 6 May 2024 21:29:47 +0200 Subject: [PATCH 01/22] [v13] chore: remove deprecated stuff (#1603) * chore: remove flush microtask legacy * chore: remove deprecated *ByAccessibilityState, *ByAccessibilityValue queries * chore: add docs * docs: add docs --- src/flush-micro-tasks.ts | 25 - src/helpers/wrap-async.ts | 4 +- src/index.ts | 4 +- .../__tests__/accessibility-state.test.tsx | 535 ------------------ .../__tests__/accessibility-value.test.tsx | 319 ----------- src/queries/accessibility-state.ts | 94 --- src/queries/accessibility-value.ts | 94 --- src/screen.ts | 24 - src/within.ts | 4 - typings/index.flow.js | 40 +- website/docs/12.x/docs/api/queries.mdx | 109 ---- website/docs/MigrationV13.md | 67 +++ 12 files changed, 75 insertions(+), 1244 deletions(-) delete mode 100644 src/queries/__tests__/accessibility-state.test.tsx delete mode 100644 src/queries/__tests__/accessibility-value.test.tsx delete mode 100644 src/queries/accessibility-state.ts delete mode 100644 src/queries/accessibility-value.ts create mode 100644 website/docs/MigrationV13.md diff --git a/src/flush-micro-tasks.ts b/src/flush-micro-tasks.ts index 08295740b..4e5fac764 100644 --- a/src/flush-micro-tasks.ts +++ b/src/flush-micro-tasks.ts @@ -3,28 +3,3 @@ import { setImmediate } from './helpers/timers'; export function flushMicroTasks() { return new Promise((resolve) => setImmediate(resolve)); } - -/** - * @deprecated To be removed in the next major release. - */ -type Thenable = { then: (callback: () => T) => unknown }; - -/** - * This legacy implementation of `flushMicroTasks` is used for compatibility with - * older versions of React Native (pre 0.71) which uses Promise polyfil. - * - * For users with older version of React Native there is a workaround of using our own - * Jest preset instead the `react-native` one, but requiring such change would be a - * breaking change for existing users. - * - * @deprecated To be removed in the next major release. - */ -export function flushMicroTasksLegacy(): Thenable { - return { - // using "thenable" instead of a Promise, because otherwise it breaks when - // using "modern" fake timers - then(resolve) { - setImmediate(resolve); - }, - }; -} diff --git a/src/helpers/wrap-async.ts b/src/helpers/wrap-async.ts index c22a1df5e..1f9797b48 100644 --- a/src/helpers/wrap-async.ts +++ b/src/helpers/wrap-async.ts @@ -1,7 +1,7 @@ /* istanbul ignore file */ import act, { getIsReactActEnvironment, setReactActEnvironment } from '../act'; -import { flushMicroTasksLegacy } from '../flush-micro-tasks'; +import { flushMicroTasks } from '../flush-micro-tasks'; import { checkReactVersionAtLeast } from '../react-versions'; /** @@ -18,7 +18,7 @@ export async function wrapAsync(callback: () => Promise): Promis try { const result = await callback(); // Flush the microtask queue before restoring the `act` environment - await flushMicroTasksLegacy(); + await flushMicroTasks(); return result; } finally { setReactActEnvironment(previousActEnvironment); diff --git a/src/index.ts b/src/index.ts index 5c867106f..b01198181 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { cleanup } from './pure'; -import { flushMicroTasksLegacy } from './flush-micro-tasks'; +import { flushMicroTasks } from './flush-micro-tasks'; import { getIsReactActEnvironment, setReactActEnvironment } from './act'; if (!process?.env?.RNTL_SKIP_AUTO_CLEANUP) { @@ -11,7 +11,7 @@ if (!process?.env?.RNTL_SKIP_AUTO_CLEANUP) { if (typeof afterEach === 'function') { // eslint-disable-next-line no-undef afterEach(async () => { - await flushMicroTasksLegacy(); + await flushMicroTasks(); cleanup(); }); } diff --git a/src/queries/__tests__/accessibility-state.test.tsx b/src/queries/__tests__/accessibility-state.test.tsx deleted file mode 100644 index f72ac7a01..000000000 --- a/src/queries/__tests__/accessibility-state.test.tsx +++ /dev/null @@ -1,535 +0,0 @@ -/* eslint-disable no-console */ -import * as React from 'react'; -import { View, Text, Pressable, TouchableOpacity } from 'react-native'; -import { render, screen } from '../..'; - -type ConsoleLogMock = jest.Mock; - -beforeEach(() => { - jest.spyOn(console, 'warn').mockImplementation(() => {}); -}); - -const TEXT_LABEL = 'cool text'; - -const Typography = ({ children, ...rest }: any) => { - return {children}; -}; - -const Button = ({ children }: { children: React.ReactNode }) => ( - - {children} - -); - -const Section = () => ( - <> - Title - - -); - -test('getByA11yState, queryByA11yState, findByA11yState', async () => { - render(
); - - expect(screen.getByA11yState({ selected: true }).props.accessibilityState).toEqual({ - selected: true, - expanded: false, - }); - expect(screen.queryByA11yState({ selected: true })?.props.accessibilityState).toEqual({ - selected: true, - expanded: false, - }); - - expect(() => screen.getByA11yState({ disabled: true })).toThrow( - 'Unable to find an element with disabled state: true', - ); - expect(screen.queryByA11yState({ disabled: true })).toEqual(null); - - expect(() => screen.getByA11yState({ expanded: false })).toThrow( - 'Found multiple elements with expanded state: false', - ); - expect(() => screen.queryByA11yState({ expanded: false })).toThrow( - 'Found multiple elements with expanded state: false', - ); - - const asyncButton = await screen.findByA11yState({ selected: true }); - expect(asyncButton.props.accessibilityState).toEqual({ - selected: true, - expanded: false, - }); - await expect(screen.findByA11yState({ disabled: true })).rejects.toThrow( - 'Unable to find an element with disabled state: true', - ); - await expect(screen.findByA11yState({ expanded: false })).rejects.toThrow( - 'Found multiple elements with expanded state: false', - ); -}); - -test('getAllByA11yState, queryAllByA11yState, findAllByA11yState', async () => { - render(
); - - expect(screen.getAllByA11yState({ selected: true })).toHaveLength(1); - expect(screen.queryAllByA11yState({ selected: true })).toHaveLength(1); - - expect(() => screen.getAllByA11yState({ disabled: true })).toThrow( - 'Unable to find an element with disabled state: true', - ); - expect(screen.queryAllByA11yState({ disabled: true })).toEqual([]); - - expect(screen.getAllByA11yState({ expanded: false })).toHaveLength(2); - expect(screen.queryAllByA11yState({ expanded: false })).toHaveLength(2); - - await expect(screen.findAllByA11yState({ selected: true })).resolves.toHaveLength(1); - await expect(screen.findAllByA11yState({ disabled: true })).rejects.toThrow( - 'Unable to find an element with disabled state: true', - ); - await expect(screen.findAllByA11yState({ expanded: false })).resolves.toHaveLength(2); -}); - -describe('checked state matching', () => { - it('handles true', () => { - render(); - - expect(screen.getByA11yState({ checked: true })).toBeTruthy(); - expect(screen.queryByA11yState({ checked: 'mixed' })).toBeFalsy(); - expect(screen.queryByA11yState({ checked: false })).toBeFalsy(); - }); - - it('handles mixed', () => { - render(); - - expect(screen.getByA11yState({ checked: 'mixed' })).toBeTruthy(); - expect(screen.queryByA11yState({ checked: true })).toBeFalsy(); - expect(screen.queryByA11yState({ checked: false })).toBeFalsy(); - }); - - it('handles false', () => { - render(); - - expect(screen.getByA11yState({ checked: false })).toBeTruthy(); - expect(screen.queryByA11yState({ checked: true })).toBeFalsy(); - expect(screen.queryByA11yState({ checked: 'mixed' })).toBeFalsy(); - }); - - it('handles default', () => { - render(); - - expect(screen.queryByA11yState({ checked: false })).toBeFalsy(); - expect(screen.queryByA11yState({ checked: true })).toBeFalsy(); - expect(screen.queryByA11yState({ checked: 'mixed' })).toBeFalsy(); - }); -}); - -describe('expanded state matching', () => { - it('handles true', () => { - render(); - - expect(screen.getByA11yState({ expanded: true })).toBeTruthy(); - expect(screen.queryByA11yState({ expanded: false })).toBeFalsy(); - }); - - it('handles false', () => { - render(); - - expect(screen.getByA11yState({ expanded: false })).toBeTruthy(); - expect(screen.queryByA11yState({ expanded: true })).toBeFalsy(); - }); - - it('handles default', () => { - render(); - - expect(screen.queryByA11yState({ expanded: false })).toBeFalsy(); - expect(screen.queryByA11yState({ expanded: true })).toBeFalsy(); - }); -}); - -describe('disabled state matching', () => { - it('handles true', () => { - render(); - - expect(screen.getByA11yState({ disabled: true })).toBeTruthy(); - expect(screen.queryByA11yState({ disabled: false })).toBeFalsy(); - }); - - it('handles false', () => { - render(); - - expect(screen.getByA11yState({ disabled: false })).toBeTruthy(); - expect(screen.queryByA11yState({ disabled: true })).toBeFalsy(); - }); - - it('handles default', () => { - render(); - - expect(screen.getByA11yState({ disabled: false })).toBeTruthy(); - expect(screen.queryByA11yState({ disabled: true })).toBeFalsy(); - }); -}); - -describe('busy state matching', () => { - it('handles true', () => { - render(); - - expect(screen.getByA11yState({ busy: true })).toBeTruthy(); - expect(screen.queryByA11yState({ busy: false })).toBeFalsy(); - }); - - it('handles false', () => { - render(); - - expect(screen.getByA11yState({ busy: false })).toBeTruthy(); - expect(screen.queryByA11yState({ busy: true })).toBeFalsy(); - }); - - it('handles default', () => { - render(); - - expect(screen.getByA11yState({ busy: false })).toBeTruthy(); - expect(screen.queryByA11yState({ busy: true })).toBeFalsy(); - }); -}); - -describe('selected state matching', () => { - it('handles true', () => { - render(); - - expect(screen.getByA11yState({ selected: true })).toBeTruthy(); - expect(screen.queryByA11yState({ selected: false })).toBeFalsy(); - }); - - it('handles false', () => { - render(); - - expect(screen.getByA11yState({ selected: false })).toBeTruthy(); - expect(screen.queryByA11yState({ selected: true })).toBeFalsy(); - }); - - it('handles default', () => { - render(); - - expect(screen.getByA11yState({ selected: false })).toBeTruthy(); - expect(screen.queryByA11yState({ selected: true })).toBeFalsy(); - }); -}); - -test('*ByA11yState on Pressable with "disabled" prop', () => { - render(); - expect(screen.getByA11yState({ disabled: true })).toBeTruthy(); - expect(screen.queryByA11yState({ disabled: false })).toBeFalsy(); -}); - -test('*ByA11yState on TouchableOpacity with "disabled" prop', () => { - render(); - expect(screen.getByA11yState({ disabled: true })).toBeTruthy(); - expect(screen.queryByA11yState({ disabled: false })).toBeFalsy(); -}); - -test('byA11yState queries support hidden option', () => { - render( - - Hidden from accessibility - , - ); - - expect(screen.getByA11yState({ expanded: false }, { includeHiddenElements: true })).toBeTruthy(); - - expect(screen.queryByA11yState({ expanded: false })).toBeFalsy(); - expect( - screen.queryByA11yState({ expanded: false }, { includeHiddenElements: false }), - ).toBeFalsy(); - expect(() => screen.getByA11yState({ expanded: false }, { includeHiddenElements: false })) - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with expanded state: false - - - - Hidden from accessibility - - " - `); -}); - -test('*ByA11yState deprecation warnings', async () => { - const mockCalls = (console.warn as ConsoleLogMock).mock.calls; - render(); - - screen.getByA11yState({ disabled: true }); - expect(mockCalls[0][0]).toMatchInlineSnapshot(` - "getByA11yState(...) is deprecated and will be removed in the future. - - Use getByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.getAllByA11yState({ disabled: true }); - expect(mockCalls[1][0]).toMatchInlineSnapshot(` - "getAllByA11yState(...) is deprecated and will be removed in the future. - - Use getAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.queryByA11yState({ disabled: true }); - expect(mockCalls[2][0]).toMatchInlineSnapshot(` - "queryByA11yState(...) is deprecated and will be removed in the future. - - Use queryByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.queryAllByA11yState({ disabled: true }); - expect(mockCalls[3][0]).toMatchInlineSnapshot(` - "queryAllByA11yState(...) is deprecated and will be removed in the future. - - Use queryAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - await screen.findByA11yState({ disabled: true }); - expect(mockCalls[4][0]).toMatchInlineSnapshot(` - "findByA11yState(...) is deprecated and will be removed in the future. - - Use findByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - await screen.findAllByA11yState({ disabled: true }); - expect(mockCalls[5][0]).toMatchInlineSnapshot(` - "findAllByA11yState(...) is deprecated and will be removed in the future. - - Use findAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); -}); - -test('*ByAccessibilityState deprecation warnings', async () => { - const mockCalls = (console.warn as ConsoleLogMock).mock.calls; - render(); - - screen.getByAccessibilityState({ disabled: true }); - expect(mockCalls[0][0]).toMatchInlineSnapshot(` - "getByAccessibilityState(...) is deprecated and will be removed in the future. - - Use getByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.getAllByAccessibilityState({ disabled: true }); - expect(mockCalls[1][0]).toMatchInlineSnapshot(` - "getAllByAccessibilityState(...) is deprecated and will be removed in the future. - - Use getAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.queryByAccessibilityState({ disabled: true }); - expect(mockCalls[2][0]).toMatchInlineSnapshot(` - "queryByAccessibilityState(...) is deprecated and will be removed in the future. - - Use queryByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - screen.queryAllByAccessibilityState({ disabled: true }); - expect(mockCalls[3][0]).toMatchInlineSnapshot(` - "queryAllByAccessibilityState(...) is deprecated and will be removed in the future. - - Use queryAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - await screen.findByAccessibilityState({ disabled: true }); - expect(mockCalls[4][0]).toMatchInlineSnapshot(` - "findByAccessibilityState(...) is deprecated and will be removed in the future. - - Use findByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); - - await screen.findAllByAccessibilityState({ disabled: true }); - expect(mockCalls[5][0]).toMatchInlineSnapshot(` - "findAllByAccessibilityState(...) is deprecated and will be removed in the future. - - Use findAllByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead." - `); -}); - -test('error message renders the element tree, preserving only helpful props', async () => { - render( - null}> - Some text - , - ); - - expect(() => screen.getByA11yState({ checked: true })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with checked state: true - - - Some text - " - `); - - expect(() => screen.getAllByA11yState({ checked: true })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with checked state: true - - - Some text - " - `); - - await expect(screen.findByA11yState({ checked: true })).rejects - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with checked state: true - - - Some text - " - `); - - await expect(screen.findAllByA11yState({ checked: true })).rejects - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with checked state: true - - - Some text - " - `); -}); - -describe('aria-disabled prop', () => { - test('supports aria-disabled={true} prop', () => { - render(); - expect(screen.getByAccessibilityState({ disabled: true })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ disabled: false })).toBeNull(); - }); - - test('supports aria-disabled={false} prop', () => { - render(); - expect(screen.getByAccessibilityState({ disabled: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ disabled: true })).toBeNull(); - }); - - test('supports default aria-disabled prop', () => { - render(); - expect(screen.getByAccessibilityState({ disabled: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ disabled: true })).toBeNull(); - }); -}); - -describe('aria-selected prop', () => { - test('supports aria-selected={true} prop', () => { - render(); - expect(screen.getByAccessibilityState({ selected: true })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ selected: false })).toBeNull(); - }); - - test('supports aria-selected={false} prop', () => { - render(); - expect(screen.getByAccessibilityState({ selected: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ selected: true })).toBeNull(); - }); - - test('supports default aria-selected prop', () => { - render(); - expect(screen.getByAccessibilityState({ selected: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ selected: true })).toBeNull(); - }); -}); - -describe('aria-checked prop', () => { - test('supports aria-checked={true} prop', () => { - render(); - expect(screen.getByAccessibilityState({ checked: true })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ checked: false })).toBeNull(); - expect(screen.queryByAccessibilityState({ checked: 'mixed' })).toBeNull(); - }); - - test('supports aria-checked={false} prop', () => { - render(); - expect(screen.getByAccessibilityState({ checked: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ checked: true })).toBeNull(); - expect(screen.queryByAccessibilityState({ checked: 'mixed' })).toBeNull(); - }); - - test('supports aria-checked="mixed prop', () => { - render(); - expect(screen.getByAccessibilityState({ checked: 'mixed' })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ checked: true })).toBeNull(); - expect(screen.queryByAccessibilityState({ checked: false })).toBeNull(); - }); - - test('supports default aria-selected prop', () => { - render(); - expect(screen.getByAccessibilityState({})).toBeTruthy(); - expect(screen.queryByAccessibilityState({ checked: true })).toBeNull(); - expect(screen.queryByAccessibilityState({ checked: false })).toBeNull(); - expect(screen.queryByAccessibilityState({ checked: 'mixed' })).toBeNull(); - }); -}); - -describe('aria-busy prop', () => { - test('supports aria-busy={true} prop', () => { - render(); - expect(screen.getByAccessibilityState({ busy: true })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ busy: false })).toBeNull(); - }); - - test('supports aria-busy={false} prop', () => { - render(); - expect(screen.getByAccessibilityState({ busy: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ busy: true })).toBeNull(); - }); - - test('supports default aria-busy prop', () => { - render(); - expect(screen.getByAccessibilityState({ busy: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ busy: true })).toBeNull(); - }); -}); - -describe('aria-expanded prop', () => { - test('supports aria-expanded={true} prop', () => { - render(); - expect(screen.getByAccessibilityState({ expanded: true })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ expanded: false })).toBeNull(); - }); - - test('supports aria-expanded={false} prop', () => { - render(); - expect(screen.getByAccessibilityState({ expanded: false })).toBeTruthy(); - expect(screen.queryByAccessibilityState({ expanded: true })).toBeNull(); - }); - - test('supports default aria-expanded prop', () => { - render(); - render(); - expect(screen.getByAccessibilityState({})).toBeTruthy(); - expect(screen.queryByAccessibilityState({ expanded: true })).toBeNull(); - expect(screen.queryByAccessibilityState({ expanded: false })).toBeNull(); - }); -}); diff --git a/src/queries/__tests__/accessibility-value.test.tsx b/src/queries/__tests__/accessibility-value.test.tsx deleted file mode 100644 index 9e07ab41c..000000000 --- a/src/queries/__tests__/accessibility-value.test.tsx +++ /dev/null @@ -1,319 +0,0 @@ -/* eslint-disable no-console */ -import * as React from 'react'; -import { Text, TouchableOpacity, View } from 'react-native'; -import { render, screen } from '../..'; - -type ConsoleLogMock = jest.Mock; - -beforeEach(() => { - jest.spyOn(console, 'warn').mockImplementation(() => {}); -}); - -const TEXT_LABEL = 'cool text'; - -const Typography = ({ children, ...rest }: any) => { - return {children}; -}; - -const Button = ({ children }: { children: React.ReactNode }) => ( - - {children} - -); - -const Section = () => ( - <> - Title - - -); - -test('getByA11yValue, queryByA11yValue, findByA11yValue', async () => { - render(
); - - expect(screen.getByA11yValue({ min: 40 }).props.accessibilityValue).toEqual({ - min: 40, - max: 60, - }); - expect(screen.queryByA11yValue({ min: 40 })?.props.accessibilityValue).toEqual({ - min: 40, - max: 60, - }); - - expect(() => screen.getByA11yValue({ min: 50 })).toThrow( - 'Unable to find an element with min value: 50', - ); - expect(screen.queryByA11yValue({ min: 50 })).toEqual(null); - - expect(() => screen.getByA11yValue({ max: 60 })).toThrow( - 'Found multiple elements with max value: 60', - ); - expect(() => screen.queryByA11yValue({ max: 60 })).toThrow( - 'Found multiple elements with max value: 60', - ); - - const asyncElement = await screen.findByA11yValue({ min: 40 }); - expect(asyncElement.props.accessibilityValue).toEqual({ - min: 40, - max: 60, - }); - await expect(screen.findByA11yValue({ min: 50 })).rejects.toThrow( - 'Unable to find an element with min value: 50', - ); - await expect(screen.findByA11yValue({ max: 60 })).rejects.toThrow( - 'Found multiple elements with max value: 60', - ); -}); - -test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { - render(
); - - expect(screen.getAllByA11yValue({ min: 40 })).toHaveLength(1); - expect(screen.queryAllByA11yValue({ min: 40 })).toHaveLength(1); - - expect(() => screen.getAllByA11yValue({ min: 50 })).toThrow( - 'Unable to find an element with min value: 50', - ); - expect(screen.queryAllByA11yValue({ min: 50 })).toEqual([]); - - expect(screen.queryAllByA11yValue({ max: 60 })).toHaveLength(2); - expect(screen.getAllByA11yValue({ max: 60 })).toHaveLength(2); - - await expect(screen.findAllByA11yValue({ min: 40 })).resolves.toHaveLength(1); - await expect(screen.findAllByA11yValue({ min: 50 })).rejects.toThrow( - 'Unable to find an element with min value: 50', - ); - await expect(screen.findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2); -}); - -test('byA11yValue queries support hidden option', () => { - render( - - Hidden from accessibility - , - ); - - expect(screen.getByA11yValue({ max: 10 }, { includeHiddenElements: true })).toBeTruthy(); - - expect(screen.queryByA11yValue({ max: 10 })).toBeFalsy(); - expect(screen.queryByA11yValue({ max: 10 }, { includeHiddenElements: false })).toBeFalsy(); - expect(() => screen.getByA11yValue({ max: 10 }, { includeHiddenElements: false })) - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with max value: 10 - - - Hidden from accessibility - " - `); -}); - -test('byA11yValue error messages', () => { - render(); - expect(() => screen.getByA11yValue({ min: 10, max: 10 })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 10, max value: 10 - - " - `); - expect(() => screen.getByA11yValue({ max: 20, now: 5 })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with max value: 20, now value: 5 - - " - `); - expect(() => screen.getByA11yValue({ min: 1, max: 2, now: 3 })) - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1, max value: 2, now value: 3 - - " - `); - expect(() => screen.getByA11yValue({ min: 1, max: 2, now: 3, text: /foo/i })) - .toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1, max value: 2, now value: 3, text value: /foo/i - - " - `); -}); - -test('*ByA11yValue deprecation warnings', async () => { - const mockCalls = (console.warn as ConsoleLogMock).mock.calls; - render(); - - screen.getByA11yValue({ min: 10 }); - expect(mockCalls[0][0]).toMatchInlineSnapshot(` - "getByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or getByRole(role, { value: ... }) query instead." - `); - - screen.getAllByA11yValue({ min: 10 }); - expect(mockCalls[1][0]).toMatchInlineSnapshot(` - "getAllByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or getAllByRole(role, { value: ... }) query instead." - `); - - screen.queryByA11yValue({ min: 10 }); - expect(mockCalls[2][0]).toMatchInlineSnapshot(` - "queryByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or queryByRole(role, { value: ... }) query instead." - `); - - screen.queryAllByA11yValue({ min: 10 }); - expect(mockCalls[3][0]).toMatchInlineSnapshot(` - "queryAllByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or queryAllByRole(role, { value: ... }) query instead." - `); - - await screen.findByA11yValue({ min: 10 }); - expect(mockCalls[4][0]).toMatchInlineSnapshot(` - "findByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or findByRole(role, { value: ... }) query instead." - `); - - await screen.findAllByA11yValue({ min: 10 }); - expect(mockCalls[5][0]).toMatchInlineSnapshot(` - "findAllByA11yValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or findAllByRole(role, { value: ... }) query instead." - `); -}); - -test('*ByAccessibilityValue deprecation warnings', async () => { - const mockCalls = (console.warn as ConsoleLogMock).mock.calls; - render(); - - screen.getByAccessibilityValue({ min: 10 }); - expect(mockCalls[0][0]).toMatchInlineSnapshot(` - "getByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or getByRole(role, { value: ... }) query instead." - `); - - screen.getAllByAccessibilityValue({ min: 10 }); - expect(mockCalls[1][0]).toMatchInlineSnapshot(` - "getAllByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or getAllByRole(role, { value: ... }) query instead." - `); - - screen.queryByAccessibilityValue({ min: 10 }); - expect(mockCalls[2][0]).toMatchInlineSnapshot(` - "queryByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or queryByRole(role, { value: ... }) query instead." - `); - - screen.queryAllByAccessibilityValue({ min: 10 }); - expect(mockCalls[3][0]).toMatchInlineSnapshot(` - "queryAllByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or queryAllByRole(role, { value: ... }) query instead." - `); - - await screen.findByAccessibilityValue({ min: 10 }); - expect(mockCalls[4][0]).toMatchInlineSnapshot(` - "findByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or findByRole(role, { value: ... }) query instead." - `); - - await screen.findAllByAccessibilityValue({ min: 10 }); - expect(mockCalls[5][0]).toMatchInlineSnapshot(` - "findAllByAccessibilityValue(...) is deprecated and will be removed in the future. - - Use toHaveAccessibilityValue(...) built-in Jest matcher or findAllByRole(role, { value: ... }) query instead." - `); -}); - -test('error message renders the element tree, preserving only helpful props', async () => { - render(); - - expect(() => screen.getByA11yValue({ min: 1 })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1 - - " - `); - - expect(() => screen.getAllByA11yValue({ min: 1 })).toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1 - - " - `); - - await expect(screen.findByA11yValue({ min: 1 })).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1 - - " - `); - - await expect(screen.findAllByA11yValue({ min: 1 })).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to find an element with min value: 1 - - " - `); -}); - -describe('getByAccessibilityValue supports "aria-*" props', () => { - test('supports "aria-valuemax"', () => { - render(); - expect(screen.getByAccessibilityValue({ max: 10 })).toBeTruthy(); - }); - - test('supports "aria-valuemin"', () => { - render(); - expect(screen.getByAccessibilityValue({ min: 20 })).toBeTruthy(); - }); - - test('supports "aria-valuenow"', () => { - render(); - expect(screen.getByAccessibilityValue({ now: 30 })).toBeTruthy(); - }); - - test('supports "aria-valuetext"', () => { - render(); - expect(screen.getByAccessibilityValue({ text: 'Hello World' })).toBeTruthy(); - expect(screen.getByAccessibilityValue({ text: /hello/i })).toBeTruthy(); - }); - - test('supports multiple "aria-value*" props', () => { - render(); - expect(screen.getByAccessibilityValue({ now: 50, min: 0, max: 100 })).toBeTruthy(); - }); -}); diff --git a/src/queries/accessibility-state.ts b/src/queries/accessibility-state.ts deleted file mode 100644 index b38df4a7a..000000000 --- a/src/queries/accessibility-state.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { ReactTestInstance } from 'react-test-renderer'; -import { accessibilityStateKeys } from '../helpers/accessibility'; -import { deprecateQueries } from '../helpers/deprecation'; -import { findAll } from '../helpers/find-all'; -import { - AccessibilityStateMatcher, - matchAccessibilityState, -} from '../helpers/matchers/match-accessibility-state'; -import { makeQueries } from './make-queries'; -import type { - FindAllByQuery, - FindByQuery, - GetAllByQuery, - GetByQuery, - QueryAllByQuery, - QueryByQuery, -} from './make-queries'; -import { CommonQueryOptions } from './options'; - -const queryAllByA11yState = ( - instance: ReactTestInstance, -): QueryAllByQuery => - function queryAllByA11yStateFn(matcher, queryOptions) { - return findAll(instance, (node) => matchAccessibilityState(node, matcher), queryOptions); - }; - -const buildErrorMessage = (state: AccessibilityStateMatcher = {}) => { - const errors: string[] = []; - - accessibilityStateKeys.forEach((stateKey) => { - if (state[stateKey] !== undefined) { - errors.push(`${stateKey} state: ${state[stateKey]}`); - } - }); - - return errors.join(', '); -}; - -const getMultipleError = (state: AccessibilityStateMatcher) => - `Found multiple elements with ${buildErrorMessage(state)}`; - -const getMissingError = (state: AccessibilityStateMatcher) => - `Unable to find an element with ${buildErrorMessage(state)}`; - -const { getBy, getAllBy, queryBy, queryAllBy, findBy, findAllBy } = makeQueries( - queryAllByA11yState, - getMissingError, - getMultipleError, -); - -export type ByA11yStateQueries = { - getByA11yState: GetByQuery; - getAllByA11yState: GetAllByQuery; - queryByA11yState: QueryByQuery; - queryAllByA11yState: QueryAllByQuery; - findByA11yState: FindByQuery; - findAllByA11yState: FindAllByQuery; - - getByAccessibilityState: GetByQuery; - getAllByAccessibilityState: GetAllByQuery; - queryByAccessibilityState: QueryByQuery; - queryAllByAccessibilityState: QueryAllByQuery; - findByAccessibilityState: FindByQuery; - findAllByAccessibilityState: FindAllByQuery; -}; - -export const bindByA11yStateQueries = (instance: ReactTestInstance): ByA11yStateQueries => { - const getByA11yState = getBy(instance); - const getAllByA11yState = getAllBy(instance); - const queryByA11yState = queryBy(instance); - const queryAllByA11yState = queryAllBy(instance); - const findByA11yState = findBy(instance); - const findAllByA11yState = findAllBy(instance); - - return { - ...deprecateQueries( - { - getByA11yState, - getAllByA11yState, - queryByA11yState, - queryAllByA11yState, - findByA11yState, - findAllByA11yState, - getByAccessibilityState: getByA11yState, - getAllByAccessibilityState: getAllByA11yState, - queryByAccessibilityState: queryByA11yState, - queryAllByAccessibilityState: queryAllByA11yState, - findByAccessibilityState: findByA11yState, - findAllByAccessibilityState: findAllByA11yState, - }, - 'Use {queryPrefix}ByRole(role, { disabled, selected, checked, busy, expanded }) query or built-in Jest matchers: toBeDisabled(), toBeSelected(), toBeChecked(), toBeBusy(), and toBeExpanded() instead.', - ), - }; -}; diff --git a/src/queries/accessibility-value.ts b/src/queries/accessibility-value.ts deleted file mode 100644 index 25d4d5361..000000000 --- a/src/queries/accessibility-value.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { ReactTestInstance } from 'react-test-renderer'; -import { accessibilityValueKeys } from '../helpers/accessibility'; -import { deprecateQueries } from '../helpers/deprecation'; -import { findAll } from '../helpers/find-all'; -import { - AccessibilityValueMatcher, - matchAccessibilityValue, -} from '../helpers/matchers/match-accessibility-value'; -import { makeQueries } from './make-queries'; -import type { - FindAllByQuery, - FindByQuery, - GetAllByQuery, - GetByQuery, - QueryAllByQuery, - QueryByQuery, -} from './make-queries'; -import { CommonQueryOptions } from './options'; - -const queryAllByA11yValue = ( - instance: ReactTestInstance, -): QueryAllByQuery => - function queryAllByA11yValueFn(value, queryOptions) { - return findAll(instance, (node) => matchAccessibilityValue(node, value), queryOptions); - }; - -const formatQueryParams = (matcher: AccessibilityValueMatcher) => { - const params: string[] = []; - - accessibilityValueKeys.forEach((valueKey) => { - if (matcher[valueKey] !== undefined) { - params.push(`${valueKey} value: ${matcher[valueKey]}`); - } - }); - - return params.join(', '); -}; - -const getMultipleError = (matcher: AccessibilityValueMatcher) => - `Found multiple elements with ${formatQueryParams(matcher)}`; - -const getMissingError = (matcher: AccessibilityValueMatcher) => - `Unable to find an element with ${formatQueryParams(matcher)}`; - -const { getBy, getAllBy, queryBy, queryAllBy, findBy, findAllBy } = makeQueries( - queryAllByA11yValue, - getMissingError, - getMultipleError, -); - -export type ByA11yValueQueries = { - getByA11yValue: GetByQuery; - getAllByA11yValue: GetAllByQuery; - queryByA11yValue: QueryByQuery; - queryAllByA11yValue: QueryAllByQuery; - findByA11yValue: FindByQuery; - findAllByA11yValue: FindAllByQuery; - - getByAccessibilityValue: GetByQuery; - getAllByAccessibilityValue: GetAllByQuery; - queryByAccessibilityValue: QueryByQuery; - queryAllByAccessibilityValue: QueryAllByQuery; - findByAccessibilityValue: FindByQuery; - findAllByAccessibilityValue: FindAllByQuery; -}; - -export const bindByA11yValueQueries = (instance: ReactTestInstance): ByA11yValueQueries => { - const getByA11yValue = getBy(instance); - const getAllByA11yValue = getAllBy(instance); - const queryByA11yValue = queryBy(instance); - const queryAllByA11yValue = queryAllBy(instance); - const findByA11yValue = findBy(instance); - const findAllByA11yValue = findAllBy(instance); - - return { - ...deprecateQueries( - { - getByA11yValue, - getAllByA11yValue, - queryByA11yValue, - queryAllByA11yValue, - findByA11yValue, - findAllByA11yValue, - getByAccessibilityValue: getByA11yValue, - getAllByAccessibilityValue: getAllByA11yValue, - queryByAccessibilityValue: queryByA11yValue, - queryAllByAccessibilityValue: queryAllByA11yValue, - findByAccessibilityValue: findByA11yValue, - findAllByAccessibilityValue: findAllByA11yValue, - }, - 'Use toHaveAccessibilityValue(...) built-in Jest matcher or {queryPrefix}ByRole(role, { value: ... }) query instead.', - ), - }; -}; diff --git a/src/screen.ts b/src/screen.ts index 1fcbd3e2a..90600ef82 100644 --- a/src/screen.ts +++ b/src/screen.ts @@ -59,30 +59,6 @@ const defaultScreen: Screen = { queryAllByRole: notImplemented, findByRole: notImplemented, findAllByRole: notImplemented, - getByA11yState: notImplemented, - getAllByA11yState: notImplemented, - queryByA11yState: notImplemented, - queryAllByA11yState: notImplemented, - findByA11yState: notImplemented, - findAllByA11yState: notImplemented, - getByAccessibilityState: notImplemented, - getAllByAccessibilityState: notImplemented, - queryByAccessibilityState: notImplemented, - queryAllByAccessibilityState: notImplemented, - findByAccessibilityState: notImplemented, - findAllByAccessibilityState: notImplemented, - getByA11yValue: notImplemented, - getAllByA11yValue: notImplemented, - queryByA11yValue: notImplemented, - queryAllByA11yValue: notImplemented, - findByA11yValue: notImplemented, - findAllByA11yValue: notImplemented, - getByAccessibilityValue: notImplemented, - getAllByAccessibilityValue: notImplemented, - queryByAccessibilityValue: notImplemented, - queryAllByAccessibilityValue: notImplemented, - findByAccessibilityValue: notImplemented, - findAllByAccessibilityValue: notImplemented, UNSAFE_getByProps: notImplemented, UNSAFE_getAllByProps: notImplemented, UNSAFE_queryByProps: notImplemented, diff --git a/src/within.ts b/src/within.ts index 59db8bf1a..0e5873007 100644 --- a/src/within.ts +++ b/src/within.ts @@ -6,8 +6,6 @@ import { bindByPlaceholderTextQueries } from './queries/placeholder-text'; import { bindByLabelTextQueries } from './queries/label-text'; import { bindByHintTextQueries } from './queries/hint-text'; import { bindByRoleQueries } from './queries/role'; -import { bindByA11yStateQueries } from './queries/accessibility-state'; -import { bindByA11yValueQueries } from './queries/accessibility-value'; import { bindUnsafeByTypeQueries } from './queries/unsafe-type'; import { bindUnsafeByPropsQueries } from './queries/unsafe-props'; @@ -20,8 +18,6 @@ export function within(instance: ReactTestInstance) { ...bindByLabelTextQueries(instance), ...bindByHintTextQueries(instance), ...bindByRoleQueries(instance), - ...bindByA11yStateQueries(instance), - ...bindByA11yValueQueries(instance), ...bindUnsafeByTypeQueries(instance), ...bindUnsafeByPropsQueries(instance), }; diff --git a/typings/index.flow.js b/typings/index.flow.js index eb05d9f24..2bea0c77b 100644 --- a/typings/index.flow.js +++ b/typings/index.flow.js @@ -55,10 +55,10 @@ declare type A11yRole = declare type A11yState = {| disabled?: boolean, - selected?: boolean, - checked?: boolean | 'mixed', - busy?: boolean, - expanded?: boolean, + selected ?: boolean, + checked ?: boolean | 'mixed', + busy ?: boolean, + expanded ?: boolean, |}; declare type A11yValue = { @@ -258,38 +258,6 @@ interface A11yAPI { queryOptions?: ByRoleOptions, waitForOptions?: WaitForOptions ) => FindAllReturn; - - // State - getByA11yState: (matcher: A11yState, options?: CommonQueryOptions) => GetReturn; - getAllByA11yState: (matcher: A11yState, options?: CommonQueryOptions) => GetAllReturn; - queryByA11yState: (matcher: A11yState, options?: CommonQueryOptions) => QueryReturn; - queryAllByA11yState: (matcher: A11yState, options?: CommonQueryOptions) => QueryAllReturn; - findByA11yState: ( - matcher: A11yState, - queryOptions?: CommonQueryOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yState: ( - matcher: A11yState, - queryOptions?: CommonQueryOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - - // Value - getByA11yValue: (matcher: A11yValue, options?: CommonQueryOptions) => GetReturn; - getAllByA11yValue: (matcher: A11yValue, options?: CommonQueryOptions) => GetAllReturn; - queryByA11yValue: (matcher: A11yValue, options?: CommonQueryOptions) => QueryReturn; - queryAllByA11yValue: (matcher: A11yValue, options?: CommonQueryOptions) => QueryAllReturn; - findByA11yValue: ( - matcher: A11yValue, - queryOptions?: CommonQueryOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yValue: ( - matcher: A11yValue, - queryOptions?: CommonQueryOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; } interface Thenable { diff --git a/website/docs/12.x/docs/api/queries.mdx b/website/docs/12.x/docs/api/queries.mdx index 8c05e8ec1..761109915 100644 --- a/website/docs/12.x/docs/api/queries.mdx +++ b/website/docs/12.x/docs/api/queries.mdx @@ -383,115 +383,6 @@ const element = screen.getByTestId('unique-id'); In the spirit of [the guiding principles](https://testing-library.com/docs/guiding-principles), it is recommended to use this only after the other queries don't work for your use case. Using `testID` attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post ["Making your UI tests resilient to change"](https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change). ::: -### `*ByA11yState`, `ByAccessibilityState` (deprecated) {#by-accessibility-state} - -:::caution -This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options: - -- [`*ByRole`](#by-role) query with relevant state options: `disabled`, `selected`, `checked`, `expanded` and `busy` -- use built-in Jest matchers to check the state of element found using some other query: - - enabled state: [`toBeEnabled()` / `toBeDisabled()`](docs/api/jest-matchers#tobeenabled) - - checked state: [`toBeChecked()` / `toBePartiallyChecked()`](docs/api/jest-matchers#tobechecked) - - selected state: [`toBeSelected()`](docs/api/jest-matchers#tobeselected) - - expanded state: [`toBeExpanded()` / `toBeCollapsed()`](docs/api/jest-matchers#tobeexpanded) - - busy state: [`toBeBusy()`](docs/api/jest-matchers#tobebusy) - -::: - -> getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState -> getByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState - -```ts -getByA11yState( - state: { - disabled?: boolean, - selected?: boolean, - checked?: boolean | 'mixed', - busy?: boolean, - expanded?: boolean, - }, - options?: { - includeHiddenElements?: boolean; - }, -): ReactTestInstance; -``` - -Returns a `ReactTestInstance` with matching `accessibilityState` prop or ARIA state props: `aria-disabled`, `aria-selected`, `aria-checked`, `aria-busy`, and `aria-expanded`. - -```jsx -import { render, screen } from '@testing-library/react-native'; - -render(); -const element = screen.getByA11yState({ disabled: true }); -``` - -:::note - -#### Default state for: `disabled`, `selected`, and `busy` keys - -Passing `false` matcher value will match both elements with explicit `false` state value and without explicit state value. - -For instance, `getByA11yState({ disabled: false })` will match elements with following props: - -- `accessibilityState={{ disabled: false, ... }}` -- no `disabled` key under `accessibilityState` prop, e.g. `accessibilityState={{}}` -- no `accessibilityState` prop at all - -#### Default state for: `checked` and `expanded` keys - -Passing `false` matcher value will only match elements with explicit `false` state value. - -For instance, `getByA11yState({ checked: false })` will only match elements with: - -- `accessibilityState={{ checked: false, ... }}` - -but will not match elements with following props: - -- no `checked` key under `accessibilityState` prop, e.g. `accessibilityState={{}}` -- no `accessibilityState` prop at all - -The difference in handling default values is made to reflect observed accessibility behaviour on iOS and Android platforms. -::: - -### `*ByA11yValue`, `*ByAccessibilityValue` (deprecated) {#by-accessibility-value} - -:::caution -This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options: - -- [`toHaveAccessibilityValue()`](docs/api/jest-matchers#tohaveaccessibilityvalue) Jest matcher to check the state of element found using some other query -- [`*ByRole`](#by-role) query with `value` option - -::: - -> getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue -> getByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue - -```ts -getByA11yValue( - value: { - min?: number; - max?: number; - now?: number; - text?: TextMatch; - }, - options?: { - includeHiddenElements?: boolean; - }, -): ReactTestInstance; -``` - -Returns a host element with matching accessibility value based on `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, `aria-valuetext` & `accessibilityValue` props. Only value entires provided to the query will be used to match elements. Element might have additional accessibility value entries and still be matched. - -When querying by `text` entry a string or regex might be used. - -```jsx -import { render, screen } from '@testing-library/react-native'; - -render(); -const element = screen.getByA11yValue({ now: 25 }); -const element2 = screen.getByA11yValue({ text: /25/ }); -``` - ### Common options Usually query first argument can be a **string** or a **regex**. All queries take at least the [`hidden`](#hidden-option) option as an optionnal second argument and some queries accept more options which change string matching behaviour. See [TextMatch](#textmatch) for more info. diff --git a/website/docs/MigrationV13.md b/website/docs/MigrationV13.md new file mode 100644 index 000000000..b58c4f93f --- /dev/null +++ b/website/docs/MigrationV13.md @@ -0,0 +1,67 @@ +## @@ -0,0 +1,20 @@ + +id: migration-v13 +title: Migration to 13.0 + +--- + +import TOCInline from '@theme/TOCInline'; + +Migration to React Native Testing Library version 13 from version 12.x. + + + +# Breaking changes + +## Removed deprecated \*ByAccessibilityState queries + +This deprecated query has been removed as is typically too general to give meaningful results. Use one of the following options: + +- [`*ByRole`](#by-role) query with relevant state options: `disabled`, `selected`, `checked`, `expanded` and `busy` +- use built-in Jest matchers to check the state of element found using some other query: + - enabled state: [`toBeEnabled()` / `toBeDisabled()`](jest-matchers#tobeenabled) + - checked state: [`toBeChecked()` / `toBePartiallyChecked()`](jest-matchers#tobechecked) + - selected state: [`toBeSelected()`](jest-matchers#tobeselected) + - expanded state: [`toBeExpanded()` / `toBeCollapsed()`](jest-matchers#tobeexpanded) + - busy state: [`toBeBusy()`](jest-matchers#tobebusy) + +```ts +// Replace this +const view = screen.getByAccessibilityState({ disabled: true }); + +// with this (getByRole query) +const view = screen.getByRole('', { disabled: true }); + +// or this (Jest matcher) +const view = screen.getBy*(...); // Find the element using any query: *ByRole, *ByText, *ByTestId +expect(view).toBeDisabled(); // Assert its accessibility state +``` + +## Removed deprecated \*ByAccessibilityValue queries + +This deprecated query has been removed as is typically too general to give meaningful results. Use one of the following options: + +- [`toHaveAccessibilityValue()`](jest-matchers#tohaveaccessibilityvalue) Jest matcher to check the state of element found using some other query +- [`*ByRole`](#by-role) query with `value` option + +```ts +// Replace this +const view = screen.getByAccessibilityValue({ now: 50, min: 0, max: 50 }); + +// with this (getByRole query) +const view = screen.getByRole('', { value: { now: 50, min: 0, max: 50 } }); + +// or this (Jest matcher) +const view = screen.getBy*(...); // Find the element using any query: *ByRole, *ByText, *ByTestId +expect(view).toHaveAccessibilityValue({ now: 50, min: 0, max: 50 }); // Assert its accessibility value +``` + +# Other changes + +## Updated `flushMicroTasks` internal method + +This should not break any tests. + +## Full Changelog + +https://github.com/callstack/react-native-testing-library/compare/v12.5.0...v13.0.0 From b797cf4cc56e7545974220a9eff580632e96ef4d Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 7 May 2024 15:04:18 +0200 Subject: [PATCH 02/22] [v13] chore: remove react 16 & 17 code (#1602) * chore: remove React 16 & 17 code chore: remove more chore: react version 18.3.1 docs: migration guide * refactor: finish merge --- package.json | 7 +- scripts/test_react_17 | 12 - src/act.ts | 5 +- src/helpers/wrap-async.ts | 36 +- website/docs/MigrationV13.md | 6 + yarn.lock | 747 ++++++++++++++++++++++++++++------- 6 files changed, 625 insertions(+), 188 deletions(-) delete mode 100755 scripts/test_react_17 diff --git a/package.json b/package.json index a6567a638..6597970ef 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "clean": "del build", "test": "jest", "test:ci": "jest --maxWorkers=2 --collectCoverage=true --coverage-provider=v8", - "test:react-17": "scripts/test_react_17", "typecheck": "tsc", "flow": "flow", "copy-flowtypes": "cp typings/index.flow.js build", @@ -58,9 +57,9 @@ }, "peerDependencies": { "jest": ">=28.0.0", - "react": ">=16.8.0", - "react-native": ">=0.59", - "react-test-renderer": ">=16.8.0" + "react": ">=18.2.0", + "react-native": ">=0.73", + "react-test-renderer": ">=18.2.0" }, "peerDependenciesMeta": { "jest": { diff --git a/scripts/test_react_17 b/scripts/test_react_17 deleted file mode 100755 index cbef0e0ce..000000000 --- a/scripts/test_react_17 +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -cp yarn.lock yarn.lock.backup -cp package.json package.json.backup - -yarn add -D react@17.0.2 react-test-renderer@17.0.2 react-native@0.68.3 --ignore-scripts -yarn test:ci --collectCoverage=false - -mv package.json.backup package.json -mv yarn.lock.backup yarn.lock - -yarn --ignore-scripts diff --git a/src/act.ts b/src/act.ts index 5c44ca358..a05168500 100644 --- a/src/act.ts +++ b/src/act.ts @@ -1,7 +1,6 @@ // This file and the act() implementation is sourced from react-testing-library // https://github.com/testing-library/react-testing-library/blob/c80809a956b0b9f3289c4a6fa8b5e8cc72d6ef6d/src/act-compat.js import { act as reactTestRendererAct } from 'react-test-renderer'; -import { checkReactVersionAtLeast } from './react-versions'; type ReactAct = typeof reactTestRendererAct; @@ -72,9 +71,7 @@ function withGlobalActEnvironment(actImplementation: ReactAct) { }; } -const act: ReactAct = checkReactVersionAtLeast(18, 0) - ? (withGlobalActEnvironment(reactTestRendererAct) as ReactAct) - : reactTestRendererAct; +const act = withGlobalActEnvironment(reactTestRendererAct) as ReactAct; export default act; export { setIsReactActEnvironment as setReactActEnvironment, getIsReactActEnvironment }; diff --git a/src/helpers/wrap-async.ts b/src/helpers/wrap-async.ts index 1f9797b48..a80d86156 100644 --- a/src/helpers/wrap-async.ts +++ b/src/helpers/wrap-async.ts @@ -1,8 +1,7 @@ /* istanbul ignore file */ -import act, { getIsReactActEnvironment, setReactActEnvironment } from '../act'; +import { getIsReactActEnvironment, setReactActEnvironment } from '../act'; import { flushMicroTasks } from '../flush-micro-tasks'; -import { checkReactVersionAtLeast } from '../react-versions'; /** * Run given async callback with temporarily disabled `act` environment and flushes microtasks queue. @@ -11,30 +10,15 @@ import { checkReactVersionAtLeast } from '../react-versions'; * @returns Result of the callback */ export async function wrapAsync(callback: () => Promise): Promise { - if (checkReactVersionAtLeast(18, 0)) { - const previousActEnvironment = getIsReactActEnvironment(); - setReactActEnvironment(false); + const previousActEnvironment = getIsReactActEnvironment(); + setReactActEnvironment(false); - try { - const result = await callback(); - // Flush the microtask queue before restoring the `act` environment - await flushMicroTasks(); - return result; - } finally { - setReactActEnvironment(previousActEnvironment); - } + try { + const result = await callback(); + // Flush the microtask queue before restoring the `act` environment + await flushMicroTasks(); + return result; + } finally { + setReactActEnvironment(previousActEnvironment); } - - if (!checkReactVersionAtLeast(16, 9)) { - return callback(); - } - - // Wrapping with act for react version 16.9 to 17.x - let result: Result; - await act(async () => { - result = await callback(); - }); - - // Either we have result or `callback` threw error - return result!; } diff --git a/website/docs/MigrationV13.md b/website/docs/MigrationV13.md index b58c4f93f..285c801a9 100644 --- a/website/docs/MigrationV13.md +++ b/website/docs/MigrationV13.md @@ -13,6 +13,12 @@ Migration to React Native Testing Library version 13 from version 12.x. # Breaking changes +## Supported React and React Native versions + +This version supports only React 19 and corresponding React Native versions. If you use React 18 or 19, please use latest of v12 versions. + +[Note: at the moment there is no React Native for React 19, and React 19 is still in beta, so we use React 18.3 for the time being]. + ## Removed deprecated \*ByAccessibilityState queries This deprecated query has been removed as is typically too general to give meaningful results. Use one of the following options: diff --git a/yarn.lock b/yarn.lock index 135d9f118..cfea9c897 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,7 +42,27 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.24.7": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13": + version: 7.23.4 + resolution: "@babel/code-frame@npm:7.23.4" + dependencies: + "@babel/highlight": "npm:^7.23.4" + chalk: "npm:^2.4.2" + checksum: 10c0/2ef6f5e10004c4e8b755961b68570db0ea556ccb17a37c13a7f1fed1f4e273aed6c1ae1fcb86abb991620d8be083e1472a7ea5429f05bc342de54c027b07ea83 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.21.4": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" + dependencies: + "@babel/highlight": "npm:^7.23.4" + chalk: "npm:^2.4.2" + checksum: 10c0/a10e843595ddd9f97faa99917414813c06214f4d9205294013e20c70fbdf4f943760da37dec1d998bf3e6fc20fa2918a47c0e987a7e458663feb7698063ad7c6 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.24.7": version: 7.24.7 resolution: "@babel/code-frame@npm:7.24.7" dependencies: @@ -170,7 +190,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.6.2": +"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.2": version: 0.6.2 resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2" dependencies: @@ -228,7 +248,14 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.22.5 + resolution: "@babel/helper-plugin-utils@npm:7.22.5" + checksum: 10c0/d2c4bfe2fa91058bcdee4f4e57a3f4933aed7af843acfd169cd6179fab8d13c1d636474ecabb2af107dc77462c7e893199aa26632bac1c6d7e025a17cbb9d20d + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-plugin-utils@npm:7.24.8" checksum: 10c0/0376037f94a3bfe6b820a39f81220ac04f243eaee7193774b983e956c1750883ff236b30785795abbcda43fac3ece74750566830c2daa4d6e3870bb0dff34c2d @@ -288,6 +315,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" @@ -323,6 +357,17 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + checksum: 10c0/fbff9fcb2f5539289c3c097d130e852afd10d89a3a08ac0b5ebebbc055cc84a4bcc3dcfed463d488cde12dd0902ef1858279e31d7349b2e8cee43913744bda33 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -2886,9 +2931,9 @@ __metadata: typescript: "npm:^5.5.4" peerDependencies: jest: ">=28.0.0" - react: ">=16.8.0" - react-native: ">=0.59" - react-test-renderer: ">=16.8.0" + react: ">=18.2.0" + react-native: ">=0.73" + react-test-renderer: ">=18.2.0" peerDependenciesMeta: jest: optional: true @@ -3524,6 +3569,16 @@ __metadata: languageName: node linkType: hard +"array-buffer-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "array-buffer-byte-length@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + is-array-buffer: "npm:^3.0.1" + checksum: 10c0/12f84f6418b57a954caa41654e5e63e019142a4bbb2c6829ba86d1ba65d31ccfaf1461d1743556fd32b091fac34ff44d9dfbdb001402361c45c373b2c86f5c20 + languageName: node + linkType: hard + "array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" @@ -3627,6 +3682,21 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.2": + version: 1.0.2 + resolution: "arraybuffer.prototype.slice@npm:1.0.2" + dependencies: + array-buffer-byte-length: "npm:^1.0.0" + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + get-intrinsic: "npm:^1.2.1" + is-array-buffer: "npm:^3.0.2" + is-shared-array-buffer: "npm:^1.0.2" + checksum: 10c0/96b6e40e439678ffb7fa266398510074d33c3980fbb475490b69980cca60adec3b0777047ef377068a29862157f83edef42efc64ce48ce38977d04d68de5b7fb + languageName: node + linkType: hard + "arraybuffer.prototype.slice@npm:^1.0.3": version: 1.0.3 resolution: "arraybuffer.prototype.slice@npm:1.0.3" @@ -3705,6 +3775,13 @@ __metadata: languageName: node linkType: hard +"available-typed-arrays@npm:^1.0.5": + version: 1.0.5 + resolution: "available-typed-arrays@npm:1.0.5" + checksum: 10c0/c4df567ca72d2754a6cbad20088f5f98b1065b3360178169fa9b44ea101af62c0f423fc3854fa820fd6895b6b9171b8386e71558203103ff8fc2ad503fdcc660 + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -3778,7 +3855,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.10.1, babel-plugin-polyfill-corejs3@npm:^0.10.4": +"babel-plugin-polyfill-corejs3@npm:^0.10.1": version: 0.10.6 resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6" dependencies: @@ -3790,6 +3867,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.10.4": + version: 0.10.4 + resolution: "babel-plugin-polyfill-corejs3@npm:0.10.4" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.1" + core-js-compat: "npm:^3.36.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/31b92cd3dfb5b417da8dfcf0deaa4b8b032b476d7bb31ca51c66127cf25d41e89260e89d17bc004b2520faa38aa9515fafabf81d89f9d4976e9dc1163e4a7c41 + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.6.1": version: 0.6.2 resolution: "babel-plugin-polyfill-regenerator@npm:0.6.2" @@ -3934,6 +4023,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.23.0": + version: 4.23.0 + resolution: "browserslist@npm:4.23.0" + dependencies: + caniuse-lite: "npm:^1.0.30001587" + electron-to-chromium: "npm:^1.4.668" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.0.13" + bin: + browserslist: cli.js + checksum: 10c0/8e9cc154529062128d02a7af4d8adeead83ca1df8cd9ee65a88e2161039f3d68a4d40fea7353cab6bae4c16182dec2fdd9a1cf7dc2a2935498cee1af0e998943 + languageName: node + linkType: hard + "browserslist@npm:^4.23.1, browserslist@npm:^4.23.3": version: 4.23.3 resolution: "browserslist@npm:4.23.3" @@ -4045,6 +4148,17 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.4": + version: 1.0.5 + resolution: "call-bind@npm:1.0.5" + dependencies: + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.1" + set-function-length: "npm:^1.1.1" + checksum: 10c0/a6172c168fd6dacf744fcde745099218056bd755c50415b592655dcd6562157ed29f130f56c3f6db2250f67e4bd62e5c218cdc56d7bfd76e0bda50770fce2d10 + languageName: node + linkType: hard + "caller-callsite@npm:^2.0.0": version: 2.0.0 resolution: "caller-callsite@npm:2.0.0" @@ -4110,6 +4224,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001587": + version: 1.0.30001597 + resolution: "caniuse-lite@npm:1.0.30001597" + checksum: 10c0/32dc315ffafacc8167286c95b05f41b3ce2818314ea913ffed6ceb7b58c64c38365ec250114d1ecceac34f1c77e5af089479e54b160c4a89b88fd25a98851b78 + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001646": version: 1.0.30001651 resolution: "caniuse-lite@npm:1.0.30001651" @@ -4678,6 +4799,15 @@ __metadata: languageName: node linkType: hard +"core-js-compat@npm:^3.36.1": + version: 3.37.0 + resolution: "core-js-compat@npm:3.37.0" + dependencies: + browserslist: "npm:^4.23.0" + checksum: 10c0/ca6ba7d200f7a4a850fd5cba58b40ab78139d3f301bad7b53816eafe0cfb000523e72882069ddaba440794b950ed101225668bf7b97b73e54a5e3384a8215e03 + languageName: node + linkType: hard + "core-js-compat@npm:^3.37.1, core-js-compat@npm:^3.38.0": version: 3.38.0 resolution: "core-js-compat@npm:3.38.0" @@ -4968,6 +5098,17 @@ __metadata: languageName: node linkType: hard +"define-data-property@npm:^1.1.1": + version: 1.1.1 + resolution: "define-data-property@npm:1.1.1" + dependencies: + get-intrinsic: "npm:^1.2.1" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + checksum: 10c0/77ef6e0bceb515e05b5913ab635a84d537cee84f8a7c37c77fdcb31fc5b80f6dbe81b33375e4b67d96aa04e6a0d8d4ea099e431d83f089af8d93adfb584bcb94 + languageName: node + linkType: hard + "define-lazy-prop@npm:^3.0.0": version: 3.0.0 resolution: "define-lazy-prop@npm:3.0.0" @@ -5127,6 +5268,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.668": + version: 1.4.701 + resolution: "electron-to-chromium@npm:1.4.701" + checksum: 10c0/a98cffc2e0c8b43092a0acb17288b4d764600fb61df676ae50f35fb2350b3165158e98b72cac3619c638ee2fab965112e1d15f38a557a8d765e0f3fb958f0a5a + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.5.4": version: 1.5.6 resolution: "electron-to-chromium@npm:1.5.6" @@ -5229,7 +5377,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3": +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3": version: 1.23.3 resolution: "es-abstract@npm:1.23.3" dependencies: @@ -5283,6 +5431,53 @@ __metadata: languageName: node linkType: hard +"es-abstract@npm:^1.22.1": + version: 1.22.3 + resolution: "es-abstract@npm:1.22.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.0" + arraybuffer.prototype.slice: "npm:^1.0.2" + available-typed-arrays: "npm:^1.0.5" + call-bind: "npm:^1.0.5" + es-set-tostringtag: "npm:^2.0.1" + es-to-primitive: "npm:^1.2.1" + function.prototype.name: "npm:^1.1.6" + get-intrinsic: "npm:^1.2.2" + get-symbol-description: "npm:^1.0.0" + globalthis: "npm:^1.0.3" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + internal-slot: "npm:^1.0.5" + is-array-buffer: "npm:^3.0.2" + is-callable: "npm:^1.2.7" + is-negative-zero: "npm:^2.0.2" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.2" + is-string: "npm:^1.0.7" + is-typed-array: "npm:^1.1.12" + is-weakref: "npm:^1.0.2" + object-inspect: "npm:^1.13.1" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.4" + regexp.prototype.flags: "npm:^1.5.1" + safe-array-concat: "npm:^1.0.1" + safe-regex-test: "npm:^1.0.0" + string.prototype.trim: "npm:^1.2.8" + string.prototype.trimend: "npm:^1.0.7" + string.prototype.trimstart: "npm:^1.0.7" + typed-array-buffer: "npm:^1.0.0" + typed-array-byte-length: "npm:^1.0.0" + typed-array-byte-offset: "npm:^1.0.0" + typed-array-length: "npm:^1.0.4" + unbox-primitive: "npm:^1.0.2" + which-typed-array: "npm:^1.1.13" + checksum: 10c0/da31ec43b1c8eb47ba8a17693cac143682a1078b6c3cd883ce0e2062f135f532e93d873694ef439670e1f6ca03195118f43567ba6f33fb0d6c7daae750090236 + languageName: node + linkType: hard + "es-define-property@npm:^1.0.0": version: 1.0.0 resolution: "es-define-property@npm:1.0.0" @@ -5330,6 +5525,17 @@ __metadata: languageName: node linkType: hard +"es-set-tostringtag@npm:^2.0.1": + version: 2.0.2 + resolution: "es-set-tostringtag@npm:2.0.2" + dependencies: + get-intrinsic: "npm:^1.2.2" + has-tostringtag: "npm:^1.0.0" + hasown: "npm:^2.0.0" + checksum: 10c0/176d6bd1be31dd0145dcceee62bb78d4a5db7f81db437615a18308a6f62bcffe45c15081278413455e8cf0aad4ea99079de66f8de389605942dfdacbad74c2d5 + languageName: node + linkType: hard + "es-set-tostringtag@npm:^2.0.3": version: 2.0.3 resolution: "es-set-tostringtag@npm:2.0.3" @@ -6234,6 +6440,18 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.2": + version: 1.2.2 + resolution: "get-intrinsic@npm:1.2.2" + dependencies: + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10c0/4e7fb8adc6172bae7c4fe579569b4d5238b3667c07931cd46b4eee74bbe6ff6b91329bec311a638d8e60f5b51f44fe5445693c6be89ae88d4b5c49f7ff12db0b + languageName: node + linkType: hard + "get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" @@ -6268,6 +6486,16 @@ __metadata: languageName: node linkType: hard +"get-symbol-description@npm:^1.0.0": + version: 1.0.0 + resolution: "get-symbol-description@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.1" + checksum: 10c0/23bc3b44c221cdf7669a88230c62f4b9e30393b61eb21ba4400cb3e346801bd8f95fe4330ee78dbae37aecd874646d53e3e76a17a654d0c84c77f6690526d6bb + languageName: node + linkType: hard + "get-symbol-description@npm:^1.0.2": version: 1.0.2 resolution: "get-symbol-description@npm:1.0.2" @@ -6595,6 +6823,13 @@ __metadata: languageName: node linkType: hard +"hermes-estree@npm:0.19.1": + version: 0.19.1 + resolution: "hermes-estree@npm:0.19.1" + checksum: 10c0/98c79807c15146c745aca7a9c74b9f1ba20a463c8b9f058caed9b3f2741fc4a8609e7e4c06d163f67d819db35cb6871fc7b25085bb9a084bc53d777f67d9d620 + languageName: node + linkType: hard + "hermes-estree@npm:0.22.0": version: 0.22.0 resolution: "hermes-estree@npm:0.22.0" @@ -6602,10 +6837,12 @@ __metadata: languageName: node linkType: hard -"hermes-estree@npm:0.23.0": - version: 0.23.0 - resolution: "hermes-estree@npm:0.23.0" - checksum: 10c0/5505fdefc119c516b92adbf7b89cc25768ff5e99b0faca3a5ce4af79cc51feef3236227774ee2f6c45bbe1d9a3fa33786e660195a264697171a85b707bc2cec8 +"hermes-parser@npm:0.19.1": + version: 0.19.1 + resolution: "hermes-parser@npm:0.19.1" + dependencies: + hermes-estree: "npm:0.19.1" + checksum: 10c0/940ccef90673b8e905016332d2660ae00ad747e2d32c694a52dce4ea220835dc1bae299554a7a8eeccb449561065bd97f3690363c087fbf69ad7cbff2deeec35 languageName: node linkType: hard @@ -6618,15 +6855,6 @@ __metadata: languageName: node linkType: hard -"hermes-parser@npm:0.23.0": - version: 0.23.0 - resolution: "hermes-parser@npm:0.23.0" - dependencies: - hermes-estree: "npm:0.23.0" - checksum: 10c0/a4ca7a66dd8cc65dfc4bb223f696e62ac06f0f32fe8b5889a03ea082291636696e36b1e1593885a19dc2a624d78a96a82cd046fef093de812b27e333350fceea - languageName: node - linkType: hard - "hosted-git-info@npm:^4.0.1": version: 4.1.0 resolution: "hosted-git-info@npm:4.1.0" @@ -6692,7 +6920,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.3, https-proxy-agent@npm:^7.0.5": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": version: 7.0.5 resolution: "https-proxy-agent@npm:7.0.5" dependencies: @@ -6702,6 +6930,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.3": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10c0/bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b + languageName: node + linkType: hard + "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" @@ -6870,6 +7108,17 @@ __metadata: languageName: node linkType: hard +"internal-slot@npm:^1.0.5": + version: 1.0.6 + resolution: "internal-slot@npm:1.0.6" + dependencies: + get-intrinsic: "npm:^1.2.2" + hasown: "npm:^2.0.0" + side-channel: "npm:^1.0.4" + checksum: 10c0/aa37cafc8ffbf513a340de58f40d5017b4949d99722d7e4f0e24b182455bdd258000d4bb1d7b4adcf9f8979b97049b99fe9defa9db8e18a78071d2637ac143fb + languageName: node + linkType: hard + "internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" @@ -6907,6 +7156,17 @@ __metadata: languageName: node linkType: hard +"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": + version: 3.0.2 + resolution: "is-array-buffer@npm:3.0.2" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.0" + is-typed-array: "npm:^1.1.10" + checksum: 10c0/40ed13a5f5746ac3ae2f2e463687d9b5a3f5fd0086f970fb4898f0253c2a5ec2e3caea2d664dd8f54761b1c1948609702416921a22faebe160c7640a9217c80e + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" @@ -6980,11 +7240,11 @@ __metadata: linkType: hard "is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1, is-core-module@npm:^2.5.0": - version: 2.15.0 - resolution: "is-core-module@npm:2.15.0" + version: 2.13.1 + resolution: "is-core-module@npm:2.13.1" dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/da161f3d9906f459486da65609b2f1a2dfdc60887c689c234d04e88a062cb7920fa5be5fb7ab08dc43b732929653c4135ef05bf77888ae2a9040ce76815eb7b1 + hasown: "npm:^2.0.0" + checksum: 10c0/2cba9903aaa52718f11c4896dabc189bab980870aae86a62dc0d5cedb546896770ee946fb14c84b7adf0735f5eaea4277243f1b95f5cefa90054f92fbcac2518 languageName: node linkType: hard @@ -7144,6 +7404,13 @@ __metadata: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.2": + version: 2.0.2 + resolution: "is-negative-zero@npm:2.0.2" + checksum: 10c0/eda024c158f70f2017f3415e471b818d314da5ef5be68f801b16314d4a4b6304a74cbed778acf9e2f955bb9c1c5f2935c1be0c7c99e1ad12286f45366217b6a3 + languageName: node + linkType: hard + "is-negative-zero@npm:^2.0.3": version: 2.0.3 resolution: "is-negative-zero@npm:2.0.3" @@ -7294,6 +7561,15 @@ __metadata: languageName: node linkType: hard +"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.12, is-typed-array@npm:^1.1.9": + version: 1.1.12 + resolution: "is-typed-array@npm:1.1.12" + dependencies: + which-typed-array: "npm:^1.1.11" + checksum: 10c0/9863e9cc7223c6fc1c462a2c3898a7beff6b41b1ee0fabb03b7d278ae7de670b5bcbc8627db56bb66ed60902fa37d53fe5cce0fd2f7d73ac64fe5da6f409b6ae + languageName: node + linkType: hard + "is-typed-array@npm:^1.1.13": version: 1.1.13 resolution: "is-typed-array@npm:1.1.13" @@ -8417,7 +8693,14 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": +"lru-cache@npm:^10.0.1": + version: 10.1.0 + resolution: "lru-cache@npm:10.1.0" + checksum: 10c0/778bc8b2626daccd75f24c4b4d10632496e21ba064b126f526c626fbdbc5b28c472013fccd45d7646b9e1ef052444824854aed617b59cd570d01a8b7d651fc1e + languageName: node + linkType: hard + +"lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb @@ -8573,73 +8856,66 @@ __metadata: languageName: node linkType: hard -"metro-babel-transformer@npm:0.80.10": - version: 0.80.10 - resolution: "metro-babel-transformer@npm:0.80.10" +"metro-babel-transformer@npm:0.80.6": + version: 0.80.6 + resolution: "metro-babel-transformer@npm:0.80.6" dependencies: "@babel/core": "npm:^7.20.0" - flow-enums-runtime: "npm:^0.0.6" - hermes-parser: "npm:0.23.0" + hermes-parser: "npm:0.19.1" nullthrows: "npm:^1.1.1" - checksum: 10c0/e82909185b67997ec3cea2c743c647706703f90fe9ece143f14991895e0de4279d8f16086bc626a091a94a76ed24ea6def00fa7815cfa917a6dae9d5675b118e + checksum: 10c0/7198efcbbecd67daced3395923edd3a647ac933566322ed66a91e30cdf725f6b0876391fbc77bf22b49d596ec746250d8d1286b20e28cd12de3ba76acc7679ac languageName: node linkType: hard -"metro-cache-key@npm:0.80.10": - version: 0.80.10 - resolution: "metro-cache-key@npm:0.80.10" - dependencies: - flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/7fd792bc82048c5f3754413aac8a129b2387cb9cdae5792a05f2780618d7b3f67bb3ea97ac147e1a1570f29bae25aaf0badf771675e17830d1aec5ba58ab4d10 +"metro-cache-key@npm:0.80.6": + version: 0.80.6 + resolution: "metro-cache-key@npm:0.80.6" + checksum: 10c0/af62885489d07aa767146c174b7520d7d636f085dd272fdf1990e6dbb0cb095a04151f12224bd36002447126a8f98e42b27fe38c069afa6ee09b36b7cb40ea32 languageName: node linkType: hard -"metro-cache@npm:0.80.10": - version: 0.80.10 - resolution: "metro-cache@npm:0.80.10" +"metro-cache@npm:0.80.6": + version: 0.80.6 + resolution: "metro-cache@npm:0.80.6" dependencies: - exponential-backoff: "npm:^3.1.1" - flow-enums-runtime: "npm:^0.0.6" - metro-core: "npm:0.80.10" - checksum: 10c0/c981b61d98e0c48cb51da17023b6654f4f6afd0b0587886201df6dd1d324e812b87339a0190336900bd659a1eccb938f78b5c3093a928e13077d3f8dfb9c1e64 + metro-core: "npm:0.80.6" + rimraf: "npm:^3.0.2" + checksum: 10c0/7f7459e822b7c2a4c7aeddde0f40a651b4d64aa8f562acd8bb7e987de4a27fc996eee169908cf81062febe2b7a6fb80c1dbdf63f675ce3f6e97a3bb58c409a44 languageName: node linkType: hard -"metro-config@npm:0.80.10, metro-config@npm:^0.80.3": - version: 0.80.10 - resolution: "metro-config@npm:0.80.10" +"metro-config@npm:0.80.6, metro-config@npm:^0.80.3": + version: 0.80.6 + resolution: "metro-config@npm:0.80.6" dependencies: connect: "npm:^3.6.5" cosmiconfig: "npm:^5.0.5" - flow-enums-runtime: "npm:^0.0.6" jest-validate: "npm:^29.6.3" - metro: "npm:0.80.10" - metro-cache: "npm:0.80.10" - metro-core: "npm:0.80.10" - metro-runtime: "npm:0.80.10" - checksum: 10c0/6953ab4b766d6c71e4e68332c6c121121f62fb904ce64579cddfd31c746ae308b3958332ff60e3ce242ffe8ce13390e4665128c9d61099ac327676fb5fd65fe5 + metro: "npm:0.80.6" + metro-cache: "npm:0.80.6" + metro-core: "npm:0.80.6" + metro-runtime: "npm:0.80.6" + checksum: 10c0/133a281593a16789409c58dfd437a97cdf4f7393ea4042dbf42d3a47fa5650840996e3b24059bc82d98c0171752e8ac617e6536bc833d3dabbcdd480480def1b languageName: node linkType: hard -"metro-core@npm:0.80.10, metro-core@npm:^0.80.3": - version: 0.80.10 - resolution: "metro-core@npm:0.80.10" +"metro-core@npm:0.80.6, metro-core@npm:^0.80.3": + version: 0.80.6 + resolution: "metro-core@npm:0.80.6" dependencies: - flow-enums-runtime: "npm:^0.0.6" lodash.throttle: "npm:^4.1.1" - metro-resolver: "npm:0.80.10" - checksum: 10c0/ae2d3d81422c0e155ec1345a5361fdac3193d9578af4e84b3eaee1dbdf06258f48c74919356e20568442ef3be6b1ff91dff7e88648d6ea4b6fc939aa3e41cdcb + metro-resolver: "npm:0.80.6" + checksum: 10c0/5aa828304c20db5109993980bd2a3805813ad005b3a051a7cad5475d71b4ceed05ca9abdf5846dc4780914fe10e965bcfd8d828e62f83b96c9a9dae015abb762 languageName: node linkType: hard -"metro-file-map@npm:0.80.10": - version: 0.80.10 - resolution: "metro-file-map@npm:0.80.10" +"metro-file-map@npm:0.80.6": + version: 0.80.6 + resolution: "metro-file-map@npm:0.80.6" dependencies: anymatch: "npm:^3.0.3" debug: "npm:^2.2.0" fb-watchman: "npm:^2.0.0" - flow-enums-runtime: "npm:^0.0.6" fsevents: "npm:^2.3.2" graceful-fs: "npm:^4.2.4" invariant: "npm:^2.2.4" @@ -8651,111 +8927,103 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: 10c0/af4003b9cb6545324c8b74f1b7293ab7d0db73f6c60ed42618754e5a3b0602d4f35d4054fe0671ebb50739ee6bd7074f5bc642840de1dcd803e8053d30b4b3fc + checksum: 10c0/745bc9a679a9713594be56c43f261290c8441761e1b61df0e7a160fa0c4be326a57c63f69a61d39cab0e4f77c119e4eb18361df3c0bb840f71486bf9b58779b1 languageName: node linkType: hard -"metro-minify-terser@npm:0.80.10": - version: 0.80.10 - resolution: "metro-minify-terser@npm:0.80.10" +"metro-minify-terser@npm:0.80.6": + version: 0.80.6 + resolution: "metro-minify-terser@npm:0.80.6" dependencies: - flow-enums-runtime: "npm:^0.0.6" terser: "npm:^5.15.0" - checksum: 10c0/dd204852a109ee65d356d8c5ca94301ec84578599d2c30123113dbf09ef0bc6c3214f1dc5767a3e9483db5cd0ef0502e03d2a22451485ce93a786a4f14786226 + checksum: 10c0/97b6cd8d60866818f1d0b96755b2a1b22a58d4db0ca10f528f8b74abaa12ba80d0904dd1e3a2acf49001c84224e9f3cd78fe0ae0386855f4898d4eb3110515bc languageName: node linkType: hard -"metro-resolver@npm:0.80.10": - version: 0.80.10 - resolution: "metro-resolver@npm:0.80.10" - dependencies: - flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/61d6b984e1e377b4369aed7ac51c42c76c8e5c6acf0101b740cc2eb1081980dd11625f76cc4367f627cf2363d405d6091adcddda927ecee8e0a6a769fba79413 +"metro-resolver@npm:0.80.6": + version: 0.80.6 + resolution: "metro-resolver@npm:0.80.6" + checksum: 10c0/ae8562d662568df52e72335f02dd6f30939e5d394d710d370771fae2206fcb1af348acb8bdea51c0d4f345ef808ae36bfb122d19f3f7a796330e49ce2d9c4168 languageName: node linkType: hard -"metro-runtime@npm:0.80.10, metro-runtime@npm:^0.80.3": - version: 0.80.10 - resolution: "metro-runtime@npm:0.80.10" +"metro-runtime@npm:0.80.6, metro-runtime@npm:^0.80.3": + version: 0.80.6 + resolution: "metro-runtime@npm:0.80.6" dependencies: "@babel/runtime": "npm:^7.0.0" - flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/a0da1e9eb46df31604fb99d4f694acf65ee60f973306df51c00a3fcfd7f3253ed9dfd4279e53bd6abaf6a918748254b62a784e5a952e333381cbd4377fa69470 + checksum: 10c0/1291e7739ad323d821b332d7bd3d6ddb0835dc77150e9d12f179423390590e8aa5e4a8bcb18e18c55a0c77ab15da7c66fa7caa1b753395f563c0e1309e3c8221 languageName: node linkType: hard -"metro-source-map@npm:0.80.10, metro-source-map@npm:^0.80.3": - version: 0.80.10 - resolution: "metro-source-map@npm:0.80.10" +"metro-source-map@npm:0.80.6, metro-source-map@npm:^0.80.3": + version: 0.80.6 + resolution: "metro-source-map@npm:0.80.6" dependencies: "@babel/traverse": "npm:^7.20.0" "@babel/types": "npm:^7.20.0" - flow-enums-runtime: "npm:^0.0.6" invariant: "npm:^2.2.4" - metro-symbolicate: "npm:0.80.10" + metro-symbolicate: "npm:0.80.6" nullthrows: "npm:^1.1.1" - ob1: "npm:0.80.10" + ob1: "npm:0.80.6" source-map: "npm:^0.5.6" vlq: "npm:^1.0.0" - checksum: 10c0/33f123bcc8d26e47789386c50c2eb4a474cda329d77933651580f5ce7e6f8486b0ae89a0230b058bf082d30ec65bb3b2cf4a47dfaa84c433cf04866ce110670a + checksum: 10c0/851ecac99ec22c7ed941222fa7989ca2aee3fd4e66561d26b4facd7ccf9f5b8a84a0a453df3b5b1e8e58af3ffc7c96cd65c4a52526715b2ec080906ffec18f0e languageName: node linkType: hard -"metro-symbolicate@npm:0.80.10": - version: 0.80.10 - resolution: "metro-symbolicate@npm:0.80.10" +"metro-symbolicate@npm:0.80.6": + version: 0.80.6 + resolution: "metro-symbolicate@npm:0.80.6" dependencies: - flow-enums-runtime: "npm:^0.0.6" invariant: "npm:^2.2.4" - metro-source-map: "npm:0.80.10" + metro-source-map: "npm:0.80.6" nullthrows: "npm:^1.1.1" source-map: "npm:^0.5.6" through2: "npm:^2.0.1" vlq: "npm:^1.0.0" bin: metro-symbolicate: src/index.js - checksum: 10c0/f67d4fd43a376e594fc007a8e4d7fe39dba08d93949ed8e215c1393b96f1fad936ac4b65948da9add7034e233e43e9abdc8647d7059ea0f59701f46a6a63e6de + checksum: 10c0/35ffacc0519b05cb0ede0e8f20a0d4e8f6d716503475d17d342e9f4adbf03a5aab8d170f34766cd6e5a2134be6b478989a2b84e1870e64f1244c568ce129665e languageName: node linkType: hard -"metro-transform-plugins@npm:0.80.10": - version: 0.80.10 - resolution: "metro-transform-plugins@npm:0.80.10" +"metro-transform-plugins@npm:0.80.6": + version: 0.80.6 + resolution: "metro-transform-plugins@npm:0.80.6" dependencies: "@babel/core": "npm:^7.20.0" "@babel/generator": "npm:^7.20.0" "@babel/template": "npm:^7.0.0" "@babel/traverse": "npm:^7.20.0" - flow-enums-runtime: "npm:^0.0.6" nullthrows: "npm:^1.1.1" - checksum: 10c0/1b0ad0d937b1166f5ec721faf227291dd158c4a756279b890748977a3cd9604f2758a4a68c554751eb5c439744dc62187e4fbb6f6d6e137d899546b02d99851c + checksum: 10c0/60464719b9e25bef7d6bf9667fc8e3c5f9ded67f151cc21a815e475c05fc7ae4b3bc9f7ddbf680890a234f9ba8b418745056ac104bca8a6b41c10e6654228dc3 languageName: node linkType: hard -"metro-transform-worker@npm:0.80.10": - version: 0.80.10 - resolution: "metro-transform-worker@npm:0.80.10" +"metro-transform-worker@npm:0.80.6": + version: 0.80.6 + resolution: "metro-transform-worker@npm:0.80.6" dependencies: "@babel/core": "npm:^7.20.0" "@babel/generator": "npm:^7.20.0" "@babel/parser": "npm:^7.20.0" "@babel/types": "npm:^7.20.0" - flow-enums-runtime: "npm:^0.0.6" - metro: "npm:0.80.10" - metro-babel-transformer: "npm:0.80.10" - metro-cache: "npm:0.80.10" - metro-cache-key: "npm:0.80.10" - metro-minify-terser: "npm:0.80.10" - metro-source-map: "npm:0.80.10" - metro-transform-plugins: "npm:0.80.10" + metro: "npm:0.80.6" + metro-babel-transformer: "npm:0.80.6" + metro-cache: "npm:0.80.6" + metro-cache-key: "npm:0.80.6" + metro-minify-terser: "npm:0.80.6" + metro-source-map: "npm:0.80.6" + metro-transform-plugins: "npm:0.80.6" nullthrows: "npm:^1.1.1" - checksum: 10c0/ff248b170a0fea2ae79741d5eaef43e38de986b59ffeed58bf8e2c27a9274cf1ba27e89838876a8320c39785e965a57f7e3caf260b33c3f6812c8c7843b6fecb + checksum: 10c0/532081e3fb67a03aa8ba3d227eb7f086e403c96614f96c2446467ee0b0887cb062bd046840f25223234300d6f2db7ac5219d17552234a74ad7876043d4b1d633 languageName: node linkType: hard -"metro@npm:0.80.10, metro@npm:^0.80.3": - version: 0.80.10 - resolution: "metro@npm:0.80.10" +"metro@npm:0.80.6, metro@npm:^0.80.3": + version: 0.80.6 + resolution: "metro@npm:0.80.6" dependencies: "@babel/code-frame": "npm:^7.0.0" "@babel/core": "npm:^7.20.0" @@ -8771,38 +9039,38 @@ __metadata: debug: "npm:^2.2.0" denodeify: "npm:^1.2.1" error-stack-parser: "npm:^2.0.6" - flow-enums-runtime: "npm:^0.0.6" graceful-fs: "npm:^4.2.4" - hermes-parser: "npm:0.23.0" + hermes-parser: "npm:0.19.1" image-size: "npm:^1.0.2" invariant: "npm:^2.2.4" jest-worker: "npm:^29.6.3" jsc-safe-url: "npm:^0.2.2" lodash.throttle: "npm:^4.1.1" - metro-babel-transformer: "npm:0.80.10" - metro-cache: "npm:0.80.10" - metro-cache-key: "npm:0.80.10" - metro-config: "npm:0.80.10" - metro-core: "npm:0.80.10" - metro-file-map: "npm:0.80.10" - metro-resolver: "npm:0.80.10" - metro-runtime: "npm:0.80.10" - metro-source-map: "npm:0.80.10" - metro-symbolicate: "npm:0.80.10" - metro-transform-plugins: "npm:0.80.10" - metro-transform-worker: "npm:0.80.10" + metro-babel-transformer: "npm:0.80.6" + metro-cache: "npm:0.80.6" + metro-cache-key: "npm:0.80.6" + metro-config: "npm:0.80.6" + metro-core: "npm:0.80.6" + metro-file-map: "npm:0.80.6" + metro-resolver: "npm:0.80.6" + metro-runtime: "npm:0.80.6" + metro-source-map: "npm:0.80.6" + metro-symbolicate: "npm:0.80.6" + metro-transform-plugins: "npm:0.80.6" + metro-transform-worker: "npm:0.80.6" mime-types: "npm:^2.1.27" node-fetch: "npm:^2.2.0" nullthrows: "npm:^1.1.1" + rimraf: "npm:^3.0.2" serialize-error: "npm:^2.1.0" source-map: "npm:^0.5.6" strip-ansi: "npm:^6.0.0" throat: "npm:^5.0.0" - ws: "npm:^7.5.10" + ws: "npm:^7.5.1" yargs: "npm:^17.6.2" bin: metro: src/cli.js - checksum: 10c0/e6cc58eb901dc1ea9e91069ba30f1d5e83460144a452d1977d1bc37811d560269f6e17ad655ffc9d1795495c7afb269cfa4e0630178ca436f7c685681856a57c + checksum: 10c0/eb810658e1b746326a729fbdb3a32873e6b7c6510b12929b34c02ad6fb0e86203b1a198f1a1a97e8eff5bd0b5eaf0e198a3134de4467a6ffa5830972a1f036fa languageName: node linkType: hard @@ -9195,6 +9463,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 10c0/199fc93773ae70ec9969bc6d5ac5b2bbd6eb986ed1907d751f411fef3ede0e4bfdb45ceb43711f8078bea237b6036db8b1bf208f6ff2b70c7d615afd157f3ab9 + languageName: node + linkType: hard + "node-releases@npm:^2.0.18": version: 2.0.18 resolution: "node-releases@npm:2.0.18" @@ -9282,12 +9557,10 @@ __metadata: languageName: node linkType: hard -"ob1@npm:0.80.10": - version: 0.80.10 - resolution: "ob1@npm:0.80.10" - dependencies: - flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/38c088d4d4fd673fafbc063b6100f8fce2cffb5023c8dcda82b78d13238c78adf600def93936daa1826595cb4035d72ccfb1be696b864f881dbb063a737482ed +"ob1@npm:0.80.6": + version: 0.80.6 + resolution: "ob1@npm:0.80.6" + checksum: 10c0/c86e9f1152d3de399dcf7e720be15ab4096a17b5a320e373052e01955c9839ab3db3a9bb194c83610ebc907dce3b7e98dc28f4651a40615c42b17057a81c6285 languageName: node linkType: hard @@ -9299,9 +9572,9 @@ __metadata: linkType: hard "object-inspect@npm:^1.13.1": - version: 1.13.2 - resolution: "object-inspect@npm:1.13.2" - checksum: 10c0/b97835b4c91ec37b5fd71add84f21c3f1047d1d155d00c0fcd6699516c256d4fcc6ff17a1aced873197fe447f91a3964178fd2a67a1ee2120cdaf60e81a050b4 + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 10c0/fad603f408e345c82e946abdf4bfd774260a5ed3e5997a0b057c44153ac32c7271ff19e3a5ae39c858da683ba045ccac2f65245c12763ce4e8594f818f4a648d languageName: node linkType: hard @@ -10383,6 +10656,17 @@ __metadata: languageName: node linkType: hard +"regexp.prototype.flags@npm:^1.5.1": + version: 1.5.1 + resolution: "regexp.prototype.flags@npm:1.5.1" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + set-function-name: "npm:^2.0.0" + checksum: 10c0/1de7d214c0a726c7c874a7023e47b0e27b9f7fdb64175bfe1861189de1704aaeca05c3d26c35aa375432289b99946f3cf86651a92a8f7601b90d8c226a23bcd8 + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" @@ -10688,6 +10972,18 @@ __metadata: languageName: node linkType: hard +"safe-array-concat@npm:^1.0.1": + version: 1.0.1 + resolution: "safe-array-concat@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.1" + has-symbols: "npm:^1.0.3" + isarray: "npm:^2.0.5" + checksum: 10c0/4b15ce5fce5ce4d7e744a63592cded88d2f27806ed229eadb2e42629cbcd40e770f7478608e75f455e7fe341acd8c0a01bdcd7146b10645ea7411c5e3c1d1dd8 + languageName: node + linkType: hard + "safe-array-concat@npm:^1.1.2": version: 1.1.2 resolution: "safe-array-concat@npm:1.1.2" @@ -10714,6 +11010,17 @@ __metadata: languageName: node linkType: hard +"safe-regex-test@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-regex-test@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.3" + is-regex: "npm:^1.1.4" + checksum: 10c0/14a81a7e683f97b2d6e9c8be61fddcf8ed7a02f4e64a825515f96bb1738eb007145359313741d2704d28b55b703a0f6300c749dde7c1dbc13952a2b85048ede2 + languageName: node + linkType: hard + "safe-regex-test@npm:^1.0.3": version: 1.0.3 resolution: "safe-regex-test@npm:1.0.3" @@ -10796,7 +11103,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.3, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2": +"semver@npm:^7.1.3, semver@npm:^7.6.0, semver@npm:^7.6.2": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -10805,6 +11112,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 10c0/5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e + languageName: node + linkType: hard + "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -10852,6 +11170,18 @@ __metadata: languageName: node linkType: hard +"set-function-length@npm:^1.1.1": + version: 1.1.1 + resolution: "set-function-length@npm:1.1.1" + dependencies: + define-data-property: "npm:^1.1.1" + get-intrinsic: "npm:^1.2.1" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + checksum: 10c0/a29e255c116c29e3323b851c4f46c58c91be9bb8b065f191e2ea1807cb2c839df56e3175732a498e0c6d54626ba6b6fef896bf699feb7ab70c42dc47eb247c95 + languageName: node + linkType: hard + "set-function-length@npm:^1.2.1": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" @@ -10866,6 +11196,17 @@ __metadata: languageName: node linkType: hard +"set-function-name@npm:^2.0.0": + version: 2.0.1 + resolution: "set-function-name@npm:2.0.1" + dependencies: + define-data-property: "npm:^1.0.1" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.0" + checksum: 10c0/6be7d3e15be47f4db8a5a563a35c60b5e7c4af91cc900e8972ffad33d3aaa227900faa55f60121cdb04b85866a734bb7fe4cd91f654c632861cc86121a48312a + languageName: node + linkType: hard + "set-function-name@npm:^2.0.1, set-function-name@npm:^2.0.2": version: 2.0.2 resolution: "set-function-name@npm:2.0.2" @@ -11254,6 +11595,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trim@npm:^1.2.8": + version: 1.2.8 + resolution: "string.prototype.trim@npm:1.2.8" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/4f76c583908bcde9a71208ddff38f67f24c9ec8093631601666a0df8b52fad44dad2368c78895ce83eb2ae8e7068294cc96a02fc971ab234e4d5c9bb61ea4e34 + languageName: node + linkType: hard + "string.prototype.trim@npm:^1.2.9": version: 1.2.9 resolution: "string.prototype.trim@npm:1.2.9" @@ -11266,6 +11618,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimend@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimend@npm:1.0.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/53c24911c7c4d8d65f5ef5322de23a3d5b6b4db73273e05871d5ab4571ae5638f38f7f19d71d09116578fb060e5a145cc6a208af2d248c8baf7a34f44d32ce57 + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.8": version: 1.0.8 resolution: "string.prototype.trimend@npm:1.0.8" @@ -11277,6 +11640,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimstart@npm:1.0.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/0bcf391b41ea16d4fda9c9953d0a7075171fe090d33b4cf64849af94944c50862995672ac03e0c5dba2940a213ad7f53515a668dac859ce22a0276289ae5cf4f + languageName: node + linkType: hard + "string.prototype.trimstart@npm:^1.0.8": version: 1.0.8 resolution: "string.prototype.trimstart@npm:1.0.8" @@ -11701,6 +12075,17 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-buffer@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.1" + is-typed-array: "npm:^1.1.10" + checksum: 10c0/ebad66cdf00c96b1395dffc7873169cf09801fca5954507a484f41f253feb1388d815db297b0b3bb8ce7421eac6f7ff45e2ec68450a3d68408aa4ae02fcf3a6c + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-buffer@npm:1.0.2" @@ -11712,6 +12097,18 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-length@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.2" + for-each: "npm:^0.3.3" + has-proto: "npm:^1.0.1" + is-typed-array: "npm:^1.1.10" + checksum: 10c0/6696435d53ce0e704ff6760c57ccc35138aec5f87859e03eb2a3246336d546feae367952dbc918116f3f0dffbe669734e3cbd8960283c2fa79aac925db50d888 + languageName: node + linkType: hard + "typed-array-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "typed-array-byte-length@npm:1.0.1" @@ -11725,6 +12122,19 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-offset@npm:1.0.0" + dependencies: + available-typed-arrays: "npm:^1.0.5" + call-bind: "npm:^1.0.2" + for-each: "npm:^0.3.3" + has-proto: "npm:^1.0.1" + is-typed-array: "npm:^1.1.10" + checksum: 10c0/4036ce007ae9752931bed3dd61e0d6de2a3e5f6a5a85a05f3adb35388d2c0728f9b1a1e638d75579f168e49c289bfb5417f00e96d4ab081f38b647fc854ff7a5 + languageName: node + linkType: hard + "typed-array-byte-offset@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-byte-offset@npm:1.0.2" @@ -11739,6 +12149,17 @@ __metadata: languageName: node linkType: hard +"typed-array-length@npm:^1.0.4": + version: 1.0.4 + resolution: "typed-array-length@npm:1.0.4" + dependencies: + call-bind: "npm:^1.0.2" + for-each: "npm:^0.3.3" + is-typed-array: "npm:^1.1.9" + checksum: 10c0/c5163c0103d07fefc8a2ad0fc151f9ca9a1f6422098c00f695d55f9896e4d63614cd62cf8d8a031c6cee5f418e8980a533796597174da4edff075b3d275a7e23 + languageName: node + linkType: hard + "typed-array-length@npm:^1.0.6": version: 1.0.6 resolution: "typed-array-length@npm:1.0.6" @@ -11910,6 +12331,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" + dependencies: + escalade: "npm:^3.1.1" + picocolors: "npm:^1.0.0" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/e52b8b521c78ce1e0c775f356cd16a9c22c70d25f3e01180839c407a5dc787fb05a13f67560cbaf316770d26fa99f78f1acd711b1b54a4f35d4820d4ea7136e6 + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" @@ -12110,6 +12545,19 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.11, which-typed-array@npm:^1.1.13": + version: 1.1.13 + resolution: "which-typed-array@npm:1.1.13" + dependencies: + available-typed-arrays: "npm:^1.0.5" + call-bind: "npm:^1.0.4" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/9f5f1c42918df3d5b91c4315ed0051d5d874370998bf095c9ae0df374f0881f85094e3c384b8fb08ab7b4d4f54ba81c0aff75da6226e7c0589b83dfbec1cd4c9 + languageName: node + linkType: hard + "which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" @@ -12266,7 +12714,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7, ws@npm:^7.5.10": +"ws@npm:^7": version: 7.5.10 resolution: "ws@npm:7.5.10" peerDependencies: @@ -12281,6 +12729,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^7.5.1": + version: 7.5.9 + resolution: "ws@npm:7.5.9" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/aec4ef4eb65821a7dde7b44790f8699cfafb7978c9b080f6d7a98a7f8fc0ce674c027073a78574c94786ba7112cc90fa2cc94fc224ceba4d4b1030cff9662494 + languageName: node + linkType: hard + "xdg-basedir@npm:^5.0.1, xdg-basedir@npm:^5.1.0": version: 5.1.0 resolution: "xdg-basedir@npm:5.1.0" From b5cfb98854dbedd94ccd1105a9348afb50a14b5e Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 8 May 2024 16:40:12 +0200 Subject: [PATCH 03/22] [v13] chore: remove debug shallow (#1601) --- .../__snapshots__/render-debug.test.tsx.snap | 100 ------------------ src/__tests__/render-debug.test.tsx | 14 ++- src/__tests__/screen.test.tsx | 1 - src/config.ts | 2 +- src/helpers/debug-shallow.ts | 22 ---- src/helpers/{debug-deep.ts => debug.ts} | 2 +- src/render.tsx | 17 ++- src/screen.ts | 1 - src/shallow.ts | 18 ---- typings/index.flow.js | 1 - website/docs/MigrationV13.md | 6 +- 11 files changed, 18 insertions(+), 166 deletions(-) delete mode 100644 src/helpers/debug-shallow.ts rename src/helpers/{debug-deep.ts => debug.ts} (95%) delete mode 100644 src/shallow.ts diff --git a/src/__tests__/__snapshots__/render-debug.test.tsx.snap b/src/__tests__/__snapshots__/render-debug.test.tsx.snap index 25106295b..8e3c10779 100644 --- a/src/__tests__/__snapshots__/render-debug.test.tsx.snap +++ b/src/__tests__/__snapshots__/render-debug.test.tsx.snap @@ -367,106 +367,6 @@ exports[`debug: another custom message 1`] = ` " `; -exports[`debug: shallow 1`] = ` -" - - Is the banana fresh? - - - not fresh - - - - - - - Change freshness! - - - First Text - - - Second Text - - - 0 - -" -`; - -exports[`debug: shallow with message 1`] = ` -"my other custom message - - - - Is the banana fresh? - - - not fresh - - - - - - - Change freshness! - - - First Text - - - Second Text - - - 0 - -" -`; - exports[`debug: with message 1`] = ` "my custom message diff --git a/src/__tests__/render-debug.test.tsx b/src/__tests__/render-debug.test.tsx index 9a57c8144..0b5bd462b 100644 --- a/src/__tests__/render-debug.test.tsx +++ b/src/__tests__/render-debug.test.tsx @@ -97,21 +97,19 @@ test('debug', () => { screen.debug(); screen.debug('my custom message'); - screen.debug.shallow(); - screen.debug.shallow('my other custom message'); screen.debug({ message: 'another custom message' }); const mockCalls = jest.mocked(console.log).mock.calls; expect(stripAnsi(mockCalls[0][0])).toMatchSnapshot(); expect(stripAnsi(mockCalls[1][0] + mockCalls[1][1])).toMatchSnapshot('with message'); - expect(stripAnsi(mockCalls[2][0])).toMatchSnapshot('shallow'); - expect(stripAnsi(mockCalls[3][0] + mockCalls[3][1])).toMatchSnapshot('shallow with message'); - expect(stripAnsi(mockCalls[4][0] + mockCalls[4][1])).toMatchSnapshot('another custom message'); + expect(stripAnsi(mockCalls[2][0] + mockCalls[2][1])).toMatchSnapshot('another custom message'); const mockWarnCalls = jest.mocked(console.warn).mock.calls; - expect(mockWarnCalls[0]).toEqual([ - 'Using debug("message") is deprecated and will be removed in future release, please use debug({ message; "message" }) instead.', - ]); + expect(mockWarnCalls[0]).toMatchInlineSnapshot(` + [ + "Using debug("message") is deprecated and will be removed in future release, please use debug({ message: "message" }) instead.", + ] + `); }); test('debug changing component', () => { diff --git a/src/__tests__/screen.test.tsx b/src/__tests__/screen.test.tsx index b22e92522..d5e5183ca 100644 --- a/src/__tests__/screen.test.tsx +++ b/src/__tests__/screen.test.tsx @@ -55,6 +55,5 @@ test('screen throws without render', () => { expect(() => screen.root).toThrow('`render` method has not been called'); expect(() => screen.UNSAFE_root).toThrow('`render` method has not been called'); expect(() => screen.debug()).toThrow('`render` method has not been called'); - expect(() => screen.debug.shallow()).toThrow('`render` method has not been called'); expect(() => screen.getByText('Mt. Everest')).toThrow('`render` method has not been called'); }); diff --git a/src/config.ts b/src/config.ts index fd867a895..78e639772 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,4 @@ -import { DebugOptions } from './helpers/debug-deep'; +import { DebugOptions } from './helpers/debug'; /** * Global configuration options for React Native Testing Library. diff --git a/src/helpers/debug-shallow.ts b/src/helpers/debug-shallow.ts deleted file mode 100644 index 510a1f402..000000000 --- a/src/helpers/debug-shallow.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import type { ReactTestInstance } from 'react-test-renderer'; -import { shallowInternal } from '../shallow'; -import format from './format'; - -/** - * Log pretty-printed shallow test component instance - */ -export default function debugShallow( - instance: ReactTestInstance | React.ReactElement, - message?: string, -) { - const { output } = shallowInternal(instance); - - if (message) { - // eslint-disable-next-line no-console - console.log(`${message}\n\n`, format(output)); - } else { - // eslint-disable-next-line no-console - console.log(format(output)); - } -} diff --git a/src/helpers/debug-deep.ts b/src/helpers/debug.ts similarity index 95% rename from src/helpers/debug-deep.ts rename to src/helpers/debug.ts index 0450330e9..14ced11af 100644 --- a/src/helpers/debug-deep.ts +++ b/src/helpers/debug.ts @@ -8,7 +8,7 @@ export type DebugOptions = { /** * Log pretty-printed deep test component instance */ -export default function debugDeep( +export function debug( instance: ReactTestRendererJSON | ReactTestRendererJSON[], options?: DebugOptions | string, ) { diff --git a/src/render.tsx b/src/render.tsx index 69d27b53e..dea119386 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -5,8 +5,7 @@ import act from './act'; import { addToCleanupQueue } from './cleanup'; import { getConfig } from './config'; import { getHostChildren } from './helpers/component-tree'; -import debugDeep, { DebugOptions } from './helpers/debug-deep'; -import debugShallow from './helpers/debug-shallow'; +import { debug, DebugOptions } from './helpers/debug'; import { configureHostComponentNamesIfNeeded } from './helpers/host-component-names'; import { validateStringsRenderedWithinText } from './helpers/string-validation'; import { renderWithAct } from './render-act'; @@ -107,7 +106,7 @@ function buildRenderResult( unmount, rerender: update, // alias for `update` toJSON: renderer.toJSON, - debug: debug(instance, renderer), + debug: makeDebug(instance, renderer), get root(): ReactTestInstance { return getHostChildren(instance)[0]; }, @@ -141,12 +140,9 @@ function updateWithAct( }; } -export interface DebugFunction { - (options?: DebugOptions | string): void; - shallow: (message?: string) => void; -} +export type DebugFunction = (options?: DebugOptions | string) => void; -function debug(instance: ReactTestInstance, renderer: ReactTestRenderer): DebugFunction { +function makeDebug(instance: ReactTestInstance, renderer: ReactTestRenderer): DebugFunction { function debugImpl(options?: DebugOptions | string) { const { defaultDebugOptions } = getConfig(); const debugOptions = @@ -157,15 +153,14 @@ function debug(instance: ReactTestInstance, renderer: ReactTestRenderer): DebugF if (typeof options === 'string') { // eslint-disable-next-line no-console console.warn( - 'Using debug("message") is deprecated and will be removed in future release, please use debug({ message; "message" }) instead.', + 'Using debug("message") is deprecated and will be removed in future release, please use debug({ message: "message" }) instead.', ); } const json = renderer.toJSON(); if (json) { - return debugDeep(json, debugOptions); + return debug(json, debugOptions); } } - debugImpl.shallow = (message?: string) => debugShallow(instance, message); return debugImpl; } diff --git a/src/screen.ts b/src/screen.ts index 90600ef82..2d85d7c35 100644 --- a/src/screen.ts +++ b/src/screen.ts @@ -10,7 +10,6 @@ const notImplemented = () => { const notImplementedDebug = () => { throw new Error(SCREEN_ERROR); }; -notImplementedDebug.shallow = notImplemented; interface Screen extends RenderResult { isDetached?: boolean; diff --git a/src/shallow.ts b/src/shallow.ts deleted file mode 100644 index 90e030ffe..000000000 --- a/src/shallow.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as React from 'react'; -import { ReactTestInstance } from 'react-test-renderer'; -import ShallowRenderer from 'react-test-renderer/shallow'; // eslint-disable-line import/no-extraneous-dependencies - -/** - * Renders test component shallowly using react-test-renderer/shallow - */ -export function shallowInternal(instance: ReactTestInstance | React.ReactElement): { - output: any; -} { - const renderer = new (ShallowRenderer as any)(); - - renderer.render(React.createElement(instance.type, instance.props)); - - return { - output: renderer.getRenderOutput(), - }; -} diff --git a/typings/index.flow.js b/typings/index.flow.js index 2bea0c77b..df25313d7 100644 --- a/typings/index.flow.js +++ b/typings/index.flow.js @@ -276,7 +276,6 @@ type DebugOptions = { type Debug = { (options?: DebugOptions | string): void, - shallow: (message?: string) => void, }; type Queries = ByTextQueries & diff --git a/website/docs/MigrationV13.md b/website/docs/MigrationV13.md index 285c801a9..c2ae14936 100644 --- a/website/docs/MigrationV13.md +++ b/website/docs/MigrationV13.md @@ -1,5 +1,3 @@ -## @@ -0,0 +1,20 @@ - id: migration-v13 title: Migration to 13.0 @@ -62,6 +60,10 @@ const view = screen.getBy*(...); // Find the element using any query: *ByRole, * expect(view).toHaveAccessibilityValue({ now: 50, min: 0, max: 50 }); // Assert its accessibility value ``` +## Removed `debug.shallow` + +For a time being we didn't support shallow rendering. Now we are removing the last remains of it: `debug.shallow()`. If you are interested in shallow rendering see [here](migration-v2#removed-global-shallow-function). + # Other changes ## Updated `flushMicroTasks` internal method From 450e7505156a3db748ee1edac23194d6afad940e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Mon, 12 Aug 2024 23:01:22 +0200 Subject: [PATCH 04/22] [v13] chore: increase required React et al. versions --- package.json | 6 ++--- website/docs/12.x/docs/api/misc/async.mdx | 14 ----------- .../docs/migration/v13.mdx} | 25 +++++++------------ yarn.lock | 6 ++--- 4 files changed, 15 insertions(+), 36 deletions(-) rename website/docs/{MigrationV13.md => 12.x/docs/migration/v13.mdx} (76%) diff --git a/package.json b/package.json index 6597970ef..d2c2c3777 100644 --- a/package.json +++ b/package.json @@ -57,9 +57,9 @@ }, "peerDependencies": { "jest": ">=28.0.0", - "react": ">=18.2.0", - "react-native": ">=0.73", - "react-test-renderer": ">=18.2.0" + "react": ">=18.3.0", + "react-native": ">=0.75", + "react-test-renderer": ">=18.3.0" }, "peerDependenciesMeta": { "jest": { diff --git a/website/docs/12.x/docs/api/misc/async.mdx b/website/docs/12.x/docs/api/misc/async.mdx index 5ae3cf1c8..47b040629 100644 --- a/website/docs/12.x/docs/api/misc/async.mdx +++ b/website/docs/12.x/docs/api/misc/async.mdx @@ -53,12 +53,6 @@ Avoiding side effects in `expectation` callback can be partially enforced with t It is also recommended to have a [single assertion per each `waitFor`](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#having-multiple-assertions-in-a-single-waitfor-callback) for more consistency and faster failing tests. If you want to make several assertions, then they should be in seperate `waitFor` calls. In many cases you won't actually need to wrap the second assertion in `waitFor` since the first one will do the waiting required for asynchronous change to happen. -### Using a React Native version < 0.71 with Jest fake timers - -:::caution -When using a version of React Native < 0.71 and modern fake timers (the default for `Jest` >= 27), `waitFor` won't work (it will always timeout even if `expectation()` doesn't throw) unless you use the custom [@testing-library/react-native preset](https://github.com/callstack/react-native-testing-library#custom-jest-preset). -::: - `waitFor` checks whether Jest fake timers are enabled and adapts its behavior in such case. The following snippet is a simplified version of how it behaves when fake timers are enabled: ```tsx @@ -96,10 +90,6 @@ await waitFor(() => { }, 10000); ``` -:::info -In order to properly use `waitFor` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). -::: - :::note If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. ::: @@ -129,10 +119,6 @@ This method expects that the element is initially present in the render tree and You can use any of `getBy`, `getAllBy`, `queryBy` and `queryAllBy` queries for `expectation` parameter. -:::info -In order to properly use `waitForElementToBeRemoved` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). -::: - :::note If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. ::: diff --git a/website/docs/MigrationV13.md b/website/docs/12.x/docs/migration/v13.mdx similarity index 76% rename from website/docs/MigrationV13.md rename to website/docs/12.x/docs/migration/v13.mdx index c2ae14936..bcf81c721 100644 --- a/website/docs/MigrationV13.md +++ b/website/docs/12.x/docs/migration/v13.mdx @@ -1,14 +1,7 @@ -id: migration-v13 -title: Migration to 13.0 - ---- - -import TOCInline from '@theme/TOCInline'; +# Migration to 13.0 Migration to React Native Testing Library version 13 from version 12.x. - - # Breaking changes ## Supported React and React Native versions @@ -23,11 +16,11 @@ This deprecated query has been removed as is typically too general to give meani - [`*ByRole`](#by-role) query with relevant state options: `disabled`, `selected`, `checked`, `expanded` and `busy` - use built-in Jest matchers to check the state of element found using some other query: - - enabled state: [`toBeEnabled()` / `toBeDisabled()`](jest-matchers#tobeenabled) - - checked state: [`toBeChecked()` / `toBePartiallyChecked()`](jest-matchers#tobechecked) - - selected state: [`toBeSelected()`](jest-matchers#tobeselected) - - expanded state: [`toBeExpanded()` / `toBeCollapsed()`](jest-matchers#tobeexpanded) - - busy state: [`toBeBusy()`](jest-matchers#tobebusy) + - enabled state: [`toBeEnabled()` / `toBeDisabled()`](docs/api/jest-matchers#tobeenabled) + - checked state: [`toBeChecked()` / `toBePartiallyChecked()`](docs/api/jest-matchers#tobechecked) + - selected state: [`toBeSelected()`](docs/api/jest-matchers#tobeselected) + - expanded state: [`toBeExpanded()` / `toBeCollapsed()`](docs/api/jest-matchers#tobeexpanded) + - busy state: [`toBeBusy()`](docs/api/jest-matchers#tobebusy) ```ts // Replace this @@ -45,7 +38,7 @@ expect(view).toBeDisabled(); // Assert its accessibility state This deprecated query has been removed as is typically too general to give meaningful results. Use one of the following options: -- [`toHaveAccessibilityValue()`](jest-matchers#tohaveaccessibilityvalue) Jest matcher to check the state of element found using some other query +- [`toHaveAccessibilityValue()`](docs/api/jest-matchers#tohaveaccessibilityvalue) Jest matcher to check the state of element found using some other query - [`*ByRole`](#by-role) query with `value` option ```ts @@ -62,7 +55,7 @@ expect(view).toHaveAccessibilityValue({ now: 50, min: 0, max: 50 }); // Assert i ## Removed `debug.shallow` -For a time being we didn't support shallow rendering. Now we are removing the last remains of it: `debug.shallow()`. If you are interested in shallow rendering see [here](migration-v2#removed-global-shallow-function). +For a time being we didn't support shallow rendering. Now we are removing the last remains of it: `debug.shallow()`. If you are interested in shallow rendering see [here](docs/migration/previous/v2#removed-global-shallow-function). # Other changes @@ -72,4 +65,4 @@ This should not break any tests. ## Full Changelog -https://github.com/callstack/react-native-testing-library/compare/v12.5.0...v13.0.0 +https://github.com/callstack/react-native-testing-library/compare/v12.5.2...v13.0.0 diff --git a/yarn.lock b/yarn.lock index cfea9c897..3373668ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2931,9 +2931,9 @@ __metadata: typescript: "npm:^5.5.4" peerDependencies: jest: ">=28.0.0" - react: ">=18.2.0" - react-native: ">=0.73" - react-test-renderer: ">=18.2.0" + react: ">=18.3.0" + react-native: ">=0.75" + react-test-renderer: ">=18.3.0" peerDependenciesMeta: jest: optional: true From 7455b216183d13bc2066a0fc858d69390003cce6 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 24 Oct 2024 10:30:42 +0200 Subject: [PATCH 05/22] feat: automatically extend matchers (#1684) --- README.md | 6 +----- extend-expect.d.ts | 1 - extend-expect.js | 1 - jest-setup.ts | 1 - matchers.d.ts | 1 + matchers.js | 2 ++ package.json | 4 ++-- src/index.ts | 1 + src/matchers/__tests__/to-be-checked.test.tsx | 3 +-- src/matchers/__tests__/to-be-partially-checked.test.tsx | 3 +-- 10 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 extend-expect.d.ts delete mode 100644 extend-expect.js create mode 100644 matchers.d.ts create mode 100644 matchers.js diff --git a/README.md b/README.md index 4f0ff8233..16c498ff0 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,7 @@ This library has a `peerDependencies` listing for `react-test-renderer`. Make su ### Additional Jest matchers -You can use the built-in Jest matchers by adding the following line to your `jest-setup.ts` file (configured using [`setupFilesAfterEnv`](https://jestjs.io/docs/configuration#setupfilesafterenv-array)): - -```ts -import '@testing-library/react-native/extend-expect'; -``` +You can use the built-in Jest matchers automatically by having any import from `@testing-library/react-native` in your test. ## Example diff --git a/extend-expect.d.ts b/extend-expect.d.ts deleted file mode 100644 index 14b2aff7c..000000000 --- a/extend-expect.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './build/matchers/extend-expect'; diff --git a/extend-expect.js b/extend-expect.js deleted file mode 100644 index 796915b5f..000000000 --- a/extend-expect.js +++ /dev/null @@ -1 +0,0 @@ -require('./build/matchers/extend-expect'); diff --git a/jest-setup.ts b/jest-setup.ts index a4d893a18..f120a77e7 100644 --- a/jest-setup.ts +++ b/jest-setup.ts @@ -1,5 +1,4 @@ import { resetToDefaults } from './src/pure'; -import './src/matchers/extend-expect'; beforeEach(() => { resetToDefaults(); diff --git a/matchers.d.ts b/matchers.d.ts new file mode 100644 index 000000000..6abd59c4e --- /dev/null +++ b/matchers.d.ts @@ -0,0 +1 @@ +export * from './build/matchers'; diff --git a/matchers.js b/matchers.js new file mode 100644 index 000000000..dafd7cfb2 --- /dev/null +++ b/matchers.js @@ -0,0 +1,2 @@ +// makes it so people can import from '@testing-library/react-native/pure' +module.exports = require('./build/matchers'); diff --git a/package.json b/package.json index a6feeb5ca..aa8c4b9bf 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,8 @@ "files": [ "build/", "jest-preset/", - "extend-expect.js", - "extend-expect.d.ts", + "matchers.js", + "matchers.d.ts", "pure.js", "pure.d.ts", "dont-cleanup-after-each.js", diff --git a/src/index.ts b/src/index.ts index b01198181..8b2ab83d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { cleanup } from './pure'; import { flushMicroTasks } from './flush-micro-tasks'; import { getIsReactActEnvironment, setReactActEnvironment } from './act'; +import './matchers/extend-expect'; if (!process?.env?.RNTL_SKIP_AUTO_CLEANUP) { // If we're running in a test runner that supports afterEach diff --git a/src/matchers/__tests__/to-be-checked.test.tsx b/src/matchers/__tests__/to-be-checked.test.tsx index 6cf432b85..2b674c627 100644 --- a/src/matchers/__tests__/to-be-checked.test.tsx +++ b/src/matchers/__tests__/to-be-checked.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { type AccessibilityRole, Switch, View } from 'react-native'; -import render from '../../render'; -import { screen } from '../../screen'; +import { render, screen } from '../..'; function renderViewsWithRole(role: AccessibilityRole) { render( diff --git a/src/matchers/__tests__/to-be-partially-checked.test.tsx b/src/matchers/__tests__/to-be-partially-checked.test.tsx index 03ab58290..dd84e0cb7 100644 --- a/src/matchers/__tests__/to-be-partially-checked.test.tsx +++ b/src/matchers/__tests__/to-be-partially-checked.test.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { type AccessibilityRole, View } from 'react-native'; -import render from '../../render'; -import { screen } from '../../screen'; +import { render, screen } from '../..'; function renderViewsWithRole(role: AccessibilityRole) { return render( From 383c241d2e02029646bf1adece8d14a47b496e7c Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 25 Oct 2024 10:02:02 +0200 Subject: [PATCH 06/22] feat(v13): enable concurrent rendering by default (#1692) * feat!: enable concurrent rendering by default * chore: tweaks --- .github/workflows/ci.yml | 9 ++++----- jest-setup.ts | 4 ++-- src/__tests__/config.test.ts | 2 +- src/config.ts | 6 +++--- src/render.tsx | 6 +++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ec3a6626..22d0c9bc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: test: needs: [install-cache-deps] runs-on: ubuntu-latest - name: Test + name: Test (concurrent by default) steps: - name: Checkout uses: actions/checkout@v4 @@ -61,11 +61,10 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 - - test-concurrent: + test-legacy: needs: [install-cache-deps] runs-on: ubuntu-latest - name: Test (concurrent mode) + name: Test (legacy) steps: - name: Checkout uses: actions/checkout@v4 @@ -74,7 +73,7 @@ jobs: uses: ./.github/actions/setup-deps - name: Test in concurrent mode - run: CONCURRENT_MODE=1 yarn test:ci + run: CONCURRENT_MODE=0 yarn test:ci test-website: runs-on: ubuntu-latest diff --git a/jest-setup.ts b/jest-setup.ts index 9ed60181d..868f7ba89 100644 --- a/jest-setup.ts +++ b/jest-setup.ts @@ -3,7 +3,7 @@ import './src/matchers/extend-expect'; beforeEach(() => { resetToDefaults(); - if (process.env.CONCURRENT_MODE === '1') { - configure({ concurrentRoot: true }); + if (process.env.CONCURRENT_MODE === '0') { + configure({ concurrentRoot: false }); } }); diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index b3d2a7ed1..d20f91707 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -16,7 +16,7 @@ test('configure() overrides existing config values', () => { asyncUtilTimeout: 5000, defaultDebugOptions: { message: 'debug message' }, defaultIncludeHiddenElements: false, - concurrentRoot: false, + concurrentRoot: true, }); }); diff --git a/src/config.ts b/src/config.ts index cd0bf1bb6..742963376 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,8 +15,8 @@ export type Config = { defaultDebugOptions?: Partial; /** - * Set to `true` to enable concurrent rendering. - * Otherwise `render` will default to legacy synchronous rendering. + * Set to `false` to disable concurrent rendering. + * Otherwise `render` will default to concurrent rendering. */ concurrentRoot: boolean; }; @@ -43,7 +43,7 @@ export type InternalConfig = Config & { const defaultConfig: InternalConfig = { asyncUtilTimeout: 1000, defaultIncludeHiddenElements: false, - concurrentRoot: false, + concurrentRoot: true, }; let config = { ...defaultConfig }; diff --git a/src/render.tsx b/src/render.tsx index acdd9511e..7727130c2 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -24,10 +24,10 @@ export interface RenderOptions { wrapper?: React.ComponentType; /** - * Set to `true` to enable concurrent rendering. - * Otherwise `render` will default to legacy synchronous rendering. + * Set to `false` to disable concurrent rendering. + * Otherwise `render` will default to concurrent rendering. */ - concurrentRoot?: boolean | undefined; + concurrentRoot?: boolean; createNodeMock?: (element: React.ReactElement) => unknown; unstable_validateStringsRenderedWithinText?: boolean; From e90360bfdec6dba459c04b3c06be120c2f3dfae5 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 25 Oct 2024 11:01:13 +0200 Subject: [PATCH 07/22] refactor(v13): use react act if available (#1695) * chore: tweak peer deps limits * chore: sync act implementation with RTL * chore: update yarn.lock --- package.json | 13 ++++++++----- src/act.ts | 23 +++++++++++------------ yarn.lock | 8 ++++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 649a6c7e4..2442457a0 100644 --- a/package.json +++ b/package.json @@ -52,10 +52,10 @@ "redent": "^3.0.0" }, "peerDependencies": { - "jest": ">=28.0.0", - "react": ">=18.3.0", - "react-native": ">=0.75", - "react-test-renderer": ">=18.3.0" + "jest": ">=29.0.0", + "react": ">=18.2.0", + "react-native": ">=0.71", + "react-test-renderer": ">=18.2.0" }, "peerDependenciesMeta": { "jest": { @@ -94,5 +94,8 @@ "publishConfig": { "registry": "https://registry.npmjs.org" }, - "packageManager": "yarn@4.4.0" + "packageManager": "yarn@4.4.0", + "engines": { + "node": ">=18" + } } diff --git a/src/act.ts b/src/act.ts index a05168500..940df677f 100644 --- a/src/act.ts +++ b/src/act.ts @@ -1,8 +1,10 @@ // This file and the act() implementation is sourced from react-testing-library -// https://github.com/testing-library/react-testing-library/blob/c80809a956b0b9f3289c4a6fa8b5e8cc72d6ef6d/src/act-compat.js +// https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/types/index.d.ts +import * as React from 'react'; import { act as reactTestRendererAct } from 'react-test-renderer'; -type ReactAct = typeof reactTestRendererAct; +const reactAct = typeof React.act === 'function' ? React.act : reactTestRendererAct; +type ReactAct = 0 extends 1 & typeof React.act ? typeof reactTestRendererAct : typeof React.act; // See https://github.com/reactwg/react-18/discussions/102 for more context on global.IS_REACT_ACT_ENVIRONMENT declare global { @@ -22,19 +24,13 @@ function withGlobalActEnvironment(actImplementation: ReactAct) { const previousActEnvironment = getIsReactActEnvironment(); setIsReactActEnvironment(true); - // this code is riddled with eslint disabling comments because this doesn't use real promises but eslint thinks we do try { // The return value of `act` is always a thenable. let callbackNeedsToBeAwaited = false; const actResult = actImplementation(() => { const result = callback(); - if ( - result !== null && - typeof result === 'object' && - // @ts-expect-error this should be a promise or thenable - // eslint-disable-next-line promise/prefer-await-to-then - typeof result.then === 'function' - ) { + // @ts-expect-error TS is too strict here + if (result !== null && typeof result === 'object' && typeof result.then === 'function') { callbackNeedsToBeAwaited = true; } return result; @@ -44,15 +40,17 @@ function withGlobalActEnvironment(actImplementation: ReactAct) { const thenable = actResult; return { then: (resolve: (value: never) => never, reject: (value: never) => never) => { - // eslint-disable-next-line + // eslint-disable-next-line promise/catch-or-return, promise/prefer-await-to-then thenable.then( // eslint-disable-next-line promise/always-return (returnValue) => { setIsReactActEnvironment(previousActEnvironment); + // @ts-expect-error resolve(returnValue); }, (error) => { setIsReactActEnvironment(previousActEnvironment); + // @ts-expect-error reject(error); }, ); @@ -71,7 +69,8 @@ function withGlobalActEnvironment(actImplementation: ReactAct) { }; } -const act = withGlobalActEnvironment(reactTestRendererAct) as ReactAct; +// @ts-expect-error +const act = withGlobalActEnvironment(reactAct) as ReactAct; export default act; export { setIsReactActEnvironment as setReactActEnvironment, getIsReactActEnvironment }; diff --git a/yarn.lock b/yarn.lock index 915a4f922..10a58669a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2603,10 +2603,10 @@ __metadata: strip-ansi: "npm:^6.0.1" typescript: "npm:^5.5.4" peerDependencies: - jest: ">=28.0.0" - react: ">=18.3.0" - react-native: ">=0.75" - react-test-renderer: ">=18.3.0" + jest: ">=29.0.0" + react: ">=18.2.0" + react-native: ">=0.71" + react-test-renderer: ">=18.2.0" peerDependenciesMeta: jest: optional: true From 1e788b6ed172bf5fc45a84ac22f46a7c53031ca9 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 25 Oct 2024 11:02:59 +0200 Subject: [PATCH 08/22] chore: alpha release script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2442457a0..103234146 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "build:js": "babel src --out-dir build --extensions \".js,.ts,.jsx,.tsx\" --source-maps --ignore \"**/__tests__/**\"", "build:ts": "tsc --build tsconfig.release.json", "build": "yarn clean && yarn build:js && yarn build:ts && yarn copy-flowtypes", - "release": "release-it" + "release": "release-it", + "release:alpha": "release-it --preRelease=alpha" }, "files": [ "build/", From 93eb53938a608e36f578717fe1a24a867c951141 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 25 Oct 2024 11:08:20 +0200 Subject: [PATCH 09/22] chore: release v13.0.0-alpha.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 103234146..d186d5be7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@testing-library/react-native", - "version": "12.8.0", + "version": "13.0.0-alpha.0", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", "main": "build/index.js", "types": "build/index.d.ts", From 13bc78a504fec403626a091f47d6129abd86073a Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Mon, 4 Nov 2024 23:20:42 +0100 Subject: [PATCH 10/22] refactor(v13): remove detect host component names (#1697) --- src/__tests__/config.test.ts | 24 +--- src/__tests__/host-component-names.test.tsx | 147 +++++--------------- src/__tests__/render.test.tsx | 11 +- src/config.ts | 23 +-- src/fire-event.ts | 2 +- src/helpers/accessibility.ts | 15 +- src/helpers/host-component-names.ts | 57 ++++++++ src/helpers/host-component-names.tsx | 120 ---------------- src/render-hook.tsx | 1 - src/render.tsx | 19 +-- 10 files changed, 105 insertions(+), 314 deletions(-) create mode 100644 src/helpers/host-component-names.ts delete mode 100644 src/helpers/host-component-names.tsx diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index d20f91707..803cfd621 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -1,4 +1,4 @@ -import { getConfig, configure, resetToDefaults, configureInternal } from '../config'; +import { getConfig, configure, resetToDefaults } from '../config'; beforeEach(() => { resetToDefaults(); @@ -34,27 +34,11 @@ test('resetToDefaults() resets config to defaults', () => { }); test('resetToDefaults() resets internal config to defaults', () => { - configureInternal({ - hostComponentNames: { - text: 'A', - textInput: 'A', - image: 'A', - switch: 'A', - scrollView: 'A', - modal: 'A', - }, - }); - expect(getConfig().hostComponentNames).toEqual({ - text: 'A', - textInput: 'A', - image: 'A', - switch: 'A', - scrollView: 'A', - modal: 'A', - }); + configure({ asyncUtilTimeout: 2000 }); + expect(getConfig().asyncUtilTimeout).toBe(2000); resetToDefaults(); - expect(getConfig().hostComponentNames).toBe(undefined); + expect(getConfig().asyncUtilTimeout).toBe(1000); }); test('configure handles alias option defaultHidden', () => { diff --git a/src/__tests__/host-component-names.test.tsx b/src/__tests__/host-component-names.test.tsx index 0e55f1a82..d3050c8ec 100644 --- a/src/__tests__/host-component-names.test.tsx +++ b/src/__tests__/host-component-names.test.tsx @@ -1,123 +1,48 @@ import * as React from 'react'; -import { View } from 'react-native'; -import TestRenderer from 'react-test-renderer'; -import { configureInternal, getConfig } from '../config'; +import { Image, Modal, ScrollView, Switch, Text, TextInput } from 'react-native'; import { - getHostComponentNames, - configureHostComponentNamesIfNeeded, + isHostImage, + isHostModal, + isHostScrollView, + isHostSwitch, + isHostText, + isHostTextInput, } from '../helpers/host-component-names'; -import { act, render } from '..'; +import { render, screen } from '..'; -describe('getHostComponentNames', () => { - test('returns host component names from internal config', () => { - configureInternal({ - hostComponentNames: { - text: 'banana', - textInput: 'banana', - image: 'banana', - switch: 'banana', - scrollView: 'banana', - modal: 'banana', - }, - }); - - expect(getHostComponentNames()).toEqual({ - text: 'banana', - textInput: 'banana', - image: 'banana', - switch: 'banana', - scrollView: 'banana', - modal: 'banana', - }); - }); - - test('detects host component names if not present in internal config', () => { - expect(getConfig().hostComponentNames).toBeUndefined(); - - const hostComponentNames = getHostComponentNames(); - - expect(hostComponentNames).toEqual({ - text: 'Text', - textInput: 'TextInput', - image: 'Image', - switch: 'RCTSwitch', - scrollView: 'RCTScrollView', - modal: 'Modal', - }); - expect(getConfig().hostComponentNames).toBe(hostComponentNames); - }); - - // Repro test for case when user indirectly triggers `getHostComponentNames` calls from - // explicit `act` wrapper. - // See: https://github.com/callstack/react-native-testing-library/issues/1302 - // and https://github.com/callstack/react-native-testing-library/issues/1305 - test('does not throw when wrapped in act after render has been called', () => { - render(); - expect(() => - act(() => { - getHostComponentNames(); - }), - ).not.toThrow(); - }); +test('detects host Text component', () => { + render(Hello); + expect(isHostText(screen.root)).toBe(true); }); -describe('configureHostComponentNamesIfNeeded', () => { - test('updates internal config with host component names when they are not defined', () => { - expect(getConfig().hostComponentNames).toBeUndefined(); - - configureHostComponentNamesIfNeeded(); - - expect(getConfig().hostComponentNames).toEqual({ - text: 'Text', - textInput: 'TextInput', - image: 'Image', - switch: 'RCTSwitch', - scrollView: 'RCTScrollView', - modal: 'Modal', - }); - }); - - test('does not update internal config when host component names are already configured', () => { - configureInternal({ - hostComponentNames: { - text: 'banana', - textInput: 'banana', - image: 'banana', - switch: 'banana', - scrollView: 'banana', - modal: 'banana', - }, - }); - - configureHostComponentNamesIfNeeded(); - - expect(getConfig().hostComponentNames).toEqual({ - text: 'banana', - textInput: 'banana', - image: 'banana', - switch: 'banana', - scrollView: 'banana', - modal: 'banana', - }); - }); - - test('throw an error when auto-detection fails', () => { - const mockCreate = jest.spyOn(TestRenderer, 'create') as jest.Mock; - const renderer = TestRenderer.create(); +// Some users might use the raw RCTText component directly for performance reasons. +// See: https://blog.theodo.com/2023/10/native-views-rn-performance/ +test('detects raw RCTText component', () => { + render(React.createElement('RCTText', { testID: 'text' }, 'Hello')); + expect(isHostText(screen.root)).toBe(true); +}); - mockCreate.mockReturnValue({ - root: renderer.root, - }); +test('detects host TextInput component', () => { + render(); + expect(isHostTextInput(screen.root)).toBe(true); +}); - expect(() => configureHostComponentNamesIfNeeded()).toThrowErrorMatchingInlineSnapshot(` - "Trying to detect host component names triggered the following error: +test('detects host Image component', () => { + render(); + expect(isHostImage(screen.root)).toBe(true); +}); - Unable to find an element with testID: text +test('detects host Switch component', () => { + render(); + expect(isHostSwitch(screen.root)).toBe(true); +}); - 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." - `); +test('detects host ScrollView component', () => { + render(); + expect(isHostScrollView(screen.root)).toBe(true); +}); - mockCreate.mockReset(); - }); +test('detects host Modal component', () => { + render(); + expect(isHostModal(screen.root)).toBe(true); }); diff --git a/src/__tests__/render.test.tsx b/src/__tests__/render.test.tsx index fae79012b..58acb4535 100644 --- a/src/__tests__/render.test.tsx +++ b/src/__tests__/render.test.tsx @@ -1,7 +1,6 @@ /* eslint-disable no-console */ import * as React from 'react'; import { Pressable, Text, TextInput, View } from 'react-native'; -import { getConfig, resetToDefaults } from '../config'; import { fireEvent, render, RenderAPI, screen } from '..'; const PLACEHOLDER_FRESHNESS = 'Add custom freshness'; @@ -234,17 +233,9 @@ test('returned output can be spread using rest operator', () => { expect(rest).toBeTruthy(); }); -test('render calls detects host component names', () => { - resetToDefaults(); - expect(getConfig().hostComponentNames).toBeUndefined(); - - render(); - expect(getConfig().hostComponentNames).not.toBeUndefined(); -}); - test('supports legacy rendering', () => { render(, { concurrentRoot: false }); - expect(screen.root).toBeDefined(); + expect(screen.root).toBeOnTheScreen(); }); test('supports concurrent rendering', () => { diff --git a/src/config.ts b/src/config.ts index 742963376..7d5d74617 100644 --- a/src/config.ts +++ b/src/config.ts @@ -26,21 +26,7 @@ export type ConfigAliasOptions = { defaultHidden: boolean; }; -export type HostComponentNames = { - text: string; - textInput: string; - image: string; - switch: string; - scrollView: string; - modal: string; -}; - -export type InternalConfig = Config & { - /** Names for key React Native host components. */ - hostComponentNames?: HostComponentNames; -}; - -const defaultConfig: InternalConfig = { +const defaultConfig: Config = { asyncUtilTimeout: 1000, defaultIncludeHiddenElements: false, concurrentRoot: true, @@ -66,13 +52,6 @@ export function configure(options: Partial) { }; } -export function configureInternal(option: Partial) { - config = { - ...config, - ...option, - }; -} - export function resetToDefaults() { config = { ...defaultConfig }; } diff --git a/src/fire-event.ts b/src/fire-event.ts index 0f0287f5e..fe3fe6d79 100644 --- a/src/fire-event.ts +++ b/src/fire-event.ts @@ -52,7 +52,7 @@ export function isEventEnabled( eventName: string, nearestTouchResponder?: ReactTestInstance, ) { - if (isHostTextInput(nearestTouchResponder)) { + if (nearestTouchResponder != null && isHostTextInput(nearestTouchResponder)) { return ( isTextInputEditable(nearestTouchResponder) || textInputEventsIgnoringEditableProp.has(eventName) diff --git a/src/helpers/accessibility.ts b/src/helpers/accessibility.ts index 5eee9401a..062ea8fb2 100644 --- a/src/helpers/accessibility.ts +++ b/src/helpers/accessibility.ts @@ -7,13 +7,7 @@ import { } from 'react-native'; import { ReactTestInstance } from 'react-test-renderer'; import { getHostSiblings, getUnsafeRootElement } from './component-tree'; -import { - getHostComponentNames, - isHostImage, - isHostSwitch, - isHostText, - isHostTextInput, -} from './host-component-names'; +import { isHostImage, isHostSwitch, isHostText, isHostTextInput } from './host-component-names'; import { getTextContent } from './text-content'; import { isTextInputEditable } from './text-input'; @@ -112,12 +106,7 @@ export function isAccessibilityElement(element: ReactTestInstance | null): boole return element.props.accessible; } - const hostComponentNames = getHostComponentNames(); - return ( - element?.type === hostComponentNames?.text || - element?.type === hostComponentNames?.textInput || - element?.type === hostComponentNames?.switch - ); + return isHostText(element) || isHostTextInput(element) || isHostSwitch(element); } /** diff --git a/src/helpers/host-component-names.ts b/src/helpers/host-component-names.ts new file mode 100644 index 000000000..c960bf264 --- /dev/null +++ b/src/helpers/host-component-names.ts @@ -0,0 +1,57 @@ +import { ReactTestInstance } from 'react-test-renderer'; +import { HostTestInstance } from './component-tree'; + +const HOST_TEXT_NAMES = ['Text', 'RCTText']; +const HOST_TEXT_INPUT_NAMES = ['TextInput']; +const HOST_IMAGE_NAMES = ['Image']; +const HOST_SWITCH_NAMES = ['RCTSwitch']; +const HOST_SCROLL_VIEW_NAMES = ['RCTScrollView']; +const HOST_MODAL_NAMES = ['Modal']; + +/** + * Checks if the given element is a host Text element. + * @param element The element to check. + */ +export function isHostText(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_TEXT_NAMES.includes(element.type); +} + +/** + * Checks if the given element is a host TextInput element. + * @param element The element to check. + */ +export function isHostTextInput(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_TEXT_INPUT_NAMES.includes(element.type); +} + +/** + * Checks if the given element is a host Image element. + * @param element The element to check. + */ +export function isHostImage(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_IMAGE_NAMES.includes(element.type); +} + +/** + * Checks if the given element is a host Switch element. + * @param element The element to check. + */ +export function isHostSwitch(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_SWITCH_NAMES.includes(element.type); +} + +/** + * Checks if the given element is a host ScrollView element. + * @param element The element to check. + */ +export function isHostScrollView(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_SCROLL_VIEW_NAMES.includes(element.type); +} + +/** + * Checks if the given element is a host Modal element. + * @param element The element to check. + */ +export function isHostModal(element: ReactTestInstance): element is HostTestInstance { + return typeof element?.type === 'string' && HOST_MODAL_NAMES.includes(element.type); +} diff --git a/src/helpers/host-component-names.tsx b/src/helpers/host-component-names.tsx deleted file mode 100644 index b450c930b..000000000 --- a/src/helpers/host-component-names.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import * as React from 'react'; -import { ReactTestInstance } from 'react-test-renderer'; -import { Image, Modal, ScrollView, 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.`; - -export function getHostComponentNames(): HostComponentNames { - let hostComponentNames = getConfig().hostComponentNames; - if (!hostComponentNames) { - hostComponentNames = detectHostComponentNames(); - configureInternal({ hostComponentNames }); - } - - return hostComponentNames; -} - -export function configureHostComponentNamesIfNeeded() { - const configHostComponentNames = getConfig().hostComponentNames; - if (configHostComponentNames) { - return; - } - - const hostComponentNames = detectHostComponentNames(); - configureInternal({ hostComponentNames }); -} - -function detectHostComponentNames(): HostComponentNames { - try { - const renderer = renderWithAct( - - Hello - - - - - - , - ); - - return { - text: getByTestId(renderer.root, 'text').type as string, - textInput: getByTestId(renderer.root, 'textInput').type as string, - image: getByTestId(renderer.root, 'image').type as string, - switch: getByTestId(renderer.root, 'switch').type as string, - scrollView: getByTestId(renderer.root, 'scrollView').type as string, - modal: getByTestId(renderer.root, 'modal').type as string, - }; - } catch (error) { - const errorMessage = - error && typeof error === 'object' && 'message' in error ? error.message : null; - - throw new Error( - `Trying to detect host component names triggered the following error:\n\n${errorMessage}\n\n${userConfigErrorMessage}`, - ); - } -} - -function getByTestId(instance: ReactTestInstance, testID: string) { - const nodes = instance.findAll( - (node) => typeof node.type === 'string' && node.props.testID === testID, - ); - - if (nodes.length === 0) { - throw new Error(`Unable to find an element with testID: ${testID}`); - } - - return nodes[0]; -} - -/** - * Checks if the given element is a host Text element. - * @param element The element to check. - */ -export function isHostText(element?: ReactTestInstance | null): element is HostTestInstance { - return element?.type === getHostComponentNames().text; -} - -/** - * Checks if the given element is a host TextInput element. - * @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 Image element. - * @param element The element to check. - */ -export function isHostImage(element?: ReactTestInstance | null): element is HostTestInstance { - return element?.type === getHostComponentNames().image; -} - -/** - * Checks if the given element is a host Switch element. - * @param element The element to check. - */ -export function isHostSwitch(element?: ReactTestInstance | null): element is HostTestInstance { - return element?.type === getHostComponentNames().switch; -} - -/** - * Checks if the given element is a host ScrollView element. - * @param element The element to check. - */ -export function isHostScrollView(element?: ReactTestInstance | null): element is HostTestInstance { - return element?.type === getHostComponentNames().scrollView; -} - -/** - * Checks if the given element is a host Modal element. - * @param element The element to check. - */ -export function isHostModal(element?: ReactTestInstance | null): element is HostTestInstance { - return element?.type === getHostComponentNames().modal; -} diff --git a/src/render-hook.tsx b/src/render-hook.tsx index f6e7cf08b..ba30077b0 100644 --- a/src/render-hook.tsx +++ b/src/render-hook.tsx @@ -37,7 +37,6 @@ export function renderHook( , { wrapper, - detectHostComponentNames: false, }, ); diff --git a/src/render.tsx b/src/render.tsx index 7727130c2..dfbec3155 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -8,9 +8,8 @@ import { Profiler } from 'react'; import act from './act'; import { addToCleanupQueue } from './cleanup'; import { getConfig } from './config'; -import { getHostChildren } from './helpers/component-tree'; +import { getHostSelves } from './helpers/component-tree'; import { debug, DebugOptions } from './helpers/debug'; -import { configureHostComponentNamesIfNeeded } from './helpers/host-component-names'; import { validateStringsRenderedWithinText } from './helpers/string-validation'; import { renderWithAct } from './render-act'; import { setRenderResult } from './screen'; @@ -43,18 +42,10 @@ export default function render(component: React.ReactElement, options: Ren return renderInternal(component, options); } -export interface RenderInternalOptions extends RenderOptions { - detectHostComponentNames?: boolean; -} - -export function renderInternal( - component: React.ReactElement, - options?: RenderInternalOptions, -) { +export function renderInternal(component: React.ReactElement, options?: RenderOptions) { const { wrapper: Wrapper, concurrentRoot, - detectHostComponentNames = true, unstable_validateStringsRenderedWithinText, ...rest } = options || {}; @@ -65,10 +56,6 @@ export function renderInternal( unstable_isConcurrent: concurrentRoot ?? getConfig().concurrentRoot, }; - if (detectHostComponentNames) { - configureHostComponentNamesIfNeeded(); - } - if (unstable_validateStringsRenderedWithinText) { return renderWithStringValidation(component, { wrapper: Wrapper, @@ -130,7 +117,7 @@ function buildRenderResult( toJSON: renderer.toJSON, debug: makeDebug(instance, renderer), get root(): ReactTestInstance { - return getHostChildren(instance)[0]; + return getHostSelves(instance)[0]; }, UNSAFE_root: instance, }; From 5a10b312e252427b6573d54270a8944be8025396 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 5 Nov 2024 09:03:57 +0100 Subject: [PATCH 11/22] chore: change tsx to ts --- src/matchers/{to-be-busy.tsx => to-be-busy.ts} | 0 src/matchers/{to-be-checked.tsx => to-be-checked.ts} | 0 src/matchers/{to-be-disabled.tsx => to-be-disabled.ts} | 0 src/matchers/{to-be-empty-element.tsx => to-be-empty-element.ts} | 0 src/matchers/{to-be-expanded.tsx => to-be-expanded.ts} | 0 src/matchers/{to-be-on-the-screen.tsx => to-be-on-the-screen.ts} | 0 .../{to-be-partially-checked.tsx => to-be-partially-checked.ts} | 0 src/matchers/{to-be-visible.tsx => to-be-visible.ts} | 0 src/matchers/{to-contain-element.tsx => to-contain-element.ts} | 0 ...ave-accessibility-value.tsx => to-have-accessibility-value.ts} | 0 .../{to-have-accessible-name.tsx => to-have-accessible-name.ts} | 0 .../{to-have-display-value.tsx => to-have-display-value.ts} | 0 src/matchers/{to-have-style.tsx => to-have-style.ts} | 0 .../{to-have-text-content.tsx => to-have-text-content.ts} | 0 src/matchers/{utils.tsx => utils.ts} | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename src/matchers/{to-be-busy.tsx => to-be-busy.ts} (100%) rename src/matchers/{to-be-checked.tsx => to-be-checked.ts} (100%) rename src/matchers/{to-be-disabled.tsx => to-be-disabled.ts} (100%) rename src/matchers/{to-be-empty-element.tsx => to-be-empty-element.ts} (100%) rename src/matchers/{to-be-expanded.tsx => to-be-expanded.ts} (100%) rename src/matchers/{to-be-on-the-screen.tsx => to-be-on-the-screen.ts} (100%) rename src/matchers/{to-be-partially-checked.tsx => to-be-partially-checked.ts} (100%) rename src/matchers/{to-be-visible.tsx => to-be-visible.ts} (100%) rename src/matchers/{to-contain-element.tsx => to-contain-element.ts} (100%) rename src/matchers/{to-have-accessibility-value.tsx => to-have-accessibility-value.ts} (100%) rename src/matchers/{to-have-accessible-name.tsx => to-have-accessible-name.ts} (100%) rename src/matchers/{to-have-display-value.tsx => to-have-display-value.ts} (100%) rename src/matchers/{to-have-style.tsx => to-have-style.ts} (100%) rename src/matchers/{to-have-text-content.tsx => to-have-text-content.ts} (100%) rename src/matchers/{utils.tsx => utils.ts} (100%) diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.ts similarity index 100% rename from src/matchers/to-be-busy.tsx rename to src/matchers/to-be-busy.ts diff --git a/src/matchers/to-be-checked.tsx b/src/matchers/to-be-checked.ts similarity index 100% rename from src/matchers/to-be-checked.tsx rename to src/matchers/to-be-checked.ts diff --git a/src/matchers/to-be-disabled.tsx b/src/matchers/to-be-disabled.ts similarity index 100% rename from src/matchers/to-be-disabled.tsx rename to src/matchers/to-be-disabled.ts diff --git a/src/matchers/to-be-empty-element.tsx b/src/matchers/to-be-empty-element.ts similarity index 100% rename from src/matchers/to-be-empty-element.tsx rename to src/matchers/to-be-empty-element.ts diff --git a/src/matchers/to-be-expanded.tsx b/src/matchers/to-be-expanded.ts similarity index 100% rename from src/matchers/to-be-expanded.tsx rename to src/matchers/to-be-expanded.ts diff --git a/src/matchers/to-be-on-the-screen.tsx b/src/matchers/to-be-on-the-screen.ts similarity index 100% rename from src/matchers/to-be-on-the-screen.tsx rename to src/matchers/to-be-on-the-screen.ts diff --git a/src/matchers/to-be-partially-checked.tsx b/src/matchers/to-be-partially-checked.ts similarity index 100% rename from src/matchers/to-be-partially-checked.tsx rename to src/matchers/to-be-partially-checked.ts diff --git a/src/matchers/to-be-visible.tsx b/src/matchers/to-be-visible.ts similarity index 100% rename from src/matchers/to-be-visible.tsx rename to src/matchers/to-be-visible.ts diff --git a/src/matchers/to-contain-element.tsx b/src/matchers/to-contain-element.ts similarity index 100% rename from src/matchers/to-contain-element.tsx rename to src/matchers/to-contain-element.ts diff --git a/src/matchers/to-have-accessibility-value.tsx b/src/matchers/to-have-accessibility-value.ts similarity index 100% rename from src/matchers/to-have-accessibility-value.tsx rename to src/matchers/to-have-accessibility-value.ts diff --git a/src/matchers/to-have-accessible-name.tsx b/src/matchers/to-have-accessible-name.ts similarity index 100% rename from src/matchers/to-have-accessible-name.tsx rename to src/matchers/to-have-accessible-name.ts diff --git a/src/matchers/to-have-display-value.tsx b/src/matchers/to-have-display-value.ts similarity index 100% rename from src/matchers/to-have-display-value.tsx rename to src/matchers/to-have-display-value.ts diff --git a/src/matchers/to-have-style.tsx b/src/matchers/to-have-style.ts similarity index 100% rename from src/matchers/to-have-style.tsx rename to src/matchers/to-have-style.ts diff --git a/src/matchers/to-have-text-content.tsx b/src/matchers/to-have-text-content.ts similarity index 100% rename from src/matchers/to-have-text-content.tsx rename to src/matchers/to-have-text-content.ts diff --git a/src/matchers/utils.tsx b/src/matchers/utils.ts similarity index 100% rename from src/matchers/utils.tsx rename to src/matchers/utils.ts From 83cafe456a9974ac3c7a77ef4ebb4861f9b89b3e Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 5 Nov 2024 09:14:31 +0100 Subject: [PATCH 12/22] refactor(v13): a11y label helpers (#1666) --- .github/workflows/ci.yml | 2 +- src/helpers/__tests__/accessiblity.test.tsx | 38 +++++++++++++++++- src/helpers/__tests__/component-tree.test.tsx | 4 -- src/helpers/accessibility.ts | 38 ++++++++---------- src/helpers/component-tree.ts | 8 +--- src/helpers/matchers/match-label-text.ts | 40 ++----------------- src/queries/label-text.ts | 4 +- 7 files changed, 63 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22d0c9bc4..cee442654 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,7 +72,7 @@ jobs: - name: Setup Node.js and deps uses: ./.github/actions/setup-deps - - name: Test in concurrent mode + - name: Test in legacy mode run: CONCURRENT_MODE=0 yarn test:ci test-website: diff --git a/src/helpers/__tests__/accessiblity.test.tsx b/src/helpers/__tests__/accessiblity.test.tsx index cbfd021c4..b206ccdc7 100644 --- a/src/helpers/__tests__/accessiblity.test.tsx +++ b/src/helpers/__tests__/accessiblity.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { View, Text, TextInput, Pressable, Switch, TouchableOpacity } from 'react-native'; import { render, isHiddenFromAccessibility, isInaccessible, screen } from '../..'; -import { isAccessibilityElement } from '../accessibility'; +import { computeAriaLabel, isAccessibilityElement } from '../accessibility'; describe('isHiddenFromAccessibility', () => { test('returns false for accessible elements', () => { @@ -371,3 +371,39 @@ describe('isAccessibilityElement', () => { expect(isAccessibilityElement(null)).toEqual(false); }); }); + +describe('computeAriaLabel', () => { + test('supports basic usage', () => { + render( + + + + + External Text + + + + Text Content + + , + ); + + expect(computeAriaLabel(screen.getByTestId('label'))).toEqual('Internal Label'); + expect(computeAriaLabel(screen.getByTestId('label-by-id'))).toEqual('External Text'); + expect(computeAriaLabel(screen.getByTestId('no-label'))).toBeUndefined(); + expect(computeAriaLabel(screen.getByTestId('text-content'))).toBeUndefined(); + }); + + test('label priority', () => { + render( + + + + External Label + + , + ); + + expect(computeAriaLabel(screen.getByTestId('subject'))).toEqual('External Label'); + }); +}); diff --git a/src/helpers/__tests__/component-tree.test.tsx b/src/helpers/__tests__/component-tree.test.tsx index 0746d58ff..fe7e3838f 100644 --- a/src/helpers/__tests__/component-tree.test.tsx +++ b/src/helpers/__tests__/component-tree.test.tsx @@ -228,8 +228,4 @@ describe('getUnsafeRootElement()', () => { const view = screen.getByTestId('view'); expect(getUnsafeRootElement(view)).toEqual(screen.UNSAFE_root); }); - - it('returns null for null', () => { - expect(getUnsafeRootElement(null)).toEqual(null); - }); }); diff --git a/src/helpers/accessibility.ts b/src/helpers/accessibility.ts index 062ea8fb2..40f7008ce 100644 --- a/src/helpers/accessibility.ts +++ b/src/helpers/accessibility.ts @@ -5,8 +5,9 @@ import { Role, StyleSheet, } from 'react-native'; -import { ReactTestInstance } from 'react-test-renderer'; -import { getHostSiblings, getUnsafeRootElement } from './component-tree'; +import type { ReactTestInstance } from 'react-test-renderer'; +import { getHostSiblings, getUnsafeRootElement, isHostElement } from './component-tree'; +import { findAll } from './find-all'; import { isHostImage, isHostSwitch, isHostText, isHostTextInput } from './host-component-names'; import { getTextContent } from './text-content'; import { isTextInputEditable } from './text-input'; @@ -158,6 +159,19 @@ export function computeAriaModal(element: ReactTestInstance): boolean | undefine } export function computeAriaLabel(element: ReactTestInstance): string | undefined { + const labelElementId = element.props['aria-labelledby'] ?? element.props.accessibilityLabelledBy; + if (labelElementId) { + const rootElement = getUnsafeRootElement(element); + const labelElement = findAll( + rootElement, + (node) => isHostElement(node) && node.props.nativeID === labelElementId, + { includeHiddenElements: true }, + ); + if (labelElement.length > 0) { + return getTextContent(labelElement[0]); + } + } + const explicitLabel = element.props['aria-label'] ?? element.props.accessibilityLabel; if (explicitLabel) { return explicitLabel; @@ -171,10 +185,6 @@ export function computeAriaLabel(element: ReactTestInstance): string | undefined return undefined; } -export function computeAriaLabelledBy(element: ReactTestInstance): string | undefined { - return element.props['aria-labelledby'] ?? element.props.accessibilityLabelledBy; -} - // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#busy-state export function computeAriaBusy({ props }: ReactTestInstance): boolean { return props['aria-busy'] ?? props.accessibilityState?.busy ?? false; @@ -234,21 +244,7 @@ export function computeAriaValue(element: ReactTestInstance): AccessibilityValue } export function computeAccessibleName(element: ReactTestInstance): string | undefined { - const label = computeAriaLabel(element); - if (label) { - return label; - } - - const labelElementId = computeAriaLabelledBy(element); - if (labelElementId) { - const rootElement = getUnsafeRootElement(element); - const labelElement = rootElement?.findByProps({ nativeID: labelElementId }); - if (labelElement) { - return getTextContent(labelElement); - } - } - - return getTextContent(element); + return computeAriaLabel(element) ?? getTextContent(element); } type RoleSupportMap = Partial>; diff --git a/src/helpers/component-tree.ts b/src/helpers/component-tree.ts index 4a4a00897..bcb2a9f08 100644 --- a/src/helpers/component-tree.ts +++ b/src/helpers/component-tree.ts @@ -13,7 +13,7 @@ export function isHostElement(element?: ReactTestInstance | null): element is Ho return typeof element?.type === 'string'; } -export function isElementMounted(element: ReactTestInstance | null) { +export function isElementMounted(element: ReactTestInstance) { return getUnsafeRootElement(element) === screen.UNSAFE_root; } @@ -91,11 +91,7 @@ export function getHostSiblings(element: ReactTestInstance | null): HostTestInst * @param element The element start traversing from. * @returns The root element of the tree (host or composite). */ -export function getUnsafeRootElement(element: ReactTestInstance | null) { - if (element == null) { - return null; - } - +export function getUnsafeRootElement(element: ReactTestInstance) { let current = element; while (current.parent) { current = current.parent; diff --git a/src/helpers/matchers/match-label-text.ts b/src/helpers/matchers/match-label-text.ts index 1da29d867..f1ceaaac9 100644 --- a/src/helpers/matchers/match-label-text.ts +++ b/src/helpers/matchers/match-label-text.ts @@ -1,43 +1,11 @@ import { ReactTestInstance } from 'react-test-renderer'; import { matches, TextMatch, TextMatchOptions } from '../../matches'; -import { computeAriaLabel, computeAriaLabelledBy } from '../accessibility'; -import { findAll } from '../find-all'; -import { matchTextContent } from './match-text-content'; +import { computeAriaLabel } from '../accessibility'; -export function matchLabelText( - root: ReactTestInstance, - element: ReactTestInstance, - expectedText: TextMatch, - options: TextMatchOptions = {}, -) { - return ( - matchAccessibilityLabel(element, expectedText, options) || - matchAccessibilityLabelledBy(root, computeAriaLabelledBy(element), expectedText, options) - ); -} - -function matchAccessibilityLabel( +export function matchAccessibilityLabel( element: ReactTestInstance, expectedLabel: TextMatch, - options: TextMatchOptions, + options?: TextMatchOptions, ) { - return matches(expectedLabel, computeAriaLabel(element), options.normalizer, options.exact); -} - -function matchAccessibilityLabelledBy( - root: ReactTestInstance, - nativeId: string | undefined, - text: TextMatch, - options: TextMatchOptions, -) { - if (!nativeId) { - return false; - } - - return ( - findAll( - root, - (node) => node.props.nativeID === nativeId && matchTextContent(node, text, options), - ).length > 0 - ); + return matches(expectedLabel, computeAriaLabel(element), options?.normalizer, options?.exact); } diff --git a/src/queries/label-text.ts b/src/queries/label-text.ts index c9dd6dc06..2e018a6a0 100644 --- a/src/queries/label-text.ts +++ b/src/queries/label-text.ts @@ -1,7 +1,7 @@ import type { ReactTestInstance } from 'react-test-renderer'; import { findAll } from '../helpers/find-all'; import { TextMatch, TextMatchOptions } from '../matches'; -import { matchLabelText } from '../helpers/matchers/match-label-text'; +import { matchAccessibilityLabel } from '../helpers/matchers/match-label-text'; import { makeQueries } from './make-queries'; import type { FindAllByQuery, @@ -19,7 +19,7 @@ function queryAllByLabelText(instance: ReactTestInstance) { return (text: TextMatch, queryOptions?: ByLabelTextOptions) => { return findAll( instance, - (node) => matchLabelText(instance, node, text, queryOptions), + (node) => matchAccessibilityLabel(node, text, queryOptions), queryOptions, ); }; From f2de20ce51f201fb1b614a955e0fec9a990492df Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 5 Nov 2024 09:21:10 +0100 Subject: [PATCH 13/22] chore: basic setup (#1659) chore: tweaks config chore: ignore build chore: tweak deps --- .eslintrc | 4 +- babel.config.js | 11 ++- package.json | 4 +- yarn.lock | 256 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 258 insertions(+), 17 deletions(-) diff --git a/.eslintrc b/.eslintrc index d09bfda8d..09e61fedf 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,13 +1,13 @@ { "extends": "@callstack", "rules": { - "react-native/no-raw-text": 0, "no-console": 1, - "react/no-multi-comp": 0, // Ignore certain webpack alias because it can't be resolved "import/no-unresolved": [2, { "ignore": ["^@theme", "^@docusaurus", "^@generated"] }], + "react/no-multi-comp": 0, "react-native/no-color-literals": "off", "react-native/no-inline-styles": "off", + "react-native/no-raw-text": 0, "react-native-a11y/has-valid-accessibility-descriptors": "off", "react-native-a11y/has-valid-accessibility-ignores-invert-colors": 0, "react-native-a11y/has-valid-accessibility-value": "off" diff --git a/babel.config.js b/babel.config.js index a21450b2c..f2c48ffa8 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,17 +1,20 @@ module.exports = { presets: [ - '@babel/preset-typescript', - '@babel/preset-react', [ '@babel/preset-env', { targets: { - node: '14', + node: '18', }, - bugfixes: true, + useBuiltIns: false, + modules: 'commonjs', }, ], + '@babel/preset-react', + '@babel/preset-typescript', + '@babel/preset-flow', ], + plugins: ['@babel/plugin-transform-strict-mode'], env: { test: { presets: ['@react-native/babel-preset'], diff --git a/package.json b/package.json index f4056161a..ae0696c35 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "devDependencies": { "@babel/cli": "^7.25.9", "@babel/core": "^7.26.0", - "@babel/plugin-transform-flow-strip-types": "^7.25.9", + "@babel/plugin-transform-strict-mode": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-flow": "^7.25.9", "@babel/preset-react": "^7.25.9", @@ -79,9 +79,9 @@ "@types/react": "^18.3.12", "@types/react-test-renderer": "^18.3.0", "babel-jest": "^29.7.0", + "babel-plugin-module-resolver": "^5.0.2", "del-cli": "^6.0.0", "eslint": "^8.57.1", - "eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-prettier": "^4.2.1", "flow-bin": "~0.170.0", "jest": "^29.7.0", diff --git a/yarn.lock b/yarn.lock index be5e0e6e3..8fd3eecde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -97,7 +97,31 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.9, @babel/generator@npm:^7.7.2": + version: 7.25.9 + resolution: "@babel/generator@npm:7.25.9" + dependencies: + "@babel/types": "npm:^7.25.9" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10c0/fca49a1440ac550bb835a73c0e8314849cd493a468a5431ca7f9dbb3d3443e3a1a6dcba2426752e8a97cc2feed4a3b7a0c639e1c45871c4a9dd0c994f08dd25a + languageName: node + linkType: hard + +"@babel/generator@npm:^7.25.6": + version: 7.25.6 + resolution: "@babel/generator@npm:7.25.6" + dependencies: + "@babel/types": "npm:^7.25.6" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10c0/f89282cce4ddc63654470b98086994d219407d025497f483eb03ba102086e11e2b685b27122f6ff2e1d93b5b5fa0c3a6b7e974fbf2e4a75b685041a746a4291e + languageName: node + linkType: hard + +"@babel/generator@npm:^7.26.0": version: 7.26.2 resolution: "@babel/generator@npm:7.26.2" dependencies: @@ -282,6 +306,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-string-parser@npm:7.24.8" + checksum: 10c0/6361f72076c17fabf305e252bf6d580106429014b3ab3c1f5c4eb3e6d465536ea6b670cc0e9a637a77a9ad40454d3e41361a2909e70e305116a23d68ce094c08 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-string-parser@npm:7.25.9" @@ -289,6 +320,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-identifier@npm:7.24.7" + checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-identifier@npm:7.25.9" @@ -335,6 +373,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.25.6": + version: 7.25.6 + resolution: "@babel/parser@npm:7.25.6" + dependencies: + "@babel/types": "npm:^7.25.6" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/f88a0e895dbb096fd37c4527ea97d12b5fc013720602580a941ac3a339698872f0c911e318c292b184c36b5fbe23b612f05aff9d24071bc847c7b1c21552c41d + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" @@ -1313,6 +1362,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-strict-mode@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-strict-mode@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b12bd8f910132be8cff2114ca3ef3896c6d4d7c6455a0a0c8527d778dc03e5f4ee383fd02f7f81f9b9e80d4da835c6b24b26ef01ba099297c2617170dcb53bc4 + languageName: node + linkType: hard + "@babel/plugin-transform-template-literals@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-transform-template-literals@npm:7.25.9" @@ -1568,7 +1628,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.25.9": +"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3, @babel/traverse@npm:^7.25.9": version: 7.25.9 resolution: "@babel/traverse@npm:7.25.9" dependencies: @@ -1583,7 +1643,43 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": +"@babel/traverse@npm:^7.25.3": + version: 7.25.6 + resolution: "@babel/traverse@npm:7.25.6" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.25.6" + "@babel/parser": "npm:^7.25.6" + "@babel/template": "npm:^7.25.0" + "@babel/types": "npm:^7.25.6" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/964304c6fa46bd705428ba380bf73177eeb481c3f26d82ea3d0661242b59e0dd4329d23886035e9ca9a4ceb565c03a76fd615109830687a27bcd350059d6377e + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.25.9 + resolution: "@babel/types@npm:7.25.9" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/33890d08bcb06b26a3a60e4c6c996cbdf2b8d8a3c212664de659c2775f80b002c5f2bceedaa309c384ff5e99bd579794fe6a7e41de07df70246f43c55016d349 + languageName: node + linkType: hard + +"@babel/types@npm:^7.25.6": + version: 7.25.6 + resolution: "@babel/types@npm:7.25.6" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/89d45fbee24e27a05dca2d08300a26b905bd384a480448823f6723c72d3a30327c517476389b7280ce8cb9a2c48ef8f47da7f9f6d326faf6f53fd6b68237bdc4 + languageName: node + linkType: hard + +"@babel/types@npm:^7.26.0": version: 7.26.0 resolution: "@babel/types@npm:7.26.0" dependencies: @@ -2576,7 +2672,7 @@ __metadata: dependencies: "@babel/cli": "npm:^7.25.9" "@babel/core": "npm:^7.26.0" - "@babel/plugin-transform-flow-strip-types": "npm:^7.25.9" + "@babel/plugin-transform-strict-mode": "npm:^7.25.9" "@babel/preset-env": "npm:^7.26.0" "@babel/preset-flow": "npm:^7.25.9" "@babel/preset-react": "npm:^7.25.9" @@ -2589,9 +2685,9 @@ __metadata: "@types/react": "npm:^18.3.12" "@types/react-test-renderer": "npm:^18.3.0" babel-jest: "npm:^29.7.0" + babel-plugin-module-resolver: "npm:^5.0.2" del-cli: "npm:^6.0.0" eslint: "npm:^8.57.1" - eslint-plugin-flowtype: "npm:^8.0.3" eslint-plugin-prettier: "npm:^4.2.1" flow-bin: "npm:~0.170.0" jest: "npm:^29.7.0" @@ -2847,6 +2943,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.4.0": + version: 8.4.0 + resolution: "@typescript-eslint/scope-manager@npm:8.4.0" + dependencies: + "@typescript-eslint/types": "npm:8.4.0" + "@typescript-eslint/visitor-keys": "npm:8.4.0" + checksum: 10c0/95188c663df7db106529c6b93c4c7c61647ed34ab6dd48114e41ddf49140ff606c5501ce2ae451a988ec49b5d3874ea96ff212fc102802327b10affd2ff80a37 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:8.12.2": version: 8.12.2 resolution: "@typescript-eslint/type-utils@npm:8.12.2" @@ -2869,6 +2975,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.4.0": + version: 8.4.0 + resolution: "@typescript-eslint/types@npm:8.4.0" + checksum: 10c0/15e09ced84827c349553530a31822f06ae5bad456c03d561b7d0c64b6ad9b5d7ca795e030bd93e65d5a2cd41bfde36ed08dcd2ff9feaa8b60a67080827f47ecb + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.12.2": version: 8.12.2 resolution: "@typescript-eslint/typescript-estree@npm:8.12.2" @@ -2888,7 +3001,26 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.12.2, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": +"@typescript-eslint/typescript-estree@npm:8.4.0": + version: 8.4.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.4.0" + dependencies: + "@typescript-eslint/types": "npm:8.4.0" + "@typescript-eslint/visitor-keys": "npm:8.4.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/170702b024121cff9268f53de8054796b0ce025f9a78d6f2bc850a360e5f3f7032ba3ee9d4b7392726308273a5f3ade5ab31b1788b504b514bc15afc07302b37 + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:8.12.2": version: 8.12.2 resolution: "@typescript-eslint/utils@npm:8.12.2" dependencies: @@ -2902,6 +3034,20 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": + version: 8.4.0 + resolution: "@typescript-eslint/utils@npm:8.4.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.4.0" + "@typescript-eslint/types": "npm:8.4.0" + "@typescript-eslint/typescript-estree": "npm:8.4.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + checksum: 10c0/8c9c36b3aa23f9bcc28cc4b10f0fa2996f1bc6cdd75135f08c2ef734baa30dbd2a8b92f344b90518e1fd07a486936734789fc7e90b780221a7707dad8e9c9364 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:8.12.2": version: 8.12.2 resolution: "@typescript-eslint/visitor-keys@npm:8.12.2" @@ -2912,6 +3058,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.4.0": + version: 8.4.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.4.0" + dependencies: + "@typescript-eslint/types": "npm:8.4.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10c0/339199b7fbb9ac83b530d03ab25f6bc5ceb688c9cd0ae460112cd14ee78ca7284a845aef5620cdf70170980123475ec875e85ebf595c60255ba3c0d6fe48c714 + languageName: node + linkType: hard + "@ungap/structured-clone@npm:^1.2.0": version: 1.2.0 resolution: "@ungap/structured-clone@npm:1.2.0" @@ -3319,6 +3475,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-module-resolver@npm:^5.0.2": + version: 5.0.2 + resolution: "babel-plugin-module-resolver@npm:5.0.2" + dependencies: + find-babel-config: "npm:^2.1.1" + glob: "npm:^9.3.3" + pkg-up: "npm:^3.1.0" + reselect: "npm:^4.1.7" + resolve: "npm:^1.22.8" + checksum: 10c0/ccbb9e673c4219f68937349267521becb72be292cf30bf70b861c3e709d24fbfa589da0bf6c100a0def799d38199299171cb6eac3fb00b1ea740373e2c1fe54c + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs2@npm:^0.4.10": version: 0.4.11 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.11" @@ -5296,6 +5465,15 @@ __metadata: languageName: node linkType: hard +"find-babel-config@npm:^2.1.1": + version: 2.1.2 + resolution: "find-babel-config@npm:2.1.2" + dependencies: + json5: "npm:^2.2.3" + checksum: 10c0/c9151b23d636378eae11aa761b0af41d5f67d5479e3ebfca7b0ec7feef91723f14242d243342783b89e6c51fc5b4120086eacf5d8a1a335cf7bae4b0ac89f493 + languageName: node + linkType: hard + "find-cache-dir@npm:^2.0.0": version: 2.1.0 resolution: "find-cache-dir@npm:2.1.0" @@ -5667,6 +5845,18 @@ __metadata: languageName: node linkType: hard +"glob@npm:^9.3.3": + version: 9.3.5 + resolution: "glob@npm:9.3.5" + dependencies: + fs.realpath: "npm:^1.0.0" + minimatch: "npm:^8.0.2" + minipass: "npm:^4.2.4" + path-scurry: "npm:^1.6.1" + checksum: 10c0/2f6c2b9ee019ee21dc258ae97a88719614591e4c979cb4580b1b9df6f0f778a3cb38b4bdaf18dfa584637ea10f89a3c5f2533a5e449cf8741514ad18b0951f2e + languageName: node + linkType: hard + "global-directory@npm:^4.0.1": version: 4.0.1 resolution: "global-directory@npm:4.0.1" @@ -7199,6 +7389,15 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" + bin: + jsesc: bin/jsesc + checksum: 10c0/dbf59312e0ebf2b4405ef413ec2b25abb5f8f4d9bc5fb8d9f90381622ebca5f2af6a6aa9a8578f65903f9e33990a6dc798edd0ce5586894bf0e9e31803a1de88 + languageName: node + linkType: hard + "jsesc@npm:^3.0.2, jsesc@npm:~3.0.2": version: 3.0.2 resolution: "jsesc@npm:3.0.2" @@ -7901,6 +8100,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^8.0.2": + version: 8.0.4 + resolution: "minimatch@npm:8.0.4" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/a0a394c356dd5b4cb7f821720841a82fa6f07c9c562c5b716909d1b6ec5e56a7e4c4b5029da26dd256b7d2b3a3f38cbf9ddd8680e887b9b5282b09c05501c1ca + languageName: node + linkType: hard + "minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -7977,6 +8185,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^4.2.4": + version: 4.2.8 + resolution: "minipass@npm:4.2.8" + checksum: 10c0/4ea76b030d97079f4429d6e8a8affd90baf1b6a1898977c8ccce4701c5a2ba2792e033abc6709373f25c2c4d4d95440d9d5e9464b46b7b76ca44d2ce26d939ce + languageName: node + linkType: hard + "minipass@npm:^5.0.0": version: 5.0.0 resolution: "minipass@npm:5.0.0" @@ -8661,7 +8876,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.11.1": +"path-scurry@npm:^1.11.1, path-scurry@npm:^1.6.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" dependencies: @@ -8724,6 +8939,15 @@ __metadata: languageName: node linkType: hard +"pkg-up@npm:^3.1.0": + version: 3.1.0 + resolution: "pkg-up@npm:3.1.0" + dependencies: + find-up: "npm:^3.0.0" + checksum: 10c0/ecb60e1f8e1f611c0bdf1a0b6a474d6dfb51185567dc6f29cdef37c8d480ecba5362e006606bb290519bbb6f49526c403fabea93c3090c20368d98bb90c999ab + languageName: node + linkType: hard + "possible-typed-array-names@npm:^1.0.0": version: 1.0.0 resolution: "possible-typed-array-names@npm:1.0.0" @@ -9300,6 +9524,13 @@ __metadata: languageName: node linkType: hard +"reselect@npm:^4.1.7": + version: 4.1.8 + resolution: "reselect@npm:4.1.8" + checksum: 10c0/06a305a504affcbb67dd0561ddc8306b35796199c7e15b38934c80606938a021eadcf68cfd58e7bb5e17786601c37602a3362a4665c7bf0a96c1041ceee9d0b7 + languageName: node + linkType: hard + "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -9337,7 +9568,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.4": +"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.4, resolve@npm:^1.22.8": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -9363,7 +9594,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -10251,6 +10482,13 @@ __metadata: languageName: node linkType: hard +"to-fast-properties@npm:^2.0.0": + version: 2.0.0 + resolution: "to-fast-properties@npm:2.0.0" + checksum: 10c0/b214d21dbfb4bce3452b6244b336806ffea9c05297148d32ebb428d5c43ce7545bdfc65a1ceb58c9ef4376a65c0cb2854d645f33961658b3e3b4f84910ddcdd7 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" From 3f1d0106c2bc9ac7be3f4235f894d0374e3529cb Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 5 Nov 2024 09:37:30 +0100 Subject: [PATCH 14/22] chore: release v13.0.0-alpha.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae0696c35..8b4238adf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@testing-library/react-native", - "version": "13.0.0-alpha.0", + "version": "13.0.0-alpha.1", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", "main": "build/index.js", "types": "build/index.d.ts", From 71b059b9748898986d1db7c78d71e229807c79af Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 5 Nov 2024 09:42:11 +0100 Subject: [PATCH 15/22] chore: update examples --- examples/basic/jest-setup.ts | 5 ----- examples/basic/package.json | 2 +- examples/basic/yarn.lock | 18 +++++++++--------- examples/cookbook/jest-setup.ts | 4 ---- examples/cookbook/package.json | 2 +- examples/cookbook/yarn.lock | 18 +++++++++--------- 6 files changed, 20 insertions(+), 29 deletions(-) diff --git a/examples/basic/jest-setup.ts b/examples/basic/jest-setup.ts index 29505bd57..e85eae6dd 100644 --- a/examples/basic/jest-setup.ts +++ b/examples/basic/jest-setup.ts @@ -1,9 +1,4 @@ import { configure } from '@testing-library/react-native'; -// Import built-in Jest matchers -import '@testing-library/react-native/extend-expect'; - // Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper'); - -configure({ concurrentRoot: true }); diff --git a/examples/basic/package.json b/examples/basic/package.json index eb0ea4447..d62b4719d 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "@babel/core": "^7.24.0", - "@testing-library/react-native": "^12.8.0", + "@testing-library/react-native": "^13.0.0-alpha.1", "@types/eslint": "^8.56.10", "@types/jest": "^29.5.12", "@types/react": "~18.2.79", diff --git a/examples/basic/yarn.lock b/examples/basic/yarn.lock index 518d371ad..232629146 100644 --- a/examples/basic/yarn.lock +++ b/examples/basic/yarn.lock @@ -2463,22 +2463,22 @@ __metadata: languageName: node linkType: hard -"@testing-library/react-native@npm:^12.8.0": - version: 12.8.0 - resolution: "@testing-library/react-native@npm:12.8.0" +"@testing-library/react-native@npm:^13.0.0-alpha.1": + version: 13.0.0-alpha.1 + resolution: "@testing-library/react-native@npm:13.0.0-alpha.1" dependencies: jest-matcher-utils: "npm:^29.7.0" pretty-format: "npm:^29.7.0" redent: "npm:^3.0.0" peerDependencies: - jest: ">=28.0.0" - react: ">=16.8.0" - react-native: ">=0.59" - react-test-renderer: ">=16.8.0" + jest: ">=29.0.0" + react: ">=18.2.0" + react-native: ">=0.71" + react-test-renderer: ">=18.2.0" peerDependenciesMeta: jest: optional: true - checksum: 10c0/216d40eefc3afa3259b37611213dcd6667cd0b8deb30521a8aaabe3afc15f07116ce64acba150f8c88b8e268df80639baf6bc38f05af1dbbae247e1d07639bde + checksum: 10c0/48b5d2d32fc6e0d3adcaf2c4fad9106eaf3274bb0b441db1c3375a811d53242c972d065cab61c57b00156fe4d33db9bb8ef6b6b160d44ef7697bae3c627e6513 languageName: node linkType: hard @@ -8923,7 +8923,7 @@ __metadata: resolution: "root-workspace-0b6124@workspace:." dependencies: "@babel/core": "npm:^7.24.0" - "@testing-library/react-native": "npm:^12.8.0" + "@testing-library/react-native": "npm:^13.0.0-alpha.1" "@types/eslint": "npm:^8.56.10" "@types/jest": "npm:^29.5.12" "@types/react": "npm:~18.2.79" diff --git a/examples/cookbook/jest-setup.ts b/examples/cookbook/jest-setup.ts index c66317303..0b7c93e2c 100644 --- a/examples/cookbook/jest-setup.ts +++ b/examples/cookbook/jest-setup.ts @@ -1,7 +1,5 @@ import { configure } from '@testing-library/react-native'; -// Import built-in Jest matchers -import '@testing-library/react-native/extend-expect'; import { server } from './app/network-requests/__tests__/test-utils'; // Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing @@ -15,5 +13,3 @@ afterEach(() => server.resetHandlers()); // Disable API mocking after the tests are done afterAll(() => server.close()); - -configure({ concurrentRoot: true }); diff --git a/examples/cookbook/package.json b/examples/cookbook/package.json index 3bb98797c..a1c6fd53c 100644 --- a/examples/cookbook/package.json +++ b/examples/cookbook/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@babel/core": "^7.20.0", "@expo/metro-runtime": "~3.2.3", - "@testing-library/react-native": "^12.8.0", + "@testing-library/react-native": "^13.0.0-alpha.1", "@types/eslint": "^8.56.10", "@types/jest": "^29.5.12", "@types/react": "~18.2.45", diff --git a/examples/cookbook/yarn.lock b/examples/cookbook/yarn.lock index 01a301ae3..d52d13b7a 100644 --- a/examples/cookbook/yarn.lock +++ b/examples/cookbook/yarn.lock @@ -2833,22 +2833,22 @@ __metadata: languageName: node linkType: hard -"@testing-library/react-native@npm:^12.8.0": - version: 12.8.0 - resolution: "@testing-library/react-native@npm:12.8.0" +"@testing-library/react-native@npm:^13.0.0-alpha.1": + version: 13.0.0-alpha.1 + resolution: "@testing-library/react-native@npm:13.0.0-alpha.1" dependencies: jest-matcher-utils: "npm:^29.7.0" pretty-format: "npm:^29.7.0" redent: "npm:^3.0.0" peerDependencies: - jest: ">=28.0.0" - react: ">=16.8.0" - react-native: ">=0.59" - react-test-renderer: ">=16.8.0" + jest: ">=29.0.0" + react: ">=18.2.0" + react-native: ">=0.71" + react-test-renderer: ">=18.2.0" peerDependenciesMeta: jest: optional: true - checksum: 10c0/216d40eefc3afa3259b37611213dcd6667cd0b8deb30521a8aaabe3afc15f07116ce64acba150f8c88b8e268df80639baf6bc38f05af1dbbae247e1d07639bde + checksum: 10c0/48b5d2d32fc6e0d3adcaf2c4fad9106eaf3274bb0b441db1c3375a811d53242c972d065cab61c57b00156fe4d33db9bb8ef6b6b160d44ef7697bae3c627e6513 languageName: node linkType: hard @@ -9762,7 +9762,7 @@ __metadata: dependencies: "@babel/core": "npm:^7.20.0" "@expo/metro-runtime": "npm:~3.2.3" - "@testing-library/react-native": "npm:^12.8.0" + "@testing-library/react-native": "npm:^13.0.0-alpha.1" "@types/eslint": "npm:^8.56.10" "@types/jest": "npm:^29.5.12" "@types/react": "npm:~18.2.45" From 048d17d86b8098f712946447ab2252287e2c2dee Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 6 Nov 2024 13:47:07 +0100 Subject: [PATCH 16/22] chore(v13): remove jest preset (#1700) * refactor: remove jest preset * chore: update docs * chore: remove files entry --- jest-preset/index.js | 10 ---------- jest-preset/restore-promise.js | 1 - jest-preset/save-promise.js | 1 - jest.config.js | 2 +- package.json | 1 - website/docs/12.x/docs/api/misc/async.mdx | 16 +++++++++++++++- website/docs/13.x-alpha/docs/api/misc/async.mdx | 16 +--------------- 7 files changed, 17 insertions(+), 30 deletions(-) delete mode 100644 jest-preset/index.js delete mode 100644 jest-preset/restore-promise.js delete mode 100644 jest-preset/save-promise.js diff --git a/jest-preset/index.js b/jest-preset/index.js deleted file mode 100644 index 40fe80597..000000000 --- a/jest-preset/index.js +++ /dev/null @@ -1,10 +0,0 @@ -const reactNativePreset = require('react-native/jest-preset'); - -module.exports = { - ...reactNativePreset, - // this is needed to make modern fake timers work - // because the react-native preset overrides global.Promise - setupFiles: [require.resolve('./save-promise.js')] - .concat(reactNativePreset.setupFiles) - .concat([require.resolve('./restore-promise.js')]), -}; diff --git a/jest-preset/restore-promise.js b/jest-preset/restore-promise.js deleted file mode 100644 index 196b35417..000000000 --- a/jest-preset/restore-promise.js +++ /dev/null @@ -1 +0,0 @@ -global.Promise = global.RNTL_ORIGINAL_PROMISE; diff --git a/jest-preset/save-promise.js b/jest-preset/save-promise.js deleted file mode 100644 index 30a5be234..000000000 --- a/jest-preset/save-promise.js +++ /dev/null @@ -1 +0,0 @@ -global.RNTL_ORIGINAL_PROMISE = Promise; diff --git a/jest.config.js b/jest.config.js index 5018adce5..459ad61aa 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - preset: './jest-preset', + preset: 'react-native', setupFilesAfterEnv: ['./jest-setup.ts'], testPathIgnorePatterns: ['build/', 'examples/', 'experiments-app/', 'timer-utils'], testTimeout: 60000, diff --git a/package.json b/package.json index 8b4238adf..58ce5a07f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ }, "files": [ "build/", - "jest-preset/", "matchers.js", "matchers.d.ts", "pure.js", diff --git a/website/docs/12.x/docs/api/misc/async.mdx b/website/docs/12.x/docs/api/misc/async.mdx index 47b040629..8400db405 100644 --- a/website/docs/12.x/docs/api/misc/async.mdx +++ b/website/docs/12.x/docs/api/misc/async.mdx @@ -53,6 +53,12 @@ Avoiding side effects in `expectation` callback can be partially enforced with t It is also recommended to have a [single assertion per each `waitFor`](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#having-multiple-assertions-in-a-single-waitfor-callback) for more consistency and faster failing tests. If you want to make several assertions, then they should be in seperate `waitFor` calls. In many cases you won't actually need to wrap the second assertion in `waitFor` since the first one will do the waiting required for asynchronous change to happen. +### Using a React Native version < 0.71 with Jest fake timers + +:::caution +When using a version of React Native < 0.71 and modern fake timers (the default for `Jest` >= 27), `waitFor` won't work (it will always timeout even if `expectation()` doesn't throw) unless you use the custom [@testing-library/react-native preset](https://github.com/callstack/react-native-testing-library#custom-jest-preset). +::: + `waitFor` checks whether Jest fake timers are enabled and adapts its behavior in such case. The following snippet is a simplified version of how it behaves when fake timers are enabled: ```tsx @@ -90,6 +96,10 @@ await waitFor(() => { }, 10000); ``` +:::info +In order to properly use `waitFor` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). +::: + :::note If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. ::: @@ -119,6 +129,10 @@ This method expects that the element is initially present in the render tree and You can use any of `getBy`, `getAllBy`, `queryBy` and `queryAllBy` queries for `expectation` parameter. +:::info +In order to properly use `waitForElementToBeRemoved` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). +::: + :::note -If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. +If you receive warnings related to `act()` function consult our [Understanding Act](docs/advanced/understanding-act.md) function document. ::: diff --git a/website/docs/13.x-alpha/docs/api/misc/async.mdx b/website/docs/13.x-alpha/docs/api/misc/async.mdx index 5ae3cf1c8..773999dac 100644 --- a/website/docs/13.x-alpha/docs/api/misc/async.mdx +++ b/website/docs/13.x-alpha/docs/api/misc/async.mdx @@ -53,12 +53,6 @@ Avoiding side effects in `expectation` callback can be partially enforced with t It is also recommended to have a [single assertion per each `waitFor`](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#having-multiple-assertions-in-a-single-waitfor-callback) for more consistency and faster failing tests. If you want to make several assertions, then they should be in seperate `waitFor` calls. In many cases you won't actually need to wrap the second assertion in `waitFor` since the first one will do the waiting required for asynchronous change to happen. -### Using a React Native version < 0.71 with Jest fake timers - -:::caution -When using a version of React Native < 0.71 and modern fake timers (the default for `Jest` >= 27), `waitFor` won't work (it will always timeout even if `expectation()` doesn't throw) unless you use the custom [@testing-library/react-native preset](https://github.com/callstack/react-native-testing-library#custom-jest-preset). -::: - `waitFor` checks whether Jest fake timers are enabled and adapts its behavior in such case. The following snippet is a simplified version of how it behaves when fake timers are enabled: ```tsx @@ -96,10 +90,6 @@ await waitFor(() => { }, 10000); ``` -:::info -In order to properly use `waitFor` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). -::: - :::note If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. ::: @@ -129,10 +119,6 @@ This method expects that the element is initially present in the render tree and You can use any of `getBy`, `getAllBy`, `queryBy` and `queryAllBy` queries for `expectation` parameter. -:::info -In order to properly use `waitForElementToBeRemoved` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.61 (which comes with React >=16.9.0). -::: - :::note -If you receive warnings related to `act()` function consult our [Undestanding Act](docs/advanced/understanding-act.md) function document. +If you receive warnings related to `act()` function consult our [Understanding Act](docs/advanced/understanding-act.md) function document. ::: From 2670b59f104b4dd3bb2cbe64f3f4592d144a52f1 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 7 Nov 2024 10:09:05 +0100 Subject: [PATCH 17/22] refactor(v13): cleanup existing code (#1701) * refactor: cleanu existing code * chore: fix lint --- src/fire-event.ts | 11 ++--- src/helpers/__tests__/query-name.test.ts | 10 ----- src/helpers/__tests__/text-input.test.tsx | 36 ++++++++++----- src/helpers/accessibility.ts | 4 +- src/helpers/deprecation.ts | 53 ----------------------- src/helpers/query-name.ts | 4 -- src/helpers/text-input.ts | 8 +--- src/user-event/clear.ts | 4 +- src/user-event/paste.ts | 4 +- src/user-event/press/press.ts | 6 +-- src/user-event/type/type.ts | 4 +- 11 files changed, 42 insertions(+), 102 deletions(-) delete mode 100644 src/helpers/__tests__/query-name.test.ts delete mode 100644 src/helpers/deprecation.ts delete mode 100644 src/helpers/query-name.ts diff --git a/src/fire-event.ts b/src/fire-event.ts index fe3fe6d79..7946baaba 100644 --- a/src/fire-event.ts +++ b/src/fire-event.ts @@ -10,7 +10,7 @@ import act from './act'; import { isElementMounted, isHostElement } from './helpers/component-tree'; import { isHostScrollView, isHostTextInput } from './helpers/host-component-names'; import { isPointerEventEnabled } from './helpers/pointer-events'; -import { isTextInputEditable } from './helpers/text-input'; +import { isEditableTextInput } from './helpers/text-input'; import { Point, StringWithAutocomplete } from './types'; import { nativeState } from './native-state'; @@ -54,7 +54,7 @@ export function isEventEnabled( ) { if (nearestTouchResponder != null && isHostTextInput(nearestTouchResponder)) { return ( - isTextInputEditable(nearestTouchResponder) || + isEditableTextInput(nearestTouchResponder) || textInputEventsIgnoringEditableProp.has(eventName) ); } @@ -160,12 +160,7 @@ const scrollEventNames = new Set([ ]); function setNativeStateIfNeeded(element: ReactTestInstance, eventName: string, value: unknown) { - if ( - eventName === 'changeText' && - typeof value === 'string' && - isHostTextInput(element) && - isTextInputEditable(element) - ) { + if (eventName === 'changeText' && typeof value === 'string' && isEditableTextInput(element)) { nativeState.valueForElement.set(element, value); } diff --git a/src/helpers/__tests__/query-name.test.ts b/src/helpers/__tests__/query-name.test.ts deleted file mode 100644 index 3ef7b9529..000000000 --- a/src/helpers/__tests__/query-name.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { getQueryPrefix } from '../query-name'; - -test('getQueryPrefix should return correct prefix', () => { - expect(getQueryPrefix('getByRole')).toBe('get'); - expect(getQueryPrefix('getAllByText')).toEqual('getAll'); - expect(getQueryPrefix('queryByTestId')).toEqual('query'); - expect(getQueryPrefix('queryAllByPlaceholderText')).toEqual('queryAll'); - expect(getQueryPrefix('findByHintText')).toEqual('find'); - expect(getQueryPrefix('findAllByDisplayValue')).toEqual('findAll'); -}); diff --git a/src/helpers/__tests__/text-input.test.tsx b/src/helpers/__tests__/text-input.test.tsx index 77cc20191..2a3ad3f1f 100644 --- a/src/helpers/__tests__/text-input.test.tsx +++ b/src/helpers/__tests__/text-input.test.tsx @@ -1,10 +1,19 @@ import * as React from 'react'; -import { View } from 'react-native'; +import { TextInput, View } from 'react-native'; import { render, screen } from '../..'; -import { getTextInputValue, isTextInputEditable } from '../text-input'; +import { getTextInputValue, isEditableTextInput } from '../text-input'; -test('getTextInputValue() throws error when invoked on non-text input', () => { - render(); +test('getTextInputValue basic test', () => { + render( + + + + + , + ); + + expect(getTextInputValue(screen.getByTestId('value'))).toBe('text-a'); + expect(getTextInputValue(screen.getByTestId('default-value'))).toBe('text-b'); const view = screen.getByTestId('view'); expect(() => getTextInputValue(view)).toThrowErrorMatchingInlineSnapshot( @@ -12,11 +21,18 @@ test('getTextInputValue() throws error when invoked on non-text input', () => { ); }); -test('isTextInputEditable() throws error when invoked on non-text input', () => { - render(); - - const view = screen.getByTestId('view'); - expect(() => isTextInputEditable(view)).toThrowErrorMatchingInlineSnapshot( - `"Element is not a "TextInput", but it has type "View"."`, +test('isEditableTextInput basic test', () => { + render( + + + + + + , ); + + expect(isEditableTextInput(screen.getByTestId('default'))).toBe(true); + expect(isEditableTextInput(screen.getByTestId('editable'))).toBe(true); + expect(isEditableTextInput(screen.getByTestId('non-editable'))).toBe(false); + expect(isEditableTextInput(screen.getByTestId('view'))).toBe(false); }); diff --git a/src/helpers/accessibility.ts b/src/helpers/accessibility.ts index 40f7008ce..e1f193368 100644 --- a/src/helpers/accessibility.ts +++ b/src/helpers/accessibility.ts @@ -10,7 +10,7 @@ import { getHostSiblings, getUnsafeRootElement, isHostElement } from './componen import { findAll } from './find-all'; import { isHostImage, isHostSwitch, isHostText, isHostTextInput } from './host-component-names'; import { getTextContent } from './text-content'; -import { isTextInputEditable } from './text-input'; +import { isEditableTextInput } from './text-input'; type IsInaccessibleOptions = { cache?: WeakMap; @@ -208,7 +208,7 @@ export function computeAriaChecked(element: ReactTestInstance): AccessibilitySta // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#disabled-state export function computeAriaDisabled(element: ReactTestInstance): boolean { - if (isHostTextInput(element) && !isTextInputEditable(element)) { + if (isHostTextInput(element) && !isEditableTextInput(element)) { return true; } diff --git a/src/helpers/deprecation.ts b/src/helpers/deprecation.ts deleted file mode 100644 index e6fb723ad..000000000 --- a/src/helpers/deprecation.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { getQueryPrefix } from './query-name'; - -export function deprecateQueries>( - queriesObject: Queries, - recommendation: string, -): Queries { - const result = {} as Queries; - Object.keys(queriesObject).forEach((queryName) => { - const queryFn = queriesObject[queryName]; - // @ts-expect-error: generic typing is hard - result[queryName] = deprecateQuery(queryFn, queryName, recommendation); - }); - - return result; -} - -function deprecateQuery any>( - queryFn: QueryFn, - queryName: string, - recommendation: string, -): QueryFn { - const formattedRecommendation = recommendation.replace( - /{queryPrefix}/g, - getQueryPrefix(queryName), - ); - - // @ts-expect-error: generic typing is hard - const wrapper: QueryFn = (...args: any) => { - const errorMessage = `${queryName}(...) is deprecated and will be removed in the future.\n\n${formattedRecommendation}`; - // eslint-disable-next-line no-console - console.warn(errorMessage); - return queryFn(...args); - }; - - return wrapper; -} - -const warned: { [functionName: string]: boolean } = {}; - -/* istanbul ignore next: occasionally used */ -export function printDeprecationWarning(functionName: string) { - if (warned[functionName]) { - return; - } - - // eslint-disable-next-line no-console - console.warn(` - Deprecation Warning: - Use of ${functionName} is not recommended and will be deleted in future versions of @testing-library/react-native. - `); - - warned[functionName] = true; -} diff --git a/src/helpers/query-name.ts b/src/helpers/query-name.ts deleted file mode 100644 index 1a6a034c8..000000000 --- a/src/helpers/query-name.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function getQueryPrefix(queryName: string) { - const parts = queryName.split('By'); - return parts[0]; -} diff --git a/src/helpers/text-input.ts b/src/helpers/text-input.ts index bf76389fe..d21360a5f 100644 --- a/src/helpers/text-input.ts +++ b/src/helpers/text-input.ts @@ -2,12 +2,8 @@ import { ReactTestInstance } from 'react-test-renderer'; import { nativeState } from '../native-state'; import { isHostTextInput } from './host-component-names'; -export function isTextInputEditable(element: ReactTestInstance) { - if (!isHostTextInput(element)) { - throw new Error(`Element is not a "TextInput", but it has type "${element.type}".`); - } - - return element.props.editable !== false; +export function isEditableTextInput(element: ReactTestInstance) { + return isHostTextInput(element) && element.props.editable !== false; } export function getTextInputValue(element: ReactTestInstance) { diff --git a/src/user-event/clear.ts b/src/user-event/clear.ts index 9b4ce555f..589d0be31 100644 --- a/src/user-event/clear.ts +++ b/src/user-event/clear.ts @@ -1,7 +1,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { ErrorWithStack } from '../helpers/errors'; import { isHostTextInput } from '../helpers/host-component-names'; -import { getTextInputValue, isTextInputEditable } from '../helpers/text-input'; +import { getTextInputValue, isEditableTextInput } from '../helpers/text-input'; import { isPointerEventEnabled } from '../helpers/pointer-events'; import { EventBuilder } from './event-builder'; import { UserEventInstance } from './setup'; @@ -16,7 +16,7 @@ export async function clear(this: UserEventInstance, element: ReactTestInstance) ); } - if (!isTextInputEditable(element) || !isPointerEventEnabled(element)) { + if (!isEditableTextInput(element) || !isPointerEventEnabled(element)) { return; } diff --git a/src/user-event/paste.ts b/src/user-event/paste.ts index 7ead1d1f3..fc0622b2d 100644 --- a/src/user-event/paste.ts +++ b/src/user-event/paste.ts @@ -2,7 +2,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { ErrorWithStack } from '../helpers/errors'; import { isHostTextInput } from '../helpers/host-component-names'; import { isPointerEventEnabled } from '../helpers/pointer-events'; -import { getTextInputValue, isTextInputEditable } from '../helpers/text-input'; +import { getTextInputValue, isEditableTextInput } from '../helpers/text-input'; import { nativeState } from '../native-state'; import { EventBuilder } from './event-builder'; import { UserEventInstance } from './setup'; @@ -20,7 +20,7 @@ export async function paste( ); } - if (!isTextInputEditable(element) || !isPointerEventEnabled(element)) { + if (!isEditableTextInput(element) || !isPointerEventEnabled(element)) { return; } diff --git a/src/user-event/press/press.ts b/src/user-event/press/press.ts index 7302c704a..f5859fc4a 100644 --- a/src/user-event/press/press.ts +++ b/src/user-event/press/press.ts @@ -1,9 +1,9 @@ import { ReactTestInstance } from 'react-test-renderer'; import act from '../../act'; import { getHostParent } from '../../helpers/component-tree'; -import { isTextInputEditable } from '../../helpers/text-input'; +import { isEditableTextInput } from '../../helpers/text-input'; import { isPointerEventEnabled } from '../../helpers/pointer-events'; -import { isHostText, isHostTextInput } from '../../helpers/host-component-names'; +import { isHostText } from '../../helpers/host-component-names'; import { EventBuilder } from '../event-builder'; import { UserEventConfig, UserEventInstance } from '../setup'; import { dispatchEvent, wait } from '../utils'; @@ -49,7 +49,7 @@ const basePress = async ( return; } - if (isHostTextInput(element) && isTextInputEditable(element) && isPointerEventEnabled(element)) { + if (isEditableTextInput(element) && isPointerEventEnabled(element)) { await emitTextInputPressEvents(config, element, options); return; } diff --git a/src/user-event/type/type.ts b/src/user-event/type/type.ts index 19fa66cc2..bd76e1c0c 100644 --- a/src/user-event/type/type.ts +++ b/src/user-event/type/type.ts @@ -3,7 +3,7 @@ import { isHostTextInput } from '../../helpers/host-component-names'; import { nativeState } from '../../native-state'; import { EventBuilder } from '../event-builder'; import { ErrorWithStack } from '../../helpers/errors'; -import { getTextInputValue, isTextInputEditable } from '../../helpers/text-input'; +import { getTextInputValue, isEditableTextInput } from '../../helpers/text-input'; import { isPointerEventEnabled } from '../../helpers/pointer-events'; import { UserEventConfig, UserEventInstance } from '../setup'; import { dispatchEvent, wait, getTextContentSize } from '../utils'; @@ -28,7 +28,7 @@ export async function type( } // Skip events if the element is disabled - if (!isTextInputEditable(element) || !isPointerEventEnabled(element)) { + if (!isEditableTextInput(element) || !isPointerEventEnabled(element)) { return; } From b402d14ec1f4be54ed6afa6930daec0c2e7aa883 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 7 Nov 2024 10:11:20 +0100 Subject: [PATCH 18/22] chore: release v13.0.0-alpha.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 58ce5a07f..eb1aa32e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@testing-library/react-native", - "version": "13.0.0-alpha.1", + "version": "13.0.0-alpha.2", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", "main": "build/index.js", "types": "build/index.d.ts", From b956cbc527fa1b60a87b2d4ec7878e34f6e478d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Tue, 12 Nov 2024 21:14:42 +0000 Subject: [PATCH 19/22] chore: v13 beta --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb1aa32e1..aa879805e 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:ts": "tsc --build tsconfig.release.json", "build": "yarn clean && yarn build:js && yarn build:ts && yarn copy-flowtypes", "release": "release-it", - "release:alpha": "release-it --preRelease=alpha" + "release:beta": "release-it --preRelease=beta" }, "files": [ "build/", From 9ed754973d8a11b4c42a2bbdd1587ca1729a5ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Tue, 12 Nov 2024 21:19:06 +0000 Subject: [PATCH 20/22] chore: release v13.0.0-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa879805e..8d4001b9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@testing-library/react-native", - "version": "13.0.0-alpha.2", + "version": "13.0.0-beta.0", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", "main": "build/index.js", "types": "build/index.d.ts", From 4f842f7970f6a8fef68a84d5d582db190a53a090 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Wed, 27 Nov 2024 10:29:25 +0100 Subject: [PATCH 21/22] chore: fix example apps --- examples/basic/jest.config.js | 2 +- examples/cookbook/jest.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/basic/jest.config.js b/examples/basic/jest.config.js index 3a8ac87b1..bc8a26721 100644 --- a/examples/basic/jest.config.js +++ b/examples/basic/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - preset: '@testing-library/react-native', + preset: 'react-native', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], setupFilesAfterEnv: ['./jest-setup.ts'], }; diff --git a/examples/cookbook/jest.config.js b/examples/cookbook/jest.config.js index 839f9c880..ce238f6cd 100644 --- a/examples/cookbook/jest.config.js +++ b/examples/cookbook/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - preset: '@testing-library/react-native', + preset: 'react-native', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], setupFilesAfterEnv: ['./jest-setup.ts'], testMatch: ['**/*.test.{ts,tsx}'], From 16728809c192394af5079bac8ce59b560f040821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Sun, 8 Dec 2024 11:28:47 +0100 Subject: [PATCH 22/22] chore: switch to RC --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 901e8c736..f70d20d12 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:ts": "tsc --build tsconfig.release.json", "build": "yarn clean && yarn build:js && yarn build:ts && yarn copy-flowtypes", "release": "release-it", - "release:beta": "release-it --preRelease=beta" + "release:rc": "release-it --preRelease=rc" }, "files": [ "build/",