@testing-library/react-native 12.1.1 → 12.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/.codecov.yml +9 -0
- package/.eslintcache +1 -0
- package/.eslintignore +2 -0
- package/.eslintrc +19 -0
- package/.flowconfig +63 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +14 -0
- package/.github/ISSUE_TEMPLATE/question.md +9 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- package/.github/actions/setup-deps/action.yml +22 -0
- package/.github/actions/setup-website-deps/action.yml +22 -0
- package/.github/dependabot.yml +10 -0
- package/.github/workflows/deploy-website.yml +36 -0
- package/.github/workflows/example-apps.yml +25 -0
- package/.github/workflows/main.yml +103 -0
- package/.gitignore +11 -0
- package/.prettierrc.js +5 -0
- package/CODE_OF_CONDUCT.md +73 -0
- package/CONTRIBUTING.md +64 -0
- package/README.md +8 -7
- package/babel.config.js +22 -0
- package/build/act.js.map +1 -1
- package/build/cleanup.js.map +1 -1
- package/build/config.d.ts +1 -0
- package/build/config.js.map +1 -1
- package/build/fireEvent.d.ts +13 -5
- package/build/fireEvent.js +57 -48
- package/build/fireEvent.js.map +1 -1
- package/build/flush-micro-tasks.d.ts +19 -0
- package/build/flush-micro-tasks.js +36 -0
- package/build/flush-micro-tasks.js.map +1 -0
- package/build/helpers/accessiblity.js +3 -1
- package/build/helpers/accessiblity.js.map +1 -1
- package/build/helpers/component-tree.d.ts +0 -15
- package/build/helpers/component-tree.js +0 -45
- package/build/helpers/component-tree.js.map +1 -1
- package/build/helpers/deprecation.d.ts +1 -0
- package/build/helpers/deprecation.js +16 -0
- package/build/helpers/deprecation.js.map +1 -1
- package/build/helpers/errors.d.ts +0 -4
- package/build/helpers/errors.js +1 -25
- package/build/helpers/errors.js.map +1 -1
- package/build/helpers/findAll.js.map +1 -1
- package/build/helpers/format-default.js.map +1 -1
- package/build/helpers/format.js.map +1 -1
- package/build/helpers/host-component-names.js +4 -1
- package/build/helpers/host-component-names.js.map +1 -1
- package/build/helpers/matchers/matchLabelText.js.map +1 -1
- package/build/helpers/pointer-events.d.ts +9 -0
- package/build/helpers/pointer-events.js +25 -0
- package/build/helpers/pointer-events.js.map +1 -0
- package/build/helpers/stringValidation.js.map +1 -1
- package/build/helpers/timers.js.map +1 -1
- package/build/index.js +2 -2
- package/build/index.js.map +1 -1
- package/build/matches.js.map +1 -1
- package/build/pure.d.ts +1 -1
- package/build/pure.js.map +1 -1
- package/build/queries/a11yState.js.map +1 -1
- package/build/queries/a11yValue.js.map +1 -1
- package/build/queries/displayValue.js.map +1 -1
- package/build/queries/hintText.js.map +1 -1
- package/build/queries/labelText.js.map +1 -1
- package/build/queries/makeQueries.js.map +1 -1
- package/build/queries/placeholderText.js.map +1 -1
- package/build/queries/role.js.map +1 -1
- package/build/queries/testId.js.map +1 -1
- package/build/queries/text.js.map +1 -1
- package/build/queries/unsafeProps.js.map +1 -1
- package/build/render.d.ts +171 -12
- package/build/render.js +11 -4
- package/build/render.js.map +1 -1
- package/build/renderHook.d.ts +3 -6
- package/build/renderHook.js +4 -3
- package/build/renderHook.js.map +1 -1
- package/build/shallow.js.map +1 -1
- package/build/test-utils/events.d.ts +10 -0
- package/build/test-utils/events.js +27 -0
- package/build/test-utils/events.js.map +1 -0
- package/build/test-utils/index.d.ts +1 -0
- package/build/test-utils/index.js +17 -0
- package/build/test-utils/index.js.map +1 -0
- package/build/user-event/event-builder/common.d.ts +45 -0
- package/build/user-event/event-builder/common.js +58 -0
- package/build/user-event/event-builder/common.js.map +1 -0
- package/build/user-event/event-builder/index.d.ts +32 -0
- package/build/user-event/event-builder/index.js +12 -0
- package/build/user-event/event-builder/index.js.map +1 -0
- package/build/user-event/index.d.ts +9 -0
- package/build/user-event/index.js +16 -0
- package/build/user-event/index.js.map +1 -0
- package/build/user-event/press/constants.d.ts +2 -0
- package/build/user-event/press/constants.js +16 -0
- package/build/user-event/press/constants.js.map +1 -0
- package/build/user-event/press/index.d.ts +1 -0
- package/build/user-event/press/index.js +19 -0
- package/build/user-event/press/index.js.map +1 -0
- package/build/user-event/press/press.d.ts +7 -0
- package/build/user-event/press/press.js +106 -0
- package/build/user-event/press/press.js.map +1 -0
- package/build/user-event/press/utils/warnAboutRealTimers.d.ts +1 -0
- package/build/user-event/press/utils/warnAboutRealTimers.js +14 -0
- package/build/user-event/press/utils/warnAboutRealTimers.js.map +1 -0
- package/build/user-event/setup/index.d.ts +2 -0
- package/build/user-event/setup/index.js +13 -0
- package/build/user-event/setup/index.js.map +1 -0
- package/build/user-event/setup/setup.d.ts +39 -0
- package/build/user-event/setup/setup.js +56 -0
- package/build/user-event/setup/setup.js.map +1 -0
- package/build/user-event/type/index.d.ts +1 -0
- package/build/user-event/type/index.js +13 -0
- package/build/user-event/type/index.js.map +1 -0
- package/build/user-event/type/type.d.ts +3 -0
- package/build/user-event/type/type.js +18 -0
- package/build/user-event/type/type.js.map +1 -0
- package/build/user-event/utils/events.d.ts +9 -0
- package/build/user-event/utils/events.js +44 -0
- package/build/user-event/utils/events.js.map +1 -0
- package/build/user-event/utils/index.d.ts +2 -0
- package/build/user-event/utils/index.js +28 -0
- package/build/user-event/utils/index.js.map +1 -0
- package/build/user-event/utils/wait.d.ts +2 -0
- package/build/user-event/utils/wait.js +14 -0
- package/build/user-event/utils/wait.js.map +1 -0
- package/build/waitFor.js +3 -3
- package/build/waitFor.js.map +1 -1
- package/build/waitForElementToBeRemoved.js.map +1 -1
- package/examples/basic/.expo-shared/assets.json +4 -0
- package/examples/basic/.gitignore +14 -0
- package/examples/basic/App.tsx +20 -0
- package/examples/basic/README.md +11 -0
- package/examples/basic/__tests__/App.test.tsx +119 -0
- package/examples/basic/app.json +31 -0
- package/examples/basic/assets/adaptive-icon.png +0 -0
- package/examples/basic/assets/favicon.png +0 -0
- package/examples/basic/assets/icon.png +0 -0
- package/examples/basic/assets/splash.png +0 -0
- package/examples/basic/babel.config.js +6 -0
- package/examples/basic/components/Home.tsx +28 -0
- package/examples/basic/components/LoginForm.tsx +138 -0
- package/examples/basic/jest-setup.ts +7 -0
- package/examples/basic/jest.config.js +5 -0
- package/examples/basic/package.json +30 -0
- package/examples/basic/tsconfig.json +7 -0
- package/examples/react-navigation/README.md +14 -0
- package/examples/react-navigation/babel.config.js +4 -0
- package/examples/react-navigation/jest-setup.js +11 -0
- package/examples/react-navigation/jest.config.js +10 -0
- package/examples/react-navigation/package.json +31 -0
- package/examples/react-navigation/src/App.js +21 -0
- package/examples/react-navigation/src/DrawerNavigator.js +15 -0
- package/examples/react-navigation/src/DrawerNavigator.test.js +42 -0
- package/examples/react-navigation/src/NativeStackNavigator.js +15 -0
- package/examples/react-navigation/src/NativeStackNavigator.test.js +34 -0
- package/examples/react-navigation/src/StackNavigator.js +15 -0
- package/examples/react-navigation/src/StackNavigator.test.js +34 -0
- package/examples/react-navigation/src/TabNavigator.js +15 -0
- package/examples/react-navigation/src/TabNavigator.test.js +21 -0
- package/examples/react-navigation/src/screens/DetailsScreen.js +43 -0
- package/examples/react-navigation/src/screens/DetailsScreen.test.js +27 -0
- package/examples/react-navigation/src/screens/DrawerHomeScreen.js +26 -0
- package/examples/react-navigation/src/screens/HomeScreen.js +48 -0
- package/examples/react-navigation/src/screens/SettingsScreen.js +20 -0
- package/examples/react-navigation/src/test-utils.js +12 -0
- package/examples/redux/App.js +27 -0
- package/examples/redux/actions/todoActions.js +25 -0
- package/examples/redux/babel.config.js +6 -0
- package/examples/redux/components/AddTodo.js +73 -0
- package/examples/redux/components/AddTodo.test.js +27 -0
- package/examples/redux/components/TodoElem.js +25 -0
- package/examples/redux/components/TodoList.js +29 -0
- package/examples/redux/components/TodoList.test.js +34 -0
- package/examples/redux/index.js +8 -0
- package/examples/redux/jest-setup.js +2 -0
- package/examples/redux/jest.config.js +4 -0
- package/examples/redux/package.json +23 -0
- package/examples/redux/reducers/index.js +6 -0
- package/examples/redux/reducers/todoReducer.js +27 -0
- package/examples/redux/store.js +10 -0
- package/examples/redux/test-utils.js +11 -0
- package/experiments-app/.expo/README.md +15 -0
- package/experiments-app/.expo/devices.json +3 -0
- package/experiments-app/.expo/packager-info.json +9 -0
- package/experiments-app/.expo/settings.json +9 -0
- package/experiments-app/.gitignore +17 -0
- package/experiments-app/.prettierrc.js +5 -0
- package/experiments-app/app.json +30 -0
- package/experiments-app/assets/adaptive-icon.png +0 -0
- package/experiments-app/assets/favicon.png +0 -0
- package/experiments-app/assets/icon.png +0 -0
- package/experiments-app/assets/splash.png +0 -0
- package/experiments-app/babel.config.js +6 -0
- package/experiments-app/index.js +4 -0
- package/experiments-app/package.json +31 -0
- package/experiments-app/src/App.tsx +31 -0
- package/experiments-app/src/MainScreen.tsx +51 -0
- package/experiments-app/src/experiments.ts +17 -0
- package/experiments-app/src/screens/TextInputEventPropagation.tsx +54 -0
- package/experiments-app/src/screens/TextInputEvents.tsx +50 -0
- package/experiments-app/src/utils/helpers.ts +8 -0
- package/experiments-app/tsconfig.json +6 -0
- package/experiments-app/yarn.lock +6913 -0
- package/flow-typed/npm/jest_v26.x.x.js +1218 -0
- package/flow-typed/npm/react-test-renderer_v16.x.x.js +81 -0
- package/jest-setup.ts +10 -0
- package/package.json +6 -6
- package/renovate.json +19 -0
- package/scripts/test_react_17 +12 -0
- package/src/__tests__/__snapshots__/render-debug.test.tsx.snap +548 -0
- package/src/__tests__/__snapshots__/render.test.tsx.snap +39 -0
- package/src/__tests__/act.test.tsx +52 -0
- package/src/__tests__/auto-cleanup-skip.test.tsx +39 -0
- package/src/__tests__/auto-cleanup.test.tsx +50 -0
- package/src/__tests__/cleanup.test.tsx +26 -0
- package/src/__tests__/config.test.ts +55 -0
- package/src/__tests__/fireEvent-textInput.test.tsx +154 -0
- package/src/__tests__/fireEvent.test.tsx +485 -0
- package/src/__tests__/host-component-names.test.tsx +109 -0
- package/src/__tests__/host-text-nesting.test.tsx +90 -0
- package/src/__tests__/jest-native.test.tsx +84 -0
- package/src/__tests__/questionsBoard.test.tsx +62 -0
- package/src/__tests__/react-native-api.test.tsx +126 -0
- package/src/__tests__/render-debug.test.tsx +207 -0
- package/src/__tests__/render-stringValidation.test.tsx +157 -0
- package/src/__tests__/render.test.tsx +256 -0
- package/src/__tests__/renderHook.test.tsx +114 -0
- package/src/__tests__/screen.test.tsx +66 -0
- package/src/__tests__/timerUtils.ts +7 -0
- package/src/__tests__/timers.test.ts +27 -0
- package/src/__tests__/waitFor.test.tsx +327 -0
- package/src/__tests__/waitForElementToBeRemoved.test.tsx +151 -0
- package/src/__tests__/within.test.tsx +96 -0
- package/src/act.ts +86 -0
- package/src/cleanup.ts +15 -0
- package/src/config.ts +72 -0
- package/src/fireEvent.ts +163 -0
- package/src/flush-micro-tasks.ts +30 -0
- package/src/helpers/__tests__/accessiblity.test.tsx +373 -0
- package/src/helpers/__tests__/component-tree.test.tsx +226 -0
- package/src/helpers/__tests__/format-default.tsx +114 -0
- package/src/helpers/__tests__/getTextContent.test.tsx +49 -0
- package/src/helpers/__tests__/includeHiddenElements.test.tsx +39 -0
- package/src/helpers/__tests__/query-name.test.ts +10 -0
- package/src/helpers/__tests__/timers.test.ts +8 -0
- package/src/helpers/accessiblity.ts +108 -0
- package/src/helpers/component-tree.ts +89 -0
- package/src/helpers/debugDeep.ts +27 -0
- package/src/helpers/debugShallow.ts +22 -0
- package/src/helpers/deprecation.ts +53 -0
- package/src/helpers/errors.ts +66 -0
- package/src/helpers/filterNodeByType.ts +7 -0
- package/src/helpers/findAll.ts +68 -0
- package/src/helpers/format-default.ts +72 -0
- package/src/helpers/format.ts +47 -0
- package/src/helpers/getTextContent.ts +20 -0
- package/src/helpers/host-component-names.tsx +67 -0
- package/src/helpers/matchers/__tests__/matchArrayValue.test.ts +34 -0
- package/src/helpers/matchers/__tests__/matchObject.test.ts +37 -0
- package/src/helpers/matchers/__tests__/matchStringValue.test.ts +15 -0
- package/src/helpers/matchers/accessibilityState.ts +48 -0
- package/src/helpers/matchers/accessibilityValue.ts +24 -0
- package/src/helpers/matchers/matchArrayProp.ts +21 -0
- package/src/helpers/matchers/matchLabelText.ts +51 -0
- package/src/helpers/matchers/matchObjectProp.ts +25 -0
- package/src/helpers/matchers/matchStringProp.ts +23 -0
- package/src/helpers/matchers/matchTextContent.ts +20 -0
- package/src/helpers/pointer-events.ts +27 -0
- package/src/helpers/query-name.ts +4 -0
- package/src/helpers/stringValidation.ts +36 -0
- package/src/helpers/timers.ts +98 -0
- package/src/index.ts +33 -0
- package/src/matches.ts +49 -0
- package/src/pure.ts +25 -0
- package/src/queries/__tests__/a11yState.test.tsx +439 -0
- package/src/queries/__tests__/a11yValue.test.tsx +309 -0
- package/src/queries/__tests__/displayValue.test.tsx +221 -0
- package/src/queries/__tests__/hintText.test.tsx +177 -0
- package/src/queries/__tests__/labelText.test.tsx +242 -0
- package/src/queries/__tests__/makeQueries.test.tsx +235 -0
- package/src/queries/__tests__/placeholderText.test.tsx +136 -0
- package/src/queries/__tests__/role-value.test.tsx +176 -0
- package/src/queries/__tests__/role.test.tsx +824 -0
- package/src/queries/__tests__/testId.test.tsx +200 -0
- package/src/queries/__tests__/text.test.tsx +556 -0
- package/src/queries/a11yState.ts +131 -0
- package/src/queries/a11yValue.ts +131 -0
- package/src/queries/displayValue.ts +78 -0
- package/src/queries/hintText.ts +112 -0
- package/src/queries/labelText.ts +59 -0
- package/src/queries/makeQueries.ts +255 -0
- package/src/queries/options.ts +14 -0
- package/src/queries/placeholderText.ts +79 -0
- package/src/queries/role.ts +132 -0
- package/src/queries/testId.ts +71 -0
- package/src/queries/text.ts +66 -0
- package/src/queries/unsafeProps.ts +76 -0
- package/src/queries/unsafeType.ts +73 -0
- package/src/react-versions.ts +11 -0
- package/src/render-act.ts +19 -0
- package/src/render.tsx +183 -0
- package/src/renderHook.tsx +56 -0
- package/src/screen.ts +123 -0
- package/src/shallow.ts +18 -0
- package/src/test-utils/events.ts +24 -0
- package/src/test-utils/index.ts +1 -0
- package/src/user-event/event-builder/common.ts +50 -0
- package/src/user-event/event-builder/index.ts +5 -0
- package/src/user-event/index.ts +14 -0
- package/src/user-event/press/__tests__/longPress.real-timers.test.tsx +115 -0
- package/src/user-event/press/__tests__/longPress.test.tsx +157 -0
- package/src/user-event/press/__tests__/press.real-timers.test.tsx +318 -0
- package/src/user-event/press/__tests__/press.test.tsx +422 -0
- package/src/user-event/press/constants.ts +7 -0
- package/src/user-event/press/index.ts +1 -0
- package/src/user-event/press/press.ts +134 -0
- package/src/user-event/press/utils/warnAboutRealTimers.ts +6 -0
- package/src/user-event/setup/index.ts +2 -0
- package/src/user-event/setup/setup.ts +93 -0
- package/src/user-event/type/__tests__/__snapshots__/type.test.tsx.snap +26 -0
- package/src/user-event/type/__tests__/type.test.tsx +63 -0
- package/src/user-event/type/index.ts +1 -0
- package/src/user-event/type/type.ts +20 -0
- package/src/user-event/utils/__tests__/wait.test.ts +63 -0
- package/src/user-event/utils/events.ts +54 -0
- package/src/user-event/utils/index.ts +2 -0
- package/src/user-event/utils/wait.ts +15 -0
- package/src/waitFor.ts +228 -0
- package/src/waitForElementToBeRemoved.ts +42 -0
- package/src/within.ts +30 -0
- package/tsconfig.json +17 -0
- package/tsconfig.release.json +8 -0
- package/website/.gitignore +20 -0
- package/website/README.md +33 -0
- package/website/docker/.dockerignore +3 -0
- package/website/docker/Dockerfile +9 -0
- package/website/docker/docker-compose.yml +11 -0
- package/website/docs/API.md +946 -0
- package/website/docs/EslintPLluginTestingLibrary.md +28 -0
- package/website/docs/FAQ.md +44 -0
- package/website/docs/GettingStarted.md +100 -0
- package/website/docs/HowShouldIQuery.md +21 -0
- package/website/docs/MigrationV11.md +64 -0
- package/website/docs/MigrationV12.md +67 -0
- package/website/docs/MigrationV2.md +126 -0
- package/website/docs/MigrationV7.md +119 -0
- package/website/docs/MigrationV9.md +67 -0
- package/website/docs/Queries.md +567 -0
- package/website/docs/ReactNavigation.md +371 -0
- package/website/docs/ReduxIntegration.md +137 -0
- package/website/docs/TestingEnvironment.md +154 -0
- package/website/docs/Troubleshooting.md +44 -0
- package/website/docs/UnderstandingAct.md +227 -0
- package/website/docs/UserEvent.md +66 -0
- package/website/docusaurus.config.js +114 -0
- package/website/package.json +31 -0
- package/website/sidebars.js +20 -0
- package/website/src/components/Feature.js +31 -0
- package/website/src/css/custom.css +13 -0
- package/website/src/css/index.module.css +77 -0
- package/website/src/pages/index.js +82 -0
- package/website/static/.nojekyll +0 -0
- package/website/static/css/custom.css +28 -0
- package/website/static/img/hit.png +0 -0
- package/website/static/img/locomotive.png +0 -0
- package/website/static/img/owl.png +0 -0
- package/website/static/img/tools.png +0 -0
- package/website/yarn.lock +7669 -0
- package/yarn.lock +7765 -0
- package/build/flushMicroTasks.d.ts +0 -5
- package/build/flushMicroTasks.js +0 -17
- package/build/flushMicroTasks.js.map +0 -1
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Text, TouchableOpacity, View, Pressable } from 'react-native';
|
|
3
|
+
import { fireEvent, render, waitFor, configure } from '..';
|
|
4
|
+
|
|
5
|
+
class Banana extends React.Component<any> {
|
|
6
|
+
changeFresh = () => {
|
|
7
|
+
this.props.onChangeFresh();
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
return (
|
|
12
|
+
<View>
|
|
13
|
+
{this.props.fresh && <Text>Fresh</Text>}
|
|
14
|
+
<TouchableOpacity onPress={this.changeFresh}>
|
|
15
|
+
<Text>Change freshness!</Text>
|
|
16
|
+
</TouchableOpacity>
|
|
17
|
+
</View>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class BananaContainer extends React.Component<{}, any> {
|
|
23
|
+
state = { fresh: false };
|
|
24
|
+
|
|
25
|
+
onChangeFresh = async () => {
|
|
26
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
27
|
+
this.setState({ fresh: true });
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
return (
|
|
32
|
+
<Banana onChangeFresh={this.onChangeFresh} fresh={this.state.fresh} />
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
jest.useRealTimers();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('waits for element until it stops throwing', async () => {
|
|
42
|
+
const { getByText, queryByText } = render(<BananaContainer />);
|
|
43
|
+
|
|
44
|
+
fireEvent.press(getByText('Change freshness!'));
|
|
45
|
+
|
|
46
|
+
expect(queryByText('Fresh')).toBeNull();
|
|
47
|
+
|
|
48
|
+
const freshBananaText = await waitFor(() => getByText('Fresh'));
|
|
49
|
+
|
|
50
|
+
expect(freshBananaText.props.children).toBe('Fresh');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('waits for element until timeout is met', async () => {
|
|
54
|
+
const { getByText } = render(<BananaContainer />);
|
|
55
|
+
|
|
56
|
+
fireEvent.press(getByText('Change freshness!'));
|
|
57
|
+
|
|
58
|
+
await expect(
|
|
59
|
+
waitFor(() => getByText('Fresh'), { timeout: 100 })
|
|
60
|
+
).rejects.toThrow();
|
|
61
|
+
|
|
62
|
+
// Async action ends after 300ms and we only waited 100ms, so we need to wait
|
|
63
|
+
// for the remaining async actions to finish
|
|
64
|
+
await waitFor(() => getByText('Fresh'));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('waitFor defaults to asyncWaitTimeout config option', async () => {
|
|
68
|
+
configure({ asyncUtilTimeout: 100 });
|
|
69
|
+
const { getByText } = render(<BananaContainer />);
|
|
70
|
+
|
|
71
|
+
fireEvent.press(getByText('Change freshness!'));
|
|
72
|
+
await expect(waitFor(() => getByText('Fresh'))).rejects.toThrow();
|
|
73
|
+
|
|
74
|
+
// Async action ends after 300ms and we only waited 100ms, so we need to wait
|
|
75
|
+
// for the remaining async actions to finish
|
|
76
|
+
await waitFor(() => getByText('Fresh'), { timeout: 1000 });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('waitFor timeout option takes precendence over `asyncWaitTimeout` config option', async () => {
|
|
80
|
+
configure({ asyncUtilTimeout: 2000 });
|
|
81
|
+
const { getByText } = render(<BananaContainer />);
|
|
82
|
+
|
|
83
|
+
fireEvent.press(getByText('Change freshness!'));
|
|
84
|
+
await expect(
|
|
85
|
+
waitFor(() => getByText('Fresh'), { timeout: 100 })
|
|
86
|
+
).rejects.toThrow();
|
|
87
|
+
|
|
88
|
+
// Async action ends after 300ms and we only waited 100ms, so we need to wait
|
|
89
|
+
// for the remaining async actions to finish
|
|
90
|
+
await waitFor(() => getByText('Fresh'));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('waits for element with custom interval', async () => {
|
|
94
|
+
const mockFn = jest.fn(() => {
|
|
95
|
+
throw Error('test');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await waitFor(() => mockFn(), { timeout: 400, interval: 200 });
|
|
100
|
+
} catch (e) {
|
|
101
|
+
// suppress
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// this component is convoluted on purpose. It is not a good react pattern, but it is valid
|
|
108
|
+
// react code that will run differently between different react versions (17 and 18), so we need
|
|
109
|
+
// explicit tests for it
|
|
110
|
+
const Comp = ({ onPress }: { onPress: () => void }) => {
|
|
111
|
+
const [state, setState] = React.useState(false);
|
|
112
|
+
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
if (state) {
|
|
115
|
+
onPress();
|
|
116
|
+
}
|
|
117
|
+
}, [state, onPress]);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Pressable
|
|
121
|
+
onPress={async () => {
|
|
122
|
+
await Promise.resolve();
|
|
123
|
+
setState(true);
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
<Text>Trigger</Text>
|
|
127
|
+
</Pressable>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
test('waits for async event with fireEvent', async () => {
|
|
132
|
+
const spy = jest.fn();
|
|
133
|
+
const { getByText } = render(<Comp onPress={spy} />);
|
|
134
|
+
|
|
135
|
+
fireEvent.press(getByText('Trigger'));
|
|
136
|
+
|
|
137
|
+
await waitFor(() => {
|
|
138
|
+
expect(spy).toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test.each([false, true])(
|
|
143
|
+
'waits for element until it stops throwing using fake timers (legacyFakeTimers = %s)',
|
|
144
|
+
async (legacyFakeTimers) => {
|
|
145
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
146
|
+
const { getByText, queryByText } = render(<BananaContainer />);
|
|
147
|
+
|
|
148
|
+
fireEvent.press(getByText('Change freshness!'));
|
|
149
|
+
expect(queryByText('Fresh')).toBeNull();
|
|
150
|
+
|
|
151
|
+
jest.advanceTimersByTime(300);
|
|
152
|
+
const freshBananaText = await waitFor(() => getByText('Fresh'));
|
|
153
|
+
|
|
154
|
+
expect(freshBananaText.props.children).toBe('Fresh');
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
test.each([false, true])(
|
|
159
|
+
'waits for assertion until timeout is met with fake timers (legacyFakeTimers = %s)',
|
|
160
|
+
async (legacyFakeTimers) => {
|
|
161
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
162
|
+
|
|
163
|
+
const mockFn = jest.fn(() => {
|
|
164
|
+
throw Error('test');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await waitFor(() => mockFn(), { timeout: 400, interval: 200 });
|
|
169
|
+
} catch (error) {
|
|
170
|
+
// suppress
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
expect(mockFn).toHaveBeenCalledTimes(3);
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
test.each([false, true])(
|
|
178
|
+
'waits for assertion until timeout is met with fake timers (legacyFakeTimers = %s)',
|
|
179
|
+
async (legacyFakeTimers) => {
|
|
180
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
181
|
+
|
|
182
|
+
const mockErrorFn = jest.fn(() => {
|
|
183
|
+
throw Error('test');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const mockHandleFn = jest.fn((e) => e);
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
await waitFor(() => mockErrorFn(), {
|
|
190
|
+
timeout: 400,
|
|
191
|
+
interval: 200,
|
|
192
|
+
onTimeout: mockHandleFn,
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// suppress
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
expect(mockErrorFn).toHaveBeenCalledTimes(3);
|
|
199
|
+
expect(mockHandleFn).toHaveBeenCalledTimes(1);
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const blockThread = (timeToBlockThread: number, legacyFakeTimers: boolean) => {
|
|
204
|
+
jest.useRealTimers();
|
|
205
|
+
let end = Date.now() + timeToBlockThread;
|
|
206
|
+
|
|
207
|
+
while (Date.now() < end) {
|
|
208
|
+
// do nothing
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
test.each([true, false])(
|
|
215
|
+
'it should not depend on real time when using fake timers (legacyFakeTimers = %s)',
|
|
216
|
+
async (legacyFakeTimers) => {
|
|
217
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
218
|
+
const WAIT_FOR_INTERVAL = 20;
|
|
219
|
+
const WAIT_FOR_TIMEOUT = WAIT_FOR_INTERVAL * 5;
|
|
220
|
+
|
|
221
|
+
const mockErrorFn = jest.fn(() => {
|
|
222
|
+
// Wait 2 times interval so that check time is longer than interval
|
|
223
|
+
blockThread(WAIT_FOR_INTERVAL * 2, legacyFakeTimers);
|
|
224
|
+
throw new Error('test');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
await expect(
|
|
228
|
+
async () =>
|
|
229
|
+
await waitFor(mockErrorFn, {
|
|
230
|
+
timeout: WAIT_FOR_TIMEOUT,
|
|
231
|
+
interval: WAIT_FOR_INTERVAL,
|
|
232
|
+
})
|
|
233
|
+
).rejects.toThrow();
|
|
234
|
+
|
|
235
|
+
// Verify that the `waitFor` callback has been called the expected number of times
|
|
236
|
+
// (timeout / interval + 1), so it confirms that the real duration of callback did not
|
|
237
|
+
// cause the real clock timeout when running using fake timers.
|
|
238
|
+
expect(mockErrorFn).toHaveBeenCalledTimes(
|
|
239
|
+
WAIT_FOR_TIMEOUT / WAIT_FOR_INTERVAL + 1
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
test.each([false, true])(
|
|
245
|
+
'awaiting something that succeeds before timeout works with fake timers (legacyFakeTimers = %s)',
|
|
246
|
+
async (legacyFakeTimers) => {
|
|
247
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
248
|
+
|
|
249
|
+
let calls = 0;
|
|
250
|
+
const mockFn = jest.fn(() => {
|
|
251
|
+
calls += 1;
|
|
252
|
+
if (calls < 3) {
|
|
253
|
+
throw Error('test');
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
await waitFor(() => mockFn(), { timeout: 400, interval: 200 });
|
|
259
|
+
} catch (error) {
|
|
260
|
+
// suppress
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
expect(mockFn).toHaveBeenCalledTimes(3);
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
test.each([
|
|
268
|
+
[false, false],
|
|
269
|
+
[true, false],
|
|
270
|
+
[true, true],
|
|
271
|
+
])(
|
|
272
|
+
'flushes scheduled updates before returning (fakeTimers = %s, legacyFakeTimers = %s)',
|
|
273
|
+
async (fakeTimers, legacyFakeTimers) => {
|
|
274
|
+
if (fakeTimers) {
|
|
275
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function Apple({ onPress }: { onPress: (color: string) => void }) {
|
|
279
|
+
const [color, setColor] = React.useState('green');
|
|
280
|
+
const [syncedColor, setSyncedColor] = React.useState(color);
|
|
281
|
+
|
|
282
|
+
// On mount, set the color to "red" in a promise microtask
|
|
283
|
+
React.useEffect(() => {
|
|
284
|
+
// eslint-disable-next-line promise/prefer-await-to-then, promise/catch-or-return
|
|
285
|
+
Promise.resolve('red').then((c) => setColor(c));
|
|
286
|
+
}, []);
|
|
287
|
+
|
|
288
|
+
// Sync the `color` state to `syncedColor` state, but with a delay caused by the effect
|
|
289
|
+
React.useEffect(() => {
|
|
290
|
+
setSyncedColor(color);
|
|
291
|
+
}, [color]);
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<View testID="root">
|
|
295
|
+
<Text>{color}</Text>
|
|
296
|
+
<Pressable onPress={() => onPress(syncedColor)}>
|
|
297
|
+
<Text>Trigger</Text>
|
|
298
|
+
</Pressable>
|
|
299
|
+
</View>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const onPress = jest.fn();
|
|
304
|
+
const view = render(<Apple onPress={onPress} />);
|
|
305
|
+
|
|
306
|
+
// Required: this `waitFor` will succeed on first check, because the "root" view is there
|
|
307
|
+
// since the initial mount.
|
|
308
|
+
await waitFor(() => view.getByTestId('root'));
|
|
309
|
+
|
|
310
|
+
// This `waitFor` will also succeed on first check, because the promise that sets the
|
|
311
|
+
// `color` state to "red" resolves right after the previous `await waitFor` statement.
|
|
312
|
+
await waitFor(() => view.getByText('red'));
|
|
313
|
+
|
|
314
|
+
// Check that the `onPress` callback is called with the already-updated value of `syncedColor`.
|
|
315
|
+
fireEvent.press(view.getByText('Trigger'));
|
|
316
|
+
expect(onPress).toHaveBeenCalledWith('red');
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
test('waitFor throws if expectation is not a function', async () => {
|
|
321
|
+
await expect(
|
|
322
|
+
// @ts-expect-error intentionally passing non-function
|
|
323
|
+
waitFor('not a function')
|
|
324
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
325
|
+
`"Received \`expectation\` arg must be a function"`
|
|
326
|
+
);
|
|
327
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { render, fireEvent, waitForElementToBeRemoved } from '..';
|
|
4
|
+
|
|
5
|
+
const TestSetup = ({ shouldUseDelay = true }) => {
|
|
6
|
+
const [isAdded, setIsAdded] = useState(true);
|
|
7
|
+
|
|
8
|
+
const removeElement = async () => {
|
|
9
|
+
if (shouldUseDelay) {
|
|
10
|
+
setTimeout(() => setIsAdded(false), 300);
|
|
11
|
+
} else {
|
|
12
|
+
setIsAdded(false);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<View>
|
|
18
|
+
{isAdded && <Text>Observed Element</Text>}
|
|
19
|
+
|
|
20
|
+
<TouchableOpacity onPress={removeElement}>
|
|
21
|
+
<Text>Remove Element</Text>
|
|
22
|
+
</TouchableOpacity>
|
|
23
|
+
</View>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.useRealTimers();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('waits when using getBy query', async () => {
|
|
32
|
+
const screen = render(<TestSetup />);
|
|
33
|
+
|
|
34
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
35
|
+
const element = screen.getByText('Observed Element');
|
|
36
|
+
expect(element).toBeTruthy();
|
|
37
|
+
|
|
38
|
+
const result = await waitForElementToBeRemoved(() =>
|
|
39
|
+
screen.getByText('Observed Element')
|
|
40
|
+
);
|
|
41
|
+
expect(screen.queryByText('Observed Element')).toBeNull();
|
|
42
|
+
expect(result).toEqual(element);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('waits when using getAllBy query', async () => {
|
|
46
|
+
const screen = render(<TestSetup />);
|
|
47
|
+
|
|
48
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
49
|
+
const elements = screen.getAllByText('Observed Element');
|
|
50
|
+
expect(elements).toBeTruthy();
|
|
51
|
+
|
|
52
|
+
const result = await waitForElementToBeRemoved(() =>
|
|
53
|
+
screen.getAllByText('Observed Element')
|
|
54
|
+
);
|
|
55
|
+
expect(screen.queryByText('Observed Element')).toBeNull();
|
|
56
|
+
expect(result).toEqual(elements);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('waits when using queryBy query', async () => {
|
|
60
|
+
const screen = render(<TestSetup />);
|
|
61
|
+
|
|
62
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
63
|
+
const element = screen.getByText('Observed Element');
|
|
64
|
+
expect(element).toBeTruthy();
|
|
65
|
+
|
|
66
|
+
const result = await waitForElementToBeRemoved(() =>
|
|
67
|
+
screen.queryByText('Observed Element')
|
|
68
|
+
);
|
|
69
|
+
expect(screen.queryByText('Observed Element')).toBeNull();
|
|
70
|
+
expect(result).toEqual(element);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('waits when using queryAllBy query', async () => {
|
|
74
|
+
const screen = render(<TestSetup />);
|
|
75
|
+
|
|
76
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
77
|
+
const elements = screen.getAllByText('Observed Element');
|
|
78
|
+
expect(elements).toBeTruthy();
|
|
79
|
+
|
|
80
|
+
const result = await waitForElementToBeRemoved(() =>
|
|
81
|
+
screen.queryAllByText('Observed Element')
|
|
82
|
+
);
|
|
83
|
+
expect(screen.queryByText('Observed Element')).toBeNull();
|
|
84
|
+
expect(result).toEqual(elements);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('checks if elements exist at start', async () => {
|
|
88
|
+
const screen = render(<TestSetup shouldUseDelay={false} />);
|
|
89
|
+
|
|
90
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
91
|
+
expect(screen.queryByText('Observed Element')).toBeNull();
|
|
92
|
+
|
|
93
|
+
await expect(
|
|
94
|
+
waitForElementToBeRemoved(() => screen.queryByText('Observed Element'))
|
|
95
|
+
).rejects.toThrow(
|
|
96
|
+
'The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.'
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('waits until timeout', async () => {
|
|
101
|
+
const screen = render(<TestSetup />);
|
|
102
|
+
|
|
103
|
+
fireEvent.press(screen.getByText('Remove Element'));
|
|
104
|
+
expect(screen.getByText('Observed Element')).toBeTruthy();
|
|
105
|
+
|
|
106
|
+
await expect(
|
|
107
|
+
waitForElementToBeRemoved(() => screen.getByText('Observed Element'), {
|
|
108
|
+
timeout: 100,
|
|
109
|
+
})
|
|
110
|
+
).rejects.toThrow('Timed out in waitForElementToBeRemoved.');
|
|
111
|
+
|
|
112
|
+
// Async action ends after 300ms and we only waited 100ms, so we need to wait for the remaining
|
|
113
|
+
// async actions to finish
|
|
114
|
+
await waitForElementToBeRemoved(() => screen.getByText('Observed Element'));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('waits with custom interval', async () => {
|
|
118
|
+
const mockFn = jest.fn(() => <View />);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await waitForElementToBeRemoved(() => mockFn(), {
|
|
122
|
+
timeout: 600,
|
|
123
|
+
interval: 200,
|
|
124
|
+
});
|
|
125
|
+
} catch (e) {
|
|
126
|
+
// Suppress expected error
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
expect(mockFn).toHaveBeenCalledTimes(4);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test.each([false, true])(
|
|
133
|
+
'works with fake timers (legacyFakeTimers = %s)',
|
|
134
|
+
async (legacyFakeTimers) => {
|
|
135
|
+
jest.useFakeTimers({ legacyFakeTimers });
|
|
136
|
+
|
|
137
|
+
const mockFn = jest.fn(() => <View />);
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
await waitForElementToBeRemoved(() => mockFn(), {
|
|
141
|
+
timeout: 400,
|
|
142
|
+
interval: 200,
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
// Suppress expected error
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// waitForElementToBeRemoved runs an initial call of the expectation
|
|
149
|
+
expect(mockFn).toHaveBeenCalledTimes(4);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View, Text, TextInput } from 'react-native';
|
|
3
|
+
import { render, within, getQueriesForElement } from '..';
|
|
4
|
+
|
|
5
|
+
test('within() exposes basic queries', async () => {
|
|
6
|
+
const rootQueries = render(
|
|
7
|
+
<View>
|
|
8
|
+
<View accessibilityHint="first">
|
|
9
|
+
<Text>Same Text</Text>
|
|
10
|
+
<TextInput value="Same Value" placeholder="Same Placeholder" />
|
|
11
|
+
</View>
|
|
12
|
+
<View accessibilityHint="second">
|
|
13
|
+
<Text>Same Text</Text>
|
|
14
|
+
<TextInput value="Same Value" placeholder="Same Placeholder" />
|
|
15
|
+
</View>
|
|
16
|
+
</View>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
expect(rootQueries.getAllByText('Same Text')).toHaveLength(2);
|
|
20
|
+
expect(rootQueries.getAllByDisplayValue('Same Value')).toHaveLength(2);
|
|
21
|
+
expect(rootQueries.getAllByPlaceholderText('Same Placeholder')).toHaveLength(
|
|
22
|
+
2
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const firstQueries = within(rootQueries.getByA11yHint('first'));
|
|
26
|
+
expect(firstQueries.getAllByText('Same Text')).toHaveLength(1);
|
|
27
|
+
expect(firstQueries.getByText('Same Text')).toBeTruthy();
|
|
28
|
+
expect(firstQueries.queryAllByText('Same Text')).toHaveLength(1);
|
|
29
|
+
expect(firstQueries.queryByText('Same Text')).toBeTruthy();
|
|
30
|
+
expect(firstQueries.getByDisplayValue('Same Value')).toBeTruthy();
|
|
31
|
+
expect(firstQueries.getByPlaceholderText('Same Placeholder')).toBeTruthy();
|
|
32
|
+
await expect(
|
|
33
|
+
firstQueries.findByDisplayValue('Same Value')
|
|
34
|
+
).resolves.toBeTruthy();
|
|
35
|
+
await expect(
|
|
36
|
+
firstQueries.findAllByPlaceholderText('Same Placeholder')
|
|
37
|
+
).resolves.toHaveLength(1);
|
|
38
|
+
|
|
39
|
+
const secondQueries = within(rootQueries.getByA11yHint('second'));
|
|
40
|
+
expect(secondQueries.getAllByText('Same Text')).toHaveLength(1);
|
|
41
|
+
expect(secondQueries.getByText('Same Text')).toBeTruthy();
|
|
42
|
+
expect(secondQueries.queryAllByText('Same Text')).toHaveLength(1);
|
|
43
|
+
expect(secondQueries.queryByText('Same Text')).toBeTruthy();
|
|
44
|
+
expect(secondQueries.getByDisplayValue('Same Value')).toBeTruthy();
|
|
45
|
+
expect(secondQueries.getByPlaceholderText('Same Placeholder')).toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('within() exposes a11y queries', async () => {
|
|
49
|
+
const rootQueries = render(
|
|
50
|
+
<View>
|
|
51
|
+
<View accessibilityHint="first">
|
|
52
|
+
<TextInput
|
|
53
|
+
value="Same Value"
|
|
54
|
+
accessibilityLabel="Same Label"
|
|
55
|
+
accessibilityHint="Same Hint"
|
|
56
|
+
/>
|
|
57
|
+
</View>
|
|
58
|
+
<View accessibilityHint="second">
|
|
59
|
+
<TextInput
|
|
60
|
+
value="Same Value"
|
|
61
|
+
accessibilityLabel="Same Label"
|
|
62
|
+
accessibilityHint="Same Hint"
|
|
63
|
+
/>
|
|
64
|
+
</View>
|
|
65
|
+
</View>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(rootQueries.getAllByLabelText('Same Label')).toHaveLength(2);
|
|
69
|
+
expect(rootQueries.getAllByA11yHint('Same Hint')).toHaveLength(2);
|
|
70
|
+
|
|
71
|
+
const firstQueries = within(rootQueries.getByA11yHint('first'));
|
|
72
|
+
expect(firstQueries.getByLabelText('Same Label')).toBeTruthy();
|
|
73
|
+
expect(firstQueries.getByA11yHint('Same Hint')).toBeTruthy();
|
|
74
|
+
expect(firstQueries.queryByLabelText('Same Label')).toBeTruthy();
|
|
75
|
+
expect(firstQueries.queryByA11yHint('Same Hint')).toBeTruthy();
|
|
76
|
+
await expect(
|
|
77
|
+
firstQueries.findByLabelText('Same Label')
|
|
78
|
+
).resolves.toBeTruthy();
|
|
79
|
+
await expect(firstQueries.findByA11yHint('Same Hint')).resolves.toBeTruthy();
|
|
80
|
+
|
|
81
|
+
const secondQueries = within(rootQueries.getByA11yHint('second'));
|
|
82
|
+
expect(secondQueries.getAllByLabelText('Same Label')).toHaveLength(1);
|
|
83
|
+
expect(secondQueries.getAllByA11yHint('Same Hint')).toHaveLength(1);
|
|
84
|
+
expect(secondQueries.queryAllByLabelText('Same Label')).toHaveLength(1);
|
|
85
|
+
expect(secondQueries.queryAllByA11yHint('Same Hint')).toHaveLength(1);
|
|
86
|
+
await expect(
|
|
87
|
+
secondQueries.findAllByLabelText('Same Label')
|
|
88
|
+
).resolves.toHaveLength(1);
|
|
89
|
+
await expect(
|
|
90
|
+
secondQueries.findAllByA11yHint('Same Hint')
|
|
91
|
+
).resolves.toHaveLength(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('getQueriesForElement is alias to within', () => {
|
|
95
|
+
expect(getQueriesForElement).toBe(within);
|
|
96
|
+
});
|
package/src/act.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// This file and the act() implementation is sourced from react-testing-library
|
|
2
|
+
// https://github.com/testing-library/react-testing-library/blob/c80809a956b0b9f3289c4a6fa8b5e8cc72d6ef6d/src/act-compat.js
|
|
3
|
+
import { act as reactTestRendererAct } from 'react-test-renderer';
|
|
4
|
+
import { checkReactVersionAtLeast } from './react-versions';
|
|
5
|
+
|
|
6
|
+
type ReactAct = typeof reactTestRendererAct;
|
|
7
|
+
|
|
8
|
+
// See https://github.com/reactwg/react-18/discussions/102 for more context on global.IS_REACT_ACT_ENVIRONMENT
|
|
9
|
+
declare global {
|
|
10
|
+
var IS_REACT_ACT_ENVIRONMENT: boolean | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function setIsReactActEnvironment(isReactActEnvironment: boolean | undefined) {
|
|
14
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getIsReactActEnvironment() {
|
|
18
|
+
return globalThis.IS_REACT_ACT_ENVIRONMENT;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function withGlobalActEnvironment(actImplementation: ReactAct) {
|
|
22
|
+
return (callback: Parameters<ReactAct>[0]) => {
|
|
23
|
+
const previousActEnvironment = getIsReactActEnvironment();
|
|
24
|
+
setIsReactActEnvironment(true);
|
|
25
|
+
|
|
26
|
+
// this code is riddled with eslint disabling comments because this doesn't use real promises but eslint thinks we do
|
|
27
|
+
try {
|
|
28
|
+
// The return value of `act` is always a thenable.
|
|
29
|
+
let callbackNeedsToBeAwaited = false;
|
|
30
|
+
const actResult = actImplementation(() => {
|
|
31
|
+
const result = callback();
|
|
32
|
+
if (
|
|
33
|
+
result !== null &&
|
|
34
|
+
typeof result === 'object' &&
|
|
35
|
+
// @ts-expect-error this should be a promise or thenable
|
|
36
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
37
|
+
typeof result.then === 'function'
|
|
38
|
+
) {
|
|
39
|
+
callbackNeedsToBeAwaited = true;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (callbackNeedsToBeAwaited) {
|
|
45
|
+
const thenable = actResult;
|
|
46
|
+
return {
|
|
47
|
+
then: (
|
|
48
|
+
resolve: (value: never) => never,
|
|
49
|
+
reject: (value: never) => never
|
|
50
|
+
) => {
|
|
51
|
+
// eslint-disable-next-line
|
|
52
|
+
thenable.then(
|
|
53
|
+
// eslint-disable-next-line promise/always-return
|
|
54
|
+
(returnValue) => {
|
|
55
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
56
|
+
resolve(returnValue);
|
|
57
|
+
},
|
|
58
|
+
(error) => {
|
|
59
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
60
|
+
reject(error);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
} else {
|
|
66
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
67
|
+
return actResult;
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
// Can't be a `finally {}` block since we don't know if we have to immediately restore IS_REACT_ACT_ENVIRONMENT
|
|
71
|
+
// or if we have to await the callback first.
|
|
72
|
+
setIsReactActEnvironment(previousActEnvironment);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const act: ReactAct = checkReactVersionAtLeast(18, 0)
|
|
79
|
+
? (withGlobalActEnvironment(reactTestRendererAct) as ReactAct)
|
|
80
|
+
: reactTestRendererAct;
|
|
81
|
+
|
|
82
|
+
export default act;
|
|
83
|
+
export {
|
|
84
|
+
setIsReactActEnvironment as setReactActEnvironment,
|
|
85
|
+
getIsReactActEnvironment,
|
|
86
|
+
};
|
package/src/cleanup.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { clearRenderResult } from './screen';
|
|
3
|
+
|
|
4
|
+
type CleanUpFunction = (nextElement?: React.ReactElement<any>) => void;
|
|
5
|
+
let cleanupQueue = new Set<CleanUpFunction>();
|
|
6
|
+
|
|
7
|
+
export default function cleanup() {
|
|
8
|
+
clearRenderResult();
|
|
9
|
+
cleanupQueue.forEach((fn) => fn());
|
|
10
|
+
cleanupQueue.clear();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function addToCleanupQueue(fn: CleanUpFunction) {
|
|
14
|
+
cleanupQueue.add(fn);
|
|
15
|
+
}
|