chore: roll expect and move it to third party (#32458)

This commit is contained in:
Pavel Feldman 2024-09-09 13:12:20 -07:00 committed by GitHub
parent 4b5422a3c7
commit 9a313eecc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 17407 additions and 487 deletions

161
package-lock.json generated
View File

@ -26,6 +26,7 @@
"@types/babel__core": "^7.20.2",
"@types/codemirror": "^5.60.7",
"@types/formidable": "^2.0.4",
"@types/immutable": "^3.8.7",
"@types/node": "^18.19.39",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
@ -37,6 +38,7 @@
"@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.2.1",
"@zip.js/zip.js": "^2.7.29",
"ansi-styles": "^4.3.0",
"chokidar": "^3.5.3",
"chromium-bidi": "^0.6.4",
"colors": "^1.4.0",
@ -51,6 +53,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"formidable": "^2.1.1",
"immutable": "^4.3.7",
"license-checker": "^25.0.1",
"mime": "^3.0.0",
"node-stream-zip": "^1.15.0",
@ -1832,6 +1835,16 @@
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
"dev": true
},
"node_modules/@types/immutable": {
"version": "3.8.7",
"resolved": "https://registry.npmjs.org/@types/immutable/-/immutable-3.8.7.tgz",
"integrity": "sha512-nsHFDX48Tl3RaP4BF47HHe5njx40Pcp+0a8CIqzJata80Fp7JzkcuGB7UhZBGjH9aA1fMEahIqvPQQNmro5YLg==",
"deprecated": "This is a stub types definition for Facebook's Immutable (https://github.com/facebook/immutable-js). Facebook's Immutable provides its own type definitions, so you don't need @types/immutable installed!",
"dev": true,
"dependencies": {
"immutable": "*"
}
},
"node_modules/@types/keyv": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
@ -2359,16 +2372,38 @@
}
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=4"
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/ansi-styles/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/ansi-styles/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/ansi-to-html": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz",
@ -2802,6 +2837,17 @@
"node": ">=4"
}
},
"node_modules/chalk/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -2942,21 +2988,6 @@
"node": ">=10.0.0"
}
},
"node_modules/concurrently/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/concurrently/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -2985,24 +3016,6 @@
"node": ">=8"
}
},
"node_modules/concurrently/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/concurrently/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/concurrently/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -3779,21 +3792,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -3820,24 +3818,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/eslint/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/eslint/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/eslint/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -4635,6 +4615,12 @@
"node": ">= 4"
}
},
"node_modules/immutable": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
"dev": true
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -7772,39 +7758,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/wrap-ansi/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@ -65,6 +65,7 @@
"@types/babel__core": "^7.20.2",
"@types/codemirror": "^5.60.7",
"@types/formidable": "^2.0.4",
"@types/immutable": "^3.8.7",
"@types/node": "^18.19.39",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
@ -76,6 +77,7 @@
"@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.2.1",
"@zip.js/zip.js": "^2.7.29",
"ansi-styles": "^4.3.0",
"chokidar": "^3.5.3",
"chromium-bidi": "^0.6.4",
"colors": "^1.4.0",
@ -90,6 +92,7 @@
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"formidable": "^2.1.1",
"immutable": "^4.3.7",
"license-checker": "^25.0.1",
"mime": "^3.0.0",
"node-stream-zip": "^1.15.0",

View File

@ -5,8 +5,8 @@ THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise.
- @ampproject/remapping@2.2.1 (https://github.com/ampproject/remapping)
- @babel/code-frame@7.22.5 (https://github.com/babel/babel)
- @babel/code-frame@7.24.2 (https://github.com/babel/babel)
- @babel/code-frame@7.24.7 (https://github.com/babel/babel)
- @babel/compat-data@7.23.5 (https://github.com/babel/babel)
- @babel/core@7.24.4 (https://github.com/babel/babel)
- @babel/generator@7.24.4 (https://github.com/babel/babel)
@ -27,11 +27,11 @@ This project incorporates components from the projects listed below. The origina
- @babel/helper-split-export-declaration@7.22.6 (https://github.com/babel/babel)
- @babel/helper-string-parser@7.23.4 (https://github.com/babel/babel)
- @babel/helper-validator-identifier@7.22.20 (https://github.com/babel/babel)
- @babel/helper-validator-identifier@7.22.5 (https://github.com/babel/babel)
- @babel/helper-validator-identifier@7.24.7 (https://github.com/babel/babel)
- @babel/helper-validator-option@7.23.5 (https://github.com/babel/babel)
- @babel/helpers@7.24.4 (https://github.com/babel/babel)
- @babel/highlight@7.22.5 (https://github.com/babel/babel)
- @babel/highlight@7.24.2 (https://github.com/babel/babel)
- @babel/highlight@7.24.7 (https://github.com/babel/babel)
- @babel/parser@7.24.4 (https://github.com/babel/babel)
- @babel/plugin-proposal-decorators@7.24.1 (https://github.com/babel/babel)
- @babel/plugin-proposal-explicit-resource-management@7.24.1 (https://github.com/babel/babel)
@ -67,22 +67,22 @@ This project incorporates components from the projects listed below. The origina
- @babel/template@7.24.0 (https://github.com/babel/babel)
- @babel/traverse@7.24.1 (https://github.com/babel/babel)
- @babel/types@7.24.0 (https://github.com/babel/babel)
- @jest/expect-utils@29.5.0 (https://github.com/facebook/jest)
- @jest/schemas@29.4.3 (https://github.com/facebook/jest)
- @jest/types@29.5.0 (https://github.com/facebook/jest)
- @jest/expect-utils@29.7.0 (https://github.com/jestjs/jest)
- @jest/schemas@29.6.3 (https://github.com/jestjs/jest)
- @jest/types@29.6.3 (https://github.com/jestjs/jest)
- @jridgewell/gen-mapping@0.3.5 (https://github.com/jridgewell/gen-mapping)
- @jridgewell/resolve-uri@3.1.1 (https://github.com/jridgewell/resolve-uri)
- @jridgewell/set-array@1.2.1 (https://github.com/jridgewell/set-array)
- @jridgewell/sourcemap-codec@1.4.15 (https://github.com/jridgewell/sourcemap-codec)
- @jridgewell/trace-mapping@0.3.25 (https://github.com/jridgewell/trace-mapping)
- @sinclair/typebox@0.25.24 (https://github.com/sinclairzx81/typebox)
- @types/istanbul-lib-coverage@2.0.4 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/istanbul-lib-report@3.0.0 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/istanbul-reports@3.0.1 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/node@20.2.5 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/stack-utils@2.0.1 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/yargs-parser@21.0.0 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/yargs@17.0.24 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @sinclair/typebox@0.27.8 (https://github.com/sinclairzx81/typebox)
- @types/istanbul-lib-coverage@2.0.6 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/istanbul-lib-report@3.0.3 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/istanbul-reports@3.0.4 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/node@22.5.4 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/stack-utils@2.0.3 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/yargs-parser@21.0.3 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- @types/yargs@17.0.33 (https://github.com/DefinitelyTyped/DefinitelyTyped)
- ansi-colors@4.1.3 (https://github.com/doowb/ansi-colors)
- ansi-styles@3.2.1 (https://github.com/chalk/ansi-styles)
- ansi-styles@4.3.0 (https://github.com/chalk/ansi-styles)
@ -96,7 +96,7 @@ This project incorporates components from the projects listed below. The origina
- chalk@2.4.2 (https://github.com/chalk/chalk)
- chalk@4.1.2 (https://github.com/chalk/chalk)
- chokidar@3.6.0 (https://github.com/paulmillr/chokidar)
- ci-info@3.8.0 (https://github.com/watson/ci-info)
- ci-info@3.9.0 (https://github.com/watson/ci-info)
- codemirror-shadow-1@0.0.1 (https://github.com/codemirror/CodeMirror)
- color-convert@1.9.3 (https://github.com/Qix-/color-convert)
- color-convert@2.0.1 (https://github.com/Qix-/color-convert)
@ -104,13 +104,12 @@ This project incorporates components from the projects listed below. The origina
- color-name@1.1.4 (https://github.com/colorjs/color-name)
- convert-source-map@2.0.0 (https://github.com/thlorenz/convert-source-map)
- debug@4.3.4 (https://github.com/debug-js/debug)
- diff-sequences@29.4.3 (https://github.com/facebook/jest)
- diff-sequences@29.6.3 (https://github.com/jestjs/jest)
- electron-to-chromium@1.4.638 (https://github.com/kilian/electron-to-chromium)
- enquirer@2.3.6 (https://github.com/enquirer/enquirer)
- escalade@3.1.1 (https://github.com/lukeed/escalade)
- escape-string-regexp@1.0.5 (https://github.com/sindresorhus/escape-string-regexp)
- escape-string-regexp@2.0.0 (https://github.com/sindresorhus/escape-string-regexp)
- expect@29.5.0 (https://github.com/facebook/jest)
- fill-range@7.1.1 (https://github.com/jonschlinkert/fill-range)
- gensync@1.0.0-beta.2 (https://github.com/loganfsmyth/gensync)
- glob-parent@5.1.2 (https://github.com/gulpjs/glob-parent)
@ -122,11 +121,12 @@ This project incorporates components from the projects listed below. The origina
- is-extglob@2.1.1 (https://github.com/jonschlinkert/is-extglob)
- is-glob@4.0.3 (https://github.com/micromatch/is-glob)
- is-number@7.0.0 (https://github.com/jonschlinkert/is-number)
- jest-diff@29.5.0 (https://github.com/facebook/jest)
- jest-get-type@29.4.3 (https://github.com/facebook/jest)
- jest-matcher-utils@29.5.0 (https://github.com/facebook/jest)
- jest-message-util@29.5.0 (https://github.com/facebook/jest)
- jest-util@29.5.0 (https://github.com/facebook/jest)
- jest-diff@29.7.0 (https://github.com/jestjs/jest)
- jest-get-type@29.6.3 (https://github.com/jestjs/jest)
- jest-matcher-utils@29.7.0 (https://github.com/jestjs/jest)
- jest-message-util@29.7.0 (https://github.com/jestjs/jest)
- jest-mock@29.7.0 (https://github.com/jestjs/jest)
- jest-util@29.7.0 (https://github.com/jestjs/jest)
- js-tokens@4.0.0 (https://github.com/lydell/js-tokens)
- jsesc@2.5.2 (https://github.com/mathiasbynens/jsesc)
- json5@2.2.3 (https://github.com/json5/json5)
@ -136,10 +136,11 @@ This project incorporates components from the projects listed below. The origina
- node-releases@2.0.14 (https://github.com/chicoxyzzy/node-releases)
- normalize-path@3.0.0 (https://github.com/jonschlinkert/normalize-path)
- picocolors@1.0.0 (https://github.com/alexeyraspopov/picocolors)
- picocolors@1.1.0 (https://github.com/alexeyraspopov/picocolors)
- picomatch@2.3.1 (https://github.com/micromatch/picomatch)
- pirates@4.0.4 (https://github.com/danez/pirates)
- pretty-format@29.5.0 (https://github.com/facebook/jest)
- react-is@18.2.0 (https://github.com/facebook/react)
- pretty-format@29.7.0 (https://github.com/jestjs/jest)
- react-is@18.3.1 (https://github.com/facebook/react)
- readdirp@3.6.0 (https://github.com/paulmillr/readdirp)
- semver@6.3.1 (https://github.com/npm/node-semver)
- slash@3.0.0 (https://github.com/sindresorhus/slash)
@ -151,6 +152,7 @@ This project incorporates components from the projects listed below. The origina
- supports-color@7.2.0 (https://github.com/chalk/supports-color)
- to-fast-properties@2.0.0 (https://github.com/sindresorhus/to-fast-properties)
- to-regex-range@5.0.1 (https://github.com/micromatch/to-regex-range)
- undici-types@6.19.8 (https://github.com/nodejs/undici)
- update-browserslist-db@1.0.13 (https://github.com/browserslist/update-db)
- yallist@3.1.1 (https://github.com/isaacs/yallist)
@ -360,33 +362,6 @@ Apache License
=========================================
END OF @ampproject/remapping@2.2.1 AND INFORMATION
%% @babel/code-frame@7.22.5 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/code-frame@7.22.5 AND INFORMATION
%% @babel/code-frame@7.24.2 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -414,6 +389,33 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/code-frame@7.24.2 AND INFORMATION
%% @babel/code-frame@7.24.7 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/code-frame@7.24.7 AND INFORMATION
%% @babel/compat-data@7.23.5 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -954,7 +956,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/helper-validator-identifier@7.22.20 AND INFORMATION
%% @babel/helper-validator-identifier@7.22.5 NOTICES AND INFORMATION BEGIN HERE
%% @babel/helper-validator-identifier@7.24.7 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -979,7 +981,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/helper-validator-identifier@7.22.5 AND INFORMATION
END OF @babel/helper-validator-identifier@7.24.7 AND INFORMATION
%% @babel/helper-validator-option@7.23.5 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -1035,33 +1037,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/helpers@7.24.4 AND INFORMATION
%% @babel/highlight@7.22.5 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/highlight@7.22.5 AND INFORMATION
%% @babel/highlight@7.24.2 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -1089,6 +1064,33 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/highlight@7.24.2 AND INFORMATION
%% @babel/highlight@7.24.7 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/highlight@7.24.7 AND INFORMATION
%% @babel/parser@7.24.4 NOTICES AND INFORMATION BEGIN HERE
=========================================
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
@ -2031,7 +2033,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF @babel/types@7.24.0 AND INFORMATION
%% @jest/expect-utils@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% @jest/expect-utils@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2055,9 +2057,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF @jest/expect-utils@29.5.0 AND INFORMATION
END OF @jest/expect-utils@29.7.0 AND INFORMATION
%% @jest/schemas@29.4.3 NOTICES AND INFORMATION BEGIN HERE
%% @jest/schemas@29.6.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2081,9 +2083,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF @jest/schemas@29.4.3 AND INFORMATION
END OF @jest/schemas@29.6.3 AND INFORMATION
%% @jest/types@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% @jest/types@29.6.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2107,7 +2109,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF @jest/types@29.5.0 AND INFORMATION
END OF @jest/types@29.6.3 AND INFORMATION
%% @jridgewell/gen-mapping@0.3.5 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -2231,7 +2233,7 @@ SOFTWARE.
=========================================
END OF @jridgewell/trace-mapping@0.3.25 AND INFORMATION
%% @sinclair/typebox@0.25.24 NOTICES AND INFORMATION BEGIN HERE
%% @sinclair/typebox@0.27.8 NOTICES AND INFORMATION BEGIN HERE
=========================================
TypeBox: JSON Schema Type Builder with Static Type Resolution for TypeScript
@ -2257,9 +2259,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
=========================================
END OF @sinclair/typebox@0.25.24 AND INFORMATION
END OF @sinclair/typebox@0.27.8 AND INFORMATION
%% @types/istanbul-lib-coverage@2.0.4 NOTICES AND INFORMATION BEGIN HERE
%% @types/istanbul-lib-coverage@2.0.6 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2283,35 +2285,9 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/istanbul-lib-coverage@2.0.4 AND INFORMATION
END OF @types/istanbul-lib-coverage@2.0.6 AND INFORMATION
%% @types/istanbul-lib-report@3.0.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/istanbul-lib-report@3.0.0 AND INFORMATION
%% @types/istanbul-reports@3.0.1 NOTICES AND INFORMATION BEGIN HERE
%% @types/istanbul-lib-report@3.0.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2335,9 +2311,9 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/istanbul-reports@3.0.1 AND INFORMATION
END OF @types/istanbul-lib-report@3.0.3 AND INFORMATION
%% @types/node@20.2.5 NOTICES AND INFORMATION BEGIN HERE
%% @types/istanbul-reports@3.0.4 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2361,9 +2337,9 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/node@20.2.5 AND INFORMATION
END OF @types/istanbul-reports@3.0.4 AND INFORMATION
%% @types/stack-utils@2.0.1 NOTICES AND INFORMATION BEGIN HERE
%% @types/node@22.5.4 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2387,9 +2363,9 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/stack-utils@2.0.1 AND INFORMATION
END OF @types/node@22.5.4 AND INFORMATION
%% @types/yargs-parser@21.0.0 NOTICES AND INFORMATION BEGIN HERE
%% @types/stack-utils@2.0.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2413,9 +2389,9 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/yargs-parser@21.0.0 AND INFORMATION
END OF @types/stack-utils@2.0.3 AND INFORMATION
%% @types/yargs@17.0.24 NOTICES AND INFORMATION BEGIN HERE
%% @types/yargs-parser@21.0.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -2439,7 +2415,33 @@ MIT License
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/yargs@17.0.24 AND INFORMATION
END OF @types/yargs-parser@21.0.3 AND INFORMATION
%% @types/yargs@17.0.33 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
=========================================
END OF @types/yargs@17.0.33 AND INFORMATION
%% ansi-colors@4.1.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -3074,11 +3076,11 @@ THE SOFTWARE.
=========================================
END OF chokidar@3.6.0 AND INFORMATION
%% ci-info@3.8.0 NOTICES AND INFORMATION BEGIN HERE
%% ci-info@3.9.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)
Copyright (c) 2016-2023 Thomas Watson Steen
Copyright (c) 2016 Thomas Watson Steen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -3098,7 +3100,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF ci-info@3.8.0 AND INFORMATION
END OF ci-info@3.9.0 AND INFORMATION
%% codemirror-shadow-1@0.0.1 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -3254,7 +3256,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF debug@4.3.4 AND INFORMATION
%% diff-sequences@29.4.3 NOTICES AND INFORMATION BEGIN HERE
%% diff-sequences@29.6.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3278,7 +3280,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF diff-sequences@29.4.3 AND INFORMATION
END OF diff-sequences@29.6.3 AND INFORMATION
%% electron-to-chromium@1.4.638 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -3370,32 +3372,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
=========================================
END OF escape-string-regexp@2.0.0 AND INFORMATION
%% expect@29.5.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF expect@29.5.0 AND INFORMATION
%% fill-range@7.1.1 NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)
@ -3608,7 +3584,7 @@ THE SOFTWARE.
=========================================
END OF is-number@7.0.0 AND INFORMATION
%% jest-diff@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% jest-diff@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3632,9 +3608,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-diff@29.5.0 AND INFORMATION
END OF jest-diff@29.7.0 AND INFORMATION
%% jest-get-type@29.4.3 NOTICES AND INFORMATION BEGIN HERE
%% jest-get-type@29.6.3 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3658,9 +3634,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-get-type@29.4.3 AND INFORMATION
END OF jest-get-type@29.6.3 AND INFORMATION
%% jest-matcher-utils@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% jest-matcher-utils@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3684,9 +3660,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-matcher-utils@29.5.0 AND INFORMATION
END OF jest-matcher-utils@29.7.0 AND INFORMATION
%% jest-message-util@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% jest-message-util@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3710,9 +3686,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-message-util@29.5.0 AND INFORMATION
END OF jest-message-util@29.7.0 AND INFORMATION
%% jest-util@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% jest-mock@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -3736,7 +3712,33 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-util@29.5.0 AND INFORMATION
END OF jest-mock@29.7.0 AND INFORMATION
%% jest-util@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF jest-util@29.7.0 AND INFORMATION
%% js-tokens@4.0.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -3961,6 +3963,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
=========================================
END OF picocolors@1.0.0 AND INFORMATION
%% picocolors@1.1.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
ISC License
Copyright (c) 2021-2024 Oleksii Raspopov, Kostiantyn Denysov, Anton Verinov
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
=========================================
END OF picocolors@1.1.0 AND INFORMATION
%% picomatch@2.3.1 NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)
@ -4013,7 +4035,7 @@ SOFTWARE.
=========================================
END OF pirates@4.0.4 AND INFORMATION
%% pretty-format@29.5.0 NOTICES AND INFORMATION BEGIN HERE
%% pretty-format@29.7.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -4037,9 +4059,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF pretty-format@29.5.0 AND INFORMATION
END OF pretty-format@29.7.0 AND INFORMATION
%% react-is@18.2.0 NOTICES AND INFORMATION BEGIN HERE
%% react-is@18.3.1 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
@ -4063,7 +4085,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF react-is@18.2.0 AND INFORMATION
END OF react-is@18.3.1 AND INFORMATION
%% readdirp@3.6.0 NOTICES AND INFORMATION BEGIN HERE
=========================================
@ -4304,6 +4326,32 @@ THE SOFTWARE.
=========================================
END OF to-regex-range@5.0.1 AND INFORMATION
%% undici-types@6.19.8 NOTICES AND INFORMATION BEGIN HERE
=========================================
MIT License
Copyright (c) Matteo Collina and Undici contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF undici-types@6.19.8 AND INFORMATION
%% update-browserslist-db@1.0.13 NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)
@ -4351,6 +4399,6 @@ END OF yallist@3.1.1 AND INFORMATION
SUMMARY BEGIN HERE
=========================================
Total Packages: 149
Total Packages: 151
=========================================
END OF SUMMARY

View File

@ -8,37 +8,43 @@
"name": "expect-bundle",
"version": "0.0.1",
"dependencies": {
"expect": "29.5.0",
"jest-matcher-utils": "29.5.0"
"@jest/expect-utils": "29.7.0",
"jest-get-type": "29.6.3",
"jest-matcher-utils": "29.7.0",
"jest-message-util": "29.7.0",
"jest-mock": "29.7.0",
"jest-util": "29.7.0"
}
},
"node_modules/@babel/code-frame": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"dependencies": {
"@babel/highlight": "^7.22.5"
"@babel/highlight": "^7.24.7",
"picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.5",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
"@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
@ -109,33 +115,33 @@
}
},
"node_modules/@jest/expect-utils": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz",
"integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
"integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
"dependencies": {
"jest-get-type": "^29.4.3"
"jest-get-type": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/schemas": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz",
"integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
"dependencies": {
"@sinclair/typebox": "^0.25.16"
"@sinclair/typebox": "^0.27.8"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/types": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
"integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"dependencies": {
"@jest/schemas": "^29.4.3",
"@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@ -147,53 +153,56 @@
}
},
"node_modules/@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
"integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ=="
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
"integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g=="
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="
},
"node_modules/@types/istanbul-lib-report": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
"integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
"integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
"dependencies": {
"@types/istanbul-lib-coverage": "*"
}
},
"node_modules/@types/istanbul-reports": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
"integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
"integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
"dependencies": {
"@types/istanbul-lib-report": "*"
}
},
"node_modules/@types/node": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
"version": "22.5.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/@types/stack-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
},
"node_modules/@types/yargs": {
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
"integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
"dependencies": {
"@types/yargs-parser": "*"
}
},
"node_modules/@types/yargs-parser": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
"version": "21.0.3",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="
},
"node_modules/ansi-styles": {
"version": "4.3.0",
@ -236,9 +245,9 @@
}
},
"node_modules/ci-info": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
"integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
"funding": [
{
"type": "github",
@ -266,9 +275,9 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/diff-sequences": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
"integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
@ -281,21 +290,6 @@
"node": ">=8"
}
},
"node_modules/expect": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz",
"integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==",
"dependencies": {
"@jest/expect-utils": "^29.5.0",
"jest-get-type": "^29.4.3",
"jest-matcher-utils": "^29.5.0",
"jest-message-util": "^29.5.0",
"jest-util": "^29.5.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -329,53 +323,53 @@
}
},
"node_modules/jest-diff": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
"integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
"integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
"dependencies": {
"chalk": "^4.0.0",
"diff-sequences": "^29.4.3",
"jest-get-type": "^29.4.3",
"pretty-format": "^29.5.0"
"diff-sequences": "^29.6.3",
"jest-get-type": "^29.6.3",
"pretty-format": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-get-type": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
"integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
"integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-matcher-utils": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz",
"integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
"integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
"dependencies": {
"chalk": "^4.0.0",
"jest-diff": "^29.5.0",
"jest-get-type": "^29.4.3",
"pretty-format": "^29.5.0"
"jest-diff": "^29.7.0",
"jest-get-type": "^29.6.3",
"pretty-format": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-message-util": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz",
"integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
"integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
"dependencies": {
"@babel/code-frame": "^7.12.13",
"@jest/types": "^29.5.0",
"@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
"pretty-format": "^29.5.0",
"pretty-format": "^29.7.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
@ -383,12 +377,25 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-util": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz",
"integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==",
"node_modules/jest-mock": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
"integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
"dependencies": {
"@jest/types": "^29.5.0",
"@jest/types": "^29.6.3",
"@types/node": "*",
"jest-util": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-util": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
"integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
"dependencies": {
"@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
@ -416,6 +423,11 @@
"node": ">=8.6"
}
},
"node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@ -428,11 +440,11 @@
}
},
"node_modules/pretty-format": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz",
"integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"dependencies": {
"@jest/schemas": "^29.4.3",
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
"react-is": "^18.0.0"
},
@ -452,9 +464,9 @@
}
},
"node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"node_modules/slash": {
"version": "3.0.0",
@ -496,30 +508,37 @@
"engines": {
"node": ">=8.0"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
}
},
"dependencies": {
"@babel/code-frame": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"requires": {
"@babel/highlight": "^7.22.5"
"@babel/highlight": "^7.24.7",
"picocolors": "^1.0.0"
}
},
"@babel/helper-validator-identifier": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w=="
},
"@babel/highlight": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"requires": {
"@babel/helper-validator-identifier": "^7.22.5",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
"@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
},
"dependencies": {
"ansi-styles": {
@ -574,27 +593,27 @@
}
},
"@jest/expect-utils": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz",
"integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
"integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
"requires": {
"jest-get-type": "^29.4.3"
"jest-get-type": "^29.6.3"
}
},
"@jest/schemas": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz",
"integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
"requires": {
"@sinclair/typebox": "^0.25.16"
"@sinclair/typebox": "^0.27.8"
}
},
"@jest/types": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
"integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"requires": {
"@jest/schemas": "^29.4.3",
"@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@ -603,53 +622,56 @@
}
},
"@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
"integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ=="
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
},
"@types/istanbul-lib-coverage": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
"integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g=="
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="
},
"@types/istanbul-lib-report": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
"integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
"integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
"requires": {
"@types/istanbul-lib-coverage": "*"
}
},
"@types/istanbul-reports": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
"integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
"integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
"requires": {
"@types/istanbul-lib-report": "*"
}
},
"@types/node": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
"version": "22.5.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"requires": {
"undici-types": "~6.19.2"
}
},
"@types/stack-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
},
"@types/yargs": {
"version": "17.0.24",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
"integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
"integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
"requires": {
"@types/yargs-parser": "*"
}
},
"@types/yargs-parser": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
"version": "21.0.3",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="
},
"ansi-styles": {
"version": "4.3.0",
@ -677,9 +699,9 @@
}
},
"ci-info": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
"integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw=="
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="
},
"color-convert": {
"version": "2.0.1",
@ -695,27 +717,15 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"diff-sequences": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
"integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA=="
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="
},
"escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
},
"expect": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz",
"integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==",
"requires": {
"@jest/expect-utils": "^29.5.0",
"jest-get-type": "^29.4.3",
"jest-matcher-utils": "^29.5.0",
"jest-message-util": "^29.5.0",
"jest-util": "^29.5.0"
}
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -740,54 +750,64 @@
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"jest-diff": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
"integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
"integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^29.4.3",
"jest-get-type": "^29.4.3",
"pretty-format": "^29.5.0"
"diff-sequences": "^29.6.3",
"jest-get-type": "^29.6.3",
"pretty-format": "^29.7.0"
}
},
"jest-get-type": {
"version": "29.4.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
"integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg=="
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
"integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw=="
},
"jest-matcher-utils": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz",
"integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
"integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
"requires": {
"chalk": "^4.0.0",
"jest-diff": "^29.5.0",
"jest-get-type": "^29.4.3",
"pretty-format": "^29.5.0"
"jest-diff": "^29.7.0",
"jest-get-type": "^29.6.3",
"pretty-format": "^29.7.0"
}
},
"jest-message-util": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz",
"integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
"integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
"requires": {
"@babel/code-frame": "^7.12.13",
"@jest/types": "^29.5.0",
"@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
"pretty-format": "^29.5.0",
"pretty-format": "^29.7.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
}
},
"jest-util": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz",
"integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==",
"jest-mock": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
"integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
"requires": {
"@jest/types": "^29.5.0",
"@jest/types": "^29.6.3",
"@types/node": "*",
"jest-util": "^29.7.0"
}
},
"jest-util": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
"integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
"requires": {
"@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
@ -809,17 +829,22 @@
"picomatch": "^2.3.1"
}
},
"picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"pretty-format": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz",
"integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==",
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"requires": {
"@jest/schemas": "^29.4.3",
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
"react-is": "^18.0.0"
},
@ -832,9 +857,9 @@
}
},
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"slash": {
"version": "3.0.0",
@ -864,6 +889,11 @@
"requires": {
"is-number": "^7.0.0"
}
},
"undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
}
}
}

View File

@ -9,7 +9,11 @@
"generate-license": "node ../../../../utils/generate_third_party_notice.js"
},
"dependencies": {
"expect": "29.5.0",
"jest-matcher-utils": "29.5.0"
"@jest/expect-utils": "29.7.0",
"jest-get-type": "29.6.3",
"jest-matcher-utils": "29.7.0",
"jest-message-util": "29.7.0",
"jest-mock": "29.7.0",
"jest-util": "29.7.0"
}
}

View File

@ -14,8 +14,30 @@
* limitations under the License.
*/
import expectLibrary from 'expect';
import expectLibrary from '../third_party/index';
export const expect = expectLibrary;
export * as mock from 'jest-mock';
import * as am from '../third_party/asymmetricMatchers';
import * as mu from 'jest-matcher-utils';
export const asymmetricMatchers = {
any: am.any,
anything: am.anything,
arrayContaining: am.arrayContaining,
arrayNotContaining: am.arrayNotContaining,
closeTo: am.closeTo,
notCloseTo: am.notCloseTo,
objectContaining: am.objectContaining,
objectNotContaining: am.objectNotContaining,
stringContaining: am.stringContaining,
stringMatching: am.stringMatching,
stringNotContaining: am.stringNotContaining,
stringNotMatching: am.stringNotMatching,
};
export const matcherUtils = {
stringify: mu.stringify,
};
export {
INVERTED_COLOR,

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,362 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {
equals,
getObjectKeys,
isA,
iterableEquality,
subsetEquality,
} from '@jest/expect-utils';
import * as matcherUtils from 'jest-matcher-utils';
import { pluralize } from 'jest-util';
import { getCustomEqualityTesters, getState } from './jestMatchersObject';
import type {
AsymmetricMatcher as AsymmetricMatcherInterface,
MatcherContext,
MatcherState,
} from './types';
const functionToString = Function.prototype.toString;
function fnNameFor(func: () => unknown) {
if (func.name)
return func.name;
const matches = functionToString
.call(func)
.match(/^(?:async)?\s*function\s*\*?\s*([\w$]+)\s*\(/);
return matches ? matches[1] : '<anonymous>';
}
const utils = Object.freeze({
...matcherUtils,
iterableEquality,
subsetEquality,
});
function getPrototype(obj: object) {
if (Object.getPrototypeOf)
return Object.getPrototypeOf(obj);
if (obj.constructor.prototype === obj)
return null;
return obj.constructor.prototype;
}
export function hasProperty(
obj: object | null,
property: string | symbol,
): boolean {
if (!obj)
return false;
if (Object.prototype.hasOwnProperty.call(obj, property))
return true;
return hasProperty(getPrototype(obj), property);
}
export abstract class AsymmetricMatcher<T>
implements AsymmetricMatcherInterface {
$$typeof = Symbol.for('jest.asymmetricMatcher');
constructor(protected sample: T, protected inverse = false) { }
protected getMatcherContext(): MatcherContext {
return {
customTesters: getCustomEqualityTesters(),
dontThrow: () => { },
...getState<MatcherState>(),
equals,
isNot: this.inverse,
utils,
};
}
abstract asymmetricMatch(other: unknown): boolean;
abstract toString(): string;
getExpectedType?(): string;
toAsymmetricMatcher?(): string;
}
class Any extends AsymmetricMatcher<any> {
constructor(sample: unknown) {
if (typeof sample === 'undefined') {
throw new TypeError(
'any() expects to be passed a constructor function. ' +
'Please pass one or use anything() to match any object.',
);
}
super(sample);
}
asymmetricMatch(other: unknown) {
if (this.sample === String)
return typeof other === 'string' || other instanceof String;
if (this.sample === Number)
return typeof other === 'number' || other instanceof Number;
if (this.sample === Function)
return typeof other === 'function' || other instanceof Function;
if (this.sample === Boolean)
return typeof other === 'boolean' || other instanceof Boolean;
if (this.sample === BigInt)
return typeof other === 'bigint' || other instanceof BigInt;
if (this.sample === Symbol)
return typeof other === 'symbol' || other instanceof Symbol;
if (this.sample === Object)
return typeof other === 'object';
return other instanceof this.sample;
}
toString() {
return 'Any';
}
override getExpectedType() {
if (this.sample === String)
return 'string';
if (this.sample === Number)
return 'number';
if (this.sample === Function)
return 'function';
if (this.sample === Object)
return 'object';
if (this.sample === Boolean)
return 'boolean';
return fnNameFor(this.sample);
}
override toAsymmetricMatcher() {
return `Any<${fnNameFor(this.sample)}>`;
}
}
class Anything extends AsymmetricMatcher<void> {
asymmetricMatch(other: unknown) {
// eslint-disable-next-line eqeqeq
return other != null;
}
toString() {
return 'Anything';
}
// No getExpectedType method, because it matches either null or undefined.
override toAsymmetricMatcher() {
return 'Anything';
}
}
class ArrayContaining extends AsymmetricMatcher<Array<unknown>> {
constructor(sample: Array<unknown>, inverse = false) {
super(sample, inverse);
}
asymmetricMatch(other: unknown) {
if (!Array.isArray(this.sample)) {
throw new Error(
`You must provide an array to ${this.toString()}, not '${typeof this
.sample}'.`,
);
}
const matcherContext = this.getMatcherContext();
const result =
this.sample.length === 0 ||
(Array.isArray(other) &&
this.sample.every(item =>
other.some(another =>
equals(item, another, matcherContext.customTesters),
),
));
return this.inverse ? !result : result;
}
toString() {
return `Array${this.inverse ? 'Not' : ''}Containing`;
}
override getExpectedType() {
return 'array';
}
}
class ObjectContaining extends AsymmetricMatcher<
Record<string | symbol, unknown>
> {
constructor(sample: Record<string | symbol, unknown>, inverse = false) {
super(sample, inverse);
}
asymmetricMatch(other: any) {
if (typeof this.sample !== 'object') {
throw new Error(
`You must provide an object to ${this.toString()}, not '${typeof this
.sample}'.`,
);
}
let result = true;
const matcherContext = this.getMatcherContext();
const objectKeys = getObjectKeys(this.sample);
for (const key of objectKeys) {
if (
!hasProperty(other, key) ||
!equals(this.sample[key], other[key], matcherContext.customTesters)
) {
result = false;
break;
}
}
return this.inverse ? !result : result;
}
toString() {
return `Object${this.inverse ? 'Not' : ''}Containing`;
}
override getExpectedType() {
return 'object';
}
}
class StringContaining extends AsymmetricMatcher<string> {
constructor(sample: string, inverse = false) {
if (!isA('String', sample))
throw new Error('Expected is not a string');
super(sample, inverse);
}
asymmetricMatch(other: unknown) {
const result = isA<string>('String', other) && other.includes(this.sample);
return this.inverse ? !result : result;
}
toString() {
return `String${this.inverse ? 'Not' : ''}Containing`;
}
override getExpectedType() {
return 'string';
}
}
class StringMatching extends AsymmetricMatcher<RegExp> {
constructor(sample: string | RegExp, inverse = false) {
if (!isA('String', sample) && !isA('RegExp', sample))
throw new Error('Expected is not a String or a RegExp');
super(new RegExp(sample), inverse);
}
asymmetricMatch(other: unknown) {
const result = isA<string>('String', other) && this.sample.test(other);
return this.inverse ? !result : result;
}
toString() {
return `String${this.inverse ? 'Not' : ''}Matching`;
}
override getExpectedType() {
return 'string';
}
}
class CloseTo extends AsymmetricMatcher<number> {
private readonly precision: number;
constructor(sample: number, precision = 2, inverse = false) {
if (!isA('Number', sample))
throw new Error('Expected is not a Number');
if (!isA('Number', precision))
throw new Error('Precision is not a Number');
super(sample);
this.inverse = inverse;
this.precision = precision;
}
asymmetricMatch(other: unknown) {
if (!isA<number>('Number', other))
return false;
let result = false;
if (other === Infinity && this.sample === Infinity) {
result = true; // Infinity - Infinity is NaN
} else if (other === -Infinity && this.sample === -Infinity) {
result = true; // -Infinity - -Infinity is NaN
} else {
result =
Math.abs(this.sample - other) < Math.pow(10, -this.precision) / 2;
}
return this.inverse ? !result : result;
}
toString() {
return `Number${this.inverse ? 'Not' : ''}CloseTo`;
}
override getExpectedType() {
return 'number';
}
override toAsymmetricMatcher(): string {
return [
this.toString(),
this.sample,
`(${pluralize('digit', this.precision)})`,
].join(' ');
}
}
export const any = (expectedObject: unknown): Any => new Any(expectedObject);
export const anything = (): Anything => new Anything();
export const arrayContaining = (sample: Array<unknown>): ArrayContaining =>
new ArrayContaining(sample);
export const arrayNotContaining = (sample: Array<unknown>): ArrayContaining =>
new ArrayContaining(sample, true);
export const objectContaining = (
sample: Record<string, unknown>,
): ObjectContaining => new ObjectContaining(sample);
export const objectNotContaining = (
sample: Record<string, unknown>,
): ObjectContaining => new ObjectContaining(sample, true);
export const stringContaining = (expected: string): StringContaining =>
new StringContaining(expected);
export const stringNotContaining = (expected: string): StringContaining =>
new StringContaining(expected, true);
export const stringMatching = (expected: string | RegExp): StringMatching =>
new StringMatching(expected);
export const stringNotMatching = (expected: string | RegExp): StringMatching =>
new StringMatching(expected, true);
export const closeTo = (expected: number, precision?: number): CloseTo =>
new CloseTo(expected, precision);
export const notCloseTo = (expected: number, precision?: number): CloseTo =>
new CloseTo(expected, precision, true);

View File

@ -0,0 +1,85 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {
EXPECTED_COLOR,
RECEIVED_COLOR,
matcherHint,
pluralize,
} from 'jest-matcher-utils';
import { getState, setState } from './jestMatchersObject';
import type { Expect, ExpectedAssertionsErrors } from './types';
const resetAssertionsLocalState = () => {
setState({
assertionCalls: 0,
expectedAssertionsNumber: null,
isExpectingAssertions: false,
numPassingAsserts: 0,
});
};
// Create and format all errors related to the mismatched number of `expect`
// calls and reset the matcher's state.
const extractExpectedAssertionsErrors: Expect['extractExpectedAssertionsErrors'] =
() => {
const result: ExpectedAssertionsErrors = [];
const {
assertionCalls,
expectedAssertionsNumber,
expectedAssertionsNumberError,
isExpectingAssertions,
isExpectingAssertionsError,
} = getState();
resetAssertionsLocalState();
if (
typeof expectedAssertionsNumber === 'number' &&
assertionCalls !== expectedAssertionsNumber
) {
const numOfAssertionsExpected = EXPECTED_COLOR(
pluralize('assertion', expectedAssertionsNumber),
);
expectedAssertionsNumberError!.message =
`${matcherHint('.assertions', '', expectedAssertionsNumber.toString(), {
isDirectExpectCall: true,
})}\n\n` +
`Expected ${numOfAssertionsExpected} to be called but received ${RECEIVED_COLOR(
pluralize('assertion call', assertionCalls || 0),
)}.`;
result.push({
actual: assertionCalls.toString(),
error: expectedAssertionsNumberError!,
expected: expectedAssertionsNumber.toString(),
});
}
if (isExpectingAssertions && assertionCalls === 0) {
const expected = EXPECTED_COLOR('at least one assertion');
const received = RECEIVED_COLOR('received none');
isExpectingAssertionsError!.message = `${matcherHint(
'.hasAssertions',
'',
'',
{ isDirectExpectCall: true },
)}\n\nExpected ${expected} to be called but ${received}.`;
result.push({
actual: 'none',
error: isExpectingAssertionsError!,
expected: 'at least one',
});
}
return result;
};
export default extractExpectedAssertionsErrors;

View File

@ -0,0 +1,463 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { equals, iterableEquality, subsetEquality } from '@jest/expect-utils';
import * as matcherUtils from 'jest-matcher-utils';
import { isPromise } from 'jest-util';
import {
any,
anything,
arrayContaining,
arrayNotContaining,
closeTo,
notCloseTo,
objectContaining,
objectNotContaining,
stringContaining,
stringMatching,
stringNotContaining,
stringNotMatching,
} from './asymmetricMatchers';
import extractExpectedAssertionsErrors from './extractExpectedAssertionsErrors';
import {
INTERNAL_MATCHER_FLAG,
addCustomEqualityTesters,
getCustomEqualityTesters,
getMatchers,
getState,
setMatchers,
setState,
} from './jestMatchersObject';
import matchers from './matchers';
import spyMatchers from './spyMatchers';
import toThrowMatchers, {
createMatcher as createThrowMatcher,
} from './toThrowMatchers';
import type {
Expect,
ExpectationResult,
MatcherContext,
MatcherState,
MatcherUtils,
MatchersObject,
PromiseMatcherFn,
RawMatcherFn,
SyncExpectationResult,
ThrowingMatcherFn,
} from './types';
export type { Tester, TesterContext } from '@jest/expect-utils';
export { AsymmetricMatcher } from './asymmetricMatchers';
export type {
AsyncExpectationResult,
AsymmetricMatchers,
BaseExpect,
Expect,
ExpectationResult,
MatcherContext,
MatcherFunction,
MatcherFunctionWithContext,
MatcherState,
MatcherUtils,
Matchers,
SyncExpectationResult,
} from './types';
export class JestAssertionError extends Error {
matcherResult?: Omit<SyncExpectationResult, 'message'> & { message: string };
}
const createToThrowErrorMatchingSnapshotMatcher = function(
matcher: RawMatcherFn,
) {
return function(
this: MatcherContext,
received: any,
testNameOrInlineSnapshot?: string,
) {
return matcher.apply(this, [received, testNameOrInlineSnapshot, true]);
};
};
const getPromiseMatcher = (name: string, matcher: RawMatcherFn) => {
if (name === 'toThrow' || name === 'toThrowError')
return createThrowMatcher(name, true);
else if (
name === 'toThrowErrorMatchingSnapshot' ||
name === 'toThrowErrorMatchingInlineSnapshot'
)
return createToThrowErrorMatchingSnapshotMatcher(matcher);
return null;
};
export const expect: Expect = (actual: any, ...rest: Array<any>) => {
if (rest.length !== 0)
throw new Error('Expect takes at most one argument.');
const allMatchers = getMatchers();
const expectation: any = {
not: {},
rejects: { not: {} },
resolves: { not: {} },
};
const err = new JestAssertionError();
Object.keys(allMatchers).forEach(name => {
const matcher = allMatchers[name];
const promiseMatcher = getPromiseMatcher(name, matcher) || matcher;
expectation[name] = makeThrowingMatcher(matcher, false, '', actual);
expectation.not[name] = makeThrowingMatcher(matcher, true, '', actual);
expectation.resolves[name] = makeResolveMatcher(
name,
promiseMatcher,
false,
actual,
err,
);
expectation.resolves.not[name] = makeResolveMatcher(
name,
promiseMatcher,
true,
actual,
err,
);
expectation.rejects[name] = makeRejectMatcher(
name,
promiseMatcher,
false,
actual,
err,
);
expectation.rejects.not[name] = makeRejectMatcher(
name,
promiseMatcher,
true,
actual,
err,
);
});
return expectation;
};
const getMessage = (message?: () => string) =>
(message && message()) ||
matcherUtils.RECEIVED_COLOR('No message was specified for this matcher.');
const makeResolveMatcher =
(
matcherName: string,
matcher: RawMatcherFn,
isNot: boolean,
actual: Promise<any>,
outerErr: JestAssertionError,
): PromiseMatcherFn =>
(...args) => {
const options = {
isNot,
promise: 'resolves',
};
if (!isPromise(actual)) {
throw new JestAssertionError(
matcherUtils.matcherErrorMessage(
matcherUtils.matcherHint(matcherName, undefined, '', options),
`${matcherUtils.RECEIVED_COLOR('received')} value must be a promise`,
matcherUtils.printWithType(
'Received',
actual,
matcherUtils.printReceived,
),
),
);
}
const innerErr = new JestAssertionError();
return actual.then(
result =>
makeThrowingMatcher(matcher, isNot, 'resolves', result, innerErr).apply(
null,
args,
),
reason => {
outerErr.message =
`${matcherUtils.matcherHint(
matcherName,
undefined,
'',
options,
)}\n\n` +
'Received promise rejected instead of resolved\n' +
`Rejected to value: ${matcherUtils.printReceived(reason)}`;
return Promise.reject(outerErr);
},
);
};
const makeRejectMatcher =
(
matcherName: string,
matcher: RawMatcherFn,
isNot: boolean,
actual: Promise<any> | (() => Promise<any>),
outerErr: JestAssertionError,
): PromiseMatcherFn =>
(...args) => {
const options = {
isNot,
promise: 'rejects',
};
const actualWrapper: Promise<any> =
typeof actual === 'function' ? actual() : actual;
if (!isPromise(actualWrapper)) {
throw new JestAssertionError(
matcherUtils.matcherErrorMessage(
matcherUtils.matcherHint(matcherName, undefined, '', options),
`${matcherUtils.RECEIVED_COLOR(
'received',
)} value must be a promise or a function returning a promise`,
matcherUtils.printWithType(
'Received',
actual,
matcherUtils.printReceived,
),
),
);
}
const innerErr = new JestAssertionError();
return actualWrapper.then(
result => {
outerErr.message =
`${matcherUtils.matcherHint(
matcherName,
undefined,
'',
options,
)}\n\n` +
'Received promise resolved instead of rejected\n' +
`Resolved to value: ${matcherUtils.printReceived(result)}`;
return Promise.reject(outerErr);
},
reason =>
makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply(
null,
args,
),
);
};
const makeThrowingMatcher = (
matcher: RawMatcherFn,
isNot: boolean,
promise: string,
actual: any,
err?: JestAssertionError,
): ThrowingMatcherFn =>
function throwingMatcher(...args): any {
let throws = true;
const utils: MatcherUtils['utils'] = {
...matcherUtils,
iterableEquality,
subsetEquality,
};
const matcherUtilsThing: MatcherUtils = {
customTesters: getCustomEqualityTesters(),
// When throws is disabled, the matcher will not throw errors during test
// execution but instead add them to the global matcher state. If a
// matcher throws, test execution is normally stopped immediately. The
// snapshot matcher uses it because we want to log all snapshot
// failures in a test.
dontThrow: () => (throws = false),
equals,
utils,
};
const matcherContext: MatcherContext = {
...getState<MatcherState>(),
...matcherUtilsThing,
error: err,
isNot,
promise,
};
const processResult = (
result: SyncExpectationResult,
asyncError?: JestAssertionError,
) => {
_validateResult(result);
getState().assertionCalls++;
if ((result.pass && isNot) || (!result.pass && !isNot)) {
// XOR
const message = getMessage(result.message);
let error;
if (err) {
error = err;
error.message = message;
} else if (asyncError) {
error = asyncError;
error.message = message;
} else {
error = new JestAssertionError(message);
// Try to remove this function from the stack trace frame.
// Guard for some environments (browsers) that do not support this feature.
if (Error.captureStackTrace)
Error.captureStackTrace(error, throwingMatcher);
}
// Passing the result of the matcher with the error so that a custom
// reporter could access the actual and expected objects of the result
// for example in order to display a custom visual diff
error.matcherResult = { ...result, message };
if (throws)
throw error;
else
getState().suppressedErrors.push(error);
} else {
getState().numPassingAsserts++;
}
};
const handleError = (error: Error) => {
if (
matcher[INTERNAL_MATCHER_FLAG] === true &&
!(error instanceof JestAssertionError) &&
error.name !== 'PrettyFormatPluginError' &&
// Guard for some environments (browsers) that do not support this feature.
Error.captureStackTrace
) {
// Try to remove this and deeper functions from the stack trace frame.
Error.captureStackTrace(error, throwingMatcher);
}
throw error;
};
let potentialResult: ExpectationResult;
try {
potentialResult =
matcher[INTERNAL_MATCHER_FLAG] === true
? matcher.call(matcherContext, actual, ...args)
: // It's a trap specifically for inline snapshot to capture this name
// in the stack trace, so that it can correctly get the custom matcher
// function call.
(function __EXTERNAL_MATCHER_TRAP__() {
return matcher.call(matcherContext, actual, ...args);
})();
if (isPromise(potentialResult)) {
const asyncError = new JestAssertionError();
if (Error.captureStackTrace)
Error.captureStackTrace(asyncError, throwingMatcher);
return potentialResult
.then(aResult => processResult(aResult, asyncError))
.catch(handleError);
} else {
return processResult(potentialResult);
}
} catch (error: any) {
return handleError(error);
}
};
expect.extend = (matchers: MatchersObject) =>
setMatchers(matchers, false, expect);
expect.addEqualityTesters = customTesters =>
addCustomEqualityTesters(customTesters);
expect.anything = anything;
expect.any = any;
expect.not = {
arrayContaining: arrayNotContaining,
closeTo: notCloseTo,
objectContaining: objectNotContaining,
stringContaining: stringNotContaining,
stringMatching: stringNotMatching,
};
expect.arrayContaining = arrayContaining;
expect.closeTo = closeTo;
expect.objectContaining = objectContaining;
expect.stringContaining = stringContaining;
expect.stringMatching = stringMatching;
const _validateResult = (result: any) => {
if (
typeof result !== 'object' ||
typeof result.pass !== 'boolean' ||
(result.message &&
typeof result.message !== 'string' &&
typeof result.message !== 'function')
) {
throw new Error(
'Unexpected return from a matcher function.\n' +
'Matcher functions should ' +
'return an object in the following format:\n' +
' {message?: string | function, pass: boolean}\n' +
`'${matcherUtils.stringify(result)}' was returned`,
);
}
};
function assertions(expected: number): void {
const error = new Error();
if (Error.captureStackTrace)
Error.captureStackTrace(error, assertions);
setState({
expectedAssertionsNumber: expected,
expectedAssertionsNumberError: error,
});
}
function hasAssertions(...args: Array<unknown>): void {
const error = new Error();
if (Error.captureStackTrace)
Error.captureStackTrace(error, hasAssertions);
matcherUtils.ensureNoExpected(args[0], '.hasAssertions');
setState({
isExpectingAssertions: true,
isExpectingAssertionsError: error,
});
}
// add default jest matchers
setMatchers(matchers, true, expect);
setMatchers(spyMatchers, true, expect);
setMatchers(toThrowMatchers, true, expect);
expect.assertions = assertions;
expect.hasAssertions = hasAssertions;
expect.getState = getState;
expect.setState = setState;
expect.extractExpectedAssertionsErrors = extractExpectedAssertionsErrors;
export default expect;

View File

@ -0,0 +1,144 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { Tester } from '@jest/expect-utils';
import { getType } from 'jest-get-type';
import { AsymmetricMatcher } from './asymmetricMatchers';
import type {
Expect,
MatcherState,
MatchersObject,
SyncExpectationResult,
} from './types';
// Global matchers object holds the list of available matchers and
// the state, that can hold matcher specific values that change over time.
const JEST_MATCHERS_OBJECT = Symbol.for('$$jest-matchers-object');
// Notes a built-in/internal Jest matcher.
// Jest may override the stack trace of Errors thrown by internal matchers.
export const INTERNAL_MATCHER_FLAG = Symbol.for('$$jest-internal-matcher');
if (!Object.prototype.hasOwnProperty.call(globalThis, JEST_MATCHERS_OBJECT)) {
const defaultState: MatcherState = {
assertionCalls: 0,
expectedAssertionsNumber: null,
isExpectingAssertions: false,
numPassingAsserts: 0,
suppressedErrors: [], // errors that are not thrown immediately.
};
Object.defineProperty(globalThis, JEST_MATCHERS_OBJECT, {
value: {
customEqualityTesters: [],
matchers: Object.create(null),
state: defaultState,
},
});
}
export const getState = <State extends MatcherState = MatcherState>(): State =>
(globalThis as any)[JEST_MATCHERS_OBJECT].state;
export const setState = <State extends MatcherState = MatcherState>(
state: Partial<State>,
): void => {
Object.assign((globalThis as any)[JEST_MATCHERS_OBJECT].state, state);
};
export const getMatchers = (): MatchersObject =>
(globalThis as any)[JEST_MATCHERS_OBJECT].matchers;
export const setMatchers = (
matchers: MatchersObject,
isInternal: boolean,
expect: Expect,
): void => {
Object.keys(matchers).forEach(key => {
const matcher = matchers[key];
if (typeof matcher !== 'function') {
throw new TypeError(
`expect.extend: \`${key}\` is not a valid matcher. Must be a function, is "${getType(
matcher,
)}"`,
);
}
Object.defineProperty(matcher, INTERNAL_MATCHER_FLAG, {
value: isInternal,
});
if (!isInternal) {
// expect is defined
class CustomMatcher extends AsymmetricMatcher<
[unknown, ...Array<unknown>]
> {
constructor(inverse = false, ...sample: [unknown, ...Array<unknown>]) {
super(sample, inverse);
}
asymmetricMatch(other: unknown) {
const { pass } = matcher.call(
this.getMatcherContext(),
other,
...this.sample,
) as SyncExpectationResult;
return this.inverse ? !pass : pass;
}
toString() {
return `${this.inverse ? 'not.' : ''}${key}`;
}
override getExpectedType() {
return 'any';
}
override toAsymmetricMatcher() {
return `${this.toString()}<${this.sample.map(String).join(', ')}>`;
}
}
Object.defineProperty(expect, key, {
configurable: true,
enumerable: true,
value: (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(false, ...sample),
writable: true,
});
Object.defineProperty(expect.not, key, {
configurable: true,
enumerable: true,
value: (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(true, ...sample),
writable: true,
});
}
});
Object.assign((globalThis as any)[JEST_MATCHERS_OBJECT].matchers, matchers);
};
export const getCustomEqualityTesters = (): Array<Tester> =>
(globalThis as any)[JEST_MATCHERS_OBJECT].customEqualityTesters;
export const addCustomEqualityTesters = (newTesters: Array<Tester>): void => {
if (!Array.isArray(newTesters)) {
throw new TypeError(
`expect.customEqualityTesters: Must be set to an array of Testers. Was given "${getType(
newTesters,
)}"`,
);
}
(globalThis as any)[JEST_MATCHERS_OBJECT].customEqualityTesters.push(
...newTesters,
);
};

View File

@ -0,0 +1,983 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
/* eslint-disable eqeqeq */
import {
arrayBufferEquality,
equals,
getObjectSubset,
getPath,
iterableEquality,
pathAsArray,
sparseArrayEquality,
subsetEquality,
typeEquality,
} from '@jest/expect-utils';
import { getType, isPrimitive } from 'jest-get-type';
import {
DIM_COLOR,
EXPECTED_COLOR,
type MatcherHintOptions,
RECEIVED_COLOR,
SUGGEST_TO_CONTAIN_EQUAL,
ensureExpectedIsNonNegativeInteger,
ensureNoExpected,
ensureNumbers,
getLabelPrinter,
matcherErrorMessage,
matcherHint,
printDiffOrStringify,
printExpected,
printReceived,
printWithType,
stringify,
} from 'jest-matcher-utils';
import {
printCloseTo,
printExpectedConstructorName,
printExpectedConstructorNameNot,
printReceivedArrayContainExpectedItem,
printReceivedConstructorName,
printReceivedConstructorNameNot,
printReceivedStringContainExpectedResult,
printReceivedStringContainExpectedSubstring,
} from './print';
import type { MatchersObject } from './types';
// Omit colon and one or more spaces, so can call getLabelPrinter.
const EXPECTED_LABEL = 'Expected';
const RECEIVED_LABEL = 'Received';
const EXPECTED_VALUE_LABEL = 'Expected value';
const RECEIVED_VALUE_LABEL = 'Received value';
// The optional property of matcher context is true if undefined.
const isExpand = (expand?: boolean): boolean => expand !== false;
const toStrictEqualTesters = [
iterableEquality,
typeEquality,
sparseArrayEquality,
arrayBufferEquality,
];
type ContainIterable =
| Array<unknown>
| Set<unknown>
| NodeListOf<Node>
| DOMTokenList
| HTMLCollectionOf<any>;
const matchers: MatchersObject = {
toBe(received: unknown, expected: unknown) {
const matcherName = 'toBe';
const options: MatcherHintOptions = {
comment: 'Object.is equality',
isNot: this.isNot,
promise: this.promise,
};
const pass = Object.is(received, expected);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: not ${printExpected(expected)}`
: () => {
const expectedType = getType(expected);
let deepEqualityName = null;
if (expectedType !== 'map' && expectedType !== 'set') {
// If deep equality passes when referential identity fails,
// but exclude map and set until review of their equality logic.
if (
equals(
received,
expected,
[...this.customTesters, ...toStrictEqualTesters],
true,
)
)
deepEqualityName = 'toStrictEqual';
else if (
equals(received, expected, [
...this.customTesters,
iterableEquality,
])
)
deepEqualityName = 'toEqual';
}
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
(deepEqualityName !== null
? `${DIM_COLOR(
`If it should pass with deep equality, replace "${matcherName}" with "${deepEqualityName}"`,
)}\n\n`
: '') +
printDiffOrStringify(
expected,
received,
EXPECTED_LABEL,
RECEIVED_LABEL,
isExpand(this.expand),
)
);
};
// Passing the actual and expected objects so that a custom reporter
// could access them, for example in order to display a custom visual diff,
// or create a different error message
return { actual: received, expected, message, name: matcherName, pass };
},
toBeCloseTo(received: number, expected: number, precision = 2) {
const matcherName = 'toBeCloseTo';
const secondArgument = arguments.length === 3 ? 'precision' : undefined;
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
secondArgument,
secondArgumentColor: (arg: string) => arg,
};
if (typeof expected !== 'number') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${EXPECTED_COLOR('expected')} value must be a number`,
printWithType('Expected', expected, printExpected),
),
);
}
if (typeof received !== 'number') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR('received')} value must be a number`,
printWithType('Received', received, printReceived),
),
);
}
let pass = false;
let expectedDiff = 0;
let receivedDiff = 0;
if (received === Infinity && expected === Infinity) {
pass = true; // Infinity - Infinity is NaN
} else if (received === -Infinity && expected === -Infinity) {
pass = true; // -Infinity - -Infinity is NaN
} else {
expectedDiff = Math.pow(10, -precision) / 2;
receivedDiff = Math.abs(expected - received);
pass = receivedDiff < expectedDiff;
}
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: not ${printExpected(expected)}\n` +
(receivedDiff === 0
? ''
: `Received: ${printReceived(received)}\n` +
`\n${printCloseTo(receivedDiff, expectedDiff, precision, isNot)}`)
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: ${printExpected(expected)}\n` +
`Received: ${printReceived(received)}\n` +
'\n' +
printCloseTo(receivedDiff, expectedDiff, precision, isNot);
return { message, pass };
},
toBeDefined(received: unknown, expected: void) {
const matcherName = 'toBeDefined';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = received !== void 0;
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toBeFalsy(received: unknown, expected: void) {
const matcherName = 'toBeFalsy';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = !received;
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toBeGreaterThan(received: number | bigint, expected: number | bigint) {
const matcherName = 'toBeGreaterThan';
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, matcherName, options);
const pass = received > expected;
const message = () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected:${isNot ? ' not' : ''} > ${printExpected(expected)}\n` +
`Received:${isNot ? ' ' : ''} ${printReceived(received)}`;
return { message, pass };
},
toBeGreaterThanOrEqual(received: number | bigint, expected: number | bigint) {
const matcherName = 'toBeGreaterThanOrEqual';
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, matcherName, options);
const pass = received >= expected;
const message = () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected:${isNot ? ' not' : ''} >= ${printExpected(expected)}\n` +
`Received:${isNot ? ' ' : ''} ${printReceived(received)}`;
return { message, pass };
},
toBeInstanceOf(received: any, expected: Function) {
const matcherName = 'toBeInstanceOf';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
if (typeof expected !== 'function') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${EXPECTED_COLOR('expected')} value must be a function`,
printWithType('Expected', expected, printExpected),
),
);
}
const pass = received instanceof expected;
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printExpectedConstructorNameNot('Expected constructor', expected) +
(typeof received.constructor === 'function' &&
received.constructor !== expected
? printReceivedConstructorNameNot(
'Received constructor',
received.constructor,
expected,
)
: '')
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printExpectedConstructorName('Expected constructor', expected) +
(isPrimitive(received) || Object.getPrototypeOf(received) === null
? `\nReceived value has no prototype\nReceived value: ${printReceived(
received,
)}`
: typeof received.constructor !== 'function'
? `\nReceived value: ${printReceived(received)}`
: printReceivedConstructorName(
'Received constructor',
received.constructor,
));
return { message, pass };
},
toBeLessThan(received: number | bigint, expected: number | bigint) {
const matcherName = 'toBeLessThan';
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, matcherName, options);
const pass = received < expected;
const message = () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected:${isNot ? ' not' : ''} < ${printExpected(expected)}\n` +
`Received:${isNot ? ' ' : ''} ${printReceived(received)}`;
return { message, pass };
},
toBeLessThanOrEqual(received: number | bigint, expected: number | bigint) {
const matcherName = 'toBeLessThanOrEqual';
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
};
ensureNumbers(received, expected, matcherName, options);
const pass = received <= expected;
const message = () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected:${isNot ? ' not' : ''} <= ${printExpected(expected)}\n` +
`Received:${isNot ? ' ' : ''} ${printReceived(received)}`;
return { message, pass };
},
toBeNaN(received: any, expected: void) {
const matcherName = 'toBeNaN';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = Number.isNaN(received);
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toBeNull(received: unknown, expected: void) {
const matcherName = 'toBeNull';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = received === null;
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toBeTruthy(received: unknown, expected: void) {
const matcherName = 'toBeTruthy';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = !!received;
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toBeUndefined(received: unknown, expected: void) {
const matcherName = 'toBeUndefined';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
ensureNoExpected(expected, matcherName, options);
const pass = received === void 0;
const message = () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
`Received: ${printReceived(received)}`;
return { message, pass };
},
toContain(received: ContainIterable | string, expected: unknown) {
const matcherName = 'toContain';
const isNot = this.isNot;
const options: MatcherHintOptions = {
comment: 'indexOf',
isNot,
promise: this.promise,
};
if (received == null) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR('received')} value must not be null nor undefined`,
printWithType('Received', received, printReceived),
),
);
}
if (typeof received === 'string') {
const wrongTypeErrorMessage = `${EXPECTED_COLOR(
'expected',
)} value must be a string if ${RECEIVED_COLOR(
'received',
)} value is a string`;
if (typeof expected !== 'string') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, received, String(expected), options),
wrongTypeErrorMessage,
printWithType('Expected', expected, printExpected) +
'\n' +
printWithType('Received', received, printReceived),
),
);
}
const index = received.indexOf(String(expected));
const pass = index !== -1;
const message = () => {
const labelExpected = `Expected ${typeof expected === 'string' ? 'substring' : 'value'
}`;
const labelReceived = 'Received string';
const printLabel = getLabelPrinter(labelExpected, labelReceived);
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(
expected,
)}\n` +
`${printLabel(labelReceived)}${isNot ? ' ' : ''}${isNot
? printReceivedStringContainExpectedSubstring(
received,
index,
String(expected).length,
)
: printReceived(received)
}`
);
};
return { message, pass };
}
const indexable = Array.from(received);
const index = indexable.indexOf(expected);
const pass = index !== -1;
const message = () => {
const labelExpected = 'Expected value';
const labelReceived = `Received ${getType(received)}`;
const printLabel = getLabelPrinter(labelExpected, labelReceived);
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(
expected,
)}\n` +
`${printLabel(labelReceived)}${isNot ? ' ' : ''}${isNot && Array.isArray(received)
? printReceivedArrayContainExpectedItem(received, index)
: printReceived(received)
}` +
(!isNot &&
indexable.findIndex(item =>
equals(item, expected, [...this.customTesters, iterableEquality]),
) !== -1
? `\n\n${SUGGEST_TO_CONTAIN_EQUAL}`
: '')
);
};
return { message, pass };
},
toContainEqual(received: ContainIterable, expected: unknown) {
const matcherName = 'toContainEqual';
const isNot = this.isNot;
const options: MatcherHintOptions = {
comment: 'deep equality',
isNot,
promise: this.promise,
};
if (received == null) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR('received')} value must not be null nor undefined`,
printWithType('Received', received, printReceived),
),
);
}
const index = Array.from(received).findIndex(item =>
equals(item, expected, [...this.customTesters, iterableEquality]),
);
const pass = index !== -1;
const message = () => {
const labelExpected = 'Expected value';
const labelReceived = `Received ${getType(received)}`;
const printLabel = getLabelPrinter(labelExpected, labelReceived);
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(
expected,
)}\n` +
`${printLabel(labelReceived)}${isNot ? ' ' : ''}${isNot && Array.isArray(received)
? printReceivedArrayContainExpectedItem(received, index)
: printReceived(received)
}`
);
};
return { message, pass };
},
toEqual(received: unknown, expected: unknown) {
const matcherName = 'toEqual';
const options: MatcherHintOptions = {
comment: 'deep equality',
isNot: this.isNot,
promise: this.promise,
};
const pass = equals(received, expected, [
...this.customTesters,
iterableEquality,
]);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: not ${printExpected(expected)}\n` +
(stringify(expected) !== stringify(received)
? `Received: ${printReceived(received)}`
: '')
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printDiffOrStringify(
expected,
received,
EXPECTED_LABEL,
RECEIVED_LABEL,
isExpand(this.expand),
);
// Passing the actual and expected objects so that a custom reporter
// could access them, for example in order to display a custom visual diff,
// or create a different error message
return { actual: received, expected, message, name: matcherName, pass };
},
toHaveLength(received: any, expected: number) {
const matcherName = 'toHaveLength';
const isNot = this.isNot;
const options: MatcherHintOptions = {
isNot,
promise: this.promise,
};
if (typeof received?.length !== 'number') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR(
'received',
)} value must have a length property whose value must be a number`,
printWithType('Received', received, printReceived),
),
);
}
ensureExpectedIsNonNegativeInteger(expected, matcherName, options);
const pass = received.length === expected;
const message = () => {
const labelExpected = 'Expected length';
const labelReceivedLength = 'Received length';
const labelReceivedValue = `Received ${getType(received)}`;
const printLabel = getLabelPrinter(
labelExpected,
labelReceivedLength,
labelReceivedValue,
);
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(
expected,
)}\n` +
(isNot
? ''
: `${printLabel(labelReceivedLength)}${printReceived(
received.length,
)}\n`) +
`${printLabel(labelReceivedValue)}${isNot ? ' ' : ''}${printReceived(
received,
)}`
);
};
return { message, pass };
},
toHaveProperty(
received: object,
expectedPath: string | Array<string>,
expectedValue?: unknown,
) {
const matcherName = 'toHaveProperty';
const expectedArgument = 'path';
const hasValue = arguments.length === 3;
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
secondArgument: hasValue ? 'value' : '',
};
if (received === null || received === undefined) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${RECEIVED_COLOR('received')} value must not be null nor undefined`,
printWithType('Received', received, printReceived),
),
);
}
const expectedPathType = getType(expectedPath);
if (expectedPathType !== 'string' && expectedPathType !== 'array') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${EXPECTED_COLOR('expected')} path must be a string or array`,
printWithType('Expected', expectedPath, printExpected),
),
);
}
const expectedPathLength =
typeof expectedPath === 'string'
? pathAsArray(expectedPath).length
: expectedPath.length;
if (expectedPathType === 'array' && expectedPathLength === 0) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${EXPECTED_COLOR('expected')} path must not be an empty array`,
printWithType('Expected', expectedPath, printExpected),
),
);
}
const result = getPath(received, expectedPath);
const { lastTraversedObject, endPropIsDefined, hasEndProp, value } = result;
const receivedPath = result.traversedPath;
const hasCompletePath = receivedPath.length === expectedPathLength;
const receivedValue = hasCompletePath ? result.value : lastTraversedObject;
const pass =
hasValue && endPropIsDefined
? equals(value, expectedValue, [
...this.customTesters,
iterableEquality,
])
: Boolean(hasEndProp);
const message = pass
? () =>
matcherHint(matcherName, undefined, expectedArgument, options) +
'\n\n' +
(hasValue
? `Expected path: ${printExpected(expectedPath)}\n\n` +
`Expected value: not ${printExpected(expectedValue)}${stringify(expectedValue) !== stringify(receivedValue)
? `\nReceived value: ${printReceived(receivedValue)}`
: ''
}`
: `Expected path: not ${printExpected(expectedPath)}\n\n` +
`Received value: ${printReceived(receivedValue)}`)
: () =>
matcherHint(matcherName, undefined, expectedArgument, options) +
'\n\n' +
`Expected path: ${printExpected(expectedPath)}\n` +
(hasCompletePath
? `\n${printDiffOrStringify(
expectedValue,
receivedValue,
EXPECTED_VALUE_LABEL,
RECEIVED_VALUE_LABEL,
isExpand(this.expand),
)}`
: `Received path: ${printReceived(
expectedPathType === 'array' || receivedPath.length === 0
? receivedPath
: receivedPath.join('.'),
)}\n\n${hasValue
? `Expected value: ${printExpected(expectedValue)}\n`
: ''
}Received value: ${printReceived(receivedValue)}`);
return { message, pass };
},
toMatch(received: string, expected: string | RegExp) {
const matcherName = 'toMatch';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
if (typeof received !== 'string') {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR('received')} value must be a string`,
printWithType('Received', received, printReceived),
),
);
}
if (
!(typeof expected === 'string') &&
!(expected && typeof expected.test === 'function')
) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${EXPECTED_COLOR(
'expected',
)} value must be a string or regular expression`,
printWithType('Expected', expected, printExpected),
),
);
}
const pass =
typeof expected === 'string'
? received.includes(expected)
: new RegExp(expected).test(received);
const message = pass
? () =>
typeof expected === 'string'
?
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected substring: not ${printExpected(expected)}\n` +
`Received string: ${printReceivedStringContainExpectedSubstring(
received,
received.indexOf(expected),
expected.length,
)}`
:
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected pattern: not ${printExpected(expected)}\n` +
`Received string: ${printReceivedStringContainExpectedResult(
received,
typeof expected.exec === 'function'
? expected.exec(received)
: null,
)}`
: () => {
const labelExpected = `Expected ${typeof expected === 'string' ? 'substring' : 'pattern'
}`;
const labelReceived = 'Received string';
const printLabel = getLabelPrinter(labelExpected, labelReceived);
return (
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`${printLabel(labelExpected)}${printExpected(expected)}\n` +
`${printLabel(labelReceived)}${printReceived(received)}`
);
};
return { message, pass };
},
toMatchObject(received: object, expected: object) {
const matcherName = 'toMatchObject';
const options: MatcherHintOptions = {
isNot: this.isNot,
promise: this.promise,
};
if (typeof received !== 'object' || received === null) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${RECEIVED_COLOR('received')} value must be a non-null object`,
printWithType('Received', received, printReceived),
),
);
}
if (typeof expected !== 'object' || expected === null) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${EXPECTED_COLOR('expected')} value must be a non-null object`,
printWithType('Expected', expected, printExpected),
),
);
}
const pass = equals(received, expected, [
...this.customTesters,
iterableEquality,
subsetEquality,
]);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: not ${printExpected(expected)}` +
(stringify(expected) !== stringify(received)
? `\nReceived: ${printReceived(received)}`
: '')
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printDiffOrStringify(
expected,
getObjectSubset(received, expected, this.customTesters),
EXPECTED_LABEL,
RECEIVED_LABEL,
isExpand(this.expand),
);
return { message, pass };
},
toStrictEqual(received: unknown, expected: unknown) {
const matcherName = 'toStrictEqual';
const options: MatcherHintOptions = {
comment: 'deep equality',
isNot: this.isNot,
promise: this.promise,
};
const pass = equals(
received,
expected,
[...this.customTesters, ...toStrictEqualTesters],
true,
);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
`Expected: not ${printExpected(expected)}\n` +
(stringify(expected) !== stringify(received)
? `Received: ${printReceived(received)}`
: '')
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printDiffOrStringify(
expected,
received,
EXPECTED_LABEL,
RECEIVED_LABEL,
isExpand(this.expand),
);
// Passing the actual and expected objects so that a custom reporter
// could access them, for example in order to display a custom visual diff,
// or create a different error message
return { actual: received, expected, message, name: matcherName, pass };
},
};
export default matchers;

View File

@ -0,0 +1,134 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {
EXPECTED_COLOR,
INVERTED_COLOR,
RECEIVED_COLOR,
printReceived,
stringify,
} from 'jest-matcher-utils';
// Format substring but do not enclose in double quote marks.
// The replacement is compatible with pretty-format package.
const printSubstring = (val: string): string => val.replace(/"|\\/g, '\\$&');
export const printReceivedStringContainExpectedSubstring = (
received: string,
start: number,
length: number, // not end
): string =>
RECEIVED_COLOR(
`"${printSubstring(received.slice(0, start))}${INVERTED_COLOR(
printSubstring(received.slice(start, start + length)),
)}${printSubstring(received.slice(start + length))}"`,
);
export const printReceivedStringContainExpectedResult = (
received: string,
result: RegExpExecArray | null,
): string =>
result === null
? printReceived(received)
: printReceivedStringContainExpectedSubstring(
received,
result.index,
result[0].length,
);
// The serialized array is compatible with pretty-format package min option.
// However, items have default stringify depth (instead of depth - 1)
// so expected item looks consistent by itself and enclosed in the array.
export const printReceivedArrayContainExpectedItem = (
received: Array<unknown>,
index: number,
): string =>
RECEIVED_COLOR(
`[${received
.map((item, i) => {
const stringified = stringify(item);
return i === index ? INVERTED_COLOR(stringified) : stringified;
})
.join(', ')}]`,
);
export const printCloseTo = (
receivedDiff: number,
expectedDiff: number,
precision: number,
isNot: boolean | undefined,
): string => {
const receivedDiffString = stringify(receivedDiff);
const expectedDiffString = receivedDiffString.includes('e')
? // toExponential arg is number of digits after the decimal point.
expectedDiff.toExponential(0)
: 0 <= precision && precision < 20
? // toFixed arg is number of digits after the decimal point.
// It may be a value between 0 and 20 inclusive.
// Implementations may optionally support a larger range of values.
expectedDiff.toFixed(precision + 1)
: stringify(expectedDiff);
return (
`Expected precision: ${isNot ? ' ' : ''} ${stringify(precision)}\n` +
`Expected difference: ${isNot ? 'not ' : ''}< ${EXPECTED_COLOR(
expectedDiffString,
)}\n` +
`Received difference: ${isNot ? ' ' : ''} ${RECEIVED_COLOR(
receivedDiffString,
)}`
);
};
export const printExpectedConstructorName = (
label: string,
expected: Function,
): string => `${printConstructorName(label, expected, false, true)}\n`;
export const printExpectedConstructorNameNot = (
label: string,
expected: Function,
): string => `${printConstructorName(label, expected, true, true)}\n`;
export const printReceivedConstructorName = (
label: string,
received: Function,
): string => `${printConstructorName(label, received, false, false)}\n`;
// Do not call function if received is equal to expected.
export const printReceivedConstructorNameNot = (
label: string,
received: Function,
expected: Function,
): string =>
typeof expected.name === 'string' &&
expected.name.length !== 0 &&
typeof received.name === 'string' &&
received.name.length !== 0
? `${printConstructorName(label, received, true, false)} ${
Object.getPrototypeOf(received) === expected
? 'extends'
: 'extends … extends'
} ${EXPECTED_COLOR(expected.name)}\n`
: `${printConstructorName(label, received, false, false)}\n`;
const printConstructorName = (
label: string,
constructor: Function,
isNot: boolean,
isExpected: boolean,
): string =>
typeof constructor.name !== 'string'
? `${label} name is not a string`
: constructor.name.length === 0
? `${label} name is an empty string`
: `${label}: ${!isNot ? '' : isExpected ? 'not ' : ' '}${
isExpected
? EXPECTED_COLOR(constructor.name)
: RECEIVED_COLOR(constructor.name)
}`;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,481 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { isError } from '@jest/expect-utils';
import {
EXPECTED_COLOR,
type MatcherHintOptions,
RECEIVED_COLOR,
matcherErrorMessage,
matcherHint,
printDiffOrStringify,
printExpected,
printReceived,
printWithType,
} from 'jest-matcher-utils';
import { formatStackTrace, separateMessageFromStack } from 'jest-message-util';
import {
printExpectedConstructorName,
printExpectedConstructorNameNot,
printReceivedConstructorName,
printReceivedConstructorNameNot,
printReceivedStringContainExpectedResult,
printReceivedStringContainExpectedSubstring,
} from './print';
import type {
ExpectationResult,
MatcherFunction,
MatchersObject,
SyncExpectationResult,
} from './types';
/* eslint-disable eqeqeq */
const DID_NOT_THROW = 'Received function did not throw';
type Thrown =
| {
hasMessage: true;
isError: true;
message: string;
value: Error;
}
| {
hasMessage: boolean;
isError: false;
message: string;
value: any;
};
const getThrown = (e: any): Thrown => {
const hasMessage =
e !== null && e !== undefined && typeof e.message === 'string';
if (hasMessage && typeof e.name === 'string' && typeof e.stack === 'string') {
return {
hasMessage,
isError: true,
message: e.message,
value: e,
};
}
return {
hasMessage,
isError: false,
message: hasMessage ? e.message : String(e),
value: e,
};
};
export const createMatcher = (
matcherName: string,
fromPromise?: boolean,
): MatcherFunction<[any]> =>
function(received, expected): ExpectationResult {
const options = {
isNot: this.isNot,
promise: this.promise,
};
let thrown = null;
if (fromPromise && isError(received)) {
thrown = getThrown(received);
} else {
if (typeof received !== 'function') {
if (!fromPromise) {
const placeholder = expected === undefined ? '' : 'expected';
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, placeholder, options),
`${RECEIVED_COLOR('received')} value must be a function`,
printWithType('Received', received, printReceived),
),
);
}
} else {
try {
received();
} catch (e) {
thrown = getThrown(e);
}
}
}
if (expected === undefined) {
return toThrow(matcherName, options, thrown);
} else if (typeof expected === 'function') {
return toThrowExpectedClass(matcherName, options, thrown, expected);
} else if (typeof expected === 'string') {
return toThrowExpectedString(matcherName, options, thrown, expected);
} else if (expected !== null && typeof expected.test === 'function') {
return toThrowExpectedRegExp(matcherName, options, thrown, expected);
} else if (
expected !== null &&
typeof expected.asymmetricMatch === 'function'
) {
return toThrowExpectedAsymmetric(matcherName, options, thrown, expected);
} else if (expected !== null && typeof expected === 'object') {
return toThrowExpectedObject(matcherName, options, thrown, expected);
} else {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, undefined, options),
`${EXPECTED_COLOR(
'expected',
)} value must be a string or regular expression or class or error`,
printWithType('Expected', expected, printExpected),
),
);
}
};
const matchers: MatchersObject = {
toThrow: createMatcher('toThrow'),
toThrowError: createMatcher('toThrowError'),
};
const toThrowExpectedRegExp = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
expected: RegExp,
): SyncExpectationResult => {
const pass = thrown !== null && expected.test(thrown.message);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected pattern: not ', expected) +
(thrown !== null && thrown.hasMessage
? formatReceived(
'Received message: ',
thrown,
'message',
expected,
) + formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected pattern: ', expected) +
(thrown === null
? `\n${DID_NOT_THROW}`
: thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));
return { message, pass };
};
type AsymmetricMatcher = {
asymmetricMatch: (received: unknown) => boolean;
};
const toThrowExpectedAsymmetric = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
expected: AsymmetricMatcher,
): SyncExpectationResult => {
const pass = thrown !== null && expected.asymmetricMatch(thrown.value);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected asymmetric matcher: not ', expected) +
'\n' +
(thrown !== null && thrown.hasMessage
? formatReceived('Received name: ', thrown, 'name') +
formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Thrown value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected asymmetric matcher: ', expected) +
'\n' +
(thrown === null
? DID_NOT_THROW
: thrown.hasMessage
? formatReceived('Received name: ', thrown, 'name') +
formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Thrown value: ', thrown, 'value'));
return { message, pass };
};
const toThrowExpectedObject = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
expected: Error,
): SyncExpectationResult => {
const expectedMessageAndCause = createMessageAndCause(expected);
const thrownMessageAndCause =
thrown !== null ? createMessageAndCause(thrown.value) : null;
const pass =
thrown !== null &&
thrown.message === expected.message &&
thrownMessageAndCause === expectedMessageAndCause;
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected(
`Expected ${messageAndCause(expected)}: not `,
expectedMessageAndCause,
) +
(thrown !== null && thrown.hasMessage
? formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
(thrown === null
?
formatExpected(
`Expected ${messageAndCause(expected)}: `,
expectedMessageAndCause,
) +
'\n' +
DID_NOT_THROW
: thrown.hasMessage
?
printDiffOrStringify(
expectedMessageAndCause,
thrownMessageAndCause,
`Expected ${messageAndCause(expected)}`,
`Received ${messageAndCause(thrown.value)}`,
true,
) +
'\n' +
formatStack(thrown)
: formatExpected(
`Expected ${messageAndCause(expected)}: `,
expectedMessageAndCause,
) + formatReceived('Received value: ', thrown, 'value'));
return { message, pass };
};
const toThrowExpectedClass = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
expected: Function,
): SyncExpectationResult => {
const pass = thrown !== null && thrown.value instanceof expected;
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printExpectedConstructorNameNot('Expected constructor', expected) +
(thrown !== null &&
thrown.value != null &&
typeof thrown.value.constructor === 'function' &&
thrown.value.constructor !== expected
? printReceivedConstructorNameNot(
'Received constructor',
thrown.value.constructor,
expected,
)
: '') +
'\n' +
(thrown !== null && thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
printExpectedConstructorName('Expected constructor', expected) +
(thrown === null
? `\n${DID_NOT_THROW}`
: `${thrown.value != null &&
typeof thrown.value.constructor === 'function'
? printReceivedConstructorName(
'Received constructor',
thrown.value.constructor,
)
: ''
}\n${thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value')
}`);
return { message, pass };
};
const toThrowExpectedString = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
expected: string,
): SyncExpectationResult => {
const pass = thrown !== null && thrown.message.includes(expected);
const message = pass
? () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected substring: not ', expected) +
(thrown !== null && thrown.hasMessage
? formatReceived(
'Received message: ',
thrown,
'message',
expected,
) + formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, undefined, options) +
'\n\n' +
formatExpected('Expected substring: ', expected) +
(thrown === null
? `\n${DID_NOT_THROW}`
: thrown.hasMessage
? formatReceived('Received message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Received value: ', thrown, 'value'));
return { message, pass };
};
const toThrow = (
matcherName: string,
options: MatcherHintOptions,
thrown: Thrown | null,
): SyncExpectationResult => {
const pass = thrown !== null;
const message = pass
? () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
(thrown !== null && thrown.hasMessage
? formatReceived('Error name: ', thrown, 'name') +
formatReceived('Error message: ', thrown, 'message') +
formatStack(thrown)
: formatReceived('Thrown value: ', thrown, 'value'))
: () =>
matcherHint(matcherName, undefined, '', options) +
'\n\n' +
DID_NOT_THROW;
return { message, pass };
};
const formatExpected = (label: string, expected: unknown) =>
`${label + printExpected(expected)}\n`;
const formatReceived = (
label: string,
thrown: Thrown | null,
key: string,
expected?: string | RegExp,
) => {
if (thrown === null)
return '';
if (key === 'message') {
const message = thrown.message;
if (typeof expected === 'string') {
const index = message.indexOf(expected);
if (index !== -1) {
return `${label +
printReceivedStringContainExpectedSubstring(
message,
index,
expected.length,
)
}\n`;
}
} else if (expected instanceof RegExp) {
return `${label +
printReceivedStringContainExpectedResult(
message,
typeof expected.exec === 'function' ? expected.exec(message) : null,
)
}\n`;
}
return `${label + printReceived(message)}\n`;
}
if (key === 'name') {
return thrown.isError
? `${label + printReceived(thrown.value.name)}\n`
: '';
}
if (key === 'value')
return thrown.isError ? '' : `${label + printReceived(thrown.value)}\n`;
return '';
};
const formatStack = (thrown: Thrown | null) =>
thrown === null || !thrown.isError
? ''
: formatStackTrace(
separateMessageFromStack(thrown.value.stack!).stack,
{
rootDir: process.cwd(),
testMatch: [],
},
{
noStackTrace: false,
},
);
function createMessageAndCauseMessage(error: Error): string {
if (error.cause instanceof Error) {
return `{ message: ${error.message}, cause: ${createMessageAndCauseMessage(
error.cause,
)}}`;
}
return `{ message: ${error.message} }`;
}
function createMessageAndCause(error: Error) {
if (error.cause instanceof Error)
return createMessageAndCauseMessage(error);
return error.message;
}
function messageAndCause(error: Error) {
return error.cause === undefined ? 'message' : 'message and cause';
}
export default matchers;

View File

@ -0,0 +1,353 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type { EqualsFunction, Tester } from '@jest/expect-utils';
import type * as jestMatcherUtils from 'jest-matcher-utils';
import type { INTERNAL_MATCHER_FLAG } from './jestMatchersObject';
export type SyncExpectationResult = {
pass: boolean;
message(): string;
};
export type AsyncExpectationResult = Promise<SyncExpectationResult>;
export type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
export type MatcherFunctionWithContext<
Context extends MatcherContext = MatcherContext,
Expected extends Array<any> = [] /** TODO should be: extends Array<unknown> = [] */,
> = (
this: Context,
actual: unknown,
...expected: Expected
) => ExpectationResult;
export type MatcherFunction<Expected extends Array<unknown> = []> =
MatcherFunctionWithContext<MatcherContext, Expected>;
// TODO should be replaced with `MatcherFunctionWithContext`
export type RawMatcherFn<Context extends MatcherContext = MatcherContext> = {
(this: Context, actual: any, ...expected: Array<any>): ExpectationResult;
/** @internal */
[INTERNAL_MATCHER_FLAG]?: boolean;
};
export type MatchersObject = {
[name: string]: RawMatcherFn;
};
export type ThrowingMatcherFn = (actual: any) => void;
export type PromiseMatcherFn = (actual: any) => Promise<void>;
export interface MatcherUtils {
customTesters: Array<Tester>;
dontThrow(): void;
equals: EqualsFunction;
utils: typeof jestMatcherUtils & {
iterableEquality: Tester;
subsetEquality: Tester;
};
}
export interface MatcherState {
assertionCalls: number;
currentConcurrentTestName?: () => string | undefined;
currentTestName?: string;
error?: Error;
expand?: boolean;
expectedAssertionsNumber: number | null;
expectedAssertionsNumberError?: Error;
isExpectingAssertions: boolean;
isExpectingAssertionsError?: Error;
isNot?: boolean;
numPassingAsserts: number;
promise?: string;
suppressedErrors: Array<Error>;
testPath?: string;
}
export type MatcherContext = MatcherUtils & Readonly<MatcherState>;
export type AsymmetricMatcher = {
asymmetricMatch(other: unknown): boolean;
toString(): string;
getExpectedType?(): string;
toAsymmetricMatcher?(): string;
};
export type ExpectedAssertionsErrors = Array<{
actual: string | number;
error: Error;
expected: string;
}>;
export interface BaseExpect {
assertions(numberOfAssertions: number): void;
addEqualityTesters(testers: Array<Tester>): void;
extend(matchers: MatchersObject): void;
extractExpectedAssertionsErrors(): ExpectedAssertionsErrors;
getState(): MatcherState;
hasAssertions(): void;
setState(state: Partial<MatcherState>): void;
}
export type Expect = {
<T = unknown>(actual: T): Matchers<void, T> &
Inverse<Matchers<void, T>> &
PromiseMatchers<T>;
} & BaseExpect &
AsymmetricMatchers &
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;
type Inverse<Matchers> = {
/**
* Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
*/
not: Matchers;
};
export interface AsymmetricMatchers {
any(sample: unknown): AsymmetricMatcher;
anything(): AsymmetricMatcher;
arrayContaining(sample: Array<unknown>): AsymmetricMatcher;
closeTo(sample: number, precision?: number): AsymmetricMatcher;
objectContaining(sample: Record<string, unknown>): AsymmetricMatcher;
stringContaining(sample: string): AsymmetricMatcher;
stringMatching(sample: string | RegExp): AsymmetricMatcher;
}
type PromiseMatchers<T = unknown> = {
/**
* Unwraps the reason of a rejected promise so any other matcher can be chained.
* If the promise is fulfilled the assertion fails.
*/
rejects: Matchers<Promise<void>, T> & Inverse<Matchers<Promise<void>, T>>;
/**
* Unwraps the value of a fulfilled promise so any other matcher can be chained.
* If the promise is rejected the assertion fails.
*/
resolves: Matchers<Promise<void>, T> & Inverse<Matchers<Promise<void>, T>>;
};
export interface Matchers<R extends void | Promise<void>, T = unknown> {
/**
* T is a type param for the benefit of users who extend Matchers. It's
* intentionally unused and needs to be named T, not _T, for those users.
* This makes sure TypeScript agrees.
*
* @internal
*/
_unusedT(expected: T): R;
/**
* Ensures the last call to a mock function was provided specific args.
*/
lastCalledWith(...expected: Array<unknown>): R;
/**
* Ensure that the last call to a mock function has returned a specified value.
*/
lastReturnedWith(expected?: unknown): R;
/**
* Ensure that a mock function is called with specific arguments on an Nth call.
*/
nthCalledWith(nth: number, ...expected: Array<unknown>): R;
/**
* Ensure that the nth call to a mock function has returned a specified value.
*/
nthReturnedWith(nth: number, expected?: unknown): R;
/**
* Checks that a value is what you expect. It calls `Object.is` to compare values.
* Don't use `toBe` with floating-point numbers.
*/
toBe(expected: unknown): R;
/**
* Ensures that a mock function is called.
*/
toBeCalled(): R;
/**
* Ensures that a mock function is called an exact number of times.
*/
toBeCalledTimes(expected: number): R;
/**
* Ensure that a mock function is called with specific arguments.
*/
toBeCalledWith(...expected: Array<unknown>): R;
/**
* Using exact equality with floating point numbers is a bad idea.
* Rounding means that intuitive things fail.
* The default for `precision` is 2.
*/
toBeCloseTo(expected: number, precision?: number): R;
/**
* Ensure that a variable is not undefined.
*/
toBeDefined(): R;
/**
* When you don't care what a value is, you just want to
* ensure a value is false in a boolean context.
*/
toBeFalsy(): R;
/**
* For comparing floating point numbers.
*/
toBeGreaterThan(expected: number | bigint): R;
/**
* For comparing floating point numbers.
*/
toBeGreaterThanOrEqual(expected: number | bigint): R;
/**
* Ensure that an object is an instance of a class.
* This matcher uses `instanceof` underneath.
*/
toBeInstanceOf(expected: unknown): R;
/**
* For comparing floating point numbers.
*/
toBeLessThan(expected: number | bigint): R;
/**
* For comparing floating point numbers.
*/
toBeLessThanOrEqual(expected: number | bigint): R;
/**
* Used to check that a variable is NaN.
*/
toBeNaN(): R;
/**
* This is the same as `.toBe(null)` but the error messages are a bit nicer.
* So use `.toBeNull()` when you want to check that something is null.
*/
toBeNull(): R;
/**
* Use when you don't care what a value is, you just want to ensure a value
* is true in a boolean context. In JavaScript, there are six falsy values:
* `false`, `0`, `''`, `null`, `undefined`, and `NaN`. Everything else is truthy.
*/
toBeTruthy(): R;
/**
* Used to check that a variable is undefined.
*/
toBeUndefined(): R;
/**
* Used when you want to check that an item is in a list.
* For testing the items in the list, this uses `===`, a strict equality check.
*/
toContain(expected: unknown): R;
/**
* Used when you want to check that an item is in a list.
* For testing the items in the list, this matcher recursively checks the
* equality of all fields, rather than checking for object identity.
*/
toContainEqual(expected: unknown): R;
/**
* Used when you want to check that two objects have the same value.
* This matcher recursively checks the equality of all fields, rather than checking for object identity.
*/
toEqual(expected: unknown): R;
/**
* Ensures that a mock function is called.
*/
toHaveBeenCalled(): R;
/**
* Ensures that a mock function is called an exact number of times.
*/
toHaveBeenCalledTimes(expected: number): R;
/**
* Ensure that a mock function is called with specific arguments.
*/
toHaveBeenCalledWith(...expected: Array<unknown>): R;
/**
* Ensure that a mock function is called with specific arguments on an Nth call.
*/
toHaveBeenNthCalledWith(nth: number, ...expected: Array<unknown>): R;
/**
* If you have a mock function, you can use `.toHaveBeenLastCalledWith`
* to test what arguments it was last called with.
*/
toHaveBeenLastCalledWith(...expected: Array<unknown>): R;
/**
* Use to test the specific value that a mock function last returned.
* If the last call to the mock function threw an error, then this matcher will fail
* no matter what value you provided as the expected return value.
*/
toHaveLastReturnedWith(expected?: unknown): R;
/**
* Used to check that an object has a `.length` property
* and it is set to a certain numeric value.
*/
toHaveLength(expected: number): R;
/**
* Use to test the specific value that a mock function returned for the nth call.
* If the nth call to the mock function threw an error, then this matcher will fail
* no matter what value you provided as the expected return value.
*/
toHaveNthReturnedWith(nth: number, expected?: unknown): R;
/**
* Use to check if property at provided reference keyPath exists for an object.
* For checking deeply nested properties in an object you may use dot notation or an array containing
* the keyPath for deep references.
*
* Optionally, you can provide a value to check if it's equal to the value present at keyPath
* on the target object. This matcher uses 'deep equality' (like `toEqual()`) and recursively checks
* the equality of all fields.
*
* @example
*
* expect(houseForSale).toHaveProperty('kitchen.area', 20);
*/
toHaveProperty(
expectedPath: string | Array<string>,
expectedValue?: unknown,
): R;
/**
* Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time
*/
toHaveReturned(): R;
/**
* Use to ensure that a mock function returned successfully (i.e., did not throw an error) an exact number of times.
* Any calls to the mock function that throw an error are not counted toward the number of times the function returned.
*/
toHaveReturnedTimes(expected: number): R;
/**
* Use to ensure that a mock function returned a specific value.
*/
toHaveReturnedWith(expected?: unknown): R;
/**
* Check that a string matches a regular expression.
*/
toMatch(expected: string | RegExp): R;
/**
* Used to check that a JavaScript object matches a subset of the properties of an object
*/
toMatchObject(
expected: Record<string, unknown> | Array<Record<string, unknown>>,
): R;
/**
* Ensure that a mock function has returned (as opposed to thrown) at least once.
*/
toReturn(): R;
/**
* Ensure that a mock function has returned (as opposed to thrown) a specified number of times.
*/
toReturnTimes(expected: number): R;
/**
* Ensure that a mock function has returned a specified value at least once.
*/
toReturnWith(expected?: unknown): R;
/**
* Use to test that objects have the same types as well as structure.
*/
toStrictEqual(expected: unknown): R;
/**
* Used to test that a function throws when it is called.
*/
toThrow(expected?: unknown): R;
/**
* If you want to test that a specific error is thrown inside a function.
*/
toThrowError(expected?: unknown): R;
}

View File

@ -14,7 +14,10 @@
* limitations under the License.
*/
export const expect: typeof import('../../bundles/expect/node_modules/expect/build').expect = require('./expectBundleImpl').expect;
export const expect: typeof import('../../bundles/expect/third_party/index').expect = require('./expectBundleImpl').expect;
export const mock: typeof import('../../bundles/expect/node_modules/jest-mock') = require('./expectBundleImpl').mock;
export const asymmetricMatchers = require('./expectBundleImpl').asymmetricMatchers;
export const matcherUtils = require('./expectBundleImpl').matcherUtils;
export const EXPECTED_COLOR: typeof import('../../bundles/expect/node_modules/jest-matcher-utils/build').EXPECTED_COLOR = require('./expectBundleImpl').EXPECTED_COLOR;
export const INVERTED_COLOR: typeof import('../../bundles/expect/node_modules/jest-matcher-utils/build').INVERTED_COLOR = require('./expectBundleImpl').INVERTED_COLOR;
export const RECEIVED_COLOR: typeof import('../../bundles/expect/node_modules/jest-matcher-utils/build').RECEIVED_COLOR = require('./expectBundleImpl').RECEIVED_COLOR;

View File

@ -26,12 +26,13 @@ export function ansi2html(text: string): string {
switch (code) {
case 0: style = {}; break;
case 1: style['font-weight'] = 'bold'; break;
case 2: style['opacity'] = '0.8'; break;
case 3: style['font-style'] = 'italic'; break;
case 4: style['text-decoration'] = 'underline'; break;
case 8: style.display = 'none'; break;
case 9: style['text-decoration'] = 'line-through'; break;
case 22: style = { ...style, 'font-weight': undefined, 'font-style': undefined, 'text-decoration': undefined }; break;
case 23: style = { ...style, 'font-weight': undefined, 'font-style': undefined }; break;
case 22: style = { ...style, 'font-weight': undefined, 'font-style': undefined, 'opacity': undefined, 'text-decoration': undefined }; break;
case 23: style = { ...style, 'font-weight': undefined, 'font-style': undefined, 'opacity': undefined }; break;
case 24: style = { ...style, 'text-decoration': undefined }; break;
case 30:
case 31:

View File

@ -23,6 +23,7 @@ import { TraceModel } from '../../packages/trace-viewer/src/traceModel';
import type { ActionTreeItem } from '../../packages/trace-viewer/src/ui/modelUtil';
import { buildActionTree, MultiTraceModel } from '../../packages/trace-viewer/src/ui/modelUtil';
import type { ActionTraceEvent, ConsoleMessageTraceEvent, EventTraceEvent, TraceEvent } from '@trace/trace';
import style from 'ansi-styles';
export async function attachFrame(page: Page, frameId: string, url: string): Promise<Frame> {
const handle = await page.evaluateHandle(async ({ frameId, url }) => {
@ -207,6 +208,40 @@ export function stripAnsi(str: string): string {
return str.replace(ansiRegex, '');
}
export function ansi2Markup(text: string): string {
return text.replace(ansiRegex, match => {
switch (match) {
case style.inverse.open:
return '<i>';
case style.inverse.close:
return '</i>';
case style.bold.open:
return '<b>';
case style.dim.open:
return '<d>';
case style.green.open:
return '<g>';
case style.red.open:
return '<r>';
case style.yellow.open:
return '<y>';
case style.bgYellow.open:
return '<Y>';
case style.bold.close:
case style.dim.close:
case style.green.close:
case style.red.close:
case style.yellow.close:
case style.bgYellow.close:
return '</>';
default:
return match; // unexpected escape sequence
}
});
}
class TraceBackend implements TraceModelBackend {
private _fileName: string;

View File

@ -0,0 +1,78 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
test.describe('.assertions()', () => {
test('does not throw', () => {
expectUnderTest.assertions(2);
expectUnderTest('a').not.toBe('b');
expectUnderTest('a').toBe('a');
});
test('redeclares different assertion count', () => {
expectUnderTest.assertions(3);
expectUnderTest('a').not.toBe('b');
expectUnderTest('a').toBe('a');
expectUnderTest.assertions(2);
});
test('expects no assertions', () => {
expectUnderTest.assertions(0);
});
});
test.describe('.hasAssertions()', () => {
test('does not throw if there is an assertion', () => {
expectUnderTest.hasAssertions();
expectUnderTest('a').toBe('a');
});
test('throws if expected is not undefined', () => {
expect(() =>
(expectUnderTest as any).hasAssertions(2)
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>)[.not].hasAssertions()</>
<b>Matcher error</>: this matcher must not have an expected argument
Expected has type: number
Expected has value: <g>2</>`);
});
});
test.describe('numPassingAsserts', () => {
test.skip('verify the default value of numPassingAsserts', () => {
const { numPassingAsserts } = expectUnderTest.getState();
expect(numPassingAsserts).toBe(0);
});
test('verify the resetting of numPassingAsserts after a test', () => {
expect('a').toBe('a');
expect('a').toBe('a');
// reset state
expectUnderTest.extractExpectedAssertionsErrors();
const { numPassingAsserts } = expectUnderTest.getState();
expect(numPassingAsserts).toBe(0);
});
test.skip('verify the correctness of numPassingAsserts count for passing test', () => {
expect('a').toBe('a');
expect('a').toBe('a');
const { numPassingAsserts } = expectUnderTest.getState();
expect(numPassingAsserts).toBe(2);
});
test.skip('verify the correctness of numPassingAsserts count for failing test', () => {
expect('a').toBe('a');
try {
expect('a').toBe('b');
} catch (error) { }
const { numPassingAsserts } = expectUnderTest.getState();
expect(numPassingAsserts).toBe(1);
});
});

View File

@ -0,0 +1,519 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test } from '../playwright-test/stable-test-runner';
import { expect as expectUnderTest, asymmetricMatchers } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
const {
any,
anything,
arrayContaining,
arrayNotContaining,
closeTo,
notCloseTo,
objectContaining,
objectNotContaining,
stringContaining,
stringMatching,
stringNotContaining,
stringNotMatching,
} = asymmetricMatchers;
test('Any.asymmetricMatch()', () => {
class Thing {}
[
any(String).asymmetricMatch('jest'),
any(Number).asymmetricMatch(1),
any(Function).asymmetricMatch(() => {}),
any(Boolean).asymmetricMatch(true),
any(BigInt).asymmetricMatch(1n),
any(Symbol).asymmetricMatch(Symbol()),
any(Object).asymmetricMatch({}),
any(Object).asymmetricMatch(null),
any(Array).asymmetricMatch([]),
any(Thing).asymmetricMatch(new Thing()),
].forEach(test => {
expectUnderTest(test).toBe(true);
});
});
test('Any.asymmetricMatch() on primitive wrapper classes', () => {
[
any(String).asymmetricMatch(new String('jest')),
any(Number).asymmetricMatch(new Number(1)),
any(Function).asymmetricMatch(new Function('() => {}')),
any(Boolean).asymmetricMatch(new Boolean(true)),
any(BigInt).asymmetricMatch(Object(1n)),
any(Symbol).asymmetricMatch(Object(Symbol())),
].forEach(test => {
expectUnderTest(test).toBe(true);
});
});
test('Any.toAsymmetricMatcher()', () => {
expectUnderTest(any(Number).toAsymmetricMatcher()).toBe('Any<Number>');
});
test('Any.toAsymmetricMatcher() with function name', () => {
[
['someFunc', function someFunc() {}],
['$someFunc', function $someFunc() {}],
[
'$someFunc2',
(function() {
function $someFunc2() {}
Object.defineProperty($someFunc2, 'name', { value: '' });
return $someFunc2;
})(),
],
[
'$someAsyncFunc',
(function() {
async function $someAsyncFunc() {}
Object.defineProperty($someAsyncFunc, 'name', { value: '' });
return $someAsyncFunc;
})(),
],
[
'$someGeneratorFunc',
(function() {
function* $someGeneratorFunc() {}
Object.defineProperty($someGeneratorFunc, 'name', { value: '' });
return $someGeneratorFunc;
})(),
],
[
'$someFuncWithFakeToString',
(function() {
function $someFuncWithFakeToString() {}
$someFuncWithFakeToString.toString = () => 'Fake to string';
return $someFuncWithFakeToString;
})(),
],
].forEach(([name, fn]) => {
expectUnderTest(any(fn).toAsymmetricMatcher()).toBe(`Any<${name}>`);
});
});
test('Any throws when called with empty constructor', () => {
// @ts-expect-error: Testing runtime error
expectUnderTest(() => any()).toThrow(
'any() expects to be passed a constructor function. Please pass one or use anything() to match any object.',
);
});
test('Anything matches any type', () => {
[
anything().asymmetricMatch('jest'),
anything().asymmetricMatch(1),
anything().asymmetricMatch(() => {}),
anything().asymmetricMatch(true),
anything().asymmetricMatch({}),
anything().asymmetricMatch([]),
].forEach(test => {
expectUnderTest(test).toBe(true);
});
});
test('Anything does not match null and undefined', () => {
[
anything().asymmetricMatch(null),
anything().asymmetricMatch(undefined),
].forEach(test => {
expectUnderTest(test).toBe(false);
});
});
test('Anything.toAsymmetricMatcher()', () => {
expectUnderTest(anything().toAsymmetricMatcher()).toBe('Anything');
});
test('ArrayContaining matches', () => {
[
arrayContaining([]).asymmetricMatch('jest'),
arrayContaining(['foo']).asymmetricMatch(['foo']),
arrayContaining(['foo']).asymmetricMatch(['foo', 'bar']),
arrayContaining([]).asymmetricMatch({}),
].forEach(test => {
expectUnderTest(test).toEqual(true);
});
});
test('ArrayContaining does not match', () => {
expectUnderTest(arrayContaining(['foo']).asymmetricMatch(['bar'])).toBe(false);
});
test('ArrayContaining throws for non-arrays', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
arrayContaining('foo').asymmetricMatch([]);
}).toThrow("You must provide an array to ArrayContaining, not 'string'.");
});
test('ArrayNotContaining matches', () => {
expectUnderTest(arrayNotContaining(['foo']).asymmetricMatch(['bar'])).toBe(true);
});
test('ArrayNotContaining does not match', () => {
[
arrayNotContaining([]).asymmetricMatch('jest'),
arrayNotContaining(['foo']).asymmetricMatch(['foo']),
arrayNotContaining(['foo']).asymmetricMatch(['foo', 'bar']),
arrayNotContaining([]).asymmetricMatch({}),
].forEach(test => {
expectUnderTest(test).toEqual(false);
});
});
test('ArrayNotContaining throws for non-arrays', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
arrayNotContaining('foo').asymmetricMatch([]);
}).toThrow("You must provide an array to ArrayNotContaining, not 'string'.");
});
test('ObjectContaining matches', () => {
const foo = Symbol('foo');
[
objectContaining({}).asymmetricMatch('jest'),
objectContaining({ foo: 'foo' }).asymmetricMatch({ foo: 'foo', jest: 'jest' }),
objectContaining({ foo: undefined }).asymmetricMatch({ foo: undefined }),
objectContaining({ first: objectContaining({ second: {} }) }).asymmetricMatch({
first: { second: {} },
}),
objectContaining({ foo: Buffer.from('foo') }).asymmetricMatch({
foo: Buffer.from('foo'),
jest: 'jest',
}),
objectContaining({ [foo]: 'foo' }).asymmetricMatch({ [foo]: 'foo' }),
].forEach(test => {
expectUnderTest(test).toEqual(true);
});
});
test('ObjectContaining does not match', () => {
const foo = Symbol('foo');
const bar = Symbol('bar');
[
objectContaining({ foo: 'foo' }).asymmetricMatch({ bar: 'bar' }),
objectContaining({ foo: 'foo' }).asymmetricMatch({ foo: 'foox' }),
objectContaining({ foo: undefined }).asymmetricMatch({}),
objectContaining({
answer: 42,
foo: { bar: 'baz', foobar: 'qux' },
}).asymmetricMatch({ foo: { bar: 'baz' } }),
objectContaining({ [foo]: 'foo' }).asymmetricMatch({ [bar]: 'bar' }),
].forEach(test => {
expectUnderTest(test).toEqual(false);
});
});
test('ObjectContaining matches defined properties', () => {
const definedPropertyObject = {};
Object.defineProperty(definedPropertyObject, 'foo', { get: () => 'bar' });
expectUnderTest(
objectContaining({ foo: 'bar' }).asymmetricMatch(definedPropertyObject),
).toBe(true);
});
test('ObjectContaining matches prototype properties', () => {
const prototypeObject = { foo: 'bar' };
let obj;
if (Object.create) {
obj = Object.create(prototypeObject);
} else {
function Foo() {}
Foo.prototype = prototypeObject;
Foo.prototype.constructor = Foo;
obj = new (Foo as any)();
}
expectUnderTest(objectContaining({ foo: 'bar' }).asymmetricMatch(obj)).toBe(true);
});
test('ObjectContaining throws for non-objects', () => {
// @ts-expect-error: Testing runtime error
expectUnderTest(() => objectContaining(1337).asymmetricMatch()).toThrow(
"You must provide an object to ObjectContaining, not 'number'.",
);
});
test('ObjectContaining does not mutate the sample', () => {
const sample = { foo: { bar: {} } };
const sample_json = JSON.stringify(sample);
expectUnderTest({ foo: { bar: {} } }).toEqual(expectUnderTest.objectContaining(sample));
expectUnderTest(JSON.stringify(sample)).toEqual(sample_json);
});
test('ObjectNotContaining matches', () => {
const foo = Symbol('foo');
const bar = Symbol('bar');
[
objectContaining({}).asymmetricMatch(null),
objectContaining({}).asymmetricMatch(undefined),
objectNotContaining({ [foo]: 'foo' }).asymmetricMatch({ [bar]: 'bar' }),
objectNotContaining({ foo: 'foo' }).asymmetricMatch({ bar: 'bar' }),
objectNotContaining({ foo: 'foo' }).asymmetricMatch({ foo: 'foox' }),
objectNotContaining({ foo: undefined }).asymmetricMatch({}),
objectNotContaining({
first: objectNotContaining({ second: {} }),
}).asymmetricMatch({ first: { second: {} } }),
objectNotContaining({ first: { second: {}, third: {} } }).asymmetricMatch({
first: { second: {} },
}),
objectNotContaining({ first: { second: {} } }).asymmetricMatch({
first: { second: {}, third: {} },
}),
objectNotContaining({ foo: 'foo', jest: 'jest' }).asymmetricMatch({
foo: 'foo',
}),
].forEach(test => {
expectUnderTest(test).toEqual(true);
});
});
test('ObjectNotContaining does not match', () => {
[
objectNotContaining({}).asymmetricMatch('jest'),
objectNotContaining({ foo: 'foo' }).asymmetricMatch({
foo: 'foo',
jest: 'jest',
}),
objectNotContaining({ foo: undefined }).asymmetricMatch({ foo: undefined }),
objectNotContaining({ first: { second: {} } }).asymmetricMatch({
first: { second: {} },
}),
objectNotContaining({
first: objectContaining({ second: {} }),
}).asymmetricMatch({ first: { second: {} } }),
objectNotContaining({}).asymmetricMatch(null),
objectNotContaining({}).asymmetricMatch(undefined),
objectNotContaining({}).asymmetricMatch({}),
].forEach(test => {
expectUnderTest(test).toEqual(false);
});
});
test('ObjectNotContaining inverts ObjectContaining', () => {
(
[
[{}, null],
[{ foo: 'foo' }, { foo: 'foo', jest: 'jest' }],
[{ foo: 'foo', jest: 'jest' }, { foo: 'foo' }],
[{ foo: undefined }, { foo: undefined }],
[{ foo: undefined }, {}],
[{ first: { second: {} } }, { first: { second: {} } }],
[{ first: objectContaining({ second: {} }) }, { first: { second: {} } }],
[{ first: objectNotContaining({ second: {} }) }, { first: { second: {} } }],
[{}, { foo: undefined }],
] as const
).forEach(([sample, received]) => {
expectUnderTest(objectNotContaining(sample).asymmetricMatch(received)).toEqual(
!objectContaining(sample).asymmetricMatch(received),
);
});
});
test('ObjectNotContaining throws for non-objects', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
objectNotContaining(1337).asymmetricMatch();
}).toThrow(
"You must provide an object to ObjectNotContaining, not 'number'.",
);
});
test('StringContaining matches string against string', () => {
expectUnderTest(stringContaining('en*').asymmetricMatch('queen*')).toBe(true);
expectUnderTest(stringContaining('en').asymmetricMatch('queue')).toBe(false);
});
test('StringContaining throws if expected value is not string', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
stringContaining([1]).asymmetricMatch('queen');
}).toThrow('Expected is not a string');
});
test('StringContaining returns false if received value is not string', () => {
expectUnderTest(stringContaining('en*').asymmetricMatch(1)).toBe(false);
});
test('StringNotContaining matches string against string', () => {
expectUnderTest(stringNotContaining('en*').asymmetricMatch('queen*')).toBe(false);
expectUnderTest(stringNotContaining('en').asymmetricMatch('queue')).toBe(true);
});
test('StringNotContaining throws if expected value is not string', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
stringNotContaining([1]).asymmetricMatch('queen');
}).toThrow('Expected is not a string');
});
test('StringNotContaining returns true if received value is not string', () => {
expectUnderTest(stringNotContaining('en*').asymmetricMatch(1)).toBe(true);
});
test('StringMatching matches string against regexp', () => {
expectUnderTest(stringMatching(/en/).asymmetricMatch('queen')).toBe(true);
expectUnderTest(stringMatching(/en/).asymmetricMatch('queue')).toBe(false);
});
test('StringMatching matches string against string', () => {
expectUnderTest(stringMatching('en').asymmetricMatch('queen')).toBe(true);
expectUnderTest(stringMatching('en').asymmetricMatch('queue')).toBe(false);
});
test('StringMatching throws if expected value is neither string nor regexp', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
stringMatching([1]).asymmetricMatch('queen');
}).toThrow('Expected is not a String or a RegExp');
});
test('StringMatching returns false if received value is not string', () => {
expectUnderTest(stringMatching('en').asymmetricMatch(1)).toBe(false);
});
test('StringMatching returns false even if coerced non-string received value matches pattern', () => {
expectUnderTest(stringMatching('null').asymmetricMatch(null)).toBe(false);
});
test('StringNotMatching matches string against regexp', () => {
expectUnderTest(stringNotMatching(/en/).asymmetricMatch('queen')).toBe(false);
expectUnderTest(stringNotMatching(/en/).asymmetricMatch('queue')).toBe(true);
});
test('StringNotMatching matches string against string', () => {
expectUnderTest(stringNotMatching('en').asymmetricMatch('queen')).toBe(false);
expectUnderTest(stringNotMatching('en').asymmetricMatch('queue')).toBe(true);
});
test('StringNotMatching throws if expected value is neither string nor regexp', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
stringNotMatching([1]).asymmetricMatch('queen');
}).toThrow('Expected is not a String or a RegExp');
});
test('StringNotMatching returns true if received value is not string', () => {
expectUnderTest(stringNotMatching('en').asymmetricMatch(1)).toBe(true);
});
test.describe('closeTo', () => {
[
[0, 0],
[0, 0.001],
[1.23, 1.229],
[1.23, 1.226],
[1.23, 1.225],
[1.23, 1.234],
[Infinity, Infinity],
[-Infinity, -Infinity],
].forEach(([expected, received]) => {
test(`${expected} closeTo ${received} return true`, () => {
expectUnderTest(closeTo(expected).asymmetricMatch(received)).toBe(true);
});
test(`${expected} notCloseTo ${received} return false`, () => {
expectUnderTest(notCloseTo(expected).asymmetricMatch(received)).toBe(false);
});
});
[
[0, 0.01],
[1, 1.23],
[1.23, 1.2249999],
[Infinity, -Infinity],
[Infinity, 1.23],
[-Infinity, -1.23],
].forEach(([expected, received]) => {
test(`${expected} closeTo ${received} return false`, () => {
expectUnderTest(closeTo(expected).asymmetricMatch(received)).toBe(false);
});
test(`${expected} notCloseTo ${received} return true`, () => {
expectUnderTest(notCloseTo(expected).asymmetricMatch(received)).toBe(true);
});
});
[
[0, 0.1, 0],
[0, 0.0001, 3],
[0, 0.000004, 5],
[2.0000002, 2, 5],
].forEach(([expected, received, precision]) => {
test(`${expected} closeTo ${received} with precision ${precision} return true`, () => {
expectUnderTest(closeTo(expected, precision).asymmetricMatch(received)).toBe(
true,
);
});
test(`${expected} notCloseTo ${received} with precision ${precision} return false`, () => {
expectUnderTest(
notCloseTo(expected, precision).asymmetricMatch(received),
).toBe(false);
});
});
[
[3.141592e-7, 3e-7, 8],
[56789, 51234, -4],
].forEach(([expected, received, precision]) => {
test(`${expected} closeTo ${received} with precision ${precision} return false`, () => {
expectUnderTest(closeTo(expected, precision).asymmetricMatch(received)).toBe(
false,
);
});
test(`${expected} notCloseTo ${received} with precision ${precision} return true`, () => {
expectUnderTest(
notCloseTo(expected, precision).asymmetricMatch(received),
).toBe(true);
});
});
test('closeTo throw if expected is not number', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
closeTo('a');
}).toThrow('Expected is not a Number');
});
test('notCloseTo throw if expected is not number', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
notCloseTo('a');
}).toThrow('Expected is not a Number');
});
test('closeTo throw if precision is not number', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
closeTo(1, 'a');
}).toThrow('Precision is not a Number');
});
test('notCloseTo throw if precision is not number', () => {
expectUnderTest(() => {
// @ts-expect-error: Testing runtime error
notCloseTo(1, 'a');
}).toThrow('Precision is not a Number');
});
test('closeTo return false if received is not number', () => {
expectUnderTest(closeTo(1).asymmetricMatch('a')).toBe(false);
});
test('notCloseTo return false if received is not number', () => {
expectUnderTest(notCloseTo(1).asymmetricMatch('a')).toBe(false);
});
});

View File

@ -0,0 +1,197 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest, mock } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
class Volume {
public amount: number;
public unit: 'L' | 'mL';
constructor(amount: number, unit: 'L' | 'mL') {
this.amount = amount;
this.unit = unit;
}
toString(): string {
return `[Volume ${this.amount}${this.unit}]`;
}
equals(other: Volume): boolean {
if (this.unit === other.unit)
return this.amount === other.amount;
else if (this.unit === 'L' && other.unit === 'mL')
return this.amount * 1000 === other.amount;
else
return this.amount === other.amount * 1000;
}
}
function createVolume(amount: number, unit: 'L' | 'mL' = 'L') {
return new Volume(amount, unit);
}
function isVolume(a: unknown): a is Volume {
return a instanceof Volume;
}
const areVolumesEqual = (
a: unknown,
b: unknown,
): boolean | undefined => {
const isAVolume = isVolume(a);
const isBVolume = isVolume(b);
if (isAVolume && isBVolume)
return a.equals(b);
else if (isAVolume !== isBVolume)
return false;
else
return undefined;
};
function* toIterator<T>(array: Array<T>): Iterator<T> {
for (const obj of array)
yield obj;
}
expectUnderTest.extend({
toEqualVolume(expected: Volume, actual: Volume) {
const result = this.equals(expected, actual, this.customTesters);
return {
message: () =>
`Expected Volume object: ${expected.toString()}. Actual Volume object: ${actual.toString()}`,
pass: result,
};
},
});
// Create Volumes with different specifications but the same value for use in
// tests. Without the custom tester, these volumes would not be equal because
// their properties have different values. However, with our custom tester they
// are equal.
const volume1 = createVolume(1, 'L');
const volume2 = createVolume(1000, 'mL');
const volumeArg1 = createVolume(1, 'L');
const volumeArg2 = createVolume(1000, 'mL');
const volumeArg3 = createVolume(2, 'L');
const volumeArg4 = createVolume(2000, 'mL');
const volumeReturn1 = createVolume(2, 'L');
const volumeReturn2 = createVolume(2000, 'mL');
const testArgs = [volumeArg1, volumeArg2, [volumeArg3, volumeArg4]];
// Swap the order of args to assert custom tester sees these volumes as equal
const expectedArgs = [volumeArg2, volumeArg1, [volumeArg4, volumeArg3]];
expectUnderTest.addEqualityTesters([areVolumesEqual]);
test.describe('with custom equality testers', () => {
test('basic matchers customTesters do not apply to still do not pass different Volume objects', () => {
expectUnderTest(volume1).not.toBe(volume2);
expectUnderTest([volume1]).not.toContain(volume2);
});
test('basic matchers pass different Volume objects', () => {
expectUnderTest(volume1).toEqual(volume1);
expectUnderTest(volume1).toEqual(volume2);
expectUnderTest([volume1, volume2]).toEqual([volume2, volume1]);
expectUnderTest(new Map([['key', volume1]])).toEqual(new Map([['key', volume2]]));
expectUnderTest(new Set([volume1])).toEqual(new Set([volume2]));
expectUnderTest(toIterator([volume1, volume2])).toEqual(
toIterator([volume2, volume1]),
);
expectUnderTest([volume1]).toContainEqual(volume2);
expectUnderTest({ a: volume1 }).toHaveProperty('a', volume2);
expectUnderTest({ a: volume1, b: undefined }).toStrictEqual({
a: volume2,
b: undefined,
});
expectUnderTest({ a: 1, b: { c: volume1 } }).toMatchObject({
a: 1,
b: { c: volume2 },
});
});
test('asymmetric matchers pass different Volume objects', () => {
expectUnderTest([volume1]).toEqual(expectUnderTest.arrayContaining([volume2]));
expectUnderTest({ a: 1, b: { c: volume1 } }).toEqual(
expectUnderTest.objectContaining({ b: { c: volume2 } }),
);
});
test('spy matchers pass different Volume objects', () => {
const mockFn = mock.fn<(...args: Array<unknown>) => unknown>(
() => volumeReturn1,
);
mockFn(...testArgs);
expectUnderTest(mockFn).toHaveBeenCalledWith(...expectedArgs);
expectUnderTest(mockFn).toHaveBeenLastCalledWith(...expectedArgs);
expectUnderTest(mockFn).toHaveBeenNthCalledWith(1, ...expectedArgs);
expectUnderTest(mockFn).toHaveReturnedWith(volumeReturn2);
expectUnderTest(mockFn).toHaveLastReturnedWith(volumeReturn2);
expectUnderTest(mockFn).toHaveNthReturnedWith(1, volumeReturn2);
});
test('custom matchers pass different Volume objects', () => {
(expectUnderTest as any)(volume1).toEqualVolume(volume2);
});
test('toBe recommends toStrictEqual even with different Volume objects', () => {
expectUnderTest(() => expectUnderTest(volume1).toBe(volume2)).toThrow('toStrictEqual');
});
test('toBe recommends toEqual even with different Volume objects', () => {
expectUnderTest(() => expectUnderTest({ a: undefined, b: volume1 }).toBe({ b: volume2 })).toThrow(
'toEqual',
);
});
test('toContains recommends toContainEquals even with different Volume objects', () => {
expectUnderTest(() => expectUnderTest([volume1]).toContain(volume2)).toThrow(
'toContainEqual',
);
});
test('toMatchObject error shows Volume objects as equal', () => {
expect(() =>
expectUnderTest({ a: 1, b: volume1 }).toMatchObject({ a: 2, b: volume2 })
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toMatchObject<d>(</><g>expected</><d>)</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "a": 2,</>
<r>+ "a": 1,</>
<d> "b": Volume {</>
<d> "amount": 1000,</>
<d> "unit": "mL",</>
<d> },</>
<d> }</>`);
});
test('iterableEquality still properly detects cycles', () => {
const a = new Set();
a.add(volume1);
a.add(a);
const b = new Set();
b.add(volume2);
b.add(b);
expectUnderTest(a).toEqual(b);
});
});

View File

@ -0,0 +1,246 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest, mock } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
// Test test file demonstrates and tests the capability of recursive custom
// testers that call `equals` within their tester logic. These testers should
// receive the array of custom testers and be able to pass it into equals
const CONNECTION_PROP = '__connection';
type DbConnection = number;
let DbConnectionId = 0;
class Author {
public name: string;
public [CONNECTION_PROP]: DbConnection;
constructor(name: string) {
this.name = name;
this[CONNECTION_PROP] = DbConnectionId++;
}
}
class Book {
public name: string;
public authors: Array<Author>;
public [CONNECTION_PROP]: DbConnection;
constructor(name: string, authors: Array<Author>) {
this.name = name;
this.authors = authors;
this[CONNECTION_PROP] = DbConnectionId++;
}
}
const areAuthorsEqual = (a: unknown, b: unknown) => {
const isAAuthor = a instanceof Author;
const isBAuthor = b instanceof Author;
if (isAAuthor && isBAuthor)
return a.name === b.name;
else if (isAAuthor !== isBAuthor)
return false;
else
return undefined;
};
const areBooksEqual = function(
a: unknown,
b: unknown,
customTesters: [],
) {
const isABook = a instanceof Book;
const isBBook = b instanceof Book;
if (isABook && isBBook) {
return (
a.name === b.name && this.equals(a.authors, b.authors, customTesters)
);
} else if (isABook !== isBBook) {
return false;
} else {
return undefined;
}
};
function* toIterator<T>(array: Array<T>): Iterator<T> {
for (const obj of array)
yield obj;
}
expectUnderTest.extend({
toEqualBook(expected: Book, actual: Book) {
const result = this.equals(expected, actual, this.customTesters);
return {
message: () =>
`Expected Book object: ${expected.name}. Actual Book object: ${actual.name}`,
pass: result,
};
},
});
// Create books with the same name and authors for use in tests. Without the
// custom tester, these books would not be equal because their DbConnections
// would have different values. However, with our custom tester they are equal.
const book1 = new Book('Book 1', [
new Author('Author 1'),
new Author('Author 2'),
]);
const book1b = new Book('Book 1', [
new Author('Author 1'),
new Author('Author 2'),
]);
const bookArg1a = new Book('Book Arg 1', [
new Author('Author Arg 1'),
new Author('Author Arg 2'),
]);
const bookArg1b = new Book('Book Arg 1', [
new Author('Author Arg 1'),
new Author('Author Arg 2'),
]);
const bookArg2a = new Book('Book Arg 2', [
new Author('Author Arg 3'),
new Author('Author Arg 4'),
]);
const bookArg2b = new Book('Book Arg 2', [
new Author('Author Arg 3'),
new Author('Author Arg 4'),
]);
const bookReturn1a = new Book('Book Return 1', [
new Author('Author Return 1'),
new Author('Author Return 2'),
]);
const bookReturn1b = new Book('Book Return 1', [
new Author('Author Return 1'),
new Author('Author Return 2'),
]);
const testArgs = [bookArg1a, bookArg1b, [bookArg2a, bookArg2b]];
// Swap the order of args to assert custom tester works correctly and ignores
// DbConnection differences
const expectedArgs = [bookArg1b, bookArg1a, [bookArg2b, bookArg2a]];
expectUnderTest.addEqualityTesters([areAuthorsEqual, areBooksEqual]);
test.describe('with custom equality testers', () => {
test('exposes an equality function to custom testers', () => {
const runTestSymbol = Symbol('run this test');
expectUnderTest.addEqualityTesters([
function dummyTester() {
return undefined;
},
]);
expectUnderTest(() =>
expectUnderTest(runTestSymbol).toEqual(runTestSymbol),
).not.toThrow();
});
test('basic matchers customTesters do not apply to still do not pass different Book objects', () => {
expectUnderTest(book1).not.toBe(book1b);
expectUnderTest([book1]).not.toContain(book1b);
});
test('basic matchers pass different Book objects', () => {
expectUnderTest(book1).toEqual(book1);
expectUnderTest(book1).toEqual(book1b);
expectUnderTest([book1, book1b]).toEqual([book1b, book1]);
expectUnderTest(new Map([['key', book1]])).toEqual(new Map([['key', book1b]]));
expectUnderTest(new Set([book1])).toEqual(new Set([book1b]));
expectUnderTest(toIterator([book1, book1b])).toEqual(toIterator([book1b, book1]));
expectUnderTest([book1]).toContainEqual(book1b);
expectUnderTest({ a: book1 }).toHaveProperty('a', book1b);
expectUnderTest({ a: book1, b: undefined }).toStrictEqual({
a: book1b,
b: undefined,
});
expectUnderTest({ a: 1, b: { c: book1 } }).toMatchObject({
a: 1,
b: { c: book1b },
});
});
test('asymmetric matchers pass different Book objects', () => {
expectUnderTest([book1]).toEqual(expect.arrayContaining([book1b]));
expectUnderTest({ a: 1, b: { c: book1 } }).toEqual(
expect.objectContaining({ b: { c: book1b } }),
);
});
test('spy matchers pass different Book objects', () => {
const mockFn = mock.fn<(...args: Array<unknown>) => unknown>(
() => bookReturn1a,
);
mockFn(...testArgs);
expectUnderTest(mockFn).toHaveBeenCalledWith(...expectedArgs);
expectUnderTest(mockFn).toHaveBeenLastCalledWith(...expectedArgs);
expectUnderTest(mockFn).toHaveBeenNthCalledWith(1, ...expectedArgs);
expectUnderTest(mockFn).toHaveReturnedWith(bookReturn1b);
expectUnderTest(mockFn).toHaveLastReturnedWith(bookReturn1b);
expectUnderTest(mockFn).toHaveNthReturnedWith(1, bookReturn1b);
});
test('custom matchers pass different Book objects', () => {
(expectUnderTest as any)(book1).toEqualBook(book1b);
});
test('toBe recommends toStrictEqual even with different Book objects', () => {
expectUnderTest(() => expectUnderTest(book1).toBe(book1b)).toThrow('toStrictEqual');
});
test('toBe recommends toEqual even with different Book objects', () => {
expectUnderTest(() => expectUnderTest({ a: undefined, b: book1 }).toBe({ b: book1b })).toThrow(
'toEqual',
);
});
test('toContains recommends toContainEquals even with different Book objects', () => {
expectUnderTest(() => expectUnderTest([book1]).toContain(book1b)).toThrow('toContainEqual');
});
test('toMatchObject error shows Book objects as equal', () => {
expect(() =>
expectUnderTest({ a: 1, b: book1 }).toMatchObject({ a: 2, b: book1b })
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toMatchObject<d>(</><g>expected</><d>)</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<y>@@ -1,7 +1,7 @@</>
<d> Object {</>
<g>- "a": 2,</>
<r>+ "a": 1,</>
<d> "b": Book {</>
<d> "__connection": 5,</>
<d> "authors": Array [</>
<d> Author {</>
<d> "__connection": 3,</>`);
});
test('iterableEquality still properly detects cycles', () => {
const a = new Set();
a.add(book1);
a.add(a);
const b = new Set();
b.add(book1b);
b.add(b);
expectUnderTest(a).toEqual(b);
});
});

247
tests/expect/extend.test.ts Normal file
View File

@ -0,0 +1,247 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
expectUnderTest.extend({
toBeDivisibleBy(actual: number, expected: number) {
const pass = actual % expected === 0;
const message: () => string = pass
? () =>
`expected ${this.utils.printReceived(
actual,
)} not to be divisible by ${expected}`
: () =>
`expected ${this.utils.printReceived(
actual,
)} to be divisible by ${expected}`;
return { message, pass };
},
toBeSymbol(actual: symbol, expected: symbol) {
const pass = actual === expected;
const message = () =>
`expected ${actual.toString()} to be Symbol ${expected.toString()}`;
return { message, pass };
},
toBeWithinRange(actual: number, floor: number, ceiling: number) {
const pass = actual >= floor && actual <= ceiling;
const message = pass
? () =>
`expected ${this.utils.printReceived(
actual,
)} not to be within range ${floor} - ${ceiling}`
: () =>
`expected ${this.utils.printReceived(
actual,
)} to be within range ${floor} - ${ceiling}`;
return { message, pass };
},
});
const expectUnderTestAsAny = expectUnderTest as any;
test('is available globally when matcher is unary', () => {
expectUnderTestAsAny(15).toBeDivisibleBy(5);
expectUnderTestAsAny(15).toBeDivisibleBy(3);
expectUnderTestAsAny(15).not.toBeDivisibleBy(6);
expect(() =>
expectUnderTestAsAny(15).toBeDivisibleBy(2),
).toThrowErrorMatchingSnapshot(`expected <r>15</> to be divisible by 2`);
});
test('is available globally when matcher is variadic', () => {
expectUnderTestAsAny(15).toBeWithinRange(10, 20);
expectUnderTestAsAny(15).not.toBeWithinRange(6, 10);
expect(() =>
expectUnderTestAsAny(15).toBeWithinRange(1, 3),
).toThrowErrorMatchingSnapshot(`expected <r>15</> to be within range 1 - 3`);
});
test.skip('exposes matcherUtils in context', () => {
// expectUnderTest.extend({
// shouldNotError(_actual: unknown) {
// const pass: boolean = this.equals(
// this.utils,
// Object.assign(matcherUtils, {
// iterableEquality,
// subsetEquality,
// }),
// );
// const message = pass
// ? () => 'expected this.utils to be defined in an extend call'
// : () => 'expected this.utils not to be defined in an extend call';
// return { message, pass };
// },
// });
// expectUnderTestAsAny('test').shouldNotError();
});
test('is ok if there is no message specified', () => {
expectUnderTest.extend({
toFailWithoutMessage(_expected: unknown) {
return { message: () => '', pass: false };
},
});
expect(() =>
expectUnderTestAsAny(true).toFailWithoutMessage(),
).toThrowErrorMatchingSnapshot(`<r>No message was specified for this matcher.</>`);
});
test('exposes an equality function to custom matchers', () => {
expectUnderTest.extend({
toBeOne(_expected: unknown) {
return { message: () => '', pass: !!this.equals(1, 1) };
},
});
expect(() => expectUnderTestAsAny('test').toBeOne()).not.toThrow();
});
test('defines asymmetric unary matchers', () => {
expect(() =>
expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.toBeDivisibleBy(2) }),
).not.toThrow();
expect(() =>
expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.toBeDivisibleBy(2) }),
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "value": toBeDivisibleBy<2>,</>
<r>+ "value": 3,</>
<d> }</>`);
});
test('defines asymmetric unary matchers that can be prefixed by not', () => {
expect(() =>
expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.not.toBeDivisibleBy(2) }),
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "value": not.toBeDivisibleBy<2>,</>
<r>+ "value": 2,</>
<d> }</>`);
expect(() =>
expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.not.toBeDivisibleBy(2) }),
).not.toThrow();
});
test('defines asymmetric variadic matchers', () => {
expect(() =>
expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.toBeWithinRange(1, 3) }),
).not.toThrow();
expect(() =>
expectUnderTest({ value: 3 }).toEqual({ value: expectUnderTestAsAny.toBeWithinRange(4, 11) }),
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "value": toBeWithinRange<4, 11>,</>
<r>+ "value": 3,</>
<d> }</>`);
});
test('defines asymmetric variadic matchers that can be prefixed by not', () => {
expect(() =>
expectUnderTest({ value: 2 }).toEqual({
value: expectUnderTestAsAny.not.toBeWithinRange(1, 3),
}),
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "value": not.toBeWithinRange<1, 3>,</>
<r>+ "value": 2,</>
<d> }</>`);
expect(() =>
expectUnderTest({ value: 3 }).toEqual({
value: expectUnderTestAsAny.not.toBeWithinRange(5, 7),
}),
).not.toThrow();
});
test('prints the Symbol into the error message', () => {
const foo = Symbol('foo');
const bar = Symbol('bar');
expect(() =>
expectUnderTest({ a: foo }).toEqual({
a: expectUnderTestAsAny.toBeSymbol(bar),
}),
).toThrowErrorMatchingSnapshot(`<d>expect(</><r>received</><d>).</>toEqual<d>(</><g>expected</><d>) // deep equality</>
<g>- Expected - 1</>
<r>+ Received + 1</>
<d> Object {</>
<g>- "a": toBeSymbol<Symbol(bar)>,</>
<r>+ "a": Symbol(foo),</>
<d> }</>`);
});
test('allows overriding existing extension', () => {
expectUnderTest.extend({
toAllowOverridingExistingMatcher(_expected: unknown) {
return { message: () => '', pass: _expected === 'bar' };
},
});
expectUnderTestAsAny('foo').not.toAllowOverridingExistingMatcher();
expectUnderTest.extend({
toAllowOverridingExistingMatcher(_expected: unknown) {
return { message: () => '', pass: _expected === 'foo' };
},
});
expectUnderTestAsAny('foo').toAllowOverridingExistingMatcher();
});
test('throws descriptive errors for invalid matchers', () => {
expect(() =>
expectUnderTest.extend({
default: undefined,
}),
).toThrow(
'expect.extend: `default` is not a valid matcher. Must be a function, is "undefined"',
);
expect(() =>
expectUnderTest.extend({
// @ts-expect-error: Testing runtime error
default: 42,
}),
).toThrow(
'expect.extend: `default` is not a valid matcher. Must be a function, is "number"',
);
expect(() =>
expectUnderTest.extend({
// @ts-expect-error: Testing runtime error
default: 'foobar',
}),
).toThrow(
'expect.extend: `default` is not a valid matcher. Must be a function, is "string"',
);
});

108
tests/expect/fixtures.ts Normal file
View File

@ -0,0 +1,108 @@
/*
Copyright (c) Microsoft Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import fs from 'fs';
import { ansi2Markup } from 'tests/config/utils';
import { expect as baseExpect } from '../playwright-test/stable-test-runner';
import { test } from '../playwright-test/stable-test-runner';
export { test } from '../playwright-test/stable-test-runner';
const ordinals = new Map<string, number>();
const snapshotFiles = new Set<string>();
function checkExpectation(unformatted: string, inlineExpected?: string) {
const actual = ansi2Markup(unformatted);
const file = test.info().file.replace('.test.ts', '.snapshots.js');
const fullKey = test.info().titlePath.join('|');
const ordinal = ordinals.get(fullKey) || 0;
ordinals.set(fullKey, ordinal + 1);
const key = test.info().titlePath.slice(1).join(' ') + (ordinal ? ` #${ordinal}` : '');
if (!inlineExpected && test.info().config.updateSnapshots === 'all') {
if (!snapshotFiles.has(file)) {
fs.writeFileSync(file, '');
snapshotFiles.add(file);
}
const line = `module.exports[${JSON.stringify(key)}] = \`${actual.replace(/\\/g, '\\\\').replace(/`/g, '\\`')}\`;\n\n`;
fs.appendFileSync(file, line);
return { message: () => '', pass: true };
}
let expected: string;
if (inlineExpected) {
expected = inlineExpected;
} else {
const data = require(file);
expected = data[key];
}
let pass: boolean;
let matcherResult: any;
try {
baseExpect(actual).toBe(expected);
pass = true;
} catch (e: any) {
matcherResult = e.matcherResult;
pass = false;
}
const expectOptions = {
isNot: this.isNot,
};
const message = pass
? () => this.utils.matcherHint('toBe', actual, expected, expectOptions) +
'\n\n' +
`Expected: ${this.isNot ? 'not' : ''}${this.utils.printExpected(expected)}\n` +
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '')
: () => this.utils.matcherHint('toBe', actual, expected, expectOptions) +
'\n\n' +
`Expected: ${this.utils.printExpected(expected)}\n` +
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '');
return {
name: 'toThrowErrorMatching',
expected,
message,
pass,
actual: matcherResult?.actual,
};
}
export const expect = baseExpect.extend({
toMatchSnapshot(message: string, expected?: string) {
return checkExpectation.call(this, message, expected);
},
toThrowErrorMatchingSnapshot(callback: () => any, expected?: string) {
try {
callback();
} catch (e) {
return checkExpectation.call(this, e.message, expected);
}
throw new Error('Expected function to throw, but it did not');
},
async toThrowErrorMatchingSnapshotAsync(callback: () => Promise<any>, expected?: string) {
try {
await callback();
} catch (e) {
return checkExpectation.call(this, e.message, expected);
}
throw new Error('Expected function to throw, but it did not');
}
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
const expectUnderTestAsAny = expectUnderTest as any;
expectUnderTest.extend({
toCustomMatch(callback: () => unknown, expected: unknown) {
const actual = callback();
if (actual !== expected) {
return {
message: () => `Expected "${expected}" but got "${actual}"`,
pass: false,
};
}
return {
message: () => '',
pass: true,
};
},
toMatchPredicate(received: unknown, expected: (a: unknown) => void) {
expected(received);
return {
message: () => '',
pass: true,
};
},
});
test('stack trace points to correct location when using matchers', () => {
try {
expectUnderTest(true).toBe(false);
} catch (error: any) {
expect(error.stack).toContain('stacktrace.test.ts:');
}
});
test('stack trace points to correct location when using nested matchers', () => {
try {
expectUnderTestAsAny(true).toMatchPredicate((value: unknown) => {
expectUnderTest(value).toBe(false);
});
} catch (error: any) {
expect(error.stack).toContain('stacktrace.test.ts:');
}
});
test('stack trace points to correct location when throwing from a custom matcher', () => {
try {
expectUnderTestAsAny(() => {
const foo = () => bar();
const bar = () => baz();
const baz = () => {
throw new Error('Expected');
};
foo();
}).toCustomMatch('bar');
} catch (error: any) {
expect(error.stack).toContain('stacktrace.test.ts:');
}
});

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { test } from './fixtures';
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
test.describe('Symbol in objects', () => {
test('should compare objects with Symbol keys', () => {
const sym = Symbol('foo');
const obj1 = { [sym]: 'one' };
const obj2 = { [sym]: 'two' };
const obj3 = { [sym]: 'one' };
expectUnderTest(obj1).toEqual(obj3);
expectUnderTest(obj1).not.toEqual(obj2);
});
test('should compare objects with mixed keys and Symbol', () => {
const sym = Symbol('foo2');
const obj1 = { foo: 2, [sym]: 'one' };
const obj2 = { foo: 2, [sym]: 'two' };
const obj3 = { foo: 2, [sym]: 'one' };
expectUnderTest(obj1).toEqual(obj3);
expectUnderTest(obj1).not.toEqual(obj2);
});
test('should compare objects with different Symbol keys', () => {
const sym = Symbol('foo');
const sym2 = Symbol('foo');
const obj1 = { [sym]: 'one' };
const obj2 = { [sym2]: 'one' };
const obj3 = { [sym]: 'one' };
expectUnderTest(obj1).toEqual(obj3);
expectUnderTest(obj1).not.toEqual(obj2);
});
});

View File

@ -0,0 +1,456 @@
module.exports["toThrowError substring did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected substring: <g>"apple"</>
Received function did not throw`;
module.exports["toThrowError substring threw, but message did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected substring: <g>"banana"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError substring threw, but message did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected substring: <g>"Server Error"</>
Received value: <r>""</>
`;
module.exports["toThrowError substring threw, but message should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected substring: not <g>"array"</>
Received message: <r>"Invalid <i>array</i> length"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError substring threw, but message should not match (non-error truthy)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected substring: not <g>"Server Error"</>
Received value: <r>"Internal Server Error"</>
`;
module.exports["toThrowError regexp did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected pattern: <g>/apple/</>
Received function did not throw`;
module.exports["toThrowError regexp threw, but message did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected pattern: <g>/banana/</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError regexp threw, but message did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected pattern: <g>/^[123456789]\\d*/</>
Received value: <r>0</>
`;
module.exports["toThrowError regexp threw, but message should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected pattern: not <g>/ array /</>
Received message: <r>"Invalid<i> array </i>length"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError regexp threw, but message should not match (non-error truthy)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected pattern: not <g>/^[123456789]\\d*/</>
Received value: <r>404</>
`;
module.exports["toThrowError error class did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err</>
Received function did not throw`;
module.exports["toThrowError error class threw, but class did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err2</>
Received constructor: <r>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError error class threw, but class did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err2</>
Received value: <r>undefined</>
`;
module.exports["toThrowError error class threw, but class should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError error class threw, but class should not match (error subclass)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received constructor: <r>SubErr</> extends <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError error class threw, but class should not match (error subsubclass)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received constructor: <r>SubSubErr</> extends … extends <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError error-message fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected message: <g>"apple"</>
Received message: <r>"banana"</>
`;
module.exports["toThrowError error-message fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected message: not <g>"Invalid array length"</>
`;
module.exports["toThrowError error-message fail multiline diff highlight incorrect expected space"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
<g>- Expected message - 1</>
<r>+ Received message + 1</>
<g>- There is no route defined for key Settings.<i> </i></>
<r>+ There is no route defined for key Settings.</>
<d> Must be one of: 'Home'</>
`;
module.exports["toThrowError asymmetric any-Class fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>Any<Err2></>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric any-Class fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>Any<Err></>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric anything fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>Anything</>
Thrown value: <r>null</>
`;
module.exports["toThrowError asymmetric anything fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>Anything</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric no-symbol fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>{"asymmetricMatch": [Function asymmetricMatch]}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric no-symbol fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>{"asymmetricMatch": [Function asymmetricMatch]}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric objectContaining fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>ObjectContaining {"name": "NotError"}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError asymmetric objectContaining fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>ObjectContaining {"name": "Error"}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrowError promise/async throws if Error-like object is returned did not throw at all"] = `callback is not a function`;
module.exports["toThrowError promise/async throws if Error-like object is returned threw, but class did not match"] = `callback is not a function`;
module.exports["toThrowError promise/async throws if Error-like object is returned threw, but should not have"] = `callback is not a function`;
module.exports["toThrowError expected is undefined threw, but should not have (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>()</>
Thrown value: <r>null</>
`;
module.exports["toThrowError invalid arguments"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrowError<d>(</><g>expected</><d>)</>
<b>Matcher error</>: <g>expected</> value must be a string or regular expression or class or error
Expected has type: number
Expected has value: <g>111</>`;
module.exports["toThrowError invalid actual"] = `<d>expect(</><r>received</><d>).</>toThrowError<d>()</>
<b>Matcher error</>: <r>received</> value must be a function
Received has type: string
Received has value: <r>"a string"</>`;
module.exports["toThrow substring did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected substring: <g>"apple"</>
Received function did not throw`;
module.exports["toThrow substring threw, but message did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected substring: <g>"banana"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow substring threw, but message did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected substring: <g>"Server Error"</>
Received value: <r>""</>
`;
module.exports["toThrow substring threw, but message should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected substring: not <g>"array"</>
Received message: <r>"Invalid <i>array</i> length"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow substring threw, but message should not match (non-error truthy)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected substring: not <g>"Server Error"</>
Received value: <r>"Internal Server Error"</>
`;
module.exports["toThrow regexp did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected pattern: <g>/apple/</>
Received function did not throw`;
module.exports["toThrow regexp threw, but message did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected pattern: <g>/banana/</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow regexp threw, but message did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected pattern: <g>/^[123456789]\\d*/</>
Received value: <r>0</>
`;
module.exports["toThrow regexp threw, but message should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected pattern: not <g>/ array /</>
Received message: <r>"Invalid<i> array </i>length"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow regexp threw, but message should not match (non-error truthy)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected pattern: not <g>/^[123456789]\\d*/</>
Received value: <r>404</>
`;
module.exports["toThrow error class did not throw at all"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err</>
Received function did not throw`;
module.exports["toThrow error class threw, but class did not match (error)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err2</>
Received constructor: <r>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow error class threw, but class did not match (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: <g>Err2</>
Received value: <r>undefined</>
`;
module.exports["toThrow error class threw, but class should not match (error)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow error class threw, but class should not match (error subclass)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received constructor: <r>SubErr</> extends <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow error class threw, but class should not match (error subsubclass)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected constructor: not <g>Err</>
Received constructor: <r>SubSubErr</> extends … extends <g>Err</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow error-message fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected message: <g>"apple"</>
Received message: <r>"banana"</>
`;
module.exports["toThrow error-message fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected message: not <g>"Invalid array length"</>
`;
module.exports["toThrow error-message fail multiline diff highlight incorrect expected space"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
<g>- Expected message - 1</>
<r>+ Received message + 1</>
<g>- There is no route defined for key Settings.<i> </i></>
<r>+ There is no route defined for key Settings.</>
<d> Must be one of: 'Home'</>
`;
module.exports["toThrow asymmetric any-Class fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>Any<Err2></>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric any-Class fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>Any<Err></>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric anything fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>Anything</>
Thrown value: <r>null</>
`;
module.exports["toThrow asymmetric anything fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>Anything</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric no-symbol fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>{"asymmetricMatch": [Function asymmetricMatch]}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric no-symbol fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>{"asymmetricMatch": [Function asymmetricMatch]}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric objectContaining fail isNot false"] = `<d>expect(</><r>received</><d>).</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: <g>ObjectContaining {"name": "NotError"}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow asymmetric objectContaining fail isNot true"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
Expected asymmetric matcher: not <g>ObjectContaining {"name": "Error"}</>
Received name: <r>"Error"</>
Received message: <r>"apple"</>
<d>at expectUnderTest (</>packages/expect/src/__tests__/toThrowMatchers-test.js<d>:24:74)</>`;
module.exports["toThrow promise/async throws if Error-like object is returned did not throw at all"] = `callback is not a function`;
module.exports["toThrow promise/async throws if Error-like object is returned threw, but class did not match"] = `callback is not a function`;
module.exports["toThrow promise/async throws if Error-like object is returned threw, but should not have"] = `callback is not a function`;
module.exports["toThrow expected is undefined threw, but should not have (non-error falsey)"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>()</>
Thrown value: <r>null</>
`;
module.exports["toThrow invalid arguments"] = `<d>expect(</><r>received</><d>).</>not<d>.</>toThrow<d>(</><g>expected</><d>)</>
<b>Matcher error</>: <g>expected</> value must be a string or regular expression or class or error
Expected has type: number
Expected has value: <g>111</>`;
module.exports["toThrow invalid actual"] = `<d>expect(</><r>received</><d>).</>toThrow<d>()</>
<b>Matcher error</>: <r>received</> value must be a function
Received has type: string
Received has value: <r>"a string"</>`;

View File

@ -0,0 +1,591 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { test, expect } from './fixtures';
import { expect as expectUnderTest } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
const expectUnderTestAsAny = expectUnderTest as any;
// Custom Error class because node versions have different stack trace strings.
class CustomError extends Error {
constructor(message?: string) {
super(message);
this.name = 'Error';
this.stack =
'Error\n' +
' at expectUnderTest' +
' (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)';
}
}
for (const toThrow of ['toThrowError', 'toThrow'] as const) {
test.describe(toThrow, () => {
class Err extends CustomError {}
class Err2 extends CustomError {}
test('to throw or not to throw', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow]();
expectUnderTest(() => {}).not[toThrow]();
});
test.describe('substring', () => {
test('passes', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow]('apple');
expectUnderTest(() => {
throw new CustomError('banana');
}).not[toThrow]('apple');
expectUnderTest(() => {}).not[toThrow]('apple');
});
test('did not throw at all', () => {
expect(() =>
expectUnderTest(() => {})[toThrow]('apple'),
).toThrowErrorMatchingSnapshot();
});
test('threw, but message did not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow]('banana');
}).toThrowErrorMatchingSnapshot();
});
test('threw, but message did not match (non-error falsey)', () => {
expect(() => {
expectUnderTest(() => {
throw '';
})[toThrow]('Server Error');
}).toThrowErrorMatchingSnapshot();
});
test('properly escapes strings when matching against errors', () => {
expectUnderTest(() => {
throw new TypeError('"this"? throws.');
})[toThrow]('"this"? throws.');
});
test('threw, but message should not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new CustomError('Invalid array length');
}).not[toThrow]('array');
}).toThrowErrorMatchingSnapshot();
});
test('threw, but message should not match (non-error truthy)', () => {
expect(() => {
expectUnderTest(() => {
throw 'Internal Server Error';
}).not[toThrow]('Server Error');
}).toThrowErrorMatchingSnapshot();
});
});
test.describe('regexp', () => {
test('passes', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](/apple/);
expectUnderTest(() => {
throw new CustomError('banana');
}).not[toThrow](/apple/);
expectUnderTest(() => {}).not[toThrow](/apple/);
});
test('did not throw at all', () => {
expect(() =>
expectUnderTest(() => {})[toThrow](/apple/),
).toThrowErrorMatchingSnapshot();
});
test('threw, but message did not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](/banana/);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but message did not match (non-error falsey)', () => {
expect(() => {
expectUnderTest(() => {
throw 0;
})[toThrow](/^[123456789]\d*/);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but message should not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new CustomError('Invalid array length');
}).not[toThrow](/ array /);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but message should not match (non-error truthy)', () => {
expect(() => {
expectUnderTest(() => {
throw 404;
}).not[toThrow](/^[123456789]\d*/);
}).toThrowErrorMatchingSnapshot();
});
});
test.describe('error class', () => {
class SubErr extends Err {
constructor(message?: string) {
super(message);
// In a carefully written error subclass,
// name property is equal to constructor name.
this.name = this.constructor.name;
}
}
class SubSubErr extends SubErr {
constructor(message?: string) {
super(message);
// In a carefully written error subclass,
// name property is equal to constructor name.
this.name = this.constructor.name;
}
}
test('passes', () => {
expectUnderTest(() => {
throw new Err();
})[toThrow](Err);
expectUnderTest(() => {
throw new Err();
})[toThrow](CustomError);
expectUnderTest(() => {
throw new Err();
}).not[toThrow](Err2);
expectUnderTest(() => {}).not[toThrow](Err);
});
test('did not throw at all', () => {
expect(() =>
expect(() => {})[toThrow](Err),
).toThrowErrorMatchingSnapshot();
});
test('threw, but class did not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new Err('apple');
})[toThrow](Err2);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but class did not match (non-error falsey)', () => {
expect(() => {
expectUnderTest(() => {
throw undefined;
})[toThrow](Err2);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but class should not match (error)', () => {
expect(() => {
expectUnderTest(() => {
throw new Err('apple');
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but class should not match (error subclass)', () => {
expect(() => {
expectUnderTest(() => {
throw new SubErr('apple');
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});
test('threw, but class should not match (error subsubclass)', () => {
expect(() => {
expectUnderTest(() => {
throw new SubSubErr('apple');
}).not[toThrow](Err);
}).toThrowErrorMatchingSnapshot();
});
});
test.describe('error-message', () => {
// Received message in report if object has message property.
class ErrorMessage {
// not extending Error!
constructor(public message: string) {}
}
const expected = new ErrorMessage('apple');
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new ErrorMessage('apple');
})[toThrow](expected);
});
test('isNot true', () => {
expectUnderTest(() => {
throw new ErrorMessage('banana');
}).not[toThrow](expected);
});
});
test.describe('fail', () => {
test('isNot false', () => {
expect(() =>
expectUnderTest(() => {
throw new ErrorMessage('banana');
})[toThrow](expected),
).toThrowErrorMatchingSnapshot();
});
test('isNot true', () => {
const message = 'Invalid array length';
expect(() =>
expectUnderTest(() => {
throw new ErrorMessage(message);
}).not[toThrow]({ message }),
).toThrowErrorMatchingSnapshot();
});
test('multiline diff highlight incorrect expected space', () => {
// jest/issues/2673
const a =
"There is no route defined for key Settings. \nMust be one of: 'Home'";
const b =
"There is no route defined for key Settings.\nMust be one of: 'Home'";
expect(() =>
expectUnderTest(() => {
throw new ErrorMessage(b);
})[toThrow]({ message: a }),
).toThrowErrorMatchingSnapshot();
});
});
});
test.describe('error message and cause', () => {
const errorA = new Error('A');
const errorB = new Error('B', { cause: errorA });
const expected = new Error('good', { cause: errorB });
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new Error('good', { cause: errorB });
})[toThrow](expected);
});
test('isNot true, incorrect message', () => {
expectUnderTest(() => {
throw new Error('bad', { cause: errorB });
}).not[toThrow](expected);
});
test('isNot true, incorrect cause', () => {
expectUnderTest(() => {
throw new Error('good', { cause: errorA });
}).not[toThrow](expected);
});
});
test.describe('fail', () => {
test('isNot false, incorrect message', () => {
expect(() =>
expectUnderTest(() => {
throw new Error('bad', { cause: errorB });
})[toThrow](expected),
).toThrow(
/^(?=.*Expected message and cause: ).*Received message and cause: /s,
);
});
test('isNot true, incorrect cause', () => {
expect(() =>
expectUnderTest(() => {
throw new Error('good', { cause: errorA });
})[toThrow](expected),
).toThrow(
/^(?=.*Expected message and cause: ).*Received message and cause: /s,
);
});
});
});
test.describe('asymmetric', () => {
test.describe('any-Class', () => {
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new Err('apple');
})[toThrow](expect.any(Err));
});
test('isNot true', () => {
expectUnderTest(() => {
throw new Err('apple');
}).not[toThrow](expect.any(Err2));
});
});
test.describe('fail', () => {
test('isNot false', () => {
expect(() =>
expectUnderTest(() => {
throw new Err('apple');
})[toThrow](expect.any(Err2)),
).toThrowErrorMatchingSnapshot();
});
test('isNot true', () => {
expect(() =>
expectUnderTest(() => {
throw new Err('apple');
}).not[toThrow](expect.any(Err)),
).toThrowErrorMatchingSnapshot();
});
});
});
test.describe('anything', () => {
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](expect.anything());
});
test('isNot true', () => {
expectUnderTest(() => {}).not[toThrow](expect.anything());
expectUnderTest(() => {
throw null;
}).not[toThrow](expect.anything());
});
});
test.describe('fail', () => {
test('isNot false', () => {
expect(() =>
expectUnderTest(() => {
throw null;
})[toThrow](expect.anything()),
).toThrowErrorMatchingSnapshot();
});
test('isNot true', () => {
expect(() =>
expectUnderTest(() => {
throw new CustomError('apple');
}).not[toThrow](expect.anything()),
).toThrowErrorMatchingSnapshot();
});
});
});
test.describe('no-symbol', () => {
// Test serialization of asymmetric matcher which has no property:
// this.$$typeof = Symbol.for('jest.asymmetricMatcher')
const matchError = {
asymmetricMatch(received: Error | null | undefined) {
return (
received !== null &&
received !== undefined &&
received.name === 'Error'
);
},
};
const matchNotError = {
asymmetricMatch(received: Error | null | undefined) {
return (
received !== null &&
received !== undefined &&
received.name !== 'Error'
);
},
};
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](matchError);
});
test('isNot true', () => {
expectUnderTest(() => {
throw new CustomError('apple');
}).not[toThrow](matchNotError);
});
});
test.describe('fail', () => {
test('isNot false', () => {
expect(() =>
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](matchNotError),
).toThrowErrorMatchingSnapshot();
});
test('isNot true', () => {
expect(() =>
expectUnderTest(() => {
throw new CustomError('apple');
}).not[toThrow](matchError),
).toThrowErrorMatchingSnapshot();
});
});
});
test.describe('objectContaining', () => {
const matchError = expect.objectContaining({
name: 'Error',
});
const matchNotError = expect.objectContaining({
name: 'NotError',
});
test.describe('pass', () => {
test('isNot false', () => {
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](matchError);
});
test('isNot true', () => {
expectUnderTest(() => {
throw new CustomError('apple');
}).not[toThrow](matchNotError);
});
});
test.describe('fail', () => {
test('isNot false', () => {
expect(() =>
expectUnderTest(() => {
throw new CustomError('apple');
})[toThrow](matchNotError),
).toThrowErrorMatchingSnapshot();
});
test('isNot true', () => {
expect(() =>
expectUnderTest(() => {
throw new CustomError('apple');
}).not[toThrow](matchError),
).toThrowErrorMatchingSnapshot();
});
});
});
});
test.describe('promise/async throws if Error-like object is returned', () => {
const asyncFn = async (shouldThrow?: boolean, resolve?: boolean) => {
let err;
if (shouldThrow)
err = new Err('async apple');
if (resolve)
return Promise.resolve(err || 'apple');
else
return Promise.reject(err || 'apple');
};
test('passes', async () => {
await expectUnderTest(Promise.reject(new Error())).rejects[toThrow]();
await expectUnderTest(asyncFn(true)).rejects[toThrow]();
await expectUnderTest(asyncFn(true)).rejects[toThrow](Err);
await expectUnderTest(asyncFn(true)).rejects[toThrow](Error);
await expectUnderTest(asyncFn(true)).rejects[toThrow]('apple');
await expectUnderTest(asyncFn(true)).rejects[toThrow](/app/);
await expectUnderTest(asyncFn(true)).rejects.not[toThrow](Err2);
await expectUnderTest(asyncFn(true)).rejects.not[toThrow]('banana');
await expectUnderTest(asyncFn(true)).rejects.not[toThrow](/banana/);
await expectUnderTest(asyncFn(true, true)).resolves[toThrow]();
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow]();
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow](Error);
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow]('apple');
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow](/apple/);
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow]('banana');
await expectUnderTest(asyncFn(false, true)).resolves.not[toThrow](/banana/);
await expectUnderTest(asyncFn()).rejects.not[toThrow]();
await expectUnderTest(asyncFn()).rejects.not[toThrow](Error);
await expectUnderTest(asyncFn()).rejects.not[toThrow]('apple');
await expectUnderTest(asyncFn()).rejects.not[toThrow](/apple/);
await expectUnderTest(asyncFn()).rejects.not[toThrow]('banana');
await expectUnderTest(asyncFn()).rejects.not[toThrow](/banana/);
// Works with nested functions inside promises
await expectUnderTest(
Promise.reject(() => {
throw new Error();
}),
).rejects[toThrow]();
await expectUnderTest(Promise.reject(() => {})).rejects.not[toThrow]();
});
test('did not throw at all', async () => {
await expectUnderTestAsAny(
expectUnderTest(asyncFn()).rejects[toThrow](),
).rejects.toThrowErrorMatchingSnapshot();
});
test('threw, but class did not match', async () => {
await expectUnderTestAsAny(
expectUnderTest(asyncFn(true)).rejects[toThrow](Err2),
).rejects.toThrowErrorMatchingSnapshot();
});
test('threw, but should not have', async () => {
await expectUnderTestAsAny(
expectUnderTest(asyncFn(true)).rejects.not[toThrow](),
).rejects.toThrowErrorMatchingSnapshot();
});
});
test.describe('expected is undefined', () => {
test('threw, but should not have (non-error falsey)', () => {
expect(() => {
expectUnderTest(() => {
throw null;
}).not[toThrow]();
}).toThrowErrorMatchingSnapshot();
});
});
test('invalid arguments', () => {
expect(() =>
expectUnderTest(() => {}).not[toThrow](111),
).toThrowErrorMatchingSnapshot();
});
test('invalid actual', () => {
expect(() =>
expectUnderTest('a string')[toThrow](),
).toThrowErrorMatchingSnapshot();
});
});
}

View File

@ -47,6 +47,10 @@ export default defineConfig({
testDir: path.join(__dirname, '../image_tools'),
testIgnore: [path.join(__dirname, '../fixtures/**')],
},
{
name: 'expect',
testDir: path.join(__dirname, '../expect'),
},
],
reporter: reporters(),
metadata: {

View File

@ -79,7 +79,7 @@ async function innerCheckDeps(root) {
});
const sourceFiles = program.getSourceFiles();
const errors = [];
sourceFiles.filter(x => !x.fileName.includes('node_modules')).map(x => visit(x, x.fileName, x.getFullText()));
sourceFiles.filter(x => !x.fileName.includes(path.sep + 'node_modules' + path.sep) && !x.fileName.includes(path.sep + 'bundles' + path.sep)).map(x => visit(x, x.fileName, x.getFullText()));
if (errors.length) {
for (const error of errors)
@ -244,7 +244,7 @@ async function innerCheckDeps(root) {
function listAllFiles(dir) {
const dirs = fs.readdirSync(dir, { withFileTypes: true });
const result = [];
dirs.map(d => {
dirs.forEach(d => {
const res = path.resolve(dir, d.name);
if (d.isDirectory())
result.push(...listAllFiles(res));