diff --git a/.circleci/config.yml b/.circleci/config.yml index 6eeee204fde..c5f2b89c032 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,17 +3,25 @@ version: 2 jobs: Filesize: docker: - - image: circleci/node:16.13.1 + - image: cimg/node:18.12.0 steps: - checkout - - run: npm run ci:precheck - run: npm version - run: npm ci - run: npm run bundlesize + Lint: + docker: + - image: cimg/node:18.12.0 + steps: + - checkout + - run: npm version + - run: npm ci + - run: npm run lint + Tests: docker: - - image: circleci/node:16.10.0 + - image: cimg/node:18.12.0 steps: - checkout - run: npm run ci:precheck @@ -29,28 +37,10 @@ jobs: - store_artifacts: path: reports/junit - # Ensure that any PR that changes packages has a changeset on it (perhaps - # an empty one created with `changeset --empty`). - # We run the Changesets job itself on all branches so that we can require - # it to pass, but we don't run any steps on the "Version Packages" PRs - # themselves. - Changesets: - docker: - - image: circleci/node:16.13.1 - steps: - - checkout - - run: npm ci - - unless: - condition: - matches: - pattern: "^changeset-release/.+$" - value: << pipeline.git.branch >> - steps: - - run: npm run changeset-check - workflows: version: 2 Build and Test: jobs: - Filesize - Tests + - Lint diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000000..7463c12238c --- /dev/null +++ b/.eslintrc @@ -0,0 +1,13 @@ +{ + "overrides": [ + { + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "files": ["**/__tests__/**/*.[jt]sx", "**/?(*.)+(test).[jt]sx"], + "extends": ["plugin:testing-library/react"], + "rules": { + "testing-library/prefer-user-event": "error" + } + } + ] +} diff --git a/package-lock.json b/package-lock.json index d9a2e3d9c5b..1a5e1441cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,10 +45,14 @@ "@types/react": "18.0.26", "@types/react-dom": "18.0.10", "@types/use-sync-external-store": "0.0.3", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "acorn": "8.8.1", "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.5", + "eslint": "8.31.0", + "eslint-plugin-testing-library": "5.9.1", "fetch-mock": "9.11.0", "glob": "8.0.3", "graphql": "16.6.0", @@ -79,7 +83,7 @@ "whatwg-fetch": "3.6.2" }, "engines": { - "npm": "^7.20.3 || ^8.0.0" + "npm": "^7.20.3 || ^8.0.0 || ^9.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0", @@ -1091,6 +1095,74 @@ "node": ">=12" } }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@graphql-tools/merge": { "version": "8.3.14", "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.14.tgz", @@ -1139,6 +1211,39 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2058,6 +2163,12 @@ "parse5": "^7.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/lodash": { "version": "4.14.191", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", @@ -2198,6 +2309,266 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@wry/context": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.0.tgz", @@ -2277,6 +2648,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -2298,6 +2678,22 @@ "node": ">= 6.0.0" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -3072,9 +3468,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3240,6 +3636,18 @@ "node": ">=8" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz", @@ -3380,67 +3788,386 @@ "has": "^1.0.3" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", + "integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.13.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", - "dev": true + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, "engines": { - "node": ">=6" + "node": ">= 0.8.0" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=6.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -3456,6 +4183,30 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", @@ -3566,6 +4317,12 @@ "node": ">=0.10.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -3645,6 +4402,18 @@ } } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3689,6 +4458,25 @@ "pkg-dir": "^4.2.0" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4167,6 +4955,31 @@ "node": ">= 4" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -4462,6 +5275,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -5693,6 +6515,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5830,6 +6662,18 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -5966,6 +6810,12 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -6249,6 +7099,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -6566,6 +7422,18 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -7302,6 +8170,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8143,6 +9023,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -8340,6 +9226,27 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/tty-table": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.1.6.tgz", @@ -8483,6 +9390,15 @@ "node": ">= 4.0.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -9757,6 +10673,55 @@ "@jridgewell/trace-mapping": "0.3.9" } }, + "@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, "@graphql-tools/merge": { "version": "8.3.14", "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.14.tgz", @@ -9793,6 +10758,29 @@ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz", "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==" }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -10578,6 +11566,12 @@ "parse5": "^7.0.0" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/lodash": { "version": "4.14.191", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", @@ -10696,26 +11690,179 @@ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", "dev": true }, - "@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true }, - "@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true + "@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + } }, "@wry/context": { "version": "0.7.0", @@ -10777,6 +11924,12 @@ } } }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -10792,6 +11945,18 @@ "debug": "4" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -11405,9 +12570,9 @@ "dev": true }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -11527,6 +12692,15 @@ "path-type": "^4.0.0" } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dom-accessibility-api": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz", @@ -11681,12 +12855,253 @@ "source-map": "~0.6.1" } }, + "eslint": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-plugin-testing-library": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", + "integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^5.13.0" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, "estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", @@ -11775,6 +13190,12 @@ } } }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -11836,6 +13257,15 @@ "whatwg-url": "^6.5.0" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -11874,6 +13304,22 @@ "pkg-dir": "^4.2.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -12224,6 +13670,24 @@ "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -12420,6 +13884,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -13349,6 +14819,12 @@ } } }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13444,6 +14920,18 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -13555,6 +15043,12 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -13762,6 +15256,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -14005,6 +15505,15 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -14549,6 +16058,12 @@ "functions-have-names": "^1.2.2" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -15209,6 +16724,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -15334,6 +16855,23 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "tty-table": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.1.6.tgz", @@ -15435,6 +16973,15 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", diff --git a/package.json b/package.json index cef46979f51..abc6b0f26b7 100644 --- a/package.json +++ b/package.json @@ -44,13 +44,14 @@ "postprocess-dist": "ts-node-script config/postprocessDist.ts", "clean": "rimraf -r dist coverage lib temp", "ci:precheck": "node config/precheck.js", + "lint": "eslint '**/__tests__/**/*.[jt]sx'", "test": "jest --config ./config/jest.config.js", - "test:debug": "node --inspect-brk node_modules/.bin/jest --config ./config/jest.config.js --runInBand --testTimeout 99999", - "test:ci": "TEST_ENV=ci npm run test:coverage && npm run test:memory", + "test:debug": "node --inspect-brk node_modules/.bin/jest --config ./config/jest.config.js --runInBand --testTimeout 99999 --logHeapUsage", + "test:ci": "TEST_ENV=ci npm run test:coverage -- --logHeapUsage && npm run test:memory", "test:watch": "jest --config ./config/jest.config.js --watch", "test:memory": "cd scripts/memory && npm i && npm test", "test:coverage": "npm run coverage -- --ci --runInBand --reporters=default --reporters=jest-junit", - "coverage": "jest --config ./config/jest.config.js --verbose --coverage", + "coverage": "node --no-compilation-cache --expose-gc --max_old_space_size=4096 node_modules/.bin/jest --config ./config/jest.config.js --logHeapUsage --coverage --watchAll=false", "bundlesize": "npm run build && ts-node-script ./config/bundlesize.ts", "predeploy": "npm run build", "deploy": "cd dist && npm publish --tag next", @@ -60,7 +61,7 @@ "changeset-version": "changeset version && npm i" }, "engines": { - "npm": "^7.20.3 || ^8.0.0" + "npm": "^7.20.3 || ^8.0.0 || ^9.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0", @@ -119,10 +120,14 @@ "@types/react": "18.0.26", "@types/react-dom": "18.0.10", "@types/use-sync-external-store": "0.0.3", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "acorn": "8.8.1", "blob-polyfill": "7.0.20220408", "bytes": "3.1.2", "cross-fetch": "3.1.5", + "eslint": "8.31.0", + "eslint-plugin-testing-library": "5.9.1", "fetch-mock": "9.11.0", "glob": "8.0.3", "graphql": "16.6.0", diff --git a/src/__tests__/client.ts b/src/__tests__/client.ts index 322c14070ec..a25b9754d1b 100644 --- a/src/__tests__/client.ts +++ b/src/__tests__/client.ts @@ -2453,6 +2453,7 @@ describe('client', () => { await client.refetchQueries(options); expect(spy).toHaveBeenCalledWith(options); + spy.mockRestore(); }); it('has a getObservableQueries method which calls QueryManager', async () => { diff --git a/src/cache/inmemory/__tests__/cache.ts b/src/cache/inmemory/__tests__/cache.ts index 8d978c4ce6c..4c4c0f6a4f2 100644 --- a/src/cache/inmemory/__tests__/cache.ts +++ b/src/cache/inmemory/__tests__/cache.ts @@ -16,6 +16,9 @@ import { TypePolicies } from '../policies'; disableFragmentWarnings(); describe('Cache', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); function itWithInitialData( message: string, initialDataForCaches: ({ [key: string]: any })[], diff --git a/src/core/__tests__/ObservableQuery.ts b/src/core/__tests__/ObservableQuery.ts index 9424a64df6b..07990ef2bf2 100644 --- a/src/core/__tests__/ObservableQuery.ts +++ b/src/core/__tests__/ObservableQuery.ts @@ -1466,7 +1466,7 @@ describe('ObservableQuery', () => { 'Called refetch({"variables":["d","e"]}) for query QueryWithoutVariables, which does not declare a $variables variable.', "Did you mean to call refetch(variables) instead of refetch({ variables })?", ].join("\n")); - consoleWarnSpy.mockReset(); + consoleWarnSpy.mockRestore(); setTimeout(resolve, 10); } else { @@ -1547,7 +1547,7 @@ describe('ObservableQuery', () => { 'Called refetch({"variables":{"vars":["d","e"]}}) for query QueryWithVarsVar, which does not declare a $variables variable.', "Did you mean to call refetch(variables) instead of refetch({ variables })?", ].join("\n")); - consoleWarnSpy.mockReset(); + consoleWarnSpy.mockRestore(); setTimeout(resolve, 10); }); @@ -1626,7 +1626,7 @@ describe('ObservableQuery', () => { }); expect(consoleWarnSpy).not.toHaveBeenCalled(); - consoleWarnSpy.mockReset(); + consoleWarnSpy.mockRestore(); setTimeout(resolve, 10); } else { diff --git a/src/link/persisted-queries/__tests__/index.ts b/src/link/persisted-queries/__tests__/persisted-queries.test.ts similarity index 99% rename from src/link/persisted-queries/__tests__/index.ts rename to src/link/persisted-queries/__tests__/persisted-queries.test.ts index 05da0ff04ae..64db01a1897 100644 --- a/src/link/persisted-queries/__tests__/index.ts +++ b/src/link/persisted-queries/__tests__/persisted-queries.test.ts @@ -8,7 +8,7 @@ import { ApolloLink, execute } from '../../core'; import { Observable } from '../../../utilities'; import { createHttpLink } from '../../http/createHttpLink'; -import { createPersistedQueryLink as createPersistedQuery, VERSION } from '../'; +import { createPersistedQueryLink as createPersistedQuery, VERSION } from '..'; import { itAsync } from '../../../testing'; // Necessary configuration in order to mock multiple requests diff --git a/src/link/persisted-queries/__tests__/react.tsx b/src/link/persisted-queries/__tests__/react.test.tsx similarity index 95% rename from src/link/persisted-queries/__tests__/react.tsx rename to src/link/persisted-queries/__tests__/react.test.tsx index b998d8db964..96eeee346bb 100644 --- a/src/link/persisted-queries/__tests__/react.tsx +++ b/src/link/persisted-queries/__tests__/react.test.tsx @@ -11,8 +11,8 @@ import { ApolloClient } from '../../../core/ApolloClient'; import { createHttpLink } from '../../http/createHttpLink'; import { graphql } from '../../../react/hoc/graphql'; import { getDataFromTree } from '../../../react/ssr/getDataFromTree'; -import { createPersistedQueryLink as createPersistedQuery, VERSION } from '../'; -import { sha256 } from './index'; +import { createPersistedQueryLink as createPersistedQuery, VERSION } from '..'; +import { sha256 } from './persisted-queries.test'; // Necessary configuration in order to mock multiple requests // to a single (/graphql) endpoint @@ -126,11 +126,11 @@ describe('react application', () => { // change filter object to different variables and SSR await getDataFromTree(app2); - const markup2 = ReactDOM.renderToString(app2); + const view = ReactDOM.renderToString(app2); const [, [, request2]] = fetchMock.calls(); - expect(markup2).not.toContain('data was returned'); + expect(view).not.toContain('data was returned'); expect(request2!.body).toBe( JSON.stringify({ operationName: 'Test', diff --git a/src/react/components/__tests__/client/Mutation.test.tsx b/src/react/components/__tests__/client/Mutation.test.tsx index 83f859ec00f..8135a3f51cb 100644 --- a/src/react/components/__tests__/client/Mutation.test.tsx +++ b/src/react/components/__tests__/client/Mutation.test.tsx @@ -1,7 +1,8 @@ import React, { useState, PropsWithChildren } from 'react'; import gql from 'graphql-tag'; import { ExecutionResult, GraphQLError } from 'graphql'; -import { render, cleanup, fireEvent, waitFor, act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { render, screen, waitFor, act } from '@testing-library/react'; import { ApolloClient } from '../../../../core'; import { ApolloError } from '../../../../errors'; @@ -74,8 +75,6 @@ const mocks = [ const cache = new Cache({ addTypename: false }); describe('General Mutation testing', () => { - afterEach(cleanup); - it('pick prop client over context client', async () => { const mock = (text: string) => [ { @@ -136,32 +135,46 @@ describe('General Mutation testing', () => { ); }; - const { getByText, rerender } = render(); - const button = getByText('Create'); + const { rerender } = render(); + await waitFor(() => { + screen.getByText('Create'); + }, { interval: 1 }); // context client mutation - fireEvent.click(button); + await userEvent.click(screen.getByText('Create')); + + await waitFor(() => { + expect(spy).toHaveBeenCalledWith(mocksContext[0].result); + }, { interval: 1 }); // props client mutation rerender(); - fireEvent.click(button); + + await userEvent.click(screen.getByText('Create')); + + await waitFor(() => { + expect(spy).toHaveBeenCalledWith(mocksProps[0].result); + }, { interval: 1 }); // context client mutation rerender(); - fireEvent.click(button); + await userEvent.click(screen.getByText('Create')); + + await waitFor(() => { + expect(spy).toHaveBeenCalledWith(mocksContext[1].result); + }, { interval: 1 }); // props client mutation rerender(); - fireEvent.click(button); + await userEvent.click(screen.getByText('Create')); await waitFor(() => { - expect(spy).toHaveBeenCalledTimes(4); - }); + expect(spy).toHaveBeenCalledWith(mocksProps[1].result); + }, { interval: 1 }); - expect(spy).toHaveBeenCalledWith(mocksContext[0].result); - expect(spy).toHaveBeenCalledWith(mocksProps[0].result); - expect(spy).toHaveBeenCalledWith(mocksContext[1].result); - expect(spy).toHaveBeenCalledWith(mocksProps[1].result); + await waitFor(() => { + expect(spy).toHaveBeenCalledTimes(4); + }, { interval: 1 }); }); itAsync('performs a mutation', (resolve, reject) => { @@ -446,12 +459,12 @@ describe('General Mutation testing', () => { {() =>
result
}
); - const { unmount, getByText } = render( + const { unmount } = render( ); - expect(getByText('result')).toBeTruthy(); + expect(screen.getByText('result')).toBeTruthy(); // unmount here or else the mutation will resolve later and schedule an update that's not wrapped in act. unmount() }); @@ -1420,7 +1433,7 @@ describe('General Mutation testing', () => { console.log = errorLogger; }); - itAsync('errors when changing from mutation to a query', (resolve, reject) => { + it('errors when changing from mutation to a query', async () => { let didError = false; const query = gql` query todos { @@ -1470,11 +1483,10 @@ describe('General Mutation testing', () => { ); - waitFor(() => { + await waitFor(() => { expect(didError).toBe(true); - }).finally(() => { - console.log = errorLogger; - }).then(resolve, reject); + }); + console.log = errorLogger; }); it('errors if a subscription is passed instead of a mutation', () => { @@ -1504,7 +1516,7 @@ describe('General Mutation testing', () => { console.log = errorLogger; }); - itAsync('errors when changing from mutation to a subscription', (resolve, reject) => { + it('errors when changing from mutation to a subscription', async () => { let didError = false; const subscription = gql` subscription todos { @@ -1555,15 +1567,14 @@ describe('General Mutation testing', () => { ); - waitFor(() => { + await waitFor(() => { expect(didError).toBe(true); - }).finally(() => { - console.log = errorLogger; - }).then(resolve, reject); + }); + console.log = errorLogger; }); describe('after it has been unmounted', () => { - itAsync('calls the onCompleted prop after the mutation is complete', (resolve, reject) => { + it('calls the onCompleted prop after the mutation is complete', async () => { let finished = false; let success = false; const context = { "foo": "bar" } @@ -1608,10 +1619,12 @@ describe('General Mutation testing', () => { ); - waitFor(() => { + await waitFor(() => { expect(finished).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(success).toBe(true); - }, { timeout: 500 }).then(resolve, reject); + }, { interval: 1 }); }); }); @@ -1653,6 +1666,8 @@ describe('General Mutation testing', () => { await waitFor(() => { expect(onErrorCalled).toBe(true); + }); + await waitFor(() => { expect(finished).toBe(true); }); }); diff --git a/src/react/components/__tests__/client/Query.test.tsx b/src/react/components/__tests__/client/Query.test.tsx index c313b04a837..dffcce4b962 100644 --- a/src/react/components/__tests__/client/Query.test.tsx +++ b/src/react/components/__tests__/client/Query.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; -import { render, waitFor } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { ApolloClient, NetworkStatus } from '../../../../core'; import { ApolloError } from '../../../../errors'; @@ -115,20 +115,20 @@ describe('Query component', () => { }).then(resolve, reject); }); - itAsync('renders using the children prop', (resolve, reject) => { + it('renders using the children prop', async () => { const Component = () => ( {(_: any) =>
test
}
); - const { getByText } = render( + render( ); - waitFor(() => { - expect(getByText('test')).toBeTruthy(); - }).then(resolve, reject); + await waitFor(() => { + expect(screen.getByText('test')).toBeTruthy(); + }); }); describe('result provides', () => { @@ -1398,7 +1398,7 @@ describe('Query component', () => { }); }); - itAsync('should error if the query changes type to a subscription', (resolve, reject) => { + it('should error if the query changes type to a subscription', async () => { let finished = false; const subscription = gql` subscription onCommentAdded($repoFullName: String!) { @@ -1445,11 +1445,10 @@ describe('Query component', () => { ); - waitFor(() => { + await waitFor(() => { expect(finished).toBe(true); - }).finally(() => { - console.error = errorLog; - }).then(resolve, reject); + }, { interval: 1 }); + console.error = errorLog; }); itAsync('should be able to refetch after there was a network error', (resolve, reject) => { @@ -1672,7 +1671,7 @@ describe('Query component', () => { } ); - itAsync('should support mixing setState and onCompleted', (resolve, reject) => { + it('should support mixing setState and onCompleted', async () => { const query = gql` query people($first: Int) { allPeople(first: $first) { @@ -1749,7 +1748,7 @@ describe('Query component', () => { expect(data).toEqual(data1); break; default: - reject(`Too many renders (${renderCount})`); + console.error(`Too many renders (${renderCount})`); } return null; }} @@ -1764,10 +1763,12 @@ describe('Query component', () => { ); - waitFor(() => { + await waitFor(() => { expect(renderCount).toBe(5); + }); + await waitFor(() => { expect(onCompletedCallCount).toBe(3); - }).then(resolve, reject); + }); }); itAsync('should not repeatedly call onError if setState in it', (resolve, reject) => { diff --git a/src/react/context/__tests__/ApolloConsumer.test.tsx b/src/react/context/__tests__/ApolloConsumer.test.tsx index 3804b3def66..c81c8a30358 100644 --- a/src/react/context/__tests__/ApolloConsumer.test.tsx +++ b/src/react/context/__tests__/ApolloConsumer.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { ApolloLink } from '../../../link/core'; import { ApolloClient } from '../../../core'; @@ -15,8 +15,6 @@ const client = new ApolloClient({ }); describe(' component', () => { - afterEach(cleanup); - itAsync('has a render prop', (resolve, reject) => { render( @@ -36,13 +34,13 @@ describe(' component', () => { }); it('renders the content in the children prop', () => { - const { getByText } = render( + render( {() =>
Test
}
); - expect(getByText('Test')).toBeTruthy(); + expect(screen.getByText('Test')).toBeTruthy(); }); it('errors if there is no client in the context', () => { diff --git a/src/react/context/__tests__/ApolloProvider.test.tsx b/src/react/context/__tests__/ApolloProvider.test.tsx index cd844668c03..bc6d0856a17 100644 --- a/src/react/context/__tests__/ApolloProvider.test.tsx +++ b/src/react/context/__tests__/ApolloProvider.test.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { ApolloLink } from '../../../link/core'; import { ApolloClient } from '../../../core'; @@ -8,31 +8,29 @@ import { ApolloProvider } from '../ApolloProvider'; import { getApolloContext } from '../ApolloContext'; describe(' Component', () => { - afterEach(cleanup); - const client = new ApolloClient({ cache: new Cache(), link: new ApolloLink((o, f) => (f ? f(o) : null)) }); it('should render children components', () => { - const { getByText } = render( + render(
Test
); - expect(getByText('Test')).toBeTruthy(); + expect(screen.getByText('Test')).toBeTruthy(); }); it('should support the 2.0', () => { - const { getByText } = render( + render( }>
Test
); - expect(getByText('Test')).toBeTruthy(); + expect(screen.getByText('Test')).toBeTruthy(); }); it('should require a client', () => { @@ -59,12 +57,12 @@ describe(' Component', () => { }); it('should not require a store', () => { - const { getByText } = render( + render(
Test
); - expect(getByText('Test')).toBeTruthy(); + expect(screen.getByText('Test')).toBeTruthy(); }); it('should add the client to the children context', () => { diff --git a/src/react/hoc/__tests__/mutations/index.test.tsx b/src/react/hoc/__tests__/mutations/index.test.tsx index 395efafbb72..f316dbe43c5 100644 --- a/src/react/hoc/__tests__/mutations/index.test.tsx +++ b/src/react/hoc/__tests__/mutations/index.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render } from '@testing-library/react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; @@ -49,7 +49,6 @@ describe('graphql(mutation)', () => { afterEach(() => { console.error = error; - cleanup(); }); it('binds a mutation to props', () => { @@ -160,6 +159,7 @@ describe('graphql(mutation)', () => { } render() { + // eslint-disable-next-line testing-library/no-node-access return this.props.children; } } diff --git a/src/react/hoc/__tests__/mutations/queries.test.tsx b/src/react/hoc/__tests__/mutations/queries.test.tsx index f10228a52e2..d3b31512b41 100644 --- a/src/react/hoc/__tests__/mutations/queries.test.tsx +++ b/src/react/hoc/__tests__/mutations/queries.test.tsx @@ -277,6 +277,7 @@ describe('graphql(mutation) query integration', () => { reject(e); } render() { + // eslint-disable-next-line testing-library/no-node-access return this.props.children; } } diff --git a/src/react/hoc/__tests__/queries/errors.test.tsx b/src/react/hoc/__tests__/queries/errors.test.tsx index a7101e88678..69f70104102 100644 --- a/src/react/hoc/__tests__/queries/errors.test.tsx +++ b/src/react/hoc/__tests__/queries/errors.test.tsx @@ -52,6 +52,7 @@ describe('[queries] errors', () => { } render() { + // eslint-disable-next-line testing-library/no-node-access return this.props.children; } } @@ -176,7 +177,7 @@ describe('[queries] errors', () => { process.removeListener('unhandledRejection', handle); }); - itAsync('does not log when you change variables resulting in an error', (resolve, reject) => { + it('does not log when you change variables resulting in an error', async () => { const query: DocumentNode = gql` query people($var: Int) { allPeople(first: $var) { @@ -220,35 +221,26 @@ describe('[queries] errors', () => { componentDidUpdate() { const { props } = this; iteration += 1; - try { - if (iteration === 1) { - // initial loading state is done, we have data - expect(props.data!.loading).toBe(false); - expect(props.data!.allPeople).toEqual(data.allPeople); - props.setVar(2); - } else if (iteration === 2) { - expect(props.data!.loading).toBe(true); - expect(props.data!.allPeople).toBeUndefined(); - } else if (iteration === 3) { - expect(props.data!.loading).toBe(false); - expect(props.data!.allPeople).toBeUndefined(); - // the second request had an error! - expect(props.data!.error).toBeTruthy(); - expect(props.data!.error!.networkError).toBeTruthy(); - // // We need to set a timeout to ensure the unhandled rejection is swept up - setTimeout(() => { - try { - expect(unhandled.length).toEqual(0); - } catch (err) { - reject(err); - } - done = true; - }); - } else { - reject(`Too many iterations (${iteration})`); - } - } catch (err) { - reject(err); + + if (iteration === 1) { + // initial loading state is done, we have data + expect(props.data!.loading).toBe(false); + expect(props.data!.allPeople).toEqual(data.allPeople); + props.setVar(2); + } else if (iteration === 2) { + expect(props.data!.loading).toBe(true); + expect(props.data!.allPeople).toBeUndefined(); + } else if (iteration === 3) { + expect(props.data!.loading).toBe(false); + expect(props.data!.allPeople).toBeUndefined(); + // the second request had an error! + expect(props.data!.error).toBeTruthy(); + expect(props.data!.error!.networkError).toBeTruthy(); + // // We need to set a timeout to ensure the unhandled rejection is swept up + setTimeout(() => { + expect(unhandled.length).toEqual(0); + done = true; + }); } } render() { @@ -264,10 +256,12 @@ describe('[queries] errors', () => {
); - waitFor(() => { - expect(done).toBeTruthy(); + await waitFor(() => { expect(iteration).toBe(3); - }).then(resolve, reject); + }) + await waitFor(() => { + expect(done).toBeTruthy(); + }); }); }); @@ -696,6 +690,7 @@ describe('[queries] errors', () => { } render() { if (!this.state.show) return null; + // eslint-disable-next-line testing-library/no-node-access return this.props.children(() => this.setState(({ show }) => ({ show: !show })) ); diff --git a/src/react/hoc/__tests__/queries/index.test.tsx b/src/react/hoc/__tests__/queries/index.test.tsx index 6a6934cc3c1..646a42aae94 100644 --- a/src/react/hoc/__tests__/queries/index.test.tsx +++ b/src/react/hoc/__tests__/queries/index.test.tsx @@ -24,7 +24,7 @@ describe('queries', () => { }); // general api - it('binds a query to props', () => { + it('binds a query to props', async() => { let done = false; const query: DocumentNode = gql` query people { @@ -58,15 +58,15 @@ describe('queries', () => { } ); - const { unmount } = render( + render( ); - return waitFor(() => { + await waitFor(() => { expect(done).toBe(true); - }).finally(unmount) + }); }); itAsync('includes the variables in the props', (resolve, reject) => { @@ -588,6 +588,7 @@ describe('queries', () => { expect(props.data!.allPeople).toEqual(data.allPeople); } render() { + // eslint-disable-next-line testing-library/no-node-access return
{this.props.children}
; } } @@ -610,6 +611,7 @@ describe('queries', () => { } render() { + // eslint-disable-next-line testing-library/no-node-access return
{this.props.children}
; } } @@ -630,6 +632,7 @@ describe('queries', () => { } count++; + // eslint-disable-next-line testing-library/no-node-access return
{this.props.children}
; } } diff --git a/src/react/hoc/__tests__/queries/lifecycle.test.tsx b/src/react/hoc/__tests__/queries/lifecycle.test.tsx index eebf707bcaf..04613af1ba5 100644 --- a/src/react/hoc/__tests__/queries/lifecycle.test.tsx +++ b/src/react/hoc/__tests__/queries/lifecycle.test.tsx @@ -108,7 +108,7 @@ describe('[queries] lifecycle', () => { waitFor(() => expect(count).toBe(3)).then(resolve, reject); }); - itAsync('rebuilds the queries on prop change when using `options`', (resolve, reject) => { + it('rebuilds the queries on prop change when using `options`', async () => { const query: DocumentNode = gql` query people { allPeople(first: 1) { @@ -166,10 +166,12 @@ describe('[queries] lifecycle', () => {
); - waitFor(() => { + await waitFor(() => { expect(firstRun).toBeFalsy(); + }); + await waitFor(() => { expect(isDone).toBeTruthy(); - }).then(resolve, reject); + }); }); itAsync('reruns the query if just the variables change', (resolve, reject) => { diff --git a/src/react/hoc/__tests__/queries/loading.test.tsx b/src/react/hoc/__tests__/queries/loading.test.tsx index cf28381e83c..a78faa0b782 100644 --- a/src/react/hoc/__tests__/queries/loading.test.tsx +++ b/src/react/hoc/__tests__/queries/loading.test.tsx @@ -327,7 +327,7 @@ describe('[queries] loading', () => { waitFor(() => expect(count).toBe(3)).then(resolve, reject); }); - itAsync('correctly sets loading state on remounted network-only query', (resolve, reject) => { + it('correctly sets loading state on remounted network-only query', async () => { const query: DocumentNode = gql` query pollingPeople { allPeople(first: 1) { @@ -413,14 +413,16 @@ describe('[queries] loading', () => { render(App); - return waitFor(() => { + await waitFor(() => { expect(usedFetchPolicies).toEqual([ "network-only", "network-only", "cache-first", ]); + }, { interval: 1 }); + await waitFor(() => { expect(count).toBe(6); - }).then(resolve, reject); + }, { interval: 1 }); }); itAsync('correctly sets loading state on remounted component with changed variables', (resolve, reject) => { diff --git a/src/react/hoc/__tests__/queries/observableQuery.test.tsx b/src/react/hoc/__tests__/queries/observableQuery.test.tsx index 3ed9572593f..71ad09a5b33 100644 --- a/src/react/hoc/__tests__/queries/observableQuery.test.tsx +++ b/src/react/hoc/__tests__/queries/observableQuery.test.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { render, fireEvent, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { render, waitFor, screen } from '@testing-library/react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; @@ -34,22 +35,20 @@ describe('[queries] observableQuery', () => { cache: new Cache({ addTypename: false }) }); - let unmount: any; - let queryByText: any; let count = 0; - const assert1 = () => { + const assert1 = async () => { const keys = Array.from( ((client as any).queryManager as any).queries.keys() ); - expect(keys).toEqual(['1']); + await waitFor(() => expect(keys).toEqual(['1']), { interval: 1 }); }; - const assert2 = () => { + const assert2 = async () => { const keys = Array.from( ((client as any).queryManager as any).queries.keys() ); - expect(keys).toEqual(['1']); + await waitFor(() => expect(keys).toEqual(['1']), { interval: 1 }); }; let done = false; @@ -57,7 +56,7 @@ describe('[queries] observableQuery', () => { options: { fetchPolicy: 'cache-and-network' } })( class extends React.Component> { - componentDidUpdate() { + async componentDidUpdate() { if (count === 2) { expect(this.props.data!.loading).toBeFalsy(); expect(this.props.data!.allPeople).toEqual( @@ -65,15 +64,15 @@ describe('[queries] observableQuery', () => { ); // ensure first assertion and umount tree - assert1(); - fireEvent.click(queryByText('Break things')); + await assert1(); + + userEvent.click(screen.getByText('Break things')); // ensure cleanup - assert2(); + await assert2(); } if (count === 4) { - unmount(); done = true; } } @@ -137,13 +136,11 @@ describe('[queries] observableQuery', () => { } } - const result = render( + render( ); - unmount = result.unmount; - queryByText = result.queryByText; await waitFor(() => { expect(done).toBeTruthy(); diff --git a/src/react/hoc/__tests__/subscriptions/subscriptions.test.tsx b/src/react/hoc/__tests__/subscriptions/subscriptions.test.tsx index c6c1a9a9936..8c54efe243b 100644 --- a/src/react/hoc/__tests__/subscriptions/subscriptions.test.tsx +++ b/src/react/hoc/__tests__/subscriptions/subscriptions.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { act, render, cleanup } from '@testing-library/react'; +import { act, render } from '@testing-library/react'; import gql from 'graphql-tag'; import { DocumentNode } from 'graphql'; @@ -22,7 +22,6 @@ describe('subscriptions', () => { afterEach(() => { console.error = error; - cleanup(); }); const results = [ @@ -136,6 +135,7 @@ describe('subscriptions', () => { } render() { + // eslint-disable-next-line testing-library/no-node-access return this.props.children; } } diff --git a/src/react/hooks/__tests__/useApolloClient.test.tsx b/src/react/hooks/__tests__/useApolloClient.test.tsx index 2043350fd24..bfba8cf7d62 100644 --- a/src/react/hooks/__tests__/useApolloClient.test.tsx +++ b/src/react/hooks/__tests__/useApolloClient.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { InvariantError } from 'ts-invariant'; import { ApolloClient } from '../../../core'; @@ -9,8 +9,10 @@ import { InMemoryCache } from '../../../cache'; import { useApolloClient } from '../useApolloClient'; describe('useApolloClient Hook', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); afterEach(() => { - cleanup(); resetApolloContext(); }); diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx index 3b2cc4f68f3..213f66dc129 100644 --- a/src/react/hooks/__tests__/useFragment.test.tsx +++ b/src/react/hooks/__tests__/useFragment.test.tsx @@ -18,6 +18,9 @@ import { import { useQuery } from "../useQuery"; describe("useFragment", () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); it("is importable and callable", () => { expect(typeof useFragment).toBe("function"); }); @@ -111,14 +114,15 @@ describe("useFragment", () => { return
  • {complete ? data!.text : "incomplete"}
  • ; } - const { getAllByText } = render( + render( ); function getItemTexts() { - return getAllByText(/^Item/).map( + return screen.getAllByText(/^Item/).map( + // eslint-disable-next-line testing-library/no-node-access li => li.firstChild!.textContent ); } @@ -367,14 +371,15 @@ describe("useFragment", () => { return
  • {complete ? data!.text : "incomplete"}
  • ; } - const { getAllByText } = render( + render( ); function getItemTexts() { - return getAllByText(/^Item/).map( + return screen.getAllByText(/^Item/).map( + // eslint-disable-next-line testing-library/no-node-access li => li.firstChild!.textContent ); } @@ -875,6 +880,7 @@ describe("useFragment", () => { function getItemTexts() { return screen.getAllByText(/^Item/).map( + // eslint-disable-next-line testing-library/no-node-access li => li.firstChild!.textContent ); } diff --git a/src/react/hooks/__tests__/useLazyQuery.test.tsx b/src/react/hooks/__tests__/useLazyQuery.test.tsx index 62f3ed8bb63..829a65b41f6 100644 --- a/src/react/hooks/__tests__/useLazyQuery.test.tsx +++ b/src/react/hooks/__tests__/useLazyQuery.test.tsx @@ -5,12 +5,20 @@ import { renderHook, waitFor } from '@testing-library/react'; import { ApolloClient, ApolloLink, ErrorPolicy, InMemoryCache, NetworkStatus, TypedDocumentNode } from '../../../core'; import { Observable } from '../../../utilities'; -import { ApolloProvider } from '../../../react'; +import { ApolloProvider, resetApolloContext } from '../../../react'; import { MockedProvider, mockSingleLink, wait, tick } from '../../../testing'; import { useLazyQuery } from '../useLazyQuery'; import { QueryResult } from '../../types/types'; +const IS_REACT_18 = React.version.startsWith("18"); + describe('useLazyQuery Hook', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + afterEach(() => { + resetApolloContext(); + }); const helloQuery: TypedDocumentNode<{ hello: string; }> = gql`query { hello }`; @@ -312,7 +320,11 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current.query.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.called).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.data).toBeUndefined(); }, { interval: 1 }); @@ -336,15 +348,19 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(execResult.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(execResult.called).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(execResult.networkStatus).toBe(NetworkStatus.ready); + }, { interval: 1 }); + await waitFor(() => { expect(execResult.data).toEqual(expectedFinalData); }, { interval: 1 }); - await waitFor(() => { expect(result.current.query.called).toBe(true); }, { interval: 1 }); - await waitFor(() => { expect(result.current.query.loading).toBe(false); }, { interval: 10 }); @@ -369,14 +385,18 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current.query.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.called).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.data).toEqual({ counter: 2, vars: { execVar: false, }, }); - }, { interval: 10 }); + }, { interval: 1 }); const execResult2 = await result.current.exec({ fetchPolicy: "cache-and-network", @@ -388,7 +408,11 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(execResult2.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(execResult2.called).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(execResult2.data).toEqual({ counter: 3, vars: { @@ -569,16 +593,30 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current[1].loading).toBe(false); - expect(result.current[1].data).toEqual({ hello: "world 1" }); + }, { interval: 1 }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current[1].data).toEqual({ hello: "world 1" }); + } else { + expect(result.current[1].data).toEqual({ hello: "world 3" }); + } }, { interval: 1 }); await waitFor(() => { expect(result.current[1].loading).toBe(false); - expect(result.current[1].data).toEqual({ hello: "world 2" }); + }, { interval: 1 }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current[1].data).toEqual({ hello: "world 2" }); + } else { + expect(result.current[1].data).toEqual({ hello: "world 3" }); + } }, { interval: 1 }); await waitFor(() => { expect(result.current[1].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toEqual({ hello: "world 3" }); }, { interval: 1 }); @@ -749,6 +787,9 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { latestRenderResult = result.current[1]; expect(latestRenderResult.loading).toBe(false); + }); + await waitFor(() => { + latestRenderResult = result.current[1]; expect(latestRenderResult.data).toEqual({ hello: 'world' }); }); @@ -851,6 +892,8 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current[1].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toEqual({ countries: { code: "BA", @@ -960,6 +1003,9 @@ describe('useLazyQuery Hook', () => { const execute = result.current[0]; await waitFor(() => { expect(result.current[1].loading).toBe(false); + execute(); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toBe(undefined); execute(); }, { interval: 1 }); @@ -1003,14 +1049,28 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current[1].loading).toBe(true); - expect(result.current[1].networkStatus).toBe(NetworkStatus.loading); + }, { interval: 1 }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current[1].networkStatus).toBe(NetworkStatus.loading); + } else { + expect(result.current[1].networkStatus).toBe(NetworkStatus.error); + } + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toBeUndefined(); }, { interval: 1 }); await waitFor(() => { expect(result.current[1].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].networkStatus).toBe(NetworkStatus.error); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toBeUndefined(); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].error!.message).toBe("from the network"); }, { interval: 1 }); } @@ -1087,7 +1147,11 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current.query.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.called).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.data).toBeUndefined(); }, { interval: 1 }); @@ -1098,18 +1162,26 @@ describe('useLazyQuery Hook', () => { await waitFor(() => { expect(result.current.query.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.data).toMatchObject({ counter: 1 }); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.called).toBe(true); }, { interval: 1 }); await waitFor(() => { expect(result.current.query.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.called).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.query.data).toEqual({ counter: 1 }); }, { interval: 1 }); const { options } = result.current.query.observable; expect(options.fetchPolicy).toBe(defaultFetchPolicy); }); - }) + }); }); diff --git a/src/react/hooks/__tests__/useMutation.test.tsx b/src/react/hooks/__tests__/useMutation.test.tsx index bb2c03b2923..032721577b0 100644 --- a/src/react/hooks/__tests__/useMutation.test.tsx +++ b/src/react/hooks/__tests__/useMutation.test.tsx @@ -9,13 +9,19 @@ import fetchMock from "fetch-mock"; import { ApolloClient, ApolloLink, ApolloQueryResult, Cache, NetworkStatus, Observable, ObservableQuery, TypedDocumentNode } from '../../../core'; import { InMemoryCache } from '../../../cache'; import { itAsync, MockedProvider, MockSubscriptionLink, mockSingleLink, subscribeAndCount } from '../../../testing'; -import { ApolloProvider } from '../../context'; +import { ApolloProvider, resetApolloContext } from '../../context'; import { useQuery } from '../useQuery'; import { useMutation } from '../useMutation'; import { BatchHttpLink } from '../../../link/batch-http'; import { FetchResult } from '../../../link/core'; describe('useMutation Hook', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + afterEach(() => { + resetApolloContext(); + }); interface Todo { id: number; description: string; @@ -1369,7 +1375,7 @@ describe('useMutation Hook', () => { }).then(resolve, reject); }); - itAsync('should be called with the provided context', async (resolve, reject) => { + it('should be called with the provided context', async () => { const optimisticResponse = { __typename: 'Mutation', createTodo: { @@ -1423,10 +1429,10 @@ describe('useMutation Hook', () => { ); - return waitFor(() => { + await waitFor(() => { expect(contextFn).toHaveBeenCalledTimes(2); - expect(contextFn).toHaveBeenCalledWith(context); - }).then(resolve, reject); + }); + expect(contextFn).toHaveBeenCalledWith(context); }); }); @@ -2211,7 +2217,7 @@ describe('useMutation Hook', () => { render(); await waitFor(() => screen.findByText('item 1')); - await waitFor(() => userEvent.click(screen.getByRole('button', { name: /mutate/i }))); + await userEvent.click(screen.getByRole('button', { name: /mutate/i })); await waitFor(() => screen.findByText('item 3')); }); }); @@ -2370,11 +2376,21 @@ describe('useMutation Hook', () => { fetchResult = await createTodo({ variables }); }); - expect(fetchResult.errors.message).toBe(CREATE_TODO_ERROR); - expect(fetchResult.data).toBe(undefined); - expect(onError).toHaveBeenCalledTimes(1); - expect(onError.mock.calls[0][0].message).toBe(CREATE_TODO_ERROR); - expect(errorSpy).not.toHaveBeenCalled(); + await waitFor(() => { + expect(fetchResult.errors.message).toBe(CREATE_TODO_ERROR); + }); + await waitFor(() => { + expect(fetchResult.data).toBe(undefined); + }); + await waitFor(() => { + expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { + expect(onError.mock.calls[0][0].message).toBe(CREATE_TODO_ERROR); + }); + await waitFor(() => { + expect(errorSpy).not.toHaveBeenCalled(); + }); errorSpy.mockRestore(); }); it('calls the update function with the final merged result data', async () => { @@ -2455,8 +2471,10 @@ describe('useMutation Hook', () => { // but we only care about variables here expect.objectContaining({ variables }) ); + await waitFor(() => { + expect(errorSpy).not.toHaveBeenCalled(); + }); - expect(errorSpy).not.toHaveBeenCalled(); errorSpy.mockRestore(); }); }); diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 82f9bcb0aa9..70d7703e8a5 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2,7 +2,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import { DocumentNode, GraphQLError } from 'graphql'; import gql from 'graphql-tag'; import { act } from 'react-dom/test-utils'; -import { render, waitFor, renderHook } from '@testing-library/react'; +import { render, screen, waitFor, renderHook } from '@testing-library/react'; import { ApolloClient, ApolloError, @@ -12,11 +12,10 @@ import { WatchQueryFetchPolicy, } from '../../../core'; import { InMemoryCache } from '../../../cache'; -import { ApolloProvider } from '../../context'; +import { ApolloProvider, resetApolloContext } from '../../context'; import { Observable, Reference, concatPagination } from '../../../utilities'; import { ApolloLink } from '../../../link/core'; import { - itAsync, MockLink, MockedProvider, MockSubscriptionLink, @@ -27,7 +26,15 @@ import { QueryResult } from "../../types/types"; import { useQuery } from '../useQuery'; import { useMutation } from '../useMutation'; +const IS_REACT_18 = React.version.startsWith('18'); + describe('useQuery Hook', () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + afterEach(() => { + resetApolloContext(); + }); describe('General use', () => { it('should handle a simple query', async () => { const query = gql`{ hello }`; @@ -77,21 +84,38 @@ describe('useQuery Hook', () => { } ]; const wrapper = ({ children }: any) => {children}; const { result, rerender } = renderHook(() => useQuery(query), { wrapper }); + await waitFor(() => result.current.loading === false); + rerender({ children: null }); + await waitFor(() => { - expect(result.current.loading).toBe(true); - expect(result.current.data).toBeUndefined(); - }, { interval: 1 }); + if (IS_REACT_18) { + expect(result.current.loading).toBe(true); + } else { + expect(result.current.loading).toBe(false); + } + }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current.data).toBeUndefined(); + } else { + expect(result.current.data).toEqual({ hello: "world"}); + } + }); await waitFor(() => { expect(result.current.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: "world" }); - }, { interval: 1 }); + }); // Repeat frame because rerender forces useQuery to be called again await waitFor(() => { expect(result.current.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: "world" }); - }, { interval: 1 }); + }); }); it("useQuery produces the expected frames when variables change", async () => { @@ -114,26 +138,62 @@ describe('useQuery Hook', () => { ); await waitFor(() => result.current.loading === false); await waitFor(() => { - expect(result.current.loading).toBe(true); - expect(result.current.data).toBeUndefined(); - expect(result.current.networkStatus).toBe(NetworkStatus.loading); - }, { interval: 1 }); + if (IS_REACT_18) { + expect(result.current.loading).toBe(true); + } else { + expect(result.current.loading).toBe(false); + } + }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current.data).toBeUndefined(); + } else { + expect(result.current.data).toEqual({ hello: "world 1" }); + } + }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current.networkStatus).toBe(NetworkStatus.loading); + } else { + expect(result.current.networkStatus).toBe(NetworkStatus.ready); + } + }); await waitFor(() => { expect(result.current.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: "world 1" }); + }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); - }, { interval: 1 }); + }); rerender({ variables: { id: 2 } }); await waitFor(() => { expect(result.current.loading).toBe(true); - expect(result.current.data).toBeUndefined(); - expect(result.current.networkStatus).toBe(NetworkStatus.setVariables); - }, { interval: 1 }); + }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current.data).toBeUndefined(); + } else { + expect(result.current.data).toEqual({ hello: "world 2" }); + } + }); + await waitFor(() => { + if (IS_REACT_18) { + expect(result.current.networkStatus).toBe(NetworkStatus.setVariables); + } else { + expect(result.current.networkStatus).toBe(NetworkStatus.ready); + } + }); await waitFor(() => { expect(result.current.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: "world 2" }); + }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); - }, { interval: 1 }); + }); }); it('should read and write results from the cache', async () => { @@ -479,13 +539,17 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current[0].loading).toBe(false); + }); + await waitFor(() => { expect(result.current[0].data).toEqual({ hello: "world 2" }); + }); + await waitFor(() => { expect(result.current[0].variables).toEqual({ name: "world 2" }); }); }); // TODO: Rewrite this test - itAsync('should not error when forcing an update with React >= 16.13.0', (resolve, reject) => { + it('should not error when forcing an update with React >= 16.13.0', async () => { const CAR_QUERY: DocumentNode = gql` query { cars { @@ -543,7 +607,7 @@ describe('useQuery Hook', () => { } render( - + @@ -552,11 +616,10 @@ describe('useQuery Hook', () => { ); - waitFor(() => { + await waitFor(() => { expect(renderCount).toBe(6); - }).finally(() => { - console.error = consoleError; - }).then(resolve, reject); + }) + console.error = consoleError; }); it('should tear down the query on unmount', async () => { @@ -677,15 +740,27 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current[0].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[0].data).toEqual(allPeopleData); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].loading).toBe(true); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toBe(undefined); }, { interval: 1 }); await waitFor(() => { expect(result.current[0].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[0].data).toEqual(allPeopleData); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current[1].data).toEqual(allThingsData); }, { interval: 1 }); @@ -1375,9 +1450,13 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.data).toEqual({ linkCount: 2, }); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); }, { interval: 1 }); @@ -1585,14 +1664,22 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); }, { interval: 1 }); - expect(result.current.data).toEqual({ hello: "world 1" }); - expect(requestSpy).toHaveBeenCalledTimes(1); + await waitFor(() => { + expect(result.current.data).toEqual({ hello: "world 1" }); + }); + await waitFor(() => { + expect(requestSpy).toHaveBeenCalledTimes(1); + }) unmount(); + await expect(waitFor(() => { expect(requestSpy).not.toHaveBeenCalledTimes(1); }, { interval: 1, timeout: 20 })).rejects.toThrow(); - expect(onErrorFn).toHaveBeenCalledTimes(0); + await waitFor(() => { + expect(onErrorFn).toHaveBeenCalledTimes(0); + }); + requestSpy.mockRestore(); }); it('should stop polling when component is unmounted in Strict Mode', async () => { @@ -1646,6 +1733,7 @@ describe('useQuery Hook', () => { expect(requestSpy).not.toHaveBeenCalledTimes(1); }, { interval: 1, timeout: 20 })).rejects.toThrow(); expect(onErrorFn).toHaveBeenCalledTimes(0); + requestSpy.mockRestore(); }); it('should start and stop polling in Strict Mode', async () => { @@ -1702,6 +1790,7 @@ describe('useQuery Hook', () => { expect(result.current.loading).toBe(false); expect(requestSpy).toHaveBeenCalledTimes(2); expect(onErrorFn).toHaveBeenCalledTimes(0); + requestSpy.mockRestore(); }); it('should not throw an error if stopPolling is called manually', async () => { @@ -1813,6 +1902,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onError).toHaveBeenCalledWith( new ApolloError({ graphQLErrors: [new GraphQLError('error')] }) ); @@ -1856,6 +1947,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onError).toHaveBeenCalledWith( new ApolloError({ networkError: new Error('Could not fetch') }) ); @@ -1976,6 +2069,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onError).toHaveBeenCalledWith( new ApolloError({ networkError: new Error('Could not fetch') }) ); @@ -2051,8 +2146,11 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onCompleted).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onCompleted).toHaveBeenCalledWith({ hello: null }); - + }); + await waitFor(() => { expect(onError).not.toHaveBeenCalled(); }); }); @@ -2095,6 +2193,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onError).toHaveBeenCalledWith( new ApolloError({ graphQLErrors: [new GraphQLError('error')] }) ); @@ -2179,14 +2279,17 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(onError).toHaveBeenCalledTimes(1); + }); + await waitFor(() => { expect(onError).toHaveBeenCalledWith( new ApolloError({ graphQLErrors: [new GraphQLError('Could not fetch "hello"')] }) ); - + }); + await waitFor(() => { expect(onCompleted).not.toHaveBeenCalled(); - }) + }); }); it('calls `onError` a single time when refetching returns a successful result', async () => { @@ -3457,8 +3560,14 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: 'world' }); + }, { interval: 1 }); + await waitFor(() => { expect(onCompleted).toHaveBeenCalledTimes(1); + }, { interval: 1 }); + await waitFor(() => { expect(onCompleted).toHaveBeenCalledWith({ hello: 'world' }); }, { interval: 1 }); expect(onCompleted).toHaveBeenCalledTimes(1); @@ -3679,8 +3788,8 @@ describe('useQuery Hook', () => { ); }; - const { findByText } = render(); - await findByText("onCompletedCalled: true"); + render(); + await screen.findByText("onCompletedCalled: true"); expect(errorSpy).not.toHaveBeenCalled(); errorSpy.mockRestore(); }); @@ -4982,68 +5091,132 @@ describe('useQuery Hook', () => { await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; + const { loading } = result.current.useQueryResult; expect(loading).toBe(true); - expect(data).toBeUndefined(); + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(data).toBeUndefined(); + } else { + expect(data).toEqual({ a: "a" }); + } + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toBeUndefined(); }, { interval: 1 }); await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; + const { loading } = result.current.useQueryResult; expect(loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; expect(data).toEqual({ a: "a" }); + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toBe(undefined); }, { interval: 1 }); - await expect(waitFor(() => { + await expect(await waitFor(() => { result.current.setQuery(abQuery); }, { interval: 1 })); await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; - expect(loading).toBe(true); - expect(data).toBeUndefined(); + const { loading } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(loading).toBe(true); + } else { + expect(loading).toBe(false); + } + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(data).toBeUndefined(); + } else { + expect(data).toEqual({ a: "aa", b: 1 }); + } + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toEqual({ a: "a" }); }, { interval: 1 }); await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; + const { loading } = result.current.useQueryResult; expect(loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; expect(data).toEqual({ a: "aa", b: 1 }); + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toEqual({ a: "a" }); }, { interval: 1 }); - await expect(waitFor(() => { + await waitFor(() => { result.current.useQueryResult.reobserve().then(result => { expect(result.loading).toBe(false); expect(result.data).toEqual({ a: "aaa", b: 2 }); }); - }, { interval: 1 })); + }, { interval: 1 }); await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; + const { loading } = result.current.useQueryResult; expect(loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; expect(data).toEqual({ a: "aaa", b: 2 }); + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toEqual({ a: "aa", b: 1 }); }, { interval: 1 }); - await expect(waitFor(() => { + await waitFor(() => { result.current.setQuery(bQuery); - }, { interval: 1 })); + }, { interval: 1 }); await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; - expect(loading).toBe(true); - expect(data).toEqual({ b: 2 }); - expect(previousData).toEqual({ a: "aaa", b: 2 }); + const { loading } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(loading).toBe(true); + } else { + expect(loading).toBe(false); + } }, { interval: 1 }); - await waitFor(() => { - const { loading, data, previousData } = result.current.useQueryResult; - expect(loading).toBe(false); + const { data } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(data).toEqual({ b: 2 }); + } else { + expect(data).toEqual({ b: 3 }); + } + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; + if (IS_REACT_18) { + expect(previousData).toEqual({ a: "aaa", b: 2 }); + } else { + expect(previousData).toEqual({ b: 2 }); + } + }, { interval: 1 }); + await waitFor(() => { + const { loading } = result.current.useQueryResult; expect(loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { + const { data } = result.current.useQueryResult; expect(data).toEqual({ b: 3 }); + }, { interval: 1 }); + await waitFor(() => { + const { previousData } = result.current.useQueryResult; expect(previousData).toEqual({ b: 2 }); }, { interval: 1 }); }); @@ -5196,16 +5369,22 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: 'world 1' }); }, { interval: 1 }); await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: 'world 2' }); }, { interval: 1 }); await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hello: 'world 3' }); }, { interval: 1 }); }); @@ -5285,6 +5464,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ results }); }, { interval: 1 }); expect(result.current.data.results.length).toBe(7); @@ -5372,6 +5553,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ results }); }, { interval: 1 }); expect(result.current.data.results.length).toBe(7); @@ -5461,6 +5644,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.a.loading).toBe(false); + }); + await waitFor(() => { expect(result.current.b.loading).toBe(false); }); expect(result.current.a.data).toEqual(aData); @@ -5514,7 +5699,7 @@ describe('useQuery Hook', () => { }); describe('regression test issue #9204', () => { - itAsync('should handle a simple query', (resolve, reject) => { + it('should handle a simple query', async () => { const query = gql`{ hello }`; const mocks = [ { @@ -5533,7 +5718,7 @@ describe('useQuery Hook', () => { * this component will re-render in an infinite loop. */ if (counter > 10) { - reject(new Error(`Too many results (${counter})`)); + console.error(`Too many results (${counter})`); } else { setCounter(c => c + 1); } @@ -5547,15 +5732,15 @@ describe('useQuery Hook', () => { return
    {result.data.hello}{counter}
    ; } - const { getByText } = render( + render( ); - waitFor(() => { - expect(getByText('world2')).toBeTruthy(); - }).then(resolve, reject); + await waitFor(() => { + expect(screen.getByText('world2')).toBeTruthy(); + }); }); }); @@ -5638,6 +5823,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { message: 'Hello world', @@ -5729,6 +5916,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greetings: [ { @@ -5761,6 +5950,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greetings: [ { @@ -5845,6 +6036,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ allProducts: [ { @@ -5903,6 +6096,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ allProducts: [ { @@ -5980,6 +6175,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { message: 'Hello world', @@ -6008,6 +6205,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { message: 'Hello world', @@ -6082,6 +6281,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hero: { heroFriends: [ @@ -6129,10 +6330,14 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); - expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.error).toBeInstanceOf(ApolloError); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.error!.message).toBe('homeWorld for character with ID 1000 could not be fetched.'); - + }, { interval: 1 }); + await waitFor(() => { // since default error policy is "none", we do *not* return partial results expect(result.current.data).toEqual({ hero: { @@ -6213,6 +6418,8 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ hero: { heroFriends: [ @@ -6264,13 +6471,22 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { // @ts-ignore expect(result.current.label).toBe(undefined); + }, { interval: 1 }); + await waitFor(() => { // @ts-ignore expect(result.current.extensions).toBe(undefined); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.error).toBeInstanceOf(ApolloError); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.error!.message).toBe('homeWorld for character with ID 1000 could not be fetched.'); - + }, { interval: 1 }); + await waitFor(() => { // since default error policy is "all", we *do* return partial results expect(result.current.data).toEqual({ hero: { @@ -6355,7 +6571,11 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { __typename: 'Greeting', @@ -6382,7 +6602,11 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { __typename: 'Greeting', @@ -6458,7 +6682,11 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { __typename: 'Greeting', @@ -6485,7 +6713,11 @@ describe('useQuery Hook', () => { await waitFor(() => { expect(result.current.loading).toBe(false); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.networkStatus).toBe(NetworkStatus.ready); + }, { interval: 1 }); + await waitFor(() => { expect(result.current.data).toEqual({ greeting: { __typename: 'Greeting', diff --git a/src/react/hooks/__tests__/useReactiveVar.test.tsx b/src/react/hooks/__tests__/useReactiveVar.test.tsx index 1416d460f74..1de2f010ac5 100644 --- a/src/react/hooks/__tests__/useReactiveVar.test.tsx +++ b/src/react/hooks/__tests__/useReactiveVar.test.tsx @@ -1,5 +1,5 @@ import React, { StrictMode, useEffect } from "react"; -import { render, waitFor, act } from "@testing-library/react"; +import { screen, render, waitFor, act } from "@testing-library/react"; import { itAsync } from "../../../testing"; import { makeVar } from "../../../core"; @@ -8,7 +8,7 @@ import { useReactiveVar } from "../useReactiveVar"; const IS_REACT_18 = React.version.startsWith('18'); describe("useReactiveVar Hook", () => { - itAsync("works with one component", (resolve, reject) => { + it("works with one component", async () => { const counterVar = makeVar(0); let renderCount = 0; @@ -29,7 +29,7 @@ describe("useReactiveVar Hook", () => { expect(count).toBe(3); break; default: - reject(`too many (${renderCount}) renders`); + console.error(`too many (${renderCount}) renders`); } }); @@ -38,10 +38,12 @@ describe("useReactiveVar Hook", () => { render(); - waitFor(() => { + await waitFor(() => { expect(renderCount).toBe(3); + }); + await waitFor(() => { expect(counterVar()).toBe(3); - }).then(resolve, reject); + }); }); itAsync("works when two components share a variable", async (resolve, reject) => { @@ -93,6 +95,9 @@ describe("useReactiveVar Hook", () => { await waitFor(() => { expect(parentRenderCount).toBe(1); + }); + + await waitFor(() => { expect(childRenderCount).toBe(1); }); @@ -103,6 +108,8 @@ describe("useReactiveVar Hook", () => { await waitFor(() => { expect(parentRenderCount).toBe(2); + }); + await waitFor(() => { expect(childRenderCount).toBe(2); }); @@ -113,6 +120,8 @@ describe("useReactiveVar Hook", () => { await waitFor(() => { expect(parentRenderCount).toBe(3); + }); + await waitFor(() => { expect(childRenderCount).toBe(3); }); @@ -121,7 +130,7 @@ describe("useReactiveVar Hook", () => { resolve(); }); - itAsync("does not update if component has been unmounted", (resolve, reject) => { + it("does not update if component has been unmounted", async () => { const counterVar = makeVar(0); let renderCount = 0; let attemptedUpdateAfterUnmount = false; @@ -161,19 +170,23 @@ describe("useReactiveVar Hook", () => { const { unmount } = render(); - return waitFor(() => { + await waitFor(() => { expect(attemptedUpdateAfterUnmount).toBe(true); - }).then(() => { + }); + await waitFor(() => { expect(renderCount).toBe(3); + }) + await waitFor(() => { expect(counterVar()).toBe(6); + }) + await waitFor(() => { expect(consoleErrorArgs).toEqual([]); - }).finally(() => { - console.error = error; - }).then(resolve, reject); + }) + console.error = error; }); describe("useEffect", () => { - itAsync("works if updated higher in the component tree", async (resolve, reject) => { + it("works if updated higher in the component tree", async () => { const counterVar = makeVar(0); function ComponentOne() { @@ -192,7 +205,7 @@ describe("useReactiveVar Hook", () => { return (
    {count}
    ); } - const { getAllByText } = render( + render( <> @@ -200,13 +213,11 @@ describe("useReactiveVar Hook", () => { ); await waitFor(() => { - expect(getAllByText("1")).toHaveLength(2); + expect(screen.getAllByText("1")).toHaveLength(2); }); - - resolve(); }); - itAsync("works if updated lower in the component tree", async (resolve, reject) => { + it("works if updated lower in the component tree", async () => { const counterVar = makeVar(0); function ComponentOne() { @@ -225,7 +236,7 @@ describe("useReactiveVar Hook", () => { return (
    {count}
    ); } - const { getAllByText } = render( + render( <> @@ -233,10 +244,8 @@ describe("useReactiveVar Hook", () => { ); await waitFor(() => { - expect(getAllByText("1")).toHaveLength(2); + expect(screen.getAllByText("1")).toHaveLength(2); }); - - resolve(); }); itAsync("works with strict mode", async (resolve, reject) => { @@ -290,7 +299,7 @@ describe("useReactiveVar Hook", () => { return (
    {count}
    ); } - const { getAllByText } = render(); + render(); Promise.resolve().then(() => { counterVar(1); counterVar(2); @@ -305,7 +314,7 @@ describe("useReactiveVar Hook", () => { }); await waitFor(() => { - expect(getAllByText("10")).toHaveLength(1); + expect(screen.getAllByText("10")).toHaveLength(1); }); resolve(); diff --git a/src/react/hooks/__tests__/useSubscription.test.tsx b/src/react/hooks/__tests__/useSubscription.test.tsx index 091cfb71a98..1c208814bef 100644 --- a/src/react/hooks/__tests__/useSubscription.test.tsx +++ b/src/react/hooks/__tests__/useSubscription.test.tsx @@ -4,14 +4,17 @@ import gql from 'graphql-tag'; import { ApolloClient, ApolloError, ApolloLink, concat } from '../../../core'; import { InMemoryCache as Cache } from '../../../cache'; -import { ApolloProvider } from '../../context'; +import { ApolloProvider, resetApolloContext } from '../../context'; import { MockSubscriptionLink } from '../../../testing'; import { useSubscription } from '../useSubscription'; describe('useSubscription Hook', () => { - afterEach(() => { + beforeEach(() => { jest.restoreAllMocks(); }); + afterEach(() => { + resetApolloContext(); + }); it('should handle a simple subscription properly', async () => { const subscription = gql` @@ -641,6 +644,7 @@ describe('useSubscription Hook', () => { expect(warningSpy).toHaveBeenCalledTimes(1); expect(warningSpy).toHaveBeenCalledWith(expect.stringContaining("supports only the 'onSubscriptionData' or 'onData' option")); + warningSpy.mockRestore(); }); test("prefers 'onData' when using 'onSubscriptionData' and 'onData' together", async () => { @@ -685,12 +689,12 @@ describe('useSubscription Hook', () => { setTimeout(() => link.simulateResult(results[0])); await waitFor(() => { expect(onData).toHaveBeenCalledTimes(1); - expect(onSubscriptionData).toHaveBeenCalledTimes(0); }, { interval: 1 }); + expect(onSubscriptionData).toHaveBeenCalledTimes(0); }); test("uses 'onSubscriptionData' when 'onData' is absent", async () => { - jest.spyOn(console, 'warn').mockImplementation(() => {}); + const warningSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); const subscription = gql` subscription { car { @@ -730,6 +734,7 @@ describe('useSubscription Hook', () => { await waitFor(() => { expect(onSubscriptionData).toHaveBeenCalledTimes(1); }, { interval: 1 }); + warningSpy.mockRestore(); }); test("only warns once using `onSubscriptionData`", () => { @@ -764,6 +769,7 @@ describe('useSubscription Hook', () => { rerender(); expect(warningSpy).toHaveBeenCalledTimes(1); + warningSpy.mockRestore(); }); test("should warn when using 'onComplete' and 'onSubscriptionComplete' together", () => { @@ -798,10 +804,11 @@ describe('useSubscription Hook', () => { expect(warningSpy).toHaveBeenCalledTimes(1); expect(warningSpy).toHaveBeenCalledWith(expect.stringContaining("supports only the 'onSubscriptionComplete' or 'onComplete' option")); + warningSpy.mockRestore(); }); test("prefers 'onComplete' when using 'onComplete' and 'onSubscriptionComplete' together", async () => { - jest.spyOn(console, 'warn').mockImplementation(() => {}); + const warningSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); const subscription = gql` subscription { car { @@ -842,13 +849,13 @@ describe('useSubscription Hook', () => { setTimeout(() => link.simulateComplete()); await waitFor(() => { expect(onComplete).toHaveBeenCalledTimes(1); - expect(onSubscriptionComplete).toHaveBeenCalledTimes(0); }, { interval: 1 }); - + expect(onSubscriptionComplete).toHaveBeenCalledTimes(0); + warningSpy.mockRestore(); }); test("uses 'onSubscriptionComplete' when 'onComplete' is absent", async () => { - jest.spyOn(console, 'warn').mockImplementation(() => {}); + const warningSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); const subscription = gql` subscription { car { @@ -888,7 +895,7 @@ describe('useSubscription Hook', () => { await waitFor(() => { expect(onSubscriptionComplete).toHaveBeenCalledTimes(1); }, { interval: 1 }); - + warningSpy.mockRestore(); }); test("only warns once using `onSubscriptionComplete`", () => { @@ -923,5 +930,6 @@ describe('useSubscription Hook', () => { rerender(); expect(warningSpy).toHaveBeenCalledTimes(1); + warningSpy.mockRestore(); }); }); diff --git a/src/react/ssr/__tests__/useQuery.test.tsx b/src/react/ssr/__tests__/useQuery.test.tsx index d8ee7847dcf..6fb118a839b 100644 --- a/src/react/ssr/__tests__/useQuery.test.tsx +++ b/src/react/ssr/__tests__/useQuery.test.tsx @@ -173,12 +173,12 @@ describe('useQuery Hook SSR', () => {
    ); - const result = await renderToStringWithData(app); + const view = await renderToStringWithData(app); expect(renderCount).toBe(1); - expect(result).toEqual(''); + expect(view).toEqual(''); await new Promise((resolve) => setTimeout(resolve, 20)); expect(renderCount).toBe(1); - expect(result).toEqual(''); + expect(view).toEqual(''); } ); diff --git a/src/testing/react/__tests__/MockedProvider.test.tsx b/src/testing/react/__tests__/MockedProvider.test.tsx index 58f54f866db..d2355accc7a 100644 --- a/src/testing/react/__tests__/MockedProvider.test.tsx +++ b/src/testing/react/__tests__/MockedProvider.test.tsx @@ -424,7 +424,7 @@ describe('General use', () => { }).then(resolve, reject); }); - itAsync('should return "No more mocked responses" errors in response', (resolve, reject) => { + it('should return "No more mocked responses" errors in response', async () => { let finished = false; function Component() { const { loading, error } = useQuery(query); @@ -443,15 +443,15 @@ describe('General use', () => { ); - waitFor(() => { + await waitFor(() => { expect(finished).toBe(true); - // The "No more mocked responses" error should not be thrown as an - // uncaught exception. - expect(errorThrown).toBeFalsy(); - }).then(resolve, reject); + }); + // The "No more mocked responses" error should not be thrown as an + // uncaught exception. + expect(errorThrown).toBeFalsy(); }); - itAsync('should return "Mocked response should contain" errors in response', (resolve, reject) => { + it('should return "Mocked response should contain" errors in response', async () => { let finished = false; function Component({ ...variables }: Variables) { const { loading, error } = useQuery(query, { variables }); @@ -477,12 +477,12 @@ describe('General use', () => { ); - waitFor(() => { + await waitFor(() => { expect(finished).toBe(true); - // The "Mocked response should contain" error should not be thrown as an - // uncaught exception. - expect(errorThrown).toBeFalsy(); - }).then(resolve, reject); + }); + // The "Mocked response should contain" error should not be thrown as an + // uncaught exception. + expect(errorThrown).toBeFalsy(); }); itAsync('should support custom error handling using setOnError', (resolve, reject) => { diff --git a/src/testing/react/__tests__/mockSubscriptionLink.test.tsx b/src/testing/react/__tests__/mockSubscriptionLink.test.tsx index e0eff8e709d..af3fc9811d1 100644 --- a/src/testing/react/__tests__/mockSubscriptionLink.test.tsx +++ b/src/testing/react/__tests__/mockSubscriptionLink.test.tsx @@ -11,7 +11,7 @@ import { useSubscription } from '../../../react/hooks'; const IS_REACT_18 = React.version.startsWith('18'); describe('mockSubscriptionLink', () => { - it('should work with multiple subscribers to the same mock websocket', () => { + it('should work with multiple subscribers to the same mock websocket', async () => { const subscription = gql` subscription { car { @@ -67,9 +67,9 @@ describe('mockSubscriptionLink', () => { const numRenders = IS_REACT_18 ? 2 : results.length + 1; // automatic batching in React 18 means we only see 2 renders vs. 5 in v17 - return waitFor(() => { + await waitFor(() => { expect(renderCountA).toBe(numRenders); - expect(renderCountB).toBe(numRenders); }, { timeout: 1000 }); + expect(renderCountB).toBe(numRenders); }); });