diff --git a/.circleci/config.yml b/.circleci/config.yml index 1fd4d1c866d..65c18975ad7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -181,7 +181,7 @@ workflows: - "@types/react@16.8 @types/react-dom@16.8" - "@types/react@17 @types/react-dom@17" - "@types/react@18 @types/react-dom@18" - - "@types/react@npm:types-react@19.0.0-rc.0 @types/react-dom@npm:types-react-dom@19.0.0-rc.0" + - "@types/react@npm:types-react@19.0.0-rc.1 @types/react-dom@npm:types-react-dom@19.0.0-rc.1" - "typescript@next" security-scans: jobs: diff --git a/.eslintrc b/.eslintrc index 3d2db88a9fc..2cc564c03e1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -92,7 +92,10 @@ "rules": { "testing-library/prefer-user-event": "error", "testing-library/no-wait-for-multiple-assertions": "off", - "local-rules/require-using-disposable": "error" + "local-rules/require-using-disposable": "error", + "local-rules/require-disable-act-environment": "error", + "local-rules/forbid-act-in-disabled-act-environment": "error", + "@typescript-eslint/no-floating-promises": "warn" } } ], diff --git a/README.md b/README.md index c533f8bcec5..49c33c2fd06 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Join 1000+ engineers at GraphQL Summit for talks, workshops, and office hours, O Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more. It allows you to easily build UI components that fetch data via GraphQL. +Apollo Client aims to comply with the [Working Draft of the GraphQL specification](https://spec.graphql.org/draft/). + | ☑️ Apollo Client User Survey | | :----- | | What do you like best about Apollo Client? What needs to be improved? Please tell us by taking a [one-minute survey](https://docs.google.com/forms/d/e/1FAIpQLSczNDXfJne3ZUOXjk9Ursm9JYvhTh1_nFTDfdq3XBAFWCzplQ/viewform?usp=pp_url&entry.1170701325=Apollo+Client&entry.204965213=Readme). Your responses will help us understand Apollo Client usage and allow us to serve you better. | diff --git a/config/jest.config.js b/config/jest.config.js index 33e7aba59df..ce297ed2af0 100644 --- a/config/jest.config.js +++ b/config/jest.config.js @@ -85,7 +85,6 @@ const standardReact17Config = { "^react-dom$": "react-dom-17", "^react-dom/server$": "react-dom-17/server", "^react-dom/test-utils$": "react-dom-17/test-utils", - "^@testing-library/react$": "@testing-library/react-12", }, }; diff --git a/eslint-local-rules/forbid-act-in-disabled-act-environment.test.ts b/eslint-local-rules/forbid-act-in-disabled-act-environment.test.ts new file mode 100644 index 00000000000..8024e91bcc5 --- /dev/null +++ b/eslint-local-rules/forbid-act-in-disabled-act-environment.test.ts @@ -0,0 +1,56 @@ +import { rule } from "./forbid-act-in-disabled-act-environment"; +import { ruleTester } from "./testSetup"; + +ruleTester.run("forbid-act-in-disabled-act-environment", rule, { + valid: [ + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + act(() => {}) + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + actAsync(() => {}) + } + `, + ], + invalid: [ + ` + () => { + using _disabledAct = disableActEnvironment(); + act(() => {}) + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + actAsync(() => {}) + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + () => { + act(() => {}) + } + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + () => { + actAsync(() => {}) + } + } + `, + ].map((code) => ({ + code, + errors: [{ messageId: "forbiddenActInNonActEnvironment" }], + })), +}); diff --git a/eslint-local-rules/forbid-act-in-disabled-act-environment.ts b/eslint-local-rules/forbid-act-in-disabled-act-environment.ts new file mode 100644 index 00000000000..7cbe9edf572 --- /dev/null +++ b/eslint-local-rules/forbid-act-in-disabled-act-environment.ts @@ -0,0 +1,63 @@ +import { ESLintUtils } from "@typescript-eslint/utils"; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + create(context) { + let depth = 1; + let disabledDepth: number | false = false; + + function EnterFn() { + depth++; + } + function ExitFn() { + depth--; + if (disabledDepth !== false && disabledDepth > depth) { + disabledDepth = false; + } + } + + return { + CallExpression(node) { + const directCallee = + node.callee.type === "Identifier" ? node.callee + : node.callee.type === "MemberExpression" ? node.callee.property + : null; + + if ( + directCallee?.type === "Identifier" && + directCallee.name === "disableActEnvironment" + ) { + if (disabledDepth === false) { + disabledDepth = depth; + } + } + + if ( + directCallee?.type === "Identifier" && + (directCallee.name === "act" || directCallee.name === "actAsync") + ) { + if (disabledDepth !== false) { + context.report({ + messageId: "forbiddenActInNonActEnvironment", + node: node, + }); + } + } + }, + ArrowFunctionExpression: EnterFn, + FunctionExpression: EnterFn, + FunctionDeclaration: EnterFn, + "ArrowFunctionExpression:exit": ExitFn, + "FunctionExpression:exit": ExitFn, + "FunctionDeclaration:exit": ExitFn, + }; + }, + meta: { + messages: { + forbiddenActInNonActEnvironment: + "`act` should not be called in a `disableActEnvironment`.", + }, + type: "problem", + schema: [], + }, + defaultOptions: [], +}); diff --git a/eslint-local-rules/index.js b/eslint-local-rules/index.js index 7261c8ccc40..34951395d60 100644 --- a/eslint-local-rules/index.js +++ b/eslint-local-rules/index.js @@ -11,4 +11,8 @@ require("ts-node").register({ module.exports = { "require-using-disposable": require("./require-using-disposable").rule, + "require-disable-act-environment": + require("./require-disable-act-environment").rule, + "forbid-act-in-disabled-act-environment": + require("./forbid-act-in-disabled-act-environment").rule, }; diff --git a/eslint-local-rules/require-disable-act-environment.test.ts b/eslint-local-rules/require-disable-act-environment.test.ts new file mode 100644 index 00000000000..0366a48dda8 --- /dev/null +++ b/eslint-local-rules/require-disable-act-environment.test.ts @@ -0,0 +1,120 @@ +import { rule } from "./require-disable-act-environment"; +import { ruleTester } from "./testSetup"; + +ruleTester.run("require-disable-act-environment", rule, { + valid: [ + ` + () => { + using _disabledAct = disableActEnvironment(); + const { takeRender } = someCall() + const {} = takeRender() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + const {} = renderStream.takeRender() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = someCall() + const {} = takeSnapshot() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + const {} = renderStream.takeSnapshot() + } + `, + ` + using _disabledAct = disableActEnvironment(); + () => { + const { takeRender } = someCall() + const {} = takeRender() + } + `, + ` + using _disabledAct = disableActEnvironment(); + () => { + const {} = renderStream.takeRender() + } + `, + ` + using _disabledAct = disableActEnvironment(); + () => { + const { takeSnapshot } = someCall() + const {} = takeSnapshot() + } + `, + ` + using _disabledAct = disableActEnvironment(); + () => { + const {} = renderStream.takeSnapshot() + } + `, + ], + invalid: [ + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + const { takeRender } = someCall() + takeRender() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + renderStream.takeRender() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + const { takeSnapshot } = someCall() + takeSnapshot() + } + `, + ` + () => { + using _disabledAct = disableActEnvironment(); + } + () => { + renderStream.takeSnapshot() + } + `, + ` + () => { + const { takeRender } = someCall() + takeRender() + } + `, + ` + () => { + renderStream.takeRender() + } + `, + ` + () => { + const { takeSnapshot } = someCall() + takeSnapshot() + } + `, + ` + () => { + renderStream.takeSnapshot() + } + `, + ].map((code) => ({ + code, + errors: [{ messageId: "missingDisableActEnvironment" }], + })), +}); diff --git a/eslint-local-rules/require-disable-act-environment.ts b/eslint-local-rules/require-disable-act-environment.ts new file mode 100644 index 00000000000..1f246194664 --- /dev/null +++ b/eslint-local-rules/require-disable-act-environment.ts @@ -0,0 +1,83 @@ +import { ESLintUtils, ASTUtils } from "@typescript-eslint/utils"; +import type { TSESTree as AST } from "@typescript-eslint/types"; + +type Fn = + | AST.FunctionDeclaration + | AST.ArrowFunctionExpression + | AST.FunctionExpression; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + create(context) { + let depth = 1; + let disabledDepth: number | false = false; + + function EnterFn() { + depth++; + } + function ExitFn() { + depth--; + if (disabledDepth !== false && disabledDepth > depth) { + disabledDepth = false; + } + } + + return { + CallExpression(node) { + const directCallee = + node.callee.type === "Identifier" ? node.callee + : node.callee.type === "MemberExpression" ? node.callee.property + : null; + + if ( + directCallee?.type === "Identifier" && + directCallee.name === "disableActEnvironment" + ) { + if (disabledDepth === false) { + disabledDepth = depth; + } + } + + if ( + directCallee?.type === "Identifier" && + (directCallee.name === "takeRender" || + directCallee.name === "takeSnapshot") + ) { + if (disabledDepth === false) { + context.report({ + messageId: "missingDisableActEnvironment", + node: node, + }); + } + } + }, + ArrowFunctionExpression: EnterFn, + FunctionExpression: EnterFn, + FunctionDeclaration: EnterFn, + "ArrowFunctionExpression:exit": ExitFn, + "FunctionExpression:exit": ExitFn, + "FunctionDeclaration:exit": ExitFn, + }; + }, + meta: { + messages: { + missingDisableActEnvironment: + "Tests using a render stream should call `disableActEnvironment`.", + }, + type: "problem", + schema: [], + }, + defaultOptions: [], +}); + +function findParentFunction(node: AST.Node): Fn | undefined { + let parentFunction: AST.Node | undefined = node; + while ( + parentFunction != null && + parentFunction.type !== "FunctionDeclaration" && + parentFunction.type !== "FunctionExpression" && + parentFunction.type !== "ArrowFunctionExpression" + ) { + parentFunction = parentFunction.parent; + } + return parentFunction; +} diff --git a/package-lock.json b/package-lock.json index b6411d72b7a..041f799f585 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,10 +38,10 @@ "@rollup/plugin-node-resolve": "11.2.1", "@size-limit/esbuild-why": "11.1.4", "@size-limit/preset-small-lib": "11.1.4", + "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "6.4.6", - "@testing-library/react": "15.0.7", - "@testing-library/react-12": "npm:@testing-library/react@^12", - "@testing-library/react-render-stream": "1.0.3", + "@testing-library/react": "^16.0.1", + "@testing-library/react-render-stream": "2.0.0-alpha.1", "@testing-library/user-event": "14.5.2", "@tsconfig/node20": "20.1.4", "@types/bytes": "3.1.4", @@ -87,10 +87,10 @@ "prettier": "3.1.1", "react": "18.3.1", "react-17": "npm:react@^17", - "react-19": "npm:react@19.0.0-rc-378b305958-20240710", + "react-19": "npm:react@19.0.0-rc.1", "react-dom": "18.3.1", "react-dom-17": "npm:react-dom@^17", - "react-dom-19": "npm:react-dom@19.0.0-rc-378b305958-20240710", + "react-dom-19": "npm:react-dom@19.0.0-rc.1", "react-error-boundary": "4.0.13", "recast": "0.23.9", "resolve": "1.22.8", @@ -3480,31 +3480,23 @@ } }, "node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" + "node": ">=18" } }, "node_modules/@testing-library/jest-dom": { @@ -3611,73 +3603,37 @@ "license": "MIT" }, "node_modules/@testing-library/react": { - "version": "15.0.7", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", - "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^10.0.0", - "@types/react-dom": "^18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { "node": ">=18" }, "peerDependencies": { + "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@testing-library/react-12": { - "name": "@testing-library/react", - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" - } - }, - "node_modules/@testing-library/react-12/node_modules/@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "^0.16", - "csstype": "^3.0.2" - } - }, - "node_modules/@testing-library/react-12/node_modules/@types/react-dom": { - "version": "17.0.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", - "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", - "dev": true, - "dependencies": { - "@types/react": "^17" - } - }, "node_modules/@testing-library/react-render-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@testing-library/react-render-stream/-/react-render-stream-1.0.3.tgz", - "integrity": "sha512-CltwyRRrpjZHKbAB6DwIcQo9mcPiGkmW4v3XHL7mWsI9xUHWzEbLzqiqErxuzuDQwI55LzjRF28aQLujrpMygw==", + "version": "2.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-render-stream/-/react-render-stream-2.0.0-alpha.1.tgz", + "integrity": "sha512-nCSbToZBlE3iEqzcFEv6jkXE1mw+tKSrHbfqE11K1/a9wiBd+eMfVVEb9Zyi8Rl75BLaX8z5REqHOGUg09zwTw==", "dev": true, "license": "MIT", "dependencies": { @@ -3693,54 +3649,6 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0" } }, - "node_modules/@testing-library/react-render-stream/node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/react-render-stream/node_modules/@testing-library/react": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@testing-library/react-render-stream/node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -3981,26 +3889,6 @@ "node": ">=18" } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.3.1.tgz", - "integrity": "sha512-q/WL+vlXMpC0uXDyfsMtc1rmotzLV8Y0gq6q1gfrrDjQeHoeLrqHbxdPvPNAh1i+xuJl7+BezywcXArz7vLqKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/user-event": { "version": "14.5.2", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", @@ -4330,12 +4218,6 @@ "@types/node": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -5994,38 +5876,6 @@ } } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -6417,26 +6267,6 @@ "node": ">= 0.4" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-set-tostringtag": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", @@ -8320,22 +8150,6 @@ "node": ">= 0.4" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -8522,18 +8336,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -8607,18 +8409,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -8706,18 +8496,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -8730,22 +8508,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -10448,22 +10210,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -11350,10 +11096,11 @@ }, "node_modules/react-19": { "name": "react", - "version": "19.0.0-rc-378b305958-20240710", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc-378b305958-20240710.tgz", - "integrity": "sha512-z+c5SdYuX74FSlyDcBWXMmR7KN30rpak804OtidcgxvYoyU43YCT0GWHubH6UvnNDvaLsr5nl66AKmC2y7VwYA==", + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc.1.tgz", + "integrity": "sha512-NZKln+uyPuyHchzP07I6GGYFxdAoaKhehgpCa3ltJGzwE31OYumLeshGaitA1R/fS5d9D2qpZVwTFAr6zCLM9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -11398,22 +11145,24 @@ }, "node_modules/react-dom-19": { "name": "react-dom", - "version": "19.0.0-rc-378b305958-20240710", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-378b305958-20240710.tgz", - "integrity": "sha512-WpE0+4pnFMyuC9WxJGj7+XysxNChbwnCcFS7INR428/uUoECSTRmlQt05hTGFIyfpYBO1zGlXfMBAkrFmqh3wg==", + "version": "19.0.0-rc.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc.1.tgz", + "integrity": "sha512-k8MfDX+4G+eaa1cXXI9QF4d+pQtYol3nx8vauqRWUEOPqC7NQn2qmEqUsLoSd28rrZUL+R3T2VC+kZ2Hyx1geQ==", "dev": true, + "license": "MIT", "dependencies": { - "scheduler": "0.25.0-rc-378b305958-20240710" + "scheduler": "0.25.0-rc.1" }, "peerDependencies": { - "react": "19.0.0-rc-378b305958-20240710" + "react": "19.0.0-rc.1" } }, "node_modules/react-dom-19/node_modules/scheduler": { - "version": "0.25.0-rc-378b305958-20240710", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-378b305958-20240710.tgz", - "integrity": "sha512-j6dzH6LeNjhKFSpxUiZT2E8tFvFTCQOn339mmzYA3QBLvIkgAtHzSrpdReKhFzw9x4hxazBjgE/4YwBLQBUNlw==", - "dev": true + "version": "0.25.0-rc.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc.1.tgz", + "integrity": "sha512-fVinv2lXqYpKConAMdergOl5owd0rY1O4P/QTe0aWKCqGtu7VsCt1iqQFxSJtqK4Lci/upVSBpGwVC7eWcuS9Q==", + "dev": true, + "license": "MIT" }, "node_modules/react-error-boundary": { "version": "4.0.13", @@ -12285,18 +12034,6 @@ "node": ">=8" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12670,22 +12407,22 @@ } }, "node_modules/tldts": { - "version": "6.1.50", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.50.tgz", - "integrity": "sha512-q9GOap6q3KCsLMdOjXhWU5jVZ8/1dIib898JBRLsN+tBhENpBDcAVQbE0epADOjw11FhQQy9AcbqKGBQPUfTQA==", + "version": "6.1.64", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.64.tgz", + "integrity": "sha512-ph4AE5BXWIOsSy9stpoeo7bYe/Cy7VfpciIH4RhVZUPItCJmhqWCN0EVzxd8BOHiyNb42vuJc6NWTjJkg91Tuw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.50" + "tldts-core": "^6.1.64" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.50", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.50.tgz", - "integrity": "sha512-na2EcZqmdA2iV9zHV7OHQDxxdciEpxrjbkp+aHmZgnZKHzoElLajP59np5/4+sare9fQBfixgvXKx8ev1d7ytw==", + "version": "6.1.64", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.64.tgz", + "integrity": "sha512-uqnl8vGV16KsyflHOzqrYjjArjfXaU6rMPXYy2/ZWoRKCkXtghgB4VwTDXUG+t0OTGeSewNAG31/x1gCTfLt+Q==", "dev": true, "license": "MIT" }, @@ -13944,24 +13681,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-pm": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", diff --git a/package.json b/package.json index 207ebc2321f..b8470e2e4bf 100644 --- a/package.json +++ b/package.json @@ -121,10 +121,10 @@ "@rollup/plugin-node-resolve": "11.2.1", "@size-limit/esbuild-why": "11.1.4", "@size-limit/preset-small-lib": "11.1.4", + "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "6.4.6", - "@testing-library/react": "15.0.7", - "@testing-library/react-12": "npm:@testing-library/react@^12", - "@testing-library/react-render-stream": "1.0.3", + "@testing-library/react": "^16.0.1", + "@testing-library/react-render-stream": "2.0.0-alpha.1", "@testing-library/user-event": "14.5.2", "@tsconfig/node20": "20.1.4", "@types/bytes": "3.1.4", @@ -170,10 +170,10 @@ "prettier": "3.1.1", "react": "18.3.1", "react-17": "npm:react@^17", - "react-19": "npm:react@19.0.0-rc-378b305958-20240710", + "react-19": "npm:react@19.0.0-rc.1", "react-dom": "18.3.1", "react-dom-17": "npm:react-dom@^17", - "react-dom-19": "npm:react-dom@19.0.0-rc-378b305958-20240710", + "react-dom-19": "npm:react-dom@19.0.0-rc.1", "react-error-boundary": "4.0.13", "recast": "0.23.9", "resolve": "1.22.8", @@ -212,6 +212,7 @@ "**/*.json" ], "overrides": { - "pretty-format": "^29.7.0" + "pretty-format": "^29.7.0", + "@testing-library/dom": "$@testing-library/dom" } } diff --git a/patches/@testing-library+react+16.0.1.patch b/patches/@testing-library+react+16.0.1.patch new file mode 100644 index 00000000000..960c91678dc --- /dev/null +++ b/patches/@testing-library+react+16.0.1.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@testing-library/react/dist/pure.js b/node_modules/@testing-library/react/dist/pure.js +index 7b62fa7..9ad1d9e 100644 +--- a/node_modules/@testing-library/react/dist/pure.js ++++ b/node_modules/@testing-library/react/dist/pure.js +@@ -223,7 +223,7 @@ function renderRoot(ui, { + function render(ui, { + container, + baseElement = container, +- legacyRoot = false, ++ legacyRoot = React.version.startsWith("17"), + queries, + hydrate = false, + wrapper diff --git a/patches/@testing-library+react-12+12.1.5.patch b/patches/@testing-library+react-12+12.1.5.patch deleted file mode 100644 index b43371e8d13..00000000000 --- a/patches/@testing-library+react-12+12.1.5.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/node_modules/@testing-library/react-12/dist/pure.js b/node_modules/@testing-library/react-12/dist/pure.js -index 72287ac..f0d2c59 100644 ---- a/node_modules/@testing-library/react-12/dist/pure.js -+++ b/node_modules/@testing-library/react-12/dist/pure.js -@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { - }); - var _exportNames = { - render: true, -+ renderHook: true, - cleanup: true, - act: true, - fireEvent: true -@@ -25,6 +26,7 @@ Object.defineProperty(exports, "fireEvent", { - } - }); - exports.render = render; -+exports.renderHook = renderHook; - - var React = _interopRequireWildcard(require("react")); - -@@ -138,6 +140,42 @@ function cleanup() { - } // maybe one day we'll expose this (perhaps even as a utility returned by render). - // but let's wait until someone asks for it. - -+function renderHook(renderCallback, options = {}) { -+ const { -+ initialProps, -+ ...renderOptions -+ } = options; -+ const result = /*#__PURE__*/React.createRef(); -+ -+ function TestComponent({ -+ renderCallbackProps -+ }) { -+ const pendingResult = renderCallback(renderCallbackProps); -+ React.useEffect(() => { -+ result.current = pendingResult; -+ }); -+ return null; -+ } -+ -+ const { -+ rerender: baseRerender, -+ unmount -+ } = render( /*#__PURE__*/React.createElement(TestComponent, { -+ renderCallbackProps: initialProps -+ }), renderOptions); -+ -+ function rerender(rerenderCallbackProps) { -+ return baseRerender( /*#__PURE__*/React.createElement(TestComponent, { -+ renderCallbackProps: rerenderCallbackProps -+ })); -+ } -+ -+ return { -+ result, -+ rerender, -+ unmount -+ }; -+} // just re-export everything from dom-testing-library - - function cleanupAtContainer(container) { - (0, _actCompat.default)(() => { diff --git a/patches/react-dom-17+17.0.2.patch b/patches/react-dom-17+17.0.2.patch new file mode 100644 index 00000000000..fe8186b5fc3 --- /dev/null +++ b/patches/react-dom-17+17.0.2.patch @@ -0,0 +1,40 @@ +diff --git a/node_modules/react-dom-17/cjs/react-dom.development.js b/node_modules/react-dom-17/cjs/react-dom.development.js +index f0b9ee7..b02eb8e 100644 +--- a/node_modules/react-dom-17/cjs/react-dom.development.js ++++ b/node_modules/react-dom-17/cjs/react-dom.development.js +@@ -15728,7 +15728,7 @@ function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + function mountEffect(create, deps) { + { + // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests +- if ('undefined' !== typeof jest) { ++ if (globalThis.IS_REACT_ACT_ENVIRONMENT) { + warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); + } + } +@@ -15739,7 +15739,7 @@ function mountEffect(create, deps) { + function updateEffect(create, deps) { + { + // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests +- if ('undefined' !== typeof jest) { ++ if (globalThis.IS_REACT_ACT_ENVIRONMENT) { + warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber$1); + } + } +@@ -16130,7 +16130,7 @@ function dispatchAction(fiber, queue, action) { + + { + // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests +- if ('undefined' !== typeof jest) { ++ if (globalThis.IS_REACT_ACT_ENVIRONMENT) { + warnIfNotScopedWithMatchingAct(fiber); + warnIfNotCurrentlyActingUpdatesInDev(fiber); + } +@@ -25436,7 +25436,7 @@ function updateContainer(element, container, parentComponent, callback) { + + { + // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests +- if ('undefined' !== typeof jest) { ++ if (globalThis.IS_REACT_ACT_ENVIRONMENT) { + warnIfUnmockedScheduler(current$1); + warnIfNotScopedWithMatchingAct(current$1); + } diff --git a/patches/react-dom-19+19.0.0-rc-378b305958-20240710.patch b/patches/react-dom-19+19.0.0-rc-378b305958-20240710.patch deleted file mode 100644 index fc7597f276a..00000000000 --- a/patches/react-dom-19+19.0.0-rc-378b305958-20240710.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/node_modules/react-dom-19/cjs/react-dom-client.development.js b/node_modules/react-dom-19/cjs/react-dom-client.development.js -index f9ae214..c29f983 100644 ---- a/node_modules/react-dom-19/cjs/react-dom-client.development.js -+++ b/node_modules/react-dom-19/cjs/react-dom-client.development.js -@@ -14401,7 +14401,7 @@ - (lanes & RetryLanes) === lanes && - ((didTimeout = - globalMostRecentFallbackTime + -- FALLBACK_THROTTLE_MS - -+ (globalThis.REACT_FALLBACK_THROTTLE_MS || FALLBACK_THROTTLE_MS) - - now$1()), - 10 < didTimeout) - ) { -@@ -15599,7 +15599,7 @@ - (workInProgressRootExitStatus === RootSuspended && - (workInProgressRootRenderLanes & RetryLanes) === - workInProgressRootRenderLanes && -- now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) -+ now$1() - globalMostRecentFallbackTime < (globalThis.REACT_FALLBACK_THROTTLE_MS || FALLBACK_THROTTLE_MS)) - ? (executionContext & RenderContext) === NoContext && - prepareFreshStack(root, 0) - : (workInProgressRootPingedLanes |= pingedLanes)); -diff --git a/node_modules/react-dom-19/cjs/react-dom-client.production.js b/node_modules/react-dom-19/cjs/react-dom-client.production.js -index b93642c..66bb184 100644 ---- a/node_modules/react-dom-19/cjs/react-dom-client.production.js -+++ b/node_modules/react-dom-19/cjs/react-dom-client.production.js -@@ -10071,7 +10071,7 @@ function performConcurrentWorkOnRoot(root, didTimeout) { - } - if ( - (lanes & 62914560) === lanes && -- ((didTimeout = globalMostRecentFallbackTime + 300 - now()), -+ ((didTimeout = globalMostRecentFallbackTime + (globalThis.REACT_FALLBACK_THROTTLE_MS || 300) - now()), - 10 < didTimeout) - ) { - markRootSuspended( -@@ -10936,7 +10936,7 @@ function pingSuspendedRoot(root, wakeable, pingedLanes) { - (3 === workInProgressRootExitStatus && - (workInProgressRootRenderLanes & 62914560) === - workInProgressRootRenderLanes && -- 300 > now() - globalMostRecentFallbackTime) -+ (globalThis.REACT_FALLBACK_THROTTLE_MS || 300) > now() - globalMostRecentFallbackTime) - ? 0 === (executionContext & 2) && prepareFreshStack(root, 0) - : (workInProgressRootPingedLanes |= pingedLanes)); - ensureRootIsScheduled(root); -diff --git a/node_modules/react-dom-19/cjs/react-dom-profiling.development.js b/node_modules/react-dom-19/cjs/react-dom-profiling.development.js -index 9e4fe6a..a4bd41e 100644 ---- a/node_modules/react-dom-19/cjs/react-dom-profiling.development.js -+++ b/node_modules/react-dom-19/cjs/react-dom-profiling.development.js -@@ -14409,7 +14409,7 @@ - (lanes & RetryLanes) === lanes && - ((didTimeout = - globalMostRecentFallbackTime + -- FALLBACK_THROTTLE_MS - -+ (globalThis.REACT_FALLBACK_THROTTLE_MS || FALLBACK_THROTTLE_MS) - - now$1()), - 10 < didTimeout) - ) { -@@ -15611,7 +15611,7 @@ - (workInProgressRootExitStatus === RootSuspended && - (workInProgressRootRenderLanes & RetryLanes) === - workInProgressRootRenderLanes && -- now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) -+ now$1() - globalMostRecentFallbackTime < (globalThis.REACT_FALLBACK_THROTTLE_MS || FALLBACK_THROTTLE_MS)) - ? (executionContext & RenderContext) === NoContext && - prepareFreshStack(root, 0) - : (workInProgressRootPingedLanes |= pingedLanes)); -diff --git a/node_modules/react-dom-19/cjs/react-dom-profiling.profiling.js b/node_modules/react-dom-19/cjs/react-dom-profiling.profiling.js -index 683c9d9..000bb78 100644 ---- a/node_modules/react-dom-19/cjs/react-dom-profiling.profiling.js -+++ b/node_modules/react-dom-19/cjs/react-dom-profiling.profiling.js -@@ -10600,7 +10600,7 @@ function performConcurrentWorkOnRoot(root, didTimeout) { - } - if ( - (lanes & 62914560) === lanes && -- ((didTimeout = globalMostRecentFallbackTime + 300 - now$1()), -+ ((didTimeout = globalMostRecentFallbackTime + (globalThis.REACT_FALLBACK_THROTTLE_MS || 300) - now$1()), - 10 < didTimeout) - ) { - markRootSuspended( -@@ -11621,7 +11621,7 @@ function pingSuspendedRoot(root, wakeable, pingedLanes) { - (3 === workInProgressRootExitStatus && - (workInProgressRootRenderLanes & 62914560) === - workInProgressRootRenderLanes && -- 300 > now$1() - globalMostRecentFallbackTime) -+ (globalThis.REACT_FALLBACK_THROTTLE_MS || 300) > now$1() - globalMostRecentFallbackTime) - ? 0 === (executionContext & 2) && prepareFreshStack(root, 0) - : (workInProgressRootPingedLanes |= pingedLanes)); - ensureRootIsScheduled(root); diff --git a/src/config/jest/setup.ts b/src/config/jest/setup.ts index fcae6fde31b..141d0e4132d 100644 --- a/src/config/jest/setup.ts +++ b/src/config/jest/setup.ts @@ -36,6 +36,3 @@ if (!Symbol.asyncDispose) { // @ts-ignore expect.addEqualityTesters([areApolloErrorsEqual, areGraphQLErrorsEqual]); - -// @ts-ignore -globalThis.REACT_FALLBACK_THROTTLE_MS = 10; diff --git a/src/react/components/__tests__/client/Query.test.tsx b/src/react/components/__tests__/client/Query.test.tsx index 3d179dc037f..a97807838aa 100644 --- a/src/react/components/__tests__/client/Query.test.tsx +++ b/src/react/components/__tests__/client/Query.test.tsx @@ -11,7 +11,10 @@ import { ApolloProvider } from "../../../context"; import { itAsync, MockedProvider, mockSingleLink } from "../../../../testing"; import { Query } from "../../Query"; import { QueryResult } from "../../../types/types"; -import { renderToRenderStream } from "@testing-library/react-render-stream"; +import { + disableActEnvironment, + createRenderStream, +} from "@testing-library/react-render-stream"; const allPeopleQuery: DocumentNode = gql` query people { @@ -1500,7 +1503,10 @@ describe("Query component", () => { ); } - const { takeRender, replaceSnapshot } = renderToRenderStream( + using _disabledAct = disableActEnvironment(); + const { takeRender, replaceSnapshot, render } = + createRenderStream(); + await render( diff --git a/src/react/components/__tests__/client/Subscription.test.tsx b/src/react/components/__tests__/client/Subscription.test.tsx index cc95def897b..efe15db56c0 100644 --- a/src/react/components/__tests__/client/Subscription.test.tsx +++ b/src/react/components/__tests__/client/Subscription.test.tsx @@ -9,7 +9,10 @@ import { ApolloLink, DocumentNode, Operation } from "../../../../link/core"; import { itAsync, MockSubscriptionLink } from "../../../../testing"; import { Subscription } from "../../Subscription"; import { spyOnConsole } from "../../../../testing/internal"; -import { renderToRenderStream } from "@testing-library/react-render-stream"; +import { + disableActEnvironment, + createRenderStream, +} from "@testing-library/react-render-stream"; const results = [ "Luke Skywalker", @@ -435,13 +438,13 @@ describe("should update", () => { ); } - const { takeRender, replaceSnapshot, renderResultPromise } = - renderToRenderStream( - - - - ); - const { rerender } = await renderResultPromise; + using _disabledAct = disableActEnvironment(); + const { takeRender, replaceSnapshot, render } = createRenderStream(); + const { rerender } = await render( + + + + ); { const { snapshot: { loading, data }, @@ -462,7 +465,7 @@ describe("should update", () => { await expect(takeRender).not.toRerender({ timeout: 50 }); - rerender( + await rerender( @@ -531,13 +534,17 @@ describe("should update", () => { ); } - const { takeRender, replaceSnapshot, renderResultPromise } = - renderToRenderStream(, { + + using _disabledAct = disableActEnvironment(); + const { takeRender, replaceSnapshot, render } = createRenderStream(); + const { rerender } = await render( + , + { wrapper: ({ children }) => ( {children} ), - }); - const { rerender } = await renderResultPromise; + } + ); { const { @@ -558,7 +565,7 @@ describe("should update", () => { await expect(takeRender).not.toRerender({ timeout: 50 }); - rerender(); + await rerender(); { const { snapshot: { loading, data }, @@ -624,13 +631,13 @@ describe("should update", () => { ); } - const { takeRender, renderResultPromise, replaceSnapshot } = - renderToRenderStream(, { - wrapper: ({ children }) => ( - {children} - ), - }); - const { rerender } = await renderResultPromise; + using _disabledAct = disableActEnvironment(); + const { takeRender, render, replaceSnapshot } = createRenderStream(); + const { rerender } = await render(, { + wrapper: ({ children }) => ( + {children} + ), + }); { const { @@ -651,7 +658,7 @@ describe("should update", () => { await expect(takeRender).not.toRerender({ timeout: 50 }); - rerender(); + await rerender(); { const { diff --git a/src/react/hoc/__tests__/queries/lifecycle.test.tsx b/src/react/hoc/__tests__/queries/lifecycle.test.tsx index 5fcf588c856..76134ba081c 100644 --- a/src/react/hoc/__tests__/queries/lifecycle.test.tsx +++ b/src/react/hoc/__tests__/queries/lifecycle.test.tsx @@ -10,7 +10,10 @@ import { mockSingleLink } from "../../../../testing"; import { Query as QueryComponent } from "../../../components"; import { graphql } from "../../graphql"; import { ChildProps, DataValue } from "../../types"; -import { renderToRenderStream } from "@testing-library/react-render-stream"; +import { + disableActEnvironment, + createRenderStream, +} from "@testing-library/react-render-stream"; describe("[queries] lifecycle", () => { // lifecycle @@ -58,13 +61,14 @@ describe("[queries] lifecycle", () => { } ); - const { takeRender, replaceSnapshot, renderResultPromise } = - renderToRenderStream>(, { - wrapper: ({ children }) => ( - {children} - ), - }); - const { rerender } = await renderResultPromise; + using _disabledAct = disableActEnvironment(); + const { takeRender, replaceSnapshot, render } = + createRenderStream>(); + const { rerender } = await render(, { + wrapper: ({ children }) => ( + {children} + ), + }); { const { snapshot } = await takeRender(); @@ -79,7 +83,7 @@ describe("[queries] lifecycle", () => { expect(snapshot!.allPeople).toEqual(data1.allPeople); } - rerender(); + await rerender(); { const { snapshot } = await takeRender(); @@ -393,7 +397,7 @@ describe("[queries] lifecycle", () => { expect(props.foo).toEqual(43); expect(props.data!.loading).toEqual(false); expect(props.data!.allPeople).toEqual(data1.allPeople); - props.data!.refetch(); + void props.data!.refetch(); } else if (count === 3) { expect(props.foo).toEqual(43); expect(props.data!.loading).toEqual(false); @@ -755,7 +759,7 @@ describe("[queries] lifecycle", () => { const Container = graphql(query)( class extends React.Component> { componentDidMount() { - this.props.data!.refetch().then((result) => { + void this.props.data!.refetch().then((result) => { expect(result.data!.user.name).toBe("Luke Skywalker"); done = true; }); diff --git a/src/react/hoc/__tests__/queries/loading.test.tsx b/src/react/hoc/__tests__/queries/loading.test.tsx index 5054d9ebb52..a59cc050d69 100644 --- a/src/react/hoc/__tests__/queries/loading.test.tsx +++ b/src/react/hoc/__tests__/queries/loading.test.tsx @@ -13,7 +13,10 @@ import { InMemoryCache as Cache } from "../../../../cache"; import { itAsync, mockSingleLink } from "../../../../testing"; import { graphql } from "../../graphql"; import { ChildProps, DataValue } from "../../types"; -import { createRenderStream } from "@testing-library/react-render-stream"; +import { + createRenderStream, + disableActEnvironment, +} from "@testing-library/react-render-stream"; describe("[queries] loading", () => { // networkStatus / loading @@ -322,7 +325,7 @@ describe("[queries] loading", () => { expect(data!.networkStatus).toBe(7); // this isn't reloading fully setTimeout(() => { - data!.refetch(); + void data!.refetch(); }); break; case 1: @@ -417,6 +420,7 @@ describe("[queries] loading", () => { {children} ); + using _disabledAct = disableActEnvironment(); const { takeRender, replaceSnapshot, render } = createRenderStream< DataValue<{ allPeople: { @@ -427,7 +431,7 @@ describe("[queries] loading", () => { }> >(); - render(, { + await render(, { wrapper, }); @@ -441,7 +445,7 @@ describe("[queries] loading", () => { expect(snapshot.loading).toBe(false); expect(snapshot.allPeople?.people[0].name).toMatch(/Darth Skywalker - /); } - render(, { + await render(, { wrapper, }); // Loading after remount diff --git a/src/react/hooks/__tests__/useBackgroundQuery.test.tsx b/src/react/hooks/__tests__/useBackgroundQuery.test.tsx index 84b16b813c8..3ef60a4b0df 100644 --- a/src/react/hooks/__tests__/useBackgroundQuery.test.tsx +++ b/src/react/hooks/__tests__/useBackgroundQuery.test.tsx @@ -55,6 +55,7 @@ import { setupSimpleCase, setupVariablesCase, spyOnConsole, + addDelayToMocks, } from "../../../testing/internal"; import { SubscribeToMoreFunction } from "../useSuspenseQuery"; import { @@ -66,6 +67,7 @@ import { Masked, MaskedDocumentNode } from "../../../masking"; import { RenderStream, createRenderStream, + disableActEnvironment, useTrackRenders, } from "@testing-library/react-render-stream"; @@ -153,7 +155,8 @@ it("fetches a simple query with minimal config", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -196,7 +199,8 @@ it("tears down the query on unmount", async () => { ); } - const { unmount } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { unmount } = await renderStream.render(, { wrapper: createClientWrapper(client), }); @@ -322,7 +326,8 @@ it("will resubscribe after disposed when mounting useReadQuery", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); expect(client.getObservableQueries().size).toBe(1); expect(client).toHaveSuspenseCacheEntryUsing(query); @@ -339,7 +344,7 @@ it("will resubscribe after disposed when mounting useReadQuery", async () => { expect(client.getObservableQueries().size).toBe(0); expect(client).not.toHaveSuspenseCacheEntryUsing(query); - await act(() => user.click(screen.getByText("Toggle"))); + await user.click(screen.getByText("Toggle")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -398,7 +403,8 @@ it("auto resubscribes when mounting useReadQuery after naturally disposed by use ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); const toggleButton = screen.getByText("Toggle"); @@ -421,7 +427,7 @@ it("auto resubscribes when mounting useReadQuery after naturally disposed by use }); } - await act(() => user.click(toggleButton)); + await user.click(toggleButton); await renderStream.takeRender(); await wait(0); @@ -431,7 +437,7 @@ it("auto resubscribes when mounting useReadQuery after naturally disposed by use // again. expect(client).toHaveSuspenseCacheEntryUsing(query); - await act(() => user.click(toggleButton)); + await user.click(toggleButton); expect(client.getObservableQueries().size).toBe(1); expect(client).toHaveSuspenseCacheEntryUsing(query); @@ -505,7 +511,8 @@ it("does not recreate queryRef and execute a network request when rerendering us ); } - const { rerender } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { wrapper: createClientWrapper(client), }); @@ -527,16 +534,16 @@ it("does not recreate queryRef and execute a network request when rerendering us }); } - await act(() => user.click(toggleButton)); + await user.click(toggleButton); await renderStream.takeRender(); await wait(0); - rerender(); + await rerender(); await renderStream.takeRender(); expect(fetchCount).toBe(1); - await act(() => user.click(toggleButton)); + await user.click(toggleButton); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -603,7 +610,8 @@ it("does not recreate queryRef or execute a network request when rerendering use ); } - renderStream.render(, { + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client, React.StrictMode), }); @@ -619,7 +627,7 @@ it("does not recreate queryRef or execute a network request when rerendering use const firstRender = await renderStream.takeRender(); const initialQueryRef = firstRender.snapshot.queryRef; - await act(() => user.click(incrementButton)); + await user.click(incrementButton); { const { snapshot } = await renderStream.takeRender(); @@ -647,7 +655,8 @@ it("disposes of the queryRef when unmounting before it is used by useReadQuery", return null; } - const { unmount } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { unmount } = await renderStream.render(, { wrapper: createClientWrapper(client), }); @@ -683,7 +692,8 @@ it("disposes of old queryRefs when changing variables before the queryRef is use return null; } - const { rerender } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { wrapper: createClientWrapper(client), }); @@ -698,9 +708,9 @@ it("disposes of old queryRefs when changing variables before the queryRef is use expect(renderedComponents).toStrictEqual([App]); } - rerender(); + await rerender(); - await wait(0); + await wait(10); expect(client.getObservableQueries().size).toBe(1); expect(client).toHaveSuspenseCacheEntryUsing(query, { @@ -727,7 +737,8 @@ it("does not prematurely dispose of the queryRef when using strict mode", async return null; } - renderStream.render(, { + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client, React.StrictMode), }); @@ -766,12 +777,13 @@ it("disposes of the queryRef when unmounting before it is used by useReadQuery e ); } - const { unmount } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { unmount } = await renderStream.render(, { wrapper: createClientWrapper(client), }); const button = screen.getByText("Increment"); - await act(() => user.click(button)); + await user.click(button); { const { renderedComponents } = await renderStream.takeRender(); @@ -822,7 +834,10 @@ it("allows the client to be overridden", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(globalClient) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createClientWrapper(globalClient), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -878,7 +893,8 @@ it("passes context to the link", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ link }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ link }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -950,7 +966,8 @@ it('enables canonical results when canonizeResults is "true"', async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ cache }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ cache }) }); const { snapshot: { result }, @@ -1019,7 +1036,8 @@ it("can disable canonical results when the cache's canonizeResults setting is tr ); } - renderStream.render(, { wrapper: createMockWrapper({ cache }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ cache }) }); const { snapshot } = await renderStream.takeRender(); const result = snapshot.result!; @@ -1064,7 +1082,8 @@ it("returns initial cache data followed by network data when the fetch policy is ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -1128,7 +1147,8 @@ it("all data is present in the cache, no network request is made", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -1185,7 +1205,8 @@ it("partial data is present in the cache so it is ignored and network request is ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1237,7 +1258,8 @@ it("existing data in the cache is ignored when fetchPolicy is 'network-only'", a ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1291,7 +1313,8 @@ it("fetches data from the network but does not update the cache when fetchPolicy ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1405,7 +1428,8 @@ it("works with startTransition to change variables", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1427,7 +1451,7 @@ it("works with startTransition to change variables", async () => { }); } - await act(() => user.click(screen.getByText("Change todo"))); + await user.click(screen.getByText("Change todo")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -1522,7 +1546,8 @@ it('does not suspend deferred queries with data in the cache and using a "cache- ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -1626,7 +1651,8 @@ it("reacts to cache updates", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1698,8 +1724,11 @@ it("reacts to variables updates", async () => { ); } - const { rerender } = renderStream.render(, { - wrapper: createMockWrapper({ mocks }), + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { + wrapper: createMockWrapper({ + mocks: addDelayToMocks(mocks, 150, true), + }), }); { @@ -1720,7 +1749,7 @@ it("reacts to variables updates", async () => { }); } - rerender(); + await rerender(); { const { renderedComponents } = await renderStream.takeRender(); @@ -1761,7 +1790,8 @@ it("does not suspend when `skip` is true", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); const { renderedComponents } = await renderStream.takeRender(); @@ -1788,7 +1818,8 @@ it("does not suspend when using `skipToken` in options", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); const { renderedComponents } = await renderStream.takeRender(); @@ -1820,7 +1851,8 @@ it("suspends when `skip` becomes `false` after it was `true`", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1828,7 +1860,7 @@ it("suspends when `skip` becomes `false` after it was `true`", async () => { expect(renderedComponents).toStrictEqual([App]); } - await act(() => user.click(screen.getByText("Run query"))); + await user.click(screen.getByText("Run query")); { const { renderedComponents } = await renderStream.takeRender(); @@ -1872,7 +1904,8 @@ it("suspends when switching away from `skipToken` in options", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1880,7 +1913,7 @@ it("suspends when switching away from `skipToken` in options", async () => { expect(renderedComponents).toStrictEqual([App]); } - await act(() => user.click(screen.getByText("Run query"))); + await user.click(screen.getByText("Run query")); { const { renderedComponents } = await renderStream.takeRender(); @@ -1924,7 +1957,8 @@ it("renders skip result, does not suspend, and maintains `data` when `skip` beco ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1942,7 +1976,7 @@ it("renders skip result, does not suspend, and maintains `data` when `skip` beco }); } - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -1980,7 +2014,8 @@ it("renders skip result, does not suspend, and maintains `data` when switching b ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -1998,7 +2033,7 @@ it("renders skip result, does not suspend, and maintains `data` when switching b }); } - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -2061,14 +2096,15 @@ it("does not make network requests when `skip` is `true`", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial skipped result await renderStream.takeRender(); expect(fetchCount).toBe(0); // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); expect(fetchCount).toBe(1); { @@ -2088,7 +2124,7 @@ it("does not make network requests when `skip` is `true`", async () => { } // Toggle skip to `true` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); expect(fetchCount).toBe(1); { @@ -2148,14 +2184,15 @@ it("does not make network requests when `skipToken` is used", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial skipped result await renderStream.takeRender(); expect(fetchCount).toBe(0); // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); expect(fetchCount).toBe(1); { @@ -2175,7 +2212,7 @@ it("does not make network requests when `skipToken` is used", async () => { } // Toggle skip to `true` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); expect(fetchCount).toBe(1); { @@ -2235,7 +2272,8 @@ it("does not make network requests when `skipToken` is used in strict mode", asy ); } - renderStream.render(, { + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client, React.StrictMode), }); @@ -2244,7 +2282,7 @@ it("does not make network requests when `skipToken` is used in strict mode", asy expect(fetchCount).toBe(0); // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); await renderStream.takeRender(); { @@ -2260,7 +2298,7 @@ it("does not make network requests when `skipToken` is used in strict mode", asy expect(fetchCount).toBe(1); // Toggle skip to `true` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot } = await renderStream.takeRender(); @@ -2323,7 +2361,8 @@ it("does not make network requests when using `skip` option in strict mode", asy ); } - renderStream.render(, { + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client, React.StrictMode), }); @@ -2332,7 +2371,7 @@ it("does not make network requests when using `skip` option in strict mode", asy expect(fetchCount).toBe(0); // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); await renderStream.takeRender(); { @@ -2348,7 +2387,7 @@ it("does not make network requests when using `skip` option in strict mode", asy expect(fetchCount).toBe(1); // Toggle skip to `true` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot } = await renderStream.takeRender(); @@ -2385,7 +2424,8 @@ it("result is referentially stable", async () => { ); } - const { rerender } = renderStream.render(, { + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { wrapper: createMockWrapper({ mocks }), }); @@ -2407,7 +2447,7 @@ it("result is referentially stable", async () => { result = snapshot.result; } - rerender(); + await rerender(); { const { snapshot } = await renderStream.takeRender(); @@ -2456,7 +2496,8 @@ it("`skip` option works with `startTransition`", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -2465,7 +2506,7 @@ it("`skip` option works with `startTransition`", async () => { } // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -2535,7 +2576,8 @@ it("`skipToken` works with `startTransition`", async () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -2544,7 +2586,7 @@ it("`skipToken` works with `startTransition`", async () => { } // Toggle skip to `false` - await act(() => user.click(screen.getByText("Toggle skip"))); + await user.click(screen.getByText("Toggle skip")); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -2619,7 +2661,8 @@ it("applies `errorPolicy` on next fetch when it changes between renders", async ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); // initial render await renderStream.takeRender(); @@ -2634,10 +2677,10 @@ it("applies `errorPolicy` on next fetch when it changes between renders", async }); } - await act(() => user.click(screen.getByText("Change error policy"))); + await user.click(screen.getByText("Change error policy")); await renderStream.takeRender(); - await act(() => user.click(screen.getByText("Refetch greeting"))); + await user.click(screen.getByText("Refetch greeting")); await renderStream.takeRender(); { @@ -2702,7 +2745,8 @@ it("applies `context` on next fetch when it changes between renders", async () = ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -2720,10 +2764,10 @@ it("applies `context` on next fetch when it changes between renders", async () = }); } - await act(() => user.click(screen.getByText("Update context"))); + await user.click(screen.getByText("Update context")); await renderStream.takeRender(); - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -2805,7 +2849,8 @@ it("returns canonical results immediately when `canonizeResults` changes from `f ); } - renderStream.render(, { wrapper: createMockWrapper({ cache }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createMockWrapper({ cache }) }); { const { snapshot } = await renderStream.takeRender(); @@ -2819,7 +2864,7 @@ it("returns canonical results immediately when `canonizeResults` changes from `f expect(values).toEqual([0, 1, 1, 2, 3, 5]); } - await act(() => user.click(screen.getByText("Canonize results"))); + await user.click(screen.getByText("Canonize results")); { const { snapshot } = await renderStream.takeRender(); @@ -2920,7 +2965,8 @@ it("applies changed `refetchWritePolicy` to next fetch when changing between ren ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial suspended render await renderStream.takeRender(); @@ -2936,7 +2982,7 @@ it("applies changed `refetchWritePolicy` to next fetch when changing between ren expect(mergeParams).toEqual([[undefined, [2, 3, 5, 7, 11]]]); } - await act(() => user.click(screen.getByText("Refetch next"))); + await user.click(screen.getByText("Refetch next")); await renderStream.takeRender(); { @@ -2956,10 +3002,10 @@ it("applies changed `refetchWritePolicy` to next fetch when changing between ren ]); } - await act(() => user.click(screen.getByText("Change refetch write policy"))); + await user.click(screen.getByText("Change refetch write policy")); await renderStream.takeRender(); - await act(() => user.click(screen.getByText("Refetch last"))); + await user.click(screen.getByText("Refetch last")); await renderStream.takeRender(); { @@ -3064,7 +3110,8 @@ it("applies `returnPartialData` on next fetch when it changes between renders", ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial suspended render await renderStream.takeRender(); @@ -3081,7 +3128,7 @@ it("applies `returnPartialData` on next fetch when it changes between renders", }); } - await act(() => user.click(screen.getByText("Update partial data"))); + await user.click(screen.getByText("Update partial data")); await renderStream.takeRender(); cache.modify({ @@ -3167,7 +3214,8 @@ it("applies updated `fetchPolicy` on next fetch when it changes between renders" ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot } = await renderStream.takeRender(); @@ -3185,7 +3233,7 @@ it("applies updated `fetchPolicy` on next fetch when it changes between renders" }); } - await act(() => user.click(screen.getByText("Change fetch policy"))); + await user.click(screen.getByText("Change fetch policy")); { const { snapshot } = await renderStream.takeRender(); @@ -3203,7 +3251,7 @@ it("applies updated `fetchPolicy` on next fetch when it changes between renders" }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -3304,7 +3352,8 @@ it("properly handles changing options along with changing `variables`", async () ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot } = await renderStream.takeRender(); @@ -3325,7 +3374,7 @@ it("properly handles changing options along with changing `variables`", async () }); } - await act(() => user.click(screen.getByText("Get second character"))); + await user.click(screen.getByText("Get second character")); await renderStream.takeRender(); { @@ -3347,7 +3396,7 @@ it("properly handles changing options along with changing `variables`", async () }); } - await act(() => user.click(screen.getByText("Get first character"))); + await user.click(screen.getByText("Get first character")); { const { snapshot } = await renderStream.takeRender(); @@ -3368,7 +3417,7 @@ it("properly handles changing options along with changing `variables`", async () }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -3433,7 +3482,8 @@ it('does not suspend when partial data is in the cache and using a "cache-first" ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -3499,8 +3549,12 @@ it('suspends and does not use partial data from other variables in the cache whe ); } - const { rerender } = renderStream.render(, { - wrapper: createMockWrapper({ cache, mocks }), + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { + wrapper: createMockWrapper({ + cache, + mocks: addDelayToMocks(mocks, 150, true), + }), }); { @@ -3527,7 +3581,7 @@ it('suspends and does not use partial data from other variables in the cache whe }); } - rerender(); + await rerender(); { const { renderedComponents } = await renderStream.takeRender(); @@ -3594,7 +3648,8 @@ it('suspends when partial data is in the cache and using a "network-only" fetch ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -3661,7 +3716,8 @@ it('suspends when partial data is in the cache and using a "no-cache" fetch poli ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -3761,7 +3817,8 @@ it('does not suspend when partial data is in the cache and using a "cache-and-ne ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -3827,8 +3884,12 @@ it('suspends and does not use partial data when changing variables and using a " ); } - const { rerender } = renderStream.render(, { - wrapper: createMockWrapper({ cache, mocks }), + using _disabledAct = disableActEnvironment(); + const { rerender } = await renderStream.render(, { + wrapper: createMockWrapper({ + cache, + mocks: addDelayToMocks(mocks, 150, true), + }), }); { @@ -3855,7 +3916,7 @@ it('suspends and does not use partial data when changing variables and using a " }); } - rerender(); + await rerender(); { const { renderedComponents } = await renderStream.takeRender(); @@ -3942,7 +4003,8 @@ it('does not suspend deferred queries with partial data in the cache and using a ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -4053,7 +4115,8 @@ it.each([ ); } - renderStream.render(, { + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { wrapper: createClientWrapper(client, React.StrictMode), }); @@ -5033,7 +5096,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5057,7 +5123,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { // parent component re-suspends @@ -5108,7 +5174,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5132,7 +5201,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5212,7 +5281,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5234,7 +5306,7 @@ describe("refetch", () => { const button = screen.getByText("Refetch"); - await act(() => user.click(button)); + await user.click(button); { const { renderedComponents } = await renderStream.takeRender(); @@ -5258,7 +5330,7 @@ describe("refetch", () => { }); } - await act(() => user.click(button)); + await user.click(button); { const { renderedComponents } = await renderStream.takeRender(); @@ -5323,7 +5395,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5350,7 +5425,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5410,7 +5485,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5437,7 +5515,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5505,7 +5583,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5532,7 +5613,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5603,7 +5684,10 @@ describe("refetch", () => { ); } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5630,7 +5714,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5740,7 +5824,10 @@ describe("refetch", () => { return null; } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5762,7 +5849,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Retry"))); + await user.click(screen.getByText("Retry")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5870,7 +5957,10 @@ describe("refetch", () => { return null; } - renderStream.render(, { wrapper: createMockWrapper({ mocks }) }); + using _disabledAct = disableActEnvironment(); + await renderStream.render(, { + wrapper: createMockWrapper({ mocks }), + }); { const { renderedComponents } = await renderStream.takeRender(); @@ -5890,7 +5980,7 @@ describe("refetch", () => { }); } - await act(() => user.click(screen.getByText("Retry"))); + await user.click(screen.getByText("Retry")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5977,7 +6067,7 @@ describe("refetch", () => { ; } - const { user } = renderWithMocks( + await renderWithMocks( (error = e)} fallback={
Oops
}>
, - { mocks } + { mocks }, + { render: renderAsync } ); + const user = userEvent.setup(); await act(() => user.click(screen.getByText("Load query in render"))); @@ -4904,7 +4957,9 @@ it("allows loadQuery to be called in useEffect on first render", async () => { return null; } - expect(() => renderWithMocks(, { mocks })).not.toThrow(); + await expect( + renderWithMocks(, { mocks }, { render: renderAsync }) + ).resolves.not.toThrow(); }); it("can subscribe to subscriptions and react to cache updates via `subscribeToMore`", async () => { @@ -4949,6 +5004,7 @@ it("can subscribe to subscriptions and react to cache updates via `subscribeToMo const client = new ApolloClient({ link, cache: new InMemoryCache() }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { subscribeToMore: null as SubscribeToMoreFunction< @@ -4978,7 +5034,7 @@ it("can subscribe to subscriptions and react to cache updates via `subscribeToMo ); } - const { user } = renderWithClient( + const { user } = await renderWithClient( , { client, @@ -4988,7 +5044,7 @@ it("can subscribe to subscriptions and react to cache updates via `subscribeToMo // initial render await renderStream.takeRender(); - await act(() => user.click(screen.getByText("Load query"))); + await user.click(screen.getByText("Load query")); { const { renderedComponents } = await renderStream.takeRender(); @@ -5083,6 +5139,7 @@ it("throws when calling `subscribeToMore` before loading the query", async () => const client = new ApolloClient({ link, cache: new InMemoryCache() }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { subscribeToMore: null as SubscribeToMoreFunction< @@ -5112,7 +5169,7 @@ it("throws when calling `subscribeToMore` before loading the query", async () => ); } - renderWithClient(, { client }, renderStream); + await renderWithClient(, { client }, renderStream); // initial render await renderStream.takeRender(); diff --git a/src/react/hooks/__tests__/useMutation.test.tsx b/src/react/hooks/__tests__/useMutation.test.tsx index c4098cc571a..d9216c6a8cb 100644 --- a/src/react/hooks/__tests__/useMutation.test.tsx +++ b/src/react/hooks/__tests__/useMutation.test.tsx @@ -35,7 +35,10 @@ import { FetchResult } from "../../../link/core"; import { spyOnConsole } from "../../../testing/internal"; import { expectTypeOf } from "expect-type"; import { Masked } from "../../../masking"; -import { renderHookToSnapshotStream } from "@testing-library/react-render-stream"; +import { + disableActEnvironment, + renderHookToSnapshotStream, +} from "@testing-library/react-render-stream"; describe("useMutation Hook", () => { interface Todo { @@ -122,7 +125,7 @@ describe("useMutation Hook", () => { const [createTodo, { loading, data }] = useMutation(CREATE_TODO_MUTATION); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, [variables]); return { loading, data }; @@ -754,7 +757,8 @@ describe("useMutation Hook", () => { }, ]; - const { takeSnapshot } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useMutation< { createTodo: Todo }, @@ -780,11 +784,8 @@ describe("useMutation Hook", () => { expect(result.called).toBe(false); } - let fetchResult: any; - act(() => { - fetchResult = createTodo({ - variables: { priority: "Low", description: "Get milk." }, - }); + let fetchResult = createTodo({ + variables: { priority: "Low", description: "Get milk." }, }); { @@ -795,7 +796,7 @@ describe("useMutation Hook", () => { expect(result.called).toBe(true); } - act(() => reset()); + reset(); { const [, result] = await takeSnapshot(); @@ -1482,7 +1483,7 @@ describe("useMutation Hook", () => { }); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, []); return null; @@ -1529,7 +1530,7 @@ describe("useMutation Hook", () => { }); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, []); return null; @@ -1572,7 +1573,7 @@ describe("useMutation Hook", () => { }); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, []); return null; @@ -1637,7 +1638,7 @@ describe("useMutation Hook", () => { case 0: expect(loading).toBeFalsy(); expect(data).toBeUndefined(); - createTodo({ variables }); + void createTodo({ variables }); const dataInStore = client.cache.extract(true); expect(dataInStore["Todo:1"]).toEqual( @@ -1710,7 +1711,7 @@ describe("useMutation Hook", () => { }); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, []); return null; @@ -1888,7 +1889,7 @@ describe("useMutation Hook", () => { expect(result.current.mutation[1].data).toBe(undefined); const createTodo = result.current.mutation[0]; act(() => { - createTodo({ + void createTodo({ variables, async onQueryUpdated(obsQuery, diff) { const result = await obsQuery.reobserve(); @@ -1984,8 +1985,8 @@ describe("useMutation Hook", () => { expect(result.current.query.data).toEqual(mocks[0].result.data); const mutate = result.current.mutation[0]; - act(() => { - mutate({ + await act(async () => { + await mutate({ variables, refetchQueries: ["getTodos"], }); @@ -2149,24 +2150,21 @@ describe("useMutation Hook", () => { (resolve) => (onMutationDone = resolve) ); - setTimeout(() => { - act(() => { - mutate({ - variables, - refetchQueries: ["getTodos"], - update() { - unmount(); - }, - }).then((result) => { - expect(result.data).toEqual(CREATE_TODO_RESULT); - onMutationDone(); - }); - }); - }); - expect(result.current.query.loading).toBe(false); expect(result.current.query.data).toEqual(mocks[0].result.data); + await act(async () => { + await mutate({ + variables, + refetchQueries: ["getTodos"], + update() { + unmount(); + }, + }).then((result) => { + expect(result.data).toEqual(CREATE_TODO_RESULT); + onMutationDone(); + }); + }); await mutatePromise; await waitFor(() => { @@ -2598,7 +2596,7 @@ describe("useMutation Hook", () => { ); useEffect(() => { - createTodo({ variables }); + void createTodo({ variables }); }, [variables]); return { loading, data }; diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 003f1899f0c..f38e6dff465 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -7,7 +7,6 @@ import { render, screen, waitFor, renderHook } from "@testing-library/react"; import { ApolloClient, ApolloError, - ApolloQueryResult, FetchPolicy, NetworkStatus, OperationVariables, @@ -31,12 +30,7 @@ import { import { QueryResult } from "../../types/types"; import { useQuery } from "../useQuery"; import { useMutation } from "../useMutation"; -import { - disableActWarnings, - PaginatedCaseData, - setupPaginatedCase, - spyOnConsole, -} from "../../../testing/internal"; +import { setupPaginatedCase, spyOnConsole } from "../../../testing/internal"; import { useApolloClient } from "../useApolloClient"; import { useLazyQuery } from "../useLazyQuery"; import { mockFetchQuery } from "../../../core/__tests__/ObservableQuery"; @@ -45,6 +39,7 @@ import { Masked, MaskedDocumentNode } from "../../../masking"; import { createRenderStream, renderHookToSnapshotStream, + disableActEnvironment, } from "@testing-library/react-render-stream"; const IS_REACT_17 = React.version.startsWith("17"); @@ -600,7 +595,7 @@ describe("useQuery Hook", () => { const mutate = result.current[1][0]; act(() => { - mutate({ variables: { name: "world 2" } }); + void mutate({ variables: { name: "world 2" } }); setName("world 2"); }); @@ -794,7 +789,8 @@ describe("useQuery Hook", () => { link, cache: new InMemoryCache(), }); - const { takeSnapshot, rerender } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( () => [useQuery(query1, { fetchPolicy: "no-cache" }), useQuery(query2)], { wrapper: ({ children }) => ( @@ -827,7 +823,7 @@ describe("useQuery Hook", () => { expect(result1.data).toStrictEqual(allThingsData); } - rerender({}); + await rerender({}); { const [result0, result1] = await takeSnapshot(); expect(result0.loading).toBe(false); @@ -1570,14 +1566,16 @@ describe("useQuery Hook", () => { checkObservableQueries(1); - await result.current.reobserve().then((result) => { - expect(result.loading).toBe(false); - expect(result.loading).toBe(false); - expect(result.networkStatus).toBe(NetworkStatus.ready); - expect(result.data).toEqual({ - linkCount: 2, - }); - }); + await act(() => + result.current.reobserve().then((result) => { + expect(result.loading).toBe(false); + expect(result.loading).toBe(false); + expect(result.networkStatus).toBe(NetworkStatus.ready); + expect(result.data).toEqual({ + linkCount: 2, + }); + }) + ); await waitFor(() => { expect(result.current.loading).toBe(false); @@ -1699,7 +1697,8 @@ describe("useQuery Hook", () => { ]; const cache = new InMemoryCache(); - const { takeSnapshot, rerender } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( ({ skip }: { skip?: boolean }) => useQuery(query, { pollInterval: 10, skip }), { @@ -1722,7 +1721,7 @@ describe("useQuery Hook", () => { expect(result.data).toEqual({ hello: "world 1" }); } - rerender({ skip: true }); + await rerender({ skip: true }); { const snapshot = await takeSnapshot(); expect(snapshot.loading).toBe(false); @@ -1731,7 +1730,7 @@ describe("useQuery Hook", () => { await expect(takeSnapshot).not.toRerender({ timeout: 100 }); - rerender({ skip: false }); + await rerender({ skip: false }); { const result = await takeSnapshot(); expect(result.loading).toBe(false); @@ -1831,7 +1830,8 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot, unmount } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, unmount } = await renderHookToSnapshotStream( () => useQuery(query, { pollInterval: 20 }), { wrapper } ); @@ -1913,7 +1913,8 @@ describe("useQuery Hook", () => { cache, }); - const { takeSnapshot, unmount } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, unmount } = await renderHookToSnapshotStream( () => useQuery(query, { pollInterval: 10, @@ -2069,7 +2070,8 @@ describe("useQuery Hook", () => { const client = new ApolloClient({ link, cache }); - const { takeSnapshot, unmount } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, unmount } = await renderHookToSnapshotStream( () => useQuery(query, { pollInterval: 10, @@ -3058,7 +3060,7 @@ describe("useQuery Hook", () => { await new Promise((resolve) => setTimeout(resolve)); expect(onError).toHaveBeenCalledTimes(1); - result.current.refetch(); + await act(async () => void result.current.refetch()); await waitFor( () => { expect(result.current.loading).toBe(true); @@ -3551,10 +3553,12 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => useQuery(query, { notifyOnNetworkStatusChange: true }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { notifyOnNetworkStatusChange: true }), + { wrapper } + ); { const result = await takeSnapshot(); @@ -3694,10 +3698,12 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => useQuery(query, { notifyOnNetworkStatusChange: true }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { notifyOnNetworkStatusChange: true }), + { wrapper } + ); { const result = await takeSnapshot(); @@ -3712,7 +3718,7 @@ describe("useQuery Hook", () => { expect(result.error).toBeInstanceOf(ApolloError); expect(result.error!.message).toBe("same error"); } - getCurrentSnapshot().refetch(); + await getCurrentSnapshot().refetch(); { const result = await takeSnapshot(); @@ -3997,7 +4003,9 @@ describe("useQuery Hook", () => { ); expect(result.current.networkStatus).toBe(NetworkStatus.ready); expect(result.current.data).toEqual({ letters: ab }); - result.current.fetchMore({ variables: { limit: 2 } }); + await act( + async () => void result.current.fetchMore({ variables: { limit: 2 } }) + ); expect(result.current.loading).toBe(false); await waitFor( @@ -4084,15 +4092,20 @@ describe("useQuery Hook", () => { const client = new ApolloClient({ cache: new InMemoryCache(), link }); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { fetchPolicy: "no-cache", variables: { limit: 2 } }), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + fetchPolicy: "no-cache", + variables: { limit: 2 }, + }), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); // loading await takeSnapshot(); @@ -4103,12 +4116,10 @@ describe("useQuery Hook", () => { const { fetchMore } = getCurrentSnapshot(); - await act(() => - fetchMore({ - variables: { offset: 2 }, - updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, - }) - ); + await fetchMore({ + variables: { offset: 2 }, + updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, + }); expect(fetches).toStrictEqual([ { variables: { limit: 2 } }, @@ -4121,19 +4132,21 @@ describe("useQuery Hook", () => { const client = new ApolloClient({ cache: new InMemoryCache(), link }); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { - notifyOnNetworkStatusChange: true, - fetchPolicy: "no-cache", - variables: { limit: 2 }, - }), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + notifyOnNetworkStatusChange: true, + fetchPolicy: "no-cache", + variables: { limit: 2 }, + }), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); { const { loading, networkStatus, data } = await takeSnapshot(); @@ -4156,16 +4169,13 @@ describe("useQuery Hook", () => { }); } - let fetchMorePromise!: Promise>; const { fetchMore } = getCurrentSnapshot(); - act(() => { - fetchMorePromise = fetchMore({ - variables: { offset: 2 }, - updateQuery: (prev, { fetchMoreResult }) => ({ - letters: prev.letters.concat(fetchMoreResult.letters), - }), - }); + let fetchMorePromise = fetchMore({ + variables: { offset: 2 }, + updateQuery: (prev, { fetchMoreResult }) => ({ + letters: prev.letters.concat(fetchMoreResult.letters), + }), }); { @@ -4220,11 +4230,9 @@ describe("useQuery Hook", () => { await expect(takeSnapshot).not.toRerender(); - act(() => { - fetchMorePromise = fetchMore({ - variables: { offset: 4 }, - updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, - }); + fetchMorePromise = fetchMore({ + variables: { offset: 4 }, + updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, }); { @@ -4282,15 +4290,20 @@ describe("useQuery Hook", () => { const client = new ApolloClient({ cache: new InMemoryCache(), link }); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { fetchPolicy: "no-cache", variables: { limit: 2 } }), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + fetchPolicy: "no-cache", + variables: { limit: 2 }, + }), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); // loading await takeSnapshot(); @@ -4323,15 +4336,20 @@ describe("useQuery Hook", () => { const client = new ApolloClient({ cache: new InMemoryCache(), link }); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { fetchPolicy: "no-cache", variables: { limit: 2 } }), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + fetchPolicy: "no-cache", + variables: { limit: 2 }, + }), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); // initial loading await takeSnapshot(); @@ -4340,12 +4358,10 @@ describe("useQuery Hook", () => { await takeSnapshot(); const { fetchMore } = getCurrentSnapshot(); - await act(() => - fetchMore({ - variables: { offset: 2 }, - updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, - }) - ); + await fetchMore({ + variables: { offset: 2 }, + updateQuery: (_, { fetchMoreResult }) => fetchMoreResult, + }); expect(client.extract()).toStrictEqual({}); }); @@ -4489,6 +4505,7 @@ describe("useQuery Hook", () => { } `; + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useQueryResult: null as QueryResult | null, @@ -4539,7 +4556,7 @@ describe("useQuery Hook", () => { // Intentionally use reobserve here as opposed to refetch to // ensure we check against reported cache results with cache-first // and notifyOnNetworkStatusChange - useQueryResult.observable.reobserve(); + void useQueryResult.observable.reobserve(); }} > Reload 1st query @@ -4548,7 +4565,7 @@ describe("useQuery Hook", () => { ); } - renderStream.render(, { + await renderStream.render(, { wrapper: ({ children }) => ( {children} ), @@ -4591,7 +4608,7 @@ describe("useQuery Hook", () => { }); } - await act(() => user.click(screen.getByText("Run 2nd query"))); + await user.click(screen.getByText("Run 2nd query")); { const { snapshot } = await renderStream.takeRender(); @@ -4648,7 +4665,7 @@ describe("useQuery Hook", () => { }); } - await act(() => user.click(screen.getByText("Reload 1st query"))); + await user.click(screen.getByText("Reload 1st query")); { const { snapshot } = await renderStream.takeRender(); @@ -4748,6 +4765,7 @@ describe("useQuery Hook", () => { } `; + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useQueryResult: null as QueryResult | null, @@ -4799,7 +4817,7 @@ describe("useQuery Hook", () => { return ; } - renderStream.render(, { + await renderStream.render(, { wrapper: ({ children }) => ( {children} ), @@ -4842,7 +4860,7 @@ describe("useQuery Hook", () => { }); } - await act(() => user.click(screen.getByText("Run 2nd query"))); + await user.click(screen.getByText("Run 2nd query")); { const { snapshot } = await renderStream.takeRender(); @@ -4970,6 +4988,7 @@ describe("useQuery Hook", () => { } `; + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useQueryResult: null as QueryResult | null, @@ -5021,7 +5040,7 @@ describe("useQuery Hook", () => { return ; } - renderStream.render(, { + await renderStream.render(, { wrapper: ({ children }) => ( {children} ), @@ -5064,7 +5083,7 @@ describe("useQuery Hook", () => { }); } - await act(() => user.click(screen.getByText("Run 2nd query"))); + await user.click(screen.getByText("Run 2nd query")); { const { snapshot } = await renderStream.takeRender(); @@ -5129,6 +5148,7 @@ describe("useQuery Hook", () => { } `; + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useQueryResult: null as QueryResult | null, @@ -5179,7 +5199,7 @@ describe("useQuery Hook", () => { return null; } - renderStream.render(, { + await renderStream.render(, { wrapper: ({ children }) => ( {children} ), @@ -5248,6 +5268,7 @@ describe("useQuery Hook", () => { const user = userEvent.setup(); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useQueryResult: null as QueryResult | null, @@ -5338,7 +5359,7 @@ describe("useQuery Hook", () => { return ; } - renderStream.render(, { + await renderStream.render(, { wrapper: ({ children }) => ( {children} ), @@ -5374,7 +5395,7 @@ describe("useQuery Hook", () => { }); } - await act(() => user.click(screen.getByText("Run mutation"))); + await user.click(screen.getByText("Run mutation")); await renderStream.takeRender(); { @@ -5451,14 +5472,16 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { - variables: { id: 1 }, - notifyOnNetworkStatusChange: true, - }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + variables: { id: 1 }, + notifyOnNetworkStatusChange: true, + }), + { wrapper } + ); { const result = await takeSnapshot(); expect(result.loading).toBe(true); @@ -5469,7 +5492,7 @@ describe("useQuery Hook", () => { expect(result.loading).toBe(false); expect(result.data).toEqual({ hello: "world 1" }); } - getCurrentSnapshot().refetch({ id: 2 }); + await getCurrentSnapshot().refetch({ id: 2 }); { const result = await takeSnapshot(); expect(result.loading).toBe(true); @@ -5507,19 +5530,21 @@ describe("useQuery Hook", () => { const cache = new InMemoryCache(); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { - notifyOnNetworkStatusChange: true, - }), - { - wrapper: ({ children }) => ( - - {children} - - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + notifyOnNetworkStatusChange: true, + }), + { + wrapper: ({ children }) => ( + + {children} + + ), + } + ); { const result = await takeSnapshot(); @@ -5533,7 +5558,9 @@ describe("useQuery Hook", () => { expect(result.data).toEqual({ hello: "world 1" }); } - getCurrentSnapshot().refetch(); + await getCurrentSnapshot() + .refetch() + .catch(() => {}); { const result = await takeSnapshot(); expect(result.loading).toBe(true); @@ -5548,7 +5575,7 @@ describe("useQuery Hook", () => { expect(result.data).toEqual({ hello: "world 1" }); } - getCurrentSnapshot().refetch(); + await getCurrentSnapshot().refetch(); { const result = await takeSnapshot(); expect(result.loading).toBe(true); @@ -5647,7 +5674,10 @@ describe("useQuery Hook", () => { expect(mergeParams).toEqual([[void 0, [2, 3, 5, 7, 11]]]); const thenFn = jest.fn(); - result.current.refetch({ min: 12, max: 30 }).then(thenFn); + await act( + async () => + void result.current.refetch({ min: 12, max: 30 }).then(thenFn) + ); await waitFor( () => { @@ -5740,7 +5770,10 @@ describe("useQuery Hook", () => { expect(mergeParams).toEqual([[undefined, [2, 3, 5, 7, 11]]]); const thenFn = jest.fn(); - result.current.refetch({ min: 12, max: 30 }).then(thenFn); + await act( + async () => + void result.current.refetch({ min: 12, max: 30 }).then(thenFn) + ); await waitFor( () => { @@ -5816,15 +5849,17 @@ describe("useQuery Hook", () => { {children} ); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => - useQuery(query, { - variables: { min: 0, max: 12 }, - notifyOnNetworkStatusChange: true, - // Intentionally not passing refetchWritePolicy. - }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + variables: { min: 0, max: 12 }, + notifyOnNetworkStatusChange: true, + // Intentionally not passing refetchWritePolicy. + }), + { wrapper } + ); { const result = await takeSnapshot(); @@ -5842,7 +5877,7 @@ describe("useQuery Hook", () => { } const thenFn = jest.fn(); - getCurrentSnapshot().refetch({ min: 12, max: 30 }).then(thenFn); + await getCurrentSnapshot().refetch({ min: 12, max: 30 }).then(thenFn); { const result = await takeSnapshot(); @@ -5953,7 +5988,7 @@ describe("useQuery Hook", () => { result.networkStatus === NetworkStatus.ready && !hasRefetchedRef.current ) { - client.reFetchObservableQueries(); + void client.reFetchObservableQueries(); hasRefetchedRef.current = true; } }, [result.networkStatus]); @@ -6316,12 +6351,13 @@ describe("useQuery Hook", () => { const cache = new InMemoryCache(); const onCompleted = jest.fn(); - const { takeSnapshot } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onCompleted, notifyOnNetworkStatusChange: true, - pollInterval: 110, + pollInterval: 200, }), { wrapper: ({ children }) => ( @@ -6437,7 +6473,7 @@ describe("useQuery Hook", () => { const ChildComponent: React.FC = () => { const { data, client } = useQuery(query, { onCompleted }); function refetchQueries() { - client.refetchQueries({ include: "active" }); + void client.refetchQueries({ include: "active" }); } function writeQuery() { client.writeQuery({ query, data: { hello: "baz" } }); @@ -6503,7 +6539,7 @@ describe("useQuery Hook", () => { notifyOnNetworkStatusChange: true, }); function refetchQueries() { - client.refetchQueries({ include: "active" }); + void client.refetchQueries({ include: "active" }); } function writeQuery() { client.writeQuery({ query, data: { hello: "baz" } }); @@ -6549,6 +6585,10 @@ describe("useQuery Hook", () => { describe("Optimistic data", () => { it("should display rolled back optimistic data when an error occurs", async () => { + if (IS_REACT_17) { + // this test is currently broken in React 17 with RTL 16 and needs further investigation + return; + } const query = gql` query AllCars { cars { @@ -6611,45 +6651,47 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => ({ - mutation: useMutation(mutation, { - optimisticResponse: { addCar: carData }, - update(cache, { data }) { - cache.modify({ - fields: { - cars(existing, { readField }) { - const newCarRef = cache.writeFragment({ - data: data!.addCar, - fragment: gql` - fragment NewCar on Car { - id - make - model - } - `, - }); - - if ( - existing.some( - (ref: Reference) => - readField("id", ref) === data!.addCar.id - ) - ) { - return existing; - } - - return [...existing, newCarRef]; + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => ({ + mutation: useMutation(mutation, { + optimisticResponse: { addCar: carData }, + update(cache, { data }) { + cache.modify({ + fields: { + cars(existing, { readField }) { + const newCarRef = cache.writeFragment({ + data: data!.addCar, + fragment: gql` + fragment NewCar on Car { + id + make + model + } + `, + }); + + if ( + existing.some( + (ref: Reference) => + readField("id", ref) === data!.addCar.id + ) + ) { + return existing; + } + + return [...existing, newCarRef]; + }, }, - }, - }); - }, - onError, + }); + }, + onError, + }), + query: useQuery(query), }), - query: useQuery(query), - }), - { wrapper } - ); + { wrapper } + ); { const { query } = await takeSnapshot(); @@ -6663,7 +6705,7 @@ describe("useQuery Hook", () => { expect(query.data).toEqual(carsData); } - act(() => void mutate()); + void mutate(); { // The mutation ran and is loading the result. The query stays at not @@ -6844,7 +6886,6 @@ describe("useQuery Hook", () => { }); it("should attempt a refetch when data is missing, partialRefetch is true and addTypename is false for the cache", async () => { - using _disabledActWarnings = disableActWarnings(); using consoleSpy = spyOnConsole("error"); const query = gql` { @@ -6875,7 +6916,8 @@ describe("useQuery Hook", () => { {children} ); - const { takeSnapshot } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { partialRefetch: true, @@ -6901,10 +6943,7 @@ describe("useQuery Hook", () => { } const calls = consoleSpy.error.mock.calls; - if (!IS_REACT_17) { - // React 17 doesn't know `IS_REACT_ACT_ENVIRONMENT` yet, so it will log a warning that we don't care about. - expect(calls.length).toBe(1); - } + expect(calls.length).toBe(1); expect(calls[0][0]).toMatch("Missing field"); { @@ -6974,7 +7013,7 @@ describe("useQuery Hook", () => { const entityId = 1; const shortTitle = "Short"; const longerTitle = "A little longer"; - client.mutate({ + await client.mutate({ mutation, variables: { id: entityId, @@ -7009,15 +7048,16 @@ describe("useQuery Hook", () => { }, }); - setTimeout(() => { - client.mutate({ - mutation, - variables: { - id: entityId, - title: longerTitle, - }, - }); - }); + await act( + async () => + void client.mutate({ + mutation, + variables: { + id: entityId, + title: longerTitle, + }, + }) + ); await waitFor( () => { @@ -7246,7 +7286,7 @@ describe("useQuery Hook", () => { ); expect(requestSpy).toHaveBeenCalledTimes(1); requestSpy.mockRestore(); - expect(promise).resolves.toEqual({ + await expect(promise).resolves.toEqual({ data: { hello: "world" }, loading: false, networkStatus: 7, @@ -7841,7 +7881,8 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { notifyOnNetworkStatusChange: true }), { wrapper } ); @@ -7859,7 +7900,7 @@ describe("useQuery Hook", () => { expect(result.data).toEqual(data1); expect(result.previousData).toBe(undefined); - result.refetch(); + await result.refetch(); } { @@ -7968,7 +8009,9 @@ describe("useQuery Hook", () => { expect(result.current.data).toEqual(data1); expect(result.current.previousData).toEqual(data1); - result.current.refetch({ vin: "ABCDEFG0123456789" }); + await act( + async () => void result.current.refetch({ vin: "ABCDEFG0123456789" }) + ); expect(result.current.loading).toBe(true); expect(result.current.data).toEqual(data1); expect(result.current.previousData).toEqual(data1); @@ -8169,7 +8212,8 @@ describe("useQuery Hook", () => { await waitFor( () => { - result.current.useQueryResult.reobserve().then((result) => { + // TODO investigate why do we call `reobserve` in a very quick loop here? + void result.current.useQueryResult.reobserve().then((result) => { expect(result.loading).toBe(false); expect(result.data).toEqual({ a: "aaa", b: 2 }); }); @@ -8262,7 +8306,7 @@ describe("useQuery Hook", () => { const link = new ApolloLink((operation) => { return new Observable((observer) => { const { gender } = operation.variables; - new Promise((resolve) => setTimeout(resolve, 300)).then(() => { + void wait(300).then(() => { observer.next({ data: { people: @@ -8301,7 +8345,8 @@ describe("useQuery Hook", () => { ); - const { takeSnapshot, rerender } = renderHookToSnapshotStream( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( ({ gender }: { gender: string }) => useQuery(query, { variables: { gender }, @@ -8325,7 +8370,7 @@ describe("useQuery Hook", () => { }); } - rerender({ gender: "female" }); + await rerender({ gender: "female" }); { const result = await takeSnapshot(); @@ -8345,7 +8390,7 @@ describe("useQuery Hook", () => { }); } - rerender({ gender: "nonbinary" }); + await rerender({ gender: "nonbinary" }); { const result = await takeSnapshot(); @@ -10093,12 +10138,17 @@ describe("useQuery Hook", () => { link, cache: new InMemoryCache(), }); - const { takeSnapshot } = renderHookToSnapshotStream(() => useQuery(query), { - wrapper: ({ children }) => ( - {children} - ), - }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); + await wait(10); expect(requests).toBe(1); { const result = await takeSnapshot(); @@ -10106,7 +10156,7 @@ describe("useQuery Hook", () => { expect(result.data).toBeUndefined(); } - client.clearStore(); + await client.clearStore(); { const result = await takeSnapshot(); @@ -10151,14 +10201,16 @@ describe("useQuery Hook", () => { }, ]; - const { takeSnapshot, getCurrentSnapshot } = renderHookToSnapshotStream( - () => useQuery(query, { notifyOnNetworkStatusChange: true }), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { notifyOnNetworkStatusChange: true }), + { + wrapper: ({ children }) => ( + {children} + ), + } + ); { const { loading, data, error } = await takeSnapshot(); diff --git a/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx b/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx index e22c2256128..48a8ac2ba64 100644 --- a/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx +++ b/src/react/hooks/__tests__/useQueryRefHandlers.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { act, screen } from "@testing-library/react"; +import { screen } from "@testing-library/react"; import { ApolloClient, InMemoryCache, @@ -33,6 +33,7 @@ import { useLoadableQuery } from "../useLoadableQuery"; import { concatPagination, getMainDefinition } from "../../../utilities"; import { createRenderStream, + disableActEnvironment, useTrackRenders, } from "@testing-library/react-render-stream"; @@ -44,6 +45,7 @@ test("does not interfere with updates from useReadQuery", async () => { link: new MockLink(mocks), }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { result: null as UseReadQueryResult | null, @@ -79,7 +81,7 @@ test("does not interfere with updates from useReadQuery", async () => { ); } - const { rerender } = renderStream.render(, { + const { rerender } = await renderStream.render(, { wrapper: createClientWrapper(client), }); { @@ -111,7 +113,7 @@ test("does not interfere with updates from useReadQuery", async () => { }); } - rerender(); + await rerender(); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -144,6 +146,7 @@ test("refetches and resuspends when calling refetch", async () => { link: new MockLink(mocks), }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { result: null as UseReadQueryResult | null, @@ -178,7 +181,7 @@ test("refetches and resuspends when calling refetch", async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + await renderStream.render(, { wrapper: createClientWrapper(client) }); { const { renderedComponents } = await renderStream.takeRender(); @@ -196,7 +199,7 @@ test("refetches and resuspends when calling refetch", async () => { }); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); { const { renderedComponents } = await renderStream.takeRender(); @@ -265,6 +268,7 @@ test('honors refetchWritePolicy set to "merge"', async () => { cache, }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { result: null as UseReadQueryResult | null, @@ -302,7 +306,7 @@ test('honors refetchWritePolicy set to "merge"', async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial render await renderStream.takeRender(); @@ -318,7 +322,7 @@ test('honors refetchWritePolicy set to "merge"', async () => { expect(mergeParams).toEqual([[undefined, [2, 3, 5, 7, 11]]]); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -391,6 +395,7 @@ test('honors refetchWritePolicy set to "overwrite"', async () => { cache, }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { result: null as UseReadQueryResult | null, @@ -428,7 +433,7 @@ test('honors refetchWritePolicy set to "overwrite"', async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial render await renderStream.takeRender(); @@ -444,7 +449,7 @@ test('honors refetchWritePolicy set to "overwrite"', async () => { expect(mergeParams).toEqual([[undefined, [2, 3, 5, 7, 11]]]); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -514,6 +519,7 @@ test('defaults refetchWritePolicy to "overwrite"', async () => { cache, }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { result: null as UseReadQueryResult | null, @@ -550,7 +556,7 @@ test('defaults refetchWritePolicy to "overwrite"', async () => { ); } - renderStream.render(, { wrapper: createClientWrapper(client) }); + await renderStream.render(, { wrapper: createClientWrapper(client) }); // initial render await renderStream.takeRender(); @@ -566,7 +572,7 @@ test('defaults refetchWritePolicy to "overwrite"', async () => { expect(mergeParams).toEqual([[undefined, [2, 3, 5, 7, 11]]]); } - await act(() => user.click(screen.getByText("Refetch"))); + await user.click(screen.getByText("Refetch")); await renderStream.takeRender(); { @@ -632,6 +638,7 @@ test("`refetch` works with startTransition", async () => { cache: new InMemoryCache(), }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { isPending: false, @@ -655,7 +662,7 @@ test("`refetch` works with startTransition", async () => { disabled={isPending} onClick={() => { startTransition(() => { - refetch(); + void refetch(); }); }} > @@ -688,7 +695,7 @@ test("`refetch` works with startTransition", async () => { ); } - renderStream.render(); + await renderStream.render(); { const { renderedComponents } = await renderStream.takeRender(); @@ -710,7 +717,7 @@ test("`refetch` works with startTransition", async () => { } const button = screen.getByText("Refetch"); - await act(() => user.click(button)); + await user.click(button); { const { snapshot, renderedComponents } = await renderStream.takeRender(); @@ -767,6 +774,7 @@ test("`refetch` works with startTransition from useBackgroundQuery and usePreloa link: new MockLink(mocks), }); + using _disabledAct = disableActEnvironment(); const renderStream = createRenderStream({ initialSnapshot: { useBackgroundQueryIsPending: false, @@ -794,7 +802,7 @@ test("`refetch` works with startTransition from useBackgroundQuery and usePreloa