diff --git a/package-lock.json b/package-lock.json index eee9062..aa85762 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "fetch-mock": "^6.5.2", "husky": "2.7.0", "identity-obj-proxy": "^3.0.0", - "jest": "29.3.1", + "jest": "^26.6.3", "react-dev-utils": "^12.0.1", "react-test-renderer": "^16.10.1", "reactifex": "1.1.1", @@ -120,9 +120,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", + "version": "7.21.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.9.tgz", + "integrity": "sha512-FUGed8kfhyWvbYug/Un/VPJD41rDIgoVVcR+FuzhzOYyRz5uED+Gd3SLZml0Uw2l2aHFb7ZgdW5mGA3G2cCCnQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -177,9 +177,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.21.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.9.tgz", + "integrity": "sha512-F3fZga2uv09wFdEjEQIJxXALXfz0+JaOb7SabvVMmjHxeVTuGW8wgE8Vp1Hd7O+zMTYtcfEISGRzPkeiaPPsvg==", "dev": true, "dependencies": { "@babel/types": "^7.21.5", @@ -531,9 +531,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz", - "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==", + "version": "7.21.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.9.tgz", + "integrity": "sha512-q5PNg/Bi1OpGgx5jYlvWZwAorZepEudDMCLtj967aeS7WMont7dUZI46M2XwcIQqvUlMxWfdLFu4S/qSxeUu5g==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1826,9 +1826,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -2091,1071 +2091,6 @@ "react": "^16.9.0 || ^17.0.0" } }, - "node_modules/@edx/frontend-build/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^8.0.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@edx/frontend-build/node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@edx/frontend-build/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@edx/frontend-build/node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/@edx/frontend-build/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/@edx/frontend-build/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@edx/frontend-build/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@edx/frontend-build/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@edx/frontend-build/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@edx/frontend-build/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@edx/frontend-build/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@edx/frontend-build/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@edx/frontend-build/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@edx/frontend-build/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@edx/frontend-build/node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@edx/frontend-build/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@edx/frontend-build/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@edx/frontend-build/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@edx/frontend-build/node_modules/yargs-parser/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/@edx/frontend-component-footer": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.0.0.tgz", @@ -3232,11 +2167,11 @@ } }, "node_modules/@edx/frontend-component-header": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.0.0.tgz", - "integrity": "sha512-r/L3p2ZSI1DitjxVKAor18GmgJllafYslrdpzGI0vcX/gTemH13jf2Xr9iQqrT921DP2nzZ5GOwGJNptTSjiaA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.0.3.tgz", + "integrity": "sha512-kczQxTeZ2qqoonIed+SX7WcDgYTJBcoflyJp6rMwKs5U/o2Z1576Tv5rH6nmRWH068WxwsgMEzI9lhg+jFMi1g==", "dependencies": { - "@edx/paragon": "20.30.1", + "@edx/paragon": "20.36.0", "@fortawesome/fontawesome-svg-core": "6.3.0", "@fortawesome/free-brands-svg-icons": "6.3.0", "@fortawesome/free-regular-svg-icons": "6.3.0", @@ -3254,9 +2189,9 @@ } }, "node_modules/@edx/frontend-component-header/node_modules/@edx/paragon": { - "version": "20.30.1", - "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.30.1.tgz", - "integrity": "sha512-v3Ek8deZWqVKi3IWP08Mj4egrvbmbqQEyRA6+qazHZdgHJA4qOP1SST42UKd9XxPeRbLWUgaJWd0iBAOAna/gw==", + "version": "20.36.0", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.36.0.tgz", + "integrity": "sha512-0dn4r1HvcrHY66xmLkLTRIBD09TDrNn6vxWu1XZr2SwkGLf56cI8aGkZEySeOVs/VLWtJRMmMJaSbozCpxvLyg==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", @@ -3307,9 +2242,6 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==", "hasInstallScript": true, - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.3.0" - }, "engines": { "node": ">=6" } @@ -3408,6 +2340,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@edx/frontend-component-header/node_modules/mailto-link": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-2.0.0.tgz", + "integrity": "sha512-b5FErkZ4t6mpH1IFZSw7Mm2IQHXQ2R0/5Q4xd7Rv8dVkWvE54mFG/UW7HjfFazXFjXTNsM+dSX2tTeIDrV9K9A==", + "dependencies": { + "assert-ok": "~1.0.0", + "cast-array": "~1.0.1", + "object-filter": "~1.0.2", + "query-string": "~7.0.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/@edx/frontend-component-header/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -3419,6 +2365,28 @@ "node": ">=10" } }, + "node_modules/@edx/frontend-component-header/node_modules/query-string": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz", + "integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==", + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" + }, "node_modules/@edx/frontend-component-header/node_modules/uuid": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", @@ -3475,6 +2443,19 @@ "form-data": "^4.0.0" } }, + "node_modules/@edx/frontend-platform/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@edx/new-relic-source-map-webpack-plugin": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@edx/new-relic-source-map-webpack-plugin/-/new-relic-source-map-webpack-plugin-2.0.0.tgz", @@ -3522,41 +2503,6 @@ "email-validator": "^2.0.4" } }, - "node_modules/@edx/paragon/node_modules/mailto-link": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-1.0.0.tgz", - "integrity": "sha512-DVRvtkoeXLHAbH+S+9m3ILIdnvQsSc9IvJwfEclQVD8e8FhzwA5Mtw4Q0XXYr/sAziw/HsMc/gpGAI+5w6ohIw==", - "dependencies": { - "assert-ok": "~1.0.0", - "cast-array": "~1.0.0", - "object-filter": "~1.0.2", - "query-string": "~2.4.1" - } - }, - "node_modules/@edx/paragon/node_modules/query-string": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-2.4.2.tgz", - "integrity": "sha512-Y+OMYUuY7HxznI6WBN822fi/FMvnCTiuqd6KNcidPColOmMWPoV1RGYyyzObve1T/dD1i0ZgCCbO8ytu0ZUrkA==", - "dependencies": { - "strict-uri-encode": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@edx/paragon/node_modules/strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@edx/paragon/node_modules/tabbable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-4.0.0.tgz", - "integrity": "sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==" - }, "node_modules/@edx/reactifex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@edx/reactifex/-/reactifex-2.1.1.tgz", @@ -3569,6 +2515,70 @@ "edx_reactifex": "main.js" } }, + "node_modules/@edx/reactifex/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/reactifex/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/@edx/reactifex/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/reactifex/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/reactifex/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edx/reactifex/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3585,9 +2595,9 @@ } }, "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3597,23 +2607,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -4017,46 +3027,20 @@ } }, "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^26.6.2", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/@jest/console/node_modules/ansi-styles": { @@ -4090,21 +3074,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/console/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/console/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4132,23 +3101,6 @@ "node": ">=8" } }, - "node_modules/@jest/console/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jest/console/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4171,102 +3123,42 @@ } }, "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "ci-info": "^3.2.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/@jest/core/node_modules/ansi-styles": { @@ -4300,21 +3192,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/core/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4333,12 +3210,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/@jest/core/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4348,89 +3219,21 @@ "node": ">=8" } }, - "node_modules/@jest/core/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "node_modules/@jest/core/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" + "glob": "^7.1.3" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/core/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" + "bin": { + "rimraf": "bin.js" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/@jest/core/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4452,504 +3255,88 @@ "node": ">=8" } }, - "node_modules/@jest/core/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", "@types/node": "*", - "jest-mock": "^29.5.0" + "jest-mock": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/environment/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/environment/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/environment/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/environment/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/fake-timers/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/fake-timers/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/fake-timers/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/globals/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/globals/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/globals/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/globals/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-instrument": "^4.0.3", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", "slash": "^3.0.0", + "source-map": "^0.6.0", "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "optionalDependencies": { + "node-notifier": "^8.0.0" } }, "node_modules/@jest/reporters/node_modules/ansi-styles": { @@ -4983,21 +3370,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/reporters/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5016,12 +3388,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/reporters/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/@jest/reporters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5031,55 +3397,19 @@ "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/reporters/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, "node_modules/@jest/reporters/node_modules/slash": { @@ -5091,6 +3421,15 @@ "node": ">=8" } }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@jest/reporters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5103,340 +3442,58 @@ "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-result/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/test-result/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/test-result/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-result/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", "dev": true, "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-sequencer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/test-sequencer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/test-sequencer/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/test-sequencer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/@jest/transform": { @@ -5718,64 +3775,6 @@ "publish-sourcemap": "scripts/publish-cli.js" } }, - "node_modules/@newrelic/publish-sourcemap/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/@newrelic/publish-sourcemap/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@newrelic/publish-sourcemap/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@newrelic/publish-sourcemap/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@newrelic/publish-sourcemap/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -6036,13 +4035,13 @@ } } }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, "engines": { - "node": ">=12.22.0" + "node": ">= 8" } }, "node_modules/@pnpm/network.ca-file": { @@ -6057,19 +4056,12 @@ "node": ">=12.22.0" } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "node_modules/@pnpm/npm-conf": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.1.1.tgz", - "integrity": "sha512-yfRcuupmxxeDOSxvw4g+wFCrGiPD0L32f5WMzqMXp7Rl93EOCdFiDcaSNnZ10Up9GdNqkj70UTa8hfhPFphaZA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", + "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", "dev": true, "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" }, @@ -6084,9 +4076,9 @@ "dev": true }, "node_modules/@popperjs/core": { - "version": "2.11.7", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", - "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -6104,9 +4096,9 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", - "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.1.tgz", + "integrity": "sha512-HikrdY+IDgRfRYlCTGUQaiCxxDDgM1mQrRbZ6S1HFZX5ZYuJ4o8EstNmhTwHdPl2rTmLxzwSu0b3AyeyTlR+RA==", "dependencies": { "immer": "^9.0.16", "redux": "^4.2.0", @@ -6127,9 +4119,9 @@ } }, "node_modules/@reduxjs/toolkit/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", "dependencies": { "@babel/runtime": "^7.9.2" } @@ -6151,9 +4143,9 @@ } }, "node_modules/@restart/hooks": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.9.tgz", - "integrity": "sha512-3BekqcwB6Umeya+16XPooARn4qEPW6vNvwYnlofIYe6h9qG1/VeD7UvShCWx11eFz5ELYmwIEshz+MkPX3wjcQ==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.8.tgz", + "integrity": "sha512-Ivvp1FZ0Lja80iUTYAhbzy+stxwO7FbPHP95ypCtIh0wyOLiayQywXhVJ2ZYP5S1AjW2GmKHeRU4UglMwTG2sA==", "dependencies": { "dequal": "^2.0.2" }, @@ -6231,9 +4223,9 @@ } }, "node_modules/@semantic-release/github/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -6324,9 +4316,9 @@ } }, "node_modules/@semantic-release/npm/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -6466,28 +4458,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^2.0.0" + "@sinonjs/commons": "^1.7.0" } }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { @@ -6892,6 +4878,38 @@ "node": ">=8" } }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/@testing-library/dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7024,9 +5042,9 @@ } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", - "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", "dev": true, "dependencies": { "@types/express-serve-static-core": "*", @@ -7039,9 +5057,9 @@ "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" }, "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -7065,27 +5083,26 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.16.tgz", + "integrity": "sha512-LkKpqRZ7zqXJuvoELakaFYuETHjZkSol8EV6cNnyishutDBCCdv6+dsKPbKkCcIk57qRphOLY5sEgClw1bO3gA==", "dev": true, "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", + "@types/express-serve-static-core": "^4.17.31", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.34", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", - "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/range-parser": "*" } }, "node_modules/@types/fs-extra": { @@ -7132,9 +5149,9 @@ "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", "dev": true, "dependencies": { "@types/node": "*" @@ -7182,9 +5199,9 @@ "dev": true }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "node_modules/@types/minimatch": { @@ -7200,9 +5217,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -7240,9 +5257,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "17.0.56", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.56.tgz", - "integrity": "sha512-Z13f9Qz7Hg8f2g2NsBjiJSVWmON2b3K8RIqFK8mMKCIgvD0CD0ZChTukz87H3lI28X3ukXoNFGzo3ZW1ICTtPA==", + "version": "18.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", + "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -7250,14 +5267,25 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", - "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", + "version": "17.0.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.18.tgz", + "integrity": "sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw==", "dev": true, "dependencies": { "@types/react": "^17" } }, + "node_modules/@types/react-dom/node_modules/@types/react": { + "version": "17.0.53", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", + "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/react-redux": { "version": "7.1.25", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", @@ -7284,9 +5312,9 @@ "dev": true }, "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/schema-utils": { "version": "2.4.0", @@ -7298,16 +5326,6 @@ "schema-utils": "*" } }, - "node_modules/@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -7318,9 +5336,9 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dev": true, "dependencies": { "@types/mime": "*", @@ -7336,17 +5354,106 @@ "@types/node": "*" } }, + "node_modules/@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/tapable": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", + "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@types/uglify-js": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.1.tgz", + "integrity": "sha512-GkewRA4i5oXacU/n4MA9+bLgt5/L3F1mKrYvFGm7r2ouLXhRKjuWwo9XHNnbx6WF3vlGW21S3fCvgqxvxXXc5g==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/@types/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@types/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" }, + "node_modules/@types/webpack": { + "version": "4.41.33", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz", + "integrity": "sha512-PPajH64Ft2vWevkerISMtnZ8rTs4YmRbs+23c402J0INmxDKCrhZNvwZYtzx96gY2wAtXdrK1BS2fiC8MlLr3g==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "anymatch": "^3.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/@types/webpack-sources": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.0.tgz", + "integrity": "sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "node_modules/@types/webpack-sources/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -7875,14 +5982,23 @@ "dev": true }, "node_modules/aria-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", - "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.2.tgz", + "integrity": "sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA==", "dependencies": { "tslib": "^2.0.0" }, "engines": { "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.9.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/aria-query": { @@ -7925,6 +6041,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -8191,9 +6308,9 @@ } }, "node_modules/axe-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", - "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.1.tgz", + "integrity": "sha512-sCXXUhA+cljomZ3ZAwb8i1p3oOlkABzPy08ZDAoGcYuvtBPlQ1Ytde129ArXyHWDhfeewq7rlx9F+cUx2SSlkg==", "dev": true, "engines": { "node": ">=4" @@ -8221,9 +6338,9 @@ } }, "node_modules/axios-mock-adapter": { - "version": "1.21.4", - "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.21.4.tgz", - "integrity": "sha512-ztnENm28ONAKeRXC/6SUW6pcsaXbThKq93MRDRAA47LYTzrGSDoO/DCr1NHz7jApEl95DrBoGPvZ0r9xtSbjqw==", + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.21.2.tgz", + "integrity": "sha512-jzyNxU3JzB2XVhplZboUcF0YDs7xuExzoRSHXPHr+UQajaGmcTqvkkUADgkVI2WkGlpZ1zZlMVdcTMU0ejV8zQ==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", @@ -8808,39 +6925,12 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bonjour-service": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", @@ -9131,9 +7221,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001474", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz", - "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==", + "version": "1.0.30001489", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz", + "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==", "dev": true, "funding": [ { @@ -9261,11 +7351,6 @@ "isarray": "0.0.1" } }, - "node_modules/cast-array/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -9373,9 +7458,9 @@ "dev": true }, "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", "dev": true }, "node_modules/class-utils": { @@ -9614,27 +7699,27 @@ "dev": true }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", + "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" } }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -9643,6 +7728,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9779,9 +7865,9 @@ "dev": true }, "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, "node_modules/colors": { @@ -9964,9 +8050,9 @@ ] }, "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true, "engines": { "node": ">= 0.6" @@ -10101,9 +8187,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.30.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.2.tgz", - "integrity": "sha512-p/npFUJXXBkCCTIlEGBdghofn00jWG6ZOtdoIXSJmAu2QBvN0IqpZXWweOytcwE6cfx8ZvVUy1vw8zxhe4Y2vg==", + "version": "3.27.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.27.2.tgz", + "integrity": "sha512-Cf2jqAbXgWH3VVzjyaaFkY1EBazxugUepGymDoeteyYr9ByX51kD2jdHZlsEF/xnJMyN3Prua7mQuzwMg6Zc9A==", "dev": true, "hasInstallScript": true, "funding": { @@ -10209,9 +8295,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "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" @@ -10418,9 +8504,9 @@ "dev": true }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/cycle": { "version": "1.0.3", @@ -10575,28 +8661,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, "node_modules/deep-diff": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", "integrity": "sha512-yVn6RZmHiGnxRKR9sJb3iVV2XTF1Ghh2DiWRZ3dMnGc43yUdWWF/kX6lQyk3+P84iprfWKU/8zFTrlkvtFm1ug==" }, "node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", "dev": true, "dependencies": { + "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", + "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -10604,7 +8685,7 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", @@ -10908,12 +8989,12 @@ "integrity": "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==" }, "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/dir-glob": { @@ -11136,9 +9217,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.352", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.352.tgz", - "integrity": "sha512-ikFUEyu5/q+wJpMOxWxTaEVk2M1qKqTGKKyfJmod1CPZxKfYnxVS41/GCBQg21ItBpZybyN8sNpRqCUGm+Zc4Q==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "node_modules/email-prop-type": { @@ -11158,12 +9239,12 @@ } }, "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -11203,9 +9284,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", - "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", + "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -11478,17 +9559,17 @@ } }, "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -11496,8 +9577,8 @@ "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", @@ -11505,12 +9586,11 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", "typed-array-length": "^1.0.4", @@ -11566,6 +9646,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/es-module-lexer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", @@ -12123,9 +10209,9 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -12147,9 +10233,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "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" @@ -12207,14 +10293,14 @@ } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -12245,9 +10331,9 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -12597,45 +10683,20 @@ } }, "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/expect/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/expect/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/expect/node_modules/ansi-styles": { @@ -12653,37 +10714,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expect/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/expect/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/expect/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -12702,44 +10732,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/expect/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/expect/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/expect/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -12818,21 +10810,6 @@ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "dev": true }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -13254,9 +11231,9 @@ "dev": true }, "node_modules/focus-lock": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.11.6.tgz", - "integrity": "sha512-KSuV3ur4gf2KqMNoZx3nXNVhqCkn42GuTYCX4tXPEwf0MjpFQmNMiN6m7dXaUXgIoivL6/65agoUMg4RLS0Vbg==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.11.4.tgz", + "integrity": "sha512-LzZWJcOBIcHslQ46N3SUu/760iLPSrUtp8omM4gh9du438V2CQdks8TcOu1yvmu2C68nVOBnl1WFiKGPbQ8L6g==", "dependencies": { "tslib": "^2.0.3" }, @@ -13309,9 +11286,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", + "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.8.3", @@ -13494,16 +11471,17 @@ "dev": true }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 6" + "node": ">= 0.12" } }, "node_modules/form-urlencoded": { @@ -13632,19 +11610,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -13953,9 +11918,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/grapheme-splitter": { @@ -14355,9 +12320,9 @@ } }, "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -14367,9 +12332,9 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", + "domhandler": "^5.0.2", "domutils": "^3.0.1", - "entities": "^4.4.0" + "entities": "^4.3.0" } }, "node_modules/http-deceiver": { @@ -14648,12 +12613,12 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" @@ -14805,18 +12770,18 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "version": "9.0.18", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.18.tgz", + "integrity": "sha512-eAPNpsj7Ax1q6Y/3lm2PmlwRcFzpON7HSNQ3ru5WQH1/PSpnyed/HpNOELl2CxLKoj4r+bAHgdyKqW5gc2Se1A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" } }, "node_modules/immutable": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", - "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==" + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", + "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -15012,11 +12977,11 @@ } }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dependencies": { - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -15696,10 +13661,9 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/isexe": { "version": "2.0.0", @@ -15859,58 +13823,50 @@ } }, "node_modules/jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^26.6.3", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^26.6.3" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">= 10.14.2" } }, "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", "dev": true, "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-changed-files/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" }, "engines": { @@ -15921,26 +13877,20 @@ } }, "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-changed-files/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/jest-changed-files/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -15980,264 +13930,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/jest-circus/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", "dev": true, "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", "prompts": "^2.0.1", - "yargs": "^17.3.1" + "yargs": "^15.4.1" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-cli/node_modules/ansi-styles": { @@ -16255,6 +13972,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-cli/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -16271,19 +13997,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-cli/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "node_modules/jest-cli/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, "node_modules/jest-cli/node_modules/color-convert": { @@ -16304,6 +14026,25 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/jest-cli/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/jest-cli/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -16313,21 +14054,66 @@ "node": ">=8" } }, - "node_modules/jest-cli/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "node_modules/jest-cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "p-locate": "^4.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-cli/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/jest-cli/node_modules/supports-color": { @@ -16342,103 +14128,98 @@ "node": ">=8" } }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "node_modules/jest-cli/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/jest-cli/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" }, "peerDependencies": { - "@types/node": "*", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, "ts-node": { "optional": true } } }, - "node_modules/jest-config/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -16454,58 +14235,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-config/node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -16522,21 +14251,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-config/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -16555,12 +14269,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-config/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/jest-config/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -16570,98 +14278,6 @@ "node": ">=8" } }, - "node_modules/jest-config/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-config/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/jest-config/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-config/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16674,32 +14290,19 @@ "node": ">=8" } }, - "node_modules/jest-config/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-diff/node_modules/ansi-styles": { @@ -16760,38 +14363,6 @@ "node": ">=8" } }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16805,57 +14376,31 @@ } }, "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", + "@jest/types": "^26.6.2", "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-each/node_modules/ansi-styles": { @@ -16889,21 +14434,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-each/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-each/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -16931,55 +14461,6 @@ "node": ">=8" } }, - "node_modules/jest-each/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-each/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -17010,31 +14491,16 @@ "node": ">= 10.14.2" } }, - "node_modules/jest-environment-jsdom/node_modules/@jest/environment": { + "node_modules/jest-environment-node": { "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", "dev": true, "dependencies": { + "@jest/environment": "^26.6.2", "@jest/fake-timers": "^26.6.2", "@jest/types": "^26.6.2", "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", "jest-mock": "^26.6.2", "jest-util": "^26.6.2" }, @@ -17042,309 +14508,13 @@ "node": ">= 10.14.2" } }, - "node_modules/jest-environment-jsdom/node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-environment-jsdom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-environment-jsdom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-environment-jsdom/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-environment-node/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "dev": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-haste-map": { @@ -17374,41 +14544,6 @@ "fsevents": "^2.1.2" } }, - "node_modules/jest-haste-map/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-jasmine2": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", @@ -17438,132 +14573,6 @@ "node": ">= 10.14.2" } }, - "node_modules/jest-jasmine2/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/jest-jasmine2/node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, "node_modules/jest-jasmine2/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -17595,23 +14604,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-jasmine2/node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "node_modules/jest-jasmine2/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -17630,63 +14622,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-jasmine2/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-jasmine2/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -17696,450 +14631,6 @@ "node": ">=8" } }, - "node_modules/jest-jasmine2/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-jasmine2/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-jasmine2/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-jasmine2/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-jasmine2/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-jasmine2/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-jasmine2/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-jasmine2/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-jasmine2/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18152,134 +14643,32 @@ "node": ">=8" } }, - "node_modules/jest-jasmine2/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jest-jasmine2/node_modules/yargs-parser/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", "dev": true, "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { @@ -18340,38 +14729,6 @@ "node": ">=8" } }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-matcher-utils/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18385,49 +14742,23 @@ } }, "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-message-util/node_modules/ansi-styles": { @@ -18488,38 +14819,6 @@ "node": ">=8" } }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-message-util/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -18542,145 +14841,16 @@ } }, "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" + "@jest/types": "^26.6.2", + "@types/node": "*" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-mock/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-mock/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, "node_modules/jest-pnp-resolver": { @@ -18710,71 +14880,36 @@ } }, "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", "dev": true, "dependencies": { + "@jest/types": "^26.6.2", "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", + "graceful-fs": "^4.2.4", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", "slash": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.14.2" } }, "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", "dev": true, "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-resolve/node_modules/ansi-styles": { @@ -18808,21 +14943,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-resolve/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -18850,57 +14970,6 @@ "node": ">=8" } }, - "node_modules/jest-resolve/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-resolve/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-resolve/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -18923,87 +14992,34 @@ } }, "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", "dev": true, "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-runner/node_modules/ansi-styles": { @@ -19037,21 +15053,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-runner/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -19070,12 +15071,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-runner/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/jest-runner/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -19085,66 +15080,6 @@ "node": ">=8" } }, - "node_modules/jest-runner/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-runner/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-runner/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19157,102 +15092,45 @@ "node": ">=8" } }, - "node_modules/jest-runner/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", "dev": true, "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", + "cjs-module-lexer": "^0.6.0", "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "bin": { + "jest-runtime": "bin/jest-runtime.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-runtime/node_modules/ansi-styles": { @@ -19270,6 +15148,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-runtime/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19286,19 +15173,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "node_modules/jest-runtime/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, "node_modules/jest-runtime/node_modules/color-convert": { @@ -19319,12 +15202,25 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-runtime/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/jest-runtime/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/jest-runtime/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runtime/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -19334,55 +15230,52 @@ "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "node_modules/jest-runtime/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "node_modules/jest-runtime/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "p-locate": "^4.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runtime/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/jest-runtime/node_modules/slash": { @@ -19394,6 +15287,20 @@ "node": ">=8" } }, + "node_modules/jest-runtime/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runtime/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19406,17 +15313,59 @@ "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "node_modules/jest-runtime/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/jest-serializer": { @@ -19433,89 +15382,30 @@ } }, "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" + "pretty-format": "^26.6.2", + "semver": "^7.3.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-snapshot/node_modules/ansi-styles": { @@ -19549,21 +15439,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-snapshot/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -19582,12 +15457,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-snapshot/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/jest-snapshot/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -19597,57 +15466,6 @@ "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-snapshot/node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-snapshot/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -19660,42 +15478,10 @@ "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -19707,15 +15493,6 @@ "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-snapshot/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19728,19 +15505,6 @@ "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/jest-snapshot/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -19835,46 +15599,20 @@ } }, "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", "dev": true, "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", + "jest-get-type": "^26.3.0", "leven": "^3.1.0", - "pretty-format": "^29.5.0" + "pretty-format": "^26.6.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-validate/node_modules/ansi-styles": { @@ -19935,38 +15673,6 @@ "node": ">=8" } }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-validate/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19980,48 +15686,21 @@ } }, "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", "dev": true, "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", + "jest-util": "^26.6.2", "string-length": "^4.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.14.2" } }, "node_modules/jest-watcher/node_modules/ansi-styles": { @@ -20055,21 +15734,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-watcher/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/jest-watcher/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -20097,23 +15761,6 @@ "node": ">=8" } }, - "node_modules/jest-watcher/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-watcher/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -20127,122 +15774,19 @@ } }, "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.5.0", "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "supports-color": "^7.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.13.0" } }, - "node_modules/jest-worker/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-worker/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-worker/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-worker/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-worker/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -20252,123 +15796,7 @@ "node": ">=8" } }, - "node_modules/jest-worker/node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -20390,15 +15818,15 @@ } }, "node_modules/jquery": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz", - "integrity": "sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.3.tgz", + "integrity": "sha512-bZ5Sy3YzKo9Fyc8wH2iIQK4JImJ6R0GWI9kL1/k7Z91ZBNgkRXE6U0JfHIizZbort8ZunhSI3jw9I6253ahKfg==", "peer": true }, "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", "dev": true, "funding": { "type": "opencollective", @@ -21012,43 +16440,42 @@ } }, "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", "dev": true, "bin": { "lz-string": "bin/bin.js" } }, "node_modules/mailto-link": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-2.0.0.tgz", - "integrity": "sha512-b5FErkZ4t6mpH1IFZSw7Mm2IQHXQ2R0/5Q4xd7Rv8dVkWvE54mFG/UW7HjfFazXFjXTNsM+dSX2tTeIDrV9K9A==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-1.0.0.tgz", + "integrity": "sha512-DVRvtkoeXLHAbH+S+9m3ILIdnvQsSc9IvJwfEclQVD8e8FhzwA5Mtw4Q0XXYr/sAziw/HsMc/gpGAI+5w6ohIw==", "dependencies": { "assert-ok": "~1.0.0", - "cast-array": "~1.0.1", + "cast-array": "~1.0.0", "object-filter": "~1.0.2", - "query-string": "~7.0.0" - }, - "engines": { - "node": ">= 12" + "query-string": "~2.4.1" } }, "node_modules/mailto-link/node_modules/query-string": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz", - "integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-2.4.2.tgz", + "integrity": "sha512-Y+OMYUuY7HxznI6WBN822fi/FMvnCTiuqd6KNcidPColOmMWPoV1RGYyyzObve1T/dD1i0ZgCCbO8ytu0ZUrkA==", "dependencies": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" + "strict-uri-encode": "^1.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" + } + }, + "node_modules/mailto-link/node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/make-dir": { @@ -21116,9 +16543,9 @@ } }, "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -21484,9 +16911,9 @@ } }, "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -21725,9 +17152,9 @@ } }, "node_modules/node-abi/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -21761,9 +17188,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -21824,9 +17251,9 @@ } }, "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "optional": true, "dependencies": { @@ -21847,9 +17274,9 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==", "dev": true }, "node_modules/normalize-package-data": { @@ -21903,9 +17330,9 @@ } }, "node_modules/npm": { - "version": "8.19.4", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.19.4.tgz", - "integrity": "sha512-3HANl8i9DKnUA89P4KEgVNN28EjSeDCmvEqbzOAuxCFDzdBZzjUl99zgnGpOUumvW5lvJo2HKcjrsc+tfyv1Hw==", + "version": "8.19.3", + "resolved": "https://registry.npmjs.org/npm/-/npm-8.19.3.tgz", + "integrity": "sha512-0QjmyPtDxSyMWWD8I91QGbrgx9KzbV6C9FK1liEb/K0zppiZkr5KxXc990G+LzPwBHDfRjUBlO9T1qZ08vl9mA==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -21979,129 +17406,7 @@ "treeverse", "validate-npm-package-name", "which", - "write-file-atomic", - "@colors/colors", - "@gar/promisify", - "@npmcli/disparity-colors", - "@npmcli/git", - "@npmcli/installed-package-contents", - "@npmcli/metavuln-calculator", - "@npmcli/move-file", - "@npmcli/name-from-folder", - "@npmcli/node-gyp", - "@npmcli/promise-spawn", - "@npmcli/query", - "@tootallnate/once", - "agent-base", - "agentkeepalive", - "aggregate-error", - "ansi-regex", - "ansi-styles", - "aproba", - "are-we-there-yet", - "asap", - "balanced-match", - "bin-links", - "binary-extensions", - "brace-expansion", - "builtins", - "cidr-regex", - "clean-stack", - "clone", - "cmd-shim", - "color-convert", - "color-name", - "color-support", - "common-ancestor-path", - "concat-map", - "console-control-strings", - "cssesc", - "debug", - "debuglog", - "defaults", - "delegates", - "depd", - "dezalgo", - "diff", - "emoji-regex", - "encoding", - "env-paths", - "err-code", - "fs.realpath", - "function-bind", - "gauge", - "has", - "has-flag", - "has-unicode", - "http-cache-semantics", - "http-proxy-agent", - "https-proxy-agent", - "humanize-ms", - "iconv-lite", - "ignore-walk", - "imurmurhash", - "indent-string", - "infer-owner", - "inflight", - "inherits", - "ip", - "ip-regex", - "is-core-module", - "is-fullwidth-code-point", - "is-lambda", - "isexe", - "json-stringify-nice", - "jsonparse", - "just-diff", - "just-diff-apply", - "lru-cache", - "minipass-collect", - "minipass-fetch", - "minipass-flush", - "minipass-json-stream", - "minipass-sized", - "minizlib", - "mute-stream", - "negotiator", - "normalize-package-data", - "npm-bundled", - "npm-normalize-package-bin", - "npm-packlist", - "once", - "path-is-absolute", - "postcss-selector-parser", - "promise-all-reject-late", - "promise-call-limit", - "promise-inflight", - "promise-retry", - "promzard", - "read-cmd-shim", - "readable-stream", - "retry", - "safe-buffer", - "safer-buffer", - "set-blocking", - "signal-exit", - "smart-buffer", - "socks", - "socks-proxy-agent", - "spdx-correct", - "spdx-exceptions", - "spdx-expression-parse", - "spdx-license-ids", - "string_decoder", - "string-width", - "strip-ansi", - "supports-color", - "unique-filename", - "unique-slug", - "util-deprecate", - "validate-npm-package-license", - "walk-up-path", - "wcwidth", - "wide-align", - "wrappy", - "yallist" + "write-file-atomic" ], "dev": true, "dependencies": { @@ -23073,7 +18378,7 @@ } }, "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.1", + "version": "4.1.0", "dev": true, "inBundle": true, "license": "BSD-2-Clause" @@ -24933,9 +20238,9 @@ } }, "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", @@ -25776,9 +21081,9 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -26149,9 +21454,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", - "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -26177,91 +21482,6 @@ "postcss": "^8.2.15" } }, - "node_modules/postcss-svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/postcss-svgo/node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/postcss-svgo/node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/postcss-svgo/node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/postcss-svgo/node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - }, - "node_modules/postcss-svgo/node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/postcss-svgo/node_modules/svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, "node_modules/postcss-unique-selectors": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", @@ -26329,31 +21549,53 @@ } }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10" } }, "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/pretty-format/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -26483,22 +21725,6 @@ "node": ">=6" } }, - "node_modules/pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, "node_modules/purgecss": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz", @@ -26574,9 +21800,9 @@ } }, "node_modules/qs": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", - "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -26706,18 +21932,6 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -27004,17 +22218,17 @@ "dev": true }, "node_modules/react-fast-compare": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", - "integrity": "sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, "node_modules/react-focus-lock": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.4.tgz", - "integrity": "sha512-7pEdXyMseqm3kVjhdVH18sovparAzLg5h6WvIx7/Ck3ekjhrrDMEegHSa3swwC8wgfdd7DIdUVRGeiHT9/7Sgg==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.2.tgz", + "integrity": "sha512-5JfrsOKyA5Zn3h958mk7bAcfphr24jPoMoznJ8vaJF6fUrPQ8zrtEd3ILLOK8P5jvGxdMd96OxWNjDzATfR2qw==", "dependencies": { "@babel/runtime": "^7.0.0", - "focus-lock": "^0.11.6", + "focus-lock": "^0.11.2", "prop-types": "^15.6.2", "react-clientside-effect": "^1.2.6", "use-callback-ref": "^1.3.0", @@ -27031,9 +22245,9 @@ } }, "node_modules/react-focus-on": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.8.0.tgz", - "integrity": "sha512-xuH4jUPeRZ4oE0a85d7pA8pPhotb4U2iWK1CBATP/Xao/WEFHUZxxi5+ffWovjjUT7k53mXDm53TE2pvjLccsw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.7.0.tgz", + "integrity": "sha512-TsCnbJr4qjqFatJ4U1N8qGSZH+FUzxJ5mJ5ta7TY2YnDmUbGGmcvZMTZgGjQ1fl6vlztsMyg6YyZlPAeeIhEUg==", "dependencies": { "aria-hidden": "^1.2.2", "react-focus-lock": "^2.9.2", @@ -27107,9 +22321,9 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-loading-skeleton": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.2.1.tgz", - "integrity": "sha512-e1KwEOuBa1REXWoseELIJXlsqWTCHL5IQnqhVhI33WmnuTK7LK1DXl4mmcOLsWVcwqXeOATU9VFJEjz2ytZSng==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.3.1.tgz", + "integrity": "sha512-NilqqwMh2v9omN7LteiDloEVpFyMIa0VGqF+ukqp0ncVlYu1sKYbYGX9JEl+GtOT9TKsh04zCHAbavnQ2USldA==", "peerDependencies": { "react": ">=16.8.0" } @@ -27308,11 +22522,6 @@ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" }, - "node_modules/react-router-redux/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, "node_modules/react-router-redux/node_modules/path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", @@ -27338,11 +22547,6 @@ "react": ">=15" } }, - "node_modules/react-router/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, "node_modules/react-router/node_modules/path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", @@ -27535,9 +22739,9 @@ } }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -27754,12 +22958,12 @@ } }, "node_modules/registry-auth-token": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", - "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", + "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", "dev": true, "dependencies": { - "@pnpm/npm-conf": "^2.1.0" + "@pnpm/npm-conf": "^1.0.4" }, "engines": { "node": ">=14" @@ -28028,15 +23232,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/restore-cursor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", @@ -28467,9 +23662,9 @@ } }, "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -28544,23 +23739,6 @@ "node": ">=16 || ^14.17" } }, - "node_modules/semantic-release/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/semantic-release/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/semantic-release/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -28617,15 +23795,6 @@ "node": ">=10.17.0" } }, - "node_modules/semantic-release/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/semantic-release/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -28692,44 +23861,12 @@ "node": ">=10" } }, - "node_modules/semantic-release/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/semantic-release/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/semantic-release/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -29041,9 +24178,9 @@ } }, "node_modules/sharp/node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -29083,9 +24220,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", - "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -29432,15 +24569,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -29459,12 +24587,12 @@ "dev": true }, "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -29496,6 +24624,18 @@ "webpack": "^5.72.1" } }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -29511,9 +24651,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -29554,9 +24694,9 @@ } }, "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -29580,9 +24720,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "node_modules/spdy": { @@ -29616,9 +24756,9 @@ } }, "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -29671,9 +24811,9 @@ } }, "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -30110,20 +25250,6 @@ "ms": "^2.1.1" } }, - "node_modules/superagent/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/superagent/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -30248,9 +25374,9 @@ "dev": true }, "node_modules/tabbable": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-4.0.0.tgz", + "integrity": "sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==" }, "node_modules/tabtab": { "version": "2.2.2", @@ -30496,9 +25622,9 @@ } }, "node_modules/terser": { - "version": "5.16.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz", - "integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==", + "version": "5.17.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.6.tgz", + "integrity": "sha512-V8QHcs8YuyLkLHsJO5ucyff1ykrLVsR4dNnS//L5Y3NiSXpbK1J+WMVUs67eI0KTxs9JtHhgEQpXQVHlHI92DQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -30514,16 +25640,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.16.8" }, "engines": { "node": ">= 10.13.0" @@ -30603,25 +25729,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -30673,9 +25780,9 @@ } }, "node_modules/through2/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -30885,9 +25992,9 @@ } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -30976,9 +26083,9 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -31358,17 +26465,26 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" }, "engines": { - "node": ">=10.12.0" + "node": ">=10.10.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" } }, "node_modules/validate-npm-package-license": { @@ -31736,15 +26852,15 @@ "dev": true }, "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", + "ajv": "^8.8.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "ajv-keywords": "^5.0.0" }, "engines": { "node": ">= 12.13.0" @@ -31863,15 +26979,15 @@ } }, "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz", - "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", + "ajv": "^8.8.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "ajv-keywords": "^5.0.0" }, "engines": { "node": ">= 12.13.0" @@ -31955,24 +27071,6 @@ "acorn": "^8" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack/node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -32014,18 +27112,6 @@ "iconv-lite": "0.4.24" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-fetch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", @@ -32319,20 +27405,21 @@ } }, "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, "dependencies": { - "cliui": "^8.0.1", + "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^4.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">=12" + "node": ">=10" } }, "node_modules/yargs-parser": { @@ -32347,12 +27434,14 @@ "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -32361,6 +27450,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -32370,14 +27460,6 @@ "node": ">=8" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index e4ca401..b690dc9 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "fetch-mock": "^6.5.2", "husky": "2.7.0", "identity-obj-proxy": "^3.0.0", - "jest": "29.3.1", + "jest": "^26.6.3", "react-dev-utils": "^12.0.1", "react-test-renderer": "^16.10.1", "reactifex": "1.1.1", diff --git a/src/components/GradebookFilters/__snapshots__/index.test.jsx.snap b/src/components/GradebookFilters/__snapshots__/index.test.jsx.snap index 4ee3e95..fe9adf0 100644 --- a/src/components/GradebookFilters/__snapshots__/index.test.jsx.snap +++ b/src/components/GradebookFilters/__snapshots__/index.test.jsx.snap @@ -16,7 +16,7 @@ exports[`GradebookFilters render snapshot 1`] = ` className="p-1" iconAs="Icon" onClick={[MockFunction hook.closeMenu]} - src={[Function]} + src="Close" /> { const includeCourseRoleMembers = selectors.filters.useIncludeCourseRoleMembers(); const updateIncludeCourseRoleMembers = actions.filters.useUpdateIncludeCourseRoleMembers(); - const closeMenu = thunkActions.app.useCloseFilterMenu(); + const closeMenu = thunkActions.app.filterMenu.useCloseMenu(); const fetchGrades = thunkActions.grades.useFetchGrades(); const handleIncludeTeamMembersChange = ({ target: { checked } }) => { diff --git a/src/components/GradebookFilters/hooks.test.jsx b/src/components/GradebookFilters/hooks.test.jsx index 2900c92..5722c52 100644 --- a/src/components/GradebookFilters/hooks.test.jsx +++ b/src/components/GradebookFilters/hooks.test.jsx @@ -9,7 +9,9 @@ jest.mock('data/redux/hooks', () => ({ filters: { useIncludeCourseRoleMembers: jest.fn() }, }, thunkActions: { - app: { useCloseFilterMenu: jest.fn() }, + app: { + filterMenu: { useCloseMenu: jest.fn() }, + }, grades: { useFetchGrades: jest.fn() }, }, })); @@ -18,7 +20,7 @@ selectors.filters.useIncludeCourseRoleMembers.mockReturnValue(true); const updateIncludeCourseRoleMembers = jest.fn(); actions.filters.useUpdateIncludeCourseRoleMembers.mockReturnValue(updateIncludeCourseRoleMembers); const closeFilterMenu = jest.fn(); -thunkActions.app.useCloseFilterMenu.mockReturnValue(closeFilterMenu); +thunkActions.app.filterMenu.useCloseMenu.mockReturnValue(closeFilterMenu); const fetchGrades = jest.fn(); thunkActions.grades.useFetchGrades.mockReturnValue(fetchGrades); @@ -34,7 +36,7 @@ describe('GradebookFiltersData component hooks', () => { it('initializes hooks', () => { expect(actions.filters.useUpdateIncludeCourseRoleMembers).toHaveBeenCalledWith(); expect(selectors.filters.useIncludeCourseRoleMembers).toHaveBeenCalledWith(); - expect(thunkActions.app.useCloseFilterMenu).toHaveBeenCalledWith(); + expect(thunkActions.app.filterMenu.useCloseMenu).toHaveBeenCalledWith(); expect(thunkActions.grades.useFetchGrades).toHaveBeenCalledWith(); }); }); diff --git a/src/components/GradebookHeader/__snapshots__/index.test.jsx.snap b/src/components/GradebookHeader/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..65f2abf --- /dev/null +++ b/src/components/GradebookHeader/__snapshots__/index.test.jsx.snap @@ -0,0 +1,131 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GradebookHeader component render default view shapshot 1`] = ` +
+ + + Back to Dashboard + +

+ Gradebook +

+
+

+ test-course-id +

+
+
+`; + +exports[`GradebookHeader component render frozen grades snapshot: show frozen warning 1`] = ` +
+ + + Back to Dashboard + +

+ Gradebook +

+
+

+ test-course-id +

+
+
+ The grades for this course are now frozen. Editing of grades is no longer allowed. +
+
+`; + +exports[`GradebookHeader component render show bulk management snapshot: show toggle view message button with handleToggleViewClick method 1`] = ` +
+ + + Back to Dashboard + +

+ Gradebook +

+
+

+ test-course-id +

+ +
+
+`; + +exports[`GradebookHeader component render user cannot view gradebook snapshot: show unauthorized warning 1`] = ` +
+ + + Back to Dashboard + +

+ Gradebook +

+
+

+ test-course-id +

+
+
+ You are not authorized to view the gradebook for this course. +
+
+`; diff --git a/src/components/GradebookHeader/__snapshots__/test.jsx.snap b/src/components/GradebookHeader/__snapshots__/test.jsx.snap deleted file mode 100644 index ea7acb8..0000000 --- a/src/components/GradebookHeader/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,261 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GradebookHeader component snapshots default values (grades frozen, cannot view). unauthorized warning, but no grades frozen warning 1`] = ` -
- - - - -

- -

-
-

- fakeID -

-
-
- -
-
-`; - -exports[`GradebookHeader component snapshots grades frozen, can view. grades frozen warning but no unauthorized warning 1`] = ` -
- - - - -

- -

-
-

- fakeID -

-
-
- -
-
-`; - -exports[`GradebookHeader component snapshots grades frozen, cannot view unauthorized warning, and grades frozen warning. 1`] = ` -
- - - - -

- -

-
-

- fakeID -

-
-
- -
-
- -
-
-`; - -exports[`GradebookHeader component snapshots show bulk management, active view is bulkManagementHistory view toggle view button to grades 1`] = ` -
- - - - -

- -

-
-

- fakeID -

- -
-
- -
-
-`; - -exports[`GradebookHeader component snapshots show bulk management, active view is grades view toggle view button to activity log 1`] = ` -
- - - - -

- -

-
-

- fakeID -

- -
-
- -
-
-`; diff --git a/src/components/GradebookHeader/hooks.js b/src/components/GradebookHeader/hooks.js new file mode 100644 index 0000000..58daa58 --- /dev/null +++ b/src/components/GradebookHeader/hooks.js @@ -0,0 +1,35 @@ +import { views } from 'data/constants/app'; +import { actions, selectors } from 'data/redux/hooks'; + +import messages from './messages'; + +export const useGradebookHeaderData = () => { + const activeView = selectors.app.useActiveView(); + const courseId = selectors.app.useCourseId(); + const areGradesFrozen = selectors.assignmentTypes.useAreGradesFrozen(); + const canUserViewGradebook = selectors.roles.useCanUserViewGradebook(); + const showBulkManagement = selectors.root.useShowBulkManagement(); + const setView = actions.app.useSetView(); + + const handleToggleViewClick = () => setView( + activeView === views.grades + ? views.bulkManagementHistory + : views.grades, + ); + + const toggleViewMessage = activeView === views.grades + ? messages.toActivityLog + : messages.toGradesView; + + return { + areGradesFrozen, + canUserViewGradebook, + courseId, + showBulkManagement, + + handleToggleViewClick, + toggleViewMessage, + }; +}; + +export default useGradebookHeaderData; diff --git a/src/components/GradebookHeader/hooks.test.js b/src/components/GradebookHeader/hooks.test.js new file mode 100644 index 0000000..79e73fc --- /dev/null +++ b/src/components/GradebookHeader/hooks.test.js @@ -0,0 +1,90 @@ +import { views } from 'data/constants/app'; +import { actions, selectors } from 'data/redux/hooks'; + +import messages from './messages'; +import useGradebookHeaderData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + app: { + useSetView: jest.fn(), + }, + }, + selectors: { + app: { + useActiveView: jest.fn(), + useCourseId: jest.fn(), + }, + assignmentTypes: { + useAreGradesFrozen: jest.fn(), + }, + roles: { + useCanUserViewGradebook: jest.fn(), + }, + root: { + useShowBulkManagement: jest.fn(), + }, + }, +})); + +const activeView = 'test-active-view'; +selectors.app.useActiveView.mockReturnValue(activeView); +const courseId = 'test-course-id'; +selectors.app.useCourseId.mockReturnValue(courseId); +const areGradesFrozen = 'test-are-grades-frozen'; +selectors.assignmentTypes.useAreGradesFrozen.mockReturnValue(areGradesFrozen); +const canUserViewGradebook = 'test-can-user-view-gradebook'; +selectors.roles.useCanUserViewGradebook.mockReturnValue(canUserViewGradebook); +const showBulkManagement = 'test-show-bulk-management'; +selectors.root.useShowBulkManagement.mockReturnValue(showBulkManagement); + +const setView = jest.fn(); +actions.app.useSetView.mockReturnValue(setView); + +let out; +describe('useGradebookHeaderData hooks', () => { + describe('initialization', () => { + it('initializes redux hooks', () => { + out = useGradebookHeaderData(); + expect(selectors.app.useActiveView).toHaveBeenCalled(); + expect(selectors.app.useCourseId).toHaveBeenCalled(); + expect(selectors.assignmentTypes.useAreGradesFrozen).toHaveBeenCalled(); + expect(selectors.roles.useCanUserViewGradebook).toHaveBeenCalled(); + expect(selectors.root.useShowBulkManagement).toHaveBeenCalled(); + expect(actions.app.useSetView).toHaveBeenCalled(); + }); + }); + describe('output', () => { + test('redux fields', () => { + out = useGradebookHeaderData(); + expect(out.areGradesFrozen).toEqual(areGradesFrozen); + expect(out.canUserViewGradebook).toEqual(canUserViewGradebook); + expect(out.courseId).toEqual(courseId); + expect(out.showBulkManagement).toEqual(showBulkManagement); + }); + describe('handleToggleViewClick', () => { + it('calls setView with bulkManagemnetHistory message if grades view is active', () => { + selectors.app.useActiveView.mockReturnValueOnce(views.grades); + out = useGradebookHeaderData(); + out.handleToggleViewClick(); + expect(setView).toHaveBeenCalledWith(views.bulkManagementHistory); + }); + it('calls setView with grades view if grades view is not active', () => { + out = useGradebookHeaderData(); + out.handleToggleViewClick(); + expect(setView).toHaveBeenCalledWith(views.grades); + }); + }); + describe('toggleViewMessage', () => { + it('returns toActivityLog message if grades view is active', () => { + selectors.app.useActiveView.mockReturnValueOnce(views.grades); + out = useGradebookHeaderData(); + expect(out.toggleViewMessage).toEqual(messages.toActivityLog); + }); + it('returns toGradesView message if grades view is not active', () => { + out = useGradebookHeaderData(); + expect(out.toggleViewMessage).toEqual(messages.toGradesView); + }); + }); + }); +}); diff --git a/src/components/GradebookHeader/index.jsx b/src/components/GradebookHeader/index.jsx index d3d3377..efc8204 100644 --- a/src/components/GradebookHeader/index.jsx +++ b/src/components/GradebookHeader/index.jsx @@ -1,106 +1,50 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { getConfig } from '@edx/frontend-platform'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Button } from '@edx/paragon'; -import { views } from 'data/constants/app'; -import actions from 'data/actions'; -import selectors from 'data/selectors'; - +import { instructorDashboardUrl } from 'data/services/lms/urls'; +import useGradebookHeaderData from './hooks'; import messages from './messages'; -export class GradebookHeader extends React.Component { - constructor(props) { - super(props); - this.handleToggleViewClick = this.handleToggleViewClick.bind(this); - } - - handleToggleViewClick() { - const newView = this.props.activeView === views.grades ? views.bulkManagementHistory : views.grades; - this.props.setView(newView); - } - - get toggleViewMessage() { - return this.props.activeView === views.grades - ? messages.toActivityLog - : messages.toGradesView; - } - - lmsInstructorDashboardUrl = courseId => ( - `${getConfig().LMS_BASE_URL}/courses/${courseId}/instructor` - ); - - render() { - return ( -
- - - - -

- -

-
-

{this.props.courseId}

- { this.props.showBulkManagement && ( - - )} -
- {this.props.areGradesFrozen - && ( -
- -
- )} - {(this.props.canUserViewGradebook === false) && ( -
- -
+export const GradebookHeader = () => { + const { formatMessage } = useIntl(); + const { + areGradesFrozen, + canUserViewGradebook, + courseId, + handleToggleViewClick, + showBulkManagement, + toggleViewMessage, + } = useGradebookHeaderData(); + const dashboardUrl = instructorDashboardUrl(); + return ( +
+ + + {formatMessage(messages.backToDashboard)} + +

{formatMessage(messages.gradebook)}

+
+

{courseId}

+ {showBulkManagement && ( + )}
- ); - } -} - -GradebookHeader.defaultProps = { - // redux - courseId: '', - areGradesFrozen: false, - canUserViewGradebook: false, - showBulkManagement: false, + {areGradesFrozen && ( +
+ {formatMessage(messages.frozenWarning)} +
+ )} + {(canUserViewGradebook === false) && ( +
+ {formatMessage(messages.unauthorizedWarning)} +
+ )} +
+ ); }; -GradebookHeader.propTypes = { - // redux - activeView: PropTypes.string.isRequired, - courseId: PropTypes.string, - areGradesFrozen: PropTypes.bool, - canUserViewGradebook: PropTypes.bool, - setView: PropTypes.func.isRequired, - showBulkManagement: PropTypes.bool, -}; - -export const mapStateToProps = (state) => ({ - activeView: selectors.app.activeView(state), - courseId: selectors.app.courseId(state), - areGradesFrozen: selectors.assignmentTypes.areGradesFrozen(state), - canUserViewGradebook: selectors.roles.canUserViewGradebook(state), - showBulkManagement: selectors.root.showBulkManagement(state), -}); - -export const mapDispatchToProps = { - setView: actions.app.setView, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(GradebookHeader); +export default GradebookHeader; diff --git a/src/components/GradebookHeader/index.test.jsx b/src/components/GradebookHeader/index.test.jsx new file mode 100644 index 0000000..369bdbb --- /dev/null +++ b/src/components/GradebookHeader/index.test.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Button } from '@edx/paragon'; + +import { formatMessage } from 'testUtils'; +import { instructorDashboardUrl } from 'data/services/lms/urls'; + +import useGradebookHeaderData from './hooks'; +import GradebookHeader from '.'; + +jest.mock('./hooks', () => ({ __esModule: true, default: jest.fn() })); +jest.mock('data/services/lms/urls', () => ({ + instructorDashboardUrl: jest.fn(), +})); + +instructorDashboardUrl.mockReturnValue('test-dashboard-url'); + +const hookProps = { + areGradesFrozen: false, + canUserViewGradebook: true, + courseId: 'test-course-id', + handleToggleViewClick: jest.fn().mockName('hooks.handleToggleViewClick'), + showBulkManagement: false, + toggleViewMessage: { defaultMessage: 'toggle-view-message' }, +}; +useGradebookHeaderData.mockReturnValue(hookProps); + +let el; +describe('GradebookHeader component', () => { + beforeAll(() => { + el = shallow(); + }); + describe('behavior', () => { + it('initializes hooks', () => { + expect(useGradebookHeaderData).toHaveBeenCalledWith(); + expect(useIntl).toHaveBeenCalledWith(); + }); + }); + describe('render', () => { + describe('default view', () => { + test('shapshot', () => { + expect(el).toMatchSnapshot(); + }); + }); + describe('show bulk management', () => { + beforeEach(() => { + useGradebookHeaderData.mockReturnValueOnce({ ...hookProps, showBulkManagement: true }); + el = shallow(); + }); + test('snapshot: show toggle view message button with handleToggleViewClick method', () => { + expect(el).toMatchSnapshot(); + const { onClick, children } = el.find(Button).props(); + expect(onClick).toEqual(hookProps.handleToggleViewClick); + expect(children).toEqual(formatMessage(hookProps.toggleViewMessage)); + }); + }); + describe('frozen grades', () => { + beforeEach(() => { + useGradebookHeaderData.mockReturnValueOnce({ ...hookProps, areGradesFrozen: true }); + el = shallow(); + }); + test('snapshot: show frozen warning', () => { + expect(el).toMatchSnapshot(); + }); + }); + describe('user cannot view gradebook', () => { + beforeEach(() => { + useGradebookHeaderData.mockReturnValueOnce({ ...hookProps, canUserViewGradebook: false }); + el = shallow(); + }); + test('snapshot: show unauthorized warning', () => { + expect(el).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/src/components/GradebookHeader/test.jsx b/src/components/GradebookHeader/test.jsx deleted file mode 100644 index 49cebe4..0000000 --- a/src/components/GradebookHeader/test.jsx +++ /dev/null @@ -1,152 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import { Button } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import { views } from 'data/constants/app'; -import messages from './messages'; -import { GradebookHeader, mapDispatchToProps, mapStateToProps } from '.'; - -jest.mock('@edx/paragon', () => ({ - Button: () => 'Button', -})); -jest.mock('@edx/frontend-platform/i18n', () => ({ - defineMessages: m => m, - FormattedMessage: () => 'FormattedMessage', -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { setView: jest.fn() }, - }, -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - activeView: jest.fn(state => ({ aciveView: state })), - courseId: jest.fn(state => ({ courseId: state })), - }, - assignmentTypes: { areGradesFrozen: jest.fn(state => ({ areGradesFrozen: state })) }, - roles: { canUserViewGradebook: jest.fn(state => ({ canUserViewGradebook: state })) }, - root: { showBulkManagement: jest.fn(state => ({ showBulkManagement: state })) }, - }, -})); - -const courseId = 'fakeID'; -describe('GradebookHeader component', () => { - const props = { - activeView: views.grades, - areGradesFrozen: false, - canUserViewGradebook: false, - courseId, - showBulkManagement: false, - }; - beforeEach(() => { - props.setView = jest.fn(); - }); - describe('snapshots', () => { - let el; - beforeEach(() => { - el = shallow(); - el.instance().handleToggleViewClick = jest.fn().mockName('this.handleToggleViewClick'); - }); - describe('default values (grades frozen, cannot view).', () => { - test('unauthorized warning, but no grades frozen warning', () => { - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('grades frozen, cannot view', () => { - test('unauthorized warning, and grades frozen warning.', () => { - el.setProps({ areGradesFrozen: true }); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('grades frozen, can view.', () => { - test('grades frozen warning but no unauthorized warning', () => { - el.setProps({ areGradesFrozen: true, canUserViewGradebook: true }); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('show bulk management, active view is grades view', () => { - test('toggle view button to activity log', () => { - el.setProps({ showBulkManagement: true }); - expect(el.find(Button).getElement()).toEqual(( - - )); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('show bulk management, active view is bulkManagementHistory view', () => { - test('toggle view button to grades', () => { - el.setProps({ showBulkManagement: true, activeView: views.bulkManagementHistory }); - expect(el.find(Button).getElement()).toEqual(( - - )); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - }); - describe('behavior', () => { - let el; - beforeEach(() => { - el = shallow(); - }); - describe('handleToggleViewClick', () => { - test('calls setView with activity view if activeView is grades', () => { - el.instance().handleToggleViewClick(); - expect(props.setView).toHaveBeenCalledWith(views.bulkManagementHistory); - }); - test('calls setView with grades view if activeView is bulkManagementHistory', () => { - el.setProps({ activeView: views.bulkManagementHistory }); - el.instance().handleToggleViewClick(); - expect(props.setView).toHaveBeenCalledWith(views.grades); - }); - }); - }); - describe('mapStateToProps', () => { - let mapped; - const testState = { a: 'test', example: 'state' }; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('activeView from app.activeView', () => { - expect(mapped.activeView).toEqual(selectors.app.activeView(testState)); - }); - test('courseId from app.courseId', () => { - expect(mapped.courseId).toEqual(selectors.app.courseId(testState)); - }); - test('areGradesFrozen from assignmentTypes selector', () => { - expect( - mapped.areGradesFrozen, - ).toEqual(selectors.assignmentTypes.areGradesFrozen(testState)); - }); - test('canUserViewGradebook from roles selector', () => { - expect( - mapped.canUserViewGradebook, - ).toEqual(selectors.roles.canUserViewGradebook(testState)); - }); - test('showBulkManagement from root showBulkManagement selector', () => { - expect(mapped.showBulkManagement).toEqual(selectors.root.showBulkManagement(testState)); - }); - }); - - describe('mapDispatchToProps', () => { - test('setView from actions.app.setView', () => { - expect(mapDispatchToProps.setView).toEqual(actions.app.setView); - }); - }); -}); diff --git a/src/components/GradesView/BulkManagementControls.jsx b/src/components/GradesView/BulkManagementControls.jsx deleted file mode 100644 index d7fcbc9..0000000 --- a/src/components/GradesView/BulkManagementControls.jsx +++ /dev/null @@ -1,71 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { views } from 'data/constants/app'; -import actions from 'data/actions'; -import selectors from 'data/selectors'; - -import NetworkButton from 'components/NetworkButton'; -import ImportGradesButton from './ImportGradesButton'; - -import messages from './BulkManagementControls.messages'; - -/** - * - * Provides download buttons for Bulk Management and Intervention reports, only if - * showBulkManagement is set in redus. - */ -export class BulkManagementControls extends React.Component { - constructor(props) { - super(props); - this.handleClickExportGrades = this.handleClickExportGrades.bind(this); - this.handleViewActivityLog = this.handleViewActivityLog.bind(this); - } - - handleClickExportGrades() { - this.props.downloadBulkGradesReport(); - window.location.assign(this.props.gradeExportUrl); - } - - handleViewActivityLog() { - this.props.setView(views.bulkManagementHistory); - } - - render() { - return this.props.showBulkManagement && ( -
- - -
- ); - } -} - -BulkManagementControls.defaultProps = { - showBulkManagement: false, -}; - -BulkManagementControls.propTypes = { - // redux - downloadBulkGradesReport: PropTypes.func.isRequired, - gradeExportUrl: PropTypes.string.isRequired, - showBulkManagement: PropTypes.bool, - setView: PropTypes.func.isRequired, -}; - -export const mapStateToProps = (state) => ({ - gradeExportUrl: selectors.root.gradeExportUrl(state), - showBulkManagement: selectors.root.showBulkManagement(state), -}); - -export const mapDispatchToProps = { - downloadBulkGradesReport: actions.grades.downloadReport.bulkGrades, - setView: actions.app.setView, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(BulkManagementControls); diff --git a/src/components/GradesView/BulkManagementControls.test.jsx b/src/components/GradesView/BulkManagementControls.test.jsx deleted file mode 100644 index f9fa5e2..0000000 --- a/src/components/GradesView/BulkManagementControls.test.jsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import { views } from 'data/constants/app'; - -import { - BulkManagementControls, - mapStateToProps, - mapDispatchToProps, -} from './BulkManagementControls'; - -jest.mock('./ImportGradesButton', () => 'ImportGradesButton'); -jest.mock('components/NetworkButton', () => 'NetworkButton'); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - root: { - gradeExportUrl: (state) => ({ gradeExportUrl: state }), - interventionExportUrl: (state) => ({ interventionExportUrl: state }), - showBulkManagement: (state) => ({ showBulkManagement: state }), - }, - }, -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { setView: jest.fn() }, - grades: { - downloadReport: { - bulkGrades: jest.fn(), - intervention: jest.fn(), - }, - }, - }, -})); - -describe('BulkManagementControls', () => { - describe('component', () => { - let el; - let props = { - gradeExportUrl: 'gradesGoHere', - interventionExportUrl: 'interventionsGoHere', - }; - beforeEach(() => { - props = { - ...props, - downloadBulkGradesReport: jest.fn(), - downloadInterventionReport: jest.fn(), - setView: jest.fn(), - }; - }); - test('snapshot - empty if showBulkManagement is not truthy', () => { - expect(shallow()).toEqual({}); - }); - describe('behavior', () => { - const oldWindowLocation = window.location; - - beforeAll(() => { - delete window.location; - window.location = Object.defineProperties( - {}, - { - ...Object.getOwnPropertyDescriptors(oldWindowLocation), - assign: { - configurable: true, - value: jest.fn(), - }, - }, - ); - }); - beforeEach(() => { - window.location.assign.mockReset(); - el = shallow(); - }); - afterAll(() => { - // restore `window.location` to the `jsdom` `Location` object - window.location = oldWindowLocation; - }); - describe('handleViewActivityLog', () => { - it('calls props.setView(views.bulkManagementHistory)', () => { - el.instance().handleViewActivityLog(); - expect(props.setView).toHaveBeenCalledWith(views.bulkManagementHistory); - }); - }); - describe('handleClickExportGrades', () => { - const assertions = [ - 'calls props.downloadBulkGradesReport', - 'sets location to props.gradeExportUrl', - ]; - it(assertions.join(' and '), () => { - el.instance().handleClickExportGrades(); - expect(props.downloadBulkGradesReport).toHaveBeenCalled(); - expect(window.location.assign).toHaveBeenCalledWith(props.gradeExportUrl); - }); - }); - }); - }); - - describe('mapStateToProps', () => { - let mapped; - const testState = { do: 'not', test: 'me' }; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('gradeExportUrl from root.gradeExportUrl', () => { - expect(mapped.gradeExportUrl).toEqual(selectors.root.gradeExportUrl(testState)); - }); - test('showBulkManagement from root.showBulkManagement', () => { - expect(mapped.showBulkManagement).toEqual(selectors.root.showBulkManagement(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('downloadBulkGradesReport from actions.grades.downloadReport.bulkGrades', () => { - expect( - mapDispatchToProps.downloadBulkGradesReport, - ).toEqual(actions.grades.downloadReport.bulkGrades); - }); - test('setView from actions.app.setView', () => { - expect(mapDispatchToProps.setView).toEqual(actions.app.setView); - }); - }); -}); diff --git a/src/components/GradesView/BulkManagementControls/__snapshots__/index.test.jsx.snap b/src/components/GradesView/BulkManagementControls/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..a97d82f --- /dev/null +++ b/src/components/GradesView/BulkManagementControls/__snapshots__/index.test.jsx.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`BulkManagementControls render snapshot - show - network and import buttons 1`] = ` +
+ + +
+`; diff --git a/src/components/GradesView/BulkManagementControls/hooks.js b/src/components/GradesView/BulkManagementControls/hooks.js new file mode 100644 index 0000000..bf97022 --- /dev/null +++ b/src/components/GradesView/BulkManagementControls/hooks.js @@ -0,0 +1,18 @@ +import { actions, selectors } from 'data/redux/hooks'; + +export const useBulkManagementControlsData = () => { + const gradeExportUrl = selectors.root.useGradeExportUrl(); + const showBulkManagement = selectors.root.useShowBulkManagement(); + const downloadBulkGradesReport = actions.grades.useDownloadBulkGradesReport(); + + const handleClickExportGrades = () => { + downloadBulkGradesReport(); + window.location.assign(gradeExportUrl); + }; + + return { + show: showBulkManagement, + handleClickExportGrades, + }; +}; +export default useBulkManagementControlsData; diff --git a/src/components/GradesView/BulkManagementControls/hooks.test.js b/src/components/GradesView/BulkManagementControls/hooks.test.js new file mode 100644 index 0000000..62bca61 --- /dev/null +++ b/src/components/GradesView/BulkManagementControls/hooks.test.js @@ -0,0 +1,72 @@ +import { actions, selectors } from 'data/redux/hooks'; + +import useBulkManagementControlsData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + grades: { + useDownloadBulkGradesReport: jest.fn(), + }, + }, + selectors: { + root: { + useGradeExportUrl: jest.fn(), + useShowBulkManagement: jest.fn(), + }, + }, +})); + +const downloadBulkGrades = jest.fn(); +actions.grades.useDownloadBulkGradesReport.mockReturnValue(downloadBulkGrades); +const gradeExportUrl = 'test-grade-export-url'; +selectors.root.useGradeExportUrl.mockReturnValue(gradeExportUrl); +selectors.root.useShowBulkManagement.mockReturnValue(true); + +let hook; +describe('useBulkManagementControlsData', () => { + const oldWindowLocation = window.location; + beforeAll(() => { + delete window.location; + window.location = Object.defineProperties( + {}, + { + ...Object.getOwnPropertyDescriptors(oldWindowLocation), + assign: { configurable: true, value: jest.fn() }, + }, + ); + }); + beforeEach(() => { + window.location.assign.mockReset(); + hook = useBulkManagementControlsData(); + }); + afterAll(() => { + // restore `window.location` to the `jsdom` `Location` object + window.location = oldWindowLocation; + }); + describe('initialization', () => { + it('initializes redux hooks', () => { + expect(selectors.root.useGradeExportUrl).toHaveBeenCalledWith(); + expect(selectors.root.useShowBulkManagement).toHaveBeenCalledWith(); + expect(actions.grades.useDownloadBulkGradesReport).toHaveBeenCalledWith(); + }); + }); + describe('output', () => { + it('forwards show from showBulkManagement', () => { + expect(hook.show).toEqual(true); + selectors.root.useShowBulkManagement.mockReturnValue(false); + hook = useBulkManagementControlsData(); + expect(hook.show).toEqual(false); + }); + describe('handleClickExportGrades', () => { + beforeEach(() => { + hook.handleClickExportGrades(); + }); + it('downloads bulk grades report', () => { + expect(downloadBulkGrades).toHaveBeenCalledWith(); + }); + it('sets window location to grade export url', () => { + expect(window.location.assign).toHaveBeenCalledWith(gradeExportUrl); + }); + }); + }); +}); diff --git a/src/components/GradesView/BulkManagementControls/index.jsx b/src/components/GradesView/BulkManagementControls/index.jsx new file mode 100644 index 0000000..8c8d800 --- /dev/null +++ b/src/components/GradesView/BulkManagementControls/index.jsx @@ -0,0 +1,33 @@ +/* eslint-disable react/sort-comp, react/button-has-type */ +import React from 'react'; + +import NetworkButton from 'components/NetworkButton'; +import ImportGradesButton from '../ImportGradesButton'; + +import useBulkManagementControlsData from './hooks'; +import messages from './messages'; + +/** + * + * Provides download buttons for Bulk Management and Intervention reports, only if + * showBulkManagement is set in redus. + */ +export const BulkManagementControls = () => { + const { + show, + handleClickExportGrades, + } = useBulkManagementControlsData(); + + if (!show) { return null; } + return ( +
+ + +
+ ); +}; + +export default BulkManagementControls; diff --git a/src/components/GradesView/BulkManagementControls/index.test.jsx b/src/components/GradesView/BulkManagementControls/index.test.jsx new file mode 100644 index 0000000..e5e3ca6 --- /dev/null +++ b/src/components/GradesView/BulkManagementControls/index.test.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import useBulkManagementControlsData from './hooks'; +import BulkManagementControls from '.'; + +jest.mock('../ImportGradesButton', () => 'ImportGradesButton'); +jest.mock('components/NetworkButton', () => 'NetworkButton'); + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + show: true, + handleClickExportGrades: jest.fn(), +}; +useBulkManagementControlsData.mockReturnValue(hookProps); + +describe('BulkManagementControls', () => { + describe('behavior', () => { + shallow(); + expect(useBulkManagementControlsData).toHaveBeenCalledWith(); + }); + describe('render', () => { + test('snapshot - show - network and import buttons', () => { + expect(shallow()).toMatchSnapshot(); + }); + test('snapshot - empty if show is not truthy', () => { + useBulkManagementControlsData.mockReturnValueOnce({ ...hookProps, show: false }); + expect(shallow().isEmptyRender()).toEqual(true); + }); + }); +}); diff --git a/src/components/GradesView/BulkManagementControls.messages.js b/src/components/GradesView/BulkManagementControls/messages.js similarity index 100% rename from src/components/GradesView/BulkManagementControls.messages.js rename to src/components/GradesView/BulkManagementControls/messages.js diff --git a/src/components/GradesView/EditModal/ModalHeaders.jsx b/src/components/GradesView/EditModal/ModalHeaders.jsx index df52d98..d9f4ca2 100644 --- a/src/components/GradesView/EditModal/ModalHeaders.jsx +++ b/src/components/GradesView/EditModal/ModalHeaders.jsx @@ -1,68 +1,53 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; -import selectors from 'data/selectors'; +import { StrictDict } from 'utils'; +import { selectors } from 'data/redux/hooks'; import messages from './messages'; import HistoryHeader from './HistoryHeader'; +export const HistoryKeys = StrictDict({ + assignment: 'assignment', + student: 'student', + originalGrade: 'original-grade', + currentGrade: 'current-grade', +}); + /** * * Provides a list of HistoryHeaders for the student name, assignment, * original grade, and current override grade. */ -export const ModalHeaders = ({ - modalState, - originalGrade, - currentGrade, -}) => ( -
- } - value={modalState.assignmentName} - /> - } - value={modalState.updateUserName} - /> - } - value={originalGrade} - /> - } - value={currentGrade} - /> -
-); -ModalHeaders.defaultProps = { - currentGrade: null, - originalGrade: null, -}; -ModalHeaders.propTypes = { - // redux - currentGrade: PropTypes.number, - originalGrade: PropTypes.number, - modalState: PropTypes.shape({ - assignmentName: PropTypes.string.isRequired, - updateUserName: PropTypes.string, - }).isRequired, +export const ModalHeaders = () => { + const { assignmentName, updateUserName } = selectors.app.useModalData(); + const { currentGrade, originalGrade } = selectors.grades.useGradeData(); + const { formatMessage } = useIntl(); + return ( +
+ + + + +
+ ); }; -export const mapStateToProps = (state) => ({ - modalState: { - assignmentName: selectors.app.modalState.assignmentName(state), - updateUserName: selectors.app.modalState.updateUserName(state), - }, - currentGrade: selectors.grades.gradeOverrideCurrentEarnedGradedOverride(state), - originalGrade: selectors.grades.gradeOriginalEarnedGraded(state), -}); - -export default connect(mapStateToProps)(ModalHeaders); +export default ModalHeaders; diff --git a/src/components/GradesView/EditModal/ModalHeaders.test.jsx b/src/components/GradesView/EditModal/ModalHeaders.test.jsx index 57c2361..382eb6a 100644 --- a/src/components/GradesView/EditModal/ModalHeaders.test.jsx +++ b/src/components/GradesView/EditModal/ModalHeaders.test.jsx @@ -1,93 +1,84 @@ import React from 'react'; import { shallow } from 'enzyme'; -import selectors from 'data/selectors'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { selectors } from 'data/redux/hooks'; -import { - ModalHeaders, - mapStateToProps, -} from './ModalHeaders'; +import { formatMessage } from 'testUtils'; + +import HistoryHeader from './HistoryHeader'; +import ModalHeaders, { HistoryKeys } from './ModalHeaders'; +import messages from './messages'; jest.mock('./HistoryHeader', () => 'HistoryHeader'); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - editUpdateData: jest.fn(state => ({ editUpdateData: state })), - modalState: { - assignmentName: jest.fn(state => ({ assignmentName: state })), - updateUserName: jest.fn(state => ({ updateUserName: state })), - }, - }, - grades: { - gradeOverrideCurrentEarnedGradedOverride: jest.fn(state => ({ currentGrade: state })), - gradeOriginalEarnedGraded: jest.fn(state => ({ originalGrade: state })), - }, +jest.mock('data/redux/hooks', () => ({ + selectors: { + app: { useModalData: jest.fn() }, + grades: { useGradeData: jest.fn() }, }, })); -describe('ModalHeaders', () => { - let el; - const props = { - currentGrade: 2, - originalGrade: 20, - modalState: { - assignmentName: 'Qwerty', - updateUserName: 'Uiop', - }, - }; - describe('Component', () => { - describe('snapshots', () => { - beforeEach(() => { - }); - describe('gradeOverrideHistoryError is and empty and open is true', () => { - test('modal open and StatusAlert showing', () => { - el = shallow(); - expect(el).toMatchSnapshot(); - }); - }); - describe('gradeOverrideHistoryError is empty and open is false', () => { - test('modal closed and StatusAlert closed', () => { - el = shallow( - , - ); - expect(el).toMatchSnapshot(); - }); - }); +const modalData = { + assignmentName: 'test-assignment-name', + updateUserName: 'test-user-name', +}; +selectors.app.useModalData.mockReturnValue(modalData); +const gradeData = { + currentGrade: 'test-current-grade', + originalGrade: 'test-original-grade', +}; +selectors.grades.useGradeData.mockReturnValue(gradeData); + +let el; +describe('ModalHeaders', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.app.useModalData).toHaveBeenCalled(); + expect(selectors.grades.useGradeData).toHaveBeenCalled(); }); }); - - describe('mapStateToProps', () => { - const testState = { he: 'lives in a', pineapple: 'under the sea' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); }); - describe('modalState', () => { - test('assignmentName from app.modalState.assignmentName', () => { - expect( - mapped.modalState.assignmentName, - ).toEqual(selectors.app.modalState.assignmentName(testState)); - }); - test('updateUserName from app.modalState.updateUserName', () => { - expect( - mapped.modalState.updateUserName, - ).toEqual(selectors.app.modalState.updateUserName(testState)); + test('assignment header', () => { + const headerProps = el.find(HistoryHeader).at(0).props(); + expect(headerProps).toMatchObject({ + id: HistoryKeys.assignment, + label: formatMessage(messages.assignmentHeader), + value: modalData.assignmentName, }); }); - describe('originalGrade', () => { - test('from grades.gradeOverrideCurrentEarnedGradedOverride', () => { - expect(mapped.currentGrade).toEqual( - selectors.grades.gradeOverrideCurrentEarnedGradedOverride(testState), - ); + test('student header', () => { + const headerProps = el.find(HistoryHeader).at(1).props(); + expect(headerProps).toMatchObject({ + id: HistoryKeys.student, + label: formatMessage(messages.studentHeader), + value: modalData.updateUserName, }); }); - describe('originalGrade', () => { - test('from grades.gradeOriginalEarnedGrades', () => { - expect(mapped.originalGrade).toEqual( - selectors.grades.gradeOriginalEarnedGraded(testState), - ); + test('originalGrade header', () => { + const headerProps = el.find(HistoryHeader).at(2).props(); + expect(headerProps).toMatchObject({ + id: HistoryKeys.originalGrade, + label: formatMessage(messages.originalGradeHeader), + value: gradeData.originalGrade, + }); + }); + test('currentGrade header', () => { + const headerProps = el.find(HistoryHeader).at(3).props(); + expect(headerProps).toMatchObject({ + id: HistoryKeys.currentGrade, + label: formatMessage(messages.currentGradeHeader), + value: gradeData.currentGrade, }); }); }); diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.jsx b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.jsx deleted file mode 100644 index 9f3a5db..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.jsx +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { Form } from '@edx/paragon'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import { getLocalizedSlash } from 'i18n/utils'; - -/** - * - * Input control for adjusting the grade of a unit - * displays an "/ ${possibleGrade} if there is one in the data model. - */ -export class AdjustedGradeInput extends React.Component { - constructor(props) { - super(props); - this.onChange = this.onChange.bind(this); - } - - onChange = ({ target }) => { - this.props.setModalState({ adjustedGradeValue: target.value }); - }; - - render() { - return ( - - - {this.props.possibleGrade && ` ${getLocalizedSlash()} ${this.props.possibleGrade}`} - - ); - } -} -AdjustedGradeInput.defaultProps = { - possibleGrade: null, -}; -AdjustedGradeInput.propTypes = { - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]).isRequired, - possibleGrade: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - setModalState: PropTypes.func.isRequired, -}; - -export const mapStateToProps = (state) => ({ - possibleGrade: selectors.root.editModalPossibleGrade(state), - value: selectors.app.modalState.adjustedGradeValue(state), -}); - -export const mapDispatchToProps = { - setModalState: actions.app.setModalState, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(AdjustedGradeInput); diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.test.jsx b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.test.jsx deleted file mode 100644 index 895fc00..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput.test.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; - -import { - AdjustedGradeInput, - mapStateToProps, - mapDispatchToProps, -} from './AdjustedGradeInput'; - -jest.mock('@edx/paragon', () => ({ - Form: { Control: () => 'Form.Control' }, -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - root: { - editModalPossibleGrade: jest.fn(state => ({ updateUserName: state })), - }, - app: { - modalState: { adjustedGradeValue: jest.fn(state => ({ adjustedGradeValue: state })) }, - }, - }, -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { setModalState: jest.fn() }, - }, -})); -describe('AdjustedGradeInput', () => { - let el; - let props = { - value: 1, - possibleGrade: 5, - }; - beforeEach(() => { - props = { - ...props, - setModalState: jest.fn(), - }; - }); - describe('Component', () => { - beforeEach(() => { - el = shallow(); - }); - describe('snapshots', () => { - test('displays input control and "out of possible grade" label', () => { - el.instance().onChange = jest.fn().mockName('this.onChange'); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('behavior', () => { - describe('onChange', () => { - it('calls props.setModalState event target value', () => { - const value = 42; - el.instance().onChange({ target: { value } }); - expect(props.setModalState).toHaveBeenCalledWith({ - adjustedGradeValue: value, - }); - }); - }); - }); - }); - - describe('mapStateToProps', () => { - const testState = { like: 'no one', ever: 'was' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - describe('modalState', () => { - test('possibleGrade from root.editModalPossibleGrade', () => { - expect( - mapped.possibleGrade, - ).toEqual(selectors.root.editModalPossibleGrade(testState)); - }); - test('updateUserName from app.modalState.updateUserName', () => { - expect( - mapped.value, - ).toEqual(selectors.app.modalState.adjustedGradeValue(testState)); - }); - }); - }); - describe('mapDispatchToProps', () => { - test('setModalState from actions.app.setModalState', () => { - expect(mapDispatchToProps.setModalState).toEqual(actions.app.setModalState); - }); - }); -}); diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/__snapshots__/index.test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..b12be4b --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/__snapshots__/index.test.jsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AdjustedGradeInput component render snapshot 1`] = ` + + + some-hint-text + +`; diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.js b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.js new file mode 100644 index 0000000..da31585 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.js @@ -0,0 +1,21 @@ +import { actions, selectors } from 'data/redux/hooks'; +import { getLocalizedSlash } from 'i18n/utils'; + +const useAdjustedGradeInputData = () => { + const possibleGrade = selectors.root.useEditModalPossibleGrade(); + const value = selectors.app.useModalData().adjustedGradeValue; + const setModalState = actions.app.useSetModalState(); + const hintText = possibleGrade && ` ${getLocalizedSlash()} ${possibleGrade}`; + + const onChange = ({ target }) => { + setModalState({ adjustedGradeValue: target.value }); + }; + + return { + value, + onChange, + hintText, + }; +}; + +export default useAdjustedGradeInputData; diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.test.jsx b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.test.jsx new file mode 100644 index 0000000..e266dc3 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/hooks.test.jsx @@ -0,0 +1,67 @@ +import { getLocalizedSlash } from 'i18n/utils'; +import { actions, selectors } from 'data/redux/hooks'; +import useAdjustedGradeInputData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + selectors: { + root: { + useEditModalPossibleGrade: jest.fn(), + }, + app: { + useModalData: jest.fn(), + }, + }, + actions: { + app: { + useSetModalState: jest.fn(), + }, + }, +})); +jest.mock('i18n/utils', () => ({ getLocalizedSlash: jest.fn() })); + +const localizedSlash = 'localized-slash'; +getLocalizedSlash.mockReturnValue(localizedSlash); + +const possibleGrade = 105; +selectors.root.useEditModalPossibleGrade.mockReturnValue(possibleGrade); +const modalData = { adjustedGradeValue: 70 }; +const setModalState = jest.fn(); +selectors.app.useModalData.mockReturnValue(modalData); +actions.app.useSetModalState.mockReturnValue(setModalState); + +let out; +describe('useAdjustedGradeInputData hook', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useAdjustedGradeInputData(); + }); + describe('behavior', () => { + it('initializes redux hooks', () => { + expect(selectors.root.useEditModalPossibleGrade).toHaveBeenCalled(); + expect(selectors.app.useModalData).toHaveBeenCalled(); + expect(actions.app.useSetModalState).toHaveBeenCalled(); + }); + }); + describe('output', () => { + it('forwards adjusted grade value as value from modal data', () => { + expect(out.value).toEqual(modalData.adjustedGradeValue); + }); + describe('hintText', () => { + it('passes an undefined value if possibleGrade is not available', () => { + selectors.root.useEditModalPossibleGrade.mockReturnValueOnce(undefined); + out = useAdjustedGradeInputData(); + expect(out.hintText).toEqual(undefined); + }); + it('passes localized slash and possible grade if available', () => { + expect(out.hintText).toEqual(` ${localizedSlash} ${possibleGrade}`); + }); + }); + describe('onChange', () => { + it('sets modal state with event target value', () => { + const testValue = 'test-value'; + out.onChange({ target: { value: testValue } }); + expect(setModalState).toHaveBeenCalledWith({ adjustedGradeValue: testValue }); + }); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.jsx b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.jsx new file mode 100644 index 0000000..d070b9b --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { Form } from '@edx/paragon'; + +import useAdjustedGradeInputData from './hooks'; + +/** + * + * Input control for adjusting the grade of a unit + * displays an "/ ${possibleGrade} if there is one in the data model. + */ +export const AdjustedGradeInput = () => { + const { + value, + onChange, + hintText, + } = useAdjustedGradeInputData(); + return ( + + + {hintText} + + ); +}; + +AdjustedGradeInput.propTypes = {}; + +export default AdjustedGradeInput; diff --git a/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.test.jsx b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.test.jsx new file mode 100644 index 0000000..895dc6f --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/AdjustedGradeInput/index.test.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Form } from '@edx/paragon'; + +import useAdjustedGradeInputData from './hooks'; +import AdjustedGradeInput from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + hintText: 'some-hint-text', + onChange: jest.fn().mockName('hook.onChange'), + value: 'test-value', +}; +useAdjustedGradeInputData.mockReturnValue(hookProps); + +let el; +describe('AdjustedGradeInput component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes hook data', () => { + expect(useAdjustedGradeInputData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + const control = el.find(Form.Control); + expect(control.props().value).toEqual(hookProps.value); + expect(control.props().onChange).toEqual(hookProps.onChange); + expect(el.contains(hookProps.hintText)).toEqual(true); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput.jsx deleted file mode 100644 index a9e1c18..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/ReasonInput.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { Form } from '@edx/paragon'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; - -/** - * - * Input control for the "reason for change" field in the Edit modal. - */ -export class ReasonInput extends React.Component { - constructor(props) { - super(props); - this.ref = React.createRef(); - this.onChange = this.onChange.bind(this); - } - - componentDidMount() { - this.ref.current.focus(); - } - - onChange = (event) => { - this.props.setModalState({ reasonForChange: event.target.value }); - }; - - render() { - return ( - - ); - } -} -ReasonInput.propTypes = { - // redux - setModalState: PropTypes.func.isRequired, - value: PropTypes.string.isRequired, -}; - -export const mapStateToProps = (state) => ({ - value: selectors.app.modalState.reasonForChange(state), -}); - -export const mapDispatchToProps = { - setModalState: actions.app.setModalState, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(ReasonInput); diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput.test.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput.test.jsx deleted file mode 100644 index 5f9c311..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/ReasonInput.test.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; - -import { - ReasonInput, - mapStateToProps, - mapDispatchToProps, -} from './ReasonInput'; - -jest.mock('@edx/paragon', () => ({ - Form: { Control: () => 'Form.Control' }, -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - modalState: { reasonForChange: jest.fn(state => ({ reasonForChange: state })) }, - }, - }, -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { setModalState: jest.fn() }, - }, -})); -describe('ReasonInput', () => { - let el; - let props = { - value: 'did not answer the question', - }; - beforeEach(() => { - props = { - ...props, - setModalState: jest.fn(), - }; - }); - describe('Component', () => { - beforeEach(() => { - el = shallow(, { disableLifecycleMethods: true }); - }); - describe('snapshots', () => { - test('displays reason for change input control', () => { - el.instance().onChange = jest.fn().mockName('this.onChange'); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('behavior', () => { - describe('onChange', () => { - it('calls props.setModalState event target value', () => { - const value = 42; - el.instance().onChange({ target: { value } }); - expect(props.setModalState).toHaveBeenCalledWith({ - reasonForChange: value, - }); - }); - }); - describe('componentDidMount', () => { - it('focuses the input ref', () => { - const focus = jest.fn(); - expect(el.instance().ref).toEqual({ current: null }); - el.instance().ref.current = { focus }; - el.instance().componentDidMount(); - expect(el.instance().ref.current.focus).toHaveBeenCalledWith(); - }); - }); - }); - }); - - describe('mapStateToProps', () => { - const testState = { to: { catchThem: 'my real test', trainThem: 'my cause!' } }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - describe('modalState', () => { - test('value from app.modalState.reasonForChange', () => { - expect(mapped.value).toEqual(selectors.app.modalState.reasonForChange(testState)); - }); - }); - }); - describe('mapDispatchToProps', () => { - test('setModalState from actions.app.setModalState', () => { - expect(mapDispatchToProps.setModalState).toEqual(actions.app.setModalState); - }); - }); -}); diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/__snapshots__/index.test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..153368f --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/__snapshots__/index.test.jsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ReasonInput component render snapshot 1`] = ` + +`; diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.js b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.js new file mode 100644 index 0000000..be0071b --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.js @@ -0,0 +1,25 @@ +import React from 'react'; + +import { actions, selectors } from 'data/redux/hooks'; + +const useReasonInputData = () => { + const ref = React.useRef(); + const { reasonForChange } = selectors.app.useModalData(); + const setModalState = actions.app.useSetModalState(); + + React.useEffect(() => { + ref.current.focus(); + }, [ref]); + + const onChange = (event) => { + setModalState({ reasonForChange: event.target.value }); + }; + + return { + value: reasonForChange, + onChange, + ref, + }; +}; + +export default useReasonInputData; diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.test.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.test.jsx new file mode 100644 index 0000000..6b5acec --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/hooks.test.jsx @@ -0,0 +1,63 @@ +import React from 'react'; + +import { actions, selectors } from 'data/redux/hooks'; +import useReasonInputData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + selectors: { + app: { + useModalData: jest.fn(), + }, + }, + actions: { + app: { + useSetModalState: jest.fn(), + }, + }, +})); + +const modalData = { reasonForChange: 'test-reason-for-change' }; +const setModalState = jest.fn(); +selectors.app.useModalData.mockReturnValue(modalData); +actions.app.useSetModalState.mockReturnValue(setModalState); + +const ref = { current: { focus: jest.fn() }, useRef: true }; +React.useRef.mockReturnValue(ref); + +let out; +describe('useReasonInputData hook', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useReasonInputData(); + }); + describe('behavior', () => { + it('initializes ref', () => { + expect(React.useRef).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.app.useModalData).toHaveBeenCalled(); + expect(actions.app.useSetModalState).toHaveBeenCalled(); + }); + it('focuses ref on load', () => { + const [[cb, prereqs]] = React.useEffect.mock.calls; + expect(prereqs).toEqual([ref]); + cb(); + expect(ref.current.focus).toHaveBeenCalled(); + }); + }); + describe('output', () => { + it('forwards reasonForChange as value from modal data', () => { + expect(out.value).toEqual(modalData.reasonForChange); + }); + it('forwards ref', () => { + expect(out.ref).toEqual(ref); + }); + describe('onChange', () => { + it('sets modal state with event target value', () => { + const testValue = 'test-value'; + out.onChange({ target: { value: testValue } }); + expect(setModalState).toHaveBeenCalledWith({ reasonForChange: testValue }); + }); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.jsx new file mode 100644 index 0000000..b76bd21 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.jsx @@ -0,0 +1,27 @@ +import React from 'react'; + +import { Form } from '@edx/paragon'; + +import useReasonInputData from './hooks'; + +export const controlTestId = 'reason-input-control'; + +/** + * + * Input control for the "reason for change" field in the Edit modal. + */ +export const ReasonInput = () => { + const { ref, value, onChange } = useReasonInputData(); + return ( + + ); +}; + +ReasonInput.propTypes = {}; + +export default ReasonInput; diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.test.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.test.jsx new file mode 100644 index 0000000..8cf8134 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/index.test.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Form } from '@edx/paragon'; + +import useReasonInputData from './hooks'; +import ReasonInput from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + ref: 'reason-input-ref', + onChange: jest.fn().mockName('hook.onChange'), + value: 'test-value', +}; +useReasonInputData.mockReturnValue(hookProps); + +let el; +describe('ReasonInput component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes hook data', () => { + expect(useReasonInputData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + const control = el.find(Form.Control); + expect(control.props().value).toEqual(hookProps.value); + expect(control.props().onChange).toEqual(hookProps.onChange); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/ReasonInput/ref.test.jsx b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/ref.test.jsx new file mode 100644 index 0000000..e93bd75 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/ReasonInput/ref.test.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import useReasonInputData from './hooks'; +import ReasonInput, { controlTestId } from '.'; + +jest.unmock('react'); +jest.unmock('@edx/paragon'); +jest.mock('./hooks', () => ({ __esModule: true, default: jest.fn() })); + +const focus = jest.fn(); +const props = { + value: 'test-value', + onChange: jest.fn(), + ref: { current: { focus }, useRef: jest.fn() }, +}; +useReasonInputData.mockReturnValue(props); + +let el; +describe('ReasonInput ref', () => { + it('loads ref from hook', () => { + el = render(); + const control = el.getByTestId(controlTestId); + expect(control).toEqual(props.ref.current); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/AdjustedGradeInput.test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/__snapshots__/AdjustedGradeInput.test.jsx.snap deleted file mode 100644 index 93a0024..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/AdjustedGradeInput.test.jsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AdjustedGradeInput Component snapshots displays input control and "out of possible grade" label 1`] = ` - - - / 5 - -`; diff --git a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/ReasonInput.test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/__snapshots__/ReasonInput.test.jsx.snap deleted file mode 100644 index 5931cf9..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/ReasonInput.test.jsx.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ReasonInput Component snapshots displays reason for change input control 1`] = ` - -`; diff --git a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/index.test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..9fb2a58 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/__snapshots__/index.test.jsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OverrideTable component render snapshot 1`] = ` +, + "date": Object { + "formatted": 2000-01-01T00:00:00.000Z, + }, + "reason": , + }, + ] + } + itemCount={2} +/> +`; diff --git a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/test.jsx.snap b/src/components/GradesView/EditModal/OverrideTable/__snapshots__/test.jsx.snap deleted file mode 100644 index 1f1169b..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OverrideTable Component snapshots basic snapshot shows a row for each entry and one editable row 1`] = ` -, - "accessor": "date", - }, - Object { - "Header": , - "accessor": "grader", - }, - Object { - "Header": , - "accessor": "reason", - }, - Object { - "Header": , - "accessor": "adjustedGrade", - }, - ] - } - data={ - Array [ - Object { - "adjustedGrade": 0, - "date": "yesterday", - "grader": "me", - "reason": "you ate my sandwich", - }, - Object { - "adjustedGrade": 20, - "date": "today", - "grader": "me", - "reason": "you brought me a new sandwich", - }, - Object { - "adjustedGrade": , - "date": "todaaaaaay", - "reason": , - }, - ] - } - itemCount={2} -/> -`; diff --git a/src/components/GradesView/EditModal/OverrideTable/hooks.js b/src/components/GradesView/EditModal/OverrideTable/hooks.js new file mode 100644 index 0000000..d4dfc14 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/hooks.js @@ -0,0 +1,26 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { gradeOverrideHistoryColumns as columns } from 'data/constants/app'; +import { selectors } from 'data/redux/hooks'; + +import messages from './messages'; + +const useOverrideTableData = () => { + const { formatMessage } = useIntl(); + + const hide = selectors.grades.useHasOverrideErrors(); + const gradeOverrides = selectors.grades.useGradeData().gradeOverrideHistoryResults; + const tableProps = {}; + if (!hide) { + tableProps.columns = [ + { Header: formatMessage(messages.dateHeader), accessor: columns.date }, + { Header: formatMessage(messages.graderHeader), accessor: columns.grader }, + { Header: formatMessage(messages.reasonHeader), accessor: columns.reason }, + { Header: formatMessage(messages.adjustedGradeHeader), accessor: columns.adjustedGrade }, + ]; + tableProps.data = gradeOverrides; + } + return { hide, ...tableProps }; +}; + +export default useOverrideTableData; diff --git a/src/components/GradesView/EditModal/OverrideTable/hooks.test.js b/src/components/GradesView/EditModal/OverrideTable/hooks.test.js new file mode 100644 index 0000000..8e684f0 --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/hooks.test.js @@ -0,0 +1,78 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; +import { formatMessage } from 'testUtils'; + +import { gradeOverrideHistoryColumns as columns } from 'data/constants/app'; +import { selectors } from 'data/redux/hooks'; + +import useOverrideTableData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + selectors: { + grades: { + useHasOverrideErrors: jest.fn(), + useGradeData: jest.fn(), + }, + }, +})); + +selectors.grades.useHasOverrideErrors.mockReturnValue(false); +const gradeOverrides = ['some', 'override', 'data']; +const gradeData = { gradeOverrideHistoryResults: gradeOverrides }; +selectors.grades.useGradeData.mockReturnValue(gradeData); + +let out; +describe('useOverrideTableData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useOverrideTableData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.grades.useHasOverrideErrors).toHaveBeenCalled(); + expect(selectors.grades.useGradeData).toHaveBeenCalled(); + }); + }); + describe('output', () => { + describe('no errors', () => { + test('hide is false', () => { + expect(out.hide).toEqual(false); + }); + describe('columns', () => { + test('date column', () => { + const { Header, accessor } = out.columns[0]; + expect(Header).toEqual(formatMessage(messages.dateHeader)); + expect(accessor).toEqual(columns.date); + }); + test('grader column', () => { + const { Header, accessor } = out.columns[1]; + expect(Header).toEqual(formatMessage(messages.graderHeader)); + expect(accessor).toEqual(columns.grader); + }); + test('reason column', () => { + const { Header, accessor } = out.columns[2]; + expect(Header).toEqual(formatMessage(messages.reasonHeader)); + expect(accessor).toEqual(columns.reason); + }); + test('adjustedGrade column', () => { + const { Header, accessor } = out.columns[3]; + expect(Header).toEqual(formatMessage(messages.adjustedGradeHeader)); + expect(accessor).toEqual(columns.adjustedGrade); + }); + }); + test('data passed from grade data', () => { + expect(out.data).toEqual(gradeOverrides); + }); + }); + describe('with errors', () => { + it('returns hide true and no other fields', () => { + selectors.grades.useHasOverrideErrors.mockReturnValue(true); + out = useOverrideTableData(); + expect(out).toEqual({ hide: true }); + }); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/index.jsx b/src/components/GradesView/EditModal/OverrideTable/index.jsx index bd5e765..bab0054 100644 --- a/src/components/GradesView/EditModal/OverrideTable/index.jsx +++ b/src/components/GradesView/EditModal/OverrideTable/index.jsx @@ -1,73 +1,40 @@ /* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { DataTable } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; -import { gradeOverrideHistoryColumns as columns } from 'data/constants/app'; -import selectors from 'data/selectors'; +import { formatDateForDisplay } from 'utils'; -import messages from './messages'; import ReasonInput from './ReasonInput'; import AdjustedGradeInput from './AdjustedGradeInput'; +import useOverrideTableData from './hooks'; /** * * Table containing previous grade override entries, and an "edit" row * with todays date, an AdjustedGradeInput and a ReasonInput */ -export const OverrideTable = ({ - hide, - gradeOverrides, - todaysDate, -}) => { - if (hide) { - return null; - } + +export const OverrideTable = () => { + const { hide, columns, data } = useOverrideTableData(); + + if (hide) { return null; } + return ( , accessor: columns.date }, - { Header: , accessor: columns.grader }, - { Header: , accessor: columns.reason }, - { - Header: , - accessor: columns.adjustedGrade, - }, - ]} + columns={columns} data={[ - ...gradeOverrides, + ...data, { adjustedGrade: , - date: todaysDate, + date: formatDateForDisplay(new Date()), reason: , }, ]} - itemCount={gradeOverrides.length} + itemCount={data.length} /> ); }; -OverrideTable.defaultProps = { - gradeOverrides: [], -}; -OverrideTable.propTypes = { - // redux - gradeOverrides: PropTypes.arrayOf(PropTypes.shape({ - date: PropTypes.string, - grader: PropTypes.string, - reason: PropTypes.string, - adjustedGrade: PropTypes.number, - })), - hide: PropTypes.bool.isRequired, - todaysDate: PropTypes.string.isRequired, -}; +OverrideTable.propTypes = {}; -export const mapStateToProps = (state) => ({ - hide: selectors.grades.hasOverrideErrors(state), - gradeOverrides: selectors.grades.gradeOverrides(state), - todaysDate: selectors.app.modalState.todaysDate(state), -}); - -export default connect(mapStateToProps)(OverrideTable); +export default OverrideTable; diff --git a/src/components/GradesView/EditModal/OverrideTable/index.test.jsx b/src/components/GradesView/EditModal/OverrideTable/index.test.jsx new file mode 100644 index 0000000..79210fb --- /dev/null +++ b/src/components/GradesView/EditModal/OverrideTable/index.test.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { DataTable } from '@edx/paragon'; + +import { formatDateForDisplay } from 'utils'; + +import AdjustedGradeInput from './AdjustedGradeInput'; +import ReasonInput from './ReasonInput'; +import useOverrideTableData from './hooks'; +import OverrideTable from '.'; + +jest.mock('utils', () => ({ + formatDateForDisplay: (date) => ({ formatted: date }), +})); +jest.mock('./hooks', () => jest.fn()); +jest.mock('./AdjustedGradeInput', () => 'AdjustedGradeInput'); +jest.mock('./ReasonInput', () => 'ReasonInput'); + +const hookProps = { + hide: false, + data: [ + { test: 'data' }, + { andOther: 'test-data' }, + ], + columns: 'test-columns', +}; +useOverrideTableData.mockReturnValue(hookProps); + +let el; +describe('OverrideTable component', () => { + beforeEach(() => { + jest + .clearAllMocks() + .useFakeTimers('modern') + .setSystemTime(new Date('2000-01-01').getTime()); + el = shallow(); + }); + describe('behavior', () => { + it('initializes hook data', () => { + expect(useOverrideTableData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('null render if hide', () => { + useOverrideTableData.mockReturnValueOnce({ ...hookProps, hide: true }); + el = shallow(); + expect(el.isEmptyRender()).toEqual(true); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + const table = el.find(DataTable); + expect(table.props().columns).toEqual(hookProps.columns); + const data = [...table.props().data]; + const inputRow = data.pop(); + const formattedDate = formatDateForDisplay(new Date()); + expect(data).toEqual(hookProps.data); + expect(inputRow).toMatchObject({ + adjustedGrade: , + date: formattedDate, + reason: , + }); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/OverrideTable/test.jsx b/src/components/GradesView/EditModal/OverrideTable/test.jsx deleted file mode 100644 index 96149b4..0000000 --- a/src/components/GradesView/EditModal/OverrideTable/test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; - -import { - OverrideTable, - mapStateToProps, -} from '.'; - -jest.mock('@edx/paragon', () => ({ DataTable: () => 'DataTable' })); -jest.mock('./ReasonInput', () => 'ReasonInput'); -jest.mock('./AdjustedGradeInput', () => 'AdjustedGradeInput'); - -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - modalState: { - todaysDate: jest.fn(state => ({ todaysDate: state })), - }, - }, - grades: { - hasOverrideErrors: jest.fn(state => ({ hasOverrideErrors: state })), - gradeOverrides: jest.fn(state => ({ gradeOverrides: state })), - }, - }, -})); - -describe('OverrideTable', () => { - const props = { - gradeOverrides: [ - { - date: 'yesterday', - grader: 'me', - reason: 'you ate my sandwich', - adjustedGrade: 0, - }, - { - date: 'today', - grader: 'me', - reason: 'you brought me a new sandwich', - adjustedGrade: 20, - }, - ], - hide: false, - todaysDate: 'todaaaaaay', - }; - - describe('Component', () => { - describe('snapshots', () => { - it('returns null if hide is true', () => { - expect(shallow()).toEqual({}); - }); - describe('basic snapshot', () => { - test('shows a row for each entry and one editable row', () => { - expect(shallow()).toMatchSnapshot(); - }); - }); - }); - }); - - describe('mapStateToProps', () => { - const testState = { I: 'wanna', be: 'the', very: 'best' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - describe('modalState', () => { - test('hide from grades.hasOverrideErrors', () => { - expect(mapped.hide).toEqual(selectors.grades.hasOverrideErrors(testState)); - }); - test('gradeOverrides from grades.gradeOverrides', () => { - expect(mapped.gradeOverrides).toEqual(selectors.grades.gradeOverrides(testState)); - }); - test('todaysData from app.modalState.todaysDate', () => { - expect(mapped.todaysDate).toEqual(selectors.app.modalState.todaysDate(testState)); - }); - }); - }); -}); diff --git a/src/components/GradesView/EditModal/__snapshots__/ModalHeaders.test.jsx.snap b/src/components/GradesView/EditModal/__snapshots__/ModalHeaders.test.jsx.snap index 0cce19b..22efe80 100644 --- a/src/components/GradesView/EditModal/__snapshots__/ModalHeaders.test.jsx.snap +++ b/src/components/GradesView/EditModal/__snapshots__/ModalHeaders.test.jsx.snap @@ -1,99 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is and empty and open is true modal open and StatusAlert showing 1`] = ` +exports[`ModalHeaders render snapshot 1`] = `
- } - value="Qwerty" + label="Assignment" + value="test-assignment-name" /> - } - value="Uiop" + label="Student" + value="test-user-name" /> - } - value={20} + label="Original Grade" + value="test-original-grade" /> - } - value={2} - /> -
-`; - -exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is empty and open is false modal closed and StatusAlert closed 1`] = ` -
- - } - value="Qwerty" - /> - - } - value="Uiop" - /> - - } - value={20} - /> - - } - value={2} + label="Current Grade" + value="test-current-grade" />
`; diff --git a/src/components/GradesView/EditModal/__snapshots__/index.test.jsx.snap b/src/components/GradesView/EditModal/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..46a0c51 --- /dev/null +++ b/src/components/GradesView/EditModal/__snapshots__/index.test.jsx.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EditModal component render with error snapshot 1`] = ` + + +
+ + + test-error + + +
+ Showing most recent actions (max 5). To see more, please contact support +
+
+ Note: Once you save, your changes will be visible to students. +
+
+
+ + + + Cancel + + + + +
+`; + +exports[`EditModal component render without error snapshot 1`] = ` + + +
+ + + +
+ Showing most recent actions (max 5). To see more, please contact support +
+
+ Note: Once you save, your changes will be visible to students. +
+
+
+ + + + Cancel + + + + +
+`; diff --git a/src/components/GradesView/EditModal/__snapshots__/test.jsx.snap b/src/components/GradesView/EditModal/__snapshots__/test.jsx.snap deleted file mode 100644 index 3bcdeb7..0000000 --- a/src/components/GradesView/EditModal/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,125 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EditModal Component snapshots gradeOverrideHistoryError is and empty and open is true modal open and StatusAlert showing 1`] = ` - - -
- - - Weve been trying to contact you regarding... - - -
- -
-
- -
-
-
- - - - - - - - -
-`; - -exports[`EditModal Component snapshots gradeOverrideHistoryError is empty and open is false modal closed and StatusAlert closed 1`] = ` - - -
- - - - - -
- -
-
- -
-
-
- - - - - - - - -
-`; diff --git a/src/components/GradesView/EditModal/hooks.js b/src/components/GradesView/EditModal/hooks.js new file mode 100644 index 0000000..a5811b7 --- /dev/null +++ b/src/components/GradesView/EditModal/hooks.js @@ -0,0 +1,29 @@ +import { selectors, actions, thunkActions } from 'data/redux/hooks'; + +export const useEditModalData = () => { + const error = selectors.grades.useGradeData().gradeOverrideHistoryError; + const isOpen = selectors.app.useModalData().open; + const closeModal = actions.app.useCloseModal(); + const doneViewingAssignment = actions.grades.useDoneViewingAssignment(); + const updateGrades = thunkActions.grades.useUpdateGrades(); + + const onClose = () => { + doneViewingAssignment(); + closeModal(); + }; + + const handleAdjustedGradeClick = () => { + updateGrades(); + doneViewingAssignment(); + closeModal(); + }; + + return { + onClose, + error, + handleAdjustedGradeClick, + isOpen, + }; +}; + +export default useEditModalData; diff --git a/src/components/GradesView/EditModal/hooks.test.js b/src/components/GradesView/EditModal/hooks.test.js new file mode 100644 index 0000000..7951a16 --- /dev/null +++ b/src/components/GradesView/EditModal/hooks.test.js @@ -0,0 +1,68 @@ +import { selectors, actions, thunkActions } from 'data/redux/hooks'; + +import useEditModalData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + app: { useCloseModal: jest.fn() }, + grades: { useDoneViewingAssignment: jest.fn() }, + }, + selectors: { + app: { useModalData: jest.fn() }, + grades: { useGradeData: jest.fn() }, + }, + thunkActions: { + grades: { useUpdateGrades: jest.fn() }, + }, +})); + +const closeModal = jest.fn(); +const doneViewingAssignment = jest.fn(); +const updateGrades = jest.fn(); +actions.app.useCloseModal.mockReturnValue(closeModal); +actions.grades.useDoneViewingAssignment.mockReturnValue(doneViewingAssignment); +thunkActions.grades.useUpdateGrades.mockReturnValue(updateGrades); + +const gradeData = { gradeOverridHistoryError: 'test-error' }; +const modalData = { open: true }; +selectors.app.useModalData.mockReturnValue(modalData); +selectors.grades.useGradeData.mockReturnValue(gradeData); + +let out; +describe('useEditModalData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useEditModalData(); + }); + describe('behavior', () => { + it('initializes redux hooks', () => { + expect(selectors.grades.useGradeData).toHaveBeenCalled(); + expect(selectors.app.useModalData).toHaveBeenCalled(); + expect(actions.app.useCloseModal).toHaveBeenCalled(); + expect(actions.grades.useDoneViewingAssignment).toHaveBeenCalled(); + expect(thunkActions.grades.useUpdateGrades).toHaveBeenCalled(); + }); + }); + describe('output', () => { + it('forwards error from gradeData.gradeOverrideHistoryError', () => { + expect(out.error).toEqual(gradeData.gradeOverrideHistoryError); + }); + it('forwards isOpen from modalData.open', () => { + expect(out.isOpen).toEqual(modalData.open); + }); + describe('handleAdjustedGradeClick', () => { + it('updates grades, calls doneViewingAssignment and closeModal', () => { + out.handleAdjustedGradeClick(); + expect(updateGrades).toHaveBeenCalled(); + expect(doneViewingAssignment).toHaveBeenCalled(); + expect(closeModal).toHaveBeenCalled(); + }); + }); + test('onClose calls doneViewingAssignment and closeModal', () => { + out.onClose(); + expect(doneViewingAssignment).toHaveBeenCalled(); + expect(closeModal).toHaveBeenCalled(); + expect(updateGrades).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/index.jsx b/src/components/GradesView/EditModal/index.jsx index d093be8..519b044 100644 --- a/src/components/GradesView/EditModal/index.jsx +++ b/src/components/GradesView/EditModal/index.jsx @@ -1,7 +1,4 @@ -/* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { Button, @@ -9,15 +6,12 @@ import { ModalDialog, ActionRow, } from '@edx/paragon'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import thunkActions from 'data/thunkActions'; - -import messages from './messages'; import OverrideTable from './OverrideTable'; import ModalHeaders from './ModalHeaders'; +import useEditModalData from './hooks'; +import messages from './messages'; /** * @@ -28,87 +22,48 @@ import ModalHeaders from './ModalHeaders'; * adjusting the grade. * (also provides a close button that clears the modal state) */ -export class EditModal extends React.Component { - constructor(props) { - super(props); - this.closeAssignmentModal = this.closeAssignmentModal.bind(this); - this.handleAdjustedGradeClick = this.handleAdjustedGradeClick.bind(this); - } +export const EditModal = () => { + const { formatMessage } = useIntl(); + const { + onClose, + error, + handleAdjustedGradeClick, + isOpen, + } = useEditModalData(); - closeAssignmentModal() { - this.props.doneViewingAssignment(); - this.props.closeModal(); - } + return ( + + +
+ + + {error} + + +
{formatMessage(messages.visibility)}
+
{formatMessage(messages.saveVisibility)}
+
+
- handleAdjustedGradeClick() { - this.props.updateGrades(); - this.closeAssignmentModal(); - } - - render() { - return ( - - -
- - - {this.props.gradeOverrideHistoryError} - - -
-
-
-
- - - - - - - - -
- ); - } -} - -EditModal.defaultProps = { - gradeOverrideHistoryError: '', + + + + {formatMessage(messages.closeText)} + + + + +
+ ); }; -EditModal.propTypes = { - // redux - gradeOverrideHistoryError: PropTypes.string, - open: PropTypes.bool.isRequired, - closeModal: PropTypes.func.isRequired, - doneViewingAssignment: PropTypes.func.isRequired, - updateGrades: PropTypes.func.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export const mapStateToProps = (state) => ({ - gradeOverrideHistoryError: selectors.grades.gradeOverrideHistoryError(state), - open: selectors.app.modalState.open(state), -}); - -export const mapDispatchToProps = { - closeModal: actions.app.closeModal, - doneViewingAssignment: actions.grades.doneViewingAssignment, - updateGrades: thunkActions.grades.updateGrades, -}; - -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(EditModal)); +export default EditModal; diff --git a/src/components/GradesView/EditModal/index.test.jsx b/src/components/GradesView/EditModal/index.test.jsx new file mode 100644 index 0000000..8a69126 --- /dev/null +++ b/src/components/GradesView/EditModal/index.test.jsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { + ActionRow, + ModalDialog, +} from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; + +import ModalHeaders from './ModalHeaders'; +import OverrideTable from './OverrideTable'; +import useEditModalData from './hooks'; +import EditModal from '.'; +import messages from './messages'; + +jest.mock('./hooks', () => jest.fn()); +jest.mock('./ModalHeaders', () => 'ModalHeaders'); +jest.mock('./OverrideTable', () => 'OverrideTable'); + +const hookProps = { + onClose: jest.fn().mockName('hooks.onClose'), + error: 'test-error', + handleAdjustedGradeClick: jest.fn().mockName('hooks.handleAdjustedGradeClick'), + isOpen: 'test-is-open', +}; +useEditModalData.mockReturnValue(hookProps); + +let el; +describe('EditModal component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes component hooks', () => { + expect(useEditModalData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('modal props', () => { + const modalProps = el.find(ModalDialog).props(); + expect(modalProps.title).toEqual(formatMessage(messages.title)); + expect(modalProps.isOpen).toEqual(hookProps.isOpen); + expect(modalProps.onClose).toEqual(hookProps.onClose); + }); + const loadBody = () => { + const body = el.find(ModalDialog).children().at(0); + const children = body.find('div').children(); + return { body, children }; + }; + const testBody = () => { + test('type', () => { + const { body } = loadBody(); + expect(body.type()).toEqual('ModalDialog.Body'); + }); + test('headers row', () => { + const { children } = loadBody(); + expect(children.at(0)).toMatchObject(shallow()); + }); + test('table row', () => { + const { children } = loadBody(); + expect(children.at(2)).toMatchObject(shallow()); + }); + test('messages', () => { + const { children } = loadBody(); + expect( + children.at(3).contains(formatMessage(messages.visibility)), + ).toEqual(true); + expect( + children.at(4).contains(formatMessage(messages.saveVisibility)), + ).toEqual(true); + }); + }; + const testFooter = () => { + let footer; + beforeEach(() => { + footer = el.find(ModalDialog).children().at(1); + }); + test('type', () => { + expect(footer.type()).toEqual('ModalDialog.Footer'); + }); + test('contains action row', () => { + expect(footer.children().at(0).type()).toEqual('ActionRow'); + }); + test('close button', () => { + const button = footer.find(ActionRow).children().at(0); + expect(button.contains(formatMessage(messages.closeText))).toEqual(true); + expect(button.type()).toEqual('ModalDialog.CloseButton'); + }); + test('adjusted grade button', () => { + const button = footer.find(ActionRow).children().at(1); + expect(button.contains(formatMessage(messages.saveGrade))).toEqual(true); + expect(button.type()).toEqual('Button'); + expect(button.props().onClick).toEqual(hookProps.handleAdjustedGradeClick); + }); + }; + describe('without error', () => { + beforeEach(() => { + useEditModalData.mockReturnValueOnce({ ...hookProps, error: undefined }); + el = shallow(); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + testBody(); + testFooter(); + test('alert row', () => { + const alert = loadBody().children.at(1); + expect(alert.type()).toEqual('Alert'); + expect(alert.props().show).toEqual(false); + }); + }); + describe('with error', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + testBody(); + test('alert row', () => { + const alert = loadBody().children.at(1); + expect(alert.type()).toEqual('Alert'); + expect(alert.props().show).toEqual(true); + expect(alert.contains(hookProps.error)).toEqual(true); + }); + testFooter(); + }); + }); +}); diff --git a/src/components/GradesView/EditModal/test.jsx b/src/components/GradesView/EditModal/test.jsx deleted file mode 100644 index c0f6cbf..0000000 --- a/src/components/GradesView/EditModal/test.jsx +++ /dev/null @@ -1,130 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; - -import { - EditModal, - mapDispatchToProps, - mapStateToProps, -} - from '.'; - -jest.mock('./OverrideTable', () => 'OverrideTable'); -jest.mock('./ModalHeaders', () => 'ModalHeaders'); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { closeModal: jest.fn() }, - grades: { doneViewingAssignment: jest.fn() }, - }, -})); -jest.mock('data/thunkActions', () => ({ - __esModule: true, - default: { - grades: { updateGrades: jest.fn() }, - }, -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - modalState: { - open: jest.fn(state => ({ isModalOpen: state })), - }, - }, - grades: { - gradeOverrideHistoryError: jest.fn(state => ({ overrideHistoryError: state })), - }, - }, -})); -describe('EditModal', () => { - let props; - beforeEach(() => { - props = { - gradeOverrideHistoryError: 'Weve been trying to contact you regarding...', - open: true, - closeModal: jest.fn(), - doneViewingAssignment: jest.fn(), - updateGrades: jest.fn(), - - intl: { formatMessage: (msg) => msg.defaultMessage }, - }; - }); - - describe('Component', () => { - describe('behavior', () => { - let el; - beforeEach(() => { - el = shallow(); - }); - describe('closeAssignmentModal', () => { - it('calls props.doneViewingAssignment and props.closeModal', () => { - el.instance().closeAssignmentModal(); - expect(props.doneViewingAssignment).toHaveBeenCalledWith(); - expect(props.closeModal).toHaveBeenCalledWith(); - }); - }); - describe('handleAdjustedGradeClick', () => { - it('calls props.updateGardes and this.closeAssignmentModal', () => { - el.instance().closeAssignmentModal = jest.fn(); - el.instance().handleAdjustedGradeClick(); - expect(props.updateGrades).toHaveBeenCalledWith(); - expect(el.instance().closeAssignmentModal).toHaveBeenCalledWith(); - }); - }); - }); - describe('snapshots', () => { - let el; - beforeEach(() => { - el = shallow(); - el.instance().closeAssignmentModal = jest.fn().mockName('this.closeAssignmentModal'); - el.instance().handleAdjustedGradeClick = jest.fn().mockName( - 'this.handleAdjustedGradeClick', - ); - }); - describe('gradeOverrideHistoryError is and empty and open is true', () => { - test('modal open and StatusAlert showing', () => { - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('gradeOverrideHistoryError is empty and open is false', () => { - test('modal closed and StatusAlert closed', () => { - el.setProps({ open: false, gradeOverrideHistoryError: '' }); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - }); - }); - - describe('mapStateToProps', () => { - const testState = { martha: 'why did you say that name?!' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('gradeOverrideHistoryError from grades.gradeOverrideHistoryError', () => { - expect( - mapped.gradeOverrideHistoryError, - ).toEqual(selectors.grades.gradeOverrideHistoryError(testState)); - }); - test('open from app.modalState.open', () => { - expect(mapped.open).toEqual(selectors.app.modalState.open(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('closeModal from actions.app.closeModal', () => { - expect(mapDispatchToProps.closeModal).toEqual(actions.app.closeModal); - }); - test('doneViewingAssignemtn from actions.grades.doneViewingAssignment', () => { - expect( - mapDispatchToProps.doneViewingAssignment, - ).toEqual(actions.grades.doneViewingAssignment); - }); - test('updateGrades from thunkActions.grades.updateGrades', () => { - expect(mapDispatchToProps.updateGrades).toEqual(thunkActions.grades.updateGrades); - }); - }); -}); diff --git a/src/components/GradesView/FilterBadges/FilterBadge.jsx b/src/components/GradesView/FilterBadges/FilterBadge.jsx index d6f5dbe..48e6862 100644 --- a/src/components/GradesView/FilterBadges/FilterBadge.jsx +++ b/src/components/GradesView/FilterBadges/FilterBadge.jsx @@ -1,11 +1,10 @@ import React from 'react'; -import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { Button } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; -import selectors from 'data/selectors'; +import { selectors } from 'data/redux/hooks'; /** * FilterBadge @@ -16,56 +15,43 @@ import selectors from 'data/selectors'; * @param {string} filterName - api filter name (for redux connector) */ export const FilterBadge = ({ - config: { + filterName, + handleClose, +}) => { + const { formatMessage } = useIntl(); + const { displayName, isDefault, hideValue, value, connectedFilters, - }, - handleClose, -}) => !isDefault && ( -
- - - + } = selectors.root.useFilterBadgeConfig(filterName); + if (isDefault) { + return null; + } + return ( +
+ + {formatMessage(displayName)} + + {!hideValue ? `: ${value}` : ''} + + - - {!hideValue ? `: ${value}` : ''} - - - -
-
-); +
+
+ ); +}; FilterBadge.propTypes = { handleClose: PropTypes.func.isRequired, - // eslint-disable-next-line filterName: PropTypes.string.isRequired, - // redux - config: PropTypes.shape({ - connectedFilters: PropTypes.arrayOf(PropTypes.string), - displayName: PropTypes.shape({ - defaultMessage: PropTypes.string, - }).isRequired, - isDefault: PropTypes.bool.isRequired, - hideValue: PropTypes.bool, - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.bool, - ]), - }).isRequired, }; -export const mapStateToProps = (state, ownProps) => ({ - config: selectors.root.filterBadgeConfig(state, ownProps.filterName), -}); - -export default connect(mapStateToProps)(FilterBadge); +export default FilterBadge; diff --git a/src/components/GradesView/FilterBadges/FilterBadge.test.jsx b/src/components/GradesView/FilterBadges/FilterBadge.test.jsx index 935cf93..30ac380 100644 --- a/src/components/GradesView/FilterBadges/FilterBadge.test.jsx +++ b/src/components/GradesView/FilterBadges/FilterBadge.test.jsx @@ -1,107 +1,95 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { formatMessage } from 'testUtils'; import { Button } from '@edx/paragon'; -import selectors from 'data/selectors'; -import { FilterBadge, mapStateToProps } from './FilterBadge'; +import { selectors } from 'data/redux/hooks'; +import FilterBadge from './FilterBadge'; jest.mock('@edx/paragon', () => ({ Button: () => 'Button', })); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { +jest.mock('data/redux/hooks', () => ({ + selectors: { root: { - filterBadgeConfig: jest.fn(state => ({ filterBadgeConfig: state })), + useFilterBadgeConfig: jest.fn(), }, }, })); +const handleClose = jest.fn(filters => ({ handleClose: filters })); +const filterName = 'test-filter-name'; + +const hookProps = { + displayName: { + defaultMessage: 'a common name', + }, + isDefault: false, + hideValue: false, + value: 'a common value', + connectedFilters: ['some', 'filters'], +}; +selectors.root.useFilterBadgeConfig.mockReturnValue(hookProps); + +let el; describe('FilterBadge', () => { - describe('component', () => { - const config = { - displayName: { - defaultMessage: 'a common name', - }, - isDefault: false, - hideValue: false, - value: 'a common value', - connectedFilters: ['some', 'filters'], - }; - const filterName = 'api.filter.name'; - let handleClose; - let el; - let props; - beforeEach(() => { - handleClose = (filters) => ({ handleClose: filters }); - props = { filterName, handleClose, config }; + beforeEach(() => { + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); }); - describe('with default value', () => { - beforeEach(() => { - el = shallow( - , - ); - }); - test('snapshot - empty', () => { - expect(el).toMatchSnapshot(); - }); - it('does not display', () => { - expect(el).toEqual({}); - }); - }); - describe('with non-default value (active)', () => { - describe('if hideValue is true', () => { - beforeEach(() => { - el = shallow( - , - ); - }); - test('snapshot - shows displayName but not value in span', () => { - expect(el).toMatchSnapshot(); - }); - it('shows displayName but not value in span', () => { - expect(el.find('span.badge').childAt(0).getElement()).toEqual( - - - , - ); - }); - it('calls a handleClose event for connected filters on button click', () => { - expect(el.find(Button).props().onClick).toEqual(handleClose(config.connectedFilters)); - }); - }); - describe('if hideValue is false (default)', () => { - beforeEach(() => { - el = shallow(); - }); - test('snapshot', () => { - expect(el).toMatchSnapshot(); - }); - it('shows displayName and value in span', () => { - expect(el.find('span.badge').childAt(0).getElement()).toEqual( - - - , - ); - expect(el.find('span.badge').childAt(1).getElement()).toEqual( - - {`: ${config.value}`} - , - ); - }); - it('calls a handleClose event for connected filters on button click', () => { - expect(el.find(Button).props().onClick).toEqual(handleClose(config.connectedFilters)); - }); - }); + it('initializes redux hooks', () => { + expect(selectors.root.useFilterBadgeConfig).toHaveBeenCalledWith(filterName); }); }); - describe('mapStateToProps', () => { - const testState = { some: 'kind', of: 'alien' }; - const filterName = 'Lilu Dallas Multipass'; - test('config loads config from root.filterBadgeConfig with ownProps.filterName', () => { - const { config } = mapStateToProps(testState, { filterName }); - expect(config).toEqual(selectors.root.filterBadgeConfig(testState, filterName)); + describe('render', () => { + const testDisplayName = () => { + test('formatted display name appears on badge', () => { + expect(el.contains(formatMessage(hookProps.displayName))).toEqual(true); + }); + }; + const testCloseButton = () => { + test('close button forwards close method', () => { + expect(el.find(Button).props().onClick).toEqual(handleClose(hookProps.connectedFilters)); + }); + }; + test('empty render if isDefault', () => { + selectors.root.useFilterBadgeConfig.mockReturnValueOnce({ + ...hookProps, + isDefault: true, + }); + el = shallow(); + expect(el.isEmptyRender()).toEqual(true); + }); + describe('hide Value', () => { + beforeEach(() => { + selectors.root.useFilterBadgeConfig.mockReturnValueOnce({ + ...hookProps, + hideValue: true, + }); + el = shallow(); + }); + testDisplayName(); + testCloseButton(); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('value is note present in the badge', () => { + expect(el.contains(hookProps.value)).toEqual(false); + }); + }); + describe('do not hide value', () => { + testDisplayName(); + testCloseButton(); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('value is note present in the badge', () => { + expect(el.text().includes(hookProps.value)).toEqual(true); + }); }); }); }); diff --git a/src/components/GradesView/FilterBadges/__snapshots__/FilterBadge.test.jsx.snap b/src/components/GradesView/FilterBadges/__snapshots__/FilterBadge.test.jsx.snap index 1eb8147..4de3fc5 100644 --- a/src/components/GradesView/FilterBadges/__snapshots__/FilterBadge.test.jsx.snap +++ b/src/components/GradesView/FilterBadges/__snapshots__/FilterBadge.test.jsx.snap @@ -1,16 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FilterBadge component with default value snapshot - empty 1`] = `""`; - -exports[`FilterBadge component with non-default value (active) if hideValue is false (default) snapshot 1`] = ` +exports[`FilterBadge render do not hide value snapshot 1`] = `
- + a common name : a common value @@ -38,15 +34,13 @@ exports[`FilterBadge component with non-default value (active) if hideValue is f
`; -exports[`FilterBadge component with non-default value (active) if hideValue is true snapshot - shows displayName but not value in span 1`] = ` +exports[`FilterBadge render hide Value snapshot 1`] = `
- + a common name -); - -FilterMenuToggle.propTypes = { - // From Redux - toggleFilterDrawer: PropTypes.func.isRequired, -}; - -export const mapStateToProps = () => ({}); - -export const mapDispatchToProps = { - toggleFilterDrawer: thunkActions.app.filterMenu.toggle, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(FilterMenuToggle); diff --git a/src/components/GradesView/FilterMenuToggle.test.jsx b/src/components/GradesView/FilterMenuToggle.test.jsx deleted file mode 100644 index 4d02fca..0000000 --- a/src/components/GradesView/FilterMenuToggle.test.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import thunkActions from 'data/thunkActions'; - -import { FilterMenuToggle, mapDispatchToProps, mapStateToProps } from './FilterMenuToggle'; - -jest.mock('@edx/paragon', () => ({ - Button: () => 'Button', - Icon: () => 'Icon', -})); -jest.mock('data/thunkActions', () => ({ - __esModule: true, - default: { - app: { - filterMenu: { toggle: jest.fn() }, - }, - }, -})); - -describe('FilterMenuToggle component', () => { - describe('snapshots', () => { - test('basic snapshot', () => { - const toggleFilterDrawer = jest.fn().mockName('this.props.toggleFilterDrawer'); - expect(shallow(( - - ))).toMatchSnapshot(); - }); - }); - describe('mapStateToProps', () => { - test('does not connect any selectors', () => { - expect(mapStateToProps({ test: 'state' })).toEqual({}); - }); - }); - describe('mapDispatchToProps', () => { - test('toggleFilterDrawer from thunkActions.app.filterMenu.toggle', () => { - expect(mapDispatchToProps.toggleFilterDrawer).toEqual( - thunkActions.app.filterMenu.toggle, - ); - }); - }); -}); diff --git a/src/components/GradesView/FilterMenuToggle/__snapshots__/index.test.jsx.snap b/src/components/GradesView/FilterMenuToggle/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..c08ee06 --- /dev/null +++ b/src/components/GradesView/FilterMenuToggle/__snapshots__/index.test.jsx.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FilterMenuToggle component render snapshot 1`] = ` + +`; diff --git a/src/components/GradesView/FilterMenuToggle/index.jsx b/src/components/GradesView/FilterMenuToggle/index.jsx new file mode 100644 index 0000000..72f60fd --- /dev/null +++ b/src/components/GradesView/FilterMenuToggle/index.jsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import { Button, Icon } from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { FilterAlt } from '@edx/paragon/icons'; + +import { thunkActions } from 'data/redux/hooks'; + +import messages from './messages'; + +/** + * Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer + * as well as the search box for searching by username/email. + */ +export const FilterMenuToggle = () => { + const toggleFilterMenu = thunkActions.app.filterMenu.useToggleMenu(); + const { formatMessage } = useIntl(); + return ( + + ); +}; + +FilterMenuToggle.propTypes = {}; + +export default FilterMenuToggle; diff --git a/src/components/GradesView/FilterMenuToggle/index.test.jsx b/src/components/GradesView/FilterMenuToggle/index.test.jsx new file mode 100644 index 0000000..ac54495 --- /dev/null +++ b/src/components/GradesView/FilterMenuToggle/index.test.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { thunkActions } from 'data/redux/hooks'; + +import FilterMenuToggle from '.'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + thunkActions: { + app: { + filterMenu: { + useToggleMenu: jest.fn(), + }, + }, + }, +})); + +const toggleFilterMenu = jest.fn().mockName('hooks.toggleFilterMenu'); +thunkActions.app.filterMenu.useToggleMenu.mockReturnValue(toggleFilterMenu); + +let el; +describe('FilterMenuToggle component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(thunkActions.app.filterMenu.useToggleMenu).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + expect(el.type()).toEqual('Button'); + expect(el.props().onClick).toEqual(toggleFilterMenu); + expect(el.text().includes(formatMessage(messages.editFilters))); + }); + }); +}); diff --git a/src/components/GradesView/FilterMenuToggle.messages.js b/src/components/GradesView/FilterMenuToggle/messages.js similarity index 100% rename from src/components/GradesView/FilterMenuToggle.messages.js rename to src/components/GradesView/FilterMenuToggle/messages.js diff --git a/src/components/GradesView/FilteredUsersLabel.jsx b/src/components/GradesView/FilteredUsersLabel.jsx deleted file mode 100644 index 3752dee..0000000 --- a/src/components/GradesView/FilteredUsersLabel.jsx +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import selectors from 'data/selectors'; - -/** - * - * Simple label component displaying the filtered and total users shown - */ -export const FilteredUsersLabel = ({ - filteredUsersCount, - totalUsersCount, -}) => { - if (!totalUsersCount) { - return null; - } - const bold = (val) => ({val}); - return ( - - ); -}; -FilteredUsersLabel.propTypes = { - filteredUsersCount: PropTypes.number.isRequired, - totalUsersCount: PropTypes.number.isRequired, -}; - -export const mapStateToProps = (state) => ({ - totalUsersCount: selectors.grades.totalUsersCount(state), - filteredUsersCount: selectors.grades.filteredUsersCount(state), -}); - -export default connect(mapStateToProps)(FilteredUsersLabel); diff --git a/src/components/GradesView/FilteredUsersLabel.test.jsx b/src/components/GradesView/FilteredUsersLabel.test.jsx deleted file mode 100644 index c6ec280..0000000 --- a/src/components/GradesView/FilteredUsersLabel.test.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import { FilteredUsersLabel, mapStateToProps } from './FilteredUsersLabel'; - -jest.mock('@edx/paragon', () => ({ - Icon: () => 'Icon', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - grades: { - filteredUsersCount: state => ({ filteredUsersCount: state }), - totalUsersCount: state => ({ totalUsersCount: state }), - }, - }, -})); - -describe('FilteredUsersLabel', () => { - describe('component', () => { - const props = { - filteredUsersCount: 23, - totalUsersCount: 140, - }; - it('does not render if totalUsersCount is falsey', () => { - expect(shallow()).toEqual({}); - }); - test('snapshot - displays label with number of filtered users out of total', () => { - expect(shallow()).toMatchSnapshot(); - }); - }); - describe('mapStateToProps', () => { - const testState = { a: 'nice', day: 'for', some: 'rain' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('filteredUsersCount from grades.filteredUsersCount', () => { - expect(mapped.filteredUsersCount).toEqual(selectors.grades.filteredUsersCount(testState)); - }); - test('totalUsersCount from grades.totalUsersCount', () => { - expect(mapped.totalUsersCount).toEqual(selectors.grades.totalUsersCount(testState)); - }); - }); -}); diff --git a/src/components/GradesView/FilteredUsersLabel/__snapshots__/index.test.jsx.snap b/src/components/GradesView/FilteredUsersLabel/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..be687e1 --- /dev/null +++ b/src/components/GradesView/FilteredUsersLabel/__snapshots__/index.test.jsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FilteredUsersLabel component render snapshot 1`] = ` +, + "totalUsers": , + } + } +/> +`; diff --git a/src/components/GradesView/FilteredUsersLabel/index.jsx b/src/components/GradesView/FilteredUsersLabel/index.jsx new file mode 100644 index 0000000..090e158 --- /dev/null +++ b/src/components/GradesView/FilteredUsersLabel/index.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { selectors } from 'data/redux/hooks'; +import messages from './messages'; + +export const BoldText = ({ text }) => ( + {text} +); +BoldText.propTypes = { + text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, +}; + +/** + * + * Simple label component displaying the filtered and total users shown + */ +export const FilteredUsersLabel = () => { + const { filteredUsersCount, totalUsersCount } = selectors.grades.useUserCounts(); + const { formatMessage } = useIntl(); + + if (!totalUsersCount) { + return null; + } + return formatMessage( + messages.visibilityLabel, + { + filteredUsers: , + totalUsers: , + }, + ); +}; +FilteredUsersLabel.propTypes = {}; + +export default FilteredUsersLabel; diff --git a/src/components/GradesView/FilteredUsersLabel/index.test.jsx b/src/components/GradesView/FilteredUsersLabel/index.test.jsx new file mode 100644 index 0000000..46617f7 --- /dev/null +++ b/src/components/GradesView/FilteredUsersLabel/index.test.jsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { selectors } from 'data/redux/hooks'; + +import FilteredUsersLabel, { BoldText } from '.'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + selectors: { + grades: { + useUserCounts: jest.fn(), + }, + }, +})); + +const userCounts = { + filteredUsersCount: 100, + totalUsersCount: 123, +}; +selectors.grades.useUserCounts.mockReturnValue(userCounts); + +let el; +describe('FilteredUsersLabel component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.grades.useUserCounts).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('null render if totalUsersCount is 0', () => { + selectors.grades.useUserCounts.mockReturnValueOnce({ + ...userCounts, + totalUsersCount: 0, + }); + expect(shallow().isEmptyRender()).toEqual(true); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + expect(el).toMatchObject(shallow(formatMessage(messages.visibilityLabel, { + filteredUsers: , + totalUsers: , + }))); + }); + }); +}); diff --git a/src/components/GradesView/FilteredUsersLabel/messages.js b/src/components/GradesView/FilteredUsersLabel/messages.js new file mode 100644 index 0000000..d0be2b4 --- /dev/null +++ b/src/components/GradesView/FilteredUsersLabel/messages.js @@ -0,0 +1,11 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + visibilityLabel: { + id: 'gradebook.GradesTab.usersVisibilityLabel', + defaultMessage: 'Showing {filteredUsers} of {totalUsers} total learners', + description: 'Users visibility label', + }, +}); + +export default messages; diff --git a/src/components/GradesView/GradebookTable/GradeButton.jsx b/src/components/GradesView/GradebookTable/GradeButton.jsx index 67be259..bbcfea5 100644 --- a/src/components/GradesView/GradebookTable/GradeButton.jsx +++ b/src/components/GradesView/GradebookTable/GradeButton.jsx @@ -1,14 +1,31 @@ -/* eslint-disable react/sort-comp, react/button-has-type */ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { Button } from '@edx/paragon'; -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; +import { selectors, thunkActions } from 'data/redux/hooks'; +import transforms from 'data/redux/transforms'; +import * as module from './GradeButton'; -const { subsectionGrade } = selectors.grades; +export const useGradeButtonData = ({ entry, subsection }) => { + const areGradesFrozen = selectors.assignmentTypes.useAreGradesFrozen(); + const { gradeFormat } = selectors.grades.useGradeData(); + const setModalState = thunkActions.app.useSetModalStateFromTable(); + const label = transforms.grades.subsectionGrade({ gradeFormat, subsection }); + + const onClick = () => { + setModalState({ + userEntry: entry, + subsection, + }); + }; + + return { + areGradesFrozen, + label, + onClick, + }; +}; /** * GradeButton @@ -18,38 +35,24 @@ const { subsectionGrade } = selectors.grades; * @param {object} entry - user's grade entry * @param {object} subsection - user's subsection grade from subsection_breakdown */ -export class GradeButton extends React.Component { - constructor(props) { - super(props); - this.onClick = this.onClick.bind(this); - } - - get label() { - return subsectionGrade[this.props.format](this.props.subsection); - } - - onClick() { - this.props.setModalState({ - userEntry: this.props.entry, - subsection: this.props.subsection, - }); - } - - render() { - return this.props.areGradesFrozen - ? this.label - : ( - - ); - } -} - +export const GradeButton = ({ entry, subsection }) => { + const { + areGradesFrozen, + label, + onClick, + } = module.useGradeButtonData({ entry, subsection }); + return areGradesFrozen + ? label + : ( + + ); +}; GradeButton.propTypes = { subsection: PropTypes.shape({ attempted: PropTypes.bool, @@ -62,19 +65,6 @@ GradeButton.propTypes = { user_id: PropTypes.number, username: PropTypes.string, }).isRequired, - // redux - areGradesFrozen: PropTypes.bool.isRequired, - format: PropTypes.string.isRequired, - setModalState: PropTypes.func.isRequired, }; -export const mapStateToProps = (state) => ({ - areGradesFrozen: selectors.assignmentTypes.areGradesFrozen(state), - format: selectors.grades.gradeFormat(state), -}); - -export const mapDispatchToProps = { - setModalState: thunkActions.app.setModalStateFromTable, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(GradeButton); +export default GradeButton; diff --git a/src/components/GradesView/GradebookTable/GradeButton.test.jsx b/src/components/GradesView/GradebookTable/GradeButton.test.jsx index 36588ff..6574f07 100644 --- a/src/components/GradesView/GradebookTable/GradeButton.test.jsx +++ b/src/components/GradesView/GradebookTable/GradeButton.test.jsx @@ -1,118 +1,121 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { Button } from '@edx/paragon'; -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; +import { selectors, thunkActions } from 'data/redux/hooks'; +import transforms from 'data/redux/transforms'; +import { keyStore } from 'utils'; -import { - GradeButton, - mapStateToProps, - mapDispatchToProps, -} from './GradeButton'; +import * as module from './GradeButton'; -jest.mock('@edx/paragon', () => ({ - Button: () => 'Button', -})); +const { useGradeButtonData, default: GradeButton } = module; -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - assignmentTypes: { - areGradesFrozen: jest.fn(state => ({ areGradesFrozen: state })), - }, +jest.mock('data/redux/hooks', () => ({ + selectors: { + assignmentTypes: { useAreGradesFrozen: jest.fn() }, grades: { - subsectionGrade: { - percent: jest.fn(subsection => ({ percent: subsection })), - }, - gradeFormat: jest.fn(state => ({ gradeFormat: state })), + useGradeData: jest.fn(), }, }, + thunkActions: { + app: { useSetModalStateFromTable: jest.fn() }, + }, })); - -jest.mock('data/thunkActions', () => ({ - app: { - setModalStateFromTable: jest.fn(), +jest.mock('data/redux/transforms', () => ({ + grades: { + subsectionGrade: jest.fn(), }, })); +const props = { + subsection: { + attempted: false, + percent: 23, + score_possible: 32, + subsection_name: 'the things we do', + module_id: 'in potions', + }, + entry: { + user_id: 2, + username: 'Jessie', + }, +}; +const gradeFormat = 'percent'; +const setModalState = jest.fn(); +const subsectionGrade = 'test-subsection-grade'; +selectors.assignmentTypes.useAreGradesFrozen.mockReturnValue(false); +selectors.grades.useGradeData.mockReturnValue({ gradeFormat }); +thunkActions.app.useSetModalStateFromTable.mockReturnValue(setModalState); +transforms.grades.subsectionGrade.mockReturnValue(subsectionGrade); + +let el; +let out; describe('GradeButton', () => { - let el; - let props = { - subsection: { - attempted: false, - percent: 23, - score_possible: 32, - subsection_name: 'the things we do', - module_id: 'in potions', - }, - entry: { - user_id: 2, - username: 'Jessie', - }, - areGradesFrozen: false, - format: 'percent', - }; beforeEach(() => { - props = { ...props, setModalState: jest.fn() }; + jest.clearAllMocks(); }); - describe('component', () => { - describe('snapshots', () => { - test('grades are frozen', () => { - el = shallow(); - const label = 'why you gotta label people?'; - jest.spyOn(el.instance(), 'label', 'get').mockReturnValue(label); - el.instance().onClick = jest.fn().mockName('this.onClick'); - expect(el.instance().render()).toMatchSnapshot(); - expect(el.instance().render()).toEqual(label); - }); - test('grades are not frozen', () => { - el = shallow(); - const label = 'why you gotta label people?'; - jest.spyOn(el.instance(), 'label', 'get').mockReturnValue(label); - el.instance().onClick = jest.fn().mockName('this.onClick'); - expect(el.instance().render()).toMatchSnapshot(); - expect(el.instance().render().props.children).toEqual(label); - expect(el.render().is(Button)).toEqual(true); + describe('useGradeButton hook', () => { + beforeEach(() => { + out = useGradeButtonData(props); + }); + describe('behavior', () => { + it('initializes redux hooks', () => { + expect(selectors.assignmentTypes.useAreGradesFrozen).toHaveBeenCalled(); + expect(selectors.grades.useGradeData).toHaveBeenCalled(); + expect(transforms.grades.subsectionGrade).toHaveBeenCalledWith({ + gradeFormat, + subsection: props.subsection, + }); + expect(thunkActions.app.useSetModalStateFromTable).toHaveBeenCalled(); }); }); - describe('label', () => { - it('calls the appropriate formatter with the subsection prop', () => { - el = shallow(); - expect( - el.instance().label, - ).toEqual(selectors.grades.subsectionGrade[props.format](props.subsection)); + describe('output', () => { + test('forwards areGradesFrozen from redux hook', () => { + expect(out.areGradesFrozen).toEqual(false); }); - }); - describe('onClick', () => { - it('calls props.setModalState with userEntry and subsection', () => { - el = shallow(); - el.instance().onClick(); - expect(props.setModalState).toHaveBeenCalledWith({ + test('label passed from subsection grade redux hook', () => { + expect(out.label).toEqual(subsectionGrade); + }); + test('onClick sets modal state with user entry and subsection', () => { + out.onClick(); + expect(setModalState).toHaveBeenCalledWith({ userEntry: props.entry, subsection: props.subsection, }); }); }); }); - describe('mapStateToProps', () => { - let mapped; - const testState = { teams: { rocket: ['jesse', 'james'] } }; + describe('component', () => { + let hookSpy; + const moduleKeys = keyStore(module); + const hookProps = { + areGradesFrozen: false, + label: 'test-label', + onClick: jest.fn().mockName('hooks.onClick'), + }; beforeEach(() => { - mapped = mapStateToProps(testState); + hookSpy = jest.spyOn(module, moduleKeys.useGradeButtonData); }); - test('areGradesFrozen form assignmentTypes.areGradesFrozen', () => { - expect( - mapped.areGradesFrozen, - ).toEqual(selectors.assignmentTypes.areGradesFrozen(testState)); + describe('frozen grades', () => { + beforeEach(() => { + hookSpy.mockReturnValue({ ...hookProps, areGradesFrozen: true }); + el = shallow(); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + expect(el.text()).toEqual(hookProps.label); + }); }); - test('format form grades.format', () => { - expect(mapped.format).toEqual(selectors.grades.gradeFormat(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('setModalState from thunkActions.app.setModalStateFromTable', () => { - expect(mapDispatchToProps.setModalState).toEqual(thunkActions.app.setModalStateFromTable); + describe('not frozen grades', () => { + beforeEach(() => { + hookSpy.mockReturnValue(hookProps); + el = shallow(); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + expect(el.type()).toEqual('Button'); + expect(el.props().onClick).toEqual(hookProps.onClick); + expect(el.contains(hookProps.label)).toEqual(true); + }); }); }); }); diff --git a/src/components/GradesView/GradebookTable/LabelReplacements.jsx b/src/components/GradesView/GradebookTable/LabelReplacements.jsx index 86dd89c..d134ac3 100644 --- a/src/components/GradesView/GradebookTable/LabelReplacements.jsx +++ b/src/components/GradesView/GradebookTable/LabelReplacements.jsx @@ -1,13 +1,13 @@ import React from 'react'; -import { StrictDict } from 'utils'; - +import { useIntl, getLocale, isRtl } from '@edx/frontend-platform/i18n'; import { Icon, OverlayTrigger, Tooltip, } from '@edx/paragon'; -import { FormattedMessage, getLocale, isRtl } from '@edx/frontend-platform/i18n'; + +import { StrictDict } from 'utils'; import messages from './messages'; @@ -18,32 +18,33 @@ export const totalGradePercentageMessage = 'Total Grade values are always displa * Total Grade column header. * displays an overlay tooltip with screen-reader text to indicate total grade percentage */ -const TotalGradeLabelReplacement = () => ( -
- - - - )} - > -
- -
- - )} - /> +const TotalGradeLabelReplacement = () => { + const { formatMessage } = useIntl(); + return ( +
+ + {formatMessage(messages.totalGradePercentage)} + + )} + > +
+ {formatMessage(messages.totalGradeHeading)} +
+ +
-
- -
-); + +
+ ); +}; /** * Asterisk to display next to heading labels that are only used for masters students @@ -56,28 +57,34 @@ const mastersOnlyFieldAsterisk = ( * * Username column header. Lists that Student Key is possibly available */ -const UsernameLabelReplacement = () => ( -
+const UsernameLabelReplacement = () => { + const { formatMessage } = useIntl(); + return (
- +
+ {formatMessage(messages.usernameHeading)} +
+
+ {formatMessage(messages.studentKeyLabel)} + { mastersOnlyFieldAsterisk } +
-
- - { mastersOnlyFieldAsterisk } -
-
-); + ); +}; /** * * Column header for fields that are only available for masters students */ -const MastersOnlyLabelReplacement = (message) => ( -
- - { mastersOnlyFieldAsterisk } -
-); +const MastersOnlyLabelReplacement = (message) => { + const { formatMessage } = useIntl(); + return ( +
+ {formatMessage(message)} + { mastersOnlyFieldAsterisk } +
+ ); +}; export default StrictDict({ TotalGradeLabelReplacement, diff --git a/src/components/GradesView/GradebookTable/__snapshots__/GradeButton.test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/GradeButton.test.jsx.snap index 13fa8f8..378fbae 100644 --- a/src/components/GradesView/GradebookTable/__snapshots__/GradeButton.test.jsx.snap +++ b/src/components/GradesView/GradebookTable/__snapshots__/GradeButton.test.jsx.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`GradeButton component snapshots grades are frozen 1`] = `"why you gotta label people?"`; +exports[`GradeButton component frozen grades snapshot 1`] = `"test-label"`; -exports[`GradeButton component snapshots grades are not frozen 1`] = ` +exports[`GradeButton component not frozen grades snapshot 1`] = ` `; diff --git a/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap index ed189e2..528c771 100644 --- a/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap +++ b/src/components/GradesView/GradebookTable/__snapshots__/LabelReplacements.test.jsx.snap @@ -2,11 +2,7 @@ exports[`LabelReplacements MastersOnlyLabelReplacement snapshot 1`] = `
- + defaultMessAge @@ -19,11 +15,7 @@ exports[`LabelReplacements TotalGradeLabelReplacement displays overlay tooltip 1 - + Total Grade values are always displayed as a percentage `; @@ -35,11 +27,7 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = ` - + Total Grade values are always displayed as a percentage } placement="left" @@ -51,23 +39,13 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = ` } >
- + Total Grade (%)
- } + screenReaderText="Total Grade values are always displayed as a percentage" />
@@ -78,20 +56,12 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = ` exports[`LabelReplacements UsernameLabelReplacement snapshot 1`] = `
- + Username
- + Student Key @@ -109,11 +79,7 @@ exports[`snapshot left to right overlay placement 1`] = ` - + Total Grade values are always displayed as a percentage } placement="right" @@ -125,23 +91,13 @@ exports[`snapshot left to right overlay placement 1`] = ` } >
- + Total Grade (%)
- } + screenReaderText="Total Grade values are always displayed as a percentage" />
@@ -157,11 +113,7 @@ exports[`snapshot right to left overlay placement 1`] = ` - + Total Grade values are always displayed as a percentage } placement="left" @@ -173,23 +125,13 @@ exports[`snapshot right to left overlay placement 1`] = ` } >
- + Total Grade (%)
- } + screenReaderText="Total Grade values are always displayed as a percentage" />
diff --git a/src/components/GradesView/GradebookTable/__snapshots__/index.test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..04bdd0e --- /dev/null +++ b/src/components/GradesView/GradebookTable/__snapshots__/index.test.jsx.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GradebookTable snapshot 1`] = ` +
+ + + + + +
+`; diff --git a/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap b/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap deleted file mode 100644 index 228b171..0000000 --- a/src/components/GradesView/GradebookTable/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,63 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GradebookTable component snapshot - fields1 and 2 between email and totalGrade, mocked rows 1`] = ` -
- , - "accessor": "Username", - }, - Object { - "Header": , - "accessor": "Full Name", - }, - Object { - "Header": , - "accessor": "Email", - }, - Object { - "Header": "field1", - "accessor": "field1", - }, - Object { - "Header": "field2", - "accessor": "field2", - }, - Object { - "Header": , - "accessor": "Total Grade (%)", - }, - ] - } - data={ - Array [ - "mappedRow: 1", - "mappedRow: 2", - "mappedRow: 3", - ] - } - hasFixedColumnWidths={true} - itemCount={3} - rowHeaderColumnKey="username" - > - - - - -
-`; diff --git a/src/components/GradesView/GradebookTable/hooks.jsx b/src/components/GradesView/GradebookTable/hooks.jsx new file mode 100644 index 0000000..99f6ef5 --- /dev/null +++ b/src/components/GradesView/GradebookTable/hooks.jsx @@ -0,0 +1,61 @@ +import React from 'react'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { selectors } from 'data/redux/hooks'; +import transforms from 'data/redux/transforms'; +import { Headings } from 'data/constants/grades'; +import { getLocalizedPercentSign } from 'i18n/utils'; + +import messages from './messages'; +import Fields from './Fields'; +import LabelReplacements from './LabelReplacements'; +import GradeButton from './GradeButton'; + +const { roundGrade } = transforms.grades; + +export const useGradebookTableData = () => { + const { formatMessage } = useIntl(); + const grades = selectors.grades.useAllGrades(); + const headings = selectors.root.useGetHeadings(); + + const mapHeaders = (heading) => { + let label; + if (heading === Headings.totalGrade) { + label = ; + } else if (heading === Headings.username) { + label = ; + } else if (heading === Headings.email) { + label = ; + } else if (heading === Headings.fullName) { + label = ; + } else { + label = heading; + } + return { Header: label, accessor: heading }; + }; + + const mapRows = entry => ({ + [Headings.username]: ( + + ), + [Headings.email]: (), + [Headings.totalGrade]: `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`, + ...entry.section_breakdown.reduce((acc, subsection) => ({ + ...acc, + [subsection.label]: , + }), {}), + }); + + const nullMethod = () => null; + + return { + columns: headings.map(mapHeaders), + data: grades.map(mapRows), + grades, + nullMethod, + emptyContent: formatMessage(messages.noResultsFound), + }; +}; + +export default useGradebookTableData; diff --git a/src/components/GradesView/GradebookTable/hooks.test.jsx b/src/components/GradesView/GradebookTable/hooks.test.jsx new file mode 100644 index 0000000..6e95c39 --- /dev/null +++ b/src/components/GradesView/GradebookTable/hooks.test.jsx @@ -0,0 +1,192 @@ +import { shallow } from 'enzyme'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; + +import { getLocalizedPercentSign } from 'i18n/utils'; +import { selectors } from 'data/redux/hooks'; +import transforms from 'data/redux/transforms'; +import { Headings } from 'data/constants/grades'; +import LabelReplacements from './LabelReplacements'; +import Fields from './Fields'; +import GradeButton from './GradeButton'; + +import messages from './messages'; + +import useGradebookTableData from './hooks'; + +jest.mock('i18n/utils', () => ({ + getLocalizedPercentSign: () => '%', +})); +jest.mock('./GradeButton', () => 'GradeButton'); +jest.mock('./Fields', () => jest.requireActual('testUtils').mockNestedComponents({ + Username: 'Fields.Username', + Email: 'Fields.Email', +})); +jest.mock('./LabelReplacements', () => jest.requireActual('testUtils').mockNestedComponents({ + TotalGradeLabelReplacement: 'LabelReplacements.TotalGradeLabelReplacement', + UsernameLabelReplacement: 'LabelReplacements.UsernameLabelReplacement', + MastersOnlyLabelReplacement: 'LabelReplacements.MastersOnlyLabelReplacement', +})); + +jest.mock('data/redux/hooks', () => ({ + selectors: { + grades: { useAllGrades: jest.fn() }, + root: { useGetHeadings: jest.fn() }, + }, +})); +jest.mock('data/redux/transforms', () => ({ + grades: { roundGrade: jest.fn() }, +})); + +const roundGrade = grade => grade * 20; +transforms.grades.roundGrade.mockImplementation(roundGrade); + +const subsectionLabels = [ + 'subsectionLabel1', + 'subsectionLabel2', + 'subsectionLabel3', +]; + +const allGrades = [ + { + username: 'test-username-1', + external_user_key: 'EKey1', + email: 'email-1', + fullName: 'test-fullNAME', + percent: 0.9, + section_breakdown: [ + { label: subsectionLabels[0] }, + { label: subsectionLabels[1] }, + { label: subsectionLabels[2] }, + ], + }, + { + username: 'test-username-2', + external_user_key: 'EKey2', + email: 'email-2', + percent: 0.8, + section_breakdown: [ + { label: subsectionLabels[0] }, + { label: subsectionLabels[1] }, + { label: subsectionLabels[2] }, + ], + }, + { + username: 'test-username-3', + external_user_key: 'EKey3', + email: 'email-3', + percent: 0.6, + section_breakdown: [ + { label: subsectionLabels[0] }, + { label: subsectionLabels[1] }, + { label: subsectionLabels[2] }, + ], + }, +]; +const testHeading = 'test-heading-value'; +const headings = [ + Headings.totalGrade, + Headings.username, + Headings.email, + Headings.fullName, + testHeading, +]; +selectors.grades.useAllGrades.mockReturnValue(allGrades); +selectors.root.useGetHeadings.mockReturnValue(headings); + +let out; +describe('useGradebookTableData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useGradebookTableData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.grades.useAllGrades).toHaveBeenCalled(); + expect(selectors.root.useGetHeadings).toHaveBeenCalled(); + }); + }); + describe('output', () => { + describe('columns', () => { + test('total grade heading produces TotalGradeLabelReplacement label', () => { + const { Header, accessor } = out.columns[0]; + expect(accessor).toEqual(headings[0]); + expect(shallow(Header)).toMatchObject( + shallow(), + ); + }); + test('username heading produces UsernameLabelReplacement', () => { + const { Header, accessor } = out.columns[1]; + expect(accessor).toEqual(headings[1]); + expect(shallow(Header)).toMatchObject( + shallow(), + ); + }); + test('email heading replaces with email heading message', () => { + const { Header, accessor } = out.columns[2]; + expect(accessor).toEqual(headings[2]); + expect(shallow(Header)).toMatchObject( + shallow(), + ); + }); + test('fullName heading replaces with fullName heading message', () => { + const { Header, accessor } = out.columns[3]; + expect(accessor).toEqual(headings[3]); + expect(shallow(Header)).toMatchObject( + shallow(), + ); + }); + test('other headings are passed through', () => { + const { Header, accessor } = out.columns[4]; + expect(accessor).toEqual(headings[4]); + expect(Header).toEqual(headings[4]); + }); + }); + describe('data', () => { + test('username field', () => { + allGrades.forEach((entry, index) => { + expect(out.data[index][Headings.username]).toMatchObject( + , + ); + }); + }); + test('email field', () => { + allGrades.forEach((entry, index) => { + expect(out.data[index][Headings.email]).toMatchObject( + , + ); + }); + }); + test('totalGrade field', () => { + allGrades.forEach((entry, index) => { + expect(out.data[index][Headings.totalGrade]).toEqual( + `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`, + ); + }); + }); + test('section breakdown', () => { + allGrades.forEach((entry, gradeIndex) => { + subsectionLabels.forEach((label, labelIndex) => { + expect(out.data[gradeIndex][label]).toMatchObject( + , + ); + }); + }); + }); + }); + it('forwards grades from redux', () => { + expect(out.grades).toEqual(allGrades); + }); + test('nullMethod returns null', () => { + expect(out.nullMethod()).toEqual(null); + }); + test('emptyContent', () => { + expect(out.emptyContent).toEqual(formatMessage(messages.noResultsFound)); + }); + }); +}); diff --git a/src/components/GradesView/GradebookTable/index.jsx b/src/components/GradesView/GradebookTable/index.jsx index 0fe6d7a..fd26ffb 100644 --- a/src/components/GradesView/GradebookTable/index.jsx +++ b/src/components/GradesView/GradebookTable/index.jsx @@ -1,21 +1,8 @@ -/* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { DataTable } from '@edx/paragon'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import selectors from 'data/selectors'; -import { Headings } from 'data/constants/grades'; -import { getLocalizedPercentSign } from 'i18n/utils'; - -import messages from './messages'; -import Fields from './Fields'; -import LabelReplacements from './LabelReplacements'; -import GradeButton from './GradeButton'; - -const { roundGrade } = selectors.grades; +import useGradebookTableData from './hooks'; /** * @@ -23,96 +10,33 @@ const { roundGrade } = selectors.grades; * a row for each user, with a column for their username, email, and total grade, * along with one for each subsection in their grade entry. */ -export class GradebookTable extends React.Component { - constructor(props) { - super(props); - this.mapHeaders = this.mapHeaders.bind(this); - this.mapRows = this.mapRows.bind(this); - this.nullMethod = this.nullMethod.bind(this); - } +export const GradebookTable = () => { + const { + columns, + data, + grades, + nullMethod, + emptyContent, + } = useGradebookTableData(); - mapHeaders(heading) { - let label; - if (heading === Headings.totalGrade) { - label = ; - } else if (heading === Headings.username) { - label = ; - } else if (heading === Headings.email) { - label = ; - } else if (heading === Headings.fullName) { - label = ; - } else { - label = heading; - } - return { Header: label, accessor: heading }; - } - - mapRows = entry => ({ - [Headings.username]: ( - - ), - [Headings.fullName]: (), - [Headings.email]: (), - [Headings.totalGrade]: `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`, - ...entry.section_breakdown.reduce((acc, subsection) => ({ - ...acc, - [subsection.label]: , - }), {}), - }); - - nullMethod() { - return null; - } - - render() { - return ( -
- - - - - -
- ); - } -} - -GradebookTable.defaultProps = { - grades: [], + return ( +
+ + + + + +
+ ); }; -GradebookTable.propTypes = { - // redux - grades: PropTypes.arrayOf(PropTypes.shape({ - percent: PropTypes.number, - section_breakdown: PropTypes.arrayOf(PropTypes.shape({ - attempted: PropTypes.bool, - category: PropTypes.string, - label: PropTypes.string, - module_id: PropTypes.string, - percent: PropTypes.number, - scoreEarned: PropTypes.number, - scorePossible: PropTypes.number, - subsection_name: PropTypes.string, - })), - user_id: PropTypes.number, - user_name: PropTypes.string, - })), - headings: PropTypes.arrayOf(PropTypes.string).isRequired, - // injected - intl: intlShape.isRequired, -}; +GradebookTable.propTypes = {}; -export const mapStateToProps = (state) => ({ - grades: selectors.grades.allGrades(state), - headings: selectors.root.getHeadings(state), -}); - -export default injectIntl(connect(mapStateToProps)(GradebookTable)); +export default GradebookTable; diff --git a/src/components/GradesView/GradebookTable/index.test.jsx b/src/components/GradesView/GradebookTable/index.test.jsx new file mode 100644 index 0000000..ac97eaa --- /dev/null +++ b/src/components/GradesView/GradebookTable/index.test.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { DataTable } from '@edx/paragon'; + +import useGradebookTableData from './hooks'; +import GradebookTable from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + columns: ['some', 'columns'], + data: ['some', 'data'], + grades: ['a', 'few', 'grades'], + nullMethod: jest.fn().mockName('hooks.nullMethod'), + emptyContent: 'empty-table-content', +}; +useGradebookTableData.mockReturnValue(hookProps); + +let el; +describe('GradebookTable', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('Datatable props', () => { + const datatable = el.find(DataTable); + const props = datatable.props(); + expect(props.columns).toEqual(hookProps.columns); + expect(props.data).toEqual(hookProps.data); + expect(props.itemCount).toEqual(hookProps.grades.length); + expect(props.RowStatusComponent).toEqual(hookProps.nullMethod); + expect(datatable.children().at(2).type()).toEqual('DataTable.EmptyTable'); + expect(datatable.children().at(2).props().content).toEqual(hookProps.emptyContent); + }); +}); diff --git a/src/components/GradesView/GradebookTable/test.jsx b/src/components/GradesView/GradebookTable/test.jsx deleted file mode 100644 index ed416a6..0000000 --- a/src/components/GradesView/GradebookTable/test.jsx +++ /dev/null @@ -1,186 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import { DataTable } from '@edx/paragon'; - -import selectors from 'data/selectors'; -import { Headings } from 'data/constants/grades'; -import LabelReplacements from './LabelReplacements'; -import Fields from './Fields'; -import messages from './messages'; -import { GradebookTable, mapStateToProps } from '.'; - -jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedComponents({ - DataTable: { - Table: 'DataTable.Table', - TableControlBar: 'DataTable.TableControlBar', - EmptyTable: 'DataTable.EmptyTable', - }, -})); -jest.mock('./Fields', () => ({ - __esModule: true, - default: { - Username: () => 'Fields.Username', - Text: () => 'Fields.Text', - }, -})); -jest.mock('./LabelReplacements', () => ({ - __esModule: true, - default: { - TotalGradeLabelReplacement: () => 'TotalGradeLabelReplacement', - UsernameLabelReplacement: () => 'UsernameLabelReplacement', - MastersOnlyLabelReplacement: () => 'MastersOnlyLabelReplacement', - }, -})); -jest.mock('./GradeButton', () => 'GradeButton'); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - grades: { - roundGrade: jest.fn(grade => `roundedGrade: ${grade}`), - allGrades: jest.fn(state => ({ allGrades: state })), - }, - root: { - getHeadings: jest.fn(state => ({ getHeadings: state })), - }, - }, -})); -describe('GradebookTable', () => { - describe('component', () => { - let el; - const fields = { field1: 'field1', field2: 'field2' }; - const props = { - grades: [ - { - percent: 1, - section_breakdown: [ - { label: fields.field1, percent: 1.2 }, - { label: fields.field2, percent: 2.3 }, - ], - }, - { - percent: 2, - section_breakdown: [ - { label: fields.field1, percent: 1.2 }, - { label: fields.field2, percent: 2.3 }, - ], - }, - { - percent: 3, - section_breakdown: [ - { label: fields.field1, percent: 1.2 }, - { label: fields.field2, percent: 2.3 }, - ], - }, - ], - headings: [ - Headings.username, - Headings.fullName, - Headings.email, - fields.field1, - fields.field2, - Headings.totalGrade, - ], - - intl: { formatMessage: (msg) => msg.defaultMessage }, - }; - test('snapshot - fields1 and 2 between email and totalGrade, mocked rows', () => { - el = shallow(); - el.instance().nullMethod = jest.fn().mockName('this.nullMethod'); - el.instance().mapRows = (entry) => `mappedRow: ${entry.percent}`; - expect(el.instance().render()).toMatchSnapshot(); - }); - test('null method returns null for stub component', () => { - el = shallow(); - expect(el.instance().nullMethod()).toEqual(null); - }); - describe('table columns (mapHeaders)', () => { - let headings; - beforeEach(() => { - el = shallow(); - headings = el.find(DataTable).props().columns; - }); - test('username sets key and replaces Header with component', () => { - const heading = headings[0]; - expect(heading.accessor).toEqual(Headings.username); - expect(heading.Header.type).toEqual(LabelReplacements.UsernameLabelReplacement); - }); - test('full name sets key and Header from header', () => { - const heading = headings[1]; - expect(heading.accessor).toEqual(Headings.fullName); - expect(heading.Header).toEqual(); - }); - test('email sets key and Header from header', () => { - const heading = headings[2]; - expect(heading.accessor).toEqual(Headings.email); - expect(heading.Header).toEqual(); - }); - test('subsections set key and Header from header', () => { - expect(headings[3]).toEqual({ accessor: fields.field1, Header: fields.field1 }); - expect(headings[4]).toEqual({ accessor: fields.field2, Header: fields.field2 }); - }); - test('totalGrade sets key and replaces Header with component', () => { - const heading = headings[5]; - expect(heading.accessor).toEqual(Headings.totalGrade); - expect(heading.Header.type).toEqual(LabelReplacements.TotalGradeLabelReplacement); - }); - }); - describe('table data (mapRows)', () => { - let rows; - beforeEach(() => { - el = shallow(); - rows = el.find(DataTable).props().data; - }); - describe.each([0, 1, 2])('gradeEntry($percent)', (gradeIndex) => { - let row; - const entry = props.grades[gradeIndex]; - beforeEach(() => { - row = rows[gradeIndex]; - }); - test('username set to Username Field', () => { - const field = row[Headings.username]; - expect(field.type).toEqual(Fields.Username); - expect(field.props).toEqual({ - username: entry.username, - userKey: entry.external_user_key, - }); - }); - test('fullName set to Text Field', () => { - const field = row[Headings.fullName]; - expect(field.type).toEqual(Fields.Text); - expect(field.props).toEqual({ value: entry.full_name }); - }); - test('email set to Text Field', () => { - const field = row[Headings.email]; - expect(field.type).toEqual(Fields.Text); - expect(field.props).toEqual({ value: entry.email }); - }); - test('totalGrade set to rounded percent grade * 100', () => { - expect( - row[Headings.totalGrade], - ).toEqual(`${selectors.grades.roundGrade(entry.percent * 100)}%`); - }); - test('subsections loaded as GradeButtons', () => { - }); - }); - }); - }); - describe('mapStateToProps', () => { - let mapped; - const testState = { - where: 'did', - all: 'of', - these: 'bananas', - come: 'from?', - }; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('grades from grades.allGrades', () => { - expect(mapped.grades).toEqual(selectors.grades.allGrades(testState)); - }); - test('headings from root.getHeadings', () => { - expect(mapped.headings).toEqual(selectors.root.getHeadings(testState)); - }); - }); -}); diff --git a/src/components/GradesView/ImportGradesButton/hooks.test.js b/src/components/GradesView/ImportGradesButton/hooks.test.js index 753dd09..c4439d0 100644 --- a/src/components/GradesView/ImportGradesButton/hooks.test.js +++ b/src/components/GradesView/ImportGradesButton/hooks.test.js @@ -29,7 +29,7 @@ testFormData.append('csv', testFile); const ref = { current: { click: jest.fn(), files: [testFile], value: 'test-value' }, }; -describe('useAssignmentFilterData hook', () => { +describe('useImportButtonData hook', () => { beforeEach(() => { jest.clearAllMocks(); React.useRef.mockReturnValue(ref); diff --git a/src/components/GradesView/ImportSuccessToast.jsx b/src/components/GradesView/ImportSuccessToast.jsx deleted file mode 100644 index a38a2e0..0000000 --- a/src/components/GradesView/ImportSuccessToast.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { Toast } from '@edx/paragon'; -import { - injectIntl, - intlShape, -} from '@edx/frontend-platform/i18n'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import { views } from 'data/constants/app'; -import messages from './ImportSuccessToast.messages'; - -/** - * - * Toast component triggered by successful grade upload. - * Provides a link to view the Bulk Management History tab. - */ -export class ImportSuccessToast extends React.Component { - constructor(props) { - super(props); - this.onClose = this.onClose.bind(this); - this.handleShowHistoryView = this.handleShowHistoryView.bind(this); - } - - onClose() { - this.props.setShow(false); - } - - handleShowHistoryView() { - this.props.setAppView(views.bulkManagementHistory); - this.onClose(); - } - - render() { - return ( - - {this.props.intl.formatMessage(messages.description)} - - ); - } -} - -ImportSuccessToast.propTypes = { - // injected - intl: intlShape.isRequired, - // redux - show: PropTypes.bool.isRequired, - setAppView: PropTypes.func.isRequired, - setShow: PropTypes.func.isRequired, -}; - -export const mapStateToProps = (state) => ({ - show: selectors.app.showImportSuccessToast(state), -}); - -export const mapDispatchToProps = { - setAppView: actions.app.setView, - setShow: actions.app.setShowImportSuccessToast, -}; - -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ImportSuccessToast)); diff --git a/src/components/GradesView/ImportSuccessToast.test.jsx b/src/components/GradesView/ImportSuccessToast.test.jsx deleted file mode 100644 index be13492..0000000 --- a/src/components/GradesView/ImportSuccessToast.test.jsx +++ /dev/null @@ -1,110 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import { views } from 'data/constants/app'; - -import { - ImportSuccessToast, - mapStateToProps, - mapDispatchToProps, -} from './ImportSuccessToast'; -import messages from './ImportSuccessToast.messages'; - -jest.mock('@edx/paragon', () => ({ - Toast: () => 'Toast', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - showImportSuccessToast: (state) => ({ showImportSuccessToast: state }), - }, - }, -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { - setView: jest.fn(), - setShow: jest.fn(), - }, - }, -})); - -describe('ImportSuccessToast component', () => { - describe('snapshots', () => { - let el; - let props = { - show: true, - }; - beforeEach(() => { - props = { - ...props, - intl: { formatMessage: (msg) => msg.defaultMessage }, - setAppView: jest.fn(), - setShow: jest.fn(), - }; - el = shallow(); - }); - test('snapshot', () => { - el.instance().handleShowHistoryView = jest.fn().mockName('handleShowHistoryView'); - el.instance().onClose = jest.fn().mockName('onClose'); - expect(el).toMatchSnapshot(); - }); - describe('Toast props', () => { - let toastProps; - beforeEach(() => { - toastProps = el.props(); - }); - test('action has translated label and onClick from this.handleShowHistoryView', () => { - expect(toastProps.action).toEqual({ - label: props.intl.formatMessage(messages.showHistoryViewBtn), - onClick: el.instance().handleShowHistoryView, - }); - }); - test('onClose from this.onClose method', () => { - expect(toastProps.onClose).toEqual(el.instance().onClose); - }); - test('show from show prop', () => { - expect(toastProps.show).toEqual(props.show); - el.setProps({ show: false }); - expect(el.props().show).toEqual(false); - }); - }); - describe('onClose', () => { - it('calls props.setShow(false)', () => { - el.instance().onClose(); - expect(props.setShow).toHaveBeenCalledWith(false); - }); - }); - describe('handleShowHistoryView', () => { - it('calls setAppView with views.bulkManagementHistory and this.onClose', () => { - el.instance().onClose = jest.fn(); - el.instance().handleShowHistoryView(); - expect(props.setAppView).toHaveBeenCalledWith(views.bulkManagementHistory); - expect(el.instance().onClose).toHaveBeenCalled(); - }); - }); - }); - describe('behavior', () => { - }); - describe('mapStateToProps', () => { - const testState = { somewhere: 'over', the: 'rainbow' }; - const mapped = mapStateToProps(testState); - test('show from app showImportSuccessToast selector', () => { - expect(mapped.show).toEqual( - selectors.app.showImportSuccessToast(testState), - ); - }); - }); - describe('mapDispatchToProps', () => { - test('setAppView from actions.app.setView', () => { - expect(mapDispatchToProps.setAppView).toEqual(actions.app.setView); - }); - test('setShow from actions.setShowImportSuccessToast', () => { - expect(mapDispatchToProps.setShow).toEqual(actions.app.setShowImportSuccessToast); - }); - }); -}); diff --git a/src/components/GradesView/ImportSuccessToast/__snapshots__/index.test.jsx.snap b/src/components/GradesView/ImportSuccessToast/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..e3c7721 --- /dev/null +++ b/src/components/GradesView/ImportSuccessToast/__snapshots__/index.test.jsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ImportSuccessToast component render snapshot 1`] = ` + + test-description + +`; diff --git a/src/components/GradesView/ImportSuccessToast/hooks.js b/src/components/GradesView/ImportSuccessToast/hooks.js new file mode 100644 index 0000000..75db550 --- /dev/null +++ b/src/components/GradesView/ImportSuccessToast/hooks.js @@ -0,0 +1,39 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { actions, selectors } from 'data/redux/hooks'; +import { views } from 'data/constants/app'; +import messages from './messages'; + +/** + * + * Toast component triggered by successful grade upload. + * Provides a link to view the Bulk Management History tab. + */ +export const useImportSuccessToastData = () => { + const { formatMessage } = useIntl(); + + const show = selectors.app.useShowImportSuccessToast(); + const setAppView = actions.app.useSetView(); + const setShow = actions.app.useSetShowImportSuccessToast(); + + const onClose = () => { + setShow(false); + }; + + const handleShowHistoryView = () => { + setAppView(views.bulkManagementHistory); + setShow(false); + }; + + return { + action: { + label: formatMessage(messages.showHistoryViewBtn), + onClick: handleShowHistoryView, + }, + onClose, + show, + description: formatMessage(messages.description), + }; +}; + +export default useImportSuccessToastData; diff --git a/src/components/GradesView/ImportSuccessToast/hooks.test.js b/src/components/GradesView/ImportSuccessToast/hooks.test.js new file mode 100644 index 0000000..8530036 --- /dev/null +++ b/src/components/GradesView/ImportSuccessToast/hooks.test.js @@ -0,0 +1,58 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { views } from 'data/constants/app'; +import { actions, selectors } from 'data/redux/hooks'; + +import useImportSuccessToastData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + app: { + useSetView: jest.fn(), + useSetShowImportSuccessToast: jest.fn(), + }, + }, + selectors: { + app: { useShowImportSuccessToast: jest.fn() }, + }, +})); + +const setView = jest.fn().mockName('hooks.setView'); +const setShowToast = jest.fn().mockName('hooks.setShowImportSuccessToast'); +actions.app.useSetView.mockReturnValue(setView); +actions.app.useSetShowImportSuccessToast.mockReturnValue(setShowToast); +const showImportSuccessToast = 'test-show-import-success-toast'; +selectors.app.useShowImportSuccessToast.mockReturnValue(showImportSuccessToast); + +let out; +describe('ImportSuccessToast component', () => { + beforeAll(() => { + out = useImportSuccessToastData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalledWith(); + }); + it('initializes redux hooks', () => { + expect(selectors.app.useShowImportSuccessToast).toHaveBeenCalled(); + expect(actions.app.useSetView).toHaveBeenCalled(); + expect(actions.app.useSetShowImportSuccessToast).toHaveBeenCalled(); + }); + }); + describe('output', () => { + test('action label', () => { + expect(out.action.label).toEqual(formatMessage(messages.showHistoryViewBtn)); + }); + test('action click event', () => { + out.action.onClick(); + expect(setView).toHaveBeenCalledWith(views.bulkManagementHistory); + expect(setShowToast).toHaveBeenCalledWith(false); + }); + test('onClose', () => { + out.onClose(); + expect(setShowToast).toHaveBeenCalledWith(false); + }); + }); +}); diff --git a/src/components/GradesView/ImportSuccessToast/index.jsx b/src/components/GradesView/ImportSuccessToast/index.jsx new file mode 100644 index 0000000..f9f80f3 --- /dev/null +++ b/src/components/GradesView/ImportSuccessToast/index.jsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import { Toast } from '@edx/paragon'; + +import useImportSuccessToastData from './hooks'; + +/** + * + * Toast component triggered by successful grade upload. + * Provides a link to view the Bulk Management History tab. + */ +export const ImportSuccessToast = () => { + const { + action, + onClose, + show, + description, + } = useImportSuccessToastData(); + return ( + + {description} + + ); +}; + +ImportSuccessToast.propTypes = {}; + +export default ImportSuccessToast; diff --git a/src/components/GradesView/ImportSuccessToast/index.test.jsx b/src/components/GradesView/ImportSuccessToast/index.test.jsx new file mode 100644 index 0000000..d9c7c55 --- /dev/null +++ b/src/components/GradesView/ImportSuccessToast/index.test.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import useImportSuccessToastData from './hooks'; +import ImportSuccessToast from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + action: 'test-action', + onClose: jest.fn().mockName('hooks.onClose'), + show: 'test-show', + description: 'test-description', +}; +useImportSuccessToastData.mockReturnValue(hookProps); + +let el; +describe('ImportSuccessToast component', () => { + beforeAll(() => { + el = shallow(); + }); + describe('behavior', () => { + it('initializes component hook', () => { + expect(useImportSuccessToastData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('Toast', () => { + expect(el.type()).toEqual('Toast'); + expect(el.props().action).toEqual(hookProps.action); + expect(el.props().onClose).toEqual(hookProps.onClose); + expect(el.props().show).toEqual(hookProps.show); + expect(el.text()).toEqual(hookProps.description); + }); + }); +}); diff --git a/src/components/GradesView/ImportSuccessToast.messages.js b/src/components/GradesView/ImportSuccessToast/messages.js similarity index 100% rename from src/components/GradesView/ImportSuccessToast.messages.js rename to src/components/GradesView/ImportSuccessToast/messages.js diff --git a/src/components/GradesView/InterventionsReport.jsx b/src/components/GradesView/InterventionsReport.jsx deleted file mode 100644 index 5a0402f..0000000 --- a/src/components/GradesView/InterventionsReport.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; - -import NetworkButton from 'components/NetworkButton'; -import messages from './InterventionsReport.messages'; - -/** - * - * Provides download buttons for Bulk Management and Intervention reports, only if - * showBulkManagement is set in redus. - */ -export class InterventionsReport extends React.Component { - constructor(props) { - super(props); - this.handleClick = this.handleClick.bind(this); - } - - handleClick() { - this.props.downloadInterventionReport(); - window.location.assign(this.props.interventionExportUrl); - } - - render() { - return this.props.showBulkManagement && ( -
-

- -

-
-
- -
- -
-
- ); - } -} - -InterventionsReport.defaultProps = { - showBulkManagement: false, -}; - -InterventionsReport.propTypes = { - // redux - downloadInterventionReport: PropTypes.func.isRequired, - interventionExportUrl: PropTypes.string.isRequired, - showBulkManagement: PropTypes.bool, -}; - -export const mapStateToProps = (state) => ({ - interventionExportUrl: selectors.root.interventionExportUrl(state), - showBulkManagement: selectors.root.showBulkManagement(state), -}); - -export const mapDispatchToProps = { - downloadInterventionReport: actions.grades.downloadReport.intervention, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(InterventionsReport); diff --git a/src/components/GradesView/InterventionsReport.test.jsx b/src/components/GradesView/InterventionsReport.test.jsx deleted file mode 100644 index 3dfe2b5..0000000 --- a/src/components/GradesView/InterventionsReport.test.jsx +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; - -import { - InterventionsReport, - mapStateToProps, - mapDispatchToProps, -} from './InterventionsReport'; - -jest.mock('@edx/paragon', () => ({ - Toast: () => 'Toast', -})); -jest.mock('components/NetworkButton', () => 'NetworkButton'); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - root: { - interventionExportUrl: (state) => ({ interventionExportUrl: state }), - showBulkManagement: (state) => ({ showBulkManagement: state }), - }, - }, -})); -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - grades: { - downloadReport: { intervention: jest.fn() }, - }, - }, -})); - -describe('InterventionsReport component', () => { - let el; - let props = { - interventionExportUrl: 'url.for.exporting.interventions', - showBulkManagement: true, - }; - let location; - beforeAll(() => { - location = window.location; - }); - beforeEach(() => { - delete window.location; - window.location = Object.defineProperties( - {}, - { - ...Object.getOwnPropertyDescriptors(location), - assign: { configurable: true, value: jest.fn() }, - }, - ); - props = { - ...props, - downloadInterventionReport: jest.fn(), - }; - }); - afterAll(() => { - window.location = location; - }); - describe('snapshots', () => { - beforeEach(() => { - el = shallow(); - }); - test('snapshot', () => { - el.instance().handleClick = jest.fn().mockName('handleClick'); - expect(el.instance().render()).toMatchSnapshot(); - }); - test('returns empty if props.showBulkManagement is false', () => { - el.setProps({ showBulkManagement: false }); - expect(el.instance().render()).toEqual(false); - }); - }); - describe('behavior', () => { - beforeEach(() => { - el = shallow(); - }); - describe('handleClick', () => { - it('calls props.downloadInterventionReport and navigates to props.interventionExportUrl', () => { - el.instance().handleClick(); - expect(props.downloadInterventionReport).toHaveBeenCalled(); - }); - }); - }); - describe('mapStateToProps', () => { - const testState = { somewhere: 'over', the: 'rainbow' }; - const mapped = mapStateToProps(testState); - test('interventionExportUrl from root interventionExportUrl selector', () => { - expect(mapped.interventionExportUrl).toEqual( - selectors.root.interventionExportUrl(testState), - ); - }); - test('showBulkManagement from root showBulkManagement selector', () => { - expect(mapped.showBulkManagement).toEqual( - selectors.root.showBulkManagement(testState), - ); - }); - }); - describe('mapDispatchToProps', () => { - test('downloadInterventionReport from actions.grades.downloadReport.intervention', () => { - expect(mapDispatchToProps.downloadInterventionReport).toEqual( - actions.grades.downloadReport.intervention, - ); - }); - }); -}); diff --git a/src/components/GradesView/InterventionsReport/__snapshots__/index.test.jsx.snap b/src/components/GradesView/InterventionsReport/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..2e130db --- /dev/null +++ b/src/components/GradesView/InterventionsReport/__snapshots__/index.test.jsx.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InterventionsReport component output snapshot 1`] = ` +
+

+ Interventions Report +

+
+
+ Need to find students who may be falling behind? Download the interventions report to obtain engagement metrics such as section attempts and visits. +
+ +
+
+`; diff --git a/src/components/GradesView/InterventionsReport/hooks.js b/src/components/GradesView/InterventionsReport/hooks.js new file mode 100644 index 0000000..493e7f3 --- /dev/null +++ b/src/components/GradesView/InterventionsReport/hooks.js @@ -0,0 +1,19 @@ +import { actions, selectors } from 'data/redux/hooks'; + +const useInterventionsReportData = () => { + const interventionExportUrl = selectors.root.useInterventionExportUrl(); + const showBulkManagement = selectors.root.useShowBulkManagement(); + const downloadInterventionReport = actions.grades.useDownloadInterventionReport(); + + const handleClick = () => { + downloadInterventionReport(); + window.location.assign(interventionExportUrl); + }; + + return { + show: showBulkManagement, + handleClick, + }; +}; + +export default useInterventionsReportData; diff --git a/src/components/GradesView/InterventionsReport/hooks.test.js b/src/components/GradesView/InterventionsReport/hooks.test.js new file mode 100644 index 0000000..357b298 --- /dev/null +++ b/src/components/GradesView/InterventionsReport/hooks.test.js @@ -0,0 +1,56 @@ +import { actions, selectors } from 'data/redux/hooks'; + +import useInterventionsReportData from './hooks'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + grades: { + useDownloadInterventionReport: jest.fn(), + }, + }, + selectors: { + root: { + useInterventionExportUrl: jest.fn(), + useShowBulkManagement: jest.fn(), + }, + }, +})); + +const downloadReport = jest.fn(); +actions.grades.useDownloadInterventionReport.mockReturnValue(downloadReport); +selectors.root.useShowBulkManagement.mockReturnValue(true); +const exportUrl = 'test-intervention-export-url'; +selectors.root.useInterventionExportUrl.mockReturnValue(exportUrl); + +let hook; +let oldLocation; +describe('useInterventionsReportData hooks', () => { + beforeEach(() => { + oldLocation = window.location; + delete window.location; + window.location = { assign: jest.fn() }; + hook = useInterventionsReportData(); + }); + afterEach(() => { + window.location = oldLocation; + }); + describe('behavior', () => { + it('initializes hooks', () => { + expect(selectors.root.useInterventionExportUrl).toHaveBeenCalled(); + expect(selectors.root.useShowBulkManagement).toHaveBeenCalled(); + expect(actions.grades.useDownloadInterventionReport).toHaveBeenCalled(); + }); + }); + describe('output', () => { + test('show from showBulkManagement selector', () => { + expect(hook.show).toEqual(true); + }); + describe('handleClick', () => { + it('downloads interventions report and navigates to export url', () => { + hook.handleClick(); + expect(downloadReport).toHaveBeenCalled(); + expect(window.location.assign).toHaveBeenCalledWith(exportUrl); + }); + }); + }); +}); diff --git a/src/components/GradesView/InterventionsReport/index.jsx b/src/components/GradesView/InterventionsReport/index.jsx new file mode 100644 index 0000000..f19e96e --- /dev/null +++ b/src/components/GradesView/InterventionsReport/index.jsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import NetworkButton from 'components/NetworkButton'; + +import messages from './messages'; +import useInterventionsReportData from './hooks'; + +/** + * + * Provides download buttons for Bulk Management and Intervention reports, only if + * showBulkManagement is set in redus. + */ +export const InterventionsReport = () => { + const { show, handleClick } = useInterventionsReportData(); + const { formatMessage } = useIntl(); + + if (!show) { + return null; + } + + return ( +
+

+ {formatMessage(messages.title)} +

+
+
+ {formatMessage(messages.description)} +
+ +
+
+ ); +}; + +export default InterventionsReport; diff --git a/src/components/GradesView/InterventionsReport/index.test.jsx b/src/components/GradesView/InterventionsReport/index.test.jsx new file mode 100644 index 0000000..0d1c82c --- /dev/null +++ b/src/components/GradesView/InterventionsReport/index.test.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { useIntl } from '@edx/frontend-platform/i18n'; + +import NetworkButton from 'components/NetworkButton'; + +import messages from './messages'; +import useInterventionsReportData from './hooks'; +import InterventionsReport from '.'; + +jest.mock('components/NetworkButton', () => 'NetworkButton'); +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { show: true, handleClick: jest.fn() }; +useInterventionsReportData.mockReturnValue(hookProps); + +let el; +describe('InterventionsReport component', () => { + beforeEach(() => { + el = shallow(); + }); + describe('behavior', () => { + it('initializes hooks', () => { + expect(useInterventionsReportData).toHaveBeenCalledWith(); + expect(useIntl).toHaveBeenCalledWith(); + }); + }); + describe('output', () => { + it('does now render if show is false', () => { + useInterventionsReportData.mockReturnValueOnce({ ...hookProps, show: false }); + el = shallow(); + expect(el.isEmptyRender()).toEqual(true); + }); + test('snapshot', () => { + expect(el).toMatchSnapshot(); + const btnProps = el.find(NetworkButton).props(); + expect(btnProps.label).toEqual(messages.downloadBtn); + expect(btnProps.onClick).toEqual(hookProps.handleClick); + }); + }); +}); diff --git a/src/components/GradesView/InterventionsReport.messages.js b/src/components/GradesView/InterventionsReport/messages.js similarity index 100% rename from src/components/GradesView/InterventionsReport.messages.js rename to src/components/GradesView/InterventionsReport/messages.js diff --git a/src/components/GradesView/PageButtons/PageButtons.test.jsx b/src/components/GradesView/PageButtons/PageButtons.test.jsx deleted file mode 100644 index 4168022..0000000 --- a/src/components/GradesView/PageButtons/PageButtons.test.jsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; - -import { PageButtons, mapStateToProps, mapDispatchToProps } from '.'; - -jest.mock('@edx/paragon', () => ({ - Button: () => 'Button', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - grades: { - nextPage: jest.fn(state => ({ nextPage: state })), - prevPage: jest.fn(state => ({ prevPage: state })), - }, - }, -})); - -jest.mock('data/thunkActions', () => ({ - __esModule: true, - default: { - grades: { - fetchPrevNextGrades: jest.fn(), - }, - }, -})); - -let props; -let el; -describe('PageButtons component', () => { - beforeEach(() => { - props = { - getPrevNextGrades: jest.fn(), - nextPage: 'NEXT PAGE', - prevPage: 'prev PAGE', - }; - }); - describe('snapshots', () => { - beforeEach(() => { - el = shallow(); - el.instance.fetchNextGrades = jest.fn().mockName('fetchNextGrades'); - el.instance.fetchPrevGrades = jest.fn().mockName('fetchPrevGrades'); - }); - test('buttons enabled with both endpoints provided', () => { - expect(el.instance().render()).toMatchSnapshot(); - }); - test('nextPage disabled if not provided', () => { - el.setProps({ nextPage: undefined }); - expect(el.instance().render()).toMatchSnapshot(); - }); - test('prevPage disabled if not provided', () => { - el.setProps({ prevPage: undefined }); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - describe('behavior', () => { - beforeEach(() => { - el = shallow(); - }); - describe('getPrevGrades', () => { - it('calls props.getPrevNextGrades with props.prevPage', () => { - el.instance().getPrevGrades(); - expect(props.getPrevNextGrades).toHaveBeenCalledWith(props.prevPage); - }); - }); - describe('getNextGrades', () => { - it('calls props.getPrevNextGrades with props.nextPage', () => { - el.instance().getNextGrades(); - expect(props.getPrevNextGrades).toHaveBeenCalledWith(props.nextPage); - }); - }); - }); - describe('mapStateToProps', () => { - const testState = { l: 'eeeerroooooy', j: 'jjjjeeeeeeenkins' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('nextPage from grades.nextPage', () => { - expect(mapped.nextPage).toEqual(selectors.grades.nextPage(testState)); - }); - test('prevPage from grades.prevPage', () => { - expect(mapped.prevPage).toEqual(selectors.grades.prevPage(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('getPrevNextGrades from thunkActions.grades.fetchPrevNextGrades', () => { - expect( - mapDispatchToProps.getPrevNextGrades, - ).toEqual(thunkActions.grades.fetchPrevNextGrades); - }); - }); -}); diff --git a/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap b/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap deleted file mode 100644 index 144c7c0..0000000 --- a/src/components/GradesView/PageButtons/__snapshots__/PageButtons.test.jsx.snap +++ /dev/null @@ -1,133 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PageButtons component snapshots buttons enabled with both endpoints provided 1`] = ` -
- - -
-`; - -exports[`PageButtons component snapshots nextPage disabled if not provided 1`] = ` -
- - -
-`; - -exports[`PageButtons component snapshots prevPage disabled if not provided 1`] = ` -
- - -
-`; diff --git a/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap b/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..8fb8ffa --- /dev/null +++ b/src/components/GradesView/PageButtons/__snapshots__/index.test.jsx.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PageButtons component render snapshot 1`] = ` +
+ + +
+`; diff --git a/src/components/GradesView/PageButtons/hooks.js b/src/components/GradesView/PageButtons/hooks.js new file mode 100644 index 0000000..f102342 --- /dev/null +++ b/src/components/GradesView/PageButtons/hooks.js @@ -0,0 +1,34 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { selectors, thunkActions } from 'data/redux/hooks'; +import messages from './messages'; + +export const usePageButtonsData = () => { + const { formatMessage } = useIntl(); + + const { nextPage, prevPage } = selectors.grades.useGradeData(); + const getPrevNextGrades = thunkActions.grades.useFetchPrevNextGrades(); + + const getPrevGrades = () => { + getPrevNextGrades(prevPage); + }; + + const getNextGrades = () => { + getPrevNextGrades(nextPage); + }; + + return { + prev: { + disabled: !prevPage, + onClick: getPrevGrades, + text: formatMessage(messages.prevPage), + }, + next: { + disabled: !nextPage, + onClick: getNextGrades, + text: formatMessage(messages.nextPage), + }, + }; +}; + +export default usePageButtonsData; diff --git a/src/components/GradesView/PageButtons/hooks.test.js b/src/components/GradesView/PageButtons/hooks.test.js new file mode 100644 index 0000000..8d96bec --- /dev/null +++ b/src/components/GradesView/PageButtons/hooks.test.js @@ -0,0 +1,77 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { selectors, thunkActions } from 'data/redux/hooks'; + +import usePageButtonsData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + selectors: { + grades: { useGradeData: jest.fn() }, + }, + thunkActions: { + grades: { useFetchPrevNextGrades: jest.fn() }, + }, +})); + +const gradeData = { nextPage: 'test-next-page', prevPage: 'test-prev-page' }; +selectors.grades.useGradeData.mockReturnValue(gradeData); + +const fetchGrades = jest.fn(); +thunkActions.grades.useFetchPrevNextGrades.mockReturnValue(fetchGrades); + +let out; +describe('usePageButtonsData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = usePageButtonsData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(selectors.grades.useGradeData).toHaveBeenCalled(); + expect(thunkActions.grades.useFetchPrevNextGrades).toHaveBeenCalled(); + }); + }); + describe('output', () => { + describe('prev button entry', () => { + it('is disabled iff prevPage is not provided', () => { + expect(out.prev.disabled).toEqual(false); + selectors.grades.useGradeData.mockReturnValueOnce({ + ...gradeData, + prevPage: undefined, + }); + out = usePageButtonsData(); + expect(out.prev.disabled).toEqual(true); + }); + it('calls fetch with prevPage on click', () => { + out.prev.onClick(); + expect(fetchGrades).toHaveBeenCalledWith(gradeData.prevPage); + }); + test('text display', () => { + expect(out.prev.text).toEqual(formatMessage(messages.prevPage)); + }); + }); + describe('next button entry', () => { + it('is disabled iff nextPage is not provided', () => { + expect(out.next.disabled).toEqual(false); + selectors.grades.useGradeData.mockReturnValueOnce({ + ...gradeData, + nextPage: undefined, + }); + out = usePageButtonsData(); + expect(out.next.disabled).toEqual(true); + }); + it('calls fetch with prevPage on click', () => { + out.next.onClick(); + expect(fetchGrades).toHaveBeenCalledWith(gradeData.nextPage); + }); + test('text display', () => { + expect(out.next.text).toEqual(formatMessage(messages.nextPage)); + }); + }); + }); +}); diff --git a/src/components/GradesView/PageButtons/index.jsx b/src/components/GradesView/PageButtons/index.jsx index 0c2fb1b..bb377f4 100644 --- a/src/components/GradesView/PageButtons/index.jsx +++ b/src/components/GradesView/PageButtons/index.jsx @@ -1,75 +1,37 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { Button } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; -import messages from './messages'; +import usePageButtonsData from './hooks'; -export class PageButtons extends React.Component { - constructor(props) { - super(props); - this.getPrevGrades = this.getPrevGrades.bind(this); - this.getNextGrades = this.getNextGrades.bind(this); - } +export const PageButtons = () => { + const { prev, next } = usePageButtonsData(); - getPrevGrades() { - this.props.getPrevNextGrades(this.props.prevPage); - } - - getNextGrades() { - this.props.getPrevNextGrades(this.props.nextPage); - } - - render() { - return ( -
+ - -
- ); - } -} - -PageButtons.defaultProps = { - nextPage: '', - prevPage: '', + {prev.text} + + +
+ ); }; -PageButtons.propTypes = { - // redux - getPrevNextGrades: PropTypes.func.isRequired, - nextPage: PropTypes.string, - prevPage: PropTypes.string, -}; +PageButtons.propTypes = {}; -export const mapStateToProps = (state) => ({ - nextPage: selectors.grades.nextPage(state), - prevPage: selectors.grades.prevPage(state), -}); - -export const mapDispatchToProps = { - getPrevNextGrades: thunkActions.grades.fetchPrevNextGrades, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(PageButtons); +export default PageButtons; diff --git a/src/components/GradesView/PageButtons/index.test.jsx b/src/components/GradesView/PageButtons/index.test.jsx new file mode 100644 index 0000000..3922408 --- /dev/null +++ b/src/components/GradesView/PageButtons/index.test.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Button } from '@edx/paragon'; + +import usePageButtonsData from './hooks'; +import PageButtons from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + prev: { + disabled: 'prev-disabled', + onClick: jest.fn().mockName('hooks.prev.onClick'), + text: 'prev-text', + }, + next: { + disabled: 'next-disabled', + onClick: jest.fn().mockName('hooks.next.onClick'), + text: 'next-text', + }, +}; +usePageButtonsData.mockReturnValue(hookProps); + +let el; +describe('PageButtons component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes component hooks', () => { + expect(usePageButtonsData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('prev button', () => { + const button = el.find(Button).at(0); + expect(button.props().disabled).toEqual(hookProps.prev.disabled); + expect(button.props().onClick).toEqual(hookProps.prev.onClick); + expect(button.text()).toEqual(hookProps.prev.text); + }); + test('next button', () => { + const button = el.find(Button).at(1); + expect(button.props().disabled).toEqual(hookProps.next.disabled); + expect(button.props().onClick).toEqual(hookProps.next.onClick); + expect(button.text()).toEqual(hookProps.next.text); + }); + }); +}); diff --git a/src/components/GradesView/ScoreViewInput.jsx b/src/components/GradesView/ScoreViewInput.jsx deleted file mode 100644 index 6759573..0000000 --- a/src/components/GradesView/ScoreViewInput.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { FormControl, FormGroup, FormLabel } from '@edx/paragon'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import messages from './ScoreViewInput.messages'; - -/** - * - * redux-connected select control for grade format (percent vs absolute) - */ -export const ScoreViewInput = ({ format, intl, toggleFormat }) => ( - - : - - - - - -); -ScoreViewInput.defaultProps = { - format: 'percent', -}; -ScoreViewInput.propTypes = { - // injected - intl: intlShape.isRequired, - // redux - format: PropTypes.string, - toggleFormat: PropTypes.func.isRequired, -}; - -export const mapStateToProps = (state) => ({ - format: selectors.grades.gradeFormat(state), -}); - -export const mapDispatchToProps = { - toggleFormat: actions.grades.toggleGradeFormat, -}; - -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ScoreViewInput)); diff --git a/src/components/GradesView/ScoreViewInput.test.jsx b/src/components/GradesView/ScoreViewInput.test.jsx deleted file mode 100644 index 1c73418..0000000 --- a/src/components/GradesView/ScoreViewInput.test.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; - -import { - ScoreViewInput, - mapDispatchToProps, - mapStateToProps, -} from './ScoreViewInput'; - -jest.mock('@edx/paragon', () => ({ - FormControl: () => 'FormControl', - FormGroup: () => 'FormGroup', - FormLabel: () => 'FormLabel', -})); - -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - grades: { toggleGradeFormat: jest.fn() }, - }, -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - grades: { gradeFormat: (state) => ({ gradeFormat: state }) }, - }, -})); - -describe('ScoreViewInput', () => { - describe('component', () => { - const props = { format: 'percent' }; - let el; - beforeEach(() => { - props.toggleFormat = jest.fn(); - props.intl = { formatMessage: (msg) => msg.defaultMessage }; - el = shallow(); - }); - const assertions = [ - 'select box with percent and absolute options', - 'onClick from props.toggleFormat', - ]; - test(`snapshot - ${assertions.join(' and ')}`, () => { - expect(el).toMatchSnapshot(); - }); - }); - describe('mapStateToProps', () => { - test('format from grades.gradeFormat', () => { - const testState = { some: 'state' }; - expect(mapStateToProps(testState).format).toEqual(selectors.grades.gradeFormat(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('toggleFormat from actions.grades.toggleGradeFormat', () => { - expect(mapDispatchToProps.toggleFormat).toEqual(actions.grades.toggleGradeFormat); - }); - }); -}); diff --git a/src/components/GradesView/ScoreViewInput/__snapshots__/index.test.jsx.snap b/src/components/GradesView/ScoreViewInput/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..d687f4c --- /dev/null +++ b/src/components/GradesView/ScoreViewInput/__snapshots__/index.test.jsx.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ScoreViewInput component render snapshot 1`] = ` + + + Score View + : + + + + + + +`; diff --git a/src/components/GradesView/ScoreViewInput/index.jsx b/src/components/GradesView/ScoreViewInput/index.jsx new file mode 100644 index 0000000..09519c5 --- /dev/null +++ b/src/components/GradesView/ScoreViewInput/index.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { Form } from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { actions, selectors } from 'data/redux/hooks'; +import messages from './messages'; + +/** + * + * redux-connected select control for grade format (percent vs absolute) + */ +export const ScoreViewInput = () => { + const { formatMessage } = useIntl(); + const { gradeFormat } = selectors.grades.useGradeData(); + const toggleFormat = actions.grades.useToggleGradeFormat(); + return ( + + {formatMessage(messages.scoreView)}: + + + + + + ); +}; +ScoreViewInput.propTypes = {}; + +export default ScoreViewInput; diff --git a/src/components/GradesView/ScoreViewInput/index.test.jsx b/src/components/GradesView/ScoreViewInput/index.test.jsx new file mode 100644 index 0000000..bb2462f --- /dev/null +++ b/src/components/GradesView/ScoreViewInput/index.test.jsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { useIntl } from '@edx/frontend-platform/i18n'; +import { GradeFormats } from 'data/constants/grades'; + +import { formatMessage } from 'testUtils'; +import { actions, selectors } from 'data/redux/hooks'; +import ScoreViewInput from '.'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + grades: { useToggleGradeFormat: jest.fn() }, + }, + selectors: { + grades: { useGradeData: jest.fn() }, + }, +})); + +const toggleGradeFormat = jest.fn().mockName('hooks.toggleGradeFormat'); +actions.grades.useToggleGradeFormat.mockReturnValue(toggleGradeFormat); +const gradeFormat = 'test-grade-format'; +selectors.grades.useGradeData.mockReturnValue({ gradeFormat }); + +let el; +describe('ScoreViewInput component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(actions.grades.useToggleGradeFormat).toHaveBeenCalled(); + expect(selectors.grades.useGradeData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('label', () => { + const label = el.children().at(0); + expect(label.text()).toEqual(`${formatMessage(messages.scoreView)}:`); + }); + describe('form control', () => { + let control; + beforeEach(() => { + control = el.children().at(1); + }); + test('value and onChange from redux hooks', () => { + expect(control.props().value).toEqual(gradeFormat); + expect(control.props().onChange).toEqual(toggleGradeFormat); + }); + test('absolute and percent options', () => { + const children = control.children(); + expect(children.at(0).props().value).toEqual(GradeFormats.percent); + expect(children.at(0).text()).toEqual(formatMessage(messages.percent)); + expect(children.at(1).props().value).toEqual(GradeFormats.absolute); + expect(children.at(1).text()).toEqual(formatMessage(messages.absolute)); + }); + }); + }); +}); diff --git a/src/components/GradesView/ScoreViewInput.messages.js b/src/components/GradesView/ScoreViewInput/messages.js similarity index 100% rename from src/components/GradesView/ScoreViewInput.messages.js rename to src/components/GradesView/ScoreViewInput/messages.js diff --git a/src/components/GradesView/SearchControls.jsx b/src/components/GradesView/SearchControls.jsx deleted file mode 100644 index 08124fe..0000000 --- a/src/components/GradesView/SearchControls.jsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { SearchField } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import thunkActions from 'data/thunkActions'; - -import messages from './SearchControls.messages'; - -/** - * Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer - * as well as the search box for searching by username/email. - */ -export class SearchControls extends React.Component { - constructor(props) { - super(props); - - this.onBlur = this.onBlur.bind(this); - this.onClear = this.onClear.bind(this); - this.onSubmit = this.onSubmit.bind(this); - } - - onBlur(e) { - this.props.setSearchValue(e.target.value); - } - - onClear() { - this.props.setSearchValue(''); - this.props.fetchGrades(); - } - - onSubmit(searchValue) { - this.props.setSearchValue(searchValue); - this.props.fetchGrades(); - } - - render() { - return ( -
- } - onBlur={this.onBlur} - onClear={this.onClear} - value={this.props.searchValue} - /> - - - -
- ); - } -} - -SearchControls.propTypes = { - // From Redux - fetchGrades: PropTypes.func.isRequired, - searchValue: PropTypes.string.isRequired, - setSearchValue: PropTypes.func.isRequired, -}; - -export const mapStateToProps = (state) => ({ - searchValue: selectors.app.searchValue(state), -}); - -export const mapDispatchToProps = { - fetchGrades: thunkActions.grades.fetchGrades, - setSearchValue: actions.app.setSearchValue, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(SearchControls); diff --git a/src/components/GradesView/SearchControls.test.jsx b/src/components/GradesView/SearchControls.test.jsx deleted file mode 100644 index b181d91..0000000 --- a/src/components/GradesView/SearchControls.test.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import thunkActions from 'data/thunkActions'; -import { - mapDispatchToProps, - mapStateToProps, - SearchControls, -} from './SearchControls'; - -jest.mock('@edx/paragon', () => ({ - Icon: 'Icon', - Button: 'Button', - SearchField: 'SearchField', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - searchValue: jest.fn((state) => ({ searchValue: state })), - }, - }, -})); -jest.mock('data/thunkActions', () => ({ - __esModule: true, - default: { - grades: { - fetchGrades: jest.fn().mockName('thunkActions.grades.fetchGrades'), - }, - app: { - filterMenu: { toggle: jest.fn().mockName('thunkActions.app.filterMenu') }, - }, - }, -})); - -describe('SearchControls', () => { - let props; - - beforeEach(() => { - jest.resetAllMocks(); - props = { - searchValue: 'alice', - setSearchValue: jest.fn(), - fetchGrades: jest.fn().mockName('fetchGrades'), - }; - }); - - const searchControls = (overriddenProps) => { - props = { ...props, ...overriddenProps }; - return shallow(); - }; - - describe('Component', () => { - describe('Snapshots', () => { - test('basic snapshot', () => { - const wrapper = searchControls(); - wrapper.instance().onBlur = jest.fn().mockName('onBlur'); - wrapper.instance().onClear = jest.fn().mockName('onClear'); - wrapper.instance().onSubmit = jest.fn().mockName('onSubmit'); - expect(wrapper.instance().render()).toMatchSnapshot(); - }); - }); - - describe('Behavior', () => { - describe('onBlur', () => { - it('saves the search value to Gradebook state but do not fetch grade', () => { - const wrapper = searchControls(); - const event = { - target: { - value: 'bob', - }, - }; - wrapper.instance().onBlur(event); - expect(props.setSearchValue).toHaveBeenCalledWith('bob'); - expect(props.fetchGrades).not.toHaveBeenCalled(); - }); - }); - - describe('onClear', () => { - it('sets search value to empty string and calls fetchGrades', () => { - const wrapper = searchControls(); - wrapper.instance().onClear(); - expect(props.setSearchValue).toHaveBeenCalledWith(''); - expect(props.fetchGrades).toHaveBeenCalled(); - }); - }); - - describe('onSubmit', () => { - it('sets search value to input and calls fetchGrades', () => { - const wrapper = searchControls(); - - wrapper.instance().onSubmit('John'); - expect(props.setSearchValue).toHaveBeenCalledWith('John'); - expect(props.fetchGrades).toHaveBeenCalled(); - }); - }); - }); - - describe('mapStateToProps', () => { - const testState = { never: 'gonna', give: 'you up' }; - test('searchValue from app.searchValue', () => { - expect( - mapStateToProps(testState).searchValue, - ).toEqual(selectors.app.searchValue(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('fetchGrades from thunkActions.grades.fetchGrades', () => { - expect(mapDispatchToProps.fetchGrades).toEqual(thunkActions.grades.fetchGrades); - }); - - test('setSearchValue from actions.app.setSearchValue', () => { - expect(mapDispatchToProps.setSearchValue).toEqual(actions.app.setSearchValue); - }); - }); - }); -}); diff --git a/src/components/GradesView/SearchControls/__snapshots__/index.test.jsx.snap b/src/components/GradesView/SearchControls/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..d9f5c94 --- /dev/null +++ b/src/components/GradesView/SearchControls/__snapshots__/index.test.jsx.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SearchControls component render snapshot 1`] = ` +
+ + + test-hint-text + +
+`; diff --git a/src/components/GradesView/SearchControls/hooks.js b/src/components/GradesView/SearchControls/hooks.js new file mode 100644 index 0000000..8ce4973 --- /dev/null +++ b/src/components/GradesView/SearchControls/hooks.js @@ -0,0 +1,41 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { actions, selectors, thunkActions } from 'data/redux/hooks'; + +import messages from './messages'; + +/** + * Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer + * as well as the search box for searching by username/email. + */ +export const useSearchControlsData = () => { + const { formatMessage } = useIntl(); + const searchValue = selectors.app.useSearchValue(); + const fetchGrades = thunkActions.grades.useFetchGrades(); + const setSearchValue = actions.app.useSetSearchValue(); + + const onBlur = (e) => { + setSearchValue(e.target.value); + }; + + const onClear = () => { + setSearchValue(''); + fetchGrades(); + }; + + const onSubmit = (newValue) => { + setSearchValue(newValue); + fetchGrades(); + }; + + return { + onSubmit, + onBlur, + onClear, + searchValue, + inputLabel: formatMessage(messages.label), + hintText: formatMessage(messages.hint), + }; +}; + +export default useSearchControlsData; diff --git a/src/components/GradesView/SearchControls/hooks.test.js b/src/components/GradesView/SearchControls/hooks.test.js new file mode 100644 index 0000000..db0c291 --- /dev/null +++ b/src/components/GradesView/SearchControls/hooks.test.js @@ -0,0 +1,71 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { actions, selectors, thunkActions } from 'data/redux/hooks'; + +import useSearchControlsData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + app: { useSetSearchValue: jest.fn() }, + }, + selectors: { + app: { useSearchValue: jest.fn() }, + }, + thunkActions: { + grades: { useFetchGrades: jest.fn() }, + }, +})); + +const searchValue = 'test-search-value'; +selectors.app.useSearchValue.mockReturnValue(searchValue); +const setSearchValue = jest.fn(); +actions.app.useSetSearchValue.mockReturnValue(setSearchValue); +const fetchGrades = jest.fn(); +thunkActions.grades.useFetchGrades.mockReturnValue(fetchGrades); + +const testValue = 'test-value'; +let out; +describe('useSearchControlsData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useSearchControlsData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(actions.app.useSetSearchValue).toHaveBeenCalled(); + expect(selectors.app.useSearchValue).toHaveBeenCalled(); + expect(thunkActions.grades.useFetchGrades).toHaveBeenCalled(); + }); + }); + describe('output', () => { + test('onSubmit sets search value and fetches grades', () => { + out.onSubmit(testValue); + expect(setSearchValue).toHaveBeenCalledWith(testValue); + expect(fetchGrades).toHaveBeenCalled(); + }); + test('onBlur sets search value to event target', () => { + out.onBlur({ target: { value: testValue } }); + expect(setSearchValue).toHaveBeenCalledWith(testValue); + expect(fetchGrades).not.toHaveBeenCalled(); + }); + test('onClear clears search value and fetches grades', () => { + out.onClear(); + expect(setSearchValue).toHaveBeenCalledWith(''); + expect(fetchGrades).toHaveBeenCalled(); + }); + it('forwards searchValue from redux', () => { + expect(out.searchValue).toEqual(searchValue); + }); + test('input label message', () => { + expect(out.inputLabel).toEqual(formatMessage(messages.label)); + }); + test('hint text message', () => { + expect(out.hintText).toEqual(formatMessage(messages.hint)); + }); + }); +}); diff --git a/src/components/GradesView/SearchControls/index.jsx b/src/components/GradesView/SearchControls/index.jsx new file mode 100644 index 0000000..17f418b --- /dev/null +++ b/src/components/GradesView/SearchControls/index.jsx @@ -0,0 +1,38 @@ +import React from 'react'; + +import { SearchField } from '@edx/paragon'; +import useSearchControlsData from './hooks'; + +/** + * Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer + * as well as the search box for searching by username/email. + */ +export const SearchControls = () => { + const { + onSubmit, + onBlur, + onClear, + searchValue, + inputLabel, + hintText, + } = useSearchControlsData(); + + return ( +
+ + + {hintText} + +
+ ); +}; + +SearchControls.propTypes = {}; + +export default SearchControls; diff --git a/src/components/GradesView/SearchControls/index.test.jsx b/src/components/GradesView/SearchControls/index.test.jsx new file mode 100644 index 0000000..ae9a102 --- /dev/null +++ b/src/components/GradesView/SearchControls/index.test.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { SearchField } from '@edx/paragon'; + +import useSearchControlsData from './hooks'; +import SearchControls from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + onSubmit: jest.fn().mockName('hooks.onSubmit'), + onBlur: jest.fn().mockName('hooks.onBlur'), + onClear: jest.fn().mockName('hooks.onClear'), + searchValue: 'test-search-value', + inputLabel: 'test-input-label', + hintText: 'test-hint-text', +}; +useSearchControlsData.mockReturnValue(hookProps); + +let el; +describe('SearchControls component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes component hooks', () => { + expect(useSearchControlsData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('search field', () => { + const props = el.find(SearchField).props(); + expect(props.onSubmit).toEqual(hookProps.onSubmit); + expect(props.onBlur).toEqual(hookProps.onBlur); + expect(props.onClear).toEqual(hookProps.onClear); + expect(props.inputLabel).toEqual(hookProps.inputLabel); + expect(props.value).toEqual(hookProps.searchValue); + }); + test('hint text', () => { + expect(el.find('small').text()).toEqual(hookProps.hintText); + }); + }); +}); diff --git a/src/components/GradesView/SearchControls.messages.js b/src/components/GradesView/SearchControls/messages.js similarity index 100% rename from src/components/GradesView/SearchControls.messages.js rename to src/components/GradesView/SearchControls/messages.js diff --git a/src/components/GradesView/SpinnerIcon.jsx b/src/components/GradesView/SpinnerIcon.jsx index 398201c..da044d6 100644 --- a/src/components/GradesView/SpinnerIcon.jsx +++ b/src/components/GradesView/SpinnerIcon.jsx @@ -1,31 +1,22 @@ -/* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { Icon } from '@edx/paragon'; -import selectors from 'data/selectors'; +import { selectors } from 'data/redux/hooks'; /** * * Simmple redux-connected icon component that shows a spinner overlay only if * redux state says it should. */ -export const SpinnerIcon = ({ show }) => show && ( -
- -
-); -SpinnerIcon.defaultProps = { - show: false, -}; -SpinnerIcon.propTypes = { - show: PropTypes.bool, +export const SpinnerIcon = () => { + const show = selectors.root.useShouldShowSpinner(); + return show && ( +
+ +
+ ); }; +SpinnerIcon.propTypes = {}; -export const mapStateToProps = (state) => ({ - show: selectors.root.shouldShowSpinner(state), -}); - -export default connect(mapStateToProps)(SpinnerIcon); +export default SpinnerIcon; diff --git a/src/components/GradesView/SpinnerIcon.test.jsx b/src/components/GradesView/SpinnerIcon.test.jsx index 0ffd088..031cf1b 100644 --- a/src/components/GradesView/SpinnerIcon.test.jsx +++ b/src/components/GradesView/SpinnerIcon.test.jsx @@ -1,32 +1,35 @@ import React from 'react'; import { shallow } from 'enzyme'; -import selectors from 'data/selectors'; -import { SpinnerIcon, mapStateToProps } from './SpinnerIcon'; +import { selectors } from 'data/redux/hooks'; +import SpinnerIcon from './SpinnerIcon'; -jest.mock('@edx/paragon', () => ({ - Icon: () => 'Icon', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - root: { shouldShowSpinner: state => ({ shouldShowSpinner: state }) }, +jest.mock('data/redux/hooks', () => ({ + selectors: { + root: { useShouldShowSpinner: jest.fn() }, }, })); +selectors.root.useShouldShowSpinner.mockReturnValue(true); +let el; describe('SpinnerIcon', () => { - describe('component', () => { - it('snapshot - does not render if show: false', () => { - expect(shallow()).toMatchSnapshot(); - }); - test('snapshot - displays spinner overlay with spinner icon', () => { - expect(shallow()).toMatchSnapshot(); + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes redux hook', () => { + expect(selectors.root.useShouldShowSpinner).toHaveBeenCalled(); }); }); - describe('mapStateToProps', () => { - const testState = { a: 'nice', day: 'for', some: 'sun' }; - test('show from root.shouldShowSpinner', () => { - expect(mapStateToProps(testState).show).toEqual(selectors.root.shouldShowSpinner(testState)); + describe('component', () => { + it('does not render if show: false', () => { + selectors.root.useShouldShowSpinner.mockReturnValueOnce(false); + el = shallow(); + expect(el.isEmptyRender()).toEqual(true); + }); + test('snapshot - displays spinner overlay with spinner icon', () => { + expect(el).toMatchSnapshot(); }); }); }); diff --git a/src/components/GradesView/StatusAlerts.jsx b/src/components/GradesView/StatusAlerts.jsx deleted file mode 100644 index 74f60fb..0000000 --- a/src/components/GradesView/StatusAlerts.jsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { Alert } from '@edx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import selectors from 'data/selectors'; -import actions from 'data/actions'; -import messages from './StatusAlerts.messages'; - -export class StatusAlerts extends React.Component { - get isCourseGradeFilterAlertOpen() { - return ( - !this.props.limitValidity.isMinValid - || !this.props.limitValidity.isMaxValid - ); - } - - get minValidityMessage() { - return (this.props.limitValidity.isMinValid) - ? '' - : ; - } - - get maxValidityMessage() { - return (this.props.limitValidity.isMaxValid) - ? '' - : ; - } - - get courseGradeFilterAlertDialogText() { - return ( - <> - {this.minValidityMessage}{this.maxValidityMessage} - - ); - } - - render() { - return ( - <> - - - - - {this.courseGradeFilterAlertDialogText} - - - ); - } -} - -StatusAlerts.defaultProps = { -}; - -StatusAlerts.propTypes = { - // redux - handleCloseSuccessBanner: PropTypes.func.isRequired, - limitValidity: PropTypes.shape({ - isMaxValid: PropTypes.bool, - isMinValid: PropTypes.bool, - }).isRequired, - showSuccessBanner: PropTypes.bool.isRequired, -}; - -export const mapStateToProps = (state) => ({ - limitValidity: selectors.app.courseGradeFilterValidity(state), - showSuccessBanner: selectors.grades.showSuccess(state), -}); - -export const mapDispatchToProps = { - handleCloseSuccessBanner: actions.grades.banner.close, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(StatusAlerts); diff --git a/src/components/GradesView/StatusAlerts.test.jsx b/src/components/GradesView/StatusAlerts.test.jsx deleted file mode 100644 index ba2d799..0000000 --- a/src/components/GradesView/StatusAlerts.test.jsx +++ /dev/null @@ -1,123 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import selectors from 'data/selectors'; -import messages from './StatusAlerts.messages'; -import { - StatusAlerts, - mapDispatchToProps, - mapStateToProps, -} from './StatusAlerts'; - -jest.mock('@edx/paragon', () => ({ - Alert: 'Alert', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - app: { - courseGradeFilterValidity: (state) => ({ courseGradeFilterValidity: state }), - }, - grades: { - showSuccess: (state) => ({ showSuccess: state }), - }, - }, -})); - -describe('StatusAlerts', () => { - let props = { - showSuccessBanner: true, - limitValidity: { - isMaxValid: true, - isMinValid: true, - }, - }; - - beforeEach(() => { - props = { - ...props, - handleCloseSuccessBanner: jest.fn().mockName('handleCloseSuccessBanner'), - }; - }); - - describe('snapshots', () => { - let el; - it('basic snapshot', () => { - el = shallow(); - const courseGradeFilterAlertDialogText = 'the quiCk brown does somEthing or other'; - jest.spyOn( - el.instance(), - 'courseGradeFilterAlertDialogText', - 'get', - ).mockReturnValue(courseGradeFilterAlertDialogText); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - - describe('behavior', () => { - it.each([ - [false, false], - [false, true], - [true, false], - [true, true], - ])('min + max course grade validity', (isMinValid, isMaxValid) => { - props = { - ...props, - limitValidity: { - isMinValid, - isMaxValid, - }, - }; - const el = shallow(); - expect( - el.instance().isCourseGradeFilterAlertOpen, - ).toEqual( - !isMinValid || !isMaxValid, - ); - if (!isMaxValid) { - if (!isMinValid) { - expect(el.instance().courseGradeFilterAlertDialogText).toEqual( - <> - - - , - ); - } else { - expect( - el.instance().courseGradeFilterAlertDialogText, - // eslint-disable-next-line react/jsx-curly-brace-presence - ).toEqual(<>{''}); - } - } else if (!isMinValid) { - expect( - el.instance().courseGradeFilterAlertDialogText, - // eslint-disable-next-line react/jsx-curly-brace-presence - ).toEqual(<>{''}); - } - }); - }); - - describe('mapStateToProps', () => { - const testState = { A: 'pple', B: 'anana', C: 'ucumber' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('limitValidity from app.courseGradeFitlerValidity', () => { - expect(mapped.limitValidity).toEqual(selectors.app.courseGradeFilterValidity(testState)); - }); - test('showSuccessBanner from grades.showSuccess', () => { - expect(mapped.showSuccessBanner).toEqual(selectors.grades.showSuccess(testState)); - }); - }); - describe('mapDispatchToProps', () => { - test('handleCloseSuccessBanner from actions.grades.banner.close', () => { - expect( - mapDispatchToProps.handleCloseSuccessBanner, - ).toEqual(actions.grades.banner.close); - }); - }); -}); diff --git a/src/components/GradesView/StatusAlerts/__snapshots__/index.test.jsx.snap b/src/components/GradesView/StatusAlerts/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..a842973 --- /dev/null +++ b/src/components/GradesView/StatusAlerts/__snapshots__/index.test.jsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StatusAlerts component render snapshot 1`] = ` + + + hooks.success-banner-text + + + hooks.grade-filter-text + + +`; diff --git a/src/components/GradesView/StatusAlerts/hooks.js b/src/components/GradesView/StatusAlerts/hooks.js new file mode 100644 index 0000000..efcd8a5 --- /dev/null +++ b/src/components/GradesView/StatusAlerts/hooks.js @@ -0,0 +1,32 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { actions, selectors } from 'data/redux/hooks'; +import messages from './messages'; + +export const useStatusAlertsData = () => { + const { formatMessage } = useIntl(); + + const limitValidity = selectors.app.useCourseGradeFilterValidity(); + const showSuccessBanner = selectors.grades.useShowSuccess(); + const handleCloseSuccessBanner = actions.grades.useCloseBanner(); + + const isCourseGradeFilterAlertOpen = !limitValidity.isMinValid || !limitValidity.isMaxValid; + + const validityMessages = { + min: limitValidity.isMinValid ? '' : formatMessage(messages.minGradeInvalid), + max: limitValidity.isMaxValid ? '' : formatMessage(messages.maxGradeInvalid), + }; + + return { + successBanner: { + onClose: handleCloseSuccessBanner, + show: showSuccessBanner, + text: formatMessage(messages.editSuccessAlert), + }, + gradeFilter: { + show: isCourseGradeFilterAlertOpen, + text: `${validityMessages.min}${validityMessages.max}`, + }, + }; +}; +export default useStatusAlertsData; diff --git a/src/components/GradesView/StatusAlerts/hooks.test.js b/src/components/GradesView/StatusAlerts/hooks.test.js new file mode 100644 index 0000000..4b0e11f --- /dev/null +++ b/src/components/GradesView/StatusAlerts/hooks.test.js @@ -0,0 +1,110 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { actions, selectors } from 'data/redux/hooks'; + +import useStatusAlertsData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + grades: { useCloseBanner: jest.fn() }, + }, + selectors: { + app: { useCourseGradeFilterValidity: jest.fn() }, + grades: { useShowSuccess: jest.fn() }, + }, +})); + +const validity = { + isMinValid: true, + isMaxValid: true, +}; +selectors.app.useCourseGradeFilterValidity.mockReturnValue(validity); +const showSuccess = 'test-show-success'; +selectors.grades.useShowSuccess.mockReturnValue(showSuccess); +const closeBanner = jest.fn().mockName('hooks.closeBanner'); +actions.grades.useCloseBanner.mockReturnValue(closeBanner); + +let out; +describe('useStatusAlertsData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useStatusAlertsData(); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(actions.grades.useCloseBanner).toHaveBeenCalled(); + expect(selectors.app.useCourseGradeFilterValidity).toHaveBeenCalled(); + expect(selectors.grades.useShowSuccess).toHaveBeenCalled(); + }); + }); + describe('output', () => { + describe('successBanner', () => { + test('onClose and show from redux', () => { + expect(out.successBanner.onClose).toEqual(closeBanner); + expect(out.successBanner.show).toEqual(showSuccess); + }); + test('message', () => { + expect(out.successBanner.text).toEqual(formatMessage(messages.editSuccessAlert)); + }); + }); + describe('gradeFilter', () => { + describe('both filters are valid', () => { + test('do not show', () => { + expect(out.gradeFilter.show).toEqual(false); + }); + }); + describe('min filter is invalid', () => { + beforeEach(() => { + selectors.app.useCourseGradeFilterValidity.mockReturnValue({ + isMinValid: false, + isMaxValid: true, + }); + out = useStatusAlertsData(); + }); + test('show grade filter banner', () => { + expect(out.gradeFilter.show).toEqual(true); + }); + test('filter message', () => { + expect(out.gradeFilter.text).toEqual(formatMessage(messages.minGradeInvalid)); + }); + }); + describe('max filter is invalid', () => { + beforeEach(() => { + selectors.app.useCourseGradeFilterValidity.mockReturnValue({ + isMinValid: true, + isMaxValid: false, + }); + out = useStatusAlertsData(); + }); + test('show grade filter banner', () => { + expect(out.gradeFilter.show).toEqual(true); + }); + test('filter message', () => { + expect(out.gradeFilter.text).toEqual(formatMessage(messages.maxGradeInvalid)); + }); + }); + describe('both filters are invalid', () => { + beforeEach(() => { + selectors.app.useCourseGradeFilterValidity.mockReturnValue({ + isMinValid: false, + isMaxValid: false, + }); + out = useStatusAlertsData(); + }); + test('show grade filter banner', () => { + expect(out.gradeFilter.show).toEqual(true); + }); + test('filter message', () => { + expect(out.gradeFilter.text).toEqual( + `${formatMessage(messages.minGradeInvalid)}${formatMessage(messages.maxGradeInvalid)}`, + ); + }); + }); + }); + }); +}); diff --git a/src/components/GradesView/StatusAlerts/index.jsx b/src/components/GradesView/StatusAlerts/index.jsx new file mode 100644 index 0000000..f7883ff --- /dev/null +++ b/src/components/GradesView/StatusAlerts/index.jsx @@ -0,0 +1,35 @@ +import React from 'react'; + +import { Alert } from '@edx/paragon'; + +import useStatusAlertsData from './hooks'; + +export const StatusAlerts = () => { + const { + successBanner, + gradeFilter, + } = useStatusAlertsData(); + + return ( + <> + + {successBanner.text} + + + {gradeFilter.text} + + + ); +}; + +StatusAlerts.propTypes = {}; + +export default StatusAlerts; diff --git a/src/components/GradesView/StatusAlerts/index.test.jsx b/src/components/GradesView/StatusAlerts/index.test.jsx new file mode 100644 index 0000000..408044d --- /dev/null +++ b/src/components/GradesView/StatusAlerts/index.test.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Alert } from '@edx/paragon'; + +import useStatusAlertsData from './hooks'; +import StatusAlerts from '.'; + +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + successBanner: { + onClose: jest.fn().mockName('hooks.successBanner.onClose'), + show: 'hooks.show-success-banner', + text: 'hooks.success-banner-text', + }, + gradeFilter: { + show: 'hooks.show-grade-filter', + text: 'hooks.grade-filter-text', + }, +}; +useStatusAlertsData.mockReturnValue(hookProps); + +let el; +describe('StatusAlerts component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes component hooks', () => { + expect(useStatusAlertsData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('success banner', () => { + const alert = el.find(Alert).at(0); + const props = alert.props(); + expect(props.onClose).toEqual(hookProps.successBanner.onClose); + expect(props.show).toEqual(hookProps.successBanner.show); + expect(alert.text()).toEqual(hookProps.successBanner.text); + }); + test('grade filter banner', () => { + const alert = el.find(Alert).at(1); + const props = alert.props(); + expect(props.show).toEqual(hookProps.gradeFilter.show); + expect(alert.text()).toEqual(hookProps.gradeFilter.text); + }); + }); +}); diff --git a/src/components/GradesView/StatusAlerts.messages.js b/src/components/GradesView/StatusAlerts/messages.js similarity index 100% rename from src/components/GradesView/StatusAlerts.messages.js rename to src/components/GradesView/StatusAlerts/messages.js diff --git a/src/components/GradesView/UsersLabel.jsx b/src/components/GradesView/UsersLabel.jsx deleted file mode 100644 index ac6df0f..0000000 --- a/src/components/GradesView/UsersLabel.jsx +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import selectors from 'data/selectors'; - -/** - * - * Simple label component displaying the filtered and total users shown - */ -export const UsersLabel = ({ - filteredUsersCount, - totalUsersCount, -}) => { - if (!totalUsersCount) { - return null; - } - const bold = (val) => ({val}); - return ( - - ); -}; -UsersLabel.propTypes = { - filteredUsersCount: PropTypes.number.isRequired, - totalUsersCount: PropTypes.number.isRequired, -}; - -export const mapStateToProps = (state) => ({ - totalUsersCount: selectors.grades.totalUsersCount(state), - filteredUsersCount: selectors.grades.filteredUsersCount(state), -}); - -export default connect(mapStateToProps)(UsersLabel); diff --git a/src/components/GradesView/UsersLabel.test.jsx b/src/components/GradesView/UsersLabel.test.jsx deleted file mode 100644 index 43a4335..0000000 --- a/src/components/GradesView/UsersLabel.test.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import selectors from 'data/selectors'; -import { UsersLabel, mapStateToProps } from './UsersLabel'; - -jest.mock('@edx/paragon', () => ({ - Icon: () => 'Icon', -})); -jest.mock('data/selectors', () => ({ - __esModule: true, - default: { - grades: { - filteredUsersCount: state => ({ filteredUsersCount: state }), - totalUsersCount: state => ({ totalUsersCount: state }), - }, - }, -})); - -describe('UsersLabel', () => { - describe('component', () => { - const props = { - filteredUsersCount: 23, - totalUsersCount: 140, - }; - it('does not render if totalUsersCount is falsey', () => { - expect(shallow()).toEqual({}); - }); - test('snapshot - displays label with number of filtered users out of total', () => { - expect(shallow()).toMatchSnapshot(); - }); - }); - describe('mapStateToProps', () => { - const testState = { a: 'nice', day: 'for', some: 'rain' }; - let mapped; - beforeEach(() => { - mapped = mapStateToProps(testState); - }); - test('filteredUsersCount from grades.filteredUsersCount', () => { - expect(mapped.filteredUsersCount).toEqual(selectors.grades.filteredUsersCount(testState)); - }); - test('totalUsersCount from grades.totalUsersCount', () => { - expect(mapped.totalUsersCount).toEqual(selectors.grades.totalUsersCount(testState)); - }); - }); -}); diff --git a/src/components/GradesView/__snapshots__/FilterMenuToggle.test.jsx.snap b/src/components/GradesView/__snapshots__/FilterMenuToggle.test.jsx.snap deleted file mode 100644 index 9b66b38..0000000 --- a/src/components/GradesView/__snapshots__/FilterMenuToggle.test.jsx.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FilterMenuToggle component snapshots basic snapshot 1`] = ` - -`; diff --git a/src/components/GradesView/__snapshots__/FilteredUsersLabel.test.jsx.snap b/src/components/GradesView/__snapshots__/FilteredUsersLabel.test.jsx.snap deleted file mode 100644 index 2086de8..0000000 --- a/src/components/GradesView/__snapshots__/FilteredUsersLabel.test.jsx.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FilteredUsersLabel component snapshot - displays label with number of filtered users out of total 1`] = ` - - 23 - , - "totalUsers": - 140 - , - } - } -/> -`; diff --git a/src/components/GradesView/__snapshots__/ImportSuccessToast.test.jsx.snap b/src/components/GradesView/__snapshots__/ImportSuccessToast.test.jsx.snap deleted file mode 100644 index b42d994..0000000 --- a/src/components/GradesView/__snapshots__/ImportSuccessToast.test.jsx.snap +++ /dev/null @@ -1,16 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ImportSuccessToast component snapshots snapshot 1`] = ` - - Import Successful! Grades will be updated momentarily. - -`; diff --git a/src/components/GradesView/__snapshots__/InterventionsReport.test.jsx.snap b/src/components/GradesView/__snapshots__/InterventionsReport.test.jsx.snap deleted file mode 100644 index 44210b1..0000000 --- a/src/components/GradesView/__snapshots__/InterventionsReport.test.jsx.snap +++ /dev/null @@ -1,38 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`InterventionsReport component snapshots snapshot 1`] = ` -
-

- -

-
-
- -
- -
-
-`; diff --git a/src/components/GradesView/__snapshots__/ScoreViewInput.test.jsx.snap b/src/components/GradesView/__snapshots__/ScoreViewInput.test.jsx.snap deleted file mode 100644 index 44b805a..0000000 --- a/src/components/GradesView/__snapshots__/ScoreViewInput.test.jsx.snap +++ /dev/null @@ -1,32 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ScoreViewInput component snapshot - select box with percent and absolute options and onClick from props.toggleFormat 1`] = ` - - - - : - - - - - - -`; diff --git a/src/components/GradesView/__snapshots__/SearchControls.test.jsx.snap b/src/components/GradesView/__snapshots__/SearchControls.test.jsx.snap deleted file mode 100644 index 43e3bb7..0000000 --- a/src/components/GradesView/__snapshots__/SearchControls.test.jsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SearchControls Component Snapshots basic snapshot 1`] = ` -
- - } - onBlur={[MockFunction onBlur]} - onClear={[MockFunction onClear]} - onSubmit={[MockFunction onSubmit]} - value="alice" - /> - - - -
-`; diff --git a/src/components/GradesView/__snapshots__/SpinnerIcon.test.jsx.snap b/src/components/GradesView/__snapshots__/SpinnerIcon.test.jsx.snap index 6a99def..c530fb3 100644 --- a/src/components/GradesView/__snapshots__/SpinnerIcon.test.jsx.snap +++ b/src/components/GradesView/__snapshots__/SpinnerIcon.test.jsx.snap @@ -9,5 +9,3 @@ exports[`SpinnerIcon component snapshot - displays spinner overlay with spinner />
`; - -exports[`SpinnerIcon component snapshot - does not render if show: false 1`] = `""`; diff --git a/src/components/GradesView/__snapshots__/StatusAlerts.test.jsx.snap b/src/components/GradesView/__snapshots__/StatusAlerts.test.jsx.snap deleted file mode 100644 index 7edc860..0000000 --- a/src/components/GradesView/__snapshots__/StatusAlerts.test.jsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`StatusAlerts snapshots basic snapshot 1`] = ` - - - - - - the quiCk brown does somEthing or other - - -`; diff --git a/src/components/GradesView/__snapshots__/UsersLabel.test.jsx.snap b/src/components/GradesView/__snapshots__/UsersLabel.test.jsx.snap deleted file mode 100644 index 9263159..0000000 --- a/src/components/GradesView/__snapshots__/UsersLabel.test.jsx.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UsersLabel component snapshot - displays label with number of filtered users out of total 1`] = ` - - 23 -
, - "totalUsers": - 140 - , - } - } -/> -`; diff --git a/src/components/GradesView/__snapshots__/index.test.jsx.snap b/src/components/GradesView/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..cc927fa --- /dev/null +++ b/src/components/GradesView/__snapshots__/index.test.jsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GradesView component render snapshot 1`] = ` + + + +

+ filter-step-heading +

+
+ + +
+ + +

+ gradebook-step-heading +

+
+ + +
+ + + +

+ * + test-masters-hint +

+ + +
+`; diff --git a/src/components/GradesView/__snapshots__/test.jsx.snap b/src/components/GradesView/__snapshots__/test.jsx.snap deleted file mode 100644 index d208f4b..0000000 --- a/src/components/GradesView/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GradesView Component snapshots basic snapshot 1`] = ` - - - -

- -

-
- - -
- - -

- -

-
- - -
- - - -

- * - -

- - -
-`; diff --git a/src/components/GradesView/hooks.js b/src/components/GradesView/hooks.js new file mode 100644 index 0000000..b8f6504 --- /dev/null +++ b/src/components/GradesView/hooks.js @@ -0,0 +1,30 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { actions, thunkActions } from 'data/redux/hooks'; +import messages from './messages'; + +export const useGradesViewData = ({ updateQueryParams }) => { + const { formatMessage } = useIntl(); + const fetchGrades = thunkActions.grades.useFetchGrades(); + const resetFilters = actions.filters.useResetFilters(); + + const handleFilterBadgeClose = (filterNames) => () => { + resetFilters(filterNames); + updateQueryParams(filterNames.reduce( + (obj, filterName) => ({ ...obj, [filterName]: false }), + {}, + )); + fetchGrades(); + }; + + return { + stepHeadings: { + filter: formatMessage(messages.filterStepHeading), + gradebook: formatMessage(messages.gradebookStepHeading), + }, + handleFilterBadgeClose, + mastersHint: formatMessage(messages.mastersHint), + }; +}; + +export default useGradesViewData; diff --git a/src/components/GradesView/hooks.test.js b/src/components/GradesView/hooks.test.js new file mode 100644 index 0000000..7e444e0 --- /dev/null +++ b/src/components/GradesView/hooks.test.js @@ -0,0 +1,62 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { formatMessage } from 'testUtils'; +import { actions, thunkActions } from 'data/redux/hooks'; + +import useGradesViewData from './hooks'; +import messages from './messages'; + +jest.mock('data/redux/hooks', () => ({ + actions: { + filters: { useResetFilters: jest.fn() }, + }, + thunkActions: { + grades: { useFetchGrades: jest.fn() }, + }, +})); + +const fetchGrades = jest.fn(); +thunkActions.grades.useFetchGrades.mockReturnValue(fetchGrades); +const resetFilters = jest.fn(); +actions.filters.useResetFilters.mockReturnValue(resetFilters); + +const updateQueryParams = jest.fn(); + +let out; +describe('useGradesViewData', () => { + beforeEach(() => { + jest.clearAllMocks(); + out = useGradesViewData({ updateQueryParams }); + }); + describe('behavior', () => { + it('initializes intl hook', () => { + expect(useIntl).toHaveBeenCalled(); + }); + it('initializes redux hooks', () => { + expect(thunkActions.grades.useFetchGrades).toHaveBeenCalled(); + expect(actions.filters.useResetFilters).toHaveBeenCalled(); + }); + }); + describe('output', () => { + test('stepHeadings', () => { + expect(out.stepHeadings.filter).toEqual(formatMessage(messages.filterStepHeading)); + expect(out.stepHeadings.gradebook).toEqual(formatMessage(messages.gradebookStepHeading)); + }); + test('mastersHint', () => { + expect(out.mastersHint).toEqual(formatMessage(messages.mastersHint)); + }); + describe('handleFilterBadgeClose', () => { + it('resets filters locally and in query params, and fetches grades', () => { + const filters = ['some', 'filter', 'names']; + out.handleFilterBadgeClose(filters)(); + expect(resetFilters).toHaveBeenCalledWith(filters); + expect(updateQueryParams).toHaveBeenCalledWith({ + some: false, + filter: false, + names: false, + }); + expect(fetchGrades).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/src/components/GradesView/index.jsx b/src/components/GradesView/index.jsx index 47373b1..5c4ddee 100644 --- a/src/components/GradesView/index.jsx +++ b/src/components/GradesView/index.jsx @@ -1,12 +1,6 @@ /* eslint-disable react/sort-comp, react/button-has-type, import/no-named-as-default */ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import { FormattedMessage } from '@edx/frontend-platform/i18n'; - -import actions from 'data/actions'; -import thunkActions from 'data/thunkActions'; import BulkManagementControls from './BulkManagementControls'; import EditModal from './EditModal'; @@ -21,79 +15,55 @@ import ScoreViewInput from './ScoreViewInput'; import SearchControls from './SearchControls'; import SpinnerIcon from './SpinnerIcon'; import StatusAlerts from './StatusAlerts'; -import messages from './messages'; -export class GradesView extends React.Component { - constructor(props) { - super(props); - this.handleFilterBadgeClose = this.handleFilterBadgeClose.bind(this); - } +import useGradesViewData from './hooks'; - handleFilterBadgeClose(filterNames) { - return () => { - this.props.resetFilters(filterNames); - this.props.updateQueryParams(filterNames.reduce( - (obj, filterName) => ({ ...obj, [filterName]: false }), - {}, - )); - this.props.fetchGrades(); - }; - } +export const GradesView = ({ updateQueryParams }) => { + const { + stepHeadings, + handleFilterBadgeClose, + mastersHint, + } = useGradesViewData({ updateQueryParams }); - render() { - return ( - <> - + return ( + <> + - -

- -

+ +

+ {stepHeadings.filter} +

-
- - -
+
+ + +
- - + + -

+

{stepHeadings.gradebook}

-
- - -
+
+ + +
- + - + - -

*

- + +

* {mastersHint}

+ - - - ); - } -} - -GradesView.defaultProps = {}; + + + ); +}; GradesView.propTypes = { updateQueryParams: PropTypes.func.isRequired, - - // redux - fetchGrades: PropTypes.func.isRequired, - resetFilters: PropTypes.func.isRequired, }; -export const mapStateToProps = () => ({}); - -export const mapDispatchToProps = { - fetchGrades: thunkActions.grades.fetchGrades, - resetFilters: actions.filters.reset, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(GradesView); +export default GradesView; diff --git a/src/components/GradesView/index.test.jsx b/src/components/GradesView/index.test.jsx new file mode 100644 index 0000000..2279071 --- /dev/null +++ b/src/components/GradesView/index.test.jsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import FilterBadges from './FilterBadges'; + +import useGradesViewData from './hooks'; +import GradesView from '.'; + +jest.mock('./BulkManagementControls', () => 'BulkManagementControls'); +jest.mock('./EditModal', () => 'EditModal'); +jest.mock('./FilterBadges', () => 'FilterBadges'); +jest.mock('./FilteredUsersLabel', () => 'FilteredUsersLabel'); +jest.mock('./FilterMenuToggle', () => 'FilterMenuToggle'); +jest.mock('./GradebookTable', () => 'GradebookTable'); +jest.mock('./ImportSuccessToast', () => 'ImportSuccessToast'); +jest.mock('./InterventionsReport', () => 'InterventionsReport'); +jest.mock('./PageButtons', () => 'PageButtons'); +jest.mock('./ScoreViewInput', () => 'ScoreViewInput'); +jest.mock('./SearchControls', () => 'SearchControls'); +jest.mock('./SpinnerIcon', () => 'SpinnerIcon'); +jest.mock('./StatusAlerts', () => 'StatusAlerts'); +jest.mock('./hooks', () => jest.fn()); + +const hookProps = { + stepHeadings: { + filter: 'filter-step-heading', + gradebook: 'gradebook-step-heading', + }, + handleFilterBadgeClose: jest.fn().mockName('hooks.handleFilterBadgeClose'), + mastersHint: 'test-masters-hint', +}; +useGradesViewData.mockReturnValue(hookProps); + +const updateQueryParams = jest.fn().mockName('props.updateQueryParams'); + +let el; +describe('GradesView component', () => { + beforeEach(() => { + jest.clearAllMocks(); + el = shallow(); + }); + describe('behavior', () => { + it('initializes component hooks', () => { + expect(useGradesViewData).toHaveBeenCalled(); + }); + }); + describe('render', () => { + test('snapshot', () => { + expect(el).toMatchSnapshot(); + }); + test('filterBadges load close behavior from hook', () => { + expect(el.find(FilterBadges).props().handleClose).toEqual( + hookProps.handleFilterBadgeClose, + ); + }); + }); +}); diff --git a/src/components/GradesView/test.jsx b/src/components/GradesView/test.jsx deleted file mode 100644 index 847e989..0000000 --- a/src/components/GradesView/test.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; - -import actions from 'data/actions'; -import thunkActions from 'data/thunkActions'; - -import { - GradesView, - mapStateToProps, - mapDispatchToProps, -} from '.'; - -jest.mock('data/actions', () => ({ - __esModule: true, - default: { - app: { setView: jest.fn() }, - filters: { resetFilters: jest.fn() }, - }, -})); -jest.mock('data/thunkActions', () => ({ - __esModule: true, - default: { - grades: { fetchGrades: jest.fn() }, - }, -})); - -jest.mock('./BulkManagementControls', () => 'BulkManagementControls'); -jest.mock('./EditModal', () => 'EditModal'); -jest.mock('./FilterBadges', () => 'FilterBadges'); -jest.mock('./FilteredUsersLabel', () => 'FilteredUsersLabel'); -jest.mock('./FilterMenuToggle', () => 'FilterMenuToggle'); -jest.mock('./GradebookTable', () => 'GradebookTable'); -jest.mock('./ImportSuccessToast', () => 'ImportSuccessToast'); -jest.mock('./InterventionsReport', () => 'InterventionsReport'); -jest.mock('./PageButtons', () => 'PageButtons'); -jest.mock('./ScoreViewInput', () => 'ScoreViewInput'); -jest.mock('./SearchControls', () => 'SearchControls'); -jest.mock('./SpinnerIcon', () => 'SpinnerIcon'); -jest.mock('./StatusAlerts', () => 'StatusAlerts'); - -describe('GradesView', () => { - let props; - beforeEach(() => { - props = { - updateQueryParams: jest.fn(), - fetchGrades: jest.fn(), - resetFilters: jest.fn(), - }; - }); - - describe('Component', () => { - const filterNames = ['duck', 'Duck', 'Duuuuuck', 'GOOOOSE!']; - describe('behavior', () => { - let el; - beforeEach(() => { - el = shallow(); - }); - describe('handleFilterBadgeClose', () => { - beforeEach(() => { - el.instance().handleFilterBadgeClose(filterNames)(); - }); - it('calls props.resetFilters with the filters', () => { - expect(props.resetFilters).toHaveBeenCalledWith(filterNames); - }); - it('calls props.updateQueryParams with a reset-filters obj', () => { - expect(props.updateQueryParams).toHaveBeenCalledWith({ - [filterNames[0]]: false, - [filterNames[1]]: false, - [filterNames[2]]: false, - [filterNames[3]]: false, - }); - }); - it('calls fetchGrades', () => { - expect(props.fetchGrades).toHaveBeenCalledWith(); - }); - }); - }); - describe('snapshots', () => { - test('basic snapshot', () => { - const el = shallow(); - el.instance().handleFilterBadgeClose = jest.fn().mockName('this.handleFilterBadgeClose'); - expect(el.instance().render()).toMatchSnapshot(); - }); - }); - }); - test('mapStateToProps is empty', () => { - expect(mapStateToProps({ some: 'state' })).toEqual({}); - }); - describe('mapDispatchToProps', () => { - describe('fetchGrades', () => { - test('from thunkActions.grades.fetchGrades', () => { - expect(mapDispatchToProps.fetchGrades).toEqual( - thunkActions.grades.fetchGrades, - ); - }); - }); - describe('resetFilters', () => { - test('from actions.filters.reset', () => { - expect(mapDispatchToProps.resetFilters).toEqual( - actions.filters.reset, - ); - }); - }); - }); -}); diff --git a/src/data/redux/hooks/actions.js b/src/data/redux/hooks/actions.js index bfe1149..526971d 100644 --- a/src/data/redux/hooks/actions.js +++ b/src/data/redux/hooks/actions.js @@ -4,6 +4,11 @@ import { actionHook } from './utils'; const app = StrictDict({ useSetLocalFilter: actionHook(actions.app.setLocalFilter), + useSetSearchValue: actionHook(actions.app.setSearchValue), + useSetShowImportSuccessToast: actionHook(actions.app.setShowImportSuccessToast), + useSetView: actionHook(actions.app.setView), + useCloseModal: actionHook(actions.app.closeModal), + useSetModalState: actionHook(actions.app.setModalState), }); const filters = StrictDict({ @@ -14,9 +19,19 @@ const filters = StrictDict({ useUpdateCourseGradeLimits: actionHook(actions.filters.update.courseGradeLimits), useUpdateIncludeCourseRoleMembers: actionHook(actions.filters.update.includeCourseRoleMembers), useUpdateTrack: actionHook(actions.filters.update.track), + useResetFilters: actionHook(actions.filters.reset), +}); + +const grades = StrictDict({ + useDoneViewingAssignment: actionHook(actions.grades.doneViewingAssignment), + useDownloadBulkGradesReport: actionHook(actions.grades.downloadReport.bulkGrades), + useDownloadInterventionReport: actionHook(actions.grades.downloadReport.intervention), + useToggleGradeFormat: actionHook(actions.grades.toggleGradeFormat), + useCloseBanner: actionHook(actions.grades.banner.close), }); export default StrictDict({ app, filters, + grades, }); diff --git a/src/data/redux/hooks/actions.test.js b/src/data/redux/hooks/actions.test.js index 95cf015..9f7de29 100644 --- a/src/data/redux/hooks/actions.test.js +++ b/src/data/redux/hooks/actions.test.js @@ -4,17 +4,6 @@ import actions from 'data/actions'; import { actionHook } from './utils'; import actionHooks from './actions'; -jest.mock('data/actions', () => ({ - app: { - setLocalFilter: jest.fn(), - }, - filters: { - update: { - assignment: jest.fn(), - assignmentLimits: jest.fn(), - }, - }, -})); jest.mock('./utils', () => ({ actionHook: (action) => ({ actionHook: action }), })); @@ -24,6 +13,7 @@ let hooks; const testActionHook = (hookKey, action) => { test(hookKey, () => { expect(hooks[hookKey]).toEqual(actionHook(action)); + expect(hooks[hookKey]).not.toEqual(undefined); }); }; @@ -32,6 +22,11 @@ describe('action hooks', () => { const hookKeys = keyStore(actionHooks.app); beforeEach(() => { hooks = actionHooks.app; }); testActionHook(hookKeys.useSetLocalFilter, actions.app.setLocalFilter); + testActionHook(hookKeys.useSetSearchValue, actions.app.setSearchValue); + testActionHook(hookKeys.useSetShowImportSuccessToast, actions.app.setShowImportSuccessToast); + testActionHook(hookKeys.useSetView, actions.app.setView); + testActionHook(hookKeys.useCloseModal, actions.app.closeModal); + testActionHook(hookKeys.useSetModalState, actions.app.setModalState); }); describe('filters', () => { const hookKeys = keyStore(actionHooks.filters); @@ -39,12 +34,23 @@ describe('action hooks', () => { beforeEach(() => { hooks = actionHooks.filters; }); testActionHook(hookKeys.useUpdateAssignment, actionGroup.assignment); testActionHook(hookKeys.useUpdateAssignmentLimits, actionGroup.assignmentLimits); - testActionHook(hookKeys.useUpdateCohort, actionGroup.updateCohort); + testActionHook(hookKeys.useUpdateAssignmentType, actionGroup.assignmentType); + testActionHook(hookKeys.useUpdateCohort, actionGroup.cohort); testActionHook(hookKeys.useUpdateCourseGradeLimits, actionGroup.courseGradeLimits); testActionHook( hookKeys.useUpdateIncludeCourseRoleMembers, - actionGroup.updateIncludeCourseRoleMembers, + actionGroup.includeCourseRoleMembers, ); - testActionHook(hookKeys.useUpdateTrack, actionGroup.updateTrack); + testActionHook(hookKeys.useResetFilters, actions.filters.reset); + }); + describe('grades', () => { + const hookKeys = keyStore(actionHooks.grades); + const actionGroup = actions.grades; + beforeEach(() => { hooks = actionHooks.grades; }); + testActionHook(hookKeys.useDoneViewingAssignment, actionGroup.doneViewingAssignment); + testActionHook(hookKeys.useDownloadBulkGradesReport, actionGroup.downloadReport.bulkGrades); + testActionHook(hookKeys.useDownloadInterventionReport, actionGroup.downloadReport.intervention); + testActionHook(hookKeys.useToggleGradeFormat, actionGroup.toggleGradeFormat); + testActionHook(hookKeys.useCloseBanner, actionGroup.banner.close); }); }); diff --git a/src/data/redux/hooks/selectors.js b/src/data/redux/hooks/selectors.js index 4b865a6..6f27ab0 100644 --- a/src/data/redux/hooks/selectors.js +++ b/src/data/redux/hooks/selectors.js @@ -3,40 +3,75 @@ import { useSelector } from 'react-redux'; import { StrictDict } from 'utils'; import selectors from 'data/selectors'; +const selectorHook = (selector) => () => useSelector(selector); + export const root = StrictDict({ - useGradeExportUrl: () => useSelector(selectors.root.gradeExportUrl), - useSelectedCohortEntry: () => useSelector(selectors.root.selectedCohortEntry), - useSelectedTrackEntry: () => useSelector(selectors.root.selectedTrackEntry), + useEditModalPossibleGrade: selectorHook(selectors.root.editModalPossibleGrade), + useGetHeadings: selectorHook(selectors.root.getHeadings), + useGradeExportUrl: selectorHook(selectors.root.gradeExportUrl), + useInterventionExportUrl: selectorHook(selectors.root.interventionExportUrl), + useSelectedCohortEntry: selectorHook(selectors.root.selectedCohortEntry), + useSelectedTrackEntry: selectorHook(selectors.root.selectedTrackEntry), + useShouldShowSpinner: selectorHook(selectors.root.shouldShowSpinner), + useShowBulkManagement: selectorHook(selectors.root.showBulkManagement), + useFilterBadgeConfig: (filterName) => useSelector( + (state) => selectors.root.filterBadgeConfig(state, filterName), + ), }); export const app = StrictDict({ - useAssignmentGradeLimits: () => useSelector(selectors.app.assignmentGradeLimits), - useAreCourseGradeFiltersValid: () => useSelector(selectors.app.areCourseGradeFiltersValid), - useCourseGradeLimits: () => useSelector(selectors.app.courseGradeLimits), + useActiveView: selectorHook(selectors.app.activeView), + useAssignmentGradeLimits: selectorHook(selectors.app.assignmentGradeLimits), + useAreCourseGradeFiltersValid: selectorHook(selectors.app.areCourseGradeFiltersValid), + useCourseGradeLimits: selectorHook(selectors.app.courseGradeLimits), + useCourseGradeFilterValidity: selectorHook(selectors.app.courseGradeFilterValidity), + useCourseId: selectorHook(selectors.app.courseId), + useModalData: selectorHook(selectors.app.modalData), + useSearchValue: selectorHook(selectors.app.searchValue), + useShowImportSuccessToast: selectorHook(selectors.app.showImportSuccessToast), }); export const assignmentTypes = StrictDict({ - useAllAssignmentTypes: () => useSelector(selectors.assignmentTypes.allAssignmentTypes), + useAllAssignmentTypes: selectorHook(selectors.assignmentTypes.allAssignmentTypes), + useAreGradesFrozen: selectorHook(selectors.assignmentTypes.areGradesFrozen), }); export const cohorts = StrictDict({ - useAllCohorts: () => useSelector(selectors.cohorts.allCohorts), + useAllCohorts: selectorHook(selectors.cohorts.allCohorts), // maybe not needed? - useCohortsByName: () => useSelector(selectors.cohorts.cohortsByName), + useCohortsByName: selectorHook(selectors.cohorts.cohortsByName), }); export const filters = StrictDict({ - useData: () => useSelector(selectors.filters.allFilters), - useIncludeCourseRoleMembers: () => useSelector(selectors.filters.includeCourseRoleMembers), - useSelectableAssignmentLabels: () => useSelector(selectors.filters.selectableAssignmentLabels), - useSelectedAssignmentLabel: () => useSelector(selectors.filters.selectedAssignmentLabel), - useAssignmentType: () => useSelector(selectors.filters.assignmentType), + useData: selectorHook(selectors.filters.allFilters), + useIncludeCourseRoleMembers: selectorHook(selectors.filters.includeCourseRoleMembers), + useSelectableAssignmentLabels: selectorHook(selectors.filters.selectableAssignmentLabels), + useSelectedAssignmentLabel: selectorHook(selectors.filters.selectedAssignmentLabel), + useAssignmentType: selectorHook(selectors.filters.assignmentType), +}); + +export const grades = StrictDict({ + useAllGrades: selectorHook(selectors.grades.allGrades), + useUserCounts: () => ({ + filteredUsersCount: useSelector(selectors.grades.filteredUsersCount), + totalUsersCount: useSelector(selectors.grades.totalUsersCount), + }), + useGradeData: selectorHook(selectors.grades.gradeData), + useHasOverrideErrors: selectorHook(selectors.grades.hasOverrideErrors), + useShowSuccess: selectorHook(selectors.grades.showSuccess), + useSubsectionGrade: ({ gradeFormat, subsection }) => () => ( + selectors.grades.subsectionGrade[gradeFormat](subsection) + ), +}); + +export const roles = StrictDict({ + useCanUserViewGradebook: selectorHook(selectors.roles.canUserViewGradebook), }); export const tracks = StrictDict({ - useAllTracks: () => useSelector(selectors.tracks.allTracks), + useAllTracks: selectorHook(selectors.tracks.allTracks), // maybe not needed? - useTracksByName: () => useSelector(selectors.tracks.tracksByName), + useTracksByName: selectorHook(selectors.tracks.tracksByName), }); export default StrictDict({ @@ -44,6 +79,8 @@ export default StrictDict({ assignmentTypes, cohorts, filters, + grades, + roles, tracks, root, }); diff --git a/src/data/redux/hooks/selectors.test.js b/src/data/redux/hooks/selectors.test.js index c19ad9a..ad74e30 100644 --- a/src/data/redux/hooks/selectors.test.js +++ b/src/data/redux/hooks/selectors.test.js @@ -7,85 +7,102 @@ jest.mock('react-redux', () => ({ useSelector: (selector) => ({ useSelector: selector }), })); -jest.mock('data/selectors', () => ({ - app: { - assignmentGradeLimits: jest.fn(), - areCourseGradeFiltersValid: jest.fn(), - courseGradelimits: jest.fn(), - }, - assignmentTypes: { allAssignmentTypes: jest.fn() }, - cohorts: { - allCohorts: jest.fn(), - cohortsByName: jest.fn(), - }, - filters: { - allFilters: jest.fn(), - includeCourseRoleMembers: jest.fn(), - selectableAssignmentLabels: jest.fn(), - selectedAssignmentLabel: jest.fn(), - assignmentType: jest.fn(), - }, - tracks: { - allTracks: jest.fn(), - tracksByName: jest.fn(), - }, - root: { - gradeExportUrl: jest.fn(), - selectedCohortEntry: jest.fn(), - selectedTrackEntry: jest.fn(), - }, -})); +const testValue = 'test-value'; +const testState = { test: 'state value' }; +let hookKeys; let hooks; -const testHook = (hookKey, selector) => { - test(hookKey, () => { - expect(hooks[hookKey]()).toEqual(useSelector(selector)); +let selKeys; +let selectorGroup; + +const loadSelectorGroup = (hookGroup, selGroup) => { + hookKeys = keyStore(hookGroup); + selKeys = keyStore(selGroup); + beforeEach(() => { + hooks = hookGroup; + selectorGroup = selGroup; }); }; + +const testHook = (hookKey, selectorKey) => { + test(hookKey, () => { + expect(hooks[hookKey]()).toEqual(useSelector(selectorGroup[selectorKey])); + }); +}; + describe('selector hooks', () => { describe('root selectors', () => { - const hookKeys = keyStore(selectorHooks.root); - beforeEach(() => { hooks = selectorHooks.root; }); - testHook(hookKeys.useGradeExportUrl, selectors.root.gradeExportUrl); - testHook(hookKeys.useSelectedCohortEntry, selectors.root.selectedCohortEntry); - testHook(hookKeys.useSelectedTrackEntry, selectors.root.selectedTrackEntry); + loadSelectorGroup(selectorHooks.root, selectors.root); + testHook(hookKeys.useEditModalPossibleGrade, selKeys.editModalPossibleGrade); + testHook(hookKeys.useGetHeadings, selKeys.getHeadings); + testHook(hookKeys.useGradeExportUrl, selKeys.gradeExportUrl); + testHook(hookKeys.useInterventionExportUrl, selKeys.interventionExportUrl); + testHook(hookKeys.useSelectedCohortEntry, selKeys.selectedCohortEntry); + testHook(hookKeys.useSelectedTrackEntry, selKeys.selectedTrackEntry); + testHook(hookKeys.useShouldShowSpinner, selKeys.shouldShowSpinner); + testHook(hookKeys.useShowBulkManagement, selKeys.showBulkManagement); + describe(hookKeys.useFilterBadgeConfig, () => { + test('calls filterBadgeConfig selector with passed filterName', () => { + const filterBadgeConfig = (state, filterName) => ({ + filterBadgeConfig: { state, filterName }, + }); + const rootKeys = keyStore(selectors.root); + jest.spyOn(selectors.root, rootKeys.filterBadgeConfig) + .mockImplementation(filterBadgeConfig); + const out = hooks.useFilterBadgeConfig(testValue); + expect(out.useSelector(testState)).toEqual(filterBadgeConfig(testState, testValue)); + }); + }); }); describe('app', () => { - const hookKeys = keyStore(selectorHooks.app); - const selGroup = selectors.app; - beforeEach(() => { hooks = selectorHooks.app; }); - testHook(hookKeys.useAssignmentGradeLimits, selGroup.assignmentGradeLimits); - testHook(hookKeys.useAreCourseGradeFiltersValid, selGroup.areCourseGradeFiltersValid); - testHook(hookKeys.useCourseGradeLimits, selGroup.courseGradeLimits); + loadSelectorGroup(selectorHooks.app, selectors.app); + testHook(hookKeys.useActiveView, selKeys.activeView); + testHook(hookKeys.useAssignmentGradeLimits, selKeys.assignmentGradeLimits); + testHook(hookKeys.useAreCourseGradeFiltersValid, selKeys.areCourseGradeFiltersValid); + testHook(hookKeys.useCourseGradeLimits, selKeys.courseGradeLimits); + testHook(hookKeys.useCourseId, selKeys.courseId); + testHook(hookKeys.useModalData, selKeys.modalData); + testHook(hookKeys.useSearchValue, selKeys.searchValue); + testHook(hookKeys.useShowImportSuccessToast, selKeys.showImportSuccessToast); }); describe('assignmentTypes', () => { - const hookKeys = keyStore(selectorHooks.assignmentTypes); - const selGroup = selectors.assignmentTypes; - beforeEach(() => { hooks = selectorHooks.assignmentTypes; }); - testHook(hookKeys.useAllAssignmentTypes, selGroup.allAssignmentTypes); + loadSelectorGroup(selectorHooks.assignmentTypes, selectors.assignmentTypes); + testHook(hookKeys.useAllAssignmentTypes, selKeys.allAssignmentTypes); + testHook(hookKeys.useAreGradesFrozen, selKeys.areGradesFrozen); }); describe('cohorts', () => { - const hookKeys = keyStore(selectorHooks.cohorts); - const selGroup = selectors.cohorts; - beforeEach(() => { hooks = selectorHooks.cohorts; }); - testHook(hookKeys.useAllCohorts, selGroup.allCohorts); - testHook(hookKeys.useCohortsByName, selGroup.cohortsByName); + loadSelectorGroup(selectorHooks.cohorts, selectors.cohorts); + testHook(hookKeys.useAllCohorts, selKeys.allCohorts); + testHook(hookKeys.useCohortsByName, selKeys.cohortsByName); }); describe('filters', () => { - const hookKeys = keyStore(selectorHooks.filters); - const selGroup = selectors.filters; - beforeEach(() => { hooks = selectorHooks.filters; }); - testHook(hookKeys.useData, selGroup.allFilters); - testHook(hookKeys.useIncludeCourseRoleMembers, selGroup.includeCourseRoleMembers); - testHook(hookKeys.useSelectableAssignmentLabels, selGroup.selectableAssignmentLabels); - testHook(hookKeys.useSelectedAssignmentLabel, selGroup.selectedAssignmentLabel); - testHook(hookKeys.useAssignmentType, selGroup.assignmentType); + loadSelectorGroup(selectorHooks.filters, selectors.filters); + testHook(hookKeys.useData, selKeys.allFilters); + testHook(hookKeys.useIncludeCourseRoleMembers, selKeys.includeCourseRoleMembers); + testHook(hookKeys.useSelectableAssignmentLabels, selKeys.selectableAssignmentLabels); + testHook(hookKeys.useSelectedAssignmentLabel, selKeys.selectedAssignmentLabel); + testHook(hookKeys.useAssignmentType, selKeys.assignmentType); + }); + describe('grades', () => { + loadSelectorGroup(selectorHooks.grades, selectors.grades); + testHook(hookKeys.useAllGrades, selKeys.allGrades); + testHook(hookKeys.useGradeData, selKeys.gradeData); + testHook(hookKeys.useHasOverrideErrors, selKeys.hasOverrideErrors); + testHook(hookKeys.useShowSuccess, selKeys.showSuccess); + test(hookKeys.useUserCounts, () => { + expect(hooks.useUserCounts()).toEqual({ + filteredUsersCount: useSelector(selectors.grades.filteredUsersCount), + totalUsersCount: useSelector(selectors.grades.totalUsersCount), + }); + }); + }); + describe('roles', () => { + loadSelectorGroup(selectorHooks.roles, selectors.roles); + testHook(hookKeys.useCanUserViewGradebook, selKeys.canUserViewGradebook); }); describe('tracks', () => { - const hookKeys = keyStore(selectorHooks.tracks); - const selGroup = selectors.tracks; - beforeEach(() => { hooks = selectorHooks.tracks; }); - testHook(hookKeys.useAllTracks, selGroup.allTracks); - testHook(hookKeys.useTracksByName, selGroup.tracksByName); + loadSelectorGroup(selectorHooks.tracks, selectors.tracks); + testHook(hookKeys.useAllTracks, selKeys.allTracks); + testHook(hookKeys.useTracksByName, selKeys.tracksByName); }); }); diff --git a/src/data/redux/hooks/thunkActions.js b/src/data/redux/hooks/thunkActions.js index 6b5bc5b..5017c5a 100644 --- a/src/data/redux/hooks/thunkActions.js +++ b/src/data/redux/hooks/thunkActions.js @@ -3,15 +3,22 @@ import thunkActions from 'data/thunkActions'; import { actionHook } from './utils'; const app = StrictDict({ - useCloseFilterMenu: actionHook(thunkActions.app.filterMenu.close), + filterMenu: { + useCloseMenu: actionHook(thunkActions.app.filterMenu.close), + useHandleTransitionEnd: actionHook(thunkActions.app.filterMenu.handleTransitionEnd), + useToggleMenu: actionHook(thunkActions.app.filterMenu.toggle), + }, + useSetModalStateFromTable: actionHook(thunkActions.app.setModalStateFromTable), }); const grades = StrictDict({ useFetchGradesIfAssignmentGradeFiltersSet: actionHook( thunkActions.grades.fetchGradesIfAssignmentGradeFiltersSet, ), + useFetchPrevNextGrades: actionHook(thunkActions.grades.fetchPrevNextGrades), useFetchGrades: actionHook(thunkActions.grades.fetchGrades), useSubmitImportGradesButtonData: actionHook(thunkActions.grades.submitImportGradesButtonData), + useUpdateGrades: actionHook(thunkActions.grades.updateGrades), }); export default StrictDict({ diff --git a/src/data/redux/hooks/thunkActions.test.js b/src/data/redux/hooks/thunkActions.test.js index 7ec8ebb..51499f0 100644 --- a/src/data/redux/hooks/thunkActions.test.js +++ b/src/data/redux/hooks/thunkActions.test.js @@ -5,7 +5,11 @@ import thunkActionHooks from './thunkActions'; jest.mock('data/thunkActions', () => ({ app: { - filterMenu: { close: jest.fn() }, + filterMenu: { + close: jest.fn(), + handleTransitionEnd: jest.fn(), + toggle: jest.fn(), + }, }, grades: { fetchGrades: jest.fn(), @@ -25,24 +29,38 @@ const testActionHook = (hookKey, action) => { expect(hooks[hookKey]).toEqual(actionHook(action)); }); }; +let hookKeys; describe('thunkAction hooks', () => { describe('app', () => { - const hookKeys = keyStore(thunkActionHooks.app); + hookKeys = keyStore(thunkActionHooks.app); beforeEach(() => { hooks = thunkActionHooks.app; }); - testActionHook(hookKeys.useCloseFilterMenu, thunkActions.app.filterMenu.close); + testActionHook(hookKeys.useSetModalStateFromTable, thunkActions.app.setModalStateFromTable); + + describe('filterMenu', () => { + hookKeys = keyStore(thunkActionHooks.app.filterMenu); + beforeEach(() => { hooks = thunkActionHooks.app.filterMenu; }); + testActionHook(hookKeys.useCloseMenu, thunkActions.app.filterMenu.close); + testActionHook( + hookKeys.useHandleTransitionEnd, + thunkActions.app.filterMenu.handleTransitionEnd, + ); + testActionHook(hookKeys.useToggleMenu, thunkActions.app.filterMenu.toggle); + }); }); describe('grades', () => { - const hookKeys = keyStore(thunkActionHooks.grades); + hookKeys = keyStore(thunkActionHooks.grades); const actionGroup = thunkActions.grades; beforeEach(() => { hooks = thunkActionHooks.grades; }); - testActionHook(hookKeys.useFetchGrades, actionGroup.fetchGrades); testActionHook( hookKeys.useFetchGradesIfAssignmentGradeFiltersSet, actionGroup.fetchGradesIfAssignmentGradeFiltersSet, ); + testActionHook(hookKeys.useFetchPrevNextGrades, actionGroup.fetchPrevNextGrades); + testActionHook(hookKeys.useFetchGrades, actionGroup.fetchGrades); testActionHook( hookKeys.useSubmitImportGradesButtonData, actionGroup.submitImportGradesButtonData, ); + testActionHook(hookKeys.useUpdateGrades, actionGroup.updateGrades); }); }); diff --git a/src/data/redux/transforms.js b/src/data/redux/transforms.js new file mode 100644 index 0000000..3980b3a --- /dev/null +++ b/src/data/redux/transforms.js @@ -0,0 +1,13 @@ +import { StrictDict } from 'utils'; +import selectors from 'data/selectors'; + +export const grades = StrictDict({ + subsectionGrade: ({ gradeFormat, subsection }) => () => ( + selectors.grades.subsectionGrade[gradeFormat](subsection) + ), + roundGrade: selectors.grades.roundGrade, +}); + +export default StrictDict({ + grades, +}); diff --git a/src/data/redux/transforms.test.js b/src/data/redux/transforms.test.js new file mode 100644 index 0000000..c639aba --- /dev/null +++ b/src/data/redux/transforms.test.js @@ -0,0 +1,38 @@ +import selectors from 'data/selectors'; + +import { GradeFormats } from 'data/constants/grades'; +import transforms from './transforms'; + +jest.mock('data/selectors', () => { + const { + GradeFormats: { absolute, percent }, + } = jest.requireActual('data/constants/grades'); + return { + grades: { + subsectionGrade: { + [absolute]: jest.fn(v => ({ absolute: v })), + [percent]: jest.fn(v => ({ percent: v })), + }, + roundGrade: jest.fn(), + }, + }; +}); + +describe('redux transforms', () => { + describe('grades transforms', () => { + test('subsectionGrade', () => { + const subsection = 'test-subsection'; + expect(transforms.grades.subsectionGrade({ + gradeFormat: GradeFormats.absolute, + subsection, + })()).toEqual(selectors.grades.subsectionGrade.absolute(subsection)); + expect(transforms.grades.subsectionGrade({ + gradeFormat: GradeFormats.percent, + subsection, + })()).toEqual(selectors.grades.subsectionGrade.percent(subsection)); + }); + test('roundGrade', () => { + expect(transforms.grades.roundGrade).toEqual(selectors.grades.roundGrade); + }); + }); +}); diff --git a/src/data/selectors/app.js b/src/data/selectors/app.js index 6fd32bd..4ef2f7c 100644 --- a/src/data/selectors/app.js +++ b/src/data/selectors/app.js @@ -89,6 +89,16 @@ const modalSelectors = simpleSelectorFactory( ], ); +const modalData = ({ app: { modalState } }) => ({ + assignmentName: modalState.assignmentName, + adjustedGradePossible: modalState.adjustedGradePossible, + adjustedGradeValue: modalState.adjustedGradeValue, + open: modalState.open, + reasonForChange: modalState.reasonForChange, + todaysDate: modalState.todaysDate, + updateUserName: modalState.updateUserName, +}); + const filterMenuSelectors = simpleSelectorFactory( ({ app: { filterMenu } }) => filterMenu, ['open', 'transitioning'], @@ -115,6 +125,7 @@ export default StrictDict({ isFilterMenuOpening, ...simpleSelectors, modalState: StrictDict(modalSelectors), + modalData, filterMenu: StrictDict({ ...filterMenuSelectors, isClosed: isFilterMenuClosed, diff --git a/src/data/selectors/grades.js b/src/data/selectors/grades.js index 7bc3f12..e5d22b6 100644 --- a/src/data/selectors/grades.js +++ b/src/data/selectors/grades.js @@ -266,12 +266,26 @@ const simpleSelectors = simpleSelectorFactory( 'gradeOverrideHistoryError', 'gradeOriginalEarnedGraded', 'gradeOriginalPossibleGraded', - 'nextPage', - 'prevPage', 'showSuccess', ], ); +const gradeData = ({ grades }) => ({ + courseId: grades.courseId, + filteredUsersCount: grades.filteredUsersCount, + totalUsersCount: grades.totalUsersCount, + gradeFormat: grades.gradeFormat, + showSpinner: grades.showSpinner, + gradeOverrideCurrentEarnedGradedOverride: grades.gradeOverrideCurrentEarnedGradedOverride, + gradeOverrideHistoryError: grades.gradeOverrideHistoryError, + gradeOverrideHistoryResults: grades.gradeOverrideHistoryResults, + gradeOriginalEarnedGraded: grades.gradeOriginalEarnedGraded, + gradeOriginalPossibleGraded: grades.gradeOriginalPossibleGraded, + nextPage: grades.nextPage, + prevPage: grades.prevPage, + showSuccess: grades.showSuccess, +}); + export default StrictDict({ bulkImportError, formatGradeOverrideForDisplay, @@ -286,6 +300,7 @@ export default StrictDict({ subsectionGrade, ...simpleSelectors, + gradeData, allGrades, bulkManagementHistoryEntries, getExampleSectionBreakdown, diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index 79737b7..d430db8 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -36,6 +36,10 @@ export const sectionOverrideHistoryUrl = (subsectionId, userId) => stringifyUrl( { user_id: userId, history_record_limit: historyRecordLimit }, ); +export const instructorDashboardUrl = () => ( + `${getConfig().LMS_BASE_URL}/courses/${courseId}/instructor` +); + export default StrictDict({ getUrlPrefix, getBulkGradesUrl, diff --git a/src/setupTest.js b/src/setupTest.js index 9cda7ed..5416431 100755 --- a/src/setupTest.js +++ b/src/setupTest.js @@ -39,6 +39,11 @@ jest.mock('@edx/frontend-component-footer', () => ({ messages: ['some', 'messages'], })); +jest.mock('@edx/paragon/icons', () => ({ + FilterAlt: 'FilterAlt', + Close: 'Close', +})); + jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedComponents({ Alert: 'Alert', ActionRow: 'ActionRow', @@ -75,6 +80,7 @@ jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedCompon Hyperlink: 'Hyperlink', Icon: 'Icon', IconButton: 'IconButton', + Input: 'Input', ModalDialog: { Body: 'ModalDialog.Body', CloseButton: 'ModalDialog.CloseButton', @@ -84,8 +90,10 @@ jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedCompon }, OverlayTrigger: 'OverlayTrigger', Row: 'Row', - StatefulButton: 'StatefulButton', + SearchField: 'SearchField', Spinner: 'Spinner', + StatefulButton: 'StatefulButton', + Toast: 'Toast', useCheckboxSetValues: () => jest.fn().mockImplementation((values) => ([values, { add: jest.fn().mockName('useCheckboxSetValues.add'), diff --git a/src/utils/formatDate.js b/src/utils/formatDate.js new file mode 100644 index 0000000..bce70da --- /dev/null +++ b/src/utils/formatDate.js @@ -0,0 +1,20 @@ +export const options = { + year: 'numeric', + month: 'long', + day: 'numeric', + timeZone: 'UTC', +}; +export const timeOptions = { + hour: '2-digit', + minute: '2-digit', + timeZone: 'UTC', + timeZoneName: 'short', +}; + +const formatDateForDisplay = (inputDate) => { + const date = inputDate.toLocaleDateString('en-US', options); + const time = inputDate.toLocaleTimeString('en-US', timeOptions); + return `${date} at ${time}`; +}; + +export default formatDateForDisplay; diff --git a/src/utils/index.js b/src/utils/index.js index 678ea70..2c038dc 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,3 +1,4 @@ /* eslint-disable import/prefer-default-export */ export { default as StrictDict } from './StrictDict'; export { default as keyStore } from './keyStore'; +export { default as formatDateForDisplay } from './formatDate';