From 0962232fe2a181a2fde0067ed95f99885b8cee28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edwin=20P=C3=A1ez?= Date: Wed, 1 Sep 2021 08:34:03 -0500 Subject: [PATCH] feat(test runner): Support for disable bail (#3074) Add support for disabling the test runner bail using `--disableBail` or `{ "disableBail": true }`. When bail is disabled, all failing tests are reported in `killedBy` and thus end up in the html report's "Tests" view. **API** (all backward compatible): * Change the `MutantRunResult` interface to support an array of tests in `killedBy` (`string` is still supported) * Add `disabeBail` in both the `DryRunOptions` and the `MutantRunOptions` * Support reporting an array of failed tests in `killedBy` in `toMutantRunResult` (while keeping it backward compatible) **Test runners** * Update all `TestRunner` plugins to support disabling bail. **Core** * Update the core to support this new interface * Add new config option `--disableBail` * Deprecate `jest.enableBail`, use `--disableBail` instead. --- docs/configuration.md | 35 + docs/images/configuration-disable-bail.png | Bin 0 -> 32152 bytes docs/images/configuration-with-bail.png | Bin 0 -> 34065 bytes e2e/helpers.ts | 12 +- e2e/package-lock.json | 3039 +++++++++++++---- e2e/package.json | 2 +- e2e/test/disable-bail/.mocharc.json | 3 + e2e/test/disable-bail/cucumber.js | 1 + e2e/test/disable-bail/features/add.feature | 9 + e2e/test/disable-bail/features/add.steps.js | 11 + e2e/test/disable-bail/karma.conf.js | 15 + e2e/test/disable-bail/package.json | 17 + .../disable-bail/spec/support/jasmine.json | 8 + e2e/test/disable-bail/src/math.js | 8 + e2e/test/disable-bail/stryker.conf.json | 9 + e2e/test/disable-bail/test/chai-setup.js | 6 + e2e/test/disable-bail/test/math.spec.js | 17 + e2e/test/disable-bail/verify/verify.ts | 45 + e2e/test/ignore-project/verify/verify.ts | 4 +- packages/api/schema/stryker-core.json | 5 + .../api/src/test-runner/mutant-run-result.ts | 6 +- packages/api/src/test-runner/run-options.ts | 4 + .../api/src/test-runner/run-result-helpers.ts | 11 +- .../test_runner/run-result-helpers.spec.ts | 32 +- packages/core/src/config/options-validator.ts | 10 + .../core/src/process/3-dry-run-executor.ts | 6 +- .../src/process/4-mutation-test-executor.ts | 1 + .../reporters/mutation-test-report-helper.ts | 2 +- packages/core/src/stryker-cli.ts | 3 +- .../create-test-runner-factory.it.spec.ts | 2 +- .../unit/config/options-validator.spec.ts | 10 + .../unit/process/3-dry-run-executor.spec.ts | 25 + .../process/4-mutation-test-executor.spec.ts | 14 + .../mutation-test-report-helper.spec.ts | 21 + packages/core/test/unit/stryker-cli.spec.ts | 1 + .../test-runner/timeout-decorator.spec.ts | 2 +- packages/cucumber-runner/.vscode/launch.json | 21 - .../src/cucumber-test-runner.ts | 15 +- .../integration/cucumber-runner.it.spec.ts | 4 +- .../example-instrumented.it.spec.ts | 22 +- .../test/integration/failures.it.spec.ts | 62 +- .../features/failure-examples.feature | 5 + packages/jasmine-runner/.vscode/launch.json | 2 +- .../jasmine-runner/src/jasmine-test-runner.ts | 14 +- .../jasmine-init-instrumented.it.spec.ts | 15 +- .../integration/jasmine-runner.it.spec.ts | 21 +- .../test/integration/memory-leak.worker.ts | 4 +- .../test/unit/jasmine-test-runner.spec.ts | 2 +- .../test-failures/spec/fooSpec.js | 5 +- .../schema/jest-runner-options.json | 5 - .../jest-runner/src/jest-override-options.ts | 4 + packages/jest-runner/src/jest-test-runner.ts | 23 +- .../src/utils/monkey-patch-exit.ts | 21 - .../jest-runner/test/helpers/producers.ts | 1 - .../integration/coverage-analysis.it.spec.ts | 38 +- .../integration/jest-test-runner.it.spec.ts | 52 +- .../test/unit/jest-test-runner.spec.ts | 82 +- .../src/__tests__/AddSpec.js | 10 + .../karma-runner/src/karma-test-runner.ts | 20 +- .../src/starters/stryker-karma.conf.ts | 15 +- .../test/integration/instrumented.it.spec.ts | 8 +- .../integration/karma-test-runner.it.spec.ts | 56 +- .../test/unit/karma-test-runner.spec.ts | 7 +- .../unit/starters/stryker-karma.conf.spec.ts | 2 +- packages/mocha-runner/.vscode/launch.json | 4 +- .../mocha-runner/src/mocha-test-runner.ts | 18 +- .../test/integration/memory-leak.worker.ts | 4 +- .../sample-project-instrumented.it.spec.ts | 19 +- .../integration/sample-project.it.spec.ts | 8 +- .../test/unit/mocha-test-runner.spec.ts | 23 +- packages/test-helpers/src/factory.ts | 4 +- tasks/instrument-test-resources.js | 8 +- 72 files changed, 3210 insertions(+), 810 deletions(-) create mode 100644 docs/images/configuration-disable-bail.png create mode 100644 docs/images/configuration-with-bail.png create mode 100644 e2e/test/disable-bail/.mocharc.json create mode 100644 e2e/test/disable-bail/cucumber.js create mode 100644 e2e/test/disable-bail/features/add.feature create mode 100644 e2e/test/disable-bail/features/add.steps.js create mode 100644 e2e/test/disable-bail/karma.conf.js create mode 100644 e2e/test/disable-bail/package.json create mode 100644 e2e/test/disable-bail/spec/support/jasmine.json create mode 100644 e2e/test/disable-bail/src/math.js create mode 100644 e2e/test/disable-bail/stryker.conf.json create mode 100644 e2e/test/disable-bail/test/chai-setup.js create mode 100644 e2e/test/disable-bail/test/math.spec.js create mode 100644 e2e/test/disable-bail/verify/verify.ts delete mode 100644 packages/jest-runner/src/utils/monkey-patch-exit.ts diff --git a/docs/configuration.md b/docs/configuration.md index 5abc56e65d..56ee7ecb5b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -98,6 +98,41 @@ Config file: Settings for the `dashboard` [reporter](#reporters-string). See the [dashboard documentation](../General/dashboard.md) for more info. +### `disableBail` [`boolean`] + +_Since v5.4_ + +Default: `false`
+Command: `--disableBail`
+Config file: `"disableBail": true` + +Configure the test runner to report all failing tests when a mutant is killed instead of bailing after the first failing test. Bailing brings better performance, but you might be interested in the full report instead. This might be useful when using the "Tests" view to hunt for tests that don't kill a single mutant. + +See the difference of bail vs no bail on StrykerJS's utils package (with `--concurrency 4`): + + + + + + + + +
+
+ With bail +
With bail, in 2min 33s.
+
+
+
+ Disable bail +
Disable bail, in 2 min 45s.
+
+
+ +As you can see, when you disable bail, a lot more tests get the "Killing" status, meaning that they killed at least 1 mutant. This does come with a performance penalty of 12s in this example. + +_Note: Disable bail needs to be supported by the test runner plugin in order to work. All official test runner plugins (`@stryker-mutator/xxx-runner`) support this feature._ + ### `disableTypeChecks` [`false | string`] Default: `"{test,src,lib}/**/*.{js,ts,jsx,tsx,html,vue}"`
diff --git a/docs/images/configuration-disable-bail.png b/docs/images/configuration-disable-bail.png new file mode 100644 index 0000000000000000000000000000000000000000..b6a3212ba096963d5a2d43181b02bcd29d29f192 GIT binary patch literal 32152 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 b+Ib*`;LBTc(pI(n&l_Db`?Koe^}qff;x|MY literal 0 HcmV?d00001 diff --git a/docs/images/configuration-with-bail.png b/docs/images/configuration-with-bail.png new file mode 100644 index 0000000000000000000000000000000000000000..fb2c7e0a734634c1ed1d7c4eec128b3a590f75e2 GIT binary patch literal 34065 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 = {}; for (const key in expectedMetricsResult) { - actualSnippet[key as keyof MetricsResult] = actualMetricsResult[key as keyof MetricsResult] as any; + actualSnippet[key as keyof MetricsResult] = actualMetricsResult.systemUnderTestMetrics[key as keyof MetricsResult] as any; } if (actualSnippet.metrics) { if (typeof actualSnippet.metrics.mutationScore === 'number') { @@ -88,7 +88,7 @@ export async function expectMetricsResult(expectedMetricsResult: Partial) { const actualMetricsResult = await readMutationTestingJsonResult(); - expectActualMetrics(expectedMetrics, actualMetricsResult); + expectActualMetrics(expectedMetrics, actualMetricsResult.systemUnderTestMetrics); } /** @@ -96,7 +96,7 @@ export async function expectMetricsJson(expectedMetrics: Partial) { */ export async function expectMetrics(expectedMetrics: Partial) { const actualMetricsResult = await readMutationTestResult(); - expectActualMetrics(expectedMetrics, actualMetricsResult); + expectActualMetrics(expectedMetrics, actualMetricsResult.systemUnderTestMetrics); } export function expectActualMetrics(expectedMetrics: Partial, actualMetricsResult: MetricsResult) { diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 62d6e528d0..6398ea3bc3 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -499,9 +499,9 @@ }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true } } @@ -542,9 +542,9 @@ }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true } } @@ -568,9 +568,9 @@ }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true } } @@ -594,9 +594,9 @@ }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true } } @@ -647,18 +647,18 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz", - "integrity": "sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true } } @@ -1398,19 +1398,41 @@ "dev": true }, "@jest/console": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.1.tgz", - "integrity": "sha512-50E6nN2F5cAXn1lDljn0gE9F0WFXHYz/u0EeR7sOt4nbRPNli34ckbl6CUDaDABJbHt62DYnyQAIB3KgdzwKDw==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.6.tgz", + "integrity": "sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.0.1", - "jest-util": "^27.0.1", + "jest-message-util": "^27.0.6", + "jest-util": "^27.0.6", "slash": "^3.0.0" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1421,15 +1443,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1451,6 +1479,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1469,35 +1526,35 @@ } }, "@jest/core": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.1.tgz", - "integrity": "sha512-PiCbKSMf6t8PEfY3MAd0Ldn3aJAt5T+UcaFkAfMZ1VZgas35+fXk5uHIjAQHQLNIHZWX19TLv0wWNT03yvrw6w==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.6.tgz", + "integrity": "sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==", "dev": true, "requires": { - "@jest/console": "^27.0.1", - "@jest/reporters": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/console": "^27.0.6", + "@jest/reporters": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.0.1", - "jest-config": "^27.0.1", - "jest-haste-map": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-regex-util": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-resolve-dependencies": "^27.0.1", - "jest-runner": "^27.0.1", - "jest-runtime": "^27.0.1", - "jest-snapshot": "^27.0.1", - "jest-util": "^27.0.1", - "jest-validate": "^27.0.1", - "jest-watcher": "^27.0.1", + "jest-changed-files": "^27.0.6", + "jest-config": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-resolve-dependencies": "^27.0.6", + "jest-runner": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "jest-watcher": "^27.0.6", "micromatch": "^4.0.4", "p-each-series": "^2.1.0", "rimraf": "^3.0.0", @@ -1505,6 +1562,28 @@ "strip-ansi": "^6.0.0" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1524,15 +1603,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1563,12 +1648,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -1621,74 +1729,39 @@ } }, "@jest/environment": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.1.tgz", - "integrity": "sha512-nG+r3uSs2pOTsdhgt6lUm4ZGJLRcTc6HZIkrFsVpPcdSqEpJehEny9r9y2Bmhkn8fKXWdGCYJKF3i4nKO0HSmA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.0.1", - "@jest/types": "^27.0.1", - "@types/node": "*", - "jest-mock": "^27.0.1" - } - }, - "@jest/fake-timers": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.1.tgz", - "integrity": "sha512-3CyLJQnHzKI4TCJSCo+I9TzIHjSK4RrNEk93jFM6Q9+9WlSJ3mpMq/p2YuKMe0SiHKbmZOd5G/Ll5ofF9Xkw9g==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.6.tgz", + "integrity": "sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==", "dev": true, "requires": { - "@jest/types": "^27.0.1", - "@sinonjs/fake-timers": "^7.0.2", + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", - "jest-message-util": "^27.0.1", - "jest-mock": "^27.0.1", - "jest-util": "^27.0.1" - } - }, - "@jest/globals": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.1.tgz", - "integrity": "sha512-80ZCzgopysKdpp5EOglgjApKxiNDR96PG4PwngB4fTwZ4qqqSKo0EwGwQIhl16szQ1M2xCVYmr9J6KelvnABNQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.1", - "@jest/types": "^27.0.1", - "expect": "^27.0.1" - } - }, - "@jest/reporters": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.1.tgz", - "integrity": "sha512-lZbJWuS1h/ytKERfu1D6tEQ4PuQ7+15S4+HrSzHR0i7AGVT1WRo49h4fZqxASOp7AQCupUVtPJNZDkaG9ZXy0g==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", - "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": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-util": "^27.0.1", - "jest-worker": "^27.0.1", - "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" + "jest-mock": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1699,9 +1772,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1729,18 +1802,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "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 - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1752,73 +1813,42 @@ } } }, - "@jest/source-map": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.1.tgz", - "integrity": "sha512-yMgkF0f+6WJtDMdDYNavmqvbHtiSpwRN2U/W+6uztgfqgkq/PXdKPqjBTUF1RD/feth4rH5N3NW0T5+wIuln1A==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "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 - } - } - }, - "@jest/test-result": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.1.tgz", - "integrity": "sha512-5aa+ibX2dsGSDLKaQMZb453MqjJU/CRVumebXfaJmuzuGE4qf87yQ2QZ6PEpEtBwVUEgrJCzi3jLCRaUbksSuw==", - "dev": true, - "requires": { - "@jest/console": "^27.0.1", - "@jest/types": "^27.0.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.1.tgz", - "integrity": "sha512-yK2c2iruJ35WgH4KH8whS72uH+FASJUrzwxzNKTzLAEWmNpWKNEPOsSEKsHynvz78bLHafrTg4adN7RrYNbEOA==", - "dev": true, - "requires": { - "@jest/test-result": "^27.0.1", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.1", - "jest-runner": "^27.0.1", - "jest-runtime": "^27.0.1" - } - }, - "@jest/transform": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.1.tgz", - "integrity": "sha512-LC95VpT6wMnQ96dRJDlUiAnW/90zyh4+jS30szI/5AsfS0qwSlr/O4TPcGoD2WVaVMfo6KvR+brvOtGyMHaNhA==", + "@jest/fake-timers": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.6.tgz", + "integrity": "sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.0.1", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.1", - "jest-regex-util": "^27.0.1", - "jest-util": "^27.0.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "@jest/types": "^27.0.6", + "@sinonjs/fake-timers": "^7.0.2", + "@types/node": "*", + "jest-message-util": "^27.0.6", + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1828,25 +1858,514 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/globals": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.6.tgz", + "integrity": "sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.6", + "@jest/types": "^27.0.6", + "expect": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/reporters": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.6.tgz", + "integrity": "sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "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": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "dependencies": { + "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 + } + } + }, + "@jest/test-result": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.6.tgz", + "integrity": "sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/test-sequencer": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz", + "integrity": "sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.0.6", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.6", + "jest-runtime": "^27.0.6" + } + }, + "@jest/transform": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.6.tgz", + "integrity": "sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.0.6", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.0.6", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1877,12 +2396,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -2014,9 +2556,9 @@ } }, "@sinonjs/fake-timers": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.1.tgz", - "integrity": "sha512-am34LJf0N2nON/PT9G7pauA+xjcwX9P6x31m4hBgfUeSXYRZBRv/R6EcdWs8iV4XJjPO++NTsrj7ua/cN2s6ZA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -2029,9 +2571,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", + "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -2042,18 +2584,18 @@ } }, "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -2061,9 +2603,9 @@ } }, "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -2133,9 +2675,9 @@ "dev": true }, "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, "@types/semver": { @@ -2419,9 +2961,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -2734,21 +3276,43 @@ } }, "babel-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.1.tgz", - "integrity": "sha512-aWFD7OGQjk3Y8MdZKf1XePlQvHnjMVJQjIq9WKrlAjz9by703kJ45Jxhp26JwnovoW71YYz5etuqRl8wMcIv0w==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz", + "integrity": "sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==", "dev": true, "requires": { - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.1", + "babel-preset-jest": "^27.0.6", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2759,9 +3323,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2829,9 +3393,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.1.tgz", - "integrity": "sha512-sqBF0owAcCDBVEDtxqfYr2F36eSHdx7lAVGyYuOBRnKdD6gzcy0I0XrAYCZgOA3CRrLhmR+Uae9nogPzmAtOfQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", + "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -2861,12 +3425,12 @@ } }, "babel-preset-jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.1.tgz", - "integrity": "sha512-nIBIqCEpuiyhvjQs2mVNwTxQQa2xk70p9Dd/0obQGBf8FBzbnI8QhQKzLsWMN2i6q+5B0OcWDtrboBX5gmOLyA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", + "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.0.1", + "babel-plugin-jest-hoist": "^27.0.6", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -3423,9 +3987,9 @@ } }, "cjs-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.1.tgz", - "integrity": "sha512-jVamGdJPDeuQilKhvVn1h3knuMOZzr8QDnpk+M9aMlCaMkTDd6fBWPhiDqFvFZ07pL0liqabAiuy8SY4jGHeaw==", + "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==", "dev": true }, "class-transformer": { @@ -4015,9 +4579,9 @@ "dev": true }, "diff-sequences": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.1.tgz", - "integrity": "sha512-XPLijkfJUh/PIBnfkcSHgvD6tlYixmcMAn3osTk6jt+H0v/mgURto1XUiD9DKuGX5NDoVS6dSlA23gd9FUaCFg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", "dev": true }, "diffie-hellman": { @@ -4412,9 +4976,9 @@ } }, "execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", @@ -4522,24 +5086,97 @@ } }, "expect": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.1.tgz", - "integrity": "sha512-hjKwLeAvKUiq0Plha1dmzOH1FGEwJC9njbT993cq4PK9r58/+3NM+WDqFVGcPuRH7XTjmbIeHQBzp2faDrPhjQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz", + "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "ansi-styles": "^5.0.0", - "jest-get-type": "^27.0.1", - "jest-matcher-utils": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-regex-util": "^27.0.1" + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-regex-util": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "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 + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -5560,9 +6197,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -5604,9 +6241,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -6034,9 +6671,9 @@ }, "dependencies": { "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -6083,16 +6720,177 @@ "dev": true }, "jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-lFEoUdXjbGAIxk/gZhcv98xOaH1hjqG5R/PQHs5GBfIK5iL3tnXCjHQf4HQLVZZ2rcXML3oeVg9+XrRZbooBdQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", + "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", "dev": true, "requires": { - "@jest/core": "^27.0.1", + "@jest/core": "^27.0.6", "import-local": "^3.0.2", - "jest-cli": "^27.0.1" + "jest-cli": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-cli": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.6.tgz", + "integrity": "sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==", + "dev": true, + "requires": { + "@jest/core": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "prompts": "^2.0.1", + "yargs": "^16.0.3" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-changed-files": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.6.tgz", + "integrity": "sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "execa": "^5.0.0", + "throat": "^6.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6103,9 +6901,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6133,26 +6931,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-cli": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.1.tgz", - "integrity": "sha512-plDsQQwpkKK1SZ5L5xqMa7v/sTwB5LTIeSJqb+cV+4EMlThdUQfg8jwMfHX8jHuUc9TPGLcdoZeBuZcGGn3Rlg==", - "dev": true, - "requires": { - "@jest/core": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/types": "^27.0.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.0.1", - "jest-util": "^27.0.1", - "jest-validate": "^27.0.1", - "prompts": "^2.0.1", - "yargs": "^16.0.3" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6164,44 +6942,55 @@ } } }, - "jest-changed-files": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.1.tgz", - "integrity": "sha512-Y/4AnqYNcUX/vVgfkmvSA3t7rcg+t8m3CsSGlU+ra8kjlVW5ZqXcBZY/NUew2Mo8M+dn0ApKl+FmGGT1JV5dVA==", - "dev": true, - "requires": { - "@jest/types": "^27.0.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - } - }, "jest-circus": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.1.tgz", - "integrity": "sha512-Tz3ytmrsgxWlTwSyPYb8StF9J2IMjLlbBMKAjhL2UU9/0ZpYb2JiEGjXaAhnGauQRbbpyFbSH3yj5HIbdurmwQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.6.tgz", + "integrity": "sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==", "dev": true, "requires": { - "@jest/environment": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/environment": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.0.1", + "expect": "^27.0.6", "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.1", - "jest-matcher-utils": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-runner": "^27.0.1", - "jest-runtime": "^27.0.1", - "jest-snapshot": "^27.0.1", - "jest-util": "^27.0.1", - "pretty-format": "^27.0.1", + "jest-each": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6", + "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6212,15 +7001,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6242,6 +7037,41 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6254,33 +7084,56 @@ } }, "jest-config": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.1.tgz", - "integrity": "sha512-V8O6+CZjGF0OMq4kxVR29ztV/LQqlAAcJLw7a94RndfRXkha4U84n50yZCXiPWtAHHTmb3g1y52US6rGPxA+3w==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.6.tgz", + "integrity": "sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.0.1", - "@jest/types": "^27.0.1", - "babel-jest": "^27.0.1", + "@jest/test-sequencer": "^27.0.6", + "@jest/types": "^27.0.6", + "babel-jest": "^27.0.6", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.0.1", - "jest-environment-jsdom": "^27.0.1", - "jest-environment-node": "^27.0.1", - "jest-get-type": "^27.0.1", - "jest-jasmine2": "^27.0.1", - "jest-regex-util": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-util": "^27.0.1", - "jest-validate": "^27.0.1", + "jest-circus": "^27.0.6", + "jest-environment-jsdom": "^27.0.6", + "jest-environment-node": "^27.0.6", + "jest-get-type": "^27.0.6", + "jest-jasmine2": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-runner": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", "micromatch": "^4.0.4", - "pretty-format": "^27.0.1" + "pretty-format": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6300,9 +7153,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6360,6 +7213,20 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -6397,15 +7264,15 @@ } }, "jest-diff": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.1.tgz", - "integrity": "sha512-DQ3OgfJgoGWVTYo4qnYW/Jg5mpYFS2QW9BLxA8bs12ZRN1K8QPZtWeYvUPohQFs3CHX3JLTndGg3jyxdL5THFQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", + "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.0.1", - "jest-get-type": "^27.0.1", - "pretty-format": "^27.0.1" + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" }, "dependencies": { "ansi-styles": { @@ -6418,9 +7285,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6460,27 +7327,49 @@ } }, "jest-docblock": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.1.tgz", - "integrity": "sha512-TA4+21s3oebURc7VgFV4r7ltdIJ5rtBH1E3Tbovcg7AV+oLfD5DcJ2V2vJ5zFA9sL5CFd/d2D6IpsAeSheEdrA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.1.tgz", - "integrity": "sha512-uJTK/aZ05HsdKkfXucAT5+/1DIURnTRv34OSxn1HWHrD+xu9eDX5Xgds09QSvg/mU01VS5upuHTDKG3W+r0rQA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.6.tgz", + "integrity": "sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "chalk": "^4.0.0", - "jest-get-type": "^27.0.1", - "jest-util": "^27.0.1", - "pretty-format": "^27.0.1" + "jest-get-type": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6491,15 +7380,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6521,6 +7416,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6533,20 +7457,42 @@ } }, "jest-environment-jsdom": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.1.tgz", - "integrity": "sha512-lesU8T9zkjgLaLpUFmFDgchu6/2OCoXm52nN6UumR063Hb+1TJdI7ihgM86+G01Ay86Lyr+K/FAR6yIIOviH3Q==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz", + "integrity": "sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==", "dev": true, "requires": { - "@jest/environment": "^27.0.1", - "@jest/fake-timers": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", - "jest-mock": "^27.0.1", - "jest-util": "^27.0.1", + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6", "jsdom": "^16.6.0" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -6554,15 +7500,55 @@ "dev": true }, "acorn": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", - "integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "escodegen": { @@ -6595,16 +7581,45 @@ "mime-types": "^2.1.12" } }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, "jsdom": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", - "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", @@ -6632,7 +7647,7 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.5", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" } }, @@ -6642,12 +7657,27 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "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 + "optional": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } }, "tough-cookie": { "version": "4.0.0", @@ -6660,21 +7690,30 @@ "universalify": "^0.1.2" } }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, "whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { "lodash": "^4.7.0", - "tr46": "^2.0.2", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", + "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", "dev": true } } @@ -6889,46 +7928,185 @@ } }, "jest-environment-node": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.1.tgz", - "integrity": "sha512-/p94lo0hx+hbKUw1opnRFUPPsjncRBEUU+2Dh7BuxX8Nr4rRiTivLYgXzo79FhaeMYV0uiV5WAbHBq6xC11JJg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.6.tgz", + "integrity": "sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==", "dev": true, "requires": { - "@jest/environment": "^27.0.1", - "@jest/fake-timers": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", - "jest-mock": "^27.0.1", - "jest-util": "^27.0.1" + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-get-type": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", - "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", "dev": true }, "jest-haste-map": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.1.tgz", - "integrity": "sha512-ioCuobr4z90H1Pz8+apz2vfz63387apzAoawm/9IIOndarDfRkjLURdLOe//AI5jUQmjVRg+WiL92339kqlCmA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.6.tgz", + "integrity": "sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.1", - "jest-serializer": "^27.0.1", - "jest-util": "^27.0.1", - "jest-worker": "^27.0.1", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", "micromatch": "^4.0.4", "walker": "^1.0.7" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -6948,6 +8126,37 @@ "fill-range": "^7.0.1" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -6964,12 +8173,49 @@ "dev": true, "optional": true }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + }, + "dependencies": { + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + } + } + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -6988,6 +8234,15 @@ } } }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7000,31 +8255,53 @@ } }, "jest-jasmine2": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.1.tgz", - "integrity": "sha512-o8Ist0o970QDDm/R2o9UDbvNxq8A0++FTFQ0z9OnieJwS1nDH6H7WBDYAGPTdmnla7kbW41oLFPvhmjJE4mekg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz", + "integrity": "sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.0.1", - "@jest/source-map": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/environment": "^27.0.6", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.0.1", + "expect": "^27.0.6", "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.1", - "jest-matcher-utils": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-runtime": "^27.0.1", - "jest-snapshot": "^27.0.1", - "jest-util": "^27.0.1", - "pretty-format": "^27.0.1", + "jest-each": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6", "throat": "^6.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7035,15 +8312,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7065,6 +8348,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7077,25 +8389,25 @@ } }, "jest-leak-detector": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.1.tgz", - "integrity": "sha512-SQ/lRhfmnV3UuiaKIjwNXCaW2yh1rTMAL4n4Cl4I4gU0X2LoIc6Ogxe4UKM/J6Ld2uzc4gDGVYc5lSdpf6WjYw==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz", + "integrity": "sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==", "dev": true, "requires": { - "jest-get-type": "^27.0.1", - "pretty-format": "^27.0.1" + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" } }, "jest-matcher-utils": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.1.tgz", - "integrity": "sha512-NauNU+olKhPzLlsRnTOYFGk/MK5QFYl9ZzkrtfsY4eCq4SB3Bcl03UL44VdnlN5S/uFn4H2jwvRY1y6nSDTX3g==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz", + "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.0.1", - "jest-get-type": "^27.0.1", - "pretty-format": "^27.0.1" + "jest-diff": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" }, "dependencies": { "ansi-styles": { @@ -7107,10 +8419,10 @@ "color-convert": "^2.0.1" } }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -7150,44 +8462,44 @@ } }, "jest-message-util": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.1.tgz", - "integrity": "sha512-w8BfON2GwWORkos8BsxcwwQrLkV2s1ENxSRXK43+6yuquDE2hVxES/jrFqOArpP1ETVqqMmktU6iGkG8ncVzeA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz", + "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.0.1", + "pretty-format": "^27.0.6", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", "dev": true }, "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -7205,12 +8517,34 @@ } } }, + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "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 }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -7221,9 +8555,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -7320,13 +8654,86 @@ } }, "jest-mock": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.1.tgz", - "integrity": "sha512-fXCSZQDT5hUcAUy8OBnB018x7JFOMQnz4XfpSKEbfpWzL6o5qaLRhgf2Qg2NPuVKmC/fgOf33Edj8wjF4I24CQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.6.tgz", + "integrity": "sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "@types/node": "*" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-pnp-resolver": { @@ -7336,27 +8743,50 @@ "dev": true }, "jest-regex-util": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.1.tgz", - "integrity": "sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", "dev": true }, "jest-resolve": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.1.tgz", - "integrity": "sha512-Q7QQ0OZ7z6D5Dul0MrsexlKalU8ZwexBfHLSu1qYPgphvUm6WO1b/xUnipU3e+uW1riDzMcJeJVYbdQ37hBHeg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.6.tgz", + "integrity": "sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "chalk": "^4.0.0", "escalade": "^3.1.1", "graceful-fs": "^4.2.4", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.0.1", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", "resolve": "^1.20.0", "slash": "^3.0.0" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7367,15 +8797,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7397,6 +8833,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -7425,45 +8890,141 @@ } }, "jest-resolve-dependencies": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.1.tgz", - "integrity": "sha512-ly1x5mEf21f3IVWbUNwIz/ePLtv4QdhYuQIVSVDqxx7yzAwhhdu0DJo7UNiEYKQY7Im48wfbNdOUpo7euFUXBQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz", + "integrity": "sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==", "dev": true, "requires": { - "@jest/types": "^27.0.1", - "jest-regex-util": "^27.0.1", - "jest-snapshot": "^27.0.1" + "@jest/types": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-runner": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.1.tgz", - "integrity": "sha512-DUNizlD2D7J80G3VOrwfbtb7KYxiftMng82HNcKwTW0W3AwwNuBeq+1exoCnLO7Mxh7NP+k/1XQBlzLpjr/CnA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.6.tgz", + "integrity": "sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==", "dev": true, "requires": { - "@jest/console": "^27.0.1", - "@jest/environment": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/console": "^27.0.6", + "@jest/environment": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-config": "^27.0.1", - "jest-docblock": "^27.0.1", - "jest-haste-map": "^27.0.1", - "jest-leak-detector": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-runtime": "^27.0.1", - "jest-util": "^27.0.1", - "jest-worker": "^27.0.1", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.0.6", + "jest-environment-node": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-leak-detector": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7474,34 +9035,69 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "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, "requires": { - "color-name": "~1.1.4" + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" } }, - "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 - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "supports-color": { @@ -7516,19 +9112,19 @@ } }, "jest-runtime": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.1.tgz", - "integrity": "sha512-ImcrbQtpCUp8X9Rm4ky3j1GG9cqIKZJvXGZyB5cHEapGPTmg7wvvNooLmKragEe61/p/bhw1qO68Y0/9BSsBBg==", - "dev": true, - "requires": { - "@jest/console": "^27.0.1", - "@jest/environment": "^27.0.1", - "@jest/fake-timers": "^27.0.1", - "@jest/globals": "^27.0.1", - "@jest/source-map": "^27.0.1", - "@jest/test-result": "^27.0.1", - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.6.tgz", + "integrity": "sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/globals": "^27.0.6", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", @@ -7536,23 +9132,36 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-mock": "^27.0.1", - "jest-regex-util": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-snapshot": "^27.0.1", - "jest-util": "^27.0.1", - "jest-validate": "^27.0.1", + "jest-haste-map": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-mock": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^16.0.3" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, "@types/yargs": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", - "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -7568,15 +9177,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7598,6 +9213,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7622,9 +9266,9 @@ } }, "jest-serializer": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.1.tgz", - "integrity": "sha512-svy//5IH6bfQvAbkAEg1s7xhhgHTtXu0li0I2fdKHDsLP2P2MOiscPQIENQep8oU2g2B3jqLyxKKzotZOz4CwQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", "dev": true, "requires": { "@types/node": "*", @@ -7632,9 +9276,9 @@ } }, "jest-snapshot": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.1.tgz", - "integrity": "sha512-HgKmSebDB3rswugREeh+nKrxJEVZE12K7lZ2MuwfFZT6YmiH0TlofsL2YmiLsCsG5KH5ZcLYYpF5bDrvtVx/Xg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.6.tgz", + "integrity": "sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==", "dev": true, "requires": { "@babel/core": "^7.7.2", @@ -7643,26 +9287,48 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.0.1", + "expect": "^27.0.6", "graceful-fs": "^4.2.4", - "jest-diff": "^27.0.1", - "jest-get-type": "^27.0.1", - "jest-haste-map": "^27.0.1", - "jest-matcher-utils": "^27.0.1", - "jest-message-util": "^27.0.1", - "jest-resolve": "^27.0.1", - "jest-util": "^27.0.1", + "jest-diff": "^27.0.6", + "jest-get-type": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-util": "^27.0.6", "natural-compare": "^1.4.0", - "pretty-format": "^27.0.1", + "pretty-format": "^27.0.6", "semver": "^7.3.2" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7673,15 +9339,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7703,6 +9375,29 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7712,6 +9407,12 @@ "yallist": "^4.0.0" } }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -7825,19 +9526,41 @@ } }, "jest-validate": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.1.tgz", - "integrity": "sha512-zvmPRcfTkqTZuHveIKAI2nbkUc3SDXjWVJULknPLGF5bdxOGSeGZg7f/Uw0MUVOkCOaspcHnsPCgZG0pqmg71g==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.6.tgz", + "integrity": "sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.0.1", + "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^27.0.1" + "pretty-format": "^27.0.6" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7854,9 +9577,9 @@ "dev": true }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -7896,20 +9619,42 @@ } }, "jest-watcher": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.1.tgz", - "integrity": "sha512-Chp9c02BN0IgEbtGreyAhGqIsOrn9a0XnzbuXOxdW1+cW0Tjh12hMzHDIdLFHpYP/TqaMTmPHaJ5KWvpCCrNFw==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.6.tgz", + "integrity": "sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==", "dev": true, "requires": { - "@jest/test-result": "^27.0.1", - "@jest/types": "^27.0.1", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.0.1", + "jest-util": "^27.0.6", "string-length": "^4.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7920,15 +9665,21 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7950,6 +9701,35 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7962,9 +9742,9 @@ } }, "jest-worker": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.1.tgz", - "integrity": "sha512-NhHqClI3owOjmS8dBhQMKHZ2rrT0sBTpqGitp9nMX5AAjVXd+15o4v96uBEMhoywaLKN+5opcKBlXwAoADZolA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", + "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", "dev": true, "requires": { "@types/node": "*", @@ -9987,22 +11767,95 @@ "dev": true }, "pretty-format": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.1.tgz", - "integrity": "sha512-qE+0J6c/gd+R6XTcQgPJMc5hMJNsxzSF5p8iZSbMZ7GQzYGlSLNkh2P80Wa2dbF4gEVUsJEgcrBY+1L2/j265w==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", "dev": true, "requires": { - "@jest/types": "^27.0.1", + "@jest/types": "^27.0.6", "ansi-regex": "^5.0.0", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "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 + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -11979,9 +13832,9 @@ "dev": true }, "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", + "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", diff --git a/e2e/package.json b/e2e/package.json index 0a52948eb3..a3715f4ff3 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -20,7 +20,7 @@ "grunt": "~1.3.0", "jasmine": "~3.6.2", "jasmine-core": "~3.6.0", - "jest": "~27.0.1", + "jest": "^27.0.6", "jest-environment-jsdom-sixteen": "^1.0.3", "karma": "~6.0.1", "karma-chai": "~0.1.0", diff --git a/e2e/test/disable-bail/.mocharc.json b/e2e/test/disable-bail/.mocharc.json new file mode 100644 index 0000000000..a17ebe5b50 --- /dev/null +++ b/e2e/test/disable-bail/.mocharc.json @@ -0,0 +1,3 @@ +{ + "require": ["test/chai-setup.js"] +} diff --git a/e2e/test/disable-bail/cucumber.js b/e2e/test/disable-bail/cucumber.js new file mode 100644 index 0000000000..dbb7402cca --- /dev/null +++ b/e2e/test/disable-bail/cucumber.js @@ -0,0 +1 @@ +module.exports = { default: '--publish-quiet' }; diff --git a/e2e/test/disable-bail/features/add.feature b/e2e/test/disable-bail/features/add.feature new file mode 100644 index 0000000000..2e47c6381a --- /dev/null +++ b/e2e/test/disable-bail/features/add.feature @@ -0,0 +1,9 @@ +Feature: Add + +Scenario: Add 40 and 2 +When I add 40 and 2 +Then I get 42 + +Scenario: Add 41 and 1 +When I add 41 and 1 +Then I get 42 \ No newline at end of file diff --git a/e2e/test/disable-bail/features/add.steps.js b/e2e/test/disable-bail/features/add.steps.js new file mode 100644 index 0000000000..f0bd3c6531 --- /dev/null +++ b/e2e/test/disable-bail/features/add.steps.js @@ -0,0 +1,11 @@ +const { When, Then } = require('@cucumber/cucumber'); +const { add } = require('../src/math'); +const { expect } = require('chai'); + +When('I add {int} and {int}', function (n, n2) { + this.result = add(n, n2); +}); + +Then('I get {int}', function (expected) { + expect(this.result).eq(expected); +}); diff --git a/e2e/test/disable-bail/karma.conf.js b/e2e/test/disable-bail/karma.conf.js new file mode 100644 index 0000000000..bc248c86b4 --- /dev/null +++ b/e2e/test/disable-bail/karma.conf.js @@ -0,0 +1,15 @@ +module.exports = function(config) { + config.set({ + frameworks: ['jasmine'], + files: [ + 'src/*.js', + 'test/math.spec.js' + ], + reporters: ['progress'], + colors: true, + autoWatch: false, + browsers: ['ChromeHeadless'], + singleRun: true, + concurrency: Infinity + }); +} diff --git a/e2e/test/disable-bail/package.json b/e2e/test/disable-bail/package.json new file mode 100644 index 0000000000..484f41bcea --- /dev/null +++ b/e2e/test/disable-bail/package.json @@ -0,0 +1,17 @@ +{ + "name": "disable-bail", + "version": "1.0.0", + "description": "A e2e test for --disableBail", + "main": "index.js", + "scripts": { + "test:cucumber": "cucumber-js", + "test:mocha": "mocha", + "test:jasmine": "jasmine", + "test:karma": "karma start", + "test:jest": "jest", + "test": "mocha --no-config --no-timeout --require ../../tasks/ts-node-register.js verify/*.ts" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/e2e/test/disable-bail/spec/support/jasmine.json b/e2e/test/disable-bail/spec/support/jasmine.json new file mode 100644 index 0000000000..67fbf562e7 --- /dev/null +++ b/e2e/test/disable-bail/spec/support/jasmine.json @@ -0,0 +1,8 @@ +{ + "spec_dir": "spec", + "spec_files": [ + "../test/*.spec.js" + ], + "stopSpecOnExpectationFailure": false, + "random": true +} diff --git a/e2e/test/disable-bail/src/math.js b/e2e/test/disable-bail/src/math.js new file mode 100644 index 0000000000..7cba9ec27f --- /dev/null +++ b/e2e/test/disable-bail/src/math.js @@ -0,0 +1,8 @@ +{ + const add = (a, b) => a + b; + + globalThis.add = add; + if (typeof exports === 'object') { + exports.add = add; + } +} diff --git a/e2e/test/disable-bail/stryker.conf.json b/e2e/test/disable-bail/stryker.conf.json new file mode 100644 index 0000000000..0b487b1af3 --- /dev/null +++ b/e2e/test/disable-bail/stryker.conf.json @@ -0,0 +1,9 @@ +{ + "$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json", + "concurrency": 1, + "reporters": ["json"], + "disableBail": true, + "karma": { + "configFile": "karma.conf.js" + } +} diff --git a/e2e/test/disable-bail/test/chai-setup.js b/e2e/test/disable-bail/test/chai-setup.js new file mode 100644 index 0000000000..38e9e0f335 --- /dev/null +++ b/e2e/test/disable-bail/test/chai-setup.js @@ -0,0 +1,6 @@ +const chai = require('chai'); + +chai.util.addMethod(chai.Assertion.prototype, 'toEqual', function (expected) { + var obj = chai.util.flag(this, 'object'); + new chai.Assertion(obj).to.deep.equal(expected); +}); diff --git a/e2e/test/disable-bail/test/math.spec.js b/e2e/test/disable-bail/test/math.spec.js new file mode 100644 index 0000000000..7bfcff0d29 --- /dev/null +++ b/e2e/test/disable-bail/test/math.spec.js @@ -0,0 +1,17 @@ +let add = globalThis.add; +if (typeof require === 'function') { + add = require('../src/math').add; +} +if(typeof expect === 'undefined'){ + globalThis.expect = require('chai').expect; +} + +describe(add.name, () => { + // Both tests kill the same mutant, necessary to test disableBail + it('should result in 42 for 40 and 2', () => { + expect(add(40, 2)).toEqual(42); + }); + it('should result in 42 for 41 and 1', () => { + expect(add(41, 1)).toEqual(42); + }); +}); diff --git a/e2e/test/disable-bail/verify/verify.ts b/e2e/test/disable-bail/verify/verify.ts new file mode 100644 index 0000000000..4c5dc38104 --- /dev/null +++ b/e2e/test/disable-bail/verify/verify.ts @@ -0,0 +1,45 @@ +import fs from 'fs'; + +import { readMutationTestingJsonResult, execStryker} from '../../../helpers'; +import { expect } from 'chai'; + +describe('disableBail', () => { + + beforeEach(async () => { + await fs.promises.rm('reports', { recursive: true, force: true }) + }) + + it('should be supported in the jest runner', async () => { + execStryker('stryker run --testRunner jest'); + await assertBailWasDisabled(); + }); + + it('should be supported in the karma runner', async () => { + execStryker('stryker run --testRunner karma'); + await assertBailWasDisabled(); + }); + + it('should be supported in the jasmine runner', async () => { + execStryker('stryker run --testRunner jasmine'); + await assertBailWasDisabled(); + }); + + it('should be supported in the mocha runner', async () => { + execStryker('stryker run --testRunner mocha'); + await assertBailWasDisabled(); + }); + + it('should be supported in the cucumber runner', async () => { + execStryker('stryker run --testRunner cucumber'); + await assertBailWasDisabled(['Feature: Add -- Scenario: Add 40 and 2', 'Feature: Add -- Scenario: Add 41 and 1']); + }); +}); + +async function assertBailWasDisabled([killedByName1, killedByName2] = ['add should result in 42 for 40 and 2', 'add should result in 42 for 41 and 1']) { + const result = await readMutationTestingJsonResult(); + const theMutant = result.systemUnderTestMetrics.childResults[0].file.mutants.find(mutant => mutant.replacement === 'a - b'); + expect(theMutant.killedByTests).lengthOf(2); + expect(theMutant.killedByTests[0].name).eq(killedByName1); + expect(theMutant.killedByTests[1].name).eq(killedByName2); +} + diff --git a/e2e/test/ignore-project/verify/verify.ts b/e2e/test/ignore-project/verify/verify.ts index 8c9374f904..484b599581 100644 --- a/e2e/test/ignore-project/verify/verify.ts +++ b/e2e/test/ignore-project/verify/verify.ts @@ -20,7 +20,7 @@ describe('After running stryker on jest-react project', () => { it('should report mutants that are disabled by a comment with correct ignore reason', async () => { const actualMetricsResult = await readMutationTestingJsonResult(); - const addResult = actualMetricsResult.childResults.find(file => file.name.endsWith('Add.js')).file!; + const addResult = actualMetricsResult.systemUnderTestMetrics.childResults.find(file => file.name.endsWith('Add.js')).file!; const mutantsAtLine31 = addResult.mutants.filter(({ location }) => location.start.line === 31) const booleanLiteralMutants = mutantsAtLine31.filter(({mutatorName}) => mutatorName === 'BooleanLiteral'); const conditionalExpressionMutants = mutantsAtLine31.filter(({mutatorName}) => mutatorName === 'ConditionalExpression'); @@ -41,7 +41,7 @@ describe('After running stryker on jest-react project', () => { it('should report mutants that result from excluded mutators with the correct ignore reason', async () => { const actualMetricsResult = await readMutationTestingJsonResult(); - const circleResult = actualMetricsResult.childResults.find(file => file.name.endsWith('Circle.js')).file!; + const circleResult = actualMetricsResult.systemUnderTestMetrics.childResults.find(file => file.name.endsWith('Circle.js')).file!; const mutantsAtLine3 = circleResult.mutants.filter(({ location }) => location.start.line === 3) mutantsAtLine3.forEach((mutant) => { diff --git a/packages/api/schema/stryker-core.json b/packages/api/schema/stryker-core.json index d9e97e0356..51f041ef25 100644 --- a/packages/api/schema/stryker-core.json +++ b/packages/api/schema/stryker-core.json @@ -456,6 +456,11 @@ } ], "description": "Enable or disable certain warnings" + }, + "disableBail": { + "description": "Disables the default of bailing after first failing test. When true runs all tests covering a mutant. Useful when the subject under test is not completely isolated by mocks and you want to know which tests are killing the mutants. This will impact performance.", + "type": "boolean", + "default": false } } } diff --git a/packages/api/src/test-runner/mutant-run-result.ts b/packages/api/src/test-runner/mutant-run-result.ts index 444f426933..e22aaab9cc 100644 --- a/packages/api/src/test-runner/mutant-run-result.ts +++ b/packages/api/src/test-runner/mutant-run-result.ts @@ -18,11 +18,11 @@ export interface TimeoutMutantRunResult { export interface KilledMutantRunResult { status: MutantRunStatus.Killed; /** - * The id of the test that killed this mutant + * An array with the ids of the tests that killed this mutant */ - killedBy: string; + killedBy: string[] | string; /** - * The failure message that was reported by the test + * The failure message that was reported by first the test */ failureMessage: string; /** diff --git a/packages/api/src/test-runner/run-options.ts b/packages/api/src/test-runner/run-options.ts index 35371cfca4..94604fa027 100644 --- a/packages/api/src/test-runner/run-options.ts +++ b/packages/api/src/test-runner/run-options.ts @@ -5,6 +5,10 @@ export interface RunOptions { * The amount of time (in milliseconds) the TestRunner has to complete the test run before a timeout occurs. */ timeout: number; + /** + * Filled from disableBail in config + */ + disableBail: boolean; } export interface DryRunOptions extends RunOptions { diff --git a/packages/api/src/test-runner/run-result-helpers.ts b/packages/api/src/test-runner/run-result-helpers.ts index 792c5daf85..cbd043501c 100644 --- a/packages/api/src/test-runner/run-result-helpers.ts +++ b/packages/api/src/test-runner/run-result-helpers.ts @@ -11,16 +11,17 @@ export function determineHitLimitReached(hitCount: number | undefined, hitLimit: return; } -export function toMutantRunResult(dryRunResult: DryRunResult): MutantRunResult { +export function toMutantRunResult(dryRunResult: DryRunResult, reportAllKillers = false): MutantRunResult { switch (dryRunResult.status) { case DryRunStatus.Complete: { - const killedBy = dryRunResult.tests.find((test): test is FailedTestResult => test.status === TestStatus.Failed); + const failedTests = dryRunResult.tests.filter((test): test is FailedTestResult => test.status === TestStatus.Failed); const nrOfTests = dryRunResult.tests.filter((test) => test.status !== TestStatus.Skipped).length; - if (killedBy) { + + if (failedTests.length > 0) { return { status: MutantRunStatus.Killed, - failureMessage: killedBy.failureMessage, - killedBy: killedBy.id, + failureMessage: failedTests[0].failureMessage, + killedBy: reportAllKillers ? failedTests.map((test) => test.id) : failedTests[0].id, nrOfTests, }; } else { diff --git a/packages/api/test/unit/test_runner/run-result-helpers.spec.ts b/packages/api/test/unit/test_runner/run-result-helpers.spec.ts index d35dbd25ce..a0b1c11fcd 100644 --- a/packages/api/test/unit/test_runner/run-result-helpers.spec.ts +++ b/packages/api/test/unit/test_runner/run-result-helpers.spec.ts @@ -36,13 +36,41 @@ describe('runResultHelpers', () => { expect(actual).deep.eq(expected); }); - it('should report a failed test as "killed"', () => { - const expected: MutantRunResult = { status: MutantRunStatus.Killed, failureMessage: 'expected foo to be bar', killedBy: '42', nrOfTests: 3 }; + it('should report all failed tests as "killed" when given the option', () => { + const expected: MutantRunResult = { + status: MutantRunStatus.Killed, + failureMessage: 'expected foo to be bar', + killedBy: ['42', '43'], + nrOfTests: 4, + }; + const actual = toMutantRunResult( + { + status: DryRunStatus.Complete, + tests: [ + { status: TestStatus.Success, id: 'success1', name: 'success1', timeSpentMs: 42 }, + { status: TestStatus.Failed, id: '42', name: 'error', timeSpentMs: 42, failureMessage: 'expected foo to be bar' }, + { status: TestStatus.Failed, id: '43', name: 'error', timeSpentMs: 42, failureMessage: 'expected this to be that' }, + { status: TestStatus.Success, id: 'success2', name: 'success2', timeSpentMs: 42 }, + ], + }, + true + ); + expect(actual).deep.eq(expected); + }); + + it('should report a single tests as "killed" by default', () => { + const expected: MutantRunResult = { + status: MutantRunStatus.Killed, + failureMessage: 'expected foo to be bar', + killedBy: '42', + nrOfTests: 4, + }; const actual = toMutantRunResult({ status: DryRunStatus.Complete, tests: [ { status: TestStatus.Success, id: 'success1', name: 'success1', timeSpentMs: 42 }, { status: TestStatus.Failed, id: '42', name: 'error', timeSpentMs: 42, failureMessage: 'expected foo to be bar' }, + { status: TestStatus.Failed, id: '43', name: 'error', timeSpentMs: 42, failureMessage: 'expected this to be that' }, { status: TestStatus.Success, id: 'success2', name: 'success2', timeSpentMs: 42 }, ], }); diff --git a/packages/core/src/config/options-validator.ts b/packages/core/src/config/options-validator.ts index 8170eb2c8b..75fd8615b7 100644 --- a/packages/core/src/config/options-validator.ts +++ b/packages/core/src/config/options-validator.ts @@ -87,6 +87,16 @@ export class OptionsValidator { const existingIgnorePatterns = Array.isArray(rawOptions[ignorePatternsName]) ? (rawOptions[ignorePatternsName] as unknown[]) : []; rawOptions[ignorePatternsName] = [...newIgnorePatterns, ...existingIgnorePatterns]; } + // @ts-expect-error jest.enableBail + if (rawOptions.jest?.enableBail !== undefined) { + this.log.warn( + 'DEPRECATED. Use of "jest.enableBail" inside deprecated, please use "disableBail" instead. See https://stryker-mutator.io/docs/stryker-js/configuration#disablebail-boolean' + ); + // @ts-expect-error jest.enableBail + rawOptions.disableBail = !rawOptions.jest?.enableBail; + // @ts-expect-error jest.enableBail + delete rawOptions.jest.enableBail; + } } private additionalValidation(options: StrykerOptions) { diff --git a/packages/core/src/process/3-dry-run-executor.ts b/packages/core/src/process/3-dry-run-executor.ts index 18b9e5c929..d6c5fe84a5 100644 --- a/packages/core/src/process/3-dry-run-executor.ts +++ b/packages/core/src/process/3-dry-run-executor.ts @@ -128,7 +128,11 @@ export class DryRunExecutor { `Starting initial test run (${this.options.testRunner} test runner with "${this.options.coverageAnalysis}" coverage analysis). This may take a while.` ); this.log.debug(`Using timeout of ${dryRunTimeout} ms.`); - const dryRunResult = await testRunner.dryRun({ timeout: dryRunTimeout, coverageAnalysis: this.options.coverageAnalysis }); + const dryRunResult = await testRunner.dryRun({ + timeout: dryRunTimeout, + coverageAnalysis: this.options.coverageAnalysis, + disableBail: this.options.disableBail, + }); const grossTimeMS = this.timer.elapsedMs(INITIAL_TEST_RUN_MARKER); const humanReadableTimeElapsed = this.timer.humanReadableElapsed(INITIAL_TEST_RUN_MARKER); this.validateResultCompleted(dryRunResult); diff --git a/packages/core/src/process/4-mutation-test-executor.ts b/packages/core/src/process/4-mutation-test-executor.ts index c0ecb9df63..156b5c1bb0 100644 --- a/packages/core/src/process/4-mutation-test-executor.ts +++ b/packages/core/src/process/4-mutation-test-executor.ts @@ -137,6 +137,7 @@ export class MutationTestExecutor { testFilter: activeMutant.coveredBy, sandboxFileName: this.sandbox.sandboxFileFor(activeMutant.fileName), hitLimit, + disableBail: this.options.disableBail, }; } diff --git a/packages/core/src/reporters/mutation-test-report-helper.ts b/packages/core/src/reporters/mutation-test-report-helper.ts index 1ea76d2c2c..b8f9c7bcc7 100644 --- a/packages/core/src/reporters/mutation-test-report-helper.ts +++ b/packages/core/src/reporters/mutation-test-report-helper.ts @@ -66,7 +66,7 @@ export class MutationTestReportHelper { ...mutant, status: MutantStatus.Killed, testsCompleted: result.nrOfTests, - killedBy: [result.killedBy], + killedBy: typeof result.killedBy === 'string' ? [result.killedBy] : result.killedBy, statusReason: result.failureMessage, }); case MutantRunStatus.Timeout: diff --git a/packages/core/src/stryker-cli.ts b/packages/core/src/stryker-cli.ts index 3bb2751db9..1826b7e2ee 100644 --- a/packages/core/src/stryker-cli.ts +++ b/packages/core/src/stryker-cli.ts @@ -67,7 +67,7 @@ export class StrykerCli { }) .option( '-f, --files ', - 'A comma separated list of patterns used for selecting all files needed to run the tests. For a more detailed way of selecting input files, please use a configFile. Example: src/**/*.js,!src/index.js,a.js,test/**/*.js.', + '[DEPRECATED, please use `--ignorePatterns` instead] A comma separated list of patterns used for selecting all files needed to run the tests. For a more detailed way of selecting input files, please use a configFile. Example: src/**/*.js,!src/index.js,a.js,test/**/*.js.', list ) .option( @@ -110,6 +110,7 @@ export class StrykerCli { 'Set the concurrency of workers. Stryker will always run checkers and test runners in parallel by creating worker processes (default: cpuCount - 1)', parseInt ) + .option('--disableBail', 'Force the test runner to keep running tests, even when a mutant is already killed.') .option( '--maxTestRunnerReuse ', 'Restart each test runner worker process after `n` runs. Not recommended unless you are experiencing memory leaks that you are unable to resolve. Configuring `0` here means infinite reuse.', diff --git a/packages/core/test/integration/test-runner/create-test-runner-factory.it.spec.ts b/packages/core/test/integration/test-runner/create-test-runner-factory.it.spec.ts index 2cacaa6abd..84ba755ee5 100644 --- a/packages/core/test/integration/test-runner/create-test-runner-factory.it.spec.ts +++ b/packages/core/test/integration/test-runner/create-test-runner-factory.it.spec.ts @@ -64,7 +64,7 @@ describe(`${createTestRunnerFactory.name} integration`, () => { } function actDryRun(timeout = 4000) { - return sut.dryRun({ timeout, coverageAnalysis: 'all' }); + return sut.dryRun(factory.dryRunOptions({ timeout, coverageAnalysis: 'all' })); } function actMutantRun(options = factory.mutantRunOptions()) { diff --git a/packages/core/test/unit/config/options-validator.spec.ts b/packages/core/test/unit/config/options-validator.spec.ts index 97c45ec980..08ae7425be 100644 --- a/packages/core/test/unit/config/options-validator.spec.ts +++ b/packages/core/test/unit/config/options-validator.spec.ts @@ -83,6 +83,7 @@ describe(OptionsValidator.name, () => { timeoutMS: 5000, tsconfigFile: 'tsconfig.json', warnings: true, + disableBail: false, }; expect(options).deep.eq(expectedOptions); }); @@ -163,6 +164,15 @@ describe(OptionsValidator.name, () => { actValidationErrors('Config option "dryRunTimeoutMinutes" must be >= 0, was -1.'); }); + it('should report a deprecation warning and set disableBail for jest.enableBail', () => { + testInjector.options.jest = { enableBail: false }; + sut.validate(testInjector.options); + expect(testInjector.logger.warn).calledWith( + 'DEPRECATED. Use of "jest.enableBail" inside deprecated, please use "disableBail" instead. See https://stryker-mutator.io/docs/stryker-js/configuration#disablebail-boolean' + ); + expect(testInjector.options.disableBail).true; + }); + describe('plugins', () => { it('should be invalid with non-array plugins', () => { breakConfig('plugins', '@stryker-mutator/typescript'); diff --git a/packages/core/test/unit/process/3-dry-run-executor.spec.ts b/packages/core/test/unit/process/3-dry-run-executor.spec.ts index e8c1fe9c53..6e5ab56f97 100644 --- a/packages/core/test/unit/process/3-dry-run-executor.spec.ts +++ b/packages/core/test/unit/process/3-dry-run-executor.spec.ts @@ -84,6 +84,31 @@ describe(DryRunExecutor.name, () => { }); }); + describe('disable bail', () => { + let runResult: CompleteDryRunResult; + + beforeEach(() => { + runResult = factory.completeDryRunResult(); + testRunnerMock.dryRun.resolves(runResult); + runResult.tests.push(factory.successTestResult()); + }); + + it('should bail by default', async () => { + await sut.execute(); + expect(testRunnerMock.dryRun).calledWithMatch({ + disableBail: false, + }); + }); + + it('should bail when given the option', async () => { + testInjector.options.disableBail = true; + await sut.execute(); + expect(testRunnerMock.dryRun).calledWithMatch({ + disableBail: true, + }); + }); + }); + describe('when the dryRun completes', () => { let runResult: CompleteDryRunResult; diff --git a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts index 81c178dff1..359ddc2c73 100644 --- a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts +++ b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts @@ -189,6 +189,20 @@ describe(MutationTestExecutor.name, () => { expect(sandboxMock.sandboxFileFor).calledWithExactly('src/foo.js'); }); + it('should pass disableBail to test runner', async () => { + // Arrange + arrangeScenario(); + mutants.push(factory.mutantTestCoverage({ id: '1', coveredBy: ['1'] })); + testInjector.options.disableBail = true; + + // Act + await sut.execute(); + + // Assert + const expected: Partial = { disableBail: true }; + expect(testRunner.mutantRun).calledWithMatch(expected); + }); + it('should not run mutants that are uncovered by tests', async () => { // Arrange arrangeScenario(); diff --git a/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts b/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts index 6f2179da4c..f8cc629a59 100644 --- a/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts +++ b/packages/core/test/unit/reporters/mutation-test-report-helper.spec.ts @@ -527,6 +527,27 @@ describe(MutationTestReportHelper.name, () => { expect(actual).deep.include(expected); }); + it('should report a killed mutant when called with a KilledMutantRunResult with KilledBy as array', () => { + // Arrange + dryRunResult.tests.push(factory.failedTestResult({ id: '1', name: 'foo should be bar' })); + const sut = createSut(); + + // Act + const actual = sut.reportMutantRunResult( + factory.mutantTestCoverage({ fileName: 'add.js' }), + factory.killedMutantRunResult({ killedBy: ['1', '2'], nrOfTests: 42, failureMessage: 'foo should have been bar at line 1' }) + ); + + // Assert + const expected: Partial = { + status: MutantStatus.Killed, + killedBy: ['1', '2'], + testsCompleted: 42, + statusReason: 'foo should have been bar at line 1', + }; + expect(actual).deep.include(expected); + }); + it('should report a runtime error when called with an ErrorMutantRunResult', () => { // Arrange const sut = createSut(); diff --git a/packages/core/test/unit/stryker-cli.spec.ts b/packages/core/test/unit/stryker-cli.spec.ts index 1f0842b1f9..57dcba82ea 100644 --- a/packages/core/test/unit/stryker-cli.spec.ts +++ b/packages/core/test/unit/stryker-cli.spec.ts @@ -31,6 +31,7 @@ describe(StrykerCli.name, () => { [['--ignorePatterns', 'foo.js,bar.js'], { ignorePatterns: ['foo.js', 'bar.js'] }], [['--buildCommand', 'npm run build'], { buildCommand: 'npm run build' }], [['-b', 'npm run build'], { buildCommand: 'npm run build' }], + [['--disableBail'], { disableBail: true }], [['--mutate', 'foo.js,bar.js'], { mutate: ['foo.js', 'bar.js'] }], [['--reporters', 'foo,bar'], { reporters: ['foo', 'bar'] }], [['--plugins', 'foo,bar'], { plugins: ['foo', 'bar'] }], diff --git a/packages/core/test/unit/test-runner/timeout-decorator.spec.ts b/packages/core/test/unit/test-runner/timeout-decorator.spec.ts index b9942c3aa8..07e63ff1c8 100644 --- a/packages/core/test/unit/test-runner/timeout-decorator.spec.ts +++ b/packages/core/test/unit/test-runner/timeout-decorator.spec.ts @@ -56,7 +56,7 @@ describe(TimeoutDecorator.name, () => { } describe('dryRun', () => { - itShouldProxyRequests(() => sut.dryRun({ coverageAnalysis: 'all', timeout: 20 }), 'dryRun'); + itShouldProxyRequests(() => sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all', timeout: 20 })), 'dryRun'); it('should not handle timeouts premature', () => { // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/packages/cucumber-runner/.vscode/launch.json b/packages/cucumber-runner/.vscode/launch.json index 396f719904..9af5760cb9 100644 --- a/packages/cucumber-runner/.vscode/launch.json +++ b/packages/cucumber-runner/.vscode/launch.json @@ -4,27 +4,6 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "type": "node", - "request": "launch", - "name": "🥒 Unit tests", - "program": "${workspaceFolder}/../../node_modules/mocha/bin/_mocha", - "args": [ - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/dist/test/helpers/**/*.js", - "${workspaceFolder}/dist/test/unit/**/*.js" - ], - "internalConsoleOptions": "openOnSessionStart", - "outFiles": [ - "${workspaceRoot}/dist/**/*.js", - "${workspaceFolder}/../test-helpers/dist/**/*.js" - ], - "skipFiles": [ - "/**" - ] - }, { "type": "node", "request": "launch", diff --git a/packages/cucumber-runner/src/cucumber-test-runner.ts b/packages/cucumber-runner/src/cucumber-test-runner.ts index 50f5de2018..93277f3896 100644 --- a/packages/cucumber-runner/src/cucumber-test-runner.ts +++ b/packages/cucumber-runner/src/cucumber-test-runner.ts @@ -68,7 +68,7 @@ export class CucumberTestRunner implements TestRunner { public async dryRun(options: DryRunOptions): Promise { StrykerFormatter.coverageAnalysis = options.coverageAnalysis; - const result = await this.run(); + const result = await this.run(options.disableBail); if ( result.status === DryRunStatus.Complete && options.coverageAnalysis !== 'off' @@ -79,23 +79,30 @@ export class CucumberTestRunner implements TestRunner { } public async mutantRun(options: MutantRunOptions): Promise { this.instrumenterContext.activeMutant = options.activeMutant.id; - return toMutantRunResult(await this.run(options.testFilter)); + return toMutantRunResult( + await this.run(options.disableBail, options.testFilter), + true + ); } - private async run(testFilter?: string[]): Promise { + private async run( + disableBail: boolean, + testFilter?: string[] + ): Promise { const testFilterArgs = this.determineFilterArgs(testFilter); const tagsArgs = this.determineTagsArgs(); const profileArgs = this.determineProfileArgs(); + const bailArgs = disableBail ? [] : ['--fail-fast']; const argv = [ 'node', 'cucumber-js', - '--fail-fast', '--retry', '0', '--parallel', '0', '--format', require.resolve('./stryker-formatter'), + ...bailArgs, ...tagsArgs, ...profileArgs, ...testFilterArgs, diff --git a/packages/cucumber-runner/test/integration/cucumber-runner.it.spec.ts b/packages/cucumber-runner/test/integration/cucumber-runner.it.spec.ts index 4ad3f8dbe5..6a2a70d5bb 100644 --- a/packages/cucumber-runner/test/integration/cucumber-runner.it.spec.ts +++ b/packages/cucumber-runner/test/integration/cucumber-runner.it.spec.ts @@ -79,9 +79,9 @@ describe('Running in an example project', () => { testInjector.logger.isDebugEnabled.returns(true); await sut.dryRun(factory.dryRunOptions()); expect(testInjector.logger.debug).calledWith( - `${process.cwd()} "node" "cucumber-js" "--fail-fast" "--retry" "0" "--parallel" "0" "--format" "${require.resolve( + `${process.cwd()} "node" "cucumber-js" "--retry" "0" "--parallel" "0" "--format" "${require.resolve( '../../src/stryker-formatter' - )}"` + )}" "--fail-fast"` ); }); diff --git a/packages/cucumber-runner/test/integration/example-instrumented.it.spec.ts b/packages/cucumber-runner/test/integration/example-instrumented.it.spec.ts index 4d652667b7..16dd0df3b3 100644 --- a/packages/cucumber-runner/test/integration/example-instrumented.it.spec.ts +++ b/packages/cucumber-runner/test/integration/example-instrumented.it.spec.ts @@ -102,10 +102,28 @@ describe('Running in an instrumented example project', () => { ); assertions.expectKilled(actual); - expect(actual.killedBy).eq(`${simpleMathFileName}:19`); + expect(actual.killedBy).deep.eq([`${simpleMathFileName}:19`]); expect(actual.nrOfTests).eq(2); }); + it('should report all killedBy tests when disableBail is true', async () => { + const sut = createSut(); + const actual = await sut.mutantRun( + factory.mutantRunOptions({ + activeMutant: factory.mutant({ id: '2' }), + disableBail: true, + }) + ); + + assertions.expectKilled(actual); + expect(actual.killedBy).deep.eq([ + `${simpleMathFileName}:19`, + `${simpleMathFileName}:20`, + `${simpleMathFileName}:22`, + ]); + expect(actual.nrOfTests).eq(4); // all tests ran + }); + it('should be able to survive if the filtered tests are not killing', async () => { const sut = createSut(); const actual = await sut.mutantRun( @@ -135,7 +153,7 @@ describe('Running in an instrumented example project', () => { ); assertions.expectKilled(actual); - expect(actual.killedBy).eq(`${simpleMathFileName}:19`); + expect(actual.killedBy).deep.eq([`${simpleMathFileName}:19`]); expect(actual.nrOfTests).eq(1); }); diff --git a/packages/cucumber-runner/test/integration/failures.it.spec.ts b/packages/cucumber-runner/test/integration/failures.it.spec.ts index 4e10910420..a4596ca469 100644 --- a/packages/cucumber-runner/test/integration/failures.it.spec.ts +++ b/packages/cucumber-runner/test/integration/failures.it.spec.ts @@ -92,7 +92,7 @@ describe('Running cucumber when steps are failing', () => { ]); }); - it('should report an test case where multiple things went wrong as "failed"', async () => { + it('should report a test case where multiple things went wrong as "failed"', async () => { // Arrange options.cucumber.tags = ['@multiple-things-wrong']; @@ -111,7 +111,7 @@ describe('Running cucumber when steps are failing', () => { }); it('should correspond the correct failure messages to the responses', async () => { - // Run all of them, multiple failuers + // Run all of them, multiple failures const actual = await sut.dryRun(factory.dryRunOptions()); const fileName = path.join('features', 'failure-examples.feature'); assertions.expectTestResults(actual, [ @@ -138,6 +138,64 @@ describe('Running cucumber when steps are failing', () => { status: TestStatus.Failed, failureMessage: 'Multiple step definitions match:', }, + { + id: `${fileName}:32`, + name: 'Feature: Failure examples -- Scenario: Second failed step', + status: TestStatus.Skipped, + }, + ]); + }); + + it('should report only the first test (bail)', async () => { + // Arrange + options.cucumber.tags = ['@failed or @failed2']; + + // Act + const actual = await sut.dryRun( + factory.dryRunOptions({ disableBail: false }) + ); + + // Assert + const fileName = path.join('features', 'failure-examples.feature'); + assertions.expectTestResults(actual, [ + { + id: `${fileName}:4`, + status: TestStatus.Failed, + failureMessage: 'Error: Failed step', + startPosition: { line: 3, column: 3 }, + }, + { + id: `${fileName}:32`, + status: TestStatus.Skipped, + startPosition: { line: 31, column: 3 }, + }, + ]); + }); + + it('should report all failed tests when disableBail is true', async () => { + // Arrange + options.cucumber.tags = ['@failed or @failed2']; + + // Act + const actual = await sut.dryRun( + factory.dryRunOptions({ disableBail: true }) + ); + + // Assert + const fileName = path.join('features', 'failure-examples.feature'); + assertions.expectTestResults(actual, [ + { + id: `${fileName}:4`, + status: TestStatus.Failed, + failureMessage: 'Error: Failed step', + startPosition: { line: 3, column: 3 }, + }, + { + id: `${fileName}:32`, + status: TestStatus.Failed, + failureMessage: 'Error: Failed step', + startPosition: { line: 31, column: 3 }, + }, ]); }); }); diff --git a/packages/cucumber-runner/testResources/failure-example/features/failure-examples.feature b/packages/cucumber-runner/testResources/failure-example/features/failure-examples.feature index cdf6a2d94d..8bd1ae80d5 100644 --- a/packages/cucumber-runner/testResources/failure-example/features/failure-examples.feature +++ b/packages/cucumber-runner/testResources/failure-example/features/failure-examples.feature @@ -27,3 +27,8 @@ Feature: Failure examples When a failed step Then an ambiguous step Then a pending step + + @failed2 + Scenario: Second failed step + Given a success step + When a failed step diff --git a/packages/jasmine-runner/.vscode/launch.json b/packages/jasmine-runner/.vscode/launch.json index 2247d31a44..0644b1828a 100644 --- a/packages/jasmine-runner/.vscode/launch.json +++ b/packages/jasmine-runner/.vscode/launch.json @@ -7,7 +7,7 @@ { "type": "node", "request": "launch", - "name": "Unit/integration tests", + "name": "🟣 Unit/integration tests", "program": "${workspaceFolder}/../../node_modules/mocha/bin/_mocha", "args": [ "--no-timeout", diff --git a/packages/jasmine-runner/src/jasmine-test-runner.ts b/packages/jasmine-runner/src/jasmine-test-runner.ts index da29b088f1..1164e20516 100644 --- a/packages/jasmine-runner/src/jasmine-test-runner.ts +++ b/packages/jasmine-runner/src/jasmine-test-runner.ts @@ -54,23 +54,23 @@ export class JasmineTestRunner implements TestRunner { } public dryRun(options: DryRunOptions): Promise { - return this.run(undefined, options.coverageAnalysis); + return this.run(undefined, options.coverageAnalysis, options.disableBail); } public async mutantRun(options: MutantRunOptions): Promise { this.instrumenterContext.activeMutant = options.activeMutant.id; - const runResult = await this.run(options.testFilter); - return toMutantRunResult(runResult); + const runResult = await this.run(options.testFilter, undefined, options.disableBail); + return toMutantRunResult(runResult, true); } public async dispose(): Promise { this.requireCache.clear(); } - private async run(testFilter?: string[], coverageAnalysis?: CoverageAnalysis): Promise { + private async run(testFilter: string[] | undefined, coverageAnalysis: CoverageAnalysis | undefined, disableBail: boolean): Promise { this.requireCache.clear(); try { - const jasmine = this.createJasmineRunner(testFilter); + const jasmine = this.createJasmineRunner(testFilter, disableBail); const self = this; const tests: TestResult[] = []; const runTask = new Task(); @@ -117,7 +117,7 @@ export class JasmineTestRunner implements TestRunner { } } - private createJasmineRunner(testFilter: string[] | undefined) { + private createJasmineRunner(testFilter: string[] | undefined, disableBail: boolean) { let specFilter: ((spec: jasmine.Spec) => boolean) | undefined = undefined; if (testFilter) { specFilter = (spec) => testFilter.includes(spec.id.toString()); @@ -126,7 +126,7 @@ export class JasmineTestRunner implements TestRunner { // The `loadConfigFile` will fallback on the default jasmine.loadConfigFile(this.jasmineConfigFile); jasmine.env.configure({ - failFast: true, + failFast: !disableBail, oneFailurePerSpec: true, specFilter, }); diff --git a/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts b/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts index 8a84ded5be..ab6c1a5d71 100644 --- a/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts +++ b/packages/jasmine-runner/test/integration/jasmine-init-instrumented.it.spec.ts @@ -45,7 +45,7 @@ describe('JasmineRunner integration with code instrumentation', () => { it('should be able to kill a mutant', async () => { const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '1' }) })); assertions.expectKilled(result); - expect(result.killedBy).eq('spec0'); + expect(result.killedBy).deep.eq(['spec0']); expect(result.failureMessage).eq('Expected Player({ currentlyPlayingSong: Song({ }), isPlaying: false }) to be playing Song({ }).'); }); @@ -58,12 +58,23 @@ describe('JasmineRunner integration with code instrumentation', () => { await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '12' }) })); const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }) })); const expected = factory.killedMutantRunResult({ - killedBy: 'spec1', + killedBy: ['spec1'], status: MutantRunStatus.Killed, failureMessage: 'Expected true to be falsy.', nrOfTests: 2, // spec0 and spec1 }); expect(result).deep.eq(expected); }); + + it('should report all killed mutants when disableBail is true', async () => { + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '2' }), disableBail: true })); + const expected = factory.killedMutantRunResult({ + killedBy: ['spec1', 'spec2'], + status: MutantRunStatus.Killed, + failureMessage: 'Expected true to be falsy.', + nrOfTests: 5, // all + }); + expect(result).deep.eq(expected); + }); }); }); diff --git a/packages/jasmine-runner/test/integration/jasmine-runner.it.spec.ts b/packages/jasmine-runner/test/integration/jasmine-runner.it.spec.ts index 190b19acae..e25ec0067c 100644 --- a/packages/jasmine-runner/test/integration/jasmine-runner.it.spec.ts +++ b/packages/jasmine-runner/test/integration/jasmine-runner.it.spec.ts @@ -103,7 +103,7 @@ describe('JasmineRunner integration', () => { sut = testInjector.injector.injectFunction(createJasmineTestRunnerFactory('__stryker2__')); }); - it('should complete with one test failure', async () => { + it('should complete with first test failure (bail)', async () => { const result = await sut.dryRun(factory.dryRunOptions()); assertions.expectCompleted(result); expectTestResultsToEqual(result.tests, [ @@ -115,5 +115,24 @@ describe('JasmineRunner integration', () => { }, ]); }); + + it('should report all failing tests when disableBail is true', async () => { + const result = await sut.dryRun(factory.dryRunOptions({ disableBail: true })); + assertions.expectCompleted(result); + expectTestResultsToEqual(result.tests, [ + { + id: 'spec0', + status: TestStatus.Failed, + failureMessage: "Expected 'bar' to be 'baz'.", + name: 'foo should be baz', + }, + { + id: 'spec1', + status: TestStatus.Failed, + failureMessage: "Expected 'bar' to be 'qux'.", + name: 'foo should be qux', + }, + ]); + }); }); }); diff --git a/packages/jasmine-runner/test/integration/memory-leak.worker.ts b/packages/jasmine-runner/test/integration/memory-leak.worker.ts index a6708828ca..fcbeb60f55 100644 --- a/packages/jasmine-runner/test/integration/memory-leak.worker.ts +++ b/packages/jasmine-runner/test/integration/memory-leak.worker.ts @@ -1,4 +1,4 @@ -import { testInjector } from '@stryker-mutator/test-helpers'; +import { factory, testInjector } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import { DryRunStatus, TestStatus } from '@stryker-mutator/api/test-runner'; @@ -30,7 +30,7 @@ async function main() { async function doDryRun(n = 40) { if (n > 0) { console.log(`Iterator count ${n}`); - const result = await jasmineRunner.dryRun({ coverageAnalysis: 'off', timeout: 3000 }); + const result = await jasmineRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off', timeout: 3000 })); if (result.status === DryRunStatus.Complete) { expect(result.tests).lengthOf(1); expect(result.tests[0].status).eq(TestStatus.Success); diff --git a/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts b/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts index 13e1437e2d..d290f70b6e 100644 --- a/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts +++ b/packages/jasmine-runner/test/unit/jasmine-test-runner.spec.ts @@ -82,7 +82,7 @@ describe(JasmineTestRunner.name, () => { } jasmineEnvStub.addReporter.callsFake(addReporter); jasmineStub.execute.callsFake(async () => customReporter.jasmineDone!(createRunDetails())); - return sut.mutantRun({ activeMutant, testFilter, timeout: 2000, sandboxFileName }); + return sut.mutantRun(factory.mutantRunOptions({ activeMutant, testFilter, timeout: 2000, sandboxFileName })); } }); diff --git a/packages/jasmine-runner/testResources/test-failures/spec/fooSpec.js b/packages/jasmine-runner/testResources/test-failures/spec/fooSpec.js index 32ae3d620b..aa2664c55f 100644 --- a/packages/jasmine-runner/testResources/test-failures/spec/fooSpec.js +++ b/packages/jasmine-runner/testResources/test-failures/spec/fooSpec.js @@ -4,4 +4,7 @@ describe('foo', () => { it('should be baz', () => { expect(foo).toBe('baz'); // not true, actually 'bar' }); -}); \ No newline at end of file + it('should be qux', () => { + expect(foo).toBe('qux'); // not true, actually 'bar' + }); +}); diff --git a/packages/jest-runner/schema/jest-runner-options.json b/packages/jest-runner/schema/jest-runner-options.json index e45ffb3b04..c2e791cf8c 100644 --- a/packages/jest-runner/schema/jest-runner-options.json +++ b/packages/jest-runner/schema/jest-runner-options.json @@ -26,11 +26,6 @@ "description": "Whether to run jest with the `--findRelatedTests` flag. When `true`, Jest will only run tests related to the mutated file per test. (See [_--findRelatedTests_](https://jestjs.io/docs/en/cli.html#findrelatedtests-spaceseparatedlistofsourcefiles)", "type": "boolean", "default": true - }, - "enableBail": { - "description": "Whether to run jest with the `--bail` flag. When `true`, Jest stop testing after the first failing test, which boosts performance. (See [_--bail_](https://jestjs.io/docs/en/cli#--bail)", - "type": "boolean", - "default": true } }, "additionalProperties": false diff --git a/packages/jest-runner/src/jest-override-options.ts b/packages/jest-runner/src/jest-override-options.ts index 9df8f040c7..2aec45ea46 100644 --- a/packages/jest-runner/src/jest-override-options.ts +++ b/packages/jest-runner/src/jest-override-options.ts @@ -15,6 +15,10 @@ export const JEST_OVERRIDE_OPTIONS: Readonly = Object.fre // the results each time Stryker runs the tests notify: false, + // Bail isn't supported programmatically in jest + // see https://github.com/facebook/jest/issues/11766 + bail: false, + /** * Disable reporters, they only way us down. */ diff --git a/packages/jest-runner/src/jest-test-runner.ts b/packages/jest-runner/src/jest-test-runner.ts index d2223bd3ca..7d532a4b18 100644 --- a/packages/jest-runner/src/jest-test-runner.ts +++ b/packages/jest-runner/src/jest-test-runner.ts @@ -1,6 +1,3 @@ -// monkey patch exit first!! -import './utils/monkey-patch-exit'; - import path from 'path'; import { StrykerOptions, INSTRUMENTER_CONSTANTS, MutantCoverage } from '@stryker-mutator/api/core'; @@ -94,7 +91,7 @@ export class JestTestRunner implements TestRunner { } } - public async dryRun({ coverageAnalysis }: Pick): Promise { + public async dryRun({ coverageAnalysis, disableBail }: Pick): Promise { state.coverageAnalysis = coverageAnalysis; const mutantCoverage: MutantCoverage = { perTest: {}, static: {} }; const fileNamesWithMutantCoverage: string[] = []; @@ -106,7 +103,7 @@ export class JestTestRunner implements TestRunner { } try { const { dryRunResult, jestResult } = await this.run({ - jestConfig: withCoverageAnalysis(this.jestConfig, coverageAnalysis), + jestConfig: withCoverageAnalysis({ ...this.jestConfig }, coverageAnalysis), testLocationInResults: true, }); if (dryRunResult.status === DryRunStatus.Complete && coverageAnalysis !== 'off') { @@ -126,7 +123,7 @@ export class JestTestRunner implements TestRunner { } } - public async mutantRun({ activeMutant, sandboxFileName, testFilter }: MutantRunOptions): Promise { + public async mutantRun({ activeMutant, sandboxFileName, testFilter, disableBail }: MutantRunOptions): Promise { const fileNameUnderTest = this.enableFindRelatedTests ? sandboxFileName : undefined; state.coverageAnalysis = 'off'; let testNamePattern: string | undefined; @@ -134,27 +131,32 @@ export class JestTestRunner implements TestRunner { testNamePattern = testFilter.map((testId) => `(${escapeRegExp(testId)})`).join('|'); } process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE] = activeMutant.id.toString(); + try { const { dryRunResult } = await this.run({ fileNameUnderTest, jestConfig: this.configForMutantRun(fileNameUnderTest), testNamePattern, }); - return toMutantRunResult(dryRunResult); + return toMutantRunResult(dryRunResult, disableBail); } finally { delete process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]; } } private configForMutantRun(fileNameUnderTest: string | undefined): jest.Config.InitialOptions { + let config: jest.Config.InitialOptions; + if (fileNameUnderTest && this.jestConfig.roots) { // Make sure the file under test lives inside one of the roots - return { + config = { ...this.jestConfig, roots: [...this.jestConfig.roots, path.dirname(fileNameUnderTest)], }; + } else { + config = this.jestConfig; } - return this.jestConfig; + return config; } private async run(settings: RunSettings): Promise<{ dryRunResult: DryRunResult; jestResult: jestTestResult.AggregatedResult }> { @@ -258,10 +260,9 @@ export class JestTestRunner implements TestRunner { private mergeConfigSettings(configFromFile: jest.Config.InitialOptions, options: JestOptions): jest.Config.InitialOptions { const config = (options.config ?? {}) as jest.Config.InitialOptions; - config.bail = options.enableBail; const stringify = (obj: unknown) => JSON.stringify(obj, null, 2); this.log.debug( - `Merging file-based config ${stringify(configFromFile)} + `Merging file-based config ${stringify(configFromFile)} with custom config ${stringify(config)} and default (internal) stryker config ${stringify(JEST_OVERRIDE_OPTIONS)}` ); diff --git a/packages/jest-runner/src/utils/monkey-patch-exit.ts b/packages/jest-runner/src/utils/monkey-patch-exit.ts deleted file mode 100644 index cbae326521..0000000000 --- a/packages/jest-runner/src/utils/monkey-patch-exit.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Jest uses a module called "exit" to exit when using `--bail` mode. - * It works by monkey-patching the `write` function from stdout and stderr, making the process completely silent, before calling `process.exit` directly. - * Stryker doesn't play nice with these side effects. In order to fix that, we use this very very very dirty hack to monkey-patch the monkey-patch. - * - * It overrides the implementation of `require('exit')` with an empty function. For this to work, it needs to be required before `jest` itself is required. - * Did I mention this hack is dirty? - * - * @see https://github.com/cowboy/node-exit - */ - -try { - const exitModuleId = require.resolve('exit', { paths: [require.resolve('jest', { paths: [process.cwd()] })] }); - // eslint-disable-next-line @typescript-eslint/no-require-imports - require(exitModuleId); - const exitModule = module.children.find((mdl) => mdl.id === exitModuleId); - // eslint-disable-next-line @typescript-eslint/no-empty-function - exitModule!.exports = () => {}; -} catch (error) { - console.log('Unable to monkey-patch exit module', error); -} diff --git a/packages/jest-runner/test/helpers/producers.ts b/packages/jest-runner/test/helpers/producers.ts index e1d7c9b9f4..9e655ebe53 100644 --- a/packages/jest-runner/test/helpers/producers.ts +++ b/packages/jest-runner/test/helpers/producers.ts @@ -13,7 +13,6 @@ export const createJestRunnerOptionsWithStrykerOptions = (overrides?: Partial): JestOptions => { return { - enableBail: true, enableFindRelatedTests: true, projectType: 'custom', ...overrides, diff --git a/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts b/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts index cf62a3b57c..a651f3a848 100644 --- a/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts +++ b/packages/jest-runner/test/integration/coverage-analysis.it.spec.ts @@ -41,23 +41,39 @@ describe('JestTestRunner coverage analysis integration', () => { describe('dryRun', () => { it('should not provide coverage analysis if coverageAnalysis is "off"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); assertions.expectCompleted(result); expect(result.mutantCoverage).undefined; }); it('should provide static coverage when coverageAnalysis is "all"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'all' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); assertions.expectCompleted(result); expect(result.mutantCoverage).not.undefined; expect(result.mutantCoverage!.perTest).deep.eq({}); - for (let i = 0; i < 17; i++) { - expect(result.mutantCoverage!.static[i]).eq(1); - } + expect(result.mutantCoverage!.static).deep.eq({ + '0': 2, + '1': 2, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + '6': 1, + '7': 1, + '8': 1, + '9': 1, + '10': 1, + '11': 1, + '12': 1, + '13': 1, + '14': 1, + '15': 1, + '16': 1, + }); }); it('should provide perTest coverage when coverageAnalysis is "perTest"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'perTest' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); assertions.expectCompleted(result); expect(result.mutantCoverage).not.undefined; expect(result.mutantCoverage!.static).deep.eq({}); @@ -66,6 +82,10 @@ describe('JestTestRunner coverage analysis integration', () => { 4: 1, 5: 1, }, + 'Add should be able to subtract using a negative number': { + '0': 1, + '1': 1, + }, 'Add should be able to add one to a number': { 2: 1, 3: 1, @@ -135,13 +155,13 @@ describe('JestTestRunner coverage analysis integration', () => { describe('dryRun', () => { it('should not provide coverage analysis if coverageAnalysis is "off"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); assertions.expectCompleted(result); expect(result.mutantCoverage).undefined; }); it('should provide static coverage when coverageAnalysis is "all"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'all' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); assertions.expectCompleted(result); expect(result.mutantCoverage).not.undefined; expect(result.mutantCoverage!.perTest).deep.eq({}); @@ -175,7 +195,7 @@ describe('JestTestRunner coverage analysis integration', () => { }); it('should provide perTest coverage when coverageAnalysis is "perTest"', async () => { - const result = await sut.dryRun({ coverageAnalysis: 'perTest' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); assertions.expectCompleted(result); expect(result.mutantCoverage).not.undefined; expect(result.mutantCoverage!.static).deep.eq({ 22: 1, 30: 1 }); diff --git a/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts b/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts index 4f74b0816f..2e9433bd3a 100644 --- a/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts +++ b/packages/jest-runner/test/integration/jest-test-runner.it.spec.ts @@ -29,6 +29,7 @@ describe(`${JestTestRunner.name} integration test`, () => { const options: JestRunnerOptionsWithStrykerOptions = factory.strykerWithPluginOptions({ jest: createJestOptions(overrides), }); + return testInjector.injector.provideValue(commonTokens.options, options).injectFunction(jestTestRunnerFactory); } @@ -41,18 +42,20 @@ describe(`${JestTestRunner.name} integration test`, () => { process.chdir(resolveTestResource('jasmine2-node')); const jestTestRunner = createSut(); - const runResult = await jestTestRunner.dryRun({ coverageAnalysis: 'off' }); + const runResult = await jestTestRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); assertions.expectCompleted(runResult); - expect(runResult.tests[0].name).to.equal('Add should be able to add two numbers'); - expect(runResult.tests[0].timeSpentMs).to.be.above(-1); + const result = runResult.tests.find((test) => test.id === 'Add should be able to add two numbers'); + expect(result).to.not.be.null; + expect(result!.name).to.equal('Add should be able to add two numbers'); + expect(result!.timeSpentMs).to.be.above(-1); }); it('should run tests on the example custom project using package.json', async () => { process.chdir(resolveTestResource('jasmine2-node')); const jestTestRunner = createSut(); - const runResult = await jestTestRunner.dryRun({ coverageAnalysis: 'off' }); + const runResult = await jestTestRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); assertions.expectCompleted(runResult); expectToHaveSuccessfulTests(runResult, testNames.length); @@ -63,7 +66,7 @@ describe(`${JestTestRunner.name} integration test`, () => { const jestTestRunner = createSut(); - const runResult = await jestTestRunner.dryRun({ coverageAnalysis: 'off' }); + const runResult = await jestTestRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); assertions.expectCompleted(runResult); expectToHaveSuccessfulTests(runResult, testNames.length); @@ -74,7 +77,7 @@ describe(`${JestTestRunner.name} integration test`, () => { const addSpecFileName = resolveTestResource('exampleProjectWithExplicitJestConfig', 'src', '__tests__', 'AddSpec.js'); const circleSpecFileName = resolveTestResource('exampleProjectWithExplicitJestConfig', 'src', '__tests__', 'CircleSpec.js'); const jestTestRunner = createSut(); - const runResult = await jestTestRunner.dryRun({ coverageAnalysis: 'perTest' }); + const runResult = await jestTestRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); assertions.expectCompleted(runResult); expectTestResults(runResult, [ { @@ -157,5 +160,42 @@ describe(`${JestTestRunner.name} integration test`, () => { assertions.expectKilled(firstResult); assertions.expectSurvived(secondResult); }); + + it('should only report the first failing test in `killedBy` when disableBail = false', async () => { + // Arrange + const exampleProjectRoot = resolveTestResource('jasmine2-node-instrumented'); + process.chdir(exampleProjectRoot); + const jestTestRunner = createSut(); + const mutantRunOptions = factory.mutantRunOptions({ + sandboxFileName: require.resolve(path.resolve(exampleProjectRoot, 'src', 'Add.js')), + activeMutant: factory.mutant({ id: '0' }), + }); + + // Act + const result = await jestTestRunner.mutantRun(mutantRunOptions); + + // Assert + assertions.expectKilled(result); + expect(result.killedBy).eq('Add should be able to add two numbers'); + }); + + it('should be able to collect all tests that kill a mutant when disableBail = true', async () => { + // Arrange + const exampleProjectRoot = resolveTestResource('jasmine2-node-instrumented'); + process.chdir(exampleProjectRoot); + const jestTestRunner = createSut(); + const mutantRunOptions = factory.mutantRunOptions({ + sandboxFileName: require.resolve(path.resolve(exampleProjectRoot, 'src', 'Add.js')), + activeMutant: factory.mutant({ id: '0' }), + disableBail: true, + }); + + // Act + const result = await jestTestRunner.mutantRun(mutantRunOptions); + + // Assert + assertions.expectKilled(result); + expect(result.killedBy).to.have.length(2); + }); }); }); diff --git a/packages/jest-runner/test/unit/jest-test-runner.spec.ts b/packages/jest-runner/test/unit/jest-test-runner.spec.ts index 4bfe99347f..bb057731d9 100644 --- a/packages/jest-runner/test/unit/jest-test-runner.spec.ts +++ b/packages/jest-runner/test/unit/jest-test-runner.spec.ts @@ -38,7 +38,6 @@ describe(JestTestRunner.name, () => { options.jest = { enableFindRelatedTests: true, projectType: 'custom', - enableBail: true, }; options.basePath = basePath; @@ -67,14 +66,14 @@ describe(JestTestRunner.name, () => { describe('dryRun', () => { it('should call the run function with the provided config and the projectRoot', async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(jestTestAdapterMock.run).called; }); it('should set reporters to an empty array', async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(jestTestAdapterMock.run).calledWithMatch( sinon.match({ jestConfig: sinon.match({ @@ -84,22 +83,19 @@ describe(JestTestRunner.name, () => { ); }); - it('should set bail = true', async () => { + it('should always set bail = false (see https://github.com/facebook/jest/issues/11766)', async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off', disableBail: true })); expect(jestTestAdapterMock.run).calledWithMatch( sinon.match({ - jestConfig: sinon.match({ - bail: true, - }), + jestConfig: sinon.match({ bail: false }), }) ); }); - it('should set bail = false when enableBail is false', async () => { - options.jest.enableBail = false; + it('should set bail = false when disableBail', async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun({ coverageAnalysis: 'off', disableBail: true }); expect(jestTestAdapterMock.run).calledWithMatch( sinon.match({ jestConfig: sinon.match({ @@ -112,7 +108,7 @@ describe(JestTestRunner.name, () => { it('should trace log a message when jest is invoked', async () => { const sut = createSut(); testInjector.logger.isTraceEnabled.returns(true); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(testInjector.logger.trace).calledWithMatch(/Invoking Jest with config\s.*/, sinon.match(/.*"jestConfig".*/)); }); @@ -120,7 +116,7 @@ describe(JestTestRunner.name, () => { const sut = createSut(); jestTestAdapterMock.run.resolves(producers.createJestRunResult({ results: producers.createSuccessResult() })); - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); const expectedRunResult: CompleteDryRunResult = { status: DryRunStatus.Complete, @@ -142,7 +138,7 @@ describe(JestTestRunner.name, () => { const sut = createSut(); jestTestAdapterMock.run.resolves(producers.createJestRunResult({ results: producers.createPendingResult() })); - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); const expectedRunResult: CompleteDryRunResult = { status: DryRunStatus.Complete, @@ -165,7 +161,7 @@ describe(JestTestRunner.name, () => { const sut = createSut(); jestTestAdapterMock.run.resolves(producers.createJestRunResult({ results: producers.createTodoResult() })); - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); const expectedRunResult: CompleteDryRunResult = { status: DryRunStatus.Complete, tests: [ @@ -194,7 +190,7 @@ describe(JestTestRunner.name, () => { const sut = createSut(); jestTestAdapterMock.run.resolves(producers.createJestRunResult({ results: producers.createFailResult() })); - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); const expectedRunResult: CompleteDryRunResult = { status: DryRunStatus.Complete, @@ -248,7 +244,7 @@ describe(JestTestRunner.name, () => { }); jestTestAdapterMock.run.resolves(producers.createJestRunResult({ results: jestResult })); - const result = await sut.dryRun({ coverageAnalysis: 'off' }); + const result = await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); const expectedRunResult: ErrorDryRunResult = { status: DryRunStatus.Error, @@ -260,7 +256,7 @@ describe(JestTestRunner.name, () => { it("should set process.env.NODE_ENV to 'test' when process.env.NODE_ENV is null", async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(processEnvMock.NODE_ENV).to.equal('test'); }); @@ -269,7 +265,7 @@ describe(JestTestRunner.name, () => { const sut = createSut(); processEnvMock.NODE_ENV = 'stryker'; - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(processEnvMock.NODE_ENV).to.equal('stryker'); }); @@ -277,17 +273,17 @@ describe(JestTestRunner.name, () => { it('should load "react-scripts/config/env.js" when projectType = create-react-app', async () => { options.jest.projectType = 'create-react-app'; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(requireResolveStub).calledWith('react-scripts/config/env.js'); }); it('should override verbose, collectCoverage, testResultsProcessor, notify and bail on all loaded configs', async () => { const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'off' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ - bail: true, + bail: false, collectCoverage: false, notify: false, testResultsProcessor: undefined, @@ -304,7 +300,7 @@ describe(JestTestRunner.name, () => { jestTestAdapterMock.run.returns(runTask.promise); // Act - const onGoingDryRun = sut.dryRun({ coverageAnalysis: 'all' }); + const onGoingDryRun = sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); state.handleMutantCoverage('foo.js', { static: { 0: 2 }, perTest: { 'foo should be bar': { 3: 1 } } }); state.handleMutantCoverage('bar.js', { static: { 0: 3, 1: 2 }, perTest: { 'foo should be bar': { 7: 1 }, 'baz should be qux': { 6: 1 } } }); runTask.resolve({ @@ -333,7 +329,7 @@ describe(JestTestRunner.name, () => { it('should remove the coverage handler afterwards', async () => { const sut = createSut(); const resetSpy = sinon.spy(state, 'resetMutantCoverageHandler'); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(resetSpy).called; }); @@ -341,7 +337,7 @@ describe(JestTestRunner.name, () => { const testEnvironment = 'my-test-environment'; options.jest.config = { testEnvironment }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'all' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ testEnvironment: require.resolve('../../src/jest-plugins/jest-environment-generic') }), }); @@ -351,7 +347,7 @@ describe(JestTestRunner.name, () => { it('should set the set the jestEnvironment to "jest-environment-jsdom" in the messaging state when the jest environment is "jsdom"', async () => { options.jest.config = { testEnvironment: 'jsdom' }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'all' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); expect(state.jestEnvironment).eq('jest-environment-jsdom'); }); @@ -359,7 +355,7 @@ describe(JestTestRunner.name, () => { it('should set the set the jestEnvironment to "jest-environment-node" in the messaging state when the jest environment is "node"', async () => { options.jest.config = { testEnvironment: 'node' }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'all' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); expect(state.jestEnvironment).eq('jest-environment-node'); }); @@ -367,7 +363,7 @@ describe(JestTestRunner.name, () => { it('should add a set setupFile if testRunner = "jest-jasmine2"', async () => { options.jest.config = { testRunner: 'jest-jasmine2' }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: [require.resolve('../../src/jest-plugins/jasmine2-setup-coverage-analysis')] }), }); @@ -378,7 +374,7 @@ describe(JestTestRunner.name, () => { getVersionStub.returns('26.999.999'); options.jest.config = { testRunner: undefined }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: [require.resolve('../../src/jest-plugins/jasmine2-setup-coverage-analysis')] }), }); @@ -389,7 +385,7 @@ describe(JestTestRunner.name, () => { getVersionStub.returns('27.0.0'); options.jest.config = { testRunner: undefined }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: undefined }), }); @@ -398,7 +394,7 @@ describe(JestTestRunner.name, () => { it('should not allow the circus test runner for coverage analysis "perTest"', async () => { options.jest.config = { testRunner: 'jest-circus/runner' }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: undefined }), }); @@ -407,7 +403,7 @@ describe(JestTestRunner.name, () => { it('should not allow a full path to circus test runner for coverage analysis "perTest"', async () => { options.jest.config = { testRunner: require.resolve('jest-circus/runner') }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: undefined }), }); @@ -416,7 +412,7 @@ describe(JestTestRunner.name, () => { it('should not remove existing setup files if testRunner = "jest-jasmine2"', async () => { options.jest.config = { testRunner: 'jest-jasmine2', setupFilesAfterEnv: ['setup/env.js', 'setup/unit.js'] }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: [require.resolve('../../src/jest-plugins/jasmine2-setup-coverage-analysis'), 'setup/env.js', 'setup/unit.js'], @@ -427,7 +423,7 @@ describe(JestTestRunner.name, () => { it('should not add a setupFile if coverageAnalysis = "all"', async () => { options.jest.config = { testRunner: 'jest-jasmine2' }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'all' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'all' })); const { jestConfig } = jestTestAdapterMock.run.getCall(0).args[0]; expect(jestConfig).has.not.property('setupFilesAfterEnv'); }); @@ -435,7 +431,7 @@ describe(JestTestRunner.name, () => { it('should not add a set setupFile if testRunner = "jest-circus/runner"', async () => { options.jest.config = { testRunner: 'jest-circus/runner', setupFilesAfterEnv: ['setup.js'] }; const sut = createSut(); - await sut.dryRun({ coverageAnalysis: 'perTest' }); + await sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); expect(jestTestAdapterMock.run).calledWithMatch({ jestConfig: sinon.match({ setupFilesAfterEnv: ['setup.js'] }), }); @@ -444,7 +440,7 @@ describe(JestTestRunner.name, () => { it('should reject if coverageAnalysis = perTest and test runner is not recognized', async () => { options.jest.config = { testRunner: 'foo/runner' }; const sut = createSut(); - const onGoingRun = sut.dryRun({ coverageAnalysis: 'perTest' }); + const onGoingRun = sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); await expect(onGoingRun).rejectedWith( 'The @stryker-mutator/jest-runner doesn\'t support coverageAnalysis "perTest" with "jestConfig.testRunner": "foo/runner". Please open an issue if you want support for this: https://github.com/stryker-mutator/stryker-js/issues' ); @@ -457,7 +453,7 @@ describe(JestTestRunner.name, () => { jestTestAdapterMock.run.returns(runTask.promise); // Act - const onGoingRun = sut.dryRun({ coverageAnalysis: 'perTest' }); + const onGoingRun = sut.dryRun(factory.dryRunOptions({ coverageAnalysis: 'perTest' })); state.handleMutantCoverage(path.resolve('foo.js'), { perTest: {}, static: {} }); // mutant coverage for bar.js is missing runTask.resolve( @@ -560,6 +556,18 @@ describe(JestTestRunner.name, () => { }) ); }); + + it('should set bail if disableBail is passed', async () => { + const sut = createSut(); + await sut.mutantRun(factory.mutantRunOptions({ disableBail: true })); + expect(jestTestAdapterMock.run).calledWithMatch( + sinon.match({ + jestConfig: sinon.match({ + bail: false, + }), + }) + ); + }); }); function createSut() { diff --git a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/__tests__/AddSpec.js b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/__tests__/AddSpec.js index 0d65de9d43..e0572863df 100644 --- a/packages/jest-runner/testResources/jasmine2-node-instrumented/src/__tests__/AddSpec.js +++ b/packages/jest-runner/testResources/jasmine2-node-instrumented/src/__tests__/AddSpec.js @@ -13,6 +13,16 @@ describe('Add', function() { expect(actual).toBe(expected); }); + + it('should be able to subtract using a negative number', function() { + var num1 = 5; + var num2 = -2; + var expected = num1 + num2; + + var actual = add(num1, num2); + + expect(actual).toBe(expected); + }); it('should be able to add one to a number', function() { var number = 2; diff --git a/packages/karma-runner/src/karma-test-runner.ts b/packages/karma-runner/src/karma-test-runner.ts index 5d0033451c..d279f24a87 100644 --- a/packages/karma-runner/src/karma-test-runner.ts +++ b/packages/karma-runner/src/karma-test-runner.ts @@ -22,7 +22,12 @@ export class KarmaTestRunner implements TestRunner { constructor(private readonly log: Logger, getLogger: LoggerFactoryMethod, options: StrykerOptions) { const setup = this.loadSetup(options); this.starter = new ProjectStarter(getLogger, setup); - this.setGlobals(setup, getLogger); + strykerKarmaConf.setGlobals({ + getLogger, + karmaConfig: setup.config, + karmaConfigFile: setup.configFile, + disableBail: options.disableBail, + }); } public async init(): Promise { @@ -47,15 +52,14 @@ export class KarmaTestRunner implements TestRunner { public async dryRun(options: DryRunOptions): Promise { TestHooksMiddleware.instance.configureCoverageAnalysis(options.coverageAnalysis); - const res = await this.run(); - return res; + return await this.run(); } public async mutantRun(options: MutantRunOptions): Promise { TestHooksMiddleware.instance.configureMutantRun(options); StrykerReporter.instance.configureHitLimit(options.hitLimit); const dryRunResult = await this.run(); - return toMutantRunResult(dryRunResult); + return toMutantRunResult(dryRunResult, true); } private run(): Promise { @@ -80,14 +84,6 @@ export class KarmaTestRunner implements TestRunner { return Object.assign(defaultKarmaConfig, (options as KarmaRunnerOptionsWithStrykerOptions).karma); } - private setGlobals(setup: StrykerKarmaSetup, getLogger: LoggerFactoryMethod) { - strykerKarmaConf.setGlobals({ - getLogger, - karmaConfig: setup.config, - karmaConfigFile: setup.configFile, - }); - } - private runServer(): void { karma.runner.run(this.runConfig, (exitCode) => { this.log.debug('karma run done with ', exitCode); diff --git a/packages/karma-runner/src/starters/stryker-karma.conf.ts b/packages/karma-runner/src/starters/stryker-karma.conf.ts index 0d3c4a10b2..51cd127148 100644 --- a/packages/karma-runner/src/starters/stryker-karma.conf.ts +++ b/packages/karma-runner/src/starters/stryker-karma.conf.ts @@ -71,12 +71,12 @@ function setClientOptions(config: Config) { if (config.frameworks?.includes('jasmine')) { (clientOptions as any).jasmine = { random: false, - failFast: true, + failFast: !globalSettings.disableBail, }; } if (config.frameworks?.includes('mocha')) { - (clientOptions as any).mocha = { bail: true }; + (clientOptions as any).mocha = { bail: !globalSettings.disableBail }; } config.set({ client: clientOptions }); } @@ -140,14 +140,18 @@ function configureStrykerReporter(config: Config) { config.reporters.push(StrykerReporter.name); } -const globalSettings: { +interface GlobalSettings { karmaConfig?: ConfigOptions; karmaConfigFile?: string; getLogger: LoggerFactoryMethod; -} = { + disableBail: boolean; +} + +const globalSettings: GlobalSettings = { getLogger() { return noopLogger; }, + disableBail: false, }; function configureKarma(config: Config): void { @@ -168,10 +172,11 @@ function configureKarma(config: Config): void { * This is the only way we can pass through any values between the `KarmaTestRunner` and the stryker-karma.conf file. * (not counting environment variables) */ -configureKarma.setGlobals = (globals: { karmaConfig?: ConfigOptions; karmaConfigFile?: string; getLogger?: LoggerFactoryMethod }) => { +configureKarma.setGlobals = (globals: Partial) => { globalSettings.karmaConfig = globals.karmaConfig; globalSettings.karmaConfigFile = globals.karmaConfigFile; globalSettings.getLogger = globals.getLogger ?? (() => noopLogger); + globalSettings.disableBail = globals.disableBail ?? false; }; export = configureKarma; diff --git a/packages/karma-runner/test/integration/instrumented.it.spec.ts b/packages/karma-runner/test/integration/instrumented.it.spec.ts index 8a2da8dc74..cc9d72ba4e 100644 --- a/packages/karma-runner/test/integration/instrumented.it.spec.ts +++ b/packages/karma-runner/test/integration/instrumented.it.spec.ts @@ -109,7 +109,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { it('should be able to kill a mutant', async () => { const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectKilled(result); - expect(result.killedBy).eq('spec0'); + expect(result.killedBy).deep.eq(['spec0']); expect(result.failureMessage.split('\n')[0]).eq('Error: Expected undefined to be 7.'); }); @@ -133,7 +133,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { assertions.expectKilled(result); result.failureMessage = result.failureMessage.split('\n')[0]; const expected = factory.killedMutantRunResult({ - killedBy: 'spec1', + killedBy: ['spec1'], status: MutantRunStatus.Killed, failureMessage: 'Error: Expected undefined to be 3.', nrOfTests: 1, @@ -237,7 +237,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { it('should be able to kill a mutant', async () => { const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '0' }) })); assertions.expectKilled(result); - expect(result.killedBy).eq('Add should be able to add two numbers'); + expect(result.killedBy).deep.eq(['Add should be able to add two numbers']); expect(result.failureMessage.split('\n')[0]).eq('AssertionError: expected undefined to equal 7'); }); @@ -270,7 +270,7 @@ describe(`${KarmaTestRunner.name} running on instrumented code`, () => { assertions.expectKilled(result); result.failureMessage = result.failureMessage.split('\n')[0]; const expected: KilledMutantRunResult = { - killedBy: 'Add should be able 1 to a number', + killedBy: ['Add should be able 1 to a number'], status: MutantRunStatus.Killed, failureMessage: 'AssertionError: expected undefined to equal 3', nrOfTests: 1, diff --git a/packages/karma-runner/test/integration/karma-test-runner.it.spec.ts b/packages/karma-runner/test/integration/karma-test-runner.it.spec.ts index 8bdff86465..10a696a68d 100644 --- a/packages/karma-runner/test/integration/karma-test-runner.it.spec.ts +++ b/packages/karma-runner/test/integration/karma-test-runner.it.spec.ts @@ -1,7 +1,7 @@ import { promisify } from 'util'; import http from 'http'; -import { DryRunStatus, TestStatus, CompleteDryRunResult, TestResult, FailedTestResult } from '@stryker-mutator/api/test-runner'; +import { TestStatus, CompleteDryRunResult, TestResult, FailedTestResult } from '@stryker-mutator/api/test-runner'; import { testInjector, assertions, factory } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import { FilePattern } from 'karma'; @@ -80,7 +80,7 @@ describe(`${KarmaTestRunner.name} integration`, () => { }); describe('when some tests fail', () => { - before(() => { + beforeEach(() => { setOptions({ files: [ 'testResources/sampleProject/src/Add.js', @@ -88,26 +88,68 @@ describe(`${KarmaTestRunner.name} integration`, () => { 'testResources/sampleProject/test-jasmine/AddFailedSpec.js', ], }); - sut = createSut(); - return sut.init(); }); - after(async () => { + afterEach(async () => { await sut.dispose(); }); describe('dryRun', () => { it('should report the first failed test (bail)', async () => { + // Arrange + sut = createSut(); + await sut.init(); + + // Act const runResult = await sut.dryRun(factory.dryRunOptions()); + + // Assert assertions.expectCompleted(runResult); expectToHaveSuccessfulTests(runResult, 5); expectToHaveFailedTests(runResult, ['Error: Expected 7 to be 8.']); - expect(runResult.status).to.be.eq(DryRunStatus.Complete); + }); + + it('should report all failing tests when disableBail is true', async () => { + // Arrange + testInjector.options.disableBail = true; + sut = createSut(); + await sut.init(); + + // Act + const runResult = await sut.dryRun(factory.dryRunOptions()); + + // Assert + assertions.expectCompleted(runResult); + expectToHaveSuccessfulTests(runResult, 5); + expectToHaveFailedTests(runResult, ['Error: Expected 7 to be 8.', 'Error: Expected 3 to be 4.']); }); }); + describe('runMutant()', () => { it('should report the mutant as killed', async () => { + // Arrange + sut = createSut(); + await sut.init(); + + // Act + const mutantResult = await sut.mutantRun(factory.mutantRunOptions()); + + // Assert + assertions.expectKilled(mutantResult); + expect(mutantResult.killedBy).deep.eq(['spec5']); + expect(mutantResult.failureMessage.split('\n')[0]).eq('Error: Expected 7 to be 8.'); + }); + + it('should report all failed tests when disableBail is true', async () => { + // Arrange + testInjector.options.disableBail = true; + sut = createSut(); + await sut.init(); + + // Act const mutantResult = await sut.mutantRun(factory.mutantRunOptions()); + + // Assert assertions.expectKilled(mutantResult); - expect(mutantResult.killedBy).eq('spec5'); + expect(mutantResult.killedBy).deep.eq(['spec5', 'spec6']); expect(mutantResult.failureMessage.split('\n')[0]).eq('Error: Expected 7 to be 8.'); }); }); diff --git a/packages/karma-runner/test/unit/karma-test-runner.spec.ts b/packages/karma-runner/test/unit/karma-test-runner.spec.ts index a4d756f9cb..9b87bf58f9 100644 --- a/packages/karma-runner/test/unit/karma-test-runner.spec.ts +++ b/packages/karma-runner/test/unit/karma-test-runner.spec.ts @@ -24,7 +24,7 @@ import { karma } from '../../src/karma-wrapper'; describe(KarmaTestRunner.name, () => { let projectStarterMock: sinon.SinonStubbedInstance; - let setGlobalsStub: sinon.SinonStub; + let setGlobalsStub: sinon.SinonStubbedMember; let karmaRunStub: sinon.SinonStubbedMember; let getLogger: LoggerFactoryMethod; let testHooksMiddlewareMock: sinon.SinonStubbedInstance; @@ -49,6 +49,7 @@ describe(KarmaTestRunner.name, () => { getLogger, karmaConfig: undefined, karmaConfigFile: undefined, + disableBail: false, }); }); @@ -61,11 +62,13 @@ describe(KarmaTestRunner.name, () => { projectType: 'angular-cli', }; testInjector.options.karma = expectedSetup; + testInjector.options.disableBail = true; createSut(); expect(setGlobalsStub).calledWith({ getLogger, karmaConfig: expectedSetup.config, karmaConfigFile: expectedSetup.configFile, + disableBail: true, }); expect(testInjector.logger.warn).not.called; @@ -86,11 +89,13 @@ describe(KarmaTestRunner.name, () => { projectType: 'angular-cli', }; testInjector.options.karma = expectedSetup; + testInjector.options.disableBail = true; createSut(); expect(setGlobalsStub).calledWith({ getLogger, karmaConfig: expectedSetup.config, karmaConfigFile: expectedSetup.configFile, + disableBail: true, }); expect(testInjector.logger.warn).not.called; expect(projectStarter.ProjectStarter).calledWith(sinon.match.func, expectedSetup); diff --git a/packages/karma-runner/test/unit/starters/stryker-karma.conf.spec.ts b/packages/karma-runner/test/unit/starters/stryker-karma.conf.spec.ts index 8fad412124..00c147c942 100644 --- a/packages/karma-runner/test/unit/starters/stryker-karma.conf.spec.ts +++ b/packages/karma-runner/test/unit/starters/stryker-karma.conf.spec.ts @@ -189,7 +189,7 @@ describe('stryker-karma.conf.js', () => { }); it('should set basePath to location of karma.conf.js', () => { - sut.setGlobals({ karmaConfigFile: '../foobar.conf.js' }); + sut.setGlobals({ karmaConfigFile: '../foobar.conf.js', disableBail: false }); requireModuleStub.returns(() => { /* noop */ }); diff --git a/packages/mocha-runner/.vscode/launch.json b/packages/mocha-runner/.vscode/launch.json index 78937dc2ee..64da58d37f 100644 --- a/packages/mocha-runner/.vscode/launch.json +++ b/packages/mocha-runner/.vscode/launch.json @@ -7,7 +7,7 @@ { "type": "node", "request": "launch", - "name": "Unit tests", + "name": "☕ Unit tests", "program": "${workspaceFolder}/../../node_modules/mocha/bin/_mocha", "args": [ "--timeout", @@ -27,7 +27,7 @@ { "type": "node", "request": "launch", - "name": "Integration tests", + "name": "☕ Integration tests", "program": "${workspaceFolder}/../../node_modules/mocha/bin/_mocha", "args": [ "--timeout", diff --git a/packages/mocha-runner/src/mocha-test-runner.ts b/packages/mocha-runner/src/mocha-test-runner.ts index 87811f326d..c9b6b7515d 100644 --- a/packages/mocha-runner/src/mocha-test-runner.ts +++ b/packages/mocha-runner/src/mocha-test-runner.ts @@ -60,10 +60,10 @@ export class MochaTestRunner implements TestRunner { } } - public async dryRun(options: DryRunOptions): Promise { + public async dryRun({ coverageAnalysis, disableBail }: DryRunOptions): Promise { // eslint-disable-next-line @typescript-eslint/no-empty-function let interceptor: (mocha: Mocha) => void = () => {}; - if (options.coverageAnalysis === 'perTest') { + if (coverageAnalysis === 'perTest') { interceptor = (mocha) => { const self = this; mocha.suite.beforeEach('StrykerIntercept', function () { @@ -71,14 +71,14 @@ export class MochaTestRunner implements TestRunner { }); }; } - const runResult = await this.run(interceptor); - if (runResult.status === DryRunStatus.Complete && options.coverageAnalysis !== 'off') { + const runResult = await this.run(interceptor, disableBail); + if (runResult.status === DryRunStatus.Complete && coverageAnalysis !== 'off') { runResult.mutantCoverage = this.instrumenterContext.mutantCoverage; } return runResult; } - public async mutantRun({ activeMutant, testFilter }: MutantRunOptions): Promise { + public async mutantRun({ activeMutant, testFilter, disableBail }: MutantRunOptions): Promise { this.instrumenterContext.activeMutant = activeMutant.id; // eslint-disable-next-line @typescript-eslint/no-empty-function let intercept: (mocha: Mocha) => void = () => {}; @@ -89,15 +89,15 @@ export class MochaTestRunner implements TestRunner { mocha.grep(regex); }; } - const dryRunResult = await this.run(intercept); - return toMutantRunResult(dryRunResult); + const dryRunResult = await this.run(intercept, disableBail); + return toMutantRunResult(dryRunResult, true); } - public async run(intercept: (mocha: Mocha) => void): Promise { + public async run(intercept: (mocha: Mocha) => void, disableBail: boolean): Promise { this.requireCache.clear(); const mocha = this.mochaAdapter.create({ reporter: StrykerMochaReporter as any, - bail: true, + bail: !disableBail, timeout: false as any, // Mocha 5 doesn't support `0` rootHooks: this.rootHooks, } as Mocha.MochaOptions); diff --git a/packages/mocha-runner/test/integration/memory-leak.worker.ts b/packages/mocha-runner/test/integration/memory-leak.worker.ts index acbc383229..42633dec2e 100644 --- a/packages/mocha-runner/test/integration/memory-leak.worker.ts +++ b/packages/mocha-runner/test/integration/memory-leak.worker.ts @@ -1,4 +1,4 @@ -import { testInjector } from '@stryker-mutator/test-helpers'; +import { factory, testInjector } from '@stryker-mutator/test-helpers'; import { expect } from 'chai'; import { DryRunStatus, TestStatus } from '@stryker-mutator/api/test-runner'; @@ -34,7 +34,7 @@ async function main() { async function doDryRun(n = 40) { if (n > 0) { console.log(`Iterator count ${n}`); - const result = await mochaRunner.dryRun({ coverageAnalysis: 'off', timeout: 3000 }); + const result = await mochaRunner.dryRun(factory.dryRunOptions({ coverageAnalysis: 'off', timeout: 3000 })); if (result.status === DryRunStatus.Complete) { expect(result.tests).lengthOf(1); expect(result.tests[0].status).eq(TestStatus.Success); diff --git a/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts b/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts index 228c5934bd..7f3d28f3e3 100644 --- a/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts +++ b/packages/mocha-runner/test/integration/sample-project-instrumented.it.spec.ts @@ -111,14 +111,25 @@ describe('Running an instrumented project', () => { it('should be able to kill a mutant', async () => { const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }) })); assertions.expectKilled(result); - expect(result.killedBy).eq('MyMath should be able to add two numbers'); + expect(result.killedBy).deep.eq(['MyMath should be able to add two numbers']); expect(result.failureMessage).eq('expected -3 to equal 7'); }); it('should bail after the first failed test', async () => { - const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }) })); + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '8' }) })); + assertions.expectKilled(result); + expect(result.killedBy).deep.eq(['MyMath should be able to recognize a negative number']); + expect(result.nrOfTests).eq(4); // 5th test shouldn't have run + }); + + it('should report all killedBy tests when bail is disabled', async () => { + const result = await sut.mutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '8' }), disableBail: true })); assertions.expectKilled(result); - expect(result.nrOfTests).eq(1); + expect(result.killedBy).deep.eq([ + 'MyMath should be able to recognize a negative number', + 'MyMath should be able to recognize that 0 is not a negative number', + ]); + expect(result.nrOfTests).eq(5); }); it('should be able to kill a mutant with filtered test', async () => { @@ -126,7 +137,7 @@ describe('Running an instrumented project', () => { factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '3' }), testFilter: ['MyMath should be able to add two numbers'] }) ); assertions.expectKilled(result); - expect(result.killedBy).eq('MyMath should be able to add two numbers'); + expect(result.killedBy).deep.eq(['MyMath should be able to add two numbers']); expect(result.failureMessage).eq('expected -3 to equal 7'); }); diff --git a/packages/mocha-runner/test/integration/sample-project.it.spec.ts b/packages/mocha-runner/test/integration/sample-project.it.spec.ts index 315ac09bf6..e88dcb2b85 100644 --- a/packages/mocha-runner/test/integration/sample-project.it.spec.ts +++ b/packages/mocha-runner/test/integration/sample-project.it.spec.ts @@ -67,11 +67,17 @@ describe('Running a sample project', () => { return sut.init(); }); - it('should only report the first failure', async () => { + it('should only report the first failure (bail)', async () => { const runResult = await sut.dryRun(factory.dryRunOptions()); assertions.expectCompleted(runResult); expect(countFailed(runResult)).to.be.eq(1); }); + + it('should report all failures with disableBail = true', async () => { + const runResult = await sut.dryRun(factory.dryRunOptions({ disableBail: true })); + assertions.expectCompleted(runResult); + expect(countFailed(runResult)).to.be.eq(2); + }); }); describe('when no tests are executed', () => { diff --git a/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts b/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts index 778bf73bdb..3b442de300 100644 --- a/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts +++ b/packages/mocha-runner/test/unit/mocha-test-runner.spec.ts @@ -135,11 +135,16 @@ describe(MochaTestRunner.name, () => { expect(mochaAdapterMock.create).calledWithMatch({ timeout: false }); }); - it('should force bail', async () => { - await actDryRun(); + it('should set bail to true when disableBail is false', async () => { + await actDryRun(factory.dryRunOptions({ disableBail: false })); expect(mochaAdapterMock.create).calledWithMatch({ bail: true }); }); + it('should set bail to false when disableBail is true', async () => { + await actDryRun(factory.dryRunOptions({ disableBail: true })); + expect(mochaAdapterMock.create).calledWithMatch({ bail: false }); + }); + it("should don't set asyncOnly if asyncOnly is false", async () => { sut.mochaOptions['async-only'] = false; await actDryRun(); @@ -247,11 +252,21 @@ describe(MochaTestRunner.name, () => { StrykerMochaReporter.currentInstance = reporterMock; }); - it('should active the given mutant', async () => { + it('should activate the given mutant', async () => { await actMutantRun(factory.mutantRunOptions({ activeMutant: factory.mutant({ id: '42' }) })); expect(global.__stryker2__?.activeMutant).eq('42'); }); + it('should set bail to false when disableBail is true', async () => { + await actMutantRun(factory.mutantRunOptions({ disableBail: true })); + expect(mochaAdapterMock.create).calledWithMatch({ bail: false }); + }); + + it('should set bail to true when disableBail is false', async () => { + await actMutantRun(factory.mutantRunOptions({ disableBail: false })); + expect(mochaAdapterMock.create).calledWithMatch({ bail: true }); + }); + it('should use `grep` to when the test filter is specified', async () => { await actMutantRun(factory.mutantRunOptions({ testFilter: ['foo should be bar', 'baz should be qux'] })); expect(mocha.grep).calledWith(new RegExp('(foo should be bar)|(baz should be qux)')); @@ -267,7 +282,7 @@ describe(MochaTestRunner.name, () => { const result = await actMutantRun(); const expectedResult: KilledMutantRunResult = { failureMessage: 'foo was baz', - killedBy: 'foo should be bar', + killedBy: ['foo should be bar'], status: MutantRunStatus.Killed, nrOfTests: 2, }; diff --git a/packages/test-helpers/src/factory.ts b/packages/test-helpers/src/factory.ts index 325c531cf3..addb3e377a 100644 --- a/packages/test-helpers/src/factory.ts +++ b/packages/test-helpers/src/factory.ts @@ -254,11 +254,13 @@ export const mutantRunOptions = factoryMethod(() => ({ activeMutant: mutant(), timeout: 2000, sandboxFileName: '.stryker-tmp/sandbox123/file', + disableBail: false, })); export const dryRunOptions = factoryMethod(() => ({ coverageAnalysis: 'off', timeout: 2000, + disableBail: false, })); export const completeDryRunResult = factoryMethod(() => ({ @@ -282,7 +284,7 @@ export const timeoutDryRunResult = factoryMethod(() => ({ export const killedMutantRunResult = factoryMethod(() => ({ status: MutantRunStatus.Killed, - killedBy: 'spec1', + killedBy: ['spec1'], failureMessage: 'foo should be bar', nrOfTests: 1, })); diff --git a/tasks/instrument-test-resources.js b/tasks/instrument-test-resources.js index 6e0c833f0f..8785c07a54 100644 --- a/tasks/instrument-test-resources.js +++ b/tasks/instrument-test-resources.js @@ -34,9 +34,9 @@ async function main() { } /** - * - * @param {object} fromTo - * @param {'__stryker__' | '__stryker2__'} globalNamespace + * + * @param {object} fromTo + * @param {'__stryker__' | '__stryker2__'} globalNamespace */ async function instrument(fromTo, globalNamespace = INSTRUMENTER_CONSTANTS.NAMESPACE) { const files = Object.keys(fromTo).map(fileName => new File(fileName, fs.readFileSync(fileName))); @@ -44,7 +44,7 @@ async function instrument(fromTo, globalNamespace = INSTRUMENTER_CONSTANTS.NAMES out.files.forEach(file => { const toFileName = fromTo[file.name]; fs.writeFileSync(toFileName, `// This file is generated with ${path.relative(process.cwd(), __filename)}\n ${file.textContent.replace(new RegExp(INSTRUMENTER_CONSTANTS.NAMESPACE, 'g'), globalNamespace)}`); - + console.log(`✅ ${toFileName}`); }); }