diff --git a/.circleci/config.yml b/.circleci/config.yml index e520dae89..3513063f8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,21 +34,21 @@ jobs: root: . paths: - . - lint-and-flow: + lint-and-typescript: <<: *defaults steps: - attach_workspace: at: ~/react-native-testing-library - run: | yarn lint - yarn flow-check - typescript: + yarn typecheck + flow: <<: *defaults steps: - attach_workspace: at: ~/react-native-testing-library - run: | - yarn typescript-check + yarn flow tests: <<: *defaults steps: @@ -89,10 +89,10 @@ workflows: build-and-test: jobs: - install-dependencies - - lint-and-flow: + - lint-and-typescript: requires: - install-dependencies - - typescript: + - flow: requires: - install-dependencies - tests: diff --git a/.flowconfig b/.flowconfig index ded766e60..c60686a31 100644 --- a/.flowconfig +++ b/.flowconfig @@ -19,11 +19,13 @@ node_modules/warning/.* .*/node_modules/@react-native-community/cli/.*/.* [include] +.*/typings/ [libs] node_modules/react-native/interface.js node_modules/react-native/flow/ flow-typed/ +.*/typings/index [options] server.max_workers=4 diff --git a/README.md b/README.md index 47dbe79e2..d929418e8 100644 --- a/README.md +++ b/README.md @@ -109,11 +109,11 @@ test('form submits two answers', () => { const allQuestions = ['q1', 'q2']; const mockFn = jest.fn(); - const { getAllByA11yLabel, getByText } = render( + const { getAllByLabelText, getByText } = render( ); - const answerInputs = getAllByA11yLabel('answer input'); + const answerInputs = getAllByLabelText('answer input'); fireEvent.changeText(answerInputs[0], 'a1'); fireEvent.changeText(answerInputs[1], 'a2'); diff --git a/babel.config.js b/babel.config.js index 1d7a6bcf8..26bde5943 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,6 @@ module.exports = { presets: [ - '@babel/preset-flow', + '@babel/preset-typescript', '@babel/preset-react', [ '@babel/preset-env', @@ -13,4 +13,10 @@ module.exports = { ], ], plugins: ['@babel/plugin-proposal-class-properties'], + env: { + test: { + // https://github.com/react-native-community/upgrade-support/issues/152 + plugins: ['@babel/plugin-transform-flow-strip-types'], + }, + }, }; diff --git a/package.json b/package.json index 388f7f729..6a92521a8 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "@testing-library/react-native", "version": "9.1.0", "description": "Simple and complete React Native testing utilities that encourage good testing practices.", - "main": "build/index.js", - "typings": "./typings/index.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "repository": { "type": "git", "url": "https://www.github.com/callstack/react-native-testing-library.git" @@ -21,7 +21,7 @@ "files": [ "build/", "jest-preset/", - "typings/index.d.ts", + "typings/index.flow.js", "pure.js", "dont-cleanup-after-each.js" ], @@ -29,18 +29,23 @@ "@babel/cli": "^7.8.4", "@babel/core": "^7.9.0", "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", "@babel/preset-env": "^7.9.6", "@babel/preset-flow": "^7.9.0", "@babel/preset-react": "^7.9.4", + "@babel/preset-typescript": "^7.16.0", "@callstack/eslint-config": "^11.0.0", "@release-it/conventional-changelog": "^2.0.0", "@testing-library/jest-native": "~4.0.2", + "@types/jest": "^27.0.0", "@types/react": "^17.0.0", - "@types/react-native": "^0.66.5", + "@types/react-native": "^0.66.6", "@types/react-test-renderer": "^17.0.0", "babel-jest": "^27.0.0", "conventional-changelog-cli": "^2.0.11", + "cp-cli": "^2.0.0", "dedent": "^0.7.0", + "del-cli": "^3.0.1", "eslint": "^7.0.0", "flow-bin": "^0.141.0", "flow-copy-source": "^2.0.9", @@ -61,25 +66,30 @@ "react-test-renderer": ">=16.0.0" }, "scripts": { + "clean": "del build", "test": "jest", - "flow-check": "flow check", - "typescript-check": "tsc --noEmit --skipLibCheck --jsx react ./typings/__tests__/*", + "typecheck": "tsc", + "flow": "flow", + "copy-flowtypes": "cp typings/index.flow.js build", "lint": "eslint src --cache", "release": "release-it", - "prepublish": "yarn build && yarn copy-flowtypes", - "copy-flowtypes": "flow-copy-source --ignore __tests__/*.js src build", - "build": "rm -rf build; babel src --out-dir build --ignore 'src/__tests__/*'" + "prepublish": "yarn build", + "build:js": "babel src --out-dir build --extensions \".js,.ts\" --source-maps --ignore \"**/__tests__/**\"", + "build:js:watch": "yarn build:js --watch", + "build:ts": "tsc --build tsconfig.release.json", + "build:ts:watch": "yarn build:ts --watch --preserveWatchOutput", + "build": "yarn clean && yarn build:js && yarn build:ts && yarn copy-flowtypes", + "prepare": "yarn build" }, "jest": { "preset": "../jest-preset", - "moduleFileExtensions": [ - "js", - "json" - ], "rootDir": "./src", "testPathIgnorePatterns": [ "timerUtils" ], - "testTimeout": 30000 + "testTimeout": 30000, + "transformIgnorePatterns": [ + "/node_modules/(?!(@react-native|react-native)/).*/" + ] } } diff --git a/src/__tests__/__snapshots__/render.test.js.snap b/src/__tests__/__snapshots__/render.test.tsx.snap similarity index 100% rename from src/__tests__/__snapshots__/render.test.js.snap rename to src/__tests__/__snapshots__/render.test.tsx.snap diff --git a/src/__tests__/a11yAPI.test.js b/src/__tests__/a11yAPI.test.tsx similarity index 70% rename from src/__tests__/a11yAPI.test.js rename to src/__tests__/a11yAPI.test.tsx index 7e348bdd0..31107484c 100644 --- a/src/__tests__/a11yAPI.test.js +++ b/src/__tests__/a11yAPI.test.tsx @@ -1,7 +1,6 @@ -// @flow import * as React from 'react'; import { TouchableOpacity, Text } from 'react-native'; -import { render } from '..'; +import { render } from '../index'; const BUTTON_LABEL = 'cool button'; const BUTTON_HINT = 'click this button'; @@ -29,11 +28,11 @@ const waitForOptions = { timeout: 10 }; class Button extends React.Component { render() { return ( - // $FlowFixMe - accessibilityStates removed in RN 0.62 { - const { getByA11yLabel, queryByA11yLabel, findByA11yLabel } = render( +test('getByLabelText, queryByLabelText, findByLabelText', async () => { + const { getByLabelText, queryByLabelText, findByLabelText } = render(
); - expect(getByA11yLabel(BUTTON_LABEL).props.accessibilityLabel).toEqual( + expect(getByLabelText(BUTTON_LABEL).props.accessibilityLabel).toEqual( BUTTON_LABEL ); - const button = queryByA11yLabel(/button/g); - expect(button && button.props.accessibilityLabel).toEqual(BUTTON_LABEL); + const button = queryByLabelText(/button/g); + expect(button?.props.accessibilityLabel).toEqual(BUTTON_LABEL); - expect(() => getByA11yLabel(NO_MATCHES_TEXT)).toThrow( + expect(() => getByLabelText(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityLabel') ); - expect(queryByA11yLabel(NO_MATCHES_TEXT)).toBeNull(); + expect(queryByLabelText(NO_MATCHES_TEXT)).toBeNull(); - expect(() => getByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); - expect(() => queryByA11yLabel(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); + expect(() => getByLabelText(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByLabelText(TEXT_LABEL)).toThrow(FOUND_TWO_INSTANCES); - const asyncButton = await findByA11yLabel(BUTTON_LABEL); + const asyncButton = await findByLabelText(BUTTON_LABEL); expect(asyncButton.props.accessibilityLabel).toEqual(BUTTON_LABEL); await expect( - findByA11yLabel(NO_MATCHES_TEXT, waitForOptions) + findByLabelText(NO_MATCHES_TEXT, waitForOptions) ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityLabel')); - await expect(findByA11yLabel(TEXT_LABEL, waitForOptions)).rejects.toThrow( + await expect(findByLabelText(TEXT_LABEL, waitForOptions)).rejects.toThrow( FOUND_TWO_INSTANCES ); }); -test('getAllByA11yLabel, queryAllByA11yLabel, findAllByA11yLabel', async () => { - const { getAllByA11yLabel, queryAllByA11yLabel, findAllByA11yLabel } = render( +test('getAllByLabelText, queryAllByLabelText, findAllByLabelText', async () => { + const { getAllByLabelText, queryAllByLabelText, findAllByLabelText } = render(
); - expect(getAllByA11yLabel(TEXT_LABEL)).toHaveLength(2); - expect(queryAllByA11yLabel(/cool/g)).toHaveLength(3); + expect(getAllByLabelText(TEXT_LABEL)).toHaveLength(2); + expect(queryAllByLabelText(/cool/g)).toHaveLength(3); - expect(() => getAllByA11yLabel(NO_MATCHES_TEXT)).toThrow( + expect(() => getAllByLabelText(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityLabel') ); - expect(queryAllByA11yLabel(NO_MATCHES_TEXT)).toEqual([]); + expect(queryAllByLabelText(NO_MATCHES_TEXT)).toEqual([]); - await expect(findAllByA11yLabel(TEXT_LABEL)).resolves.toHaveLength(2); - await expect(findAllByA11yLabel(NO_MATCHES_TEXT)).rejects.toThrow( + await expect(findAllByLabelText(TEXT_LABEL)).resolves.toHaveLength(2); + await expect(findAllByLabelText(NO_MATCHES_TEXT)).rejects.toThrow( getNoInstancesFoundMessage('accessibilityLabel') ); }); @@ -128,7 +127,7 @@ test('getByA11yHint, queryByA11yHint, findByA11yHint', async () => { BUTTON_HINT ); const button = queryByA11yHint(/button/g); - expect(button && button.props.accessibilityHint).toEqual(BUTTON_HINT); + expect(button?.props.accessibilityHint).toEqual(BUTTON_HINT); expect(() => getByA11yHint(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityHint') @@ -167,48 +166,44 @@ test('getAllByA11yHint, queryAllByA11yHint, findAllByA11yHint', async () => { ); }); -test('getByA11yRole, queryByA11yRole, findByA11yRole', async () => { - const { getByA11yRole, queryByA11yRole, findByA11yRole } = render( -
- ); +test('getByRole, queryByRole, findByRole', async () => { + const { getByRole, queryByRole, findByRole } = render(
); - expect(getByA11yRole('button').props.accessibilityRole).toEqual('button'); - const button = queryByA11yRole(/button/g); - expect(button && button.props.accessibilityRole).toEqual('button'); + expect(getByRole('button').props.accessibilityRole).toEqual('button'); + const button = queryByRole(/button/g); + expect(button?.props.accessibilityRole).toEqual('button'); - expect(() => getByA11yRole(NO_MATCHES_TEXT)).toThrow( + expect(() => getByRole(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityRole') ); - expect(queryByA11yRole(NO_MATCHES_TEXT)).toBeNull(); + expect(queryByRole(NO_MATCHES_TEXT)).toBeNull(); - expect(() => getByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES); - expect(() => queryByA11yRole('link')).toThrow(FOUND_TWO_INSTANCES); + expect(() => getByRole('link')).toThrow(FOUND_TWO_INSTANCES); + expect(() => queryByRole('link')).toThrow(FOUND_TWO_INSTANCES); - const asyncButton = await findByA11yRole('button'); + const asyncButton = await findByRole('button'); expect(asyncButton.props.accessibilityRole).toEqual('button'); - await expect(findByA11yRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( + await expect(findByRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( getNoInstancesFoundMessage('accessibilityRole') ); - await expect(findByA11yRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); + await expect(findByRole('link')).rejects.toThrow(FOUND_TWO_INSTANCES); }); -test('getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole', async () => { - const { getAllByA11yRole, queryAllByA11yRole, findAllByA11yRole } = render( -
- ); +test('getAllByRole, queryAllByRole, findAllByRole', async () => { + const { getAllByRole, queryAllByRole, findAllByRole } = render(
); - expect(getAllByA11yRole('link')).toHaveLength(2); - expect(queryAllByA11yRole(/ink/g)).toHaveLength(2); + expect(getAllByRole('link')).toHaveLength(2); + expect(queryAllByRole(/ink/g)).toHaveLength(2); - expect(() => getAllByA11yRole(NO_MATCHES_TEXT)).toThrow( + expect(() => getAllByRole(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityRole') ); - expect(queryAllByA11yRole(NO_MATCHES_TEXT)).toEqual([]); + expect(queryAllByRole(NO_MATCHES_TEXT)).toEqual([]); - await expect(findAllByA11yRole('link')).resolves.toHaveLength(2); - await expect( - findAllByA11yRole(NO_MATCHES_TEXT, waitForOptions) - ).rejects.toThrow(getNoInstancesFoundMessage('accessibilityRole')); + await expect(findAllByRole('link')).resolves.toHaveLength(2); + await expect(findAllByRole(NO_MATCHES_TEXT, waitForOptions)).rejects.toThrow( + getNoInstancesFoundMessage('accessibilityRole') + ); }); // TODO: accessibilityStates was removed from RN 0.62 @@ -220,14 +215,15 @@ test.skip('getByA11yStates, queryByA11yStates', () => { 'disabled', ]); const disabled = queryByA11yStates(['disabled']); - expect(disabled && disabled.props.accessibilityStates).toMatchObject([ + expect(disabled?.props.accessibilityStates).toMatchObject([ 'selected', 'disabled', ]); const disabledSelected = queryByA11yStates(['selected', 'disabled']); - expect( - disabledSelected && disabledSelected.props.accessibilityStates - ).toEqual(['selected', 'disabled']); + expect(disabledSelected?.props.accessibilityStates).toEqual([ + 'selected', + 'disabled', + ]); expect(() => getByA11yStates(NO_MATCHES_TEXT)).toThrow( getNoInstancesFoundMessage('accessibilityStates') @@ -396,31 +392,6 @@ test('getAllByA11yValue, queryAllByA11yValue, findAllByA11yValue', async () => { await expect(findAllByA11yValue({ max: 60 })).resolves.toHaveLength(2); }); -test('a11y label queries have aliases', () => { - const { - getByA11yLabel, - getByLabelText, - queryByA11yLabel, - queryByLabelText, - findByA11yLabel, - findByLabelText, - getAllByA11yLabel, - getAllByLabelText, - queryAllByA11yLabel, - queryAllByLabelText, - findAllByA11yLabel, - findAllByLabelText, - } = render(
); - - // Assert that query aliases are referencing the same function - expect(getByA11yLabel).toBe(getByLabelText); - expect(queryByA11yLabel).toBe(queryByLabelText); - expect(findByA11yLabel).toBe(findByLabelText); - expect(getAllByA11yLabel).toBe(getAllByLabelText); - expect(queryAllByA11yLabel).toBe(queryAllByLabelText); - expect(findAllByA11yLabel).toBe(findAllByLabelText); -}); - test('a11y hint queries have aliases', () => { const { getByA11yHint, @@ -445,28 +416,3 @@ test('a11y hint queries have aliases', () => { expect(queryAllByA11yHint).toBe(queryAllByHintText); expect(findAllByA11yHint).toBe(findAllByHintText); }); - -test('a11y role queries have aliases', () => { - const { - getByA11yRole, - getByRole, - queryByA11yRole, - queryByRole, - findByA11yRole, - findByRole, - getAllByA11yRole, - getAllByRole, - queryAllByA11yRole, - queryAllByRole, - findAllByA11yRole, - findAllByRole, - } = render(
); - - // Assert that query aliases are referencing the same function - expect(getByA11yRole).toBe(getByRole); - expect(queryByA11yRole).toBe(queryByRole); - expect(findByA11yRole).toBe(findByRole); - expect(getAllByA11yRole).toBe(getAllByRole); - expect(queryAllByA11yRole).toBe(queryAllByRole); - expect(findAllByA11yRole).toBe(findAllByRole); -}); diff --git a/src/__tests__/act.test.js b/src/__tests__/act.test.tsx similarity index 92% rename from src/__tests__/act.test.js rename to src/__tests__/act.test.tsx index 0b536ab2a..138985896 100644 --- a/src/__tests__/act.test.js +++ b/src/__tests__/act.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { Text } from 'react-native'; import ReactTestRenderer from 'react-test-renderer'; @@ -6,7 +5,8 @@ import act from '../act'; import render from '../render'; import fireEvent from '../fireEvent'; -const UseEffect = ({ callback }: { callback: Function }) => { +type UseEffectProps = { callback(): void }; +const UseEffect = ({ callback }: UseEffectProps) => { React.useEffect(callback); return null; }; @@ -43,7 +43,7 @@ test('fireEvent should trigger useState', () => { }); test('should act even if there is no act in react-test-renderer', () => { - // $FlowFixMe + // @ts-ignore ReactTestRenderer.act = undefined; const callback = jest.fn(); diff --git a/src/__tests__/auto-cleanup-skip.test.js b/src/__tests__/auto-cleanup-skip.test.tsx similarity index 88% rename from src/__tests__/auto-cleanup-skip.test.js rename to src/__tests__/auto-cleanup-skip.test.tsx index 846255dca..e09e2cbca 100644 --- a/src/__tests__/auto-cleanup-skip.test.js +++ b/src/__tests__/auto-cleanup-skip.test.tsx @@ -1,8 +1,7 @@ -// @flow import * as React from 'react'; import { View } from 'react-native'; -let render; +let render: (element: React.ReactElement) => void; beforeAll(() => { process.env.RNTL_SKIP_AUTO_CLEANUP = 'true'; const rntl = require('..'); @@ -11,7 +10,7 @@ beforeAll(() => { let isMounted = false; -class Test extends React.Component<*> { +class Test extends React.Component<{ onUnmount?(): void }> { componentDidMount() { isMounted = true; } diff --git a/src/__tests__/auto-cleanup.test.js b/src/__tests__/auto-cleanup.test.tsx similarity index 94% rename from src/__tests__/auto-cleanup.test.js rename to src/__tests__/auto-cleanup.test.tsx index 5349dde9a..87c1bf945 100644 --- a/src/__tests__/auto-cleanup.test.js +++ b/src/__tests__/auto-cleanup.test.tsx @@ -1,11 +1,10 @@ -// @flow import * as React from 'react'; import { View } from 'react-native'; import { render } from '..'; let isMounted = false; -class Test extends React.Component<*> { +class Test extends React.Component<{ onUnmount?(): void }> { componentDidMount() { isMounted = true; } diff --git a/src/__tests__/byDisplayValue.test.js b/src/__tests__/byDisplayValue.test.tsx similarity index 99% rename from src/__tests__/byDisplayValue.test.js rename to src/__tests__/byDisplayValue.test.tsx index 518ced57b..8a5422c03 100644 --- a/src/__tests__/byDisplayValue.test.js +++ b/src/__tests__/byDisplayValue.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, TextInput } from 'react-native'; diff --git a/src/__tests__/byPlaceholderText.test.js b/src/__tests__/byPlaceholderText.test.tsx similarity index 99% rename from src/__tests__/byPlaceholderText.test.js rename to src/__tests__/byPlaceholderText.test.tsx index 6e4ee1c00..691ecb632 100644 --- a/src/__tests__/byPlaceholderText.test.js +++ b/src/__tests__/byPlaceholderText.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, TextInput } from 'react-native'; import { render } from '..'; diff --git a/src/__tests__/byTestId.test.js b/src/__tests__/byTestId.test.tsx similarity index 98% rename from src/__tests__/byTestId.test.js rename to src/__tests__/byTestId.test.tsx index 630c6e97e..9fabcd688 100644 --- a/src/__tests__/byTestId.test.js +++ b/src/__tests__/byTestId.test.tsx @@ -1,4 +1,3 @@ -// @flow import React from 'react'; import { View, Text, TextInput, Button } from 'react-native'; import { render } from '..'; @@ -27,7 +26,7 @@ const Banana = () => ( ); -const MyComponent = () => My Component; +const MyComponent = (_props: { testID?: string }) => My Component; test('getByTestId returns only native elements', () => { const { getByTestId, getAllByTestId } = render( diff --git a/src/__tests__/byText.test.js b/src/__tests__/byText.test.tsx similarity index 94% rename from src/__tests__/byText.test.js rename to src/__tests__/byText.test.tsx index 52e0a770a..22edd1f7e 100644 --- a/src/__tests__/byText.test.js +++ b/src/__tests__/byText.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, @@ -10,7 +9,11 @@ import { } from 'react-native'; import { render, getDefaultNormalizer } from '..'; -const MyButton = ({ children, onPress }) => ( +type MyButtonProps = { + children: React.ReactNode; + onPress: () => void; +}; +const MyButton = ({ children, onPress }: MyButtonProps) => ( {children} @@ -23,9 +26,7 @@ const Banana = () => { Is the banana fresh? not fresh - - Change freshness! - + Change freshness! First Text Second Text {test} @@ -33,6 +34,8 @@ const Banana = () => { ); }; +type ChildrenProps = { children: React.ReactNode }; + test('getByText, queryByText', () => { const { getByText, queryByText } = render(); const button = getByText(/change/i); @@ -57,7 +60,8 @@ test('getByText, queryByText', () => { }); test('getByText, queryByText with children as Array', () => { - const BananaCounter = ({ numBananas }) => ( + type BananaCounterProps = { numBananas: number }; + const BananaCounter = ({ numBananas }: BananaCounterProps) => ( There are {numBananas} bananas in the bunch ); @@ -113,7 +117,7 @@ test('findByText queries work asynchronously', async () => { }, 20000); describe('findBy options deprecations', () => { - let warnSpy; + let warnSpy: jest.SpyInstance; beforeEach(() => { warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); }); @@ -146,7 +150,7 @@ describe('findBy options deprecations', () => { }); test.skip('getByText works properly with custom text component', () => { - function BoldText({ children }) { + function BoldText({ children }: ChildrenProps) { return {children}; } @@ -160,10 +164,10 @@ test.skip('getByText works properly with custom text component', () => { }); test.skip('getByText works properly with custom text container', () => { - function MyText({ children }) { + function MyText({ children }: ChildrenProps) { return {children}; } - function BoldText({ children }) { + function BoldText({ children }: ChildrenProps) { return {children}; } @@ -261,7 +265,7 @@ test('queryByText with nested Text components each with text return the lowest o }); test('queryByText nested deep in ', () => { - const CustomText = ({ children }) => { + const CustomText = ({ children }: ChildrenProps) => { return {children}; }; @@ -425,7 +429,7 @@ describe('Supports normalization', () => { test('normalizer function is customisable', () => { const testText = 'A TO REMOVE text'; - const normalizerFn = (textToNormalize) => + const normalizerFn = (textToNormalize: string) => textToNormalize.replace('TO REMOVE ', ''); const { getByText } = render( diff --git a/src/__tests__/cleanup.test.js b/src/__tests__/cleanup.test.tsx similarity index 88% rename from src/__tests__/cleanup.test.js rename to src/__tests__/cleanup.test.tsx index 7fdf2653b..b33fc6485 100644 --- a/src/__tests__/cleanup.test.js +++ b/src/__tests__/cleanup.test.tsx @@ -1,10 +1,9 @@ -// @flow /* eslint-disable react/no-multi-comp */ import * as React from 'react'; import { View } from 'react-native'; import { cleanup, render } from '../pure'; -class Test extends React.Component<*> { +class Test extends React.Component<{ onUnmount: () => void }> { componentWillUnmount() { if (this.props.onUnmount) { this.props.onUnmount(); diff --git a/src/__tests__/fireEvent.test.js b/src/__tests__/fireEvent.test.tsx similarity index 89% rename from src/__tests__/fireEvent.test.js rename to src/__tests__/fireEvent.test.tsx index e21da6835..d5e337688 100644 --- a/src/__tests__/fireEvent.test.js +++ b/src/__tests__/fireEvent.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, @@ -11,7 +10,11 @@ import { } from 'react-native'; import { render, fireEvent } from '..'; -const OnPressComponent = ({ onPress, text }) => ( +type OnPressComponentProps = { + onPress: () => void; + text: string; +}; +const OnPressComponent = ({ onPress, text }: OnPressComponentProps) => ( {text} @@ -19,23 +22,36 @@ const OnPressComponent = ({ onPress, text }) => ( ); -const WithoutEventComponent = () => ( +type WithoutEventComponentProps = { onPress: () => void }; +const WithoutEventComponent = (_props: WithoutEventComponentProps) => ( Without event ); -const CustomEventComponent = ({ onCustomEvent }) => ( +type CustomEventComponentProps = { + onCustomEvent: () => void; +}; +const CustomEventComponent = ({ onCustomEvent }: CustomEventComponentProps) => ( Custom event component ); -const MyCustomButton = ({ handlePress, text }) => ( +type MyCustomButtonProps = { + handlePress: () => void; + text: string; +}; +const MyCustomButton = ({ handlePress, text }: MyCustomButtonProps) => ( ); -const CustomEventComponentWithCustomName = ({ handlePress }) => ( +type CustomEventComponentWithCustomNameProps = { + handlePress: () => void; +}; +const CustomEventComponentWithCustomName = ({ + handlePress, +}: CustomEventComponentWithCustomNameProps) => ( ); @@ -349,7 +365,11 @@ test('should pass event up on disabled Pressable', () => { expect(handleOuterPress).toHaveBeenCalledTimes(1); }); -const TestComponent = ({ onPress }) => { +type TestComponentProps = { + onPress: () => void; + disabled?: boolean; +}; +const TestComponent = ({ onPress }: TestComponentProps) => { return ( Trigger Test @@ -367,7 +387,14 @@ test('is not fooled by non-native disabled prop', () => { expect(handlePress).toHaveBeenCalledTimes(1); }); -function TestChildTouchableComponent({ onPress, someProp }) { +type TestChildTouchableComponentProps = { + onPress: () => void; + someProp: boolean; +}; +function TestChildTouchableComponent({ + onPress, + someProp, +}: TestChildTouchableComponentProps) { return ( @@ -390,7 +417,8 @@ test('is not fooled by non-responder wrapping host elements', () => { expect(handlePress).not.toHaveBeenCalled(); }); -function TestDraggableComponent({ onDrag }) { +type TestDraggableComponentProps = { onDrag: () => void }; +function TestDraggableComponent({ onDrag }: TestDraggableComponentProps) { const responderHandlers = PanResponder.create({ onMoveShouldSetPanResponder: (_evt, _gestureState) => true, onPanResponderMove: onDrag, diff --git a/src/__tests__/jest-native.test.js b/src/__tests__/jest-native.test.tsx similarity index 99% rename from src/__tests__/jest-native.test.js rename to src/__tests__/jest-native.test.tsx index f2f5e2b74..f52e74f7e 100644 --- a/src/__tests__/jest-native.test.js +++ b/src/__tests__/jest-native.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { StyleSheet, View, Button, Text, TextInput } from 'react-native'; import { render } from '..'; diff --git a/src/__tests__/questionsBoard.test.js b/src/__tests__/questionsBoard.test.tsx similarity index 82% rename from src/__tests__/questionsBoard.test.js rename to src/__tests__/questionsBoard.test.tsx index b2c879400..3999c78de 100644 --- a/src/__tests__/questionsBoard.test.js +++ b/src/__tests__/questionsBoard.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, @@ -9,7 +8,11 @@ import { } from 'react-native'; import { render, fireEvent } from '..'; -function QuestionsBoard({ questions, onSubmit }) { +type QuestionsBoardProps = { + questions: string[]; + onSubmit: (obj: {}) => void; +}; +function QuestionsBoard({ questions, onSubmit }: QuestionsBoardProps) { const [data, setData] = React.useState({}); return ( @@ -42,11 +45,11 @@ test('form submits two answers', () => { const allQuestions = ['q1', 'q2']; const mockFn = jest.fn(); - const { getAllByA11yLabel, getByText } = render( + const { getAllByLabelText, getByText } = render( ); - const answerInputs = getAllByA11yLabel('answer input'); + const answerInputs = getAllByLabelText('answer input'); fireEvent.changeText(answerInputs[0], 'a1'); fireEvent.changeText(answerInputs[1], 'a2'); diff --git a/src/__tests__/render.test.js b/src/__tests__/render.test.tsx similarity index 91% rename from src/__tests__/render.test.js rename to src/__tests__/render.test.tsx index b5c2a6e76..68e6accc4 100644 --- a/src/__tests__/render.test.js +++ b/src/__tests__/render.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, @@ -10,7 +9,7 @@ import { import stripAnsi from 'strip-ansi'; import { render, fireEvent } from '..'; -type ConsoleLogMock = JestMockFn, void>; +type ConsoleLogMock = jest.Mock>; const PLACEHOLDER_FRESHNESS = 'Add custom freshness'; const PLACEHOLDER_CHEF = 'Who inspected freshness?'; @@ -29,7 +28,7 @@ class MyButton extends React.Component { } } -class Banana extends React.Component { +class Banana extends React.Component { state = { fresh: false, }; @@ -174,7 +173,7 @@ test('debug', () => { debug.shallow('my other custom message'); // eslint-disable-next-line no-console - const mockCalls = ((console.log: any): ConsoleLogMock).mock.calls; + const mockCalls = ((console.log as any) as ConsoleLogMock).mock.calls; expect(stripAnsi(mockCalls[0][0])).toMatchSnapshot(); expect(stripAnsi(mockCalls[1][0] + mockCalls[1][1])).toMatchSnapshot( @@ -196,7 +195,7 @@ test('debug changing component', () => { debug(); // eslint-disable-next-line no-console - const mockCalls = ((console.log: any): ConsoleLogMock).mock.calls; + const mockCalls = ((console.log as any) as ConsoleLogMock).mock.calls; expect(stripAnsi(mockCalls[4][0])).toMatchSnapshot( 'bananaFresh button message should now be "fresh"' @@ -204,7 +203,8 @@ test('debug changing component', () => { }); test('renders options.wrapper around node', () => { - const WrapperComponent = ({ children }) => ( + type WrapperComponentProps = { children: React.ReactNode }; + const WrapperComponent = ({ children }: WrapperComponentProps) => ( {children} ); @@ -226,7 +226,8 @@ test('renders options.wrapper around node', () => { }); test('renders options.wrapper around updated node', () => { - const WrapperComponent = ({ children }) => ( + type WrapperComponentProps = { children: React.ReactNode }; + const WrapperComponent = ({ children }: WrapperComponentProps) => ( {children} ); @@ -264,7 +265,8 @@ test('returns container', () => { }); test('returns wrapped component as container', () => { - const WrapperComponent = ({ children }) => ( + type WrapperComponentProps = { children: React.ReactNode }; + const WrapperComponent = ({ children }: WrapperComponentProps) => ( {children} ); diff --git a/src/__tests__/timerUtils.js b/src/__tests__/timerUtils.ts similarity index 95% rename from src/__tests__/timerUtils.js rename to src/__tests__/timerUtils.ts index 5132745d1..78cfe53ca 100644 --- a/src/__tests__/timerUtils.js +++ b/src/__tests__/timerUtils.ts @@ -1,11 +1,9 @@ -// @flow - import { setTimeout } from '../helpers/timers'; const TimerMode = { Legacy: 'legacy', Modern: 'modern', // broken for now -}; +} as const; async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/__tests__/timers.test.js b/src/__tests__/timers.test.ts similarity index 98% rename from src/__tests__/timers.test.js rename to src/__tests__/timers.test.ts index c53d9420d..f1ef62eb1 100644 --- a/src/__tests__/timers.test.js +++ b/src/__tests__/timers.test.ts @@ -1,4 +1,3 @@ -// @flow import waitFor from '../waitFor'; import { TimerMode } from './timerUtils'; diff --git a/src/__tests__/waitFor.test.js b/src/__tests__/waitFor.test.tsx similarity index 99% rename from src/__tests__/waitFor.test.js rename to src/__tests__/waitFor.test.tsx index 793c45f2c..7350084fe 100644 --- a/src/__tests__/waitFor.test.js +++ b/src/__tests__/waitFor.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { Text, TouchableOpacity, View } from 'react-native'; import { fireEvent, render, waitFor } from '..'; diff --git a/src/__tests__/waitForElementToBeRemoved.test.js b/src/__tests__/waitForElementToBeRemoved.test.tsx similarity index 99% rename from src/__tests__/waitForElementToBeRemoved.test.js rename to src/__tests__/waitForElementToBeRemoved.test.tsx index 7c56936b0..5ed0dd2ee 100644 --- a/src/__tests__/waitForElementToBeRemoved.test.js +++ b/src/__tests__/waitForElementToBeRemoved.test.tsx @@ -1,4 +1,3 @@ -// @flow import React, { useState } from 'react'; import { View, Text, TouchableOpacity } from 'react-native'; import { render, fireEvent, waitForElementToBeRemoved } from '..'; diff --git a/src/__tests__/within.test.js b/src/__tests__/within.test.tsx similarity index 88% rename from src/__tests__/within.test.js rename to src/__tests__/within.test.tsx index 386d4f9e3..4066245e6 100644 --- a/src/__tests__/within.test.js +++ b/src/__tests__/within.test.tsx @@ -1,4 +1,3 @@ -// @flow import * as React from 'react'; import { View, Text, TextInput } from 'react-native'; import { render, within, getQueriesForElement } from '..'; @@ -66,26 +65,26 @@ test('within() exposes a11y queries', async () => { ); - expect(rootQueries.getAllByA11yLabel('Same Label')).toHaveLength(2); + expect(rootQueries.getAllByLabelText('Same Label')).toHaveLength(2); expect(rootQueries.getAllByA11yHint('Same Hint')).toHaveLength(2); const firstQueries = within(rootQueries.getByA11yHint('first')); - expect(firstQueries.getByA11yLabel('Same Label')).toBeTruthy(); + expect(firstQueries.getByLabelText('Same Label')).toBeTruthy(); expect(firstQueries.getByA11yHint('Same Hint')).toBeTruthy(); - expect(firstQueries.queryByA11yLabel('Same Label')).toBeTruthy(); + expect(firstQueries.queryByLabelText('Same Label')).toBeTruthy(); expect(firstQueries.queryByA11yHint('Same Hint')).toBeTruthy(); await expect( - firstQueries.findByA11yLabel('Same Label') + firstQueries.findByLabelText('Same Label') ).resolves.toBeTruthy(); await expect(firstQueries.findByA11yHint('Same Hint')).resolves.toBeTruthy(); const secondQueries = within(rootQueries.getByA11yHint('second')); - expect(secondQueries.getAllByA11yLabel('Same Label')).toHaveLength(1); + expect(secondQueries.getAllByLabelText('Same Label')).toHaveLength(1); expect(secondQueries.getAllByA11yHint('Same Hint')).toHaveLength(1); - expect(secondQueries.queryAllByA11yLabel('Same Label')).toHaveLength(1); + expect(secondQueries.queryAllByLabelText('Same Label')).toHaveLength(1); expect(secondQueries.queryAllByA11yHint('Same Hint')).toHaveLength(1); await expect( - secondQueries.findAllByA11yLabel('Same Label') + secondQueries.findAllByLabelText('Same Label') ).resolves.toHaveLength(1); await expect( secondQueries.findAllByA11yHint('Same Hint') diff --git a/src/act.js b/src/act.js deleted file mode 100644 index 8d5e7cfb0..000000000 --- a/src/act.js +++ /dev/null @@ -1,9 +0,0 @@ -// @flow -import { act } from 'react-test-renderer'; -import type { Thenable } from './types.flow'; - -const actMock = (callback: () => void) => { - callback(); -}; - -export default (act || actMock: (callback: () => void) => Thenable); diff --git a/src/act.ts b/src/act.ts new file mode 100644 index 000000000..2d4bdb13e --- /dev/null +++ b/src/act.ts @@ -0,0 +1,7 @@ +import { act } from 'react-test-renderer'; + +const actMock = (callback: () => void) => { + callback(); +}; + +export default act || actMock; diff --git a/src/cleanup.js b/src/cleanup.js deleted file mode 100644 index 88a7b2d60..000000000 --- a/src/cleanup.js +++ /dev/null @@ -1,13 +0,0 @@ -// @flow -let cleanupQueue = new Set(); - -export default function cleanup() { - cleanupQueue.forEach((fn) => fn()); - cleanupQueue.clear(); -} - -export function addToCleanupQueue( - fn: (nextElement?: React$Element) => void -) { - cleanupQueue.add(fn); -} diff --git a/src/cleanup.ts b/src/cleanup.ts new file mode 100644 index 000000000..04cdfa208 --- /dev/null +++ b/src/cleanup.ts @@ -0,0 +1,13 @@ +import * as React from 'react'; + +type CleanUpFunction = (nextElement?: React.ReactElement) => void; +let cleanupQueue = new Set(); + +export default function cleanup() { + cleanupQueue.forEach((fn) => fn()); + cleanupQueue.clear(); +} + +export function addToCleanupQueue(fn: CleanUpFunction) { + cleanupQueue.add(fn); +} diff --git a/src/fireEvent.js b/src/fireEvent.ts similarity index 92% rename from src/fireEvent.js rename to src/fireEvent.ts index 8447c4b8c..3fa931a6e 100644 --- a/src/fireEvent.js +++ b/src/fireEvent.ts @@ -1,6 +1,8 @@ -// @flow +import { ReactTestInstance } from 'react-test-renderer'; import act from './act'; +type EventHandler = (...args: any) => unknown; + const isHostElement = (element?: ReactTestInstance) => { return typeof element?.type === 'string'; }; @@ -19,7 +21,7 @@ const isTouchResponder = (element?: ReactTestInstance) => { const isPointerEventEnabled = ( element?: ReactTestInstance, isParent?: boolean -) => { +): boolean => { const parentCondition = isParent ? element?.props.pointerEvents === 'box-only' : element?.props.pointerEvents === 'box-none'; @@ -53,7 +55,7 @@ const findEventHandler = ( eventName: string, callsite?: any, nearestTouchResponder?: ReactTestInstance -) => { +): EventHandler | null => { const touchResponder = isTouchResponder(element) ? element : nearestTouchResponder; @@ -68,7 +70,10 @@ const findEventHandler = ( return findEventHandler(element.parent, eventName, callsite, touchResponder); }; -const getEventHandler = (element: ReactTestInstance, eventName: string) => { +const getEventHandler = ( + element: ReactTestInstance, + eventName: string +): EventHandler | undefined => { const eventHandlerName = toEventHandlerName(eventName); if (typeof element.props[eventHandlerName] === 'function') { return element.props[eventHandlerName]; diff --git a/src/flushMicroTasks.js b/src/flushMicroTasks.js deleted file mode 100644 index 666cbc088..000000000 --- a/src/flushMicroTasks.js +++ /dev/null @@ -1,23 +0,0 @@ -// @flow -import { printDeprecationWarning } from './helpers/errors'; -import { setImmediate } from './helpers/timers'; - -type Thenable = { then: (() => T) => mixed }; - -/** - * Wait for microtasks queue to flush - */ -export default function flushMicrotasksQueue(): Thenable { - printDeprecationWarning('flushMicrotasksQueue'); - return flushMicroTasks(); -} - -export function flushMicroTasks(): 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/flushMicroTasks.ts b/src/flushMicroTasks.ts new file mode 100644 index 000000000..011f01d6e --- /dev/null +++ b/src/flushMicroTasks.ts @@ -0,0 +1,13 @@ +import { setImmediate } from './helpers/timers'; + +type Thenable = { then: (callback: () => T) => unknown }; + +export function flushMicroTasks(): 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/a11yAPI.js b/src/helpers/a11yAPI.js deleted file mode 100644 index 1f9c84608..000000000 --- a/src/helpers/a11yAPI.js +++ /dev/null @@ -1,241 +0,0 @@ -// @flow -import type { A11yRole, A11yStates, A11yState, A11yValue } from '../types.flow'; -import type { WaitForOptions } from '../waitFor'; -import makeA11yQuery from './makeA11yQuery'; - -type GetReturn = ReactTestInstance; -type GetAllReturn = Array; -type QueryReturn = ReactTestInstance | null; -type QueryAllReturn = Array; -type FindReturn = Promise; -type FindAllReturn = Promise; - -export type A11yAPI = {| - // Label - getByA11yLabel: (string | RegExp) => GetReturn, - getByLabelText: (string | RegExp) => GetReturn, - getAllByA11yLabel: (string | RegExp) => GetAllReturn, - getAllByLabelText: (string | RegExp) => GetAllReturn, - queryByA11yLabel: (string | RegExp) => QueryReturn, - queryByLabelText: (string | RegExp) => QueryReturn, - queryAllByA11yLabel: (string | RegExp) => QueryAllReturn, - queryAllByLabelText: (string | RegExp) => QueryAllReturn, - findByA11yLabel: (string | RegExp, ?WaitForOptions) => FindReturn, - findByLabelText: (string | RegExp, ?WaitForOptions) => FindReturn, - findAllByA11yLabel: (string | RegExp, ?WaitForOptions) => FindAllReturn, - findAllByLabelText: (string | RegExp, ?WaitForOptions) => FindAllReturn, - - // Hint - getByA11yHint: (string | RegExp) => GetReturn, - getByHintText: (string | RegExp) => GetReturn, - getAllByA11yHint: (string | RegExp) => GetAllReturn, - getAllByHintText: (string | RegExp) => GetAllReturn, - queryByA11yHint: (string | RegExp) => QueryReturn, - queryByHintText: (string | RegExp) => QueryReturn, - queryAllByA11yHint: (string | RegExp) => QueryAllReturn, - queryAllByHintText: (string | RegExp) => QueryAllReturn, - findByA11yHint: (string | RegExp, ?WaitForOptions) => FindReturn, - findByHintText: (string | RegExp, ?WaitForOptions) => FindReturn, - findAllByA11yHint: (string | RegExp, ?WaitForOptions) => FindAllReturn, - findAllByHintText: (string | RegExp, ?WaitForOptions) => FindAllReturn, - - // Role - getByA11yRole: (A11yRole | RegExp) => GetReturn, - getByRole: (A11yRole | RegExp) => GetReturn, - getAllByA11yRole: (A11yRole | RegExp) => GetAllReturn, - getAllByRole: (A11yRole | RegExp) => GetAllReturn, - queryByA11yRole: (A11yRole | RegExp) => QueryReturn, - queryByRole: (A11yRole | RegExp) => QueryReturn, - queryAllByA11yRole: (A11yRole | RegExp) => QueryAllReturn, - queryAllByRole: (A11yRole | RegExp) => QueryAllReturn, - findByA11yRole: (A11yRole, ?WaitForOptions) => FindReturn, - findByRole: (A11yRole, ?WaitForOptions) => FindReturn, - findAllByA11yRole: (A11yRole, ?WaitForOptions) => FindAllReturn, - findAllByRole: (A11yRole, ?WaitForOptions) => FindAllReturn, - - // States - getByA11yStates: (A11yStates | Array) => GetReturn, - getAllByA11yStates: (A11yStates | Array) => GetAllReturn, - queryByA11yStates: (A11yStates | Array) => QueryReturn, - queryAllByA11yStates: (A11yStates | Array) => QueryAllReturn, - findByA11yStates: (A11yStates, ?WaitForOptions) => FindReturn, - findAllByA11yStates: (A11yStates, ?WaitForOptions) => FindAllReturn, - - // State - getByA11yState: (A11yState) => GetReturn, - getAllByA11yState: (A11yState) => GetAllReturn, - queryByA11yState: (A11yState) => QueryReturn, - queryAllByA11yState: (A11yState) => QueryAllReturn, - findByA11yState: (A11yState, ?WaitForOptions) => FindReturn, - findAllByA11yState: (A11yState, ?WaitForOptions) => FindAllReturn, - - // Value - getByA11yValue: (A11yValue) => GetReturn, - getAllByA11yValue: (A11yValue) => GetAllReturn, - queryByA11yValue: (A11yValue) => QueryReturn, - queryAllByA11yValue: (A11yValue) => QueryAllReturn, - findByA11yValue: (A11yValue, ?WaitForOptions) => FindReturn, - findAllByA11yValue: (A11yValue, ?WaitForOptions) => FindAllReturn, -|}; - -export function matchStringValue( - prop?: string, - matcher: string | RegExp -): boolean { - if (!prop) { - return false; - } - - if (typeof matcher === 'string') { - return prop === matcher; - } - - return Boolean(prop.match(matcher)); -} - -export function matchArrayValue( - prop?: Array, - matcher: string | Array -): boolean { - if (!prop || matcher.length === 0) { - return false; - } - - if (typeof matcher === 'string') { - return prop.includes(matcher); - } - - return !matcher.some((e) => !prop.includes(e)); -} - -export function matchObject(prop?: T, matcher: T): boolean { - return prop - ? Object.keys(matcher).length !== 0 && - Object.keys(prop).length !== 0 && - !Object.keys(matcher).some((key) => prop[key] !== matcher[key]) - : false; -} - -export const a11yAPI = (instance: ReactTestInstance): A11yAPI => - ({ - ...makeA11yQuery( - 'accessibilityLabel', - { - getBy: ['getByA11yLabel', 'getByAccessibilityLabel', 'getByLabelText'], - getAllBy: [ - 'getAllByA11yLabel', - 'getAllByAccessibilityLabel', - 'getAllByLabelText', - ], - queryBy: [ - 'queryByA11yLabel', - 'queryByAccessibilityLabel', - 'queryByLabelText', - ], - queryAllBy: [ - 'queryAllByA11yLabel', - 'queryAllByAccessibilityLabel', - 'queryAllByLabelText', - ], - findBy: [ - 'findByA11yLabel', - 'findByAccessibilityLabel', - 'findByLabelText', - ], - findAllBy: [ - 'findAllByA11yLabel', - 'findAllByAccessibilityLabel', - 'findAllByLabelText', - ], - }, - matchStringValue - )(instance), - ...makeA11yQuery( - 'accessibilityHint', - { - getBy: ['getByA11yHint', 'getByAccessibilityHint', 'getByHintText'], - getAllBy: [ - 'getAllByA11yHint', - 'getAllByAccessibilityHint', - 'getAllByHintText', - ], - queryBy: [ - 'queryByA11yHint', - 'queryByAccessibilityHint', - 'queryByHintText', - ], - queryAllBy: [ - 'queryAllByA11yHint', - 'queryAllByAccessibilityHint', - 'queryAllByHintText', - ], - findBy: ['findByA11yHint', 'findByAccessibilityHint', 'findByHintText'], - findAllBy: [ - 'findAllByA11yHint', - 'findAllByAccessibilityHint', - 'findAllByHintText', - ], - }, - matchStringValue - )(instance), - ...makeA11yQuery( - 'accessibilityRole', - { - getBy: ['getByA11yRole', 'getByAccessibilityRole', 'getByRole'], - getAllBy: [ - 'getAllByA11yRole', - 'getAllByAccessibilityRole', - 'getAllByRole', - ], - queryBy: ['queryByA11yRole', 'queryByAccessibilityRole', 'queryByRole'], - queryAllBy: [ - 'queryAllByA11yRole', - 'queryAllByAccessibilityRole', - 'queryAllByRole', - ], - findBy: ['findByA11yRole', 'findByAccessibilityRole', 'findByRole'], - findAllBy: [ - 'findAllByA11yRole', - 'findAllByAccessibilityRole', - 'findAllByRole', - ], - }, - matchStringValue - )(instance), - ...makeA11yQuery( - 'accessibilityStates', - { - getBy: ['getByA11yStates', 'getByAccessibilityStates'], - getAllBy: ['getAllByA11yStates', 'getAllByAccessibilityStates'], - queryBy: ['queryByA11yStates', 'queryByAccessibilityStates'], - queryAllBy: ['queryAllByA11yStates', 'queryAllByAccessibilityStates'], - findBy: ['findByA11yStates', 'findByAccessibilityStates'], - findAllBy: ['findAllByA11yStates', 'findAllByAccessibilityStates'], - }, - matchArrayValue - )(instance), - ...makeA11yQuery( - 'accessibilityState', - { - getBy: ['getByA11yState', 'getByAccessibilityState'], - getAllBy: ['getAllByA11yState', 'getAllByAccessibilityState'], - queryBy: ['queryByA11yState', 'queryByAccessibilityState'], - queryAllBy: ['queryAllByA11yState', 'queryAllByAccessibilityState'], - findBy: ['findByA11yState', 'findByAccessibilityState'], - findAllBy: ['findAllByA11yState', 'findAllByAccessibilityState'], - }, - matchObject - )(instance), - ...makeA11yQuery( - 'accessibilityValue', - { - getBy: ['getByA11yValue', 'getByAccessibilityValue'], - getAllBy: ['getAllByA11yValue', 'getAllByAccessibilityValue'], - queryBy: ['queryByA11yValue', 'queryByAccessibilityValue'], - queryAllBy: ['queryAllByA11yValue', 'queryAllByAccessibilityValue'], - findBy: ['findByA11yValue', 'findByAccessibilityValue'], - findAllBy: ['findAllByA11yValue', 'findAllByAccessibilityValue'], - }, - matchObject - )(instance), - }: any); diff --git a/src/helpers/a11yAPI.ts b/src/helpers/a11yAPI.ts new file mode 100644 index 000000000..4b9f42e53 --- /dev/null +++ b/src/helpers/a11yAPI.ts @@ -0,0 +1,261 @@ +import type { ReactTestInstance } from 'react-test-renderer'; +import type { AccessibilityRole, AccessibilityState } from 'react-native'; +import type { WaitForOptions } from '../waitFor'; +import type { TextMatch } from '../matches'; +import makeA11yQuery from './makeA11yQuery'; + +type AccessibilityStateKey = keyof AccessibilityState; +type A11yValue = { + min?: number; + max?: number; + now?: number; + text?: string; +}; + +type GetReturn = ReactTestInstance; +type GetAllReturn = Array; +type QueryReturn = ReactTestInstance | null; +type QueryAllReturn = Array; +type FindReturn = Promise; +type FindAllReturn = Promise; + +export type A11yAPI = { + // Label + getByLabelText: (label: TextMatch) => GetReturn; + getAllByLabelText: (label: TextMatch) => GetAllReturn; + queryByLabelText: (label: TextMatch) => QueryReturn; + queryAllByLabelText: (label: TextMatch) => QueryAllReturn; + findByLabelText: ( + label: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByLabelText: ( + label: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Hint + getByA11yHint: (a11yHint: TextMatch) => GetReturn; + getByHintText: (a11yHint: TextMatch) => GetReturn; + getAllByA11yHint: (a11yHint: TextMatch) => GetAllReturn; + getAllByHintText: (a11yHint: TextMatch) => GetAllReturn; + queryByA11yHint: (a11yHint: TextMatch) => QueryReturn; + queryByHintText: (a11yHint: TextMatch) => QueryReturn; + queryAllByA11yHint: (a11yHint: TextMatch) => QueryAllReturn; + queryAllByHintText: (a11yHint: TextMatch) => QueryAllReturn; + findByA11yHint: ( + a11yHint: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findByHintText: ( + a11yHint: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yHint: ( + a11yHint: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + findAllByHintText: ( + a11yHint: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Role + getByRole: (role: AccessibilityRole | RegExp) => GetReturn; + getAllByRole: (role: AccessibilityRole | RegExp) => GetAllReturn; + queryByRole: (role: AccessibilityRole | RegExp) => QueryReturn; + queryAllByRole: (role: AccessibilityRole | RegExp) => QueryAllReturn; + findByRole: ( + role: AccessibilityRole, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByRole: ( + role: AccessibilityRole, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // States + getByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey | Array + ) => GetReturn; + getAllByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey | Array + ) => GetAllReturn; + queryByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey | Array + ) => QueryReturn; + queryAllByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey | Array + ) => QueryAllReturn; + findByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yStates: ( + accessibilityStateKey: AccessibilityStateKey, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // State + getByA11yState: (accessibilityState: AccessibilityState) => GetReturn; + getAllByA11yState: (accessibilityState: AccessibilityState) => GetAllReturn; + queryByA11yState: (accessibilityState: AccessibilityState) => QueryReturn; + queryAllByA11yState: ( + accessibilityState: AccessibilityState + ) => QueryAllReturn; + findByA11yState: ( + accessibilityState: AccessibilityState, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yState: ( + accessibilityState: AccessibilityState, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Value + getByA11yValue: (a11yValue: A11yValue) => GetReturn; + getAllByA11yValue: (a11yValue: A11yValue) => GetAllReturn; + queryByA11yValue: (a11yValue: A11yValue) => QueryReturn; + queryAllByA11yValue: (a11yValue: A11yValue) => QueryAllReturn; + findByA11yValue: ( + a11yValue: A11yValue, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yValue: ( + a11yValue: A11yValue, + waitForOptions?: WaitForOptions + ) => FindAllReturn; +}; + +export function matchStringValue( + prop: string | undefined, + matcher: TextMatch +): boolean { + if (!prop) { + return false; + } + + if (typeof matcher === 'string') { + return prop === matcher; + } + + return Boolean(prop.match(matcher)); +} + +export function matchArrayValue( + prop: Array | undefined, + matcher: string | Array +): boolean { + if (!prop || matcher.length === 0) { + return false; + } + + if (typeof matcher === 'string') { + return prop.includes(matcher); + } + + return !matcher.some((e) => !prop.includes(e)); +} + +export function matchObject>( + prop: T | undefined, + matcher: T +): boolean { + return prop + ? Object.keys(matcher).length !== 0 && + Object.keys(prop).length !== 0 && + !Object.keys(matcher).some((key) => prop[key] !== matcher[key]) + : false; +} + +export const a11yAPI = (instance: ReactTestInstance): A11yAPI => + ({ + ...makeA11yQuery( + 'accessibilityLabel', + { + getBy: ['getByLabelText'], + getAllBy: ['getAllByLabelText'], + queryBy: ['queryByLabelText'], + queryAllBy: ['queryAllByLabelText'], + findBy: ['findByLabelText'], + findAllBy: ['findAllByLabelText'], + }, + matchStringValue + )(instance), + ...makeA11yQuery( + 'accessibilityHint', + { + getBy: ['getByA11yHint', 'getByAccessibilityHint', 'getByHintText'], + getAllBy: [ + 'getAllByA11yHint', + 'getAllByAccessibilityHint', + 'getAllByHintText', + ], + queryBy: [ + 'queryByA11yHint', + 'queryByAccessibilityHint', + 'queryByHintText', + ], + queryAllBy: [ + 'queryAllByA11yHint', + 'queryAllByAccessibilityHint', + 'queryAllByHintText', + ], + findBy: ['findByA11yHint', 'findByAccessibilityHint', 'findByHintText'], + findAllBy: [ + 'findAllByA11yHint', + 'findAllByAccessibilityHint', + 'findAllByHintText', + ], + }, + matchStringValue + )(instance), + ...makeA11yQuery( + 'accessibilityRole', + { + getBy: ['getByRole'], + getAllBy: ['getAllByRole'], + queryBy: ['queryByRole'], + queryAllBy: ['queryAllByRole'], + findBy: ['findByRole'], + findAllBy: ['findAllByRole'], + }, + matchStringValue + )(instance), + ...makeA11yQuery( + 'accessibilityStates', + { + getBy: ['getByA11yStates', 'getByAccessibilityStates'], + getAllBy: ['getAllByA11yStates', 'getAllByAccessibilityStates'], + queryBy: ['queryByA11yStates', 'queryByAccessibilityStates'], + queryAllBy: ['queryAllByA11yStates', 'queryAllByAccessibilityStates'], + findBy: ['findByA11yStates', 'findByAccessibilityStates'], + findAllBy: ['findAllByA11yStates', 'findAllByAccessibilityStates'], + }, + matchArrayValue + )(instance), + ...makeA11yQuery( + 'accessibilityState', + { + getBy: ['getByA11yState', 'getByAccessibilityState'], + getAllBy: ['getAllByA11yState', 'getAllByAccessibilityState'], + queryBy: ['queryByA11yState', 'queryByAccessibilityState'], + queryAllBy: ['queryAllByA11yState', 'queryAllByAccessibilityState'], + findBy: ['findByA11yState', 'findByAccessibilityState'], + findAllBy: ['findAllByA11yState', 'findAllByAccessibilityState'], + }, + matchObject + )(instance), + ...makeA11yQuery( + 'accessibilityValue', + { + getBy: ['getByA11yValue', 'getByAccessibilityValue'], + getAllBy: ['getAllByA11yValue', 'getAllByAccessibilityValue'], + queryBy: ['queryByA11yValue', 'queryByAccessibilityValue'], + queryAllBy: ['queryAllByA11yValue', 'queryAllByAccessibilityValue'], + findBy: ['findByA11yValue', 'findByAccessibilityValue'], + findAllBy: ['findAllByA11yValue', 'findAllByAccessibilityValue'], + }, + matchObject + )(instance), + } as any); diff --git a/src/helpers/byDisplayValue.js b/src/helpers/byDisplayValue.ts similarity index 81% rename from src/helpers/byDisplayValue.js rename to src/helpers/byDisplayValue.ts index e92bb8fd0..da89a6390 100644 --- a/src/helpers/byDisplayValue.js +++ b/src/helpers/byDisplayValue.ts @@ -1,5 +1,5 @@ -// @flow -import { matches } from '../matches'; +import type { ReactTestInstance } from 'react-test-renderer'; +import { matches, TextMatch } from '../matches'; import { makeQueries } from './makeQueries'; import type { Queries } from './makeQueries'; import { filterNodeByType } from './filterNodeByType'; @@ -7,9 +7,9 @@ import { createLibraryNotSupportedError } from './errors'; import type { TextMatchOptions } from './byText'; const getTextInputNodeByDisplayValue = ( - node, - value, - options?: TextMatchOptions = {} + node: ReactTestInstance, + value: TextMatch, + options: TextMatchOptions = {} ) => { try { const { TextInput } = require('react-native'); @@ -30,7 +30,7 @@ const getTextInputNodeByDisplayValue = ( const queryAllByDisplayValue = ( instance: ReactTestInstance ): (( - displayValue: string | RegExp, + displayValue: TextMatch, queryOptions?: TextMatchOptions ) => Array) => function queryAllByDisplayValueFn(displayValue, queryOptions) { @@ -39,9 +39,9 @@ const queryAllByDisplayValue = ( ); }; -const getMultipleError = (displayValue: string | RegExp) => +const getMultipleError = (displayValue: TextMatch) => `Found multiple elements with display value: ${String(displayValue)} `; -const getMissingError = (displayValue: string | RegExp) => +const getMissingError = (displayValue: TextMatch) => `Unable to find an element with displayValue: ${String(displayValue)}`; const { @@ -50,7 +50,7 @@ const { queryBy: queryByDisplayValue, findBy: findByDisplayValue, findAllBy: findAllByDisplayValue, -}: Queries = makeQueries( +}: Queries = makeQueries( queryAllByDisplayValue, getMissingError, getMultipleError diff --git a/src/helpers/byPlaceholderText.js b/src/helpers/byPlaceholderText.ts similarity index 80% rename from src/helpers/byPlaceholderText.js rename to src/helpers/byPlaceholderText.ts index e024be4eb..2145ef176 100644 --- a/src/helpers/byPlaceholderText.js +++ b/src/helpers/byPlaceholderText.ts @@ -1,5 +1,5 @@ -// @flow -import { matches } from '../matches'; +import type { ReactTestInstance } from 'react-test-renderer'; +import { matches, TextMatch } from '../matches'; import { makeQueries } from './makeQueries'; import type { Queries } from './makeQueries'; import { filterNodeByType } from './filterNodeByType'; @@ -7,9 +7,9 @@ import { createLibraryNotSupportedError } from './errors'; import type { TextMatchOptions } from './byText'; const getTextInputNodeByPlaceholderText = ( - node, - placeholder, - options?: TextMatchOptions = {} + node: ReactTestInstance, + placeholder: TextMatch, + options: TextMatchOptions = {} ) => { try { const { TextInput } = require('react-native'); @@ -26,7 +26,7 @@ const getTextInputNodeByPlaceholderText = ( const queryAllByPlaceholderText = ( instance: ReactTestInstance ): (( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions ) => Array) => function queryAllByPlaceholderFn(placeholder, queryOptions) { @@ -35,9 +35,9 @@ const queryAllByPlaceholderText = ( ); }; -const getMultipleError = (placeholder) => +const getMultipleError = (placeholder: TextMatch) => `Found multiple elements with placeholder: ${String(placeholder)} `; -const getMissingError = (placeholder) => +const getMissingError = (placeholder: TextMatch) => `Unable to find an element with placeholder: ${String(placeholder)}`; const { @@ -46,7 +46,7 @@ const { queryBy: queryByPlaceholderText, findBy: findByPlaceholderText, findAllBy: findAllByPlaceholderText, -}: Queries = makeQueries( +}: Queries = makeQueries( queryAllByPlaceholderText, getMissingError, getMultipleError diff --git a/src/helpers/byTestId.js b/src/helpers/byTestId.ts similarity index 73% rename from src/helpers/byTestId.js rename to src/helpers/byTestId.ts index 0518448be..e14e833e2 100644 --- a/src/helpers/byTestId.js +++ b/src/helpers/byTestId.ts @@ -1,10 +1,14 @@ -// @flow -import { matches } from '../matches'; +import type { ReactTestInstance } from 'react-test-renderer'; +import { matches, TextMatch } from '../matches'; import { makeQueries } from './makeQueries'; import type { Queries } from './makeQueries'; import type { TextMatchOptions } from './byText'; -const getNodeByTestId = (node, testID, options?: TextMatchOptions = {}) => { +const getNodeByTestId = ( + node: ReactTestInstance, + testID: TextMatch, + options: TextMatchOptions = {} +) => { const { exact, normalizer } = options; return matches(testID, node.props.testID, normalizer, exact); }; @@ -12,7 +16,7 @@ const getNodeByTestId = (node, testID, options?: TextMatchOptions = {}) => { const queryAllByTestId = ( instance: ReactTestInstance ): (( - testId: string | RegExp, + testId: TextMatch, queryOptions?: TextMatchOptions ) => Array) => function queryAllByTestIdFn(testId, queryOptions) { @@ -23,9 +27,9 @@ const queryAllByTestId = ( return results; }; -const getMultipleError = (testId) => +const getMultipleError = (testId: TextMatch) => `Found multiple elements with testID: ${String(testId)}`; -const getMissingError = (testId) => +const getMissingError = (testId: TextMatch) => `Unable to find an element with testID: ${String(testId)}`; const { @@ -34,7 +38,7 @@ const { queryBy: queryByTestId, findBy: findByTestId, findAllBy: findAllByTestId, -}: Queries = makeQueries( +}: Queries = makeQueries( queryAllByTestId, getMissingError, getMultipleError diff --git a/src/helpers/byText.js b/src/helpers/byText.ts similarity index 82% rename from src/helpers/byText.js rename to src/helpers/byText.ts index 8615f0507..1d9249798 100644 --- a/src/helpers/byText.js +++ b/src/helpers/byText.ts @@ -1,6 +1,6 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import * as React from 'react'; -import { matches } from '../matches'; +import { matches, TextMatch } from '../matches'; import type { NormalizerFn } from '../matches'; import { makeQueries } from './makeQueries'; import type { Queries } from './makeQueries'; @@ -8,12 +8,15 @@ import { filterNodeByType } from './filterNodeByType'; import { createLibraryNotSupportedError } from './errors'; export type TextMatchOptions = { - exact?: boolean, - normalizer?: NormalizerFn, + exact?: boolean; + normalizer?: NormalizerFn; }; -const getChildrenAsText = (children, TextComponent) => { - const textContent = []; +const getChildrenAsText = ( + children: React.ReactChild[], + TextComponent: React.ComponentType +) => { + const textContent: string[] = []; React.Children.forEach(children, (child) => { if (typeof child === 'string') { textContent.push(child); @@ -46,9 +49,9 @@ const getChildrenAsText = (children, TextComponent) => { }; const getNodeByText = ( - node, - text: string | RegExp, - options?: TextMatchOptions = {} + node: ReactTestInstance, + text: TextMatch, + options: TextMatchOptions = {} ) => { try { const { Text } = require('react-native'); @@ -70,7 +73,7 @@ const getNodeByText = ( const queryAllByText = ( instance: ReactTestInstance ): (( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions ) => Array) => function queryAllByTextFn(text, queryOptions) { @@ -81,9 +84,9 @@ const queryAllByText = ( return results; }; -const getMultipleError = (text: string | RegExp) => +const getMultipleError = (text: TextMatch) => `Found multiple elements with text: ${String(text)}`; -const getMissingError = (text: string | RegExp) => +const getMissingError = (text: TextMatch) => `Unable to find an element with text: ${String(text)}`; const { @@ -92,7 +95,7 @@ const { queryBy: queryByText, findBy: findByText, findAllBy: findAllByText, -}: Queries = makeQueries( +}: Queries = makeQueries( queryAllByText, getMissingError, getMultipleError diff --git a/src/helpers/debugDeep.js b/src/helpers/debugDeep.ts similarity index 55% rename from src/helpers/debugDeep.js rename to src/helpers/debugDeep.ts index 007115fca..bde90f155 100644 --- a/src/helpers/debugDeep.js +++ b/src/helpers/debugDeep.ts @@ -1,16 +1,18 @@ -// @flow +import type { ReactTestRendererJSON } from 'react-test-renderer'; import format from './format'; /** * Log pretty-printed deep test component instance */ export default function debugDeep( - instance: ?ReactTestRendererJSON, + instance: ReactTestRendererJSON | ReactTestRendererJSON[], message?: string ) { if (message) { + // eslint-disable-next-line no-console console.log(`${message}\n\n`, format(instance)); } else { + // eslint-disable-next-line no-console console.log(format(instance)); } } diff --git a/src/helpers/debugShallow.js b/src/helpers/debugShallow.ts similarity index 66% rename from src/helpers/debugShallow.js rename to src/helpers/debugShallow.ts index f02fa4d36..fe51f5e36 100644 --- a/src/helpers/debugShallow.js +++ b/src/helpers/debugShallow.ts @@ -1,5 +1,5 @@ -// @flow import * as React from 'react'; +import type { ReactTestInstance } from 'react-test-renderer'; import { shallowInternal } from '../shallow'; import format from './format'; @@ -7,14 +7,16 @@ import format from './format'; * Log pretty-printed shallow test component instance */ export default function debugShallow( - instance: ReactTestInstance | React.Element, + 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/errors.js b/src/helpers/errors.js deleted file mode 100644 index 8f4c74c9b..000000000 --- a/src/helpers/errors.js +++ /dev/null @@ -1,82 +0,0 @@ -// @flow -import prettyFormat from 'pretty-format'; - -export class ErrorWithStack extends Error { - constructor(message: ?string, callsite: Function) { - super(message); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, callsite); - } - } -} - -export const createLibraryNotSupportedError = (error: Error): Error => - new Error( - `Currently the only supported library to search by text is "react-native".\n\n${error.message}` - ); - -export const prepareErrorMessage = ( - error: Error, - name: ?string, - value: ?mixed -): string => { - // Strip info about custom predicate - let errorMessage = error.message.replace( - / matching custom predicate[^]*/gm, - '' - ); - - if (name && value) { - errorMessage += ` with ${name} ${prettyFormat(value, { min: true })}`; - } - return errorMessage; -}; - -export const createQueryByError = (error: Error, callsite: Function): null => { - if (error.message.includes('No instances found')) { - return null; - } - throw new ErrorWithStack(error.message, callsite); -}; - -export function copyStackTrace(target: Error, stackTraceSource: Error) { - target.stack = stackTraceSource.stack.replace( - stackTraceSource.message, - target.message - ); -} - -const warned = {}; - -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; -} - -export function throwRemovedFunctionError( - functionName: string, - docsRef: string -) { - throw new Error( - `"${functionName}" has been removed.\n\nPlease consult: https://callstack.github.io/react-native-testing-library/docs/${docsRef}` - ); -} - -export function throwRenamedFunctionError( - functionName: string, - newFunctionName: string -) { - throw new ErrorWithStack( - `The "${functionName}" function has been renamed to "${newFunctionName}". Please replace all occurrences.`, - throwRenamedFunctionError - ); -} diff --git a/src/helpers/errors.ts b/src/helpers/errors.ts new file mode 100644 index 000000000..11662fa32 --- /dev/null +++ b/src/helpers/errors.ts @@ -0,0 +1,106 @@ +import prettyFormat from 'pretty-format'; + +export class ErrorWithStack extends Error { + constructor(message: string | undefined, callsite: Function) { + super(message); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, callsite); + } + } +} + +export const createLibraryNotSupportedError = (error: unknown): Error => + new Error( + `Currently the only supported library to search by text is "react-native".\n\n${ + error instanceof Error ? error.message : '' + }` + ); + +export const prepareErrorMessage = ( + // TS states that error caught in a catch close are of type `unknown` + // most real cases will be `Error`, but better safe than sorry + error: unknown, + name?: string, + value?: unknown +): string => { + let errorMessage: string; + if (error instanceof Error) { + // Strip info about custom predicate + errorMessage = error.message.replace( + / matching custom predicate[^]*/gm, + '' + ); + } else if (error && typeof error === 'object') { + errorMessage = error.toString(); + } else { + errorMessage = 'Caught unknown error'; + } + + if (name && value) { + errorMessage += ` with ${name} ${prettyFormat(value, { min: true })}`; + } + return errorMessage; +}; + +export const createQueryByError = ( + error: NonNullable, + callsite: Function +): null => { + if (error instanceof Error) { + if (error.message.includes('No instances found')) { + return null; + } + throw new ErrorWithStack(error.message, callsite); + } + + throw new ErrorWithStack( + // generic refining of `unknown` is very hard, you cannot do `'toString' in error` or anything like that + // Converting as any with extra safe optional chaining will do the job just as well + `Query: caught unknown error type: ${typeof error}, value: ${(error as any)?.toString?.()}`, + callsite + ); +}; + +export function copyStackTrace(target: unknown, stackTraceSource: Error) { + if (target instanceof Error && stackTraceSource.stack) { + target.stack = stackTraceSource.stack.replace( + stackTraceSource.message, + target.message + ); + } +} + +const warned: { [functionName: string]: boolean } = {}; + +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; +} + +export function throwRemovedFunctionError( + functionName: string, + docsRef: string +) { + throw new Error( + `"${functionName}" has been removed.\n\nPlease consult: https://callstack.github.io/react-native-testing-library/docs/${docsRef}` + ); +} + +export function throwRenamedFunctionError( + functionName: string, + newFunctionName: string +) { + throw new ErrorWithStack( + `The "${functionName}" function has been renamed to "${newFunctionName}". Please replace all occurrences.`, + throwRenamedFunctionError + ); +} diff --git a/src/helpers/filterNodeByType.js b/src/helpers/filterNodeByType.js deleted file mode 100644 index 89b973467..000000000 --- a/src/helpers/filterNodeByType.js +++ /dev/null @@ -1 +0,0 @@ -export const filterNodeByType = (node, type) => node.type === type; diff --git a/src/helpers/filterNodeByType.ts b/src/helpers/filterNodeByType.ts new file mode 100644 index 000000000..751e73b3f --- /dev/null +++ b/src/helpers/filterNodeByType.ts @@ -0,0 +1,7 @@ +import type { ReactTestInstance } from 'react-test-renderer'; +import * as React from 'react'; + +export const filterNodeByType = ( + node: ReactTestInstance | React.ReactElement, + type: React.ElementType +) => node.type === type; diff --git a/src/helpers/findByAPI.js b/src/helpers/findByAPI.ts similarity index 74% rename from src/helpers/findByAPI.js rename to src/helpers/findByAPI.ts index 86750605d..551008137 100644 --- a/src/helpers/findByAPI.js +++ b/src/helpers/findByAPI.ts @@ -1,5 +1,6 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import type { WaitForOptions } from '../waitFor'; +import type { TextMatch } from '../matches'; import type { TextMatchOptions } from './byText'; import { findAllByTestId, findByTestId } from './byTestId'; import { findAllByText, findByText } from './byText'; @@ -10,50 +11,50 @@ import { import { findAllByDisplayValue, findByDisplayValue } from './byDisplayValue'; import { throwRenamedFunctionError } from './errors'; -export type FindByAPI = {| +export type FindByAPI = { findAllByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise>, - findAllByPlaceholder: () => void, + ) => Promise>; + findAllByPlaceholder: () => void; findAllByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise>, + ) => Promise>; findAllByTestId: ( - testId: string | RegExp, + testId: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise>, + ) => Promise>; findAllByText: ( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise>, + ) => Promise>; findByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise, - findByPlaceholder: () => void, + ) => Promise; + findByPlaceholder: () => void; findByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise, + ) => Promise; findByTestId: ( - testId: string | RegExp, + testId: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise, + ) => Promise; findByText: ( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions & WaitForOptions, waitForOptions?: WaitForOptions - ) => Promise, -|}; + ) => Promise; +}; export const findByAPI = (instance: ReactTestInstance): FindByAPI => ({ findByTestId: findByTestId(instance), diff --git a/src/helpers/format.js b/src/helpers/format.ts similarity index 58% rename from src/helpers/format.js rename to src/helpers/format.ts index f55f69b39..0a3868754 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.ts @@ -1,7 +1,7 @@ -// @flow +import type { ReactTestRendererJSON } from 'react-test-renderer'; import prettyFormat, { plugins } from 'pretty-format'; -const format = (input: ?ReactTestRendererJSON): typeof prettyFormat => +const format = (input: ReactTestRendererJSON | ReactTestRendererJSON[]) => prettyFormat(input, { plugins: [plugins.ReactTestComponent, plugins.ReactElement], highlight: true, diff --git a/src/helpers/getByAPI.js b/src/helpers/getByAPI.ts similarity index 62% rename from src/helpers/getByAPI.js rename to src/helpers/getByAPI.ts index c8f3ec918..0c816e9df 100644 --- a/src/helpers/getByAPI.js +++ b/src/helpers/getByAPI.ts @@ -1,12 +1,8 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import * as React from 'react'; import prettyFormat from 'pretty-format'; -import { - ErrorWithStack, - prepareErrorMessage, - throwRemovedFunctionError, - throwRenamedFunctionError, -} from './errors'; +import type { TextMatch } from '../matches'; +import { ErrorWithStack, prepareErrorMessage } from './errors'; import { getAllByTestId, getByTestId } from './byTestId'; import { getAllByText, getByText } from './byText'; import { @@ -16,58 +12,50 @@ import { import { getAllByDisplayValue, getByDisplayValue } from './byDisplayValue'; import type { TextMatchOptions } from './byText'; -export type GetByAPI = {| +export type GetByAPI = { getByText: ( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance, + ) => ReactTestInstance; getByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance, + ) => ReactTestInstance; getByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance, + ) => ReactTestInstance; getByTestId: ( - testID: string | RegExp, + testID: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance, + ) => ReactTestInstance; getAllByTestId: ( - testID: string | RegExp, + testID: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; getAllByText: ( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; getAllByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; getAllByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; // Unsafe aliases - UNSAFE_getByType:

(type: React.ComponentType

) => ReactTestInstance, + UNSAFE_getByType:

(type: React.ComponentType

) => ReactTestInstance; UNSAFE_getAllByType:

( type: React.ComponentType

- ) => Array, - UNSAFE_getByProps: (props: { [string]: any }) => ReactTestInstance, - UNSAFE_getAllByProps: (props: { [string]: any }) => Array, - - getByName: () => void, - getByType: () => void, - getByProps: () => void, - getAllByName: () => void, - getAllByType: () => void, - getAllByProps: () => void, - - getByPlaceholder: () => void, - getAllByPlaceholder: () => void, -|}; + ) => Array; + UNSAFE_getByProps: (props: { [key: string]: any }) => ReactTestInstance; + UNSAFE_getAllByProps: (props: { + [key: string]: any; + }) => Array; +}; export const UNSAFE_getByType = ( instance: ReactTestInstance @@ -131,27 +119,4 @@ export const getByAPI = (instance: ReactTestInstance): GetByAPI => ({ UNSAFE_getAllByType: UNSAFE_getAllByType(instance), UNSAFE_getByProps: UNSAFE_getByProps(instance), UNSAFE_getAllByProps: UNSAFE_getAllByProps(instance), - - // Removed - getByName: () => - throwRemovedFunctionError('getByName', 'migration-v2#removed-functions'), - getAllByName: () => - throwRemovedFunctionError('getAllByName', 'migration-v2#removed-functions'), - getByType: () => - throwRemovedFunctionError('getByType', 'migration-v2#removed-functions'), - getAllByType: () => - throwRemovedFunctionError('getAllByType', 'migration-v2#removed-functions'), - getByProps: () => - throwRemovedFunctionError('getByProps', 'migration-v2#removed-functions'), - getAllByProps: () => - throwRemovedFunctionError( - 'getAllByProps', - 'migration-v2#removed-functions' - ), - - // Renamed - getByPlaceholder: () => - throwRenamedFunctionError('getByPlaceholder', 'getByPlaceholderText'), - getAllByPlaceholder: () => - throwRenamedFunctionError('getAllByPlaceholder', 'getByPlaceholderText'), }); diff --git a/src/helpers/makeA11yQuery.js b/src/helpers/makeA11yQuery.ts similarity index 86% rename from src/helpers/makeA11yQuery.js rename to src/helpers/makeA11yQuery.ts index fff34e8f9..658f36f96 100644 --- a/src/helpers/makeA11yQuery.js +++ b/src/helpers/makeA11yQuery.ts @@ -1,4 +1,4 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import waitFor from '../waitFor'; import type { WaitForOptions } from '../waitFor'; import { @@ -18,21 +18,19 @@ function makeAliases(aliases: Array, query: Function) { } type QueryNames = { - getBy: Array, - getAllBy: Array, - queryBy: Array, - queryAllBy: Array, - findBy: Array, - findAllBy: Array, + getBy: Array; + getAllBy: Array; + queryBy: Array; + queryAllBy: Array; + findBy: Array; + findAllBy: Array; }; -const makeA11yQuery = ( +const makeA11yQuery =

( name: string, queryNames: QueryNames, matcherFn: (prop: P, value: M) => boolean -): ((instance: ReactTestInstance) => { ... }) => ( - instance: ReactTestInstance -) => { +) => (instance: ReactTestInstance) => { const getBy = (matcher: M) => { try { return instance.find( diff --git a/src/helpers/makeQueries.js b/src/helpers/makeQueries.ts similarity index 90% rename from src/helpers/makeQueries.js rename to src/helpers/makeQueries.ts index 5d0a4e1ce..78dd61661 100644 --- a/src/helpers/makeQueries.js +++ b/src/helpers/makeQueries.ts @@ -1,4 +1,4 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import waitFor from '../waitFor'; import type { WaitForOptions } from '../waitFor'; import { ErrorWithStack } from './errors'; @@ -35,16 +35,16 @@ type FindAllByQuery = FindQueryFunction< type FindByQuery = FindQueryFunction; export type Queries = { - getBy: GetByQuery, - getAllBy: GetAllByQuery, - queryBy: QueryByQuery, - findBy: FindByQuery, - findAllBy: FindAllByQuery, + getBy: GetByQuery; + getAllBy: GetAllByQuery; + queryBy: QueryByQuery; + findBy: FindByQuery; + findAllBy: FindAllByQuery; }; // The WaitForOptions has been moved to the second option param of findBy* methods with the adding of TextMatchOptions // To make the migration easier and avoid a breaking change, keep reading this options from the first param but warn -const deprecatedKeys: $Keys[] = [ +const deprecatedKeys: (keyof WaitForOptions)[] = [ 'timeout', 'interval', 'stackTraceError', @@ -57,13 +57,14 @@ const extractDeprecatedWaitForOptionUsage = (queryOptions?: WaitForOptions) => { stackTraceError: queryOptions.stackTraceError, }; deprecatedKeys.forEach((key) => { - if (queryOptions[key]) { + const option = queryOptions[key]; + if (option) { // eslint-disable-next-line no-console console.warn( `Use of option "${key}" in a findBy* query's second parameter, TextMatchOptions, is deprecated. Please pass this option in the third, WaitForOptions, parameter. Example: - findByText(text, {}, { ${key}: ${queryOptions[key].toString()} })` + findByText(text, {}, { ${key}: ${option.toString()} })` ); } }); @@ -127,7 +128,7 @@ export function makeQueries( return function findAllFn( args: QueryArg, queryOptions?: TextMatchOptions & WaitForOptions, - waitForOptions?: WaitForOptions = {} + waitForOptions: WaitForOptions = {} ) { const deprecatedWaitForOptions = extractDeprecatedWaitForOptionUsage( queryOptions @@ -143,7 +144,7 @@ export function makeQueries( return function findFn( args: QueryArg, queryOptions?: TextMatchOptions & WaitForOptions, - waitForOptions?: WaitForOptions = {} + waitForOptions: WaitForOptions = {} ) { const deprecatedWaitForOptions = extractDeprecatedWaitForOptionUsage( queryOptions diff --git a/src/helpers/queryByAPI.js b/src/helpers/queryByAPI.ts similarity index 78% rename from src/helpers/queryByAPI.js rename to src/helpers/queryByAPI.ts index 064bb3cc8..12f73ecc5 100644 --- a/src/helpers/queryByAPI.js +++ b/src/helpers/queryByAPI.ts @@ -1,5 +1,6 @@ -// @flow +import type { ReactTestInstance } from 'react-test-renderer'; import * as React from 'react'; +import type { TextMatch } from '../matches'; import type { TextMatchOptions } from './byText'; import { UNSAFE_getByType, @@ -20,55 +21,57 @@ import { throwRenamedFunctionError, } from './errors'; -export type QueryByAPI = {| +export type QueryByAPI = { queryByText: ( - name: string | RegExp, + name: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance | null, + ) => ReactTestInstance | null; queryAllByText: ( - text: string | RegExp, + text: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; queryByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance | null, + ) => ReactTestInstance | null; queryAllByPlaceholderText: ( - placeholder: string | RegExp, + placeholder: TextMatch, queryOptions?: TextMatchOptions - ) => Array, + ) => Array; queryByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions - ) => ReactTestInstance | null, + ) => ReactTestInstance | null; queryAllByDisplayValue: ( - value: string | RegExp, + value: TextMatch, queryOptions?: TextMatchOptions - ) => Array, - queryByTestId: (testID: string | RegExp) => ReactTestInstance | null, - queryAllByTestId: (testID: string | RegExp) => Array, + ) => Array; + queryByTestId: (testID: TextMatch) => ReactTestInstance | null; + queryAllByTestId: (testID: TextMatch) => Array; // Unsafe aliases UNSAFE_queryByType:

( type: React.ComponentType

- ) => ReactTestInstance | null, + ) => ReactTestInstance | null; UNSAFE_queryAllByType:

( type: React.ComponentType

- ) => Array, - UNSAFE_queryByProps: (props: { [string]: any }) => ReactTestInstance | null, + ) => Array; + UNSAFE_queryByProps: (props: { + [key: string]: any; + }) => ReactTestInstance | null; UNSAFE_queryAllByProps: (props: { - [string]: any, - }) => Array, - queryByName: () => void, - queryByType: () => void, - queryByProps: () => void, - queryAllByName: () => void, - queryAllByType: () => void, - queryAllByProps: () => void, + [key: string]: any; + }) => Array; + queryByName: () => void; + queryByType: () => void; + queryByProps: () => void; + queryAllByName: () => void; + queryAllByType: () => void; + queryAllByProps: () => void; - queryByPlaceholder: () => void, - queryAllByPlaceholder: () => void, -|}; + queryByPlaceholder: () => void; + queryAllByPlaceholder: () => void; +}; export const UNSAFE_queryByType = ( instance: ReactTestInstance @@ -107,7 +110,7 @@ export const UNSAFE_queryAllByType = ( export const UNSAFE_queryAllByProps = ( instance: ReactTestInstance ): ((props: { - [propName: string]: any, + [propName: string]: any; }) => Array) => (props: { [propName: string]: any }) => { try { return UNSAFE_getAllByProps(instance)(props); diff --git a/src/helpers/timers.js b/src/helpers/timers.ts similarity index 82% rename from src/helpers/timers.js rename to src/helpers/timers.ts index 95868d683..e140e991a 100644 --- a/src/helpers/timers.js +++ b/src/helpers/timers.ts @@ -1,7 +1,5 @@ // Most content of this file sourced directly from https://github.com/testing-library/dom-testing-library/blob/main/src/helpers.js -// @flow /* globals jest */ - const globalObj = typeof window === 'undefined' ? global : window; // Currently this fn only supports jest timers, but it could support other test runners in the future. @@ -30,20 +28,21 @@ function getJestFakeTimersType() { } if ( + // @ts-expect-error jest mutates setTimeout typeof globalObj.setTimeout._isMockFunction !== 'undefined' && + // @ts-expect-error jest mutates setTimeout globalObj.setTimeout._isMockFunction ) { return 'legacy'; } if ( + // @ts-expect-error jest mutates setTimeout typeof globalObj.setTimeout.clock !== 'undefined' && - // $FlowIgnore[prop-missing] typeof jest.getRealSystemTime !== 'undefined' ) { try { // jest.getRealSystemTime is only supported for Jest's `modern` fake timers and otherwise throws - // $FlowExpectedError jest.getRealSystemTime(); return 'modern'; } catch { @@ -57,14 +56,14 @@ const jestFakeTimersAreEnabled = (): boolean => Boolean(getJestFakeTimersType()); // we only run our tests in node, and setImmediate is supported in node. -function setImmediatePolyfill(fn) { +function setImmediatePolyfill(fn: Function) { return globalObj.setTimeout(fn, 0); } type BindTimeFunctions = { - clearTimeoutFn: typeof clearTimeout, - setImmediateFn: typeof setImmediate, - setTimeoutFn: typeof setTimeout, + clearTimeoutFn: typeof clearTimeout; + setImmediateFn: typeof setImmediate; + setTimeoutFn: typeof setTimeout; }; function bindTimeFunctions(): BindTimeFunctions { @@ -75,9 +74,9 @@ function bindTimeFunctions(): BindTimeFunctions { }; } -const { clearTimeoutFn, setImmediateFn, setTimeoutFn } = (runWithRealTimers( +const { clearTimeoutFn, setImmediateFn, setTimeoutFn } = runWithRealTimers( bindTimeFunctions -): BindTimeFunctions); +) as BindTimeFunctions; export { runWithRealTimers, diff --git a/src/index.js b/src/index.ts similarity index 98% rename from src/index.js rename to src/index.ts index d4cb964e8..a8bc65b9f 100644 --- a/src/index.js +++ b/src/index.ts @@ -1,4 +1,3 @@ -// @flow import { cleanup } from './pure'; import { flushMicroTasks } from './flushMicroTasks'; diff --git a/src/matches.js b/src/matches.ts similarity index 81% rename from src/matches.js rename to src/matches.ts index b5cfcd74c..1783dec35 100644 --- a/src/matches.js +++ b/src/matches.ts @@ -1,11 +1,11 @@ -// @flow export type NormalizerFn = (textToNormalize: string) => string; +export type TextMatch = string | RegExp; export function matches( - matcher: string | RegExp, + matcher: TextMatch, text: string, - normalizer?: NormalizerFn = getDefaultNormalizer(), - exact?: boolean = true + normalizer: NormalizerFn = getDefaultNormalizer(), + exact: boolean = true ): boolean { if (typeof text !== 'string') { return false; @@ -22,8 +22,8 @@ export function matches( } type NormalizerConfig = { - trim?: boolean, - collapseWhitespace?: boolean, + trim?: boolean; + collapseWhitespace?: boolean; }; export function getDefaultNormalizer({ diff --git a/src/pure.js b/src/pure.ts similarity index 67% rename from src/pure.js rename to src/pure.ts index 61d9c5414..9baffa97f 100644 --- a/src/pure.js +++ b/src/pure.ts @@ -1,11 +1,8 @@ -// @flow import act from './act'; import cleanup from './cleanup'; import fireEvent from './fireEvent'; -import flushMicrotasksQueue from './flushMicroTasks'; import render from './render'; -import shallow from './shallow'; -import waitFor, { waitForElement } from './waitFor'; +import waitFor from './waitFor'; import waitForElementToBeRemoved from './waitForElementToBeRemoved'; import { within, getQueriesForElement } from './within'; import { getDefaultNormalizer } from './matches'; @@ -13,10 +10,8 @@ import { getDefaultNormalizer } from './matches'; export { act }; export { cleanup }; export { fireEvent }; -export { flushMicrotasksQueue }; export { render }; -export { shallow }; -export { waitFor, waitForElement }; +export { waitFor }; export { waitForElementToBeRemoved }; export { within, getQueriesForElement }; export { getDefaultNormalizer }; diff --git a/src/render.js b/src/render.tsx similarity index 57% rename from src/render.js rename to src/render.tsx index e6323d58d..1f446900a 100644 --- a/src/render.js +++ b/src/render.tsx @@ -1,21 +1,21 @@ -// @flow +import TestRenderer from 'react-test-renderer'; +import type { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; import * as React from 'react'; -import TestRenderer, { type ReactTestRenderer } from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies import act from './act'; import { addToCleanupQueue } from './cleanup'; -import { getByAPI, type GetByAPI } from './helpers/getByAPI'; -import { queryByAPI, type QueryByAPI } from './helpers/queryByAPI'; -import { findByAPI, type FindByAPI } from './helpers/findByAPI'; -import { a11yAPI, type A11yAPI } from './helpers/a11yAPI'; +import { getByAPI } from './helpers/getByAPI'; +import { queryByAPI } from './helpers/queryByAPI'; +import { findByAPI } from './helpers/findByAPI'; +import { a11yAPI } from './helpers/a11yAPI'; import debugShallow from './helpers/debugShallow'; import debugDeep from './helpers/debugDeep'; type Options = { - wrapper?: React.ComponentType, - createNodeMock?: (element: React.Element) => any, + wrapper?: React.ComponentType; + createNodeMock?: (element: React.ReactElement) => any; }; type TestRendererOptions = { - createNodeMock: (element: React.Element) => any, + createNodeMock: (element: React.ReactElement) => any; }; /** @@ -23,21 +23,10 @@ type TestRendererOptions = { * to assert on the output. */ export default function render( - component: React.Element, + component: React.ReactElement, { wrapper: Wrapper, createNodeMock }: Options = {} -): { - ...FindByAPI, - ...QueryByAPI, - ...GetByAPI, - ...A11yAPI, - update: (component: React.Element) => void, - container: ReactTestInstance, - rerender: (component: React.Element) => void, - unmount: (nextElement?: React.Element) => void, - toJSON: () => null | ReactTestRendererJSON, - debug: DebugFunction, -} { - const wrap = (innerElement: React.Element) => +) { + const wrap = (innerElement: React.ReactElement) => Wrapper ? {innerElement} : innerElement; const renderer = renderWithAct( @@ -69,7 +58,7 @@ export default function render( } function renderWithAct( - component: React.Element, + component: React.ReactElement, options?: TestRendererOptions ): ReactTestRenderer { let renderer: ReactTestRenderer; @@ -78,14 +67,15 @@ function renderWithAct( renderer = TestRenderer.create(component, options); }); - return ((renderer: any): ReactTestRenderer); + // @ts-ignore act is sync, so renderer is always initialised here + return renderer; } function updateWithAct( renderer: ReactTestRenderer, - wrap: (innerElement: React.Element) => React.Element + wrap: (innerElement: React.ReactElement) => React.ReactElement ) { - return function (component: React.Element) { + return function (component: React.ReactElement) { act(() => { renderer.update(wrap(component)); }); @@ -102,8 +92,11 @@ function debug( renderer: ReactTestRenderer ): DebugFunction { function debugImpl(message?: string) { - return debugDeep(renderer.toJSON(), message); + const json = renderer.toJSON(); + if (json) { + return debugDeep(json, message); + } } - debugImpl.shallow = (message) => debugShallow(instance, message); + debugImpl.shallow = (message?: string) => debugShallow(instance, message); return debugImpl; } diff --git a/src/shallow.js b/src/shallow.ts similarity index 51% rename from src/shallow.js rename to src/shallow.ts index d3fecd0c3..bc5ae0993 100644 --- a/src/shallow.js +++ b/src/shallow.ts @@ -1,15 +1,14 @@ -// @flow 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 -import { throwRemovedFunctionError } from './helpers/errors'; /** * Renders test component shallowly using react-test-renderer/shallow */ export function shallowInternal( - instance: ReactTestInstance | React.Element -): {| output: any |} { - const renderer = new ShallowRenderer(); + instance: ReactTestInstance | React.ReactElement +): { output: any } { + const renderer = new (ShallowRenderer as any)(); renderer.render(React.createElement(instance.type, instance.props)); @@ -17,10 +16,3 @@ export function shallowInternal( output: renderer.getRenderOutput(), }; } - -export default function shallow(_: ReactTestInstance | React.Element) { - throwRemovedFunctionError( - 'shallow', - 'migration-v2#removed-global-shallow-function' - ); -} diff --git a/src/types.flow.js b/src/types.flow.js deleted file mode 100644 index c48b5ed0e..000000000 --- a/src/types.flow.js +++ /dev/null @@ -1,59 +0,0 @@ -// @flow - -export type Thenable = { - then(resolve: () => mixed, reject?: () => mixed): mixed, -}; - -export type A11yRole = - | 'none' - | 'button' - | 'link' - | 'search' - | 'image' - | 'keyboardkey' - | 'text' - | 'adjustable' - | 'imagebutton' - | 'header' - | 'summary' - | 'alert' - | 'checkbox' - | 'combobox' - | 'menu' - | 'menubar' - | 'menuitem' - | 'progressbar' - | 'radio' - | 'radiogroup' - | 'scrollbar' - | 'spinbutton' - | 'switch' - | 'tab' - | 'tablist' - | 'timer' - | 'toolbar'; - -export type A11yState = {| - disabled?: boolean, - selected?: boolean, - checked?: boolean | 'mixed', - busy?: boolean, - expanded?: boolean, -|}; - -export type A11yStates = - | 'disabled' - | 'selected' - | 'checked' - | 'unchecked' - | 'busy' - | 'expanded' - | 'collapsed' - | 'hasPopup'; - -export type A11yValue = { - min?: number, - max?: number, - now?: number, - text?: string, -}; diff --git a/src/waitFor.js b/src/waitFor.ts similarity index 85% rename from src/waitFor.js rename to src/waitFor.ts index 3e5a881f0..35d42c7ad 100644 --- a/src/waitFor.js +++ b/src/waitFor.ts @@ -1,13 +1,7 @@ -// @flow /* globals jest */ - import * as React from 'react'; import act from './act'; -import { - ErrorWithStack, - throwRemovedFunctionError, - copyStackTrace, -} from './helpers/errors'; +import { ErrorWithStack, copyStackTrace } from './helpers/errors'; import { setTimeout, clearTimeout, @@ -26,10 +20,10 @@ function checkReactVersionAtLeast(major: number, minor: number): boolean { } export type WaitForOptions = { - timeout?: number, - interval?: number, - stackTraceError?: ErrorWithStack, - onTimeout?: (error: Error) => Error, + timeout?: number; + interval?: number; + stackTraceError?: ErrorWithStack; + onTimeout?: (error: unknown) => Error; }; function waitForInternal( @@ -47,7 +41,7 @@ function waitForInternal( // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { - let lastError, intervalId; + let lastError: unknown, intervalId: ReturnType; let finished = false; let promiseStatus = 'idle'; @@ -107,7 +101,9 @@ function waitForInternal( checkExpectation(); } - function onDone(error, result) { + function onDone( + done: { type: 'result'; result: T } | { type: 'error'; error: unknown } + ) { finished = true; clearTimeout(overallTimeoutTimer); @@ -115,11 +111,10 @@ function waitForInternal( clearInterval(intervalId); } - if (error) { - reject(error); + if (done.type === 'error') { + reject(done.error); } else { - // $FlowIgnore[incompatible-return] error and result are mutually exclusive - resolve(result); + resolve(done.result); } } @@ -142,14 +137,16 @@ function waitForInternal( try { const result = expectation(); - // $FlowIgnore[incompatible-type] + // @ts-ignore result can be a promise + // eslint-disable-next-line promise/prefer-await-to-then if (typeof result?.then === 'function') { + const promiseResult: Promise = result as any; promiseStatus = 'pending'; - // eslint-disable-next-line promise/catch-or-return - result.then( + // eslint-disable-next-line promise/catch-or-return, promise/prefer-await-to-then + promiseResult.then( (resolvedValue) => { promiseStatus = 'resolved'; - onDone(null, resolvedValue); + onDone({ type: 'result', result: resolvedValue }); return; }, (rejectedValue) => { @@ -159,7 +156,7 @@ function waitForInternal( } ); } else { - onDone(null, result); + onDone({ type: 'result', result: result }); } // If `callback` throws, wait for the next mutation, interval, or timeout. } catch (error) { @@ -184,7 +181,7 @@ function waitForInternal( if (typeof onTimeout === 'function') { onTimeout(error); } - onDone(error, null); + onDone({ type: 'error', error }); } }); } @@ -203,24 +200,10 @@ export default async function waitFor( let result: T; - //$FlowFixMe: `act` has incorrect flow typing await act(async () => { result = await waitForInternal(expectation, optionsWithStackTrace); }); - //$FlowFixMe: either we have result or `waitFor` threw error - return result; -} - -export function waitForElement( - expectation: () => T, - _timeout: number = 4500, - _interval: number = 50 -): Promise { - throwRemovedFunctionError( - 'waitForElement', - 'migration-v2#waitfor-api-changes' - ); - - return Promise.reject(); + // Either we have result or `waitFor` threw error + return result!; } diff --git a/src/waitForElementToBeRemoved.js b/src/waitForElementToBeRemoved.ts similarity index 93% rename from src/waitForElementToBeRemoved.js rename to src/waitForElementToBeRemoved.ts index fb3cc5bc4..9308bec25 100644 --- a/src/waitForElementToBeRemoved.js +++ b/src/waitForElementToBeRemoved.ts @@ -1,5 +1,5 @@ -// @flow -import waitFor, { type WaitForOptions } from './waitFor'; +import waitFor from './waitFor'; +import type { WaitForOptions } from './waitFor'; import { ErrorWithStack } from './helpers/errors'; function isRemoved(result: T): boolean { diff --git a/src/within.js b/src/within.js deleted file mode 100644 index 9b54671e8..000000000 --- a/src/within.js +++ /dev/null @@ -1,18 +0,0 @@ -// @flow -import { getByAPI, type GetByAPI } from './helpers/getByAPI'; -import { queryByAPI, type QueryByAPI } from './helpers/queryByAPI'; -import { findByAPI, type FindByAPI } from './helpers/findByAPI'; -import { a11yAPI, type A11yAPI } from './helpers/a11yAPI'; - -export function within( - instance: ReactTestInstance -): { ...FindByAPI, ...QueryByAPI, ...GetByAPI, ...A11yAPI } { - return { - ...getByAPI(instance), - ...queryByAPI(instance), - ...findByAPI(instance), - ...a11yAPI(instance), - }; -} - -export const getQueriesForElement = within; diff --git a/src/within.ts b/src/within.ts new file mode 100644 index 000000000..bfc6304a9 --- /dev/null +++ b/src/within.ts @@ -0,0 +1,16 @@ +import type { ReactTestInstance } from 'react-test-renderer'; +import { getByAPI } from './helpers/getByAPI'; +import { queryByAPI } from './helpers/queryByAPI'; +import { findByAPI } from './helpers/findByAPI'; +import { a11yAPI } from './helpers/a11yAPI'; + +export function within(instance: ReactTestInstance) { + return { + ...getByAPI(instance), + ...queryByAPI(instance), + ...findByAPI(instance), + ...a11yAPI(instance), + }; +} + +export const getQueriesForElement = within; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..620131f6b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "jsx": "react", + "target": "ES2020", + "lib": ["ES2020", "DOM"], + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "noEmit": true, + "outDir": "build" + }, + "include": ["src/**/*"] +} diff --git a/tsconfig.release.json b/tsconfig.release.json new file mode 100644 index 000000000..7477c950f --- /dev/null +++ b/tsconfig.release.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true + }, + "exclude": ["**/__tests__**"] +} diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx deleted file mode 100644 index 6cd6c558c..000000000 --- a/typings/__tests__/index.test.tsx +++ /dev/null @@ -1,486 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import * as React from 'react'; -import { ReactTestInstance } from 'react-test-renderer'; -import { - render, - fireEvent, - flushMicrotasksQueue, - waitFor, - waitForElementToBeRemoved, - act, - within, - getQueriesForElement, - getDefaultNormalizer, -} from '../..'; - -interface HasRequiredProp { - requiredProp: string; -} - -const View = (props) => props.children; -const Text = (props) => props.children; -const TextInput = (props) => props.children; -const ElementWithRequiredProps = (props: HasRequiredProp) => ( - {props.requiredProp} -); - -const TestComponent = () => ( - - Test component - - -); - -const tree = render(); - -// getBy API -const getBy: ReactTestInstance[] = [ - tree.getByText(''), - tree.getByText(/View/g), - tree.getByPlaceholderText('my placeholder'), - tree.getByPlaceholderText(/placeholder/g), - tree.getByDisplayValue('my value'), - tree.getByDisplayValue(/value/g), - tree.getByTestId('test-id'), - tree.getByTestId(/test-id/), - tree.getByA11yLabel('label'), - tree.getByLabelText('label'), - tree.getByA11yHint('label'), - tree.getByHintText('label'), - tree.getByA11yRole('button'), - tree.getByRole('button'), - tree.getByA11yStates('selected'), - tree.getByA11yStates(['selected']), - tree.getByA11yState({ busy: true }), - tree.getByA11yValue({ min: 10 }), - tree.UNSAFE_getByType(View), - tree.UNSAFE_getByType(ElementWithRequiredProps), - tree.UNSAFE_getByProps({ value: 2 }), -]; - -const getAllBy: ReactTestInstance[][] = [ - tree.getAllByText(''), - tree.getAllByText(/Text/g), - tree.getAllByPlaceholderText('my placeholder'), - tree.getAllByPlaceholderText(/placeholder/g), - tree.getAllByDisplayValue('my value'), - tree.getAllByDisplayValue(/value/g), - tree.getAllByTestId('test-id'), - tree.getAllByTestId(/value/g), - tree.getAllByA11yLabel('label'), - tree.getAllByLabelText('label'), - tree.getAllByA11yHint('label'), - tree.getAllByHintText('label'), - tree.getAllByA11yRole('button'), - tree.getAllByRole('button'), - tree.getAllByA11yStates('selected'), - tree.getAllByA11yStates(['selected']), - tree.getAllByA11yState({ busy: true }), - tree.getAllByA11yValue({ min: 10 }), - tree.UNSAFE_getAllByType(View), - tree.UNSAFE_getAllByType(ElementWithRequiredProps), - tree.UNSAFE_getAllByProps({ value: 2 }), -]; - -// queryBy API -const queryBy: Array = [ - tree.queryByText('View'), - tree.queryByText(/View/g), - tree.queryByPlaceholderText('my placeholder'), - tree.queryByPlaceholderText(/placeholder/g), - tree.queryByDisplayValue('my value'), - tree.queryByDisplayValue(/value/g), - tree.queryByTestId('test-id'), - tree.queryByTestId(/test-id/), - tree.queryByA11yHint('label'), - tree.queryByHintText('label'), - tree.queryByA11yLabel('label'), - tree.queryByLabelText('label'), - tree.queryByA11yRole('button'), - tree.queryByRole('button'), - tree.queryByA11yStates('selected'), - tree.queryByA11yStates(['selected']), - tree.queryByA11yState({ busy: true }), - tree.queryByA11yValue({ min: 10 }), - tree.UNSAFE_queryByType(View), - tree.UNSAFE_queryByType(ElementWithRequiredProps), - tree.UNSAFE_queryByProps({ value: 2 }), -]; - -const queryAllBy: ReactTestInstance[][] = [ - tree.queryAllByText('View'), - tree.queryAllByText(/View/g), - tree.queryAllByPlaceholderText('my placeholder'), - tree.queryAllByPlaceholderText(/placeholder/g), - tree.queryAllByDisplayValue('my value'), - tree.queryAllByDisplayValue(/value/g), - tree.queryAllByTestId('test-id'), - tree.queryAllByTestId(/test-id/), - tree.queryAllByA11yLabel('label'), - tree.queryAllByLabelText('label'), - tree.queryAllByA11yHint('label'), - tree.queryAllByHintText('label'), - tree.queryAllByA11yRole('button'), - tree.queryAllByRole('button'), - tree.queryAllByA11yStates('selected'), - tree.queryAllByA11yStates(['selected']), - tree.queryAllByA11yState({ busy: true }), - tree.queryAllByA11yValue({ min: 10 }), - tree.UNSAFE_queryAllByType(View), - tree.UNSAFE_queryAllByType(ElementWithRequiredProps), - tree.UNSAFE_queryAllByProps({ value: 2 }), -]; - -// findBy API -const findBy: Promise[] = [ - tree.findByText('View'), - tree.findByText('View', {}, { timeout: 10, interval: 10 }), - tree.findByText(/View/g), - tree.findByText(/View/g, {}, { timeout: 10, interval: 5 }), - tree.findByPlaceholderText('my placeholder'), - tree.findByPlaceholderText( - 'my placeholder', - {}, - { timeout: 10, interval: 5 } - ), - tree.findByPlaceholderText(/placeholder/g), - tree.findByPlaceholderText(/placeholder/g, {}, { timeout: 10, interval: 5 }), - tree.findByDisplayValue('my value'), - tree.findByDisplayValue('my value', {}, { timeout: 10, interval: 10 }), - tree.findByDisplayValue(/value/g), - tree.findByDisplayValue(/value/g, {}, { timeout: 10, interval: 10 }), - tree.findByTestId('test-id'), - tree.findByTestId(/test-id/, {}, { timeout: 10, interval: 10 }), - tree.findByA11yLabel('label'), - tree.findByA11yLabel('label', { timeout: 10, interval: 10 }), - tree.findByLabelText('label'), - tree.findByLabelText('label', { timeout: 10, interval: 10 }), - tree.findByA11yHint('label'), - tree.findByA11yHint('label', { timeout: 10, interval: 10 }), - tree.findByHintText('label'), - tree.findByHintText('label', { timeout: 10, interval: 10 }), - tree.findByA11yRole('button'), - tree.findByA11yRole('button', { timeout: 10, interval: 10 }), - tree.findByRole('button'), - tree.findByRole('button', { timeout: 10, interval: 10 }), - tree.findByA11yState({ busy: true }), - tree.findByA11yState({ busy: true }, { timeout: 10, interval: 10 }), - tree.findByA11yValue({ min: 10 }), - tree.findByA11yValue({ min: 10 }, { timeout: 10, interval: 10 }), -]; - -const findAllBy: Promise[] = [ - tree.findAllByText('View'), - tree.findAllByText('View', {}, { timeout: 10, interval: 10 }), - tree.findAllByText(/View/g), - tree.findAllByText(/View/g, { exact: false }, { timeout: 10, interval: 5 }), - tree.findAllByPlaceholderText('my placeholder'), - tree.findAllByPlaceholderText( - 'my placeholder', - { exact: false }, - { - timeout: 10, - interval: 10, - } - ), - tree.findAllByPlaceholderText(/placeholder/g), - tree.findAllByPlaceholderText( - /placeholder/g, - {}, - { timeout: 10, interval: 10 } - ), - tree.findAllByDisplayValue('View'), - tree.findAllByDisplayValue('View', {}, { timeout: 10, interval: 10 }), - tree.findAllByDisplayValue(/View/g), - tree.findAllByDisplayValue(/View/g, {}, { timeout: 10, interval: 10 }), - tree.findAllByTestId('test-id'), - tree.findAllByTestId(/test-id/, {}, { timeout: 10, interval: 10 }), - tree.findAllByA11yLabel('label'), - tree.findAllByA11yLabel('label', { timeout: 10, interval: 10 }), - tree.findAllByLabelText('label'), - tree.findAllByLabelText('label', { timeout: 10, interval: 10 }), - tree.findAllByA11yHint('label'), - tree.findAllByA11yHint('label', { timeout: 10, interval: 10 }), - tree.findAllByHintText('label'), - tree.findAllByHintText('label', { timeout: 10, interval: 10 }), - tree.findAllByA11yState({ busy: true }), - tree.findAllByA11yState({ busy: true }, { timeout: 10, interval: 10 }), - tree.findAllByA11yValue({ min: 10 }), - tree.findAllByA11yValue({ min: 10 }, { timeout: 10, interval: 10 }), -]; - -// debug API -const debugFn = tree.debug(); -const debugFnWithMessage = tree.debug('my message'); -const shallowDebug = tree.debug.shallow(); -const shallowDebugWithMessage = tree.debug.shallow('my message'); - -// update API -tree.update(); -tree.rerender(); -tree.unmount(); - -// fireEvent API -const element: ReactTestInstance = tree.getByText('text'); -fireEvent(element, 'press'); -fireEvent(element, 'press', 'data'); -fireEvent(element, 'press', 'param1', 'param2'); -fireEvent.press(element); -fireEvent.changeText(element, 'string'); -fireEvent.scroll(element, 'eventData'); - -// waitFor API -const timeout = { timeout: 10 }; -const timeoutInterval = { timeout: 100, interval: 10 }; - -const waitGetBy: Promise[] = [ - waitFor(() => tree.getByA11yLabel('label')), - waitFor(() => tree.getByA11yLabel('label'), timeout), - waitFor( - () => tree.getByA11yLabel('label'), - timeoutInterval - ), -]; - -const waitGetAllBy: Promise[] = [ - waitFor(() => tree.getAllByA11yLabel('label')), - waitFor(() => tree.getAllByA11yLabel('label'), timeout), - waitFor( - () => tree.getAllByA11yLabel('label'), - timeoutInterval - ), -]; - -// waitForElementToBeRemoved API -const waitForElementToBeRemovedGetBy: Promise[] = [ - waitForElementToBeRemoved(() => tree.getByText('text')), - waitForElementToBeRemoved( - () => tree.getByText('text'), - timeout - ), - waitForElementToBeRemoved( - () => tree.getByText('text'), - timeoutInterval - ), -]; -const waitForElementToBeRemovedGetAllBy: Promise[] = [ - waitForElementToBeRemoved(() => - tree.getAllByText('text') - ), - waitForElementToBeRemoved( - () => tree.getAllByText('text'), - timeout - ), - waitForElementToBeRemoved( - () => tree.getAllByText('text'), - timeoutInterval - ), -]; -const waitForElementToBeRemovedQueryBy: Promise[] = [ - waitForElementToBeRemoved(() => - tree.queryByText('text') - ), - waitForElementToBeRemoved( - () => tree.queryByText('text'), - timeout - ), - waitForElementToBeRemoved( - () => tree.queryByText('text'), - timeoutInterval - ), -]; -const waitForElementToBeRemovedQueryAllBy: Promise[] = [ - waitForElementToBeRemoved(() => - tree.queryAllByText('text') - ), - waitForElementToBeRemoved( - () => tree.queryAllByText('text'), - timeout - ), - waitForElementToBeRemoved( - () => tree.queryAllByText('text'), - timeoutInterval - ), -]; - -const waitForFlush: Promise = flushMicrotasksQueue(); - -// act API -act(() => { - render(); -}); - -// within API -const instance: ReactTestInstance = tree.getByText(''); - -const withinGet: Array = [ - within(instance).getByText('Test'), - within(instance).getByDisplayValue('Test'), - within(instance).getByPlaceholderText('Test'), - within(instance).getByTestId('Test'), - within(instance).getByA11yLabel('Test'), - within(instance).getByLabelText('Test'), - within(instance).getByA11yHint('Test'), - within(instance).getByHintText('Test'), - within(instance).getByA11yRole('button'), - within(instance).getByRole('button'), - within(instance).getByA11yState({ busy: true }), - within(instance).getByA11yValue({ min: 10 }), - getQueriesForElement(instance).getByText('Test'), - getQueriesForElement(instance).getByDisplayValue('Test'), - getQueriesForElement(instance).getByPlaceholderText('Test'), - getQueriesForElement(instance).getByTestId('Test'), - getQueriesForElement(instance).getByA11yLabel('Test'), - getQueriesForElement(instance).getByLabelText('Test'), - getQueriesForElement(instance).getByA11yHint('Test'), - getQueriesForElement(instance).getByHintText('Test'), - getQueriesForElement(instance).getByA11yRole('button'), - getQueriesForElement(instance).getByRole('button'), - getQueriesForElement(instance).getByA11yState({ busy: true }), - getQueriesForElement(instance).getByA11yValue({ min: 10 }), -]; - -const withinGetAll: Array = [ - within(instance).getAllByText('Test'), - within(instance).getAllByDisplayValue('Test'), - within(instance).getAllByPlaceholderText('Test'), - within(instance).getAllByTestId('Test'), - within(instance).getAllByA11yLabel('Test'), - within(instance).getAllByLabelText('button'), - within(instance).getAllByA11yHint('Test'), - within(instance).getAllByHintText('button'), - within(instance).getAllByA11yRole('button'), - within(instance).getAllByRole('button'), - within(instance).getAllByA11yState({ busy: true }), - within(instance).getAllByA11yValue({ min: 10 }), - getQueriesForElement(instance).getAllByText('Test'), - getQueriesForElement(instance).getAllByDisplayValue('Test'), - getQueriesForElement(instance).getAllByPlaceholderText('Test'), - getQueriesForElement(instance).getAllByTestId('Test'), - getQueriesForElement(instance).getAllByA11yLabel('Test'), - getQueriesForElement(instance).getAllByLabelText('button'), - getQueriesForElement(instance).getAllByA11yHint('Test'), - getQueriesForElement(instance).getAllByHintText('button'), - getQueriesForElement(instance).getAllByA11yRole('button'), - getQueriesForElement(instance).getAllByRole('button'), - getQueriesForElement(instance).getAllByA11yState({ busy: true }), - getQueriesForElement(instance).getAllByA11yValue({ min: 10 }), -]; - -const withinQuery: Array = [ - within(instance).queryByText('Test'), - within(instance).queryByDisplayValue('Test'), - within(instance).queryByPlaceholderText('Test'), - within(instance).queryByTestId('Test'), - within(instance).queryByA11yLabel('Test'), - within(instance).queryByLabelText('button'), - within(instance).queryByA11yHint('Test'), - within(instance).queryByHintText('button'), - within(instance).queryByA11yRole('button'), - within(instance).queryByRole('button'), - within(instance).queryByA11yState({ busy: true }), - within(instance).queryByA11yValue({ min: 10 }), - getQueriesForElement(instance).queryByText('Test'), - getQueriesForElement(instance).queryByDisplayValue('Test'), - getQueriesForElement(instance).queryByPlaceholderText('Test'), - getQueriesForElement(instance).queryByTestId('Test'), - getQueriesForElement(instance).queryByA11yLabel('Test'), - getQueriesForElement(instance).queryByLabelText('button'), - getQueriesForElement(instance).queryByA11yHint('Test'), - getQueriesForElement(instance).queryByHintText('button'), - getQueriesForElement(instance).queryByA11yRole('button'), - getQueriesForElement(instance).queryByRole('button'), - getQueriesForElement(instance).queryByA11yState({ busy: true }), - getQueriesForElement(instance).queryByA11yValue({ min: 10 }), -]; - -const withinQueryAll: Array = [ - within(instance).queryAllByText('Test'), - within(instance).queryAllByDisplayValue('Test'), - within(instance).queryAllByPlaceholderText('Test'), - within(instance).queryAllByTestId('Test'), - within(instance).queryAllByA11yLabel('Test'), - within(instance).queryAllByLabelText('Test'), - within(instance).queryAllByA11yHint('Test'), - within(instance).queryAllByHintText('Test'), - within(instance).queryAllByA11yRole('button'), - within(instance).queryAllByRole('button'), - within(instance).queryAllByA11yState({ busy: true }), - within(instance).queryAllByA11yValue({ min: 10 }), - getQueriesForElement(instance).queryAllByText('Test'), - getQueriesForElement(instance).queryAllByDisplayValue('Test'), - getQueriesForElement(instance).queryAllByPlaceholderText('Test'), - getQueriesForElement(instance).queryAllByTestId('Test'), - getQueriesForElement(instance).queryAllByA11yLabel('Test'), - getQueriesForElement(instance).queryAllByLabelText('Test'), - getQueriesForElement(instance).queryAllByA11yHint('Test'), - getQueriesForElement(instance).queryAllByHintText('Test'), - getQueriesForElement(instance).queryAllByA11yRole('button'), - getQueriesForElement(instance).queryAllByRole('button'), - getQueriesForElement(instance).queryAllByA11yState({ busy: true }), - getQueriesForElement(instance).queryAllByA11yValue({ min: 10 }), -]; - -const withinFind: Promise[] = [ - within(instance).findByText('Test'), - within(instance).findByDisplayValue('Test'), - within(instance).findByPlaceholderText('Test'), - within(instance).findByTestId('Test'), - within(instance).findByA11yLabel('Test'), - within(instance).findByLabelText('Test'), - within(instance).findByA11yHint('Test'), - within(instance).findByHintText('Test'), - within(instance).findByA11yRole('button'), - within(instance).findByRole('button'), - within(instance).findByA11yState({ busy: true }), - within(instance).findByA11yValue({ min: 10 }), - getQueriesForElement(instance).findByText('Test'), - getQueriesForElement(instance).findByDisplayValue('Test'), - getQueriesForElement(instance).findByPlaceholderText('Test'), - getQueriesForElement(instance).findByTestId('Test'), - getQueriesForElement(instance).findByA11yLabel('Test'), - getQueriesForElement(instance).findByLabelText('Test'), - getQueriesForElement(instance).findByA11yHint('Test'), - getQueriesForElement(instance).findByHintText('Test'), - getQueriesForElement(instance).findByA11yRole('button'), - getQueriesForElement(instance).findByRole('button'), - getQueriesForElement(instance).findByA11yState({ busy: true }), - getQueriesForElement(instance).findByA11yValue({ min: 10 }), -]; - -const withinFindAll: Promise[] = [ - within(instance).findAllByText('Test'), - within(instance).findAllByDisplayValue('Test'), - within(instance).findAllByPlaceholderText('Test'), - within(instance).findAllByTestId('Test'), - within(instance).findAllByA11yLabel('Test'), - within(instance).findAllByLabelText('Test'), - within(instance).findAllByA11yHint('Test'), - within(instance).findAllByHintText('Test'), - within(instance).findAllByA11yRole('button'), - within(instance).findAllByRole('button'), - within(instance).findAllByA11yState({ busy: true }), - within(instance).findAllByA11yValue({ min: 10 }), - getQueriesForElement(instance).findAllByText('Test'), - getQueriesForElement(instance).findAllByDisplayValue('Test'), - getQueriesForElement(instance).findAllByPlaceholderText('Test'), - getQueriesForElement(instance).findAllByTestId('Test'), - getQueriesForElement(instance).findAllByA11yLabel('Test'), - getQueriesForElement(instance).findAllByLabelText('Test'), - getQueriesForElement(instance).findAllByA11yHint('Test'), - getQueriesForElement(instance).findAllByHintText('Test'), - getQueriesForElement(instance).findAllByA11yRole('button'), - getQueriesForElement(instance).findAllByRole('button'), - getQueriesForElement(instance).findAllByA11yState({ busy: true }), - getQueriesForElement(instance).findAllByA11yValue({ min: 10 }), -]; - -// TextMatch -const normalizer = getDefaultNormalizer({ - trim: false, - collapseWhitespace: true, -}); -tree.getByText('text', { exact: false, normalizer }); -tree.getByPlaceholderText('text', { exact: false, normalizer }); -tree.getByDisplayValue('text', { exact: true, normalizer }); -tree.getByTestId('text', { exact: false, normalizer }); diff --git a/typings/index.d.ts b/typings/index.d.ts deleted file mode 100644 index 89ecc59d7..000000000 --- a/typings/index.d.ts +++ /dev/null @@ -1,433 +0,0 @@ -import * as React from 'react'; -import { - AccessibilityState, - // @ts-ignore AccessibilityStates was deprecated in RN0.62 https://reactnative.dev/blog/2020/03/26/version-0.62#breaking-changes - AccessibilityStates, - AccessibilityRole, -} from 'react-native'; -import { ReactTestInstance, ReactTestRendererJSON } from 'react-test-renderer'; - -type GetReturn = ReactTestInstance; -type GetAllReturn = Array; -type QueryReturn = ReactTestInstance | null; -type QueryAllReturn = Array | []; -type FindReturn = Promise; -type FindAllReturn = Promise; - -type TextMatch = string | RegExp; - -interface GetByAPI { - getByText: (text: TextMatch, options?: TextMatchOptions) => ReactTestInstance; - getByPlaceholderText: ( - placeholder: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance; - getByDisplayValue: ( - value: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance; - getByTestId: ( - testID: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance; - getAllByTestId: ( - testID: TextMatch, - options?: TextMatchOptions - ) => Array; - getAllByText: ( - text: TextMatch, - options?: TextMatchOptions - ) => Array; - getAllByPlaceholderText: ( - placeholder: TextMatch, - options?: TextMatchOptions - ) => Array; - getAllByDisplayValue: ( - value: TextMatch, - options?: TextMatchOptions - ) => Array; - - // Unsafe aliases - UNSAFE_getByType:

(type: React.ComponentType

) => ReactTestInstance; - UNSAFE_getAllByType:

( - type: React.ComponentType

- ) => Array; - UNSAFE_getByProps: (props: Record) => ReactTestInstance; - UNSAFE_getAllByProps: ( - props: Record - ) => Array; - - // Removed - /** - * @deprecated This function has been removed. Please use other queries. - */ - getByName: (name: React.ReactType | string) => ReactTestInstance; - /** - * @deprecated This function has been renamed to `UNSAFE_getByType`. - */ - getByType:

(type: React.ComponentType

) => ReactTestInstance; - /** - * @deprecated This function has been renamed to `UNSAFE_getByProps`. - */ - getByProps: (props: Record) => ReactTestInstance; - /** - * @deprecated This function has been removed. Please use other queries. - */ - getAllByName: (name: React.ReactType | string) => Array; - /** - * @deprecated This function has been renamed to `UNSAFE_getAllByType`. - */ - getAllByType:

(type: React.ComponentType

) => Array; - /** - * @deprecated This function has been renamed to `UNSAFE_getAllByProps`. - */ - getAllByProps: (props: Record) => Array; -} - -interface QueryByAPI { - queryByText: ( - name: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance | null; - queryByPlaceholderText: ( - placeholder: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance | null; - queryByDisplayValue: ( - value: TextMatch, - options?: TextMatchOptions - ) => ReactTestInstance | null; - queryByTestId: (testID: TextMatch) => ReactTestInstance | null; - queryAllByTestId: (testID: TextMatch) => Array | []; - queryAllByText: ( - text: TextMatch, - options?: TextMatchOptions - ) => Array | []; - queryAllByPlaceholderText: ( - placeholder: TextMatch, - options?: TextMatchOptions - ) => Array | []; - queryAllByDisplayValue: ( - value: TextMatch, - options?: TextMatchOptions - ) => Array | []; - - // Unsafe aliases - UNSAFE_queryByType:

( - type: React.ComponentType

- ) => ReactTestInstance | null; - UNSAFE_queryAllByType:

( - type: React.ComponentType

- ) => Array | []; - UNSAFE_queryByProps: (props: Record) => ReactTestInstance | null; - UNSAFE_queryAllByProps: ( - props: Record - ) => Array | []; - - // Removed - /** - * @deprecated This function has been removed. Please use other queries. - */ - queryByName: (name: React.ReactType | string) => ReactTestInstance | null; - /** - * @deprecated This function has been renamed to `UNSAFE_queryByType`. - */ - queryByType:

(type: React.ComponentType

) => ReactTestInstance | null; - /** - * @deprecated This function has been renamed to `UNSAFE_queryByProps`. - */ - queryByProps: (props: Record) => ReactTestInstance | null; - /** - * @deprecated This function has been removed. Please use other queries. - */ - queryAllByName: ( - name: React.ReactType | string - ) => Array | []; - /** - * @deprecated This function has been renamed to `UNSAFE_queryAllByType`. - */ - queryAllByType:

( - type: React.ComponentType

- ) => Array | []; - /** - * @deprecated This function has been renamed to `UNSAFE_queryAllByProps`. - */ - queryAllByProps: ( - props: Record - ) => Array | []; -} - -interface FindByAPI { - findByText: ( - text: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByPlaceholderText: ( - placeholder: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByDisplayValue: ( - value: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByTestId: ( - testID: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByText: ( - text: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByPlaceholderText: ( - placeholder: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByDisplayValue: ( - value: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByTestId: ( - testID: TextMatch, - queryOptions?: TextMatchOptions, - waitForOptions?: WaitForOptions - ) => FindAllReturn; -} - -// Not yet available in DefinitelyTyped -export type A11yValue = { - min?: number; - max?: number; - now?: number; - text?: string; -}; - -type A11yAPI = { - // Label - getByA11yLabel: (matcher: TextMatch) => GetReturn; - getByLabelText: (matcher: TextMatch) => GetReturn; - getAllByA11yLabel: (matcher: TextMatch) => GetAllReturn; - getAllByLabelText: (matcher: TextMatch) => GetAllReturn; - queryByA11yLabel: (matcher: TextMatch) => QueryReturn; - queryByLabelText: (matcher: TextMatch) => QueryReturn; - queryAllByA11yLabel: (matcher: TextMatch) => QueryAllReturn; - queryAllByLabelText: (matcher: TextMatch) => QueryAllReturn; - findByA11yLabel: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByLabelText: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yLabel: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByLabelText: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - - // Hint - getByA11yHint: (matcher: TextMatch) => GetReturn; - getByHintText: (matcher: TextMatch) => GetReturn; - getAllByA11yHint: (matcher: TextMatch) => GetAllReturn; - getAllByHintText: (matcher: TextMatch) => GetAllReturn; - queryByA11yHint: (matcher: TextMatch) => QueryReturn; - queryByHintText: (matcher: TextMatch) => QueryReturn; - queryAllByA11yHint: (matcher: TextMatch) => QueryAllReturn; - queryAllByHintText: (matcher: TextMatch) => QueryAllReturn; - findByA11yHint: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByHintText: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yHint: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByHintText: ( - matcher: TextMatch, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - - // Role - getByA11yRole: (matcher: AccessibilityRole | RegExp) => GetReturn; - getByRole: (matcher: AccessibilityRole | RegExp) => GetReturn; - getAllByA11yRole: (matcher: AccessibilityRole | RegExp) => GetAllReturn; - getAllByRole: (matcher: AccessibilityRole | RegExp) => GetAllReturn; - queryByA11yRole: (matcher: AccessibilityRole | RegExp) => QueryReturn; - queryByRole: (matcher: AccessibilityRole | RegExp) => QueryReturn; - queryAllByA11yRole: (matcher: AccessibilityRole | RegExp) => QueryAllReturn; - queryAllByRole: (matcher: AccessibilityRole | RegExp) => QueryAllReturn; - findByA11yRole: ( - matcher: AccessibilityRole | RegExp, - waitForOptions?: WaitForOptions - ) => FindReturn; - findByRole: ( - matcher: AccessibilityRole | RegExp, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yRole: ( - matcher: AccessibilityRole | RegExp, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - findAllByRole: ( - matcher: AccessibilityRole | RegExp, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - - // States - getByA11yStates: ( - matcher: AccessibilityStates | Array - ) => GetReturn; - getAllByA11yStates: ( - matcher: AccessibilityStates | Array - ) => GetAllReturn; - queryByA11yStates: ( - matcher: AccessibilityStates | Array - ) => QueryReturn; - queryAllByA11yStates: ( - matcher: AccessibilityStates | Array - ) => QueryAllReturn; - - // State - getByA11yState: (matcher: AccessibilityState) => GetReturn; - getAllByA11yState: (matcher: AccessibilityState) => GetAllReturn; - queryByA11yState: (matcher: AccessibilityState) => QueryReturn; - queryAllByA11yState: (matcher: AccessibilityState) => QueryAllReturn; - findByA11yState: ( - matcher: AccessibilityState, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yState: ( - matcher: AccessibilityState, - waitForOptions?: WaitForOptions - ) => FindAllReturn; - - // Value - getByA11yValue: (matcher: A11yValue) => GetReturn; - getAllByA11yValue: (matcher: A11yValue) => GetAllReturn; - queryByA11yValue: (matcher: A11yValue) => QueryReturn; - queryAllByA11yValue: (matcher: A11yValue) => QueryAllReturn; - findByA11yValue: ( - matcher: A11yValue, - waitForOptions?: WaitForOptions - ) => FindReturn; - findAllByA11yValue: ( - matcher: A11yValue, - waitForOptions?: WaitForOptions - ) => FindAllReturn; -}; - -export interface Thenable { - then: (resolve: () => any, reject?: () => any) => any; -} - -export interface RenderOptions { - wrapper?: React.ComponentType; - createNodeMock?: (element: React.ReactElement) => any; -} - -type Debug = { - (message?: string): void; - shallow: (message?: string) => void; -}; - -type Queries = GetByAPI & QueryByAPI & FindByAPI & A11yAPI; - -export interface RenderAPI extends Queries { - update(nextElement: React.ReactElement): void; - rerender(nextElement: React.ReactElement): void; - unmount(nextElement?: React.ReactElement): void; - toJSON(): ReactTestRendererJSON[] | ReactTestRendererJSON | null; - debug: Debug; - container: ReactTestInstance; -} - -export type FireEventFunction = ( - element: ReactTestInstance, - eventName: string, - ...data: Array -) => any; - -export type FireEventAPI = FireEventFunction & { - press: (element: ReactTestInstance, ...data: Array) => any; - changeText: (element: ReactTestInstance, ...data: Array) => any; - scroll: (element: ReactTestInstance, ...data: Array) => any; -}; - -export declare const render: ( - component: React.ReactElement, - options?: RenderOptions -) => RenderAPI; - -export declare const cleanup: () => void; -export declare const fireEvent: FireEventAPI; - -type NormalizerFn = (textToNormalize: string) => string; -type NormalizerConfig = { - trim?: boolean; - collapseWhitespace?: boolean; -}; -type TextMatchOptions = { - exact?: boolean; - normalizer?: NormalizerFn; -}; - -type WaitForOptions = { - timeout?: number; - interval?: number; - onTimeout?: (error: Error) => Error; -}; - -export type WaitForFunction = ( - expectation: () => T, - options?: WaitForOptions -) => Promise; - -export declare const waitFor: WaitForFunction; - -export type WaitForElementToBeRemovedFunction = ( - expectation: () => T, - options?: WaitForOptions -) => Promise; - -export declare const waitForElementToBeRemoved: WaitForElementToBeRemovedFunction; - -export declare const act: (callback: () => void) => Thenable; -export declare const within: (instance: ReactTestInstance) => Queries; -export declare const getQueriesForElement: ( - instance: ReactTestInstance -) => Queries; - -export declare const getDefaultNormalizer: ( - normalizerConfig?: NormalizerConfig -) => NormalizerFn; - -/** - * @deprecated This function has been removed. Please use `waitFor` function. - */ -export declare const waitForElement: WaitForFunction; - -/** - * @deprecated This function has been deprecated and will be removed in the next release. - */ -export declare const flushMicrotasksQueue: () => Promise; - -/** - * @deprecated This function has been removed. - */ -export declare const shallow:

( - instance: ReactTestInstance | React.ReactElement

-) => { output: React.ReactElement

}; diff --git a/typings/index.flow.js b/typings/index.flow.js new file mode 100644 index 000000000..4c550cff7 --- /dev/null +++ b/typings/index.flow.js @@ -0,0 +1,366 @@ +// @flow +import * as React from 'react'; + +type GetReturn = ReactTestInstance; +type GetAllReturn = Array; +type QueryReturn = ReactTestInstance | null; +type QueryAllReturn = Array | []; +type FindReturn = Promise; +type FindAllReturn = Promise; + +type TextMatch = string | RegExp; + +declare type NormalizerFn = (textToNormalize: string) => string; +declare type NormalizerConfig = { + trim?: boolean, + collapseWhitespace?: boolean, +}; +declare type TextMatchOptions = { + exact?: boolean, + normalizer?: NormalizerFn, +}; +declare type A11yRole = + | 'none' + | 'button' + | 'link' + | 'search' + | 'image' + | 'keyboardkey' + | 'text' + | 'adjustable' + | 'imagebutton' + | 'header' + | 'summary' + | 'alert' + | 'checkbox' + | 'combobox' + | 'menu' + | 'menubar' + | 'menuitem' + | 'progressbar' + | 'radio' + | 'radiogroup' + | 'scrollbar' + | 'spinbutton' + | 'switch' + | 'tab' + | 'tablist' + | 'timer' + | 'toolbar'; + +declare type A11yState = {| + disabled?: boolean, + selected?: boolean, + checked?: boolean | 'mixed', + busy?: boolean, + expanded?: boolean, +|}; + +declare type A11yStates = + | 'disabled' + | 'selected' + | 'checked' + | 'unchecked' + | 'busy' + | 'expanded' + | 'collapsed' + | 'hasPopup'; + +declare type A11yValue = { + min?: number, + max?: number, + now?: number, + text?: string, +}; + +interface GetByAPI { + getByText: (text: TextMatch, options?: TextMatchOptions) => ReactTestInstance; + getByPlaceholderText: ( + placeholder: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance; + getByDisplayValue: ( + value: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance; + getByTestId: ( + testID: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance; + getAllByTestId: ( + testID: TextMatch, + options?: TextMatchOptions + ) => Array; + getAllByText: ( + text: TextMatch, + options?: TextMatchOptions + ) => Array; + getAllByPlaceholderText: ( + placeholder: TextMatch, + options?: TextMatchOptions + ) => Array; + getAllByDisplayValue: ( + value: TextMatch, + options?: TextMatchOptions + ) => Array; + + // Unsafe aliases + UNSAFE_getByType:

(type: React.ComponentType

) => ReactTestInstance; + UNSAFE_getAllByType:

( + type: React.ComponentType

+ ) => Array; + UNSAFE_getByProps: (props: { [string]: any }) => ReactTestInstance; + UNSAFE_getAllByProps: (props: { [string]: any }) => Array; +} + +interface QueryByAPI { + queryByText: ( + name: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance | null; + queryByPlaceholderText: ( + placeholder: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance | null; + queryByDisplayValue: ( + value: TextMatch, + options?: TextMatchOptions + ) => ReactTestInstance | null; + queryByTestId: (testID: TextMatch) => ReactTestInstance | null; + queryAllByTestId: (testID: TextMatch) => Array | []; + queryAllByText: ( + text: TextMatch, + options?: TextMatchOptions + ) => Array | []; + queryAllByPlaceholderText: ( + placeholder: TextMatch, + options?: TextMatchOptions + ) => Array | []; + queryAllByDisplayValue: ( + value: TextMatch, + options?: TextMatchOptions + ) => Array | []; + + // Unsafe aliases + UNSAFE_queryByType:

( + type: React.ComponentType

+ ) => ReactTestInstance | null; + UNSAFE_queryAllByType:

( + type: React.ComponentType

+ ) => Array | []; + UNSAFE_queryByProps: (props: { [string]: any }) => ReactTestInstance | null; + UNSAFE_queryAllByProps: (props: { [string]: any }) => + | Array + | []; +} + +type WaitForOptions = { + timeout?: number, + interval?: number, + onTimeout?: (error: mixed) => Error, +}; +type WaitForFunction = ( + expectation: () => T, + options?: WaitForOptions +) => Promise; + +interface FindByAPI { + findByText: ( + text: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindReturn; + findByPlaceholderText: ( + placeholder: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindReturn; + findByDisplayValue: ( + value: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindReturn; + findByTestId: ( + testID: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByText: ( + text: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + findAllByPlaceholderText: ( + placeholder: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + findAllByDisplayValue: ( + value: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + findAllByTestId: ( + testID: TextMatch, + queryOptions?: TextMatchOptions, + waitForOptions?: WaitForOptions + ) => FindAllReturn; +} + +interface A11yAPI { + // Label + getByLabelText: (matcher: TextMatch) => GetReturn; + getAllByLabelText: (matcher: TextMatch) => GetAllReturn; + queryByLabelText: (matcher: TextMatch) => QueryReturn; + queryAllByLabelText: (matcher: TextMatch) => QueryAllReturn; + findByLabelText: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByLabelText: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Hint + getByA11yHint: (matcher: TextMatch) => GetReturn; + getByHintText: (matcher: TextMatch) => GetReturn; + getAllByA11yHint: (matcher: TextMatch) => GetAllReturn; + getAllByHintText: (matcher: TextMatch) => GetAllReturn; + queryByA11yHint: (matcher: TextMatch) => QueryReturn; + queryByHintText: (matcher: TextMatch) => QueryReturn; + queryAllByA11yHint: (matcher: TextMatch) => QueryAllReturn; + queryAllByHintText: (matcher: TextMatch) => QueryAllReturn; + findByA11yHint: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findByHintText: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yHint: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + findAllByHintText: ( + matcher: TextMatch, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Role + getByRole: (matcher: A11yRole | RegExp) => GetReturn; + getAllByRole: (matcher: A11yRole | RegExp) => GetAllReturn; + queryByRole: (matcher: A11yRole | RegExp) => QueryReturn; + queryAllByRole: (matcher: A11yRole | RegExp) => QueryAllReturn; + findByRole: ( + matcher: A11yRole | RegExp, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByRole: ( + matcher: A11yRole | RegExp, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // States + getByA11yStates: (matcher: A11yStates | Array) => GetReturn; + getAllByA11yStates: (matcher: A11yStates | Array) => GetAllReturn; + queryByA11yStates: (matcher: A11yStates | Array) => QueryReturn; + queryAllByA11yStates: ( + matcher: A11yStates | Array + ) => QueryAllReturn; + + // State + getByA11yState: (matcher: A11yStates) => GetReturn; + getAllByA11yState: (matcher: A11yStates) => GetAllReturn; + queryByA11yState: (matcher: A11yStates) => QueryReturn; + queryAllByA11yState: (matcher: A11yStates) => QueryAllReturn; + findByA11yState: ( + matcher: A11yStates, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yState: ( + matcher: A11yStates, + waitForOptions?: WaitForOptions + ) => FindAllReturn; + + // Value + getByA11yValue: (matcher: A11yValue) => GetReturn; + getAllByA11yValue: (matcher: A11yValue) => GetAllReturn; + queryByA11yValue: (matcher: A11yValue) => QueryReturn; + queryAllByA11yValue: (matcher: A11yValue) => QueryAllReturn; + findByA11yValue: ( + matcher: A11yValue, + waitForOptions?: WaitForOptions + ) => FindReturn; + findAllByA11yValue: ( + matcher: A11yValue, + waitForOptions?: WaitForOptions + ) => FindAllReturn; +} + +interface Thenable { + then: (resolve: () => any, reject?: () => any) => any; +} + +interface RenderOptions { + wrapper?: React.ComponentType; + createNodeMock?: (element: React.Element) => any; +} + +type Debug = { + (message?: string): void, + shallow: (message?: string) => void, +}; + +type Queries = GetByAPI & QueryByAPI & FindByAPI & A11yAPI; + +interface RenderAPI extends Queries { + update(nextElement: React.Element): void; + rerender(nextElement: React.Element): void; + unmount(nextElement?: React.Element): void; + toJSON(): ReactTestRendererJSON[] | ReactTestRendererJSON | null; + debug: Debug; + container: ReactTestInstance; +} + +type FireEventFunction = ( + element: ReactTestInstance, + eventName: string, + ...data: Array +) => any; + +type FireEventAPI = FireEventFunction & { + press: (element: ReactTestInstance, ...data: Array) => any, + changeText: (element: ReactTestInstance, ...data: Array) => any, + scroll: (element: ReactTestInstance, ...data: Array) => any, +}; + +declare module '@testing-library/react-native' { + declare export var render: ( + component: React.Element, + options?: RenderOptions + ) => RenderAPI; + + declare export var cleanup: () => void; + declare export var fireEvent: FireEventAPI; + + declare export var waitFor: WaitForFunction; + + declare type WaitForElementToBeRemovedFunction = ( + expectation: () => T, + options?: WaitForOptions + ) => Promise; + + declare export var waitForElementToBeRemoved: WaitForElementToBeRemovedFunction; + + declare export var act: (callback: () => void) => Thenable; + declare export var within: (instance: ReactTestInstance) => Queries; + declare export var getQueriesForElement: ( + instance: ReactTestInstance + ) => Queries; + + declare export var getDefaultNormalizer: ( + normalizerConfig?: NormalizerConfig + ) => NormalizerFn; +} diff --git a/website/docs/API.md b/website/docs/API.md index f0a6a9a45..dd66193c4 100644 --- a/website/docs/API.md +++ b/website/docs/API.md @@ -30,8 +30,8 @@ import { render } from '@testing-library/react-native'; import { QuestionsBoard } from '../QuestionsBoard'; test('should verify two questions', () => { - const { queryAllByA11yRole } = render(); - const allQuestions = queryAllByA11yRole('header'); + const { queryAllByRole } = render(); + const allQuestions = queryAllByRole('header'); expect(allQuestions).toHaveLength(2); }); @@ -429,7 +429,7 @@ Please note that additional `render` specific operations like `update`, `unmount const detailsScreen = within(getByA11yHint('Details Screen')); expect(detailsScreen.getByText('Some Text')).toBeTruthy(); expect(detailsScreen.getByDisplayValue('Some Value')).toBeTruthy(); -expect(detailsScreen.queryByA11yLabel('Some Label')).toBeTruthy(); +expect(detailsScreen.queryByLabelText('Some Label')).toBeTruthy(); await expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeTruthy(); ``` diff --git a/website/docs/GettingStarted.md b/website/docs/GettingStarted.md index d9c66d945..33698c03e 100644 --- a/website/docs/GettingStarted.md +++ b/website/docs/GettingStarted.md @@ -82,11 +82,11 @@ test('form submits two answers', () => { const allQuestions = ['q1', 'q2']; const mockFn = jest.fn(); - const { getAllByA11yLabel, getByText } = render( + const { getAllByLabelText, getByText } = render( ); - const answerInputs = getAllByA11yLabel('answer input'); + const answerInputs = getAllByLabelText('answer input'); fireEvent.changeText(answerInputs[0], 'a1'); fireEvent.changeText(answerInputs[1], 'a2'); diff --git a/website/docs/HowShouldIQuery.md b/website/docs/HowShouldIQuery.md index f3b50ab76..55af03e7f 100644 --- a/website/docs/HowShouldIQuery.md +++ b/website/docs/HowShouldIQuery.md @@ -11,11 +11,11 @@ Based on the [Guiding Principles](https://testing-library.com/docs/guiding-princ - [`getByText`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bytext): This is the number 1 method a user finds any visible text on interactive and non-interactive elements. - [`getByDisplayValue`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bydisplayvalue): Useful for the current value of a `TextInput`. - [`getByPlaceholderText`](https://callstack.github.io/react-native-testing-library/docs/api-queries#byplaceholdertext): Only useful for targeting a placeholder of a `TextInput`. - - [`getByLabelText`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11ylabel-byaccessibilitylabel-bylabeltext): This can be used to query every element that is exposed in the accessibility tree as a label, usually when there's no visible text. + - [`getByLabelText`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bylabeltext): This can be used to query every element that is exposed in the accessibility tree as a label, usually when there's no visible text. - [`getByHintText`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11yhint-byaccessibilityhint-byhinttext): This can be used to query every element that is exposed in the accessibility tree as a hint. Make sure it also has a label set. - [`getByAccessibilityState`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11ystate-byaccessibilitystate): This can be used to query every element that is exposed in the accessibility tree as a state of an interactive element, like a checkbox. - [`getByAccessibilityValue`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11value-byaccessibilityvalue): This can be used to query every element that is exposed in the accessibility tree as a value on a range, like a slider. 2. **Queries Users Can Infer** - - [`getByRole`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11yrole-byaccessibilityrole-byrole): This can be used to query every element that is exposed in the accessibility tree as a role, like buttons or images. + - [`getByRole`](https://callstack.github.io/react-native-testing-library/docs/api-queries#byrole): This can be used to query every element that is exposed in the accessibility tree as a role, like buttons or images. 3. **Test IDs** - [`getByTestId`](https://callstack.github.io/react-native-testing-library/docs/api-queries#bytestid): The user cannot see (or hear) these, so this is only recommended for cases where you can't match by text or it doesn't make sense diff --git a/website/docs/Queries.md b/website/docs/Queries.md index 835b8628d..85fa0d881 100644 --- a/website/docs/Queries.md +++ b/website/docs/Queries.md @@ -115,10 +115,8 @@ const element = 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). ::: -### `ByA11yLabel`, `ByAccessibilityLabel`, `ByLabelText` +### `ByLabelText` -> getByA11yLabel, getAllByA11yLabel, queryByA11yLabel, queryAllByA11yLabel, findByA11yLabel, findAllByA11yLabel -> getByAccessibilityLabel, getAllByAccessibilityLabel, queryByAccessibilityLabel, queryAllByAccessibilityLabel, findByAccessibilityLabel, findAllByAccessibilityLabel > getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText Returns a `ReactTestInstance` with matching `accessibilityLabel` prop. @@ -164,10 +162,8 @@ const element = getByA11yStates(['checked']); const element2 = getByA11yStates('checked'); ``` -### `ByA11yRole`, `ByAccessibilityRole`, `ByRole` +### `ByRole` -> getByA11yRole, getAllByA11yRole, queryByA11yRole, queryAllByA11yRole, findByA11yRole, findAllByA11yRole -> getByAccessibilityRole, getAllByAccessibilityRole, queryByAccessibilityRole, queryAllByAccessibilityRole, findByAccessibilityRole, findAllByAccessibilityRole > getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole Returns a `ReactTestInstance` with matching `accessibilityRole` prop. @@ -175,8 +171,8 @@ Returns a `ReactTestInstance` with matching `accessibilityRole` prop. ```jsx import { render } from '@testing-library/react-native'; -const { getByA11yRole } = render(); -const element = getByA11yRole('button'); +const { getByRole } = render(); +const element = getByRole('button'); ``` ### `ByA11yState`, `ByAccessibilityState` diff --git a/yarn.lock b/yarn.lock index fb4577741..b9a8a8b27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,6 +39,13 @@ dependencies: "@babel/highlight" "^7.14.5" +"@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + "@babel/compat-data@^7.13.0", "@babel/compat-data@^7.13.8": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.8.tgz#5b783b9808f15cef71547f1b691f34f8ff6003a6" @@ -110,6 +117,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== + dependencies: + "@babel/types" "^7.16.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" @@ -124,6 +140,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-annotate-as-pure@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" + integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" @@ -164,6 +187,18 @@ "@babel/helper-replace-supers" "^7.15.4" "@babel/helper-split-export-declaration" "^7.15.4" +"@babel/helper-create-class-features-plugin@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b" + integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-create-regexp-features-plugin@^7.12.13": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7" @@ -211,6 +246,15 @@ "@babel/template" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== + dependencies: + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-get-function-arity@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" @@ -225,6 +269,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-hoist-variables@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz#5d5882e855b5c5eda91e0cadc26c6e7a2c8593d8" @@ -240,6 +291,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-member-expression-to-functions@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz#6aa4bb678e0f8c22f58cdb79451d30494461b091" @@ -254,6 +312,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-imports@^7.12.1": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" @@ -318,7 +383,19 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-plugin-utils@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== @@ -361,6 +438,16 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-simple-access@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz#8478bcc5cacf6aa1672b251c1d2dde5ccd61a6c4" @@ -396,6 +483,13 @@ dependencies: "@babel/types" "^7.15.4" +"@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" @@ -481,6 +575,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.4", "@babel/parser@^7.7.0": version "7.13.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab" @@ -496,6 +599,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== +"@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + "@babel/plugin-proposal-async-generator-functions@^7.13.8": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz#87aacb574b3bc4b5603f6fe41458d72a5a2ec4b1" @@ -662,6 +770,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-flow@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.0.tgz#07427021d093ed77019408221beaf0272bbcfaec" + integrity sha512-dH91yCo0RyqfzWgoM5Ji9ir8fQ+uFbt9KHM3d2x4jZOuHS6wNA+CRmRUP/BWCsHG2bjc7A2Way6AvH1eQk0wig== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-flow@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" @@ -760,6 +875,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-typescript@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb" + integrity sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript@^7.7.2": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" @@ -864,6 +986,14 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-flow" "^7.16.7" +"@babel/plugin-transform-flow-strip-types@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.0.tgz#edd968dc2041c1b69e451a262e948d6654a79dc2" + integrity sha512-vs/F5roOaO/+WxKfp9PkvLsAyj0G+Q0zbFimHm9X2KDgabN2XmNFoAafmeGEYspUlIF9+MvVmyek9UyHiqeG/w== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-flow" "^7.16.0" + "@babel/plugin-transform-for-of@^7.0.0", "@babel/plugin-transform-for-of@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" @@ -1090,6 +1220,15 @@ "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-syntax-typescript" "^7.12.13" +"@babel/plugin-transform-typescript@^7.16.0": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409" + integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.16.0" + "@babel/plugin-transform-typescript@^7.5.0": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz#d92cc0af504d510e26a754a7dbc2e5c8cd9c7ab4" @@ -1229,6 +1368,15 @@ "@babel/helper-validator-option" "^7.12.17" "@babel/plugin-transform-typescript" "^7.13.0" +"@babel/preset-typescript@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac" + integrity sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.16.0" + "@babel/register@^7.0.0": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.12.1.tgz#cdb087bdfc4f7241c03231f22e15d211acf21438" @@ -1280,6 +1428,15 @@ "@babel/parser" "^7.15.4" "@babel/types" "^7.15.4" +"@babel/template@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.7.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" @@ -1310,6 +1467,21 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.5", "@babel/types@^7.13.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" @@ -1327,6 +1499,14 @@ "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" +"@babel/types@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -2082,6 +2262,14 @@ "@types/node" "*" "@types/responselike" "*" +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.3" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" @@ -2121,6 +2309,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@^27.0.0": + version "27.0.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a" + integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + "@types/json-schema@^7.0.3": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" @@ -2138,6 +2334,11 @@ dependencies: "@types/node" "*" +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + "@types/minimist@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" @@ -2173,10 +2374,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== -"@types/react-native@^0.66.5": - version "0.66.5" - resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.66.5.tgz#a9bb2fdf6355c4a4426904eae95077d1a462f5c6" - integrity sha512-hTLfKfepd+A+jUpgj+OhHtW7UlIvhyHyQ4mOCnRfEjhxq4PGvspETIHIcTV2DEfnWNX3Gi9Q0gGINrU8AG7YeA== +"@types/react-native@^0.66.6": + version "0.66.6" + resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.66.6.tgz#08f5b93cca9a50b7d19f353ff2a1ebe1a7c24a79" + integrity sha512-VqC2wN5wNCXqL9/Fve/bI1C+Q8BJlkiF/JOs7Qfw5eeD//nk5Imw4KrB8UiZZ/TPMSXPWYiKvWHiiqgA99L69g== dependencies: "@types/react" "*" @@ -2433,6 +2634,14 @@ agent-base@6: dependencies: debug "4" +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" @@ -2486,6 +2695,16 @@ ansi-fragments@^0.2.1: slice-ansi "^2.0.0" strip-ansi "^5.0.0" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^4.0.0, ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -3222,6 +3441,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" @@ -3251,6 +3475,15 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -3286,6 +3519,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -3663,6 +3901,14 @@ cosmiconfig@^5.0.5, cosmiconfig@^5.1.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cp-cli@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cp-cli/-/cp-cli-2.0.0.tgz#0707ca60bcbf20884b16c2c110484263fa7f922d" + integrity sha512-UfGOwpKeEVfdT+RFBGqlXTPZfHSJn31vaIOvr/YXLk494k6/xWUbN8+YZ2EvM6G8C8dGaU2Hy0nBmYCR5ux15g== + dependencies: + fs-extra "7.0.1" + yargs "12.0.5" + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -3870,6 +4116,28 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +del-cli@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/del-cli/-/del-cli-3.0.1.tgz#2d27ff260204b5104cadeda86f78f180a4ebe89a" + integrity sha512-BLHItGr82rUbHhjMu41d+vw9Md49i81jmZSV00HdTq4t+RTHywmEht/23mNFpUl2YeLYJZJyGz4rdlMAyOxNeg== + dependencies: + del "^5.1.0" + meow "^6.1.1" + +del@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" + integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== + dependencies: + globby "^10.0.1" + graceful-fs "^4.2.2" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.1" + p-map "^3.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3918,6 +4186,11 @@ diff-sequences@^27.0.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== +diff-sequences@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4487,6 +4760,17 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== +fast-glob@^3.0.3: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-glob@^3.1.1: version "3.2.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" @@ -4685,6 +4969,15 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-extra@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" @@ -4738,6 +5031,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -4919,6 +5217,20 @@ globby@11.0.4, globby@^11.0.1, globby@^11.0.3: merge2 "^1.3.0" slash "^3.0.0" +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + got@11.8.2: version "11.8.2" resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" @@ -4958,6 +5270,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +graceful-fs@^4.2.2: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + handlebars@^4.7.6: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" @@ -5142,6 +5459,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + ignore@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" @@ -5281,6 +5603,11 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -5412,6 +5739,13 @@ is-finite@^1.0.0: resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -5469,6 +5803,16 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-inside@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-path-inside@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" @@ -5745,6 +6089,16 @@ jest-diff@^24.0.0, jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" +jest-diff@^27.0.0: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.2.tgz#786b2a5211d854f848e2dcc1e324448e9481f36f" + integrity sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.4.0" + jest-get-type "^27.4.0" + pretty-format "^27.4.2" + jest-diff@^27.2.5: version "27.2.5" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.5.tgz#908f7a6aca5653824516ad30e0a9fd9767e53623" @@ -5813,6 +6167,11 @@ jest-get-type@^27.0.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== +jest-get-type@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== + jest-haste-map@^26.5.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" @@ -6409,6 +6768,13 @@ latest-version@^5.1.0: dependencies: package-json "^6.3.0" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -6637,6 +7003,13 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -6664,6 +7037,15 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -6695,6 +7077,23 @@ meow@^4.0.0: redent "^2.0.0" trim-newlines "^2.0.0" +meow@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-6.1.1.tgz#1ad64c4b76b2a24dfb2f635fddcadf320d251467" + integrity sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg== + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "^4.0.2" + normalize-package-data "^2.5.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.13.1" + yargs-parser "^18.1.3" + meow@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-8.0.0.tgz#1aa10ee61046719e334ffdc038bb5069250ec99a" @@ -6717,6 +7116,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + merge2@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" @@ -7055,7 +7459,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-fn@^2.1.0: +mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -7082,7 +7486,7 @@ minimatch@^3.0.2, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist-options@4.1.0: +minimist-options@4.1.0, minimist-options@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== @@ -7488,6 +7892,15 @@ ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + os-name@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/os-name/-/os-name-4.0.1.tgz#32cee7823de85a8897647ba4d76db46bf845e555" @@ -7519,11 +7932,21 @@ p-cancelable@^2.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e" integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg== +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -7559,6 +7982,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -7861,7 +8291,7 @@ pretty-format@^26.5.2, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^27.0.0, pretty-format@^27.2.5, pretty-format@^27.3.1: +pretty-format@^27.0.0, pretty-format@^27.2.5, pretty-format@^27.3.1, pretty-format@^27.4.2: version "27.4.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.2.tgz#e4ce92ad66c3888423d332b40477c87d1dac1fb8" integrity sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw== @@ -8385,6 +8815,11 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -8949,6 +9384,23 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -9027,6 +9479,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -9404,6 +9870,11 @@ type-fest@^0.11.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" @@ -9770,6 +10241,14 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -9889,6 +10368,11 @@ xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +"y18n@^3.2.1 || ^4.0.0": + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + y18n@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" @@ -9914,7 +10398,15 @@ yargs-parser@20.2.9, yargs-parser@^20.2.2, yargs-parser@^20.2.3: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^18.1.1, yargs-parser@^18.1.2: +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^18.1.1, yargs-parser@^18.1.2, yargs-parser@^18.1.3: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -9922,6 +10414,24 @@ yargs-parser@^18.1.1, yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs@12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + yargs@^15.0.1: version "15.3.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b"