diff --git a/package-lock.json b/package-lock.json index 4e24bcfa49..b7cdad125e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 44d259d7a4..c095546c7d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/playwright/ThirdPartyNotices.txt b/packages/playwright/ThirdPartyNotices.txt index 020b2bc3f6..f2bb64d661 100644 --- a/packages/playwright/ThirdPartyNotices.txt +++ b/packages/playwright/ThirdPartyNotices.txt @@ -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 \ No newline at end of file diff --git a/packages/playwright/bundles/expect/package-lock.json b/packages/playwright/bundles/expect/package-lock.json index 9a1707ff38..73375dd81b 100644 --- a/packages/playwright/bundles/expect/package-lock.json +++ b/packages/playwright/bundles/expect/package-lock.json @@ -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==" } } } diff --git a/packages/playwright/bundles/expect/package.json b/packages/playwright/bundles/expect/package.json index 11ea4cc42e..d9f436755f 100644 --- a/packages/playwright/bundles/expect/package.json +++ b/packages/playwright/bundles/expect/package.json @@ -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" } } diff --git a/packages/playwright/bundles/expect/src/expectBundleImpl.ts b/packages/playwright/bundles/expect/src/expectBundleImpl.ts index 3eddff1323..dbfd169353 100644 --- a/packages/playwright/bundles/expect/src/expectBundleImpl.ts +++ b/packages/playwright/bundles/expect/src/expectBundleImpl.ts @@ -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, diff --git a/packages/playwright/bundles/expect/third_party/LICENSE b/packages/playwright/bundles/expect/third_party/LICENSE new file mode 100644 index 0000000000..b93be90515 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/LICENSE @@ -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. diff --git a/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts b/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts new file mode 100644 index 0000000000..4e7a3402c9 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts @@ -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] : ''; +} + +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 +implements AsymmetricMatcherInterface { + $$typeof = Symbol.for('jest.asymmetricMatcher'); + + constructor(protected sample: T, protected inverse = false) { } + + protected getMatcherContext(): MatcherContext { + return { + customTesters: getCustomEqualityTesters(), + + dontThrow: () => { }, + ...getState(), + equals, + isNot: this.inverse, + utils, + }; + } + + abstract asymmetricMatch(other: unknown): boolean; + abstract toString(): string; + getExpectedType?(): string; + toAsymmetricMatcher?(): string; +} + +class Any extends AsymmetricMatcher { + 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 { + 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> { + constructor(sample: Array, 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 +> { + constructor(sample: Record, 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 { + 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', 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 { + 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', 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 { + 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', 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): ArrayContaining => + new ArrayContaining(sample); +export const arrayNotContaining = (sample: Array): ArrayContaining => + new ArrayContaining(sample, true); +export const objectContaining = ( + sample: Record, +): ObjectContaining => new ObjectContaining(sample); +export const objectNotContaining = ( + sample: Record, +): 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); diff --git a/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts b/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts new file mode 100644 index 0000000000..1be9b4dce9 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts @@ -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; diff --git a/packages/playwright/bundles/expect/third_party/index.ts b/packages/playwright/bundles/expect/third_party/index.ts new file mode 100644 index 0000000000..3935ab71e1 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/index.ts @@ -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 & { 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) => { + 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, + 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 | (() => Promise), + outerErr: JestAssertionError, + ): PromiseMatcherFn => + (...args) => { + const options = { + isNot, + promise: 'rejects', + }; + + const actualWrapper: Promise = + 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(), + ...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): 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; diff --git a/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts b/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts new file mode 100644 index 0000000000..7a9a304b30 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts @@ -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 => + (globalThis as any)[JEST_MATCHERS_OBJECT].state; + +export const setState = ( + state: Partial, +): 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] + > { + constructor(inverse = false, ...sample: [unknown, ...Array]) { + 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]) => + new CustomMatcher(false, ...sample), + writable: true, + }); + Object.defineProperty(expect.not, key, { + configurable: true, + enumerable: true, + value: (...sample: [unknown, ...Array]) => + new CustomMatcher(true, ...sample), + writable: true, + }); + } + }); + + Object.assign((globalThis as any)[JEST_MATCHERS_OBJECT].matchers, matchers); +}; + +export const getCustomEqualityTesters = (): Array => + (globalThis as any)[JEST_MATCHERS_OBJECT].customEqualityTesters; + +export const addCustomEqualityTesters = (newTesters: Array): 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, + ); +}; diff --git a/packages/playwright/bundles/expect/third_party/matchers.ts b/packages/playwright/bundles/expect/third_party/matchers.ts new file mode 100644 index 0000000000..5102b50c32 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/matchers.ts @@ -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 + | Set + | NodeListOf + | DOMTokenList + | HTMLCollectionOf; + +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, + 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; diff --git a/packages/playwright/bundles/expect/third_party/print.ts b/packages/playwright/bundles/expect/third_party/print.ts new file mode 100644 index 0000000000..63cad0f91e --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/print.ts @@ -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, + 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) + }`; diff --git a/packages/playwright/bundles/expect/third_party/spyMatchers.ts b/packages/playwright/bundles/expect/third_party/spyMatchers.ts new file mode 100644 index 0000000000..ac74fd8d91 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/spyMatchers.ts @@ -0,0 +1,1184 @@ +/** + * 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 } from '@jest/expect-utils'; +import { getType, isPrimitive } from 'jest-get-type'; +import { + DIM_COLOR, + EXPECTED_COLOR, + type MatcherHintOptions, + RECEIVED_COLOR, + diff, + ensureExpectedIsNonNegativeInteger, + ensureNoExpected, + matcherErrorMessage, + matcherHint, + printExpected, + printReceived, + printWithType, + stringify, +} from 'jest-matcher-utils'; +import { getCustomEqualityTesters } from './jestMatchersObject'; +import type { + MatcherFunction, + MatchersObject, + SyncExpectationResult, +} from './types'; + +/* eslint-disable eqeqeq */ + +// The optional property of matcher context is true if undefined. +const isExpand = (expand?: boolean): boolean => expand !== false; + +const PRINT_LIMIT = 3; + +const NO_ARGUMENTS = 'called with 0 arguments'; + +const printExpectedArgs = (expected: Array): string => + expected.length === 0 + ? NO_ARGUMENTS + : expected.map(arg => printExpected(arg)).join(', '); + +const printReceivedArgs = ( + received: Array, + expected?: Array, +): string => + received.length === 0 + ? NO_ARGUMENTS + : received + .map((arg, i) => + Array.isArray(expected) && + i < expected.length && + isEqualValue(expected[i], arg) + ? printCommon(arg) + : printReceived(arg), + ) + .join(', '); + +const printCommon = (val: unknown) => DIM_COLOR(stringify(val)); + +const isEqualValue = (expected: unknown, received: unknown): boolean => + equals(expected, received, [...getCustomEqualityTesters(), iterableEquality]); + +const isEqualCall = ( + expected: Array, + received: Array, +): boolean => + received.length === expected.length && isEqualValue(expected, received); + +const isEqualReturn = (expected: unknown, result: any): boolean => + result.type === 'return' && isEqualValue(expected, result.value); + +const countReturns = (results: Array): number => + results.reduce( + (n: number, result: any) => (result.type === 'return' ? n + 1 : n), + 0, + ); + +const printNumberOfReturns = ( + countReturns: number, + countCalls: number, +): string => + `\nNumber of returns: ${printReceived(countReturns)}${countCalls !== countReturns + ? `\nNumber of calls: ${printReceived(countCalls)}` + : '' + }`; + +type PrintLabel = (string: string, isExpectedCall: boolean) => string; + +// Given a label, return a function which given a string, +// right-aligns it preceding the colon in the label. +const getRightAlignedPrinter = (label: string): PrintLabel => { + // Assume that the label contains a colon. + const index = label.indexOf(':'); + const suffix = label.slice(index); + + return (string: string, isExpectedCall: boolean) => + (isExpectedCall + ? `->${' '.repeat(Math.max(0, index - 2 - string.length))}` + : ' '.repeat(Math.max(index - string.length))) + + string + + suffix; +}; + +type IndexedCall = [number, Array]; + +const printReceivedCallsNegative = ( + expected: Array, + indexedCalls: Array, + isOnlyCall: boolean, + iExpectedCall?: number, +) => { + if (indexedCalls.length === 0) + return ''; + + + const label = 'Received: '; + if (isOnlyCall) + return `${label + printReceivedArgs(indexedCalls[0], expected)}\n`; + + + const printAligned = getRightAlignedPrinter(label); + + return `Received\n${indexedCalls.reduce( + (printed: string, [i, args]: IndexedCall) => + `${printed + + printAligned(String(i + 1), i === iExpectedCall) + + printReceivedArgs(args, expected) + }\n`, + '', + )}`; +}; + +const printExpectedReceivedCallsPositive = ( + expected: Array, + indexedCalls: Array, + expand: boolean, + isOnlyCall: boolean, + iExpectedCall?: number, +) => { + const expectedLine = `Expected: ${printExpectedArgs(expected)}\n`; + if (indexedCalls.length === 0) + return expectedLine; + + + const label = 'Received: '; + if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) { + const received = indexedCalls[0][1]; + + if (isLineDiffableCall(expected, received)) { + // Display diff without indentation. + const lines = [ + EXPECTED_COLOR('- Expected'), + RECEIVED_COLOR('+ Received'), + '', + ]; + + const length = Math.max(expected.length, received.length); + for (let i = 0; i < length; i += 1) { + if (i < expected.length && i < received.length) { + if (isEqualValue(expected[i], received[i])) { + lines.push(` ${printCommon(received[i])},`); + continue; + } + + if (isLineDiffableArg(expected[i], received[i])) { + const difference = diff(expected[i], received[i], { expand }); + if ( + typeof difference === 'string' && + difference.includes('- Expected') && + difference.includes('+ Received') + ) { + // Omit annotation in case multiple args have diff. + lines.push(`${difference.split('\n').slice(3).join('\n')},`); + continue; + } + } + } + + if (i < expected.length) + lines.push(`${EXPECTED_COLOR(`- ${stringify(expected[i])}`)},`); + + if (i < received.length) + lines.push(`${RECEIVED_COLOR(`+ ${stringify(received[i])}`)},`); + + } + + return `${lines.join('\n')}\n`; + } + + return `${expectedLine + label + printReceivedArgs(received, expected)}\n`; + } + + const printAligned = getRightAlignedPrinter(label); + + return ( + + expectedLine + + 'Received\n' + + indexedCalls.reduce((printed: string, [i, received]: IndexedCall) => { + const aligned = printAligned(String(i + 1), i === iExpectedCall); + return `${printed + + ((i === iExpectedCall || iExpectedCall === undefined) && + isLineDiffableCall(expected, received) + ? aligned.replace(': ', '\n') + + printDiffCall(expected, received, expand) + : aligned + printReceivedArgs(received, expected)) + }\n`; + }, '') + ); +}; + +const indentation = 'Received'.replace(/\w/g, ' '); + +const printDiffCall = ( + expected: Array, + received: Array, + expand: boolean, +) => + received + .map((arg, i) => { + if (i < expected.length) { + if (isEqualValue(expected[i], arg)) + return `${indentation} ${printCommon(arg)},`; + + + if (isLineDiffableArg(expected[i], arg)) { + const difference = diff(expected[i], arg, { expand }); + + if ( + typeof difference === 'string' && + difference.includes('- Expected') && + difference.includes('+ Received') + ) { + // Display diff with indentation. + // Omit annotation in case multiple args have diff. + return `${difference + .split('\n') + .slice(3) + .map(line => indentation + line) + .join('\n')},`; + } + } + } + + // Display + only if received arg has no corresponding expected arg. + return `${indentation + + (i < expected.length + ? ` ${printReceived(arg)}` + : RECEIVED_COLOR(`+ ${stringify(arg)}`)) + },`; + }) + .join('\n'); + +const isLineDiffableCall = ( + expected: Array, + received: Array, +): boolean => + expected.some( + (arg, i) => i < received.length && isLineDiffableArg(arg, received[i]), + ); + +// Almost redundant with function in jest-matcher-utils, +// except no line diff for any strings. +const isLineDiffableArg = (expected: unknown, received: unknown): boolean => { + const expectedType = getType(expected); + const receivedType = getType(received); + + if (expectedType !== receivedType) + return false; + + + if (isPrimitive(expected)) + return false; + + + if ( + expectedType === 'date' || + expectedType === 'function' || + expectedType === 'regexp' + ) + return false; + + + if (expected instanceof Error && received instanceof Error) + return false; + + + if ( + expectedType === 'object' && + typeof (expected as any).asymmetricMatch === 'function' + ) + return false; + + + if ( + receivedType === 'object' && + typeof (received as any).asymmetricMatch === 'function' + ) + return false; + + + return true; +}; + +const printResult = (result: any, expected: unknown) => + result.type === 'throw' + ? 'function call threw an error' + : result.type === 'incomplete' + ? 'function call has not returned yet' + : isEqualValue(expected, result.value) + ? printCommon(result.value) + : printReceived(result.value); + +type IndexedResult = [number, any]; + +// Return either empty string or one line per indexed result, +// so additional empty line can separate from `Number of returns` which follows. +const printReceivedResults = ( + label: string, + expected: unknown, + indexedResults: Array, + isOnlyCall: boolean, + iExpectedCall?: number, +) => { + if (indexedResults.length === 0) + return ''; + + + if (isOnlyCall && (iExpectedCall === 0 || iExpectedCall === undefined)) + return `${label + printResult(indexedResults[0][1], expected)}\n`; + + + const printAligned = getRightAlignedPrinter(label); + + return ( + + label.replace(':', '').trim() + + '\n' + + indexedResults.reduce( + (printed: string, [i, result]: IndexedResult) => + `${printed + + printAligned(String(i + 1), i === iExpectedCall) + + printResult(result, expected) + }\n`, + '', + ) + ); +}; + +const createToBeCalledMatcher = ( + matcherName: string, +): MatcherFunction<[unknown]> => + function(received: any, expected: unknown): SyncExpectationResult { + const expectedArgument = ''; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, matcherName, options); + ensureMockOrSpy(received, matcherName, expectedArgument, options); + + const receivedIsSpy = isSpy(received); + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + const count = receivedIsSpy + ? received.calls.count() + : received.mock.calls.length; + const calls = receivedIsSpy + ? received.calls.all().map((x: any) => x.args) + : received.mock.calls; + const pass = count > 0; + const message = pass + ? () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of calls: ${printExpected(0)}\n` + + `Received number of calls: ${printReceived(count)}\n\n` + + calls + .reduce((lines: Array, args: any, i: number) => { + if (lines.length < PRINT_LIMIT) + lines.push(`${i + 1}: ${printReceivedArgs(args)}`); + + + return lines; + }, []) + .join('\n') + : () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of calls: >= ${printExpected(1)}\n` + + `Received number of calls: ${printReceived(count)}`; + + return { message, pass }; + }; + +const createToReturnMatcher = ( + matcherName: string, +): MatcherFunction<[unknown]> => + function(received: any, expected): SyncExpectationResult { + const expectedArgument = ''; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureNoExpected(expected, matcherName, options); + ensureMock(received, matcherName, expectedArgument, options); + + const receivedName = received.getMockName(); + + // Count return values that correspond only to calls that returned + const count = received.mock.results.reduce( + (n: number, result: any) => (result.type === 'return' ? n + 1 : n), + 0, + ); + + const pass = count > 0; + + const message = pass + ? () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of returns: ${printExpected(0)}\n` + + `Received number of returns: ${printReceived(count)}\n\n` + + received.mock.results + .reduce((lines: Array, result: any, i: number) => { + if (result.type === 'return' && lines.length < PRINT_LIMIT) + lines.push(`${i + 1}: ${printReceived(result.value)}`); + + + return lines; + }, []) + .join('\n') + + (received.mock.calls.length !== count + ? `\n\nReceived number of calls: ${printReceived( + received.mock.calls.length, + )}` + : '') + : () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of returns: >= ${printExpected(1)}\n` + + `Received number of returns: ${printReceived(count)}` + + (received.mock.calls.length !== count + ? `\nReceived number of calls: ${printReceived( + received.mock.calls.length, + )}` + : ''); + + return { message, pass }; + }; + +const createToBeCalledTimesMatcher = ( + matcherName: string, +): MatcherFunction<[number]> => + function(received: any, expected): SyncExpectationResult { + const expectedArgument = 'expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureExpectedIsNonNegativeInteger(expected, matcherName, options); + ensureMockOrSpy(received, matcherName, expectedArgument, options); + + const receivedIsSpy = isSpy(received); + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + const count = receivedIsSpy + ? received.calls.count() + : received.mock.calls.length; + + const pass = count === expected; + + const message = pass + ? () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of calls: not ${printExpected(expected)}` + : () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of calls: ${printExpected(expected)}\n` + + `Received number of calls: ${printReceived(count)}`; + + return { message, pass }; + }; + +const createToReturnTimesMatcher = ( + matcherName: string, +): MatcherFunction<[number]> => + function(received: any, expected): SyncExpectationResult { + const expectedArgument = 'expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureExpectedIsNonNegativeInteger(expected, matcherName, options); + ensureMock(received, matcherName, expectedArgument, options); + + const receivedName = received.getMockName(); + + // Count return values that correspond only to calls that returned + const count = received.mock.results.reduce( + (n: number, result: any) => (result.type === 'return' ? n + 1 : n), + 0, + ); + + const pass = count === expected; + + const message = pass + ? () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of returns: not ${printExpected(expected)}` + + (received.mock.calls.length !== count + ? `\n\nReceived number of calls: ${printReceived( + received.mock.calls.length, + )}` + : '') + : () => + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected number of returns: ${printExpected(expected)}\n` + + `Received number of returns: ${printReceived(count)}` + + (received.mock.calls.length !== count + ? `\nReceived number of calls: ${printReceived( + received.mock.calls.length, + )}` + : ''); + + return { message, pass }; + }; + +const createToBeCalledWithMatcher = ( + matcherName: string, +): MatcherFunction> => + function(received: any, ...expected): SyncExpectationResult { + const expectedArgument = '...expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureMockOrSpy(received, matcherName, expectedArgument, options); + + const receivedIsSpy = isSpy(received); + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + + const calls = receivedIsSpy + ? received.calls.all().map((x: any) => x.args) + : received.mock.calls; + + const pass = calls.some((call: any) => isEqualCall(expected, call)); + + const message = pass + ? () => { + // Some examples of calls that are equal to expected value. + const indexedCalls: Array = []; + let i = 0; + while (i < calls.length && indexedCalls.length < PRINT_LIMIT) { + if (isEqualCall(expected, calls[i])) + indexedCalls.push([i, calls[i]]); + + i += 1; + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpectedArgs(expected)}\n` + + (calls.length === 1 && stringify(calls[0]) === stringify(expected) + ? '' + : printReceivedCallsNegative( + expected, + indexedCalls, + calls.length === 1, + )) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + } + : () => { + // Some examples of calls that are not equal to expected value. + const indexedCalls: Array = []; + let i = 0; + while (i < calls.length && indexedCalls.length < PRINT_LIMIT) { + indexedCalls.push([i, calls[i]]); + i += 1; + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + printExpectedReceivedCallsPositive( + expected, + indexedCalls, + isExpand(this.expand), + calls.length === 1, + ) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + }; + + return { message, pass }; + }; + +const createToReturnWithMatcher = ( + matcherName: string, +): MatcherFunction<[unknown]> => + function(received: any, expected): SyncExpectationResult { + const expectedArgument = 'expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureMock(received, matcherName, expectedArgument, options); + + const receivedName = received.getMockName(); + const { calls, results } = received.mock; + + const pass = results.some((result: any) => isEqualReturn(expected, result)); + + const message = pass + ? () => { + // Some examples of results that are equal to expected value. + const indexedResults: Array = []; + let i = 0; + while (i < results.length && indexedResults.length < PRINT_LIMIT) { + if (isEqualReturn(expected, results[i])) + indexedResults.push([i, results[i]]); + + i += 1; + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + )) + + printNumberOfReturns(countReturns(results), calls.length) + ); + } + : () => { + // Some examples of results that are not equal to expected value. + const indexedResults: Array = []; + let i = 0; + while (i < results.length && indexedResults.length < PRINT_LIMIT) { + indexedResults.push([i, results[i]]); + i += 1; + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; + + return { message, pass }; + }; + +const createLastCalledWithMatcher = ( + matcherName: string, +): MatcherFunction> => + function(received: any, ...expected): SyncExpectationResult { + const expectedArgument = '...expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureMockOrSpy(received, matcherName, expectedArgument, options); + + const receivedIsSpy = isSpy(received); + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + + const calls = receivedIsSpy + ? received.calls.all().map((x: any) => x.args) + : received.mock.calls; + const iLast = calls.length - 1; + + const pass = iLast >= 0 && isEqualCall(expected, calls[iLast]); + + const message = pass + ? () => { + const indexedCalls: Array = []; + if (iLast > 0) { + // Display preceding call as context. + indexedCalls.push([iLast - 1, calls[iLast - 1]]); + } + indexedCalls.push([iLast, calls[iLast]]); + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpectedArgs(expected)}\n` + + (calls.length === 1 && stringify(calls[0]) === stringify(expected) + ? '' + : printReceivedCallsNegative( + expected, + indexedCalls, + calls.length === 1, + iLast, + )) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + } + : () => { + const indexedCalls: Array = []; + if (iLast >= 0) { + if (iLast > 0) { + let i = iLast - 1; + // Is there a preceding call that is equal to expected args? + while (i >= 0 && !isEqualCall(expected, calls[i])) + i -= 1; + + if (i < 0) + i = iLast - 1; // otherwise, preceding call + + + indexedCalls.push([i, calls[i]]); + } + + indexedCalls.push([iLast, calls[iLast]]); + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + printExpectedReceivedCallsPositive( + expected, + indexedCalls, + isExpand(this.expand), + calls.length === 1, + iLast, + ) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + }; + + return { message, pass }; + }; + +const createLastReturnedMatcher = ( + matcherName: string, +): MatcherFunction<[unknown]> => + function(received: any, expected): SyncExpectationResult { + const expectedArgument = 'expected'; + const options: MatcherHintOptions = { + isNot: this.isNot, + promise: this.promise, + }; + ensureMock(received, matcherName, expectedArgument, options); + + const receivedName = received.getMockName(); + + const { calls, results } = received.mock; + const iLast = results.length - 1; + + const pass = iLast >= 0 && isEqualReturn(expected, results[iLast]); + + const message = pass + ? () => { + const indexedResults: Array = []; + if (iLast > 0) { + // Display preceding result as context. + indexedResults.push([iLast - 1, results[iLast - 1]]); + } + indexedResults.push([iLast, results[iLast]]); + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + iLast, + )) + + printNumberOfReturns(countReturns(results), calls.length) + ); + } + : () => { + const indexedResults: Array = []; + if (iLast >= 0) { + if (iLast > 0) { + let i = iLast - 1; + // Is there a preceding result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) + i -= 1; + + if (i < 0) + i = iLast - 1; // otherwise, preceding result + + + indexedResults.push([i, results[i]]); + } + + indexedResults.push([iLast, results[iLast]]); + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + iLast, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; + + return { message, pass }; + }; + +const createNthCalledWithMatcher = ( + matcherName: string, +): MatcherFunction<[number, ...Array]> => + function(received: any, nth, ...expected): SyncExpectationResult { + const expectedArgument = 'n'; + const options: MatcherHintOptions = { + expectedColor: (arg: string) => arg, + isNot: this.isNot, + promise: this.promise, + secondArgument: '...expected', + }; + ensureMockOrSpy(received, matcherName, expectedArgument, options); + + if (!Number.isSafeInteger(nth) || nth < 1) { + throw new Error( + matcherErrorMessage( + matcherHint(matcherName, undefined, expectedArgument, options), + `${expectedArgument} must be a positive integer`, + printWithType(expectedArgument, nth, stringify), + ), + ); + } + + const receivedIsSpy = isSpy(received); + const receivedName = receivedIsSpy ? 'spy' : received.getMockName(); + + const calls = receivedIsSpy + ? received.calls.all().map((x: any) => x.args) + : received.mock.calls; + const length = calls.length; + const iNth = nth - 1; + + const pass = iNth < length && isEqualCall(expected, calls[iNth]); + + const message = pass + ? () => { + // Display preceding and following calls, + // in case assertions fails because index is off by one. + const indexedCalls: Array = []; + if (iNth - 1 >= 0) + indexedCalls.push([iNth - 1, calls[iNth - 1]]); + + indexedCalls.push([iNth, calls[iNth]]); + if (iNth + 1 < length) + indexedCalls.push([iNth + 1, calls[iNth + 1]]); + + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + `Expected: not ${printExpectedArgs(expected)}\n` + + (calls.length === 1 && stringify(calls[0]) === stringify(expected) + ? '' + : printReceivedCallsNegative( + expected, + indexedCalls, + calls.length === 1, + iNth, + )) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + } + : () => { + // Display preceding and following calls: + // * nearest call that is equal to expected args + // * otherwise, adjacent call + // in case assertions fails because of index, especially off by one. + const indexedCalls: Array = []; + if (iNth < length) { + if (iNth - 1 >= 0) { + let i = iNth - 1; + // Is there a preceding call that is equal to expected args? + while (i >= 0 && !isEqualCall(expected, calls[i])) + i -= 1; + + if (i < 0) + i = iNth - 1; // otherwise, adjacent call + + + indexedCalls.push([i, calls[i]]); + } + indexedCalls.push([iNth, calls[iNth]]); + if (iNth + 1 < length) { + let i = iNth + 1; + // Is there a following call that is equal to expected args? + while (i < length && !isEqualCall(expected, calls[i])) + i += 1; + + if (i >= length) + i = iNth + 1; // otherwise, adjacent call + + + indexedCalls.push([i, calls[i]]); + } + } else if (length > 0) { + // The number of received calls is fewer than the expected number. + let i = length - 1; + // Is there a call that is equal to expected args? + while (i >= 0 && !isEqualCall(expected, calls[i])) + i -= 1; + + if (i < 0) + i = length - 1; // otherwise, last call + + + indexedCalls.push([i, calls[i]]); + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + printExpectedReceivedCallsPositive( + expected, + indexedCalls, + isExpand(this.expand), + calls.length === 1, + iNth, + ) + + `\nNumber of calls: ${printReceived(calls.length)}` + ); + }; + + return { message, pass }; + }; + +const createNthReturnedWithMatcher = ( + matcherName: string, +): MatcherFunction<[number, unknown]> => + function(received: any, nth, expected): SyncExpectationResult { + const expectedArgument = 'n'; + const options: MatcherHintOptions = { + expectedColor: (arg: string) => arg, + isNot: this.isNot, + promise: this.promise, + secondArgument: 'expected', + }; + ensureMock(received, matcherName, expectedArgument, options); + + if (!Number.isSafeInteger(nth) || nth < 1) { + throw new Error( + matcherErrorMessage( + matcherHint(matcherName, undefined, expectedArgument, options), + `${expectedArgument} must be a positive integer`, + printWithType(expectedArgument, nth, stringify), + ), + ); + } + + const receivedName = received.getMockName(); + const { calls, results } = received.mock; + const length = results.length; + const iNth = nth - 1; + + const pass = iNth < length && isEqualReturn(expected, results[iNth]); + + const message = pass + ? () => { + // Display preceding and following results, + // in case assertions fails because index is off by one. + const indexedResults: Array = []; + if (iNth - 1 >= 0) + indexedResults.push([iNth - 1, results[iNth - 1]]); + + indexedResults.push([iNth, results[iNth]]); + if (iNth + 1 < length) + indexedResults.push([iNth + 1, results[iNth + 1]]); + + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + `Expected: not ${printExpected(expected)}\n` + + (results.length === 1 && + results[0].type === 'return' && + stringify(results[0].value) === stringify(expected) + ? '' + : printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + iNth, + )) + + printNumberOfReturns(countReturns(results), calls.length) + ); + } + : () => { + // Display preceding and following results: + // * nearest result that is equal to expected value + // * otherwise, adjacent result + // in case assertions fails because of index, especially off by one. + const indexedResults: Array = []; + if (iNth < length) { + if (iNth - 1 >= 0) { + let i = iNth - 1; + // Is there a preceding result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) + i -= 1; + + if (i < 0) + i = iNth - 1; // otherwise, adjacent result + + + indexedResults.push([i, results[i]]); + } + indexedResults.push([iNth, results[iNth]]); + if (iNth + 1 < length) { + let i = iNth + 1; + // Is there a following result that is equal to expected value? + while (i < length && !isEqualReturn(expected, results[i])) + i += 1; + + if (i >= length) + i = iNth + 1; // otherwise, adjacent result + + + indexedResults.push([i, results[i]]); + } + } else if (length > 0) { + // The number of received calls is fewer than the expected number. + let i = length - 1; + // Is there a result that is equal to expected value? + while (i >= 0 && !isEqualReturn(expected, results[i])) + i -= 1; + + if (i < 0) + i = length - 1; // otherwise, last result + + + indexedResults.push([i, results[i]]); + } + + return ( + + matcherHint(matcherName, receivedName, expectedArgument, options) + + '\n\n' + + `n: ${nth}\n` + + `Expected: ${printExpected(expected)}\n` + + printReceivedResults( + 'Received: ', + expected, + indexedResults, + results.length === 1, + iNth, + ) + + printNumberOfReturns(countReturns(results), calls.length) + ); + }; + + return { message, pass }; + }; + +const spyMatchers: MatchersObject = { + lastCalledWith: createLastCalledWithMatcher('lastCalledWith'), + lastReturnedWith: createLastReturnedMatcher('lastReturnedWith'), + nthCalledWith: createNthCalledWithMatcher('nthCalledWith'), + nthReturnedWith: createNthReturnedWithMatcher('nthReturnedWith'), + toBeCalled: createToBeCalledMatcher('toBeCalled'), + toBeCalledTimes: createToBeCalledTimesMatcher('toBeCalledTimes'), + toBeCalledWith: createToBeCalledWithMatcher('toBeCalledWith'), + toHaveBeenCalled: createToBeCalledMatcher('toHaveBeenCalled'), + toHaveBeenCalledTimes: createToBeCalledTimesMatcher('toHaveBeenCalledTimes'), + toHaveBeenCalledWith: createToBeCalledWithMatcher('toHaveBeenCalledWith'), + toHaveBeenLastCalledWith: createLastCalledWithMatcher( + 'toHaveBeenLastCalledWith', + ), + toHaveBeenNthCalledWith: createNthCalledWithMatcher( + 'toHaveBeenNthCalledWith', + ), + toHaveLastReturnedWith: createLastReturnedMatcher('toHaveLastReturnedWith'), + toHaveNthReturnedWith: createNthReturnedWithMatcher('toHaveNthReturnedWith'), + toHaveReturned: createToReturnMatcher('toHaveReturned'), + toHaveReturnedTimes: createToReturnTimesMatcher('toHaveReturnedTimes'), + toHaveReturnedWith: createToReturnWithMatcher('toHaveReturnedWith'), + toReturn: createToReturnMatcher('toReturn'), + toReturnTimes: createToReturnTimesMatcher('toReturnTimes'), + toReturnWith: createToReturnWithMatcher('toReturnWith'), +}; + +const isMock = (received: any) => + received != null && received._isMockFunction === true; + +const isSpy = (received: any) => + received != null && + received.calls != null && + typeof received.calls.all === 'function' && + typeof received.calls.count === 'function'; + +const ensureMockOrSpy = ( + received: any, + matcherName: string, + expectedArgument: string, + options: MatcherHintOptions, +) => { + if (!isMock(received) && !isSpy(received)) { + throw new Error( + matcherErrorMessage( + matcherHint(matcherName, undefined, expectedArgument, options), + `${RECEIVED_COLOR('received')} value must be a mock or spy function`, + printWithType('Received', received, printReceived), + ), + ); + } +}; + +const ensureMock = ( + received: any, + matcherName: string, + expectedArgument: string, + options: MatcherHintOptions, +) => { + if (!isMock(received)) { + throw new Error( + matcherErrorMessage( + matcherHint(matcherName, undefined, expectedArgument, options), + `${RECEIVED_COLOR('received')} value must be a mock function`, + printWithType('Received', received, printReceived), + ), + ); + } +}; + +export default spyMatchers; diff --git a/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts b/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts new file mode 100644 index 0000000000..5a2bb9dcad --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts @@ -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; diff --git a/packages/playwright/bundles/expect/third_party/types.ts b/packages/playwright/bundles/expect/third_party/types.ts new file mode 100644 index 0000000000..abaa3a3b69 --- /dev/null +++ b/packages/playwright/bundles/expect/third_party/types.ts @@ -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; + +export type ExpectationResult = SyncExpectationResult | AsyncExpectationResult; + +export type MatcherFunctionWithContext< + Context extends MatcherContext = MatcherContext, + Expected extends Array = [] /** TODO should be: extends Array = [] */, +> = ( + this: Context, + actual: unknown, + ...expected: Expected +) => ExpectationResult; + +export type MatcherFunction = []> = + MatcherFunctionWithContext; + +// TODO should be replaced with `MatcherFunctionWithContext` +export type RawMatcherFn = { + (this: Context, actual: any, ...expected: Array): ExpectationResult; + /** @internal */ + [INTERNAL_MATCHER_FLAG]?: boolean; +}; + +export type MatchersObject = { + [name: string]: RawMatcherFn; +}; + +export type ThrowingMatcherFn = (actual: any) => void; +export type PromiseMatcherFn = (actual: any) => Promise; + +export interface MatcherUtils { + customTesters: Array; + 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; + testPath?: string; +} + +export type MatcherContext = MatcherUtils & Readonly; + +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): void; + extend(matchers: MatchersObject): void; + extractExpectedAssertionsErrors(): ExpectedAssertionsErrors; + getState(): MatcherState; + hasAssertions(): void; + setState(state: Partial): void; +} + +export type Expect = { + (actual: T): Matchers & + Inverse> & + PromiseMatchers; +} & BaseExpect & + AsymmetricMatchers & + Inverse>; + +type Inverse = { + /** + * 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): AsymmetricMatcher; + closeTo(sample: number, precision?: number): AsymmetricMatcher; + objectContaining(sample: Record): AsymmetricMatcher; + stringContaining(sample: string): AsymmetricMatcher; + stringMatching(sample: string | RegExp): AsymmetricMatcher; +} + +type PromiseMatchers = { + /** + * Unwraps the reason of a rejected promise so any other matcher can be chained. + * If the promise is fulfilled the assertion fails. + */ + rejects: Matchers, T> & Inverse, 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, T> & Inverse, T>>; +}; + +export interface Matchers, 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): 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): 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): 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): R; + /** + * Ensure that a mock function is called with specific arguments on an Nth call. + */ + toHaveBeenNthCalledWith(nth: number, ...expected: Array): R; + /** + * If you have a mock function, you can use `.toHaveBeenLastCalledWith` + * to test what arguments it was last called with. + */ + toHaveBeenLastCalledWith(...expected: Array): 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, + 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 | Array>, + ): 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; +} diff --git a/packages/playwright/src/common/expectBundle.ts b/packages/playwright/src/common/expectBundle.ts index 3322c36277..4b601b77ae 100644 --- a/packages/playwright/src/common/expectBundle.ts +++ b/packages/playwright/src/common/expectBundle.ts @@ -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; diff --git a/packages/web/src/ansi2html.ts b/packages/web/src/ansi2html.ts index 210d1210bc..e1d80ed073 100644 --- a/packages/web/src/ansi2html.ts +++ b/packages/web/src/ansi2html.ts @@ -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: diff --git a/tests/config/utils.ts b/tests/config/utils.ts index 88cff686b3..d01d40771f 100644 --- a/tests/config/utils.ts +++ b/tests/config/utils.ts @@ -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 { 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 ''; + case style.inverse.close: + return ''; + + case style.bold.open: + return ''; + case style.dim.open: + return ''; + case style.green.open: + return ''; + case style.red.open: + return ''; + case style.yellow.open: + return ''; + case style.bgYellow.open: + return ''; + + 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; diff --git a/tests/expect/assertionCounts.test.ts b/tests/expect/assertionCounts.test.ts new file mode 100644 index 0000000000..ebaae506c9 --- /dev/null +++ b/tests/expect/assertionCounts.test.ts @@ -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(`expect(received)[.not].hasAssertions() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 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); + }); +}); diff --git a/tests/expect/asymmetricMatchers.test.ts b/tests/expect/asymmetricMatchers.test.ts new file mode 100644 index 0000000000..ec0c40dbec --- /dev/null +++ b/tests/expect/asymmetricMatchers.test.ts @@ -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'); +}); + +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); + }); +}); diff --git a/tests/expect/customEqualityTesters.test.ts b/tests/expect/customEqualityTesters.test.ts new file mode 100644 index 0000000000..2909c1091e --- /dev/null +++ b/tests/expect/customEqualityTesters.test.ts @@ -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(array: Array): Iterator { + 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>( + () => 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(`expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": 2, ++ "a": 1, + "b": Volume { + "amount": 1000, + "unit": "mL", + }, + }`); + }); + + 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); + }); +}); diff --git a/tests/expect/customEqualityTestersRecursive.test.ts b/tests/expect/customEqualityTestersRecursive.test.ts new file mode 100644 index 0000000000..34c5813a8d --- /dev/null +++ b/tests/expect/customEqualityTestersRecursive.test.ts @@ -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; + public [CONNECTION_PROP]: DbConnection; + + constructor(name: string, authors: Array) { + 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(array: Array): Iterator { + 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>( + () => 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(`expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + +@@ -1,7 +1,7 @@ + Object { +- "a": 2, ++ "a": 1, + "b": Book { + "__connection": 5, + "authors": Array [ + Author { + "__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); + }); +}); diff --git a/tests/expect/extend.test.ts b/tests/expect/extend.test.ts new file mode 100644 index 0000000000..94b879bb40 --- /dev/null +++ b/tests/expect/extend.test.ts @@ -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 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 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(`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(`expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "value": toBeDivisibleBy<2>, ++ "value": 3, + }`); +}); + +test('defines asymmetric unary matchers that can be prefixed by not', () => { + expect(() => + expectUnderTest({ value: 2 }).toEqual({ value: expectUnderTestAsAny.not.toBeDivisibleBy(2) }), + ).toThrowErrorMatchingSnapshot(`expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "value": not.toBeDivisibleBy<2>, ++ "value": 2, + }`); + 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(`expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "value": toBeWithinRange<4, 11>, ++ "value": 3, + }`); +}); + +test('defines asymmetric variadic matchers that can be prefixed by not', () => { + expect(() => + expectUnderTest({ value: 2 }).toEqual({ + value: expectUnderTestAsAny.not.toBeWithinRange(1, 3), + }), + ).toThrowErrorMatchingSnapshot(`expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "value": not.toBeWithinRange<1, 3>, ++ "value": 2, + }`); + 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(`expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "a": toBeSymbol, ++ "a": Symbol(foo), + }`); +}); + +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"', + ); +}); diff --git a/tests/expect/fixtures.ts b/tests/expect/fixtures.ts new file mode 100644 index 0000000000..502f9571b0 --- /dev/null +++ b/tests/expect/fixtures.ts @@ -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(); +const snapshotFiles = new Set(); + +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, 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'); + } +}); diff --git a/tests/expect/matchers.snapshots.js b/tests/expect/matchers.snapshots.js new file mode 100644 index 0000000000..0f8a5a5030 --- /dev/null +++ b/tests/expect/matchers.snapshots.js @@ -0,0 +1,3614 @@ +module.exports[".rejects fails non-promise value \"a\""] = `expect(received).rejects.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: string +Received has value: "a"`; + +module.exports[".rejects fails non-promise value [1]"] = `expect(received).rejects.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: array +Received has value: [1]`; + +module.exports[".rejects fails non-promise value [Function anonymous]"] = `expect(received).rejects.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: function +Received has value: [Function anonymous]`; + +module.exports[".rejects fails non-promise value {\"a\": 1}"] = `expect(received).rejects.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: object +Received has value: {"a": 1}`; + +module.exports[".rejects fails non-promise value 4"] = `expect(received).rejects.not.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: number +Received has value: 4`; + +module.exports[".rejects fails non-promise value null"] = `expect(received).rejects.not.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has value: null`; + +module.exports[".rejects fails non-promise value true"] = `expect(received).rejects.not.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has type: boolean +Received has value: true`; + +module.exports[".rejects fails non-promise value undefined"] = `expect(received).rejects.not.toBeDefined() + +Matcher error: received value must be a promise or a function returning a promise + +Received has value: undefined`; + +module.exports[".rejects fails for promise that resolves"] = `expect(received).rejects.toBe() + +Received promise resolved instead of rejected +Resolved to value: 4`; + +module.exports[".resolves fails non-promise value \"a\" synchronously"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: string +Received has value: "a"`; + +module.exports[".resolves fails non-promise value \"a\""] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: string +Received has value: "a"`; + +module.exports[".resolves fails non-promise value [1] synchronously"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: array +Received has value: [1]`; + +module.exports[".resolves fails non-promise value [1]"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: array +Received has value: [1]`; + +module.exports[".resolves fails non-promise value [Function anonymous] synchronously"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: function +Received has value: [Function anonymous]`; + +module.exports[".resolves fails non-promise value [Function anonymous]"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: function +Received has value: [Function anonymous]`; + +module.exports[".resolves fails non-promise value {\"a\": 1} synchronously"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: object +Received has value: {"a": 1}`; + +module.exports[".resolves fails non-promise value {\"a\": 1}"] = `expect(received).resolves.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: object +Received has value: {"a": 1}`; + +module.exports[".resolves fails non-promise value 4 synchronously"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: number +Received has value: 4`; + +module.exports[".resolves fails non-promise value 4"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: number +Received has value: 4`; + +module.exports[".resolves fails non-promise value null synchronously"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has value: null`; + +module.exports[".resolves fails non-promise value null"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has value: null`; + +module.exports[".resolves fails non-promise value true synchronously"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: boolean +Received has value: true`; + +module.exports[".resolves fails non-promise value true"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has type: boolean +Received has value: true`; + +module.exports[".resolves fails non-promise value undefined synchronously"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has value: undefined`; + +module.exports[".resolves fails non-promise value undefined"] = `expect(received).resolves.not.toBeDefined() + +Matcher error: received value must be a promise + +Received has value: undefined`; + +module.exports[".resolves fails for promise that rejects"] = `expect(received).resolves.toBe() + +Received promise rejected instead of resolved +Rejected to value: 4`; + +module.exports[".toBe() fails for: 1 and 2 (0)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: 2 +Received: 1`; + +module.exports[".toBe() fails for: true and false (1)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: false +Received: true`; + +module.exports[".toBe() fails for: [Function anonymous] and [Function anonymous] (2)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: [Function anonymous] +Received: serializes to the same string`; + +module.exports[".toBe() fails for: {} and {} (3)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toStrictEqual" + +Expected: {} +Received: serializes to the same string`; + +module.exports[".toBe() fails for: {\"a\": 1} and {\"a\": 1} (4)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toStrictEqual" + +Expected: {"a": 1} +Received: serializes to the same string`; + +module.exports[".toBe() fails for: {\"a\": 1} and {\"a\": 5} (5)"] = `expect(received).toBe(expected) // Object.is equality + +- Expected - 1 ++ Received + 1 + + Object { +- "a": 5, ++ "a": 1, + }`; + +module.exports[".toBe() fails for: {\"a\": [Function a], \"b\": 2} and {\"a\": Any, \"b\": 2} (6)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toStrictEqual" + +Expected: {"a": Any, "b": 2} +Received: {"a": [Function a], "b": 2}`; + +module.exports[".toBe() fails for: {\"a\": undefined, \"b\": 2} and {\"b\": 2} (7)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toEqual" + +- Expected - 0 ++ Received + 1 + + Object { ++ "a": undefined, + "b": 2, + }`; + +module.exports[".toBe() fails for: 2020-02-20T00:00:00.000Z and 2020-02-20T00:00:00.000Z (8)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toStrictEqual" + +Expected: 2020-02-20T00:00:00.000Z +Received: serializes to the same string`; + +module.exports[".toBe() fails for: 2020-02-21T00:00:00.000Z and 2020-02-20T00:00:00.000Z (9)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: 2020-02-20T00:00:00.000Z +Received: 2020-02-21T00:00:00.000Z`; + +module.exports[".toBe() fails for: /received/ and /expected/ (10)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: /expected/ +Received: /received/`; + +module.exports[".toBe() fails for: Symbol(received) and Symbol(expected) (11)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: Symbol(expected) +Received: Symbol(received)`; + +module.exports[".toBe() fails for: [Error: received] and [Error: expected] (12)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: [Error: expected] +Received: [Error: received]`; + +module.exports[".toBe() fails for: \"abc\" and \"cde\" (13)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: "cde" +Received: "abc"`; + +module.exports[".toBe() fails for: \"painless JavaScript testing\" and \"delightful JavaScript testing\" (14)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: "delightful JavaScript testing" +Received: "painless JavaScript testing"`; + +module.exports[".toBe() fails for: \"\" and \"compare one-line string to empty string\" (15)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: "compare one-line string to empty string" +Received: ""`; + +module.exports[".toBe() fails for: \"with \ntrailing space\" and \"without trailing space\" (16)"] = `expect(received).toBe(expected) // Object.is equality + +- Expected - 1 ++ Received + 2 + +- without trailing space ++ with ++ trailing space`; + +module.exports[".toBe() fails for: \"four\n4\nline\nstring\" and \"3\nline\nstring\" (17)"] = `expect(received).toBe(expected) // Object.is equality + +- Expected - 1 ++ Received + 2 + +- 3 ++ four ++ 4 + line + string`; + +module.exports[".toBe() fails for: [] and [] (18)"] = `expect(received).toBe(expected) // Object.is equality + +If it should pass with deep equality, replace "toBe" with "toStrictEqual" + +Expected: [] +Received: serializes to the same string`; + +module.exports[".toBe() fails for: null and undefined (19)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: undefined +Received: null`; + +module.exports[".toBe() fails for: -0 and 0 (20)"] = `expect(received).toBe(expected) // Object.is equality + +Expected: 0 +Received: -0`; + +module.exports[".toBe() fails for 'false' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not false`; + +module.exports[".toBe() fails for '1' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not 1`; + +module.exports[".toBe() fails for '\"a\"' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not "a"`; + +module.exports[".toBe() fails for 'undefined' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not undefined`; + +module.exports[".toBe() fails for 'null' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not null`; + +module.exports[".toBe() fails for '{}' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not {}`; + +module.exports[".toBe() fails for '[]' with '.not'"] = `expect(received).not.toBe(expected) // Object.is equality + +Expected: not []`; + +module.exports[".toBe() does not crash on circular references"] = `expect(received).toBe(expected) // Object.is equality + +- Expected - 1 ++ Received + 3 + +- Object {} ++ Object { ++ "circular": [Circular], ++ }`; + +module.exports[".toStrictEqual() matches the expected snapshot when it fails"] = `expect(received).toStrictEqual(expected) // deep equality + +- Expected - 4 ++ Received + 1 + + Object { +- "test": TestClassA { +- "a": 1, +- "b": 2, +- }, ++ "test": 2, + }`; + +module.exports[".toStrictEqual() matches the expected snapshot when it fails #1"] = `expect(received).not.toStrictEqual(expected) // deep equality + +Expected: not {"test": {"a": 1, "b": 2}} +`; + +module.exports[".toStrictEqual() displays substring diff"] = `expect(received).toStrictEqual(expected) // deep equality + +Expected: "Another caveat is that Jest will not typecheck your tests." +Received: "Because TypeScript support in Babel is just transpilation, Jest will not type-check your tests as they run."`; + +module.exports[".toStrictEqual() displays substring diff for multiple lines"] = `expect(received).toStrictEqual(expected) // deep equality + +- Expected - 7 ++ Received + 7 + +- 69 | ++ 68 | +- 70 | test('assert.doesNotThrow', () => { ++ 69 | test('assert.doesNotThrow', () => { +- > 71 | assert.doesNotThrow(() => { ++ > 70 | assert.doesNotThrow(() => { + | ^ +- 72 | throw Error('err!'); ++ 71 | throw Error('err!'); +- 73 | }); ++ 72 | }); +- 74 | }); ++ 73 | }); +- at Object.doesNotThrow (__tests__/assertionError.test.js:71:10) ++ at Object.doesNotThrow (__tests__/assertionError.test.js:70:10)`; + +module.exports[".toEqual() {pass: false} expect(true).toEqual(false (0))"] = `expect(received).toEqual(expected) // deep equality + +Expected: false +Received: true`; + +module.exports[".toEqual() {pass: false} expect(1).toEqual(2 (1))"] = `expect(received).toEqual(expected) // deep equality + +Expected: 2 +Received: 1`; + +module.exports[".toEqual() {pass: false} expect(0).toEqual(-0 (2))"] = `expect(received).toEqual(expected) // deep equality + +Expected: -0 +Received: 0`; + +module.exports[".toEqual() {pass: false} expect(0).toEqual(5e-324 (3))"] = `expect(received).toEqual(expected) // deep equality + +Expected: 5e-324 +Received: 0`; + +module.exports[".toEqual() {pass: false} expect(5e-324).toEqual(0 (4))"] = `expect(received).toEqual(expected) // deep equality + +Expected: 0 +Received: 5e-324`; + +module.exports[".toEqual() {pass: false} expect(0).toEqual({} (5))"] = `expect(received).toEqual(expected) // deep equality + +Expected: {} +Received: 0`; + +module.exports[".toEqual() {pass: false} expect({}).toEqual(0 (6))"] = `expect(received).toEqual(expected) // deep equality + +Expected: 0 +Received: {}`; + +module.exports[".toEqual() {pass: false} expect({}).toEqual({} (7))"] = `expect(received).toEqual(expected) // deep equality + +Expected: {} +Received: serializes to the same string`; + +module.exports[".toEqual() {pass: false} expect(\"abc\").toEqual({\"0\": \"a\", \"1\": \"b\", \"2\": \"c\"} (8))"] = `expect(received).toEqual(expected) // deep equality + +Expected: {"0": "a", "1": "b", "2": "c"} +Received: "abc"`; + +module.exports[".toEqual() {pass: false} expect({\"0\": \"a\", \"1\": \"b\", \"2\": \"c\"}).toEqual(\"abc\" (9))"] = `expect(received).toEqual(expected) // deep equality + +Expected: "abc" +Received: {"0": "a", "1": "b", "2": "c"}`; + +module.exports[".toEqual() {pass: false} expect(/abc/gsy).toEqual(/abc/g (10))"] = `expect(received).toEqual(expected) // deep equality + +Expected: /abc/g +Received: /abc/gsy`; + +module.exports[".toEqual() {pass: false} expect({\"a\": 1}).toEqual({\"a\": 2} (11))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "a": 2, ++ "a": 1, + }`; + +module.exports[".toEqual() {pass: false} expect({\"a\": 5}).toEqual({\"b\": 6} (12))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "b": 6, ++ "a": 5, + }`; + +module.exports[".toEqual() {pass: false} expect({\"foo\": {\"bar\": 1}}).toEqual({\"foo\": {}} (13))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 3 + + Object { +- "foo": Object {}, ++ "foo": Object { ++ "bar": 1, ++ }, + }`; + +module.exports[".toEqual() {pass: false} expect({\"getterAndSetter\": {}}).toEqual({\"getterAndSetter\": {\"foo\": \"bar\"}} (14))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "getterAndSetter": Object { +- "foo": "bar", +- }, ++ "getterAndSetter": Object {}, + }`; + +module.exports[".toEqual() {pass: false} expect({\"frozenGetterAndSetter\": {}}).toEqual({\"frozenGetterAndSetter\": {\"foo\": \"bar\"}} (15))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "frozenGetterAndSetter": Object { +- "foo": "bar", +- }, ++ "frozenGetterAndSetter": Object {}, + }`; + +module.exports[".toEqual() {pass: false} expect({\"getter\": {}}).toEqual({\"getter\": {\"foo\": \"bar\"}} (16))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "getter": Object { +- "foo": "bar", +- }, ++ "getter": Object {}, + }`; + +module.exports[".toEqual() {pass: false} expect({\"frozenGetter\": {}}).toEqual({\"frozenGetter\": {\"foo\": \"bar\"}} (17))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "frozenGetter": Object { +- "foo": "bar", +- }, ++ "frozenGetter": Object {}, + }`; + +module.exports[".toEqual() {pass: false} expect({\"setter\": undefined}).toEqual({\"setter\": {\"foo\": \"bar\"}} (18))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "setter": Object { +- "foo": "bar", +- }, ++ "setter": undefined, + }`; + +module.exports[".toEqual() {pass: false} expect({\"frozenSetter\": undefined}).toEqual({\"frozenSetter\": {\"foo\": \"bar\"}} (19))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + + Object { +- "frozenSetter": Object { +- "foo": "bar", +- }, ++ "frozenSetter": undefined, + }`; + +module.exports[".toEqual() {pass: false} expect(\"banana\").toEqual(\"apple\" (20))"] = `expect(received).toEqual(expected) // deep equality + +Expected: "apple" +Received: "banana"`; + +module.exports[".toEqual() {pass: false} expect(\"1 234,57 $\").toEqual(\"1 234,57 $\" (21))"] = `expect(received).toEqual(expected) // deep equality + +Expected: "1 234,57 $" +Received: "1 234,57 $"`; + +module.exports[".toEqual() {pass: false} expect(\"type TypeName = T extends Function ? \\\"function\\\" : \\\"object\\\";\").toEqual(\"type TypeName = T extends Function\n? \\\"function\\\"\n: \\\"object\\\";\" (22))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + +- type TypeName = T extends Function +- ? "function" +- : "object"; ++ type TypeName = T extends Function ? "function" : "object";`; + +module.exports[".toEqual() {pass: false} expect(null).toEqual(undefined (23))"] = `expect(received).toEqual(expected) // deep equality + +Expected: undefined +Received: null`; + +module.exports[".toEqual() {pass: false} expect([1]).toEqual([2] (24))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Array [ +- 2, ++ 1, + ]`; + +module.exports[".toEqual() {pass: false} expect([1, 2]).toEqual([2, 1] (25))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Array [ +- 2, + 1, ++ 2, + ]`; + +module.exports[".toEqual() {pass: false} expect(Immutable.List [1]).toEqual(Immutable.List [2] (26))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.List [ +- 2, ++ 1, + ]`; + +module.exports[".toEqual() {pass: false} expect(Immutable.List [1, 2]).toEqual(Immutable.List [2, 1] (27))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.List [ +- 2, + 1, ++ 2, + ]`; + +module.exports[".toEqual() {pass: false} expect(Map {}).toEqual(Set {} (28))"] = `expect(received).toEqual(expected) // deep equality + +Expected: Set {} +Received: Map {}`; + +module.exports[".toEqual() {pass: false} expect(Set {1, 2}).toEqual(Set {} (29))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 4 + +- Set {} ++ Set { ++ 1, ++ 2, ++ }`; + +module.exports[".toEqual() {pass: false} expect(Set {1, 2}).toEqual(Set {1, 2, 3} (30))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 0 + + Set { + 1, + 2, +- 3, + }`; + +module.exports[".toEqual() {pass: false} expect(Set {[1], [2]}).toEqual(Set {[1], [2], [3]} (31))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 0 + +@@ -3,9 +3,6 @@ + 1, + ], + Array [ + 2, + ], +- Array [ +- 3, +- ], + }`; + +module.exports[".toEqual() {pass: false} expect(Set {[1], [2]}).toEqual(Set {[1], [2], [2]} (32))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 0 + +@@ -3,9 +3,6 @@ + 1, + ], + Array [ + 2, + ], +- Array [ +- 2, +- ], + }`; + +module.exports[".toEqual() {pass: false} expect(Set {Set {1}, Set {2}}).toEqual(Set {Set {1}, Set {3}} (33))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Set { + Set { + 1, + }, + Set { +- 3, ++ 2, + }, + }`; + +module.exports[".toEqual() {pass: false} expect(Immutable.Set [1, 2]).toEqual(Immutable.Set [] (34))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 4 + +- Immutable.Set [] ++ Immutable.Set [ ++ 1, ++ 2, ++ ]`; + +module.exports[".toEqual() {pass: false} expect(Immutable.Set [1, 2]).toEqual(Immutable.Set [1, 2, 3] (35))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 0 + + Immutable.Set [ + 1, + 2, +- 3, + ]`; + +module.exports[".toEqual() {pass: false} expect(Immutable.OrderedSet [1, 2]).toEqual(Immutable.OrderedSet [2, 1] (36))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.OrderedSet [ +- 2, + 1, ++ 2, + ]`; + +module.exports[".toEqual() {pass: false} expect(Map {1 => \"one\", 2 => \"two\"}).toEqual(Map {1 => \"one\"} (37))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 0 ++ Received + 1 + + Map { + 1 => "one", ++ 2 => "two", + }`; + +module.exports[".toEqual() {pass: false} expect(Map {\"a\" => 0}).toEqual(Map {\"b\" => 0} (38))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Map { +- "b" => 0, ++ "a" => 0, + }`; + +module.exports[".toEqual() {pass: false} expect(Map {\"v\" => 1}).toEqual(Map {\"v\" => 2} (39))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Map { +- "v" => 2, ++ "v" => 1, + }`; + +module.exports[".toEqual() {pass: false} expect(Map {[\"v\"] => 1}).toEqual(Map {[\"v\"] => 2} (40))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Map { + Array [ + "v", +- ] => 2, ++ ] => 1, + }`; + +module.exports[".toEqual() {pass: false} expect(Map {[1] => Map {[1] => \"one\"}}).toEqual(Map {[1] => Map {[1] => \"two\"}} (41))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + +@@ -2,8 +2,8 @@ + Array [ + 1, + ] => Map { + Array [ + 1, +- ] => "two", ++ ] => "one", + }, + }`; + +module.exports[".toEqual() {pass: false} expect(Immutable.Map {\"a\": 0}).toEqual(Immutable.Map {\"b\": 0} (42))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.Map { +- "b": 0, ++ "a": 0, + }`; + +module.exports[".toEqual() {pass: false} expect(Immutable.Map {\"v\": 1}).toEqual(Immutable.Map {\"v\": 2} (43))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.Map { +- "v": 2, ++ "v": 1, + }`; + +module.exports[".toEqual() {pass: false} expect(Immutable.OrderedMap {1: \"one\", 2: \"two\"}).toEqual(Immutable.OrderedMap {2: \"two\", 1: \"one\"} (44))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.OrderedMap { +- 2: "two", + 1: "one", ++ 2: "two", + }`; + +module.exports[".toEqual() {pass: false} expect(Immutable.Map {\"1\": Immutable.Map {\"2\": {\"a\": 99}}}).toEqual(Immutable.Map {\"1\": Immutable.Map {\"2\": {\"a\": 11}}} (45))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Immutable.Map { + "1": Immutable.Map { + "2": Object { +- "a": 11, ++ "a": 99, + }, + }, + }`; + +module.exports[".toEqual() {pass: false} expect([97, 98, 99]).toEqual([97, 98, 100] (46))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Uint8Array [ + 97, + 98, +- 100, ++ 99, + ]`; + +module.exports[".toEqual() {pass: false} expect({\"a\": 1, \"b\": 2}).toEqual(ObjectContaining {\"a\": 2} (47))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 2 ++ Received + 3 + +- ObjectContaining { +- "a": 2, ++ Object { ++ "a": 1, ++ "b": 2, + }`; + +module.exports[".toEqual() {pass: false} expect(false).toEqual(ObjectContaining {\"a\": 2} (48))"] = `expect(received).toEqual(expected) // deep equality + +Expected: ObjectContaining {"a": 2} +Received: false`; + +module.exports[".toEqual() {pass: false} expect([1, 3]).toEqual(ArrayContaining [1, 2] (49))"] = `expect(received).toEqual(expected) // deep equality + +Expected: ArrayContaining [1, 2] +Received: [1, 3]`; + +module.exports[".toEqual() {pass: false} expect(1).toEqual(ArrayContaining [1, 2] (50))"] = `expect(received).toEqual(expected) // deep equality + +Expected: ArrayContaining [1, 2] +Received: 1`; + +module.exports[".toEqual() {pass: false} expect(\"abd\").toEqual(StringContaining \"bc\" (51))"] = `expect(received).toEqual(expected) // deep equality + +Expected: StringContaining "bc" +Received: "abd"`; + +module.exports[".toEqual() {pass: false} expect(\"abd\").toEqual(StringMatching /bc/i (52))"] = `expect(received).toEqual(expected) // deep equality + +Expected: StringMatching /bc/i +Received: "abd"`; + +module.exports[".toEqual() {pass: false} expect(undefined).toEqual(Anything (53))"] = `expect(received).toEqual(expected) // deep equality + +Expected: Anything +Received: undefined`; + +module.exports[".toEqual() {pass: false} expect(undefined).toEqual(Any (54))"] = `expect(received).toEqual(expected) // deep equality + +Expected: Any +Received: undefined`; + +module.exports[".toEqual() {pass: false} expect(\"Eve\").toEqual({\"asymmetricMatch\": [Function asymmetricMatch]} (55))"] = `expect(received).toEqual(expected) // deep equality + +Expected: {"asymmetricMatch": [Function asymmetricMatch]} +Received: "Eve"`; + +module.exports[".toEqual() {pass: false} expect({\"target\": {\"nodeType\": 1, \"value\": \"a\"}}).toEqual({\"target\": {\"nodeType\": 1, \"value\": \"b\"}} (56))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { + "target": Object { + "nodeType": 1, +- "value": "b", ++ "value": "a", + }, + }`; + +module.exports[".toEqual() {pass: false} expect({\"nodeName\": \"div\", \"nodeType\": 1}).toEqual({\"nodeName\": \"p\", \"nodeType\": 1} (57))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { +- "nodeName": "p", ++ "nodeName": "div", + "nodeType": 1, + }`; + +module.exports[".toEqual() {pass: false} expect({Symbol(foo): 1, Symbol(bar): 2}).toEqual({Symbol(foo): Any, Symbol(bar): 1} (58))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Object { + Symbol(foo): Any, +- Symbol(bar): 1, ++ Symbol(bar): 2, + }`; + +module.exports[".toEqual() {pass: false} expect([, , 1, ]).toEqual([, , 2, ] (59))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 1 ++ Received + 1 + + Array [ + undefined, + undefined, +- 2, ++ 1, + undefined, + ]`; + +module.exports[".toEqual() {pass: false} expect([]).toEqual([] (60))"] = `expect(received).toEqual(expected) // deep equality + +Expected: [] +Received: serializes to the same string`; + +module.exports[".toEqual() {pass: false} expect([]).toEqual([1] (61))"] = `expect(received).toEqual(expected) // deep equality + +- Expected - 3 ++ Received + 1 + +- Array [ +- 1, +- ] ++ Array []`; + +module.exports[".toEqual() {pass: false} expect([]).toEqual([] (62))"] = `expect(received).toEqual(expected) // deep equality + +Expected: [] +Received: serializes to the same string`; + +module.exports[".toEqual() {pass: false} expect([]).toEqual([] (63))"] = `expect(received).toEqual(expected) // deep equality + +Expected: [] +Received: serializes to the same string`; + +module.exports[".toEqual() {pass: true} expect(true).not.toEqual(true) (0)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not true +`; + +module.exports[".toEqual() {pass: true} expect(1).not.toEqual(1) (1)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not 1 +`; + +module.exports[".toEqual() {pass: true} expect(NaN).not.toEqual(NaN) (2)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not NaN +`; + +module.exports[".toEqual() {pass: true} expect(0).not.toEqual(0) (3)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not 0 +`; + +module.exports[".toEqual() {pass: true} expect(0).not.toEqual(0) (4)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not 0 +`; + +module.exports[".toEqual() {pass: true} expect({}).not.toEqual({}) (5)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {} +`; + +module.exports[".toEqual() {pass: true} expect(\"abc\").not.toEqual(\"abc\") (6)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not "abc" +`; + +module.exports[".toEqual() {pass: true} expect(\"abc\").not.toEqual(\"abc\") (7)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not "abc" +`; + +module.exports[".toEqual() {pass: true} expect(\"abc\").not.toEqual(\"abc\") (8)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not "abc" +`; + +module.exports[".toEqual() {pass: true} expect([1]).not.toEqual([1]) (9)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1] +`; + +module.exports[".toEqual() {pass: true} expect([1, 2]).not.toEqual([1, 2]) (10)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, 2] +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.List [1]).not.toEqual(Immutable.List [1]) (11)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.List [1] +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.List [1, 2]).not.toEqual(Immutable.List [1, 2]) (12)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.List [1, 2] +`; + +module.exports[".toEqual() {pass: true} expect({}).not.toEqual({}) (13)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {} +`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 99}).not.toEqual({\"a\": 99}) (14)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 99} +`; + +module.exports[".toEqual() {pass: true} expect(Set {}).not.toEqual(Set {}) (15)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {} +`; + +module.exports[".toEqual() {pass: true} expect(Set {1, 2}).not.toEqual(Set {1, 2}) (16)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {1, 2} +`; + +module.exports[".toEqual() {pass: true} expect(Set {1, 2}).not.toEqual(Set {2, 1}) (17)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {2, 1} +Received: Set {1, 2}`; + +module.exports[".toEqual() {pass: true} expect(Set {[1], [2]}).not.toEqual(Set {[2], [1]}) (18)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {[2], [1]} +Received: Set {[1], [2]}`; + +module.exports[".toEqual() {pass: true} expect(Set {Set {[1]}, Set {[2]}}).not.toEqual(Set {Set {[2]}, Set {[1]}}) (19)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {Set {[2]}, Set {[1]}} +Received: Set {Set {[1]}, Set {[2]}}`; + +module.exports[".toEqual() {pass: true} expect(Set {[1], [2], [3], [3]}).not.toEqual(Set {[3], [3], [2], [1]}) (20)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {[3], [3], [2], [1]} +Received: Set {[1], [2], [3], [3]}`; + +module.exports[".toEqual() {pass: true} expect(Set {{\"a\": 1}, {\"b\": 2}}).not.toEqual(Set {{\"b\": 2}, {\"a\": 1}}) (21)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Set {{"b": 2}, {"a": 1}} +Received: Set {{"a": 1}, {"b": 2}}`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Set []).not.toEqual(Immutable.Set []) (22)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Set [] +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Set [1, 2]).not.toEqual(Immutable.Set [1, 2]) (23)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Set [1, 2] +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Set [1, 2]).not.toEqual(Immutable.Set [2, 1]) (24)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Set [2, 1] +Received: Immutable.Set [1, 2]`; + +module.exports[".toEqual() {pass: true} expect(Immutable.OrderedSet []).not.toEqual(Immutable.OrderedSet []) (25)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.OrderedSet [] +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.OrderedSet [1, 2]).not.toEqual(Immutable.OrderedSet [1, 2]) (26)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.OrderedSet [1, 2] +`; + +module.exports[".toEqual() {pass: true} expect(Map {}).not.toEqual(Map {}) (27)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {} +`; + +module.exports[".toEqual() {pass: true} expect(Map {1 => \"one\", 2 => \"two\"}).not.toEqual(Map {1 => \"one\", 2 => \"two\"}) (28)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {1 => "one", 2 => "two"} +`; + +module.exports[".toEqual() {pass: true} expect(Map {1 => \"one\", 2 => \"two\"}).not.toEqual(Map {2 => \"two\", 1 => \"one\"}) (29)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {2 => "two", 1 => "one"} +Received: Map {1 => "one", 2 => "two"}`; + +module.exports[".toEqual() {pass: true} expect(Map {[1] => \"one\", [2] => \"two\", [3] => \"three\", [3] => \"four\"}).not.toEqual(Map {[3] => \"three\", [3] => \"four\", [2] => \"two\", [1] => \"one\"}) (30)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {[3] => "three", [3] => "four", [2] => "two", [1] => "one"} +Received: Map {[1] => "one", [2] => "two", [3] => "three", [3] => "four"}`; + +module.exports[".toEqual() {pass: true} expect(Map {[1] => Map {[1] => \"one\"}, [2] => Map {[2] => \"two\"}}).not.toEqual(Map {[2] => Map {[2] => \"two\"}, [1] => Map {[1] => \"one\"}}) (31)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {[2] => Map {[2] => "two"}, [1] => Map {[1] => "one"}} +Received: Map {[1] => Map {[1] => "one"}, [2] => Map {[2] => "two"}}`; + +module.exports[".toEqual() {pass: true} expect(Map {[1] => \"one\", [2] => \"two\"}).not.toEqual(Map {[2] => \"two\", [1] => \"one\"}) (32)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {[2] => "two", [1] => "one"} +Received: Map {[1] => "one", [2] => "two"}`; + +module.exports[".toEqual() {pass: true} expect(Map {{\"a\": 1} => \"one\", {\"b\": 2} => \"two\"}).not.toEqual(Map {{\"b\": 2} => \"two\", {\"a\": 1} => \"one\"}) (33)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {{"b": 2} => "two", {"a": 1} => "one"} +Received: Map {{"a": 1} => "one", {"b": 2} => "two"}`; + +module.exports[".toEqual() {pass: true} expect(Map {1 => [\"one\"], 2 => [\"two\"]}).not.toEqual(Map {2 => [\"two\"], 1 => [\"one\"]}) (34)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Map {2 => ["two"], 1 => ["one"]} +Received: Map {1 => ["one"], 2 => ["two"]}`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Map {}).not.toEqual(Immutable.Map {}) (35)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Map {} +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Map {1: \"one\", 2: \"two\"}).not.toEqual(Immutable.Map {1: \"one\", 2: \"two\"}) (36)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Map {1: "one", 2: "two"} +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Map {1: \"one\", 2: \"two\"}).not.toEqual(Immutable.Map {2: \"two\", 1: \"one\"}) (37)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Map {2: "two", 1: "one"} +Received: Immutable.Map {1: "one", 2: "two"}`; + +module.exports[".toEqual() {pass: true} expect(Immutable.OrderedMap {1: \"one\", 2: \"two\"}).not.toEqual(Immutable.OrderedMap {1: \"one\", 2: \"two\"}) (38)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.OrderedMap {1: "one", 2: "two"} +`; + +module.exports[".toEqual() {pass: true} expect(Immutable.Map {\"1\": Immutable.Map {\"2\": {\"a\": 99}}}).not.toEqual(Immutable.Map {\"1\": Immutable.Map {\"2\": {\"a\": 99}}}) (39)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Immutable.Map {"1": Immutable.Map {"2": {"a": 99}}} +`; + +module.exports[".toEqual() {pass: true} expect([97, 98, 99]).not.toEqual([97, 98, 99]) (40)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [97, 98, 99] +`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": 2}).not.toEqual(ObjectContaining {\"a\": 1}) (41)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not ObjectContaining {"a": 1} +Received: {"a": 1, "b": 2}`; + +module.exports[".toEqual() {pass: true} expect([1, 2, 3]).not.toEqual(ArrayContaining [2, 3]) (42)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not ArrayContaining [2, 3] +Received: [1, 2, 3]`; + +module.exports[".toEqual() {pass: true} expect(\"abcd\").not.toEqual(StringContaining \"bc\") (43)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not StringContaining "bc" +Received: "abcd"`; + +module.exports[".toEqual() {pass: true} expect(\"abcd\").not.toEqual(StringMatching /bc/) (44)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not StringMatching /bc/ +Received: "abcd"`; + +module.exports[".toEqual() {pass: true} expect(true).not.toEqual(Anything) (45)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Anything +Received: true`; + +module.exports[".toEqual() {pass: true} expect([Function anonymous]).not.toEqual(Any) (46)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not Any +Received: [Function anonymous]`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": [Function b], \"c\": true}).not.toEqual({\"a\": 1, \"b\": Any, \"c\": Anything}) (47)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": Any, "c": Anything} +Received: {"a": 1, "b": [Function b], "c": true}`; + +module.exports[".toEqual() {pass: true} expect(\"Alice\").not.toEqual({\"asymmetricMatch\": [Function asymmetricMatch]}) (48)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"asymmetricMatch": [Function asymmetricMatch]} +Received: "Alice"`; + +module.exports[".toEqual() {pass: true} expect({\"nodeName\": \"div\", \"nodeType\": 1}).not.toEqual({\"nodeName\": \"div\", \"nodeType\": 1}) (49)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"nodeName": "div", "nodeType": 1} +`; + +module.exports[".toEqual() {pass: true} expect({Symbol(foo): 1, Symbol(bar): 2}).not.toEqual({Symbol(foo): Any, Symbol(bar): 2}) (50)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {Symbol(foo): Any, Symbol(bar): 2} +Received: {Symbol(foo): 1, Symbol(bar): 2}`; + +module.exports[".toEqual() {pass: true} expect([, , 1, ]).not.toEqual([, , 1, ]) (51)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [, , 1, ] +`; + +module.exports[".toEqual() {pass: true} expect([, , 1, , ]).not.toEqual([, , 1, undefined, ]) (52)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [, , 1, undefined, ] +Received: [, , 1, , ]`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": [Function b]}).not.toEqual({\"a\": 1, \"b\": optionalFn<>}) (53)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": optionalFn<>} +Received: {"a": 1, "b": [Function b]}`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": optionalFn<>}).not.toEqual({\"a\": 1, \"b\": [Function b]}) (54)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": [Function b]} +Received: {"a": 1, "b": optionalFn<>}`; + +module.exports[".toEqual() {pass: true} expect([1, [Function anonymous]]).not.toEqual([1, optionalFn<>]) (55)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, optionalFn<>] +Received: [1, [Function anonymous]]`; + +module.exports[".toEqual() {pass: true} expect([1, optionalFn<>]).not.toEqual([1, [Function anonymous]]) (56)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, [Function anonymous]] +Received: [1, optionalFn<>]`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": undefined}).not.toEqual({\"a\": 1, \"b\": optionalFn<>}) (57)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": optionalFn<>} +Received: {"a": 1, "b": undefined}`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": optionalFn<>}).not.toEqual({\"a\": 1, \"b\": undefined}) (58)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": undefined} +Received: {"a": 1, "b": optionalFn<>}`; + +module.exports[".toEqual() {pass: true} expect([1, undefined]).not.toEqual([1, optionalFn<>]) (59)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, optionalFn<>] +Received: [1, undefined]`; + +module.exports[".toEqual() {pass: true} expect([1, optionalFn<>]).not.toEqual([1, undefined]) (60)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, undefined] +Received: [1, optionalFn<>]`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1}).not.toEqual({\"a\": 1, \"b\": optionalFn<>}) (61)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1, "b": optionalFn<>} +Received: {"a": 1}`; + +module.exports[".toEqual() {pass: true} expect({\"a\": 1, \"b\": optionalFn<>}).not.toEqual({\"a\": 1}) (62)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not {"a": 1} +Received: {"a": 1, "b": optionalFn<>}`; + +module.exports[".toEqual() {pass: true} expect([1]).not.toEqual([1, optionalFn<>]) (63)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1, optionalFn<>] +Received: [1]`; + +module.exports[".toEqual() {pass: true} expect([1, optionalFn<>]).not.toEqual([1]) (64)"] = `expect(received).not.toEqual(expected) // deep equality + +Expected: not [1] +Received: [1, optionalFn<>]`; + +module.exports[".toBeInstanceOf() passing Map {} and [Function Map] (0)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not Map +`; + +module.exports[".toBeInstanceOf() passing [] and [Function Array] (1)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not Array +`; + +module.exports[".toBeInstanceOf() passing {} and [Function A] (2)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not A +`; + +module.exports[".toBeInstanceOf() passing {} and [Function B] (3)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not B +Received constructor: C extends B +`; + +module.exports[".toBeInstanceOf() passing {} and [Function B] (4)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not B +Received constructor: E extends … extends B +`; + +module.exports[".toBeInstanceOf() passing {} and [Function anonymous] (5)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor name is an empty string +Received constructor: SubHasNameProp +`; + +module.exports[".toBeInstanceOf() passing {} and [Function B] (6)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor: not B +Received constructor name is not a string +`; + +module.exports[".toBeInstanceOf() passing {} and [Function name() {}] (7)"] = `expect(received).not.toBeInstanceOf(expected) + +Expected constructor name is not a string +`; + +module.exports[".toBeInstanceOf() failing \"a\" and [Function String] (0)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: String + +Received value has no prototype +Received value: "a"`; + +module.exports[".toBeInstanceOf() failing 1 and [Function Number] (1)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: Number + +Received value has no prototype +Received value: 1`; + +module.exports[".toBeInstanceOf() failing true and [Function Boolean] (2)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: Boolean + +Received value has no prototype +Received value: true`; + +module.exports[".toBeInstanceOf() failing {} and [Function B] (3)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: B +Received constructor: A +`; + +module.exports[".toBeInstanceOf() failing {} and [Function A] (4)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: A + +Received value has no prototype +Received value: {}`; + +module.exports[".toBeInstanceOf() failing undefined and [Function String] (5)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: String + +Received value has no prototype +Received value: undefined`; + +module.exports[".toBeInstanceOf() failing null and [Function String] (6)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: String + +Received value has no prototype +Received value: null`; + +module.exports[".toBeInstanceOf() failing /\\w+/ and [Function anonymous] (7)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor name is an empty string +Received constructor: RegExp +`; + +module.exports[".toBeInstanceOf() failing {} and [Function RegExp] (8)"] = `expect(received).toBeInstanceOf(expected) + +Expected constructor: RegExp +Received constructor name is an empty string +`; + +module.exports[".toBeInstanceOf() throws if constructor is not a function"] = `expect(received).toBeInstanceOf(expected) + +Matcher error: expected value must be a function + +Expected has type: number +Expected has value: 4`; + +module.exports[".toBeTruthy(), .toBeFalsy() does not accept arguments"] = `expect(received).toBeTruthy() + +Matcher error: this matcher must not have an expected argument + +Expected has value: null`; + +module.exports[".toBeTruthy(), .toBeFalsy() does not accept arguments #1"] = `expect(received).not.toBeFalsy() + +Matcher error: this matcher must not have an expected argument + +Expected has value: null`; + +module.exports[".toBeTruthy(), .toBeFalsy() '{}' is truthy"] = `expect(received).not.toBeTruthy() + +Received: {}`; + +module.exports[".toBeTruthy(), .toBeFalsy() '{}' is truthy #1"] = `expect(received).toBeFalsy() + +Received: {}`; + +module.exports[".toBeTruthy(), .toBeFalsy() '[]' is truthy"] = `expect(received).not.toBeTruthy() + +Received: []`; + +module.exports[".toBeTruthy(), .toBeFalsy() '[]' is truthy #1"] = `expect(received).toBeFalsy() + +Received: []`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'true' is truthy"] = `expect(received).not.toBeTruthy() + +Received: true`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'true' is truthy #1"] = `expect(received).toBeFalsy() + +Received: true`; + +module.exports[".toBeTruthy(), .toBeFalsy() '1' is truthy"] = `expect(received).not.toBeTruthy() + +Received: 1`; + +module.exports[".toBeTruthy(), .toBeFalsy() '1' is truthy #1"] = `expect(received).toBeFalsy() + +Received: 1`; + +module.exports[".toBeTruthy(), .toBeFalsy() '\"a\"' is truthy"] = `expect(received).not.toBeTruthy() + +Received: "a"`; + +module.exports[".toBeTruthy(), .toBeFalsy() '\"a\"' is truthy #1"] = `expect(received).toBeFalsy() + +Received: "a"`; + +module.exports[".toBeTruthy(), .toBeFalsy() '0.5' is truthy"] = `expect(received).not.toBeTruthy() + +Received: 0.5`; + +module.exports[".toBeTruthy(), .toBeFalsy() '0.5' is truthy #1"] = `expect(received).toBeFalsy() + +Received: 0.5`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'Map {}' is truthy"] = `expect(received).not.toBeTruthy() + +Received: Map {}`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'Map {}' is truthy #1"] = `expect(received).toBeFalsy() + +Received: Map {}`; + +module.exports[".toBeTruthy(), .toBeFalsy() '[Function anonymous]' is truthy"] = `expect(received).not.toBeTruthy() + +Received: [Function anonymous]`; + +module.exports[".toBeTruthy(), .toBeFalsy() '[Function anonymous]' is truthy #1"] = `expect(received).toBeFalsy() + +Received: [Function anonymous]`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'Infinity' is truthy"] = `expect(received).not.toBeTruthy() + +Received: Infinity`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'Infinity' is truthy #1"] = `expect(received).toBeFalsy() + +Received: Infinity`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'false' is falsy"] = `expect(received).toBeTruthy() + +Received: false`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'false' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: false`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'null' is falsy"] = `expect(received).toBeTruthy() + +Received: null`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'null' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: null`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'NaN' is falsy"] = `expect(received).toBeTruthy() + +Received: NaN`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'NaN' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: NaN`; + +module.exports[".toBeTruthy(), .toBeFalsy() '0' is falsy"] = `expect(received).toBeTruthy() + +Received: 0`; + +module.exports[".toBeTruthy(), .toBeFalsy() '0' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: 0`; + +module.exports[".toBeTruthy(), .toBeFalsy() '\"\"' is falsy"] = `expect(received).toBeTruthy() + +Received: ""`; + +module.exports[".toBeTruthy(), .toBeFalsy() '\"\"' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: ""`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'undefined' is falsy"] = `expect(received).toBeTruthy() + +Received: undefined`; + +module.exports[".toBeTruthy(), .toBeFalsy() 'undefined' is falsy #1"] = `expect(received).not.toBeFalsy() + +Received: undefined`; + +module.exports[".toBeNaN() {pass: true} expect(NaN).toBeNaN()"] = `expect(received).not.toBeNaN() + +Received: NaN`; + +module.exports[".toBeNaN() {pass: true} expect(NaN).toBeNaN() #1"] = `expect(received).not.toBeNaN() + +Received: NaN`; + +module.exports[".toBeNaN() {pass: true} expect(NaN).toBeNaN() #2"] = `expect(received).not.toBeNaN() + +Received: NaN`; + +module.exports[".toBeNaN() {pass: true} expect(NaN).toBeNaN() #3"] = `expect(received).not.toBeNaN() + +Received: NaN`; + +module.exports[".toBeNaN() throws"] = `expect(received).toBeNaN() + +Received: 1`; + +module.exports[".toBeNaN() throws #1"] = `expect(received).toBeNaN() + +Received: ""`; + +module.exports[".toBeNaN() throws #2"] = `expect(received).toBeNaN() + +Received: null`; + +module.exports[".toBeNaN() throws #3"] = `expect(received).toBeNaN() + +Received: undefined`; + +module.exports[".toBeNaN() throws #4"] = `expect(received).toBeNaN() + +Received: {}`; + +module.exports[".toBeNaN() throws #5"] = `expect(received).toBeNaN() + +Received: []`; + +module.exports[".toBeNaN() throws #6"] = `expect(received).toBeNaN() + +Received: 0.2`; + +module.exports[".toBeNaN() throws #7"] = `expect(received).toBeNaN() + +Received: 0`; + +module.exports[".toBeNaN() throws #8"] = `expect(received).toBeNaN() + +Received: Infinity`; + +module.exports[".toBeNaN() throws #9"] = `expect(received).toBeNaN() + +Received: -Infinity`; + +module.exports[".toBeNull() fails for '{}'"] = `expect(received).toBeNull() + +Received: {}`; + +module.exports[".toBeNull() fails for '[]'"] = `expect(received).toBeNull() + +Received: []`; + +module.exports[".toBeNull() fails for 'true'"] = `expect(received).toBeNull() + +Received: true`; + +module.exports[".toBeNull() fails for '1'"] = `expect(received).toBeNull() + +Received: 1`; + +module.exports[".toBeNull() fails for '\"a\"'"] = `expect(received).toBeNull() + +Received: "a"`; + +module.exports[".toBeNull() fails for '0.5'"] = `expect(received).toBeNull() + +Received: 0.5`; + +module.exports[".toBeNull() fails for 'Map {}'"] = `expect(received).toBeNull() + +Received: Map {}`; + +module.exports[".toBeNull() fails for '[Function anonymous]'"] = `expect(received).toBeNull() + +Received: [Function anonymous]`; + +module.exports[".toBeNull() fails for 'Infinity'"] = `expect(received).toBeNull() + +Received: Infinity`; + +module.exports[".toBeNull() fails for null with .not"] = `expect(received).not.toBeNull() + +Received: null`; + +module.exports[".toBeDefined(), .toBeUndefined() '{}' is defined"] = `expect(received).not.toBeDefined() + +Received: {}`; + +module.exports[".toBeDefined(), .toBeUndefined() '{}' is defined #1"] = `expect(received).toBeUndefined() + +Received: {}`; + +module.exports[".toBeDefined(), .toBeUndefined() '[]' is defined"] = `expect(received).not.toBeDefined() + +Received: []`; + +module.exports[".toBeDefined(), .toBeUndefined() '[]' is defined #1"] = `expect(received).toBeUndefined() + +Received: []`; + +module.exports[".toBeDefined(), .toBeUndefined() 'true' is defined"] = `expect(received).not.toBeDefined() + +Received: true`; + +module.exports[".toBeDefined(), .toBeUndefined() 'true' is defined #1"] = `expect(received).toBeUndefined() + +Received: true`; + +module.exports[".toBeDefined(), .toBeUndefined() '1' is defined"] = `expect(received).not.toBeDefined() + +Received: 1`; + +module.exports[".toBeDefined(), .toBeUndefined() '1' is defined #1"] = `expect(received).toBeUndefined() + +Received: 1`; + +module.exports[".toBeDefined(), .toBeUndefined() '\"a\"' is defined"] = `expect(received).not.toBeDefined() + +Received: "a"`; + +module.exports[".toBeDefined(), .toBeUndefined() '\"a\"' is defined #1"] = `expect(received).toBeUndefined() + +Received: "a"`; + +module.exports[".toBeDefined(), .toBeUndefined() '0.5' is defined"] = `expect(received).not.toBeDefined() + +Received: 0.5`; + +module.exports[".toBeDefined(), .toBeUndefined() '0.5' is defined #1"] = `expect(received).toBeUndefined() + +Received: 0.5`; + +module.exports[".toBeDefined(), .toBeUndefined() 'Map {}' is defined"] = `expect(received).not.toBeDefined() + +Received: Map {}`; + +module.exports[".toBeDefined(), .toBeUndefined() 'Map {}' is defined #1"] = `expect(received).toBeUndefined() + +Received: Map {}`; + +module.exports[".toBeDefined(), .toBeUndefined() '[Function anonymous]' is defined"] = `expect(received).not.toBeDefined() + +Received: [Function anonymous]`; + +module.exports[".toBeDefined(), .toBeUndefined() '[Function anonymous]' is defined #1"] = `expect(received).toBeUndefined() + +Received: [Function anonymous]`; + +module.exports[".toBeDefined(), .toBeUndefined() 'Infinity' is defined"] = `expect(received).not.toBeDefined() + +Received: Infinity`; + +module.exports[".toBeDefined(), .toBeUndefined() 'Infinity' is defined #1"] = `expect(received).toBeUndefined() + +Received: Infinity`; + +module.exports[".toBeDefined(), .toBeUndefined() undefined is undefined"] = `expect(received).toBeDefined() + +Received: undefined`; + +module.exports[".toBeDefined(), .toBeUndefined() undefined is undefined #1"] = `expect(received).not.toBeUndefined() + +Received: undefined`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 2 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 2 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 1 +Received: 2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 1 +Received: 2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 2 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 2 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 1 +Received: 2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [1, 2] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 1 +Received: 2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > Infinity +Received: -Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < Infinity +Received: -Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > -Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < -Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= Infinity +Received: -Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= Infinity +Received: -Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= -Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [-Infinity, Infinity] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= -Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 1.7976931348623157e+308 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 1.7976931348623157e+308 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 5e-324 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 5e-324 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 1.7976931348623157e+308 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 1.7976931348623157e+308 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 5e-324 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [5e-324, 1.7976931348623157e+308] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 5e-324 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 34 +Received: 17`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 34 +Received: 17`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 17 +Received: 34`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 17 +Received: 34`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 34 +Received: 17`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 34 +Received: 17`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 17 +Received: 34`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [17, 34] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 17 +Received: 34`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 7 +Received: 3`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 7 +Received: 3`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 3 +Received: 7`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 3 +Received: 7`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 7 +Received: 3`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 7 +Received: 3`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 3 +Received: 7`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [3, 7] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 3 +Received: 7`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 18 +Received: 9`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 18 +Received: 9`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 9 +Received: 18`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 9 +Received: 18`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 18 +Received: 9`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 18 +Received: 9`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 9 +Received: 18`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [9, 18] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 9 +Received: 18`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2]"] = `expect(received).toBeGreaterThan(expected) + +Expected: > 0.2 +Received: 0.1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #1"] = `expect(received).not.toBeLessThan(expected) + +Expected: not < 0.2 +Received: 0.1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #2"] = `expect(received).not.toBeGreaterThan(expected) + +Expected: not > 0.1 +Received: 0.2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #3"] = `expect(received).toBeLessThan(expected) + +Expected: < 0.1 +Received: 0.2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #4"] = `expect(received).toBeGreaterThanOrEqual(expected) + +Expected: >= 0.2 +Received: 0.1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #5"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 0.2 +Received: 0.1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #6"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 0.1 +Received: 0.2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() throws: [0.1, 0.2] #7"] = `expect(received).toBeLessThanOrEqual(expected) + +Expected: <= 0.1 +Received: 0.2`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1, 1]"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 1 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1, 1] #1"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 1 +Received: 1`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [5e-324, 5e-324]"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 5e-324 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [5e-324, 5e-324] #1"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 5e-324 +Received: 5e-324`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1.7976931348623157e+308, 1.7976931348623157e+308]"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= 1.7976931348623157e+308 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [1.7976931348623157e+308, 1.7976931348623157e+308] #1"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= 1.7976931348623157e+308 +Received: 1.7976931348623157e+308`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [Infinity, Infinity]"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [Infinity, Infinity] #1"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= Infinity +Received: Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [-Infinity, -Infinity]"] = `expect(received).not.toBeGreaterThanOrEqual(expected) + +Expected: not >= -Infinity +Received: -Infinity`; + +module.exports[".toBeGreaterThan(), .toBeLessThan(), .toBeGreaterThanOrEqual(), .toBeLessThanOrEqual() equal numbers: [-Infinity, -Infinity] #1"] = `expect(received).not.toBeLessThanOrEqual(expected) + +Expected: not <= -Infinity +Received: -Infinity`; + +module.exports[".toContain(), .toContainEqual() '[1, 2, 3, 4]' contains '1'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not 1 +Received array: [1, 2, 3, 4]`; + +module.exports[".toContain(), .toContainEqual() '[\"a\", \"b\", \"c\", \"d\"]' contains '\"a\"'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not "a" +Received array: ["a", "b", "c", "d"]`; + +module.exports[".toContain(), .toContainEqual() '[undefined, null]' contains 'null'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not null +Received array: [undefined, null]`; + +module.exports[".toContain(), .toContainEqual() '[undefined, null]' contains 'undefined'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not undefined +Received array: [undefined, null]`; + +module.exports[".toContain(), .toContainEqual() '[Symbol(a)]' contains 'Symbol(a)'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not Symbol(a) +Received array: [Symbol(a)]`; + +module.exports[".toContain(), .toContainEqual() '\"abcdef\"' contains '\"abc\"'"] = `expect(received).not.toContain(expected) // indexOf + +Expected substring: not "abc" +Received string: "abcdef"`; + +module.exports[".toContain(), .toContainEqual() '\"11112111\"' contains '\"2\"'"] = `expect(received).not.toContain(expected) // indexOf + +Expected substring: not "2" +Received string: "11112111"`; + +module.exports[".toContain(), .toContainEqual() 'Set {\"abc\", \"def\"}' contains '\"abc\"'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not "abc" +Received set: Set {"abc", "def"}`; + +module.exports[".toContain(), .toContainEqual() '[0, 1]' contains '1'"] = `expect(received).not.toContain(expected) // indexOf + +Expected value: not 1 +Received object: [0, 1]`; + +module.exports[".toContain(), .toContainEqual() '[1, 2, 3]' does not contain '4'"] = `expect(received).toContain(expected) // indexOf + +Expected value: 4 +Received array: [1, 2, 3]`; + +module.exports[".toContain(), .toContainEqual() '[null, undefined]' does not contain '1'"] = `expect(received).toContain(expected) // indexOf + +Expected value: 1 +Received array: [null, undefined]`; + +module.exports[".toContain(), .toContainEqual() '[{}, []]' does not contain '[]'"] = `expect(received).toContain(expected) // indexOf + +Expected value: [] +Received array: [{}, []] + +Looks like you wanted to test for object/array equality with the stricter \`toContain\` matcher. You probably need to use \`toContainEqual\` instead.`; + +module.exports[".toContain(), .toContainEqual() '[{}, []]' does not contain '{}'"] = `expect(received).toContain(expected) // indexOf + +Expected value: {} +Received array: [{}, []] + +Looks like you wanted to test for object/array equality with the stricter \`toContain\` matcher. You probably need to use \`toContainEqual\` instead.`; + +module.exports[".toContain(), .toContainEqual() error cases"] = `expect(received).toContain(expected) // indexOf + +Matcher error: received value must not be null nor undefined + +Received has value: null`; + +module.exports[".toContain(), .toContainEqual() error cases #1"] = `expect(-0).toContain(0) // indexOf + +Matcher error: expected value must be a string if received value is a string + +Expected has type: number +Expected has value: -0 +Received has type: string +Received has value: "-0"`; + +module.exports[".toContain(), .toContainEqual() error cases #2"] = `expect(null).toContain(null) // indexOf + +Matcher error: expected value must be a string if received value is a string + +Expected has value: null +Received has type: string +Received has value: "null"`; + +module.exports[".toContain(), .toContainEqual() error cases #3"] = `expect(undefined).toContain(undefined) // indexOf + +Matcher error: expected value must be a string if received value is a string + +Expected has value: undefined +Received has type: string +Received has value: "undefined"`; + +module.exports[".toContain(), .toContainEqual() error cases #4"] = `expect(false).toContain(false) // indexOf + +Matcher error: expected value must be a string if received value is a string + +Expected has type: boolean +Expected has value: false +Received has type: string +Received has value: "false"`; + +module.exports[".toContain(), .toContainEqual() '[1, 2, 3, 4]' contains a value equal to '1'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not 1 +Received array: [1, 2, 3, 4]`; + +module.exports[".toContain(), .toContainEqual() '[\"a\", \"b\", \"c\", \"d\"]' contains a value equal to '\"a\"'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not "a" +Received array: ["a", "b", "c", "d"]`; + +module.exports[".toContain(), .toContainEqual() '[undefined, null]' contains a value equal to 'null'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not null +Received array: [undefined, null]`; + +module.exports[".toContain(), .toContainEqual() '[undefined, null]' contains a value equal to 'undefined'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not undefined +Received array: [undefined, null]`; + +module.exports[".toContain(), .toContainEqual() '[Symbol(a)]' contains a value equal to 'Symbol(a)'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not Symbol(a) +Received array: [Symbol(a)]`; + +module.exports[".toContain(), .toContainEqual() '[{\"a\": \"b\"}, {\"a\": \"c\"}]' contains a value equal to '{\"a\": \"b\"}'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not {"a": "b"} +Received array: [{"a": "b"}, {"a": "c"}]`; + +module.exports[".toContain(), .toContainEqual() 'Set {1, 2, 3, 4}' contains a value equal to '1'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not 1 +Received set: Set {1, 2, 3, 4}`; + +module.exports[".toContain(), .toContainEqual() '[0, 1]' contains a value equal to '1'"] = `expect(received).not.toContainEqual(expected) // deep equality + +Expected value: not 1 +Received object: [0, 1]`; + +module.exports[".toContain(), .toContainEqual() '[{\"a\": \"b\"}, {\"a\": \"c\"}]' does not contain a value equal to'{\"a\": \"d\"}'"] = `expect(received).toContainEqual(expected) // deep equality + +Expected value: {"a": "d"} +Received array: [{"a": "b"}, {"a": "c"}]`; + +module.exports[".toContain(), .toContainEqual() error cases for toContainEqual"] = `expect(received).toContainEqual(expected) // deep equality + +Matcher error: received value must not be null nor undefined + +Received has value: null`; + +module.exports[".toBeCloseTo {pass: true} expect(0).toBeCloseTo(0)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 0 +`; + +module.exports[".toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.001)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 0.001 +Received: 0 + +Expected precision: 2 +Expected difference: not < 0.005 +Received difference: 0.001`; + +module.exports[".toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.229)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 1.229 +Received: 1.23 + +Expected precision: 2 +Expected difference: not < 0.005 +Received difference: 0.0009999999999998899`; + +module.exports[".toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.226)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 1.226 +Received: 1.23 + +Expected precision: 2 +Expected difference: not < 0.005 +Received difference: 0.0040000000000000036`; + +module.exports[".toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.225)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 1.225 +Received: 1.23 + +Expected precision: 2 +Expected difference: not < 0.005 +Received difference: 0.004999999999999893`; + +module.exports[".toBeCloseTo {pass: true} expect(1.23).toBeCloseTo(1.234)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not 1.234 +Received: 1.23 + +Expected precision: 2 +Expected difference: not < 0.005 +Received difference: 0.0040000000000000036`; + +module.exports[".toBeCloseTo {pass: true} expect(Infinity).toBeCloseTo(Infinity)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not Infinity +`; + +module.exports[".toBeCloseTo {pass: true} expect(-Infinity).toBeCloseTo(-Infinity)"] = `expect(received).not.toBeCloseTo(expected) + +Expected: not -Infinity +`; + +module.exports[".toBeCloseTo {pass: false} expect(0).toBeCloseTo(0.01)"] = `expect(received).toBeCloseTo(expected) + +Expected: 0.01 +Received: 0 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.01`; + +module.exports[".toBeCloseTo {pass: false} expect(1).toBeCloseTo(1.23)"] = `expect(received).toBeCloseTo(expected) + +Expected: 1.23 +Received: 1 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.22999999999999998`; + +module.exports[".toBeCloseTo {pass: false} expect(1.23).toBeCloseTo(1.2249999)"] = `expect(received).toBeCloseTo(expected) + +Expected: 1.2249999 +Received: 1.23 + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: 0.005000099999999952`; + +module.exports[".toBeCloseTo {pass: false} expect(Infinity).toBeCloseTo(-Infinity)"] = `expect(received).toBeCloseTo(expected) + +Expected: -Infinity +Received: Infinity + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: Infinity`; + +module.exports[".toBeCloseTo {pass: false} expect(Infinity).toBeCloseTo(1.23)"] = `expect(received).toBeCloseTo(expected) + +Expected: 1.23 +Received: Infinity + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: Infinity`; + +module.exports[".toBeCloseTo {pass: false} expect(-Infinity).toBeCloseTo(-1.23)"] = `expect(received).toBeCloseTo(expected) + +Expected: -1.23 +Received: -Infinity + +Expected precision: 2 +Expected difference: < 0.005 +Received difference: Infinity`; + +module.exports[".toBeCloseTo {pass: false} expect(3.141592e-7).toBeCloseTo(3e-7, 8)"] = `expect(received).toBeCloseTo(expected, precision) + +Expected: 3e-7 +Received: 3.141592e-7 + +Expected precision: 8 +Expected difference: < 5e-9 +Received difference: 1.4159200000000025e-8`; + +module.exports[".toBeCloseTo {pass: false} expect(56789).toBeCloseTo(51234, -4)"] = `expect(received).toBeCloseTo(expected, precision) + +Expected: 51234 +Received: 56789 + +Expected precision: -4 +Expected difference: < 5000 +Received difference: 5555`; + +module.exports[".toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.1, 0)"] = `expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.1 +Received: 0 + +Expected precision: 0 +Expected difference: not < 0.5 +Received difference: 0.1`; + +module.exports[".toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.0001, 3)"] = `expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.0001 +Received: 0 + +Expected precision: 3 +Expected difference: not < 0.0005 +Received difference: 0.0001`; + +module.exports[".toBeCloseTo {pass: true} expect(0).toBeCloseTo(0.000004, 5)"] = `expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 0.000004 +Received: 0 + +Expected precision: 5 +Expected difference: not < 0.000005 +Received difference: 0.000004`; + +module.exports[".toBeCloseTo {pass: true} expect(2.0000002).toBeCloseTo(2, 5)"] = `expect(received).not.toBeCloseTo(expected, precision) + +Expected: not 2 +Received: 2.0000002 + +Expected precision: 5 +Expected difference: not < 5e-6 +Received difference: 2.0000000011677344e-7`; + +module.exports[".toBeCloseTo throws: Matcher error promise empty isNot false received"] = `expect(received).toBeCloseTo(expected, precision) + +Matcher error: received value must be a number + +Received has type: string +Received has value: ""`; + +module.exports[".toBeCloseTo throws: Matcher error promise empty isNot true expected"] = `expect(received).not.toBeCloseTo(expected) + +Matcher error: expected value must be a number + +Expected has value: undefined`; + +module.exports[".toBeCloseTo throws: Matcher error promise rejects isNot false expected"] = `callback is not a function`; + +module.exports[".toBeCloseTo throws: Matcher error promise rejects isNot true received"] = `callback is not a function`; + +module.exports[".toBeCloseTo throws: Matcher error promise resolves isNot false received"] = `callback is not a function`; + +module.exports[".toBeCloseTo throws: Matcher error promise resolves isNot true expected"] = `callback is not a function`; + +module.exports[".toMatch() {pass: true} expect(foo).toMatch(foo)"] = `expect(received).not.toMatch(expected) + +Expected substring: not "foo" +Received string: "foo"`; + +module.exports[".toMatch() {pass: true} expect(Foo bar).toMatch(/^foo/i)"] = `expect(received).not.toMatch(expected) + +Expected pattern: not /^foo/i +Received string: "Foo bar"`; + +module.exports[".toMatch() throws: [bar, foo]"] = `expect(received).toMatch(expected) + +Expected substring: "foo" +Received string: "bar"`; + +module.exports[".toMatch() throws: [bar, /foo/]"] = `expect(received).toMatch(expected) + +Expected pattern: /foo/ +Received string: "bar"`; + +module.exports[".toMatch() throws if non String actual value passed: [1, \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: number +Received has value: 1`; + +module.exports[".toMatch() throws if non String actual value passed: [{}, \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: object +Received has value: {}`; + +module.exports[".toMatch() throws if non String actual value passed: [[], \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: array +Received has value: []`; + +module.exports[".toMatch() throws if non String actual value passed: [true, \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: boolean +Received has value: true`; + +module.exports[".toMatch() throws if non String actual value passed: [/foo/i, \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: regexp +Received has value: /foo/i`; + +module.exports[".toMatch() throws if non String actual value passed: [[Function anonymous], \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has type: function +Received has value: [Function anonymous]`; + +module.exports[".toMatch() throws if non String actual value passed: [undefined, \"foo\"]"] = `expect(received).toMatch(expected) + +Matcher error: received value must be a string + +Received has value: undefined`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", 1]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has type: number +Expected has value: 1`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", {}]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has type: object +Expected has value: {}`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", []]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has type: array +Expected has value: []`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", true]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has type: boolean +Expected has value: true`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", [Function anonymous]]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports[".toMatch() throws if non String/RegExp expected value passed: [\"foo\", undefined]"] = `expect(received).toMatch(expected) + +Matcher error: expected value must be a string or regular expression + +Expected has value: undefined`; + +module.exports[".toHaveLength {pass: true} expect([1, 2]).toHaveLength(2)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 2 +Received array: [1, 2]`; + +module.exports[".toHaveLength {pass: true} expect([]).toHaveLength(0)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 0 +Received array: []`; + +module.exports[".toHaveLength {pass: true} expect([\"a\", \"b\"]).toHaveLength(2)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 2 +Received array: ["a", "b"]`; + +module.exports[".toHaveLength {pass: true} expect(\"abc\").toHaveLength(3)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 3 +Received string: "abc"`; + +module.exports[".toHaveLength {pass: true} expect(\"\").toHaveLength(0)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 0 +Received string: ""`; + +module.exports[".toHaveLength {pass: true} expect([Function anonymous]).toHaveLength(0)"] = `expect(received).not.toHaveLength(expected) + +Expected length: not 0 +Received function: [Function anonymous]`; + +module.exports[".toHaveLength {pass: false} expect([1, 2]).toHaveLength(3)"] = `expect(received).toHaveLength(expected) + +Expected length: 3 +Received length: 2 +Received array: [1, 2]`; + +module.exports[".toHaveLength {pass: false} expect([]).toHaveLength(1)"] = `expect(received).toHaveLength(expected) + +Expected length: 1 +Received length: 0 +Received array: []`; + +module.exports[".toHaveLength {pass: false} expect([\"a\", \"b\"]).toHaveLength(99)"] = `expect(received).toHaveLength(expected) + +Expected length: 99 +Received length: 2 +Received array: ["a", "b"]`; + +module.exports[".toHaveLength {pass: false} expect(\"abc\").toHaveLength(66)"] = `expect(received).toHaveLength(expected) + +Expected length: 66 +Received length: 3 +Received string: "abc"`; + +module.exports[".toHaveLength {pass: false} expect(\"\").toHaveLength(1)"] = `expect(received).toHaveLength(expected) + +Expected length: 1 +Received length: 0 +Received string: ""`; + +module.exports[".toHaveLength error cases"] = `expect(received).toHaveLength(expected) + +Matcher error: received value must have a length property whose value must be a number + +Received has type: object +Received has value: {"a": 9}`; + +module.exports[".toHaveLength error cases #1"] = `expect(received).toHaveLength(expected) + +Matcher error: received value must have a length property whose value must be a number + +Received has type: number +Received has value: 0`; + +module.exports[".toHaveLength error cases #2"] = `expect(received).not.toHaveLength(expected) + +Matcher error: received value must have a length property whose value must be a number + +Received has value: undefined`; + +module.exports[".toHaveLength matcher error expected length not number"] = `expect(received).not.toHaveLength(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "3"`; + +module.exports[".toHaveLength matcher error expected length number Infinity"] = `callback is not a function`; + +module.exports[".toHaveLength matcher error expected length number NaN"] = `callback is not a function`; + +module.exports[".toHaveLength matcher error expected length number float"] = `callback is not a function`; + +module.exports[".toHaveLength matcher error expected length number negative integer"] = `callback is not a function`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a.b.c.d', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b.c.d" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a,b,c,d', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: ["a", "b", "c", "d"] + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a.b.c.d\": 1}).toHaveProperty('a.b.c.d', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: ["a.b.c.d"] + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [1, 2, 3]}}).toHaveProperty('a,b,1', 2)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: ["a", "b", 1] + +Expected value: not 2`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [1, 2, 3]}}).toHaveProperty('a,b,1', Any)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: ["a", "b", 1] + +Expected value: not Any +Received value: 2`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": 0}).toHaveProperty('a', 0)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a" + +Expected value: not 0`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": undefined}}).toHaveProperty('a.b', undefined)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b" + +Expected value: not undefined`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": {\"c\": 5}}}).toHaveProperty('a.b', {\"c\": 5})"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b" + +Expected value: not {"c": 5}`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [{\"c\": [{\"d\": 1}]}]}}).toHaveProperty('a.b[0].c[0].d', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b[0].c[0].d" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [{\"c\": {\"d\": [{\"e\": 1}, {\"f\": 2}]}}]}}).toHaveProperty('a.b[0].c.d[1].f', 2)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b[0].c.d[1].f" + +Expected value: not 2`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [[{\"c\": [{\"d\": 1}]}]]}}).toHaveProperty('a.b[0][0].c[0].d', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a.b[0][0].c[0].d" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"property\": 1}).toHaveProperty('property', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "property" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": undefined}).toHaveProperty('a', undefined)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a" + +Expected value: not undefined`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": undefined}).toHaveProperty('b', \"b\")"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "b" + +Expected value: not "b"`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": undefined}).toHaveProperty('setter', undefined)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "setter" + +Expected value: not undefined`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": true}).toHaveProperty('a', undefined)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "a" + +Expected value: not undefined`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": true}).toHaveProperty('c', \"c\")"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "c" + +Expected value: not "c"`; + +module.exports[".toHaveProperty() {pass: true} expect({\"val\": true}).toHaveProperty('val', true)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "val" + +Expected value: not true`; + +module.exports[".toHaveProperty() {pass: true} expect({\"nodeName\": \"DIV\"}).toHaveProperty('nodeType', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "nodeType" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: true} expect(\"\").toHaveProperty('length', 0)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "length" + +Expected value: not 0`; + +module.exports[".toHaveProperty() {pass: true} expect([Function memoized]).toHaveProperty('memo', [])"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "memo" + +Expected value: not []`; + +module.exports[".toHaveProperty() {pass: true} expect({\"\": 1}).toHaveProperty('', 1)"] = `expect(received).not.toHaveProperty(path, value) + +Expected path: "" + +Expected value: not 1`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a.b.ttt.d', 1) (0)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.ttt.d" +Received path: "a.b" + +Expected value: 1 +Received value: {"c": {"d": 1}}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a.b.c.d', 2) (1)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c.d" + +Expected value: 2 +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a.b.c.d\": 1}).toHaveProperty('a.b.c.d', 2) (2)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c.d" +Received path: [] + +Expected value: 2 +Received value: {"a.b.c.d": 1}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a.b.c.d\": 1}).toHaveProperty('a.b.c.d', 2) (3)"] = `expect(received).toHaveProperty(path, value) + +Expected path: ["a.b.c.d"] + +Expected value: 2 +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect({\"children\": [\"\\\"That cartoon\\\"\"], \"props\": null, \"type\": \"p\"}).toHaveProperty('children,0', \"\\\"That cat cartoon\\\"\") (4)"] = `expect(received).toHaveProperty(path, value) + +Expected path: ["children", 0] + +Expected value: "\\"That cat cartoon\\"" +Received value: "\\"That cartoon\\""`; + +module.exports[".toHaveProperty() {pass: false} expect({\"children\": [\"Roses are red.\nViolets are blue.\nTesting with Jest is good for you.\"], \"props\": null, \"type\": \"pre\"}).toHaveProperty('children,0', \"Roses are red, violets are blue.\nTesting with Jest\nIs good for you.\") (5)"] = `expect(received).toHaveProperty(path, value) + +Expected path: ["children", 0] + +- Expected value - 3 ++ Received value + 3 + +- Roses are red, violets are blue. ++ Roses are red. ++ Violets are blue. +- Testing with Jest +- Is good for you. ++ Testing with Jest is good for you.`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a,b,c,d', 2) (6)"] = `expect(received).toHaveProperty(path, value) + +Expected path: ["a", "b", "c", "d"] + +Expected value: 2 +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {}}}}).toHaveProperty('a.b.c.d', 1) (7)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c.d" +Received path: "a.b.c" + +Expected value: 1 +Received value: {}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": 1}).toHaveProperty('a.b.c.d', 5) (8)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c.d" +Received path: "a" + +Expected value: 5 +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect({}).toHaveProperty('a', \"test\") (9)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a" +Received path: [] + +Expected value: "test" +Received value: {}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": 3}}).toHaveProperty('a.b', undefined) (10)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b" + +Expected value: undefined +Received value: 3`; + +module.exports[".toHaveProperty() {pass: false} expect(1).toHaveProperty('a.b.c', \"test\") (11)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c" +Received path: [] + +Expected value: "test" +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect(\"abc\").toHaveProperty('a.b.c', {\"a\": 5}) (12)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b.c" +Received path: [] + +Expected value: {"a": 5} +Received value: "abc"`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": 5}}}).toHaveProperty('a.b', {\"c\": 4}) (13)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b" + +- Expected value - 1 ++ Received value + 1 + + Object { +- "c": 4, ++ "c": 5, + }`; + +module.exports[".toHaveProperty() {pass: false} expect({\"val\": undefined}).toHaveProperty('a', \"a\") (14)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a" + +Expected value: "a" +Received value: undefined`; + +module.exports[".toHaveProperty() {pass: false} expect({\"val\": undefined}).toHaveProperty('b', undefined) (15)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "b" + +Expected value: undefined +Received value: "b"`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {}}).toHaveProperty('a.b', undefined) (16)"] = `expect(received).toHaveProperty(path, value) + +Expected path: "a.b" +Received path: "a" + +Expected value: undefined +Received value: {}`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a.b.c.d')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not "a.b.c.d" + +Received value: 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": {\"c\": {\"d\": 1}}}}).toHaveProperty('a,b,c,d')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not ["a", "b", "c", "d"] + +Received value: 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a.b.c.d\": 1}).toHaveProperty('a.b.c.d')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not ["a.b.c.d"] + +Received value: 1`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": [1, 2, 3]}}).toHaveProperty('a,b,1')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not ["a", "b", 1] + +Received value: 2`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": 0}).toHaveProperty('a')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not "a" + +Received value: 0`; + +module.exports[".toHaveProperty() {pass: true} expect({\"a\": {\"b\": undefined}}).toHaveProperty('a.b')"] = `expect(received).not.toHaveProperty(path) + +Expected path: not "a.b" + +Received value: undefined`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {}}}}).toHaveProperty('a.b.c.d')"] = `expect(received).toHaveProperty(path) + +Expected path: "a.b.c.d" +Received path: "a.b.c" + +Received value: {}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": {\"b\": {\"c\": {}}}}).toHaveProperty('.a.b.c')"] = `expect(received).toHaveProperty(path) + +Expected path: ".a.b.c" +Received path: [] + +Received value: {"a": {"b": {"c": {}}}}`; + +module.exports[".toHaveProperty() {pass: false} expect({\"a\": 1}).toHaveProperty('a.b.c.d')"] = `expect(received).toHaveProperty(path) + +Expected path: "a.b.c.d" +Received path: "a" + +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect({}).toHaveProperty('a')"] = `expect(received).toHaveProperty(path) + +Expected path: "a" +Received path: [] + +Received value: {}`; + +module.exports[".toHaveProperty() {pass: false} expect(1).toHaveProperty('a.b.c')"] = `expect(received).toHaveProperty(path) + +Expected path: "a.b.c" +Received path: [] + +Received value: 1`; + +module.exports[".toHaveProperty() {pass: false} expect(\"abc\").toHaveProperty('a.b.c')"] = `expect(received).toHaveProperty(path) + +Expected path: "a.b.c" +Received path: [] + +Received value: "abc"`; + +module.exports[".toHaveProperty() {pass: false} expect(false).toHaveProperty('key')"] = `expect(received).toHaveProperty(path) + +Expected path: "key" +Received path: [] + +Received value: false`; + +module.exports[".toHaveProperty() {pass: false} expect(0).toHaveProperty('key')"] = `expect(received).toHaveProperty(path) + +Expected path: "key" +Received path: [] + +Received value: 0`; + +module.exports[".toHaveProperty() {pass: false} expect(\"\").toHaveProperty('key')"] = `expect(received).toHaveProperty(path) + +Expected path: "key" +Received path: [] + +Received value: ""`; + +module.exports[".toHaveProperty() {pass: false} expect(Symbol()).toHaveProperty('key')"] = `expect(received).toHaveProperty(path) + +Expected path: "key" +Received path: [] + +Received value: Symbol()`; + +module.exports[".toHaveProperty() {pass: false} expect({\"key\": 1}).toHaveProperty('not')"] = `expect(received).toHaveProperty(path) + +Expected path: "not" +Received path: [] + +Received value: {"key": 1}`; + +module.exports[".toHaveProperty() {error} expect(null).toHaveProperty('a.b')"] = `expect(received).toHaveProperty(path) + +Matcher error: received value must not be null nor undefined + +Received has value: null`; + +module.exports[".toHaveProperty() {error} expect(undefined).toHaveProperty('a')"] = `expect(received).toHaveProperty(path) + +Matcher error: received value must not be null nor undefined + +Received has value: undefined`; + +module.exports[".toHaveProperty() {error} expect({\"a\": {\"b\": {}}}).toHaveProperty('undefined')"] = `expect(received).toHaveProperty(path) + +Matcher error: expected path must be a string or array + +Expected has value: undefined`; + +module.exports[".toHaveProperty() {error} expect({\"a\": {\"b\": {}}}).toHaveProperty('null')"] = `expect(received).toHaveProperty(path) + +Matcher error: expected path must be a string or array + +Expected has value: null`; + +module.exports[".toHaveProperty() {error} expect({\"a\": {\"b\": {}}}).toHaveProperty('1')"] = `expect(received).toHaveProperty(path) + +Matcher error: expected path must be a string or array + +Expected has type: number +Expected has value: 1`; + +module.exports[".toHaveProperty() {error} expect({}).toHaveProperty('')"] = `expect(received).toHaveProperty(path) + +Matcher error: expected path must not be an empty array + +Expected has type: array +Expected has value: []`; + +module.exports["toMatchObject() circular references simple circular references {pass: true} expect({\"a\": \"hello\", \"ref\": [Circular]}).toMatchObject({})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {} +Received: {"a": "hello", "ref": [Circular]}`; + +module.exports["toMatchObject() circular references simple circular references {pass: true} expect({\"a\": \"hello\", \"ref\": [Circular]}).toMatchObject({\"a\": \"hello\", \"ref\": [Circular]})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "hello", "ref": [Circular]}`; + +module.exports["toMatchObject() circular references simple circular references {pass: false} expect({}).toMatchObject({\"a\": \"hello\", \"ref\": [Circular]})"] = `expect(received).toMatchObject(expected) + +- Expected - 4 ++ Received + 1 + +- Object { +- "a": "hello", +- "ref": [Circular], +- } ++ Object {}`; + +module.exports["toMatchObject() circular references simple circular references {pass: false} expect({\"a\": \"hello\", \"ref\": [Circular]}).toMatchObject({\"a\": \"world\", \"ref\": [Circular]})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": "world", ++ "a": "hello", + "ref": [Circular], + }`; + +module.exports["toMatchObject() circular references simple circular references {pass: false} expect({\"ref\": \"not a ref\"}).toMatchObject({\"a\": \"hello\", \"ref\": [Circular]})"] = `expect(received).toMatchObject(expected) + +- Expected - 2 ++ Received + 1 + + Object { +- "a": "hello", +- "ref": [Circular], ++ "ref": "not a ref", + }`; + +module.exports["toMatchObject() circular references transitive circular references {pass: true} expect({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}}).toMatchObject({})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {} +Received: {"a": "hello", "nestedObj": {"parentObj": [Circular]}}`; + +module.exports["toMatchObject() circular references transitive circular references {pass: true} expect({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}}).toMatchObject({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "hello", "nestedObj": {"parentObj": [Circular]}}`; + +module.exports["toMatchObject() circular references transitive circular references {pass: false} expect({}).toMatchObject({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}})"] = `expect(received).toMatchObject(expected) + +- Expected - 6 ++ Received + 1 + +- Object { +- "a": "hello", +- "nestedObj": Object { +- "parentObj": [Circular], +- }, +- } ++ Object {}`; + +module.exports["toMatchObject() circular references transitive circular references {pass: false} expect({\"a\": \"world\", \"nestedObj\": {\"parentObj\": [Circular]}}).toMatchObject({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": "hello", ++ "a": "world", + "nestedObj": Object { + "parentObj": [Circular], + }, + }`; + +module.exports["toMatchObject() circular references transitive circular references {pass: false} expect({\"nestedObj\": {\"parentObj\": \"not the parent ref\"}}).toMatchObject({\"a\": \"hello\", \"nestedObj\": {\"parentObj\": [Circular]}})"] = `expect(received).toMatchObject(expected) + +- Expected - 2 ++ Received + 1 + + Object { +- "a": "hello", + "nestedObj": Object { +- "parentObj": [Circular], ++ "parentObj": "not the parent ref", + }, + }`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"c\": \"d\"}).toMatchObject({\"a\": \"b\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b"} +Received: {"a": "b", "c": "d"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"c\": \"d\"}).toMatchObject({\"a\": \"b\", \"c\": \"d\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b", "c": "d"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"t\": {\"x\": {\"r\": \"r\"}, \"z\": \"z\"}}).toMatchObject({\"a\": \"b\", \"t\": {\"z\": \"z\"}})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b", "t": {"z": "z"}} +Received: {"a": "b", "t": {"x": {"r": "r"}, "z": "z"}}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"t\": {\"x\": {\"r\": \"r\"}, \"z\": \"z\"}}).toMatchObject({\"t\": {\"x\": {\"r\": \"r\"}}})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"t": {"x": {"r": "r"}}} +Received: {"a": "b", "t": {"x": {"r": "r"}, "z": "z"}}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": [3, 4, 5], \"b\": \"b\"}).toMatchObject({\"a\": [3, 4, 5]})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": [3, 4, 5]} +Received: {"a": [3, 4, 5], "b": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": [3, 4, 5, \"v\"], \"b\": \"b\"}).toMatchObject({\"a\": [3, 4, 5, \"v\"]})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": [3, 4, 5, "v"]} +Received: {"a": [3, 4, 5, "v"], "b": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": 1, \"c\": 2}).toMatchObject({\"a\": Any})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": Any} +Received: {"a": 1, "c": 2}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": {\"x\": \"x\", \"y\": \"y\"}}).toMatchObject({\"a\": {\"x\": Any}})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": {"x": Any}} +Received: {"a": {"x": "x", "y": "y"}}`; + +module.exports["toMatchObject() {pass: true} expect(Set {1, 2}).toMatchObject(Set {1, 2})"] = `expect(received).not.toMatchObject(expected) + +Expected: not Set {1, 2}`; + +module.exports["toMatchObject() {pass: true} expect(Set {1, 2}).toMatchObject(Set {2, 1})"] = `expect(received).not.toMatchObject(expected) + +Expected: not Set {2, 1} +Received: Set {1, 2}`; + +module.exports["toMatchObject() {pass: true} expect(2015-11-30T00:00:00.000Z).toMatchObject(2015-11-30T00:00:00.000Z)"] = `expect(received).not.toMatchObject(expected) + +Expected: not 2015-11-30T00:00:00.000Z`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": 2015-11-30T00:00:00.000Z, \"b\": \"b\"}).toMatchObject({\"a\": 2015-11-30T00:00:00.000Z})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": 2015-11-30T00:00:00.000Z} +Received: {"a": 2015-11-30T00:00:00.000Z, "b": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": null, \"b\": \"b\"}).toMatchObject({\"a\": null})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": null} +Received: {"a": null, "b": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": undefined, \"b\": \"b\"}).toMatchObject({\"a\": undefined})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": undefined} +Received: {"a": undefined, "b": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": [{\"a\": \"a\", \"b\": \"b\"}]}).toMatchObject({\"a\": [{\"a\": \"a\"}]})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": [{"a": "a"}]} +Received: {"a": [{"a": "a", "b": "b"}]}`; + +module.exports["toMatchObject() {pass: true} expect([1, 2]).toMatchObject([1, 2])"] = `expect(received).not.toMatchObject(expected) + +Expected: not [1, 2]`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": undefined}).toMatchObject({\"a\": undefined})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": undefined}`; + +module.exports["toMatchObject() {pass: true} expect([]).toMatchObject([])"] = `expect(received).not.toMatchObject(expected) + +Expected: not []`; + +module.exports["toMatchObject() {pass: true} expect([Error: foo]).toMatchObject([Error: foo])"] = `expect(received).not.toMatchObject(expected) + +Expected: not [Error: foo]`; + +module.exports["toMatchObject() {pass: true} expect([Error: bar]).toMatchObject({\"message\": \"bar\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"message": "bar"} +Received: [Error: bar]`; + +module.exports["toMatchObject() {pass: true} expect({}).toMatchObject({\"a\": undefined, \"b\": \"b\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": undefined, "b": "b"} +Received: {}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\"}).toMatchObject({\"a\": \"b\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"c\": \"d\", Symbol(jest): \"jest\"}).toMatchObject({\"a\": \"b\", Symbol(jest): \"jest\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b", Symbol(jest): "jest"} +Received: {"a": "b", "c": "d", Symbol(jest): "jest"}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"c\": \"d\", Symbol(jest): \"jest\"}).toMatchObject({\"a\": \"b\", \"c\": \"d\", Symbol(jest): \"jest\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": "b", "c": "d", Symbol(jest): "jest"}`; + +module.exports["toMatchObject() {pass: true} expect({}).toMatchObject({\"a\": undefined, \"b\": \"b\", \"c\": \"c\"})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"a": undefined, "b": "b", "c": "c"} +Received: {}`; + +module.exports["toMatchObject() {pass: true} expect({}).toMatchObject({\"d\": 4})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"d": 4} +Received: {}`; + +module.exports["toMatchObject() {pass: true} expect({\"a\": \"b\", \"toString\": [Function toString]}).toMatchObject({\"toString\": Any})"] = `expect(received).not.toMatchObject(expected) + +Expected: not {"toString": Any} +Received: {"a": "b", "toString": [Function toString]}`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\", \"c\": \"d\"}).toMatchObject({\"e\": \"b\"})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 2 + + Object { +- "e": "b", ++ "a": "b", ++ "c": "d", + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\", \"c\": \"d\"}).toMatchObject({\"a\": \"b!\", \"c\": \"d\"})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": "b!", ++ "a": "b", + "c": "d", + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"a\", \"c\": \"d\"}).toMatchObject({\"a\": Any})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": Any, ++ "a": "a", + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\", \"t\": {\"x\": {\"r\": \"r\"}, \"z\": \"z\"}}).toMatchObject({\"a\": \"b\", \"t\": {\"z\": [3]}})"] = `expect(received).toMatchObject(expected) + +- Expected - 3 ++ Received + 1 + + Object { + "a": "b", + "t": Object { +- "z": Array [ +- 3, +- ], ++ "z": "z", + }, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\", \"t\": {\"x\": {\"r\": \"r\"}, \"z\": \"z\"}}).toMatchObject({\"t\": {\"l\": {\"r\": \"r\"}}})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 2 + + Object { + "t": Object { +- "l": Object { ++ "x": Object { + "r": "r", + }, ++ "z": "z", + }, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [3, 4, 5], \"b\": \"b\"}).toMatchObject({\"a\": [3, 4, 5, 6]})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 0 + + Object { + "a": Array [ + 3, + 4, + 5, +- 6, + ], + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [3, 4, 5], \"b\": \"b\"}).toMatchObject({\"a\": [3, 4]})"] = `expect(received).toMatchObject(expected) + +- Expected - 0 ++ Received + 1 + + Object { + "a": Array [ + 3, + 4, ++ 5, + ], + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [3, 4, \"v\"], \"b\": \"b\"}).toMatchObject({\"a\": [\"v\"]})"] = `expect(received).toMatchObject(expected) + +- Expected - 0 ++ Received + 2 + + Object { + "a": Array [ ++ 3, ++ 4, + "v", + ], + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [3, 4, 5], \"b\": \"b\"}).toMatchObject({\"a\": {\"b\": 4}})"] = `expect(received).toMatchObject(expected) + +- Expected - 3 ++ Received + 5 + + Object { +- "a": Object { +- "b": 4, +- }, ++ "a": Array [ ++ 3, ++ 4, ++ 5, ++ ], + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [3, 4, 5], \"b\": \"b\"}).toMatchObject({\"a\": {\"b\": Any}})"] = `expect(received).toMatchObject(expected) + +- Expected - 3 ++ Received + 5 + + Object { +- "a": Object { +- "b": Any, +- }, ++ "a": Array [ ++ 3, ++ 4, ++ 5, ++ ], + }`; + +module.exports["toMatchObject() {pass: false} expect([1, 2]).toMatchObject([1, 3])"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Array [ + 1, +- 3, ++ 2, + ]`; + +module.exports["toMatchObject() {pass: false} expect([0]).toMatchObject([-0])"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Array [ +- -0, ++ 0, + ]`; + +module.exports["toMatchObject() {pass: false} expect(Set {1, 2}).toMatchObject(Set {2})"] = `expect(received).toMatchObject(expected) + +- Expected - 0 ++ Received + 1 + + Set { ++ 1, + 2, + }`; + +module.exports["toMatchObject() {pass: false} expect(2015-11-30T00:00:00.000Z).toMatchObject(2015-10-10T00:00:00.000Z)"] = `expect(received).toMatchObject(expected) + +Expected: 2015-10-10T00:00:00.000Z +Received: 2015-11-30T00:00:00.000Z`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": 2015-11-30T00:00:00.000Z, \"b\": \"b\"}).toMatchObject({\"a\": 2015-10-10T00:00:00.000Z})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": 2015-10-10T00:00:00.000Z, ++ "a": 2015-11-30T00:00:00.000Z, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": null, \"b\": \"b\"}).toMatchObject({\"a\": \"4\"})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": "4", ++ "a": null, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": null, \"b\": \"b\"}).toMatchObject({\"a\": undefined})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": undefined, ++ "a": null, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": undefined}).toMatchObject({\"a\": null})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": null, ++ "a": undefined, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": [{\"a\": \"a\", \"b\": \"b\"}]}).toMatchObject({\"a\": [{\"a\": \"c\"}]})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { + "a": Array [ + Object { +- "a": "c", ++ "a": "a", + }, + ], + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": 1, \"b\": 1, \"c\": 1, \"d\": {\"e\": {\"f\": 555}}}).toMatchObject({\"d\": {\"e\": {\"f\": 222}}})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { + "d": Object { + "e": Object { +- "f": 222, ++ "f": 555, + }, + }, + }`; + +module.exports["toMatchObject() {pass: false} expect({}).toMatchObject({\"a\": undefined})"] = `expect(received).toMatchObject(expected) + +- Expected - 3 ++ Received + 1 + +- Object { +- "a": undefined, +- } ++ Object {}`; + +module.exports["toMatchObject() {pass: false} expect([1, 2, 3]).toMatchObject([2, 3, 1])"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Array [ ++ 1, + 2, + 3, +- 1, + ]`; + +module.exports["toMatchObject() {pass: false} expect([1, 2, 3]).toMatchObject([1, 2, 2])"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Array [ + 1, + 2, +- 2, ++ 3, + ]`; + +module.exports["toMatchObject() {pass: false} expect([Error: foo]).toMatchObject([Error: bar])"] = `expect(received).toMatchObject(expected) + +Expected: [Error: bar] +Received: [Error: foo]`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\"}).toMatchObject({\"c\": \"d\"})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "c": "d", ++ "a": "b", + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\", \"c\": \"d\", Symbol(jest): \"jest\"}).toMatchObject({\"a\": \"c\", Symbol(jest): Any})"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 1 + + Object { +- "a": "c", ++ "a": "b", + Symbol(jest): Any, + }`; + +module.exports["toMatchObject() {pass: false} expect({\"a\": \"b\"}).toMatchObject({\"toString\": Any})"] = `expect(received).toMatchObject(expected) + +- Expected - 0 ++ Received + 1 + + Object { ++ "a": "b", + "toString": Any, + }`; + +module.exports["toMatchObject() throws expect(null).toMatchObject({})"] = `expect(received).toMatchObject(expected) + +Matcher error: received value must be a non-null object + +Received has value: null`; + +module.exports["toMatchObject() throws expect(4).toMatchObject({})"] = `expect(received).toMatchObject(expected) + +Matcher error: received value must be a non-null object + +Received has type: number +Received has value: 4`; + +module.exports["toMatchObject() throws expect(\"44\").toMatchObject({})"] = `expect(received).toMatchObject(expected) + +Matcher error: received value must be a non-null object + +Received has type: string +Received has value: "44"`; + +module.exports["toMatchObject() throws expect(true).toMatchObject({})"] = `expect(received).toMatchObject(expected) + +Matcher error: received value must be a non-null object + +Received has type: boolean +Received has value: true`; + +module.exports["toMatchObject() throws expect(undefined).toMatchObject({})"] = `expect(received).toMatchObject(expected) + +Matcher error: received value must be a non-null object + +Received has value: undefined`; + +module.exports["toMatchObject() throws expect({}).toMatchObject(null)"] = `expect(received).toMatchObject(expected) + +Matcher error: expected value must be a non-null object + +Expected has value: null`; + +module.exports["toMatchObject() throws expect({}).toMatchObject(4)"] = `expect(received).toMatchObject(expected) + +Matcher error: expected value must be a non-null object + +Expected has type: number +Expected has value: 4`; + +module.exports["toMatchObject() throws expect({}).toMatchObject(\"some string\")"] = `expect(received).toMatchObject(expected) + +Matcher error: expected value must be a non-null object + +Expected has type: string +Expected has value: "some string"`; + +module.exports["toMatchObject() throws expect({}).toMatchObject(true)"] = `expect(received).toMatchObject(expected) + +Matcher error: expected value must be a non-null object + +Expected has type: boolean +Expected has value: true`; + +module.exports["toMatchObject() throws expect({}).toMatchObject(undefined)"] = `expect(received).toMatchObject(expected) + +Matcher error: expected value must be a non-null object + +Expected has value: undefined`; + +module.exports["toMatchObject() does not match properties up in the prototype chain"] = `expect(received).toMatchObject(expected) + +- Expected - 1 ++ Received + 0 + + Object { + "other": "child", +- "ref": [Circular], + }`; + diff --git a/tests/expect/matchers.test.ts b/tests/expect/matchers.test.ts new file mode 100644 index 0000000000..8824039bab --- /dev/null +++ b/tests/expect/matchers.test.ts @@ -0,0 +1,2338 @@ +/** + * 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, matcherUtils } from '../../packages/playwright/bundles/expect/src/expectBundleImpl'; +import Immutable from 'immutable'; + +const { stringify } = matcherUtils; + +const expectUnderTestAsAny = expectUnderTest as any; + +expectUnderTest.extend({ + optionalFn(fn) { + const pass = fn === undefined || typeof fn === 'function'; + return { message: () => 'expect either a function or undefined', pass }; + }, +}); + +test('should throw if passed two arguments', () => { + expect(() => expectUnderTestAsAny('foo', 'bar')).toThrow( + new Error('Expect takes at most one argument.'), + ); +}); + +test.describe('.rejects', () => { + test('should reject', async () => { + await expectUnderTest(Promise.reject(4)).rejects.toBe(4); + await expectUnderTest(Promise.reject(4)).rejects.not.toBe(5); + await expectUnderTest(Promise.reject(4.2)).rejects.toBeCloseTo(4.2, 5); + await expectUnderTest(Promise.reject(3)).rejects.not.toBeCloseTo(4.2, 5); + await expectUnderTest(Promise.reject({ a: 1, b: 2 })).rejects.toMatchObject({ + a: 1, + }); + await expectUnderTest(Promise.reject({ a: 1, b: 2 })).rejects.not.toMatchObject({ + c: 1, + }); + await expectUnderTest( + Promise.reject(new Error('rejectMessage')), + ).rejects.toMatchObject({ message: 'rejectMessage' }); + await expectUnderTest(Promise.reject(new Error())).rejects.toThrow(); + }); + + test('should reject with toThrow', async () => { + async function fn() { + throw new Error('some error'); + } + await expectUnderTest(fn()).rejects.toThrow('some error'); + }); + + test('should reject async function to toThrow', async () => { + await expectUnderTest(async () => { + throw new Error('Test'); + }).rejects.toThrow('Test'); + }); + + ['a', [1], () => { }, { a: 1 }].forEach(value => { + test(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expectUnderTest(value).rejects.toBe(111); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + }); + + test(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await expectUnderTest(value).rejects.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + + [4, null, true, undefined].forEach(value => { + test(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expectUnderTest(value).rejects.not.toBe(111); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + }); + + test(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await expectUnderTest(value).rejects.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + + test('fails for promise that resolves', async () => { + let error; + try { + await expectUnderTest(Promise.resolve(4)).rejects.toBe(4); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); +}); + +test.describe('.resolves', () => { + test('should resolve', async () => { + await expectUnderTest(Promise.resolve(4)).resolves.toBe(4); + await expectUnderTest(Promise.resolve(4)).resolves.not.toBe(5); + await expectUnderTest(Promise.resolve(4.2)).resolves.toBeCloseTo(4.2, 5); + await expectUnderTest(Promise.resolve(3)).resolves.not.toBeCloseTo(4.2, 5); + await expectUnderTest(Promise.resolve({ a: 1, b: 2 })).resolves.toMatchObject({ + a: 1, + }); + await expectUnderTest(Promise.resolve({ a: 1, b: 2 })).resolves.not.toMatchObject({ + c: 1, + }); + await expectUnderTest( + Promise.resolve(() => { + throw new Error(); + }), + ).resolves.toThrow(); + }); + + ['a', [1], () => { }, { a: 1 }].forEach(value => { + test(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expectUnderTest(value).resolves.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + + test(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await expectUnderTest(value).resolves.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + + [4, null, true, undefined].forEach(value => { + test(`fails non-promise value ${stringify(value)} synchronously`, () => { + let error; + try { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expectUnderTest(value).resolves.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + + test(`fails non-promise value ${stringify(value)}`, async () => { + let error; + try { + await expectUnderTest(value).resolves.not.toBeDefined(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); + }); + + test('fails for promise that rejects', async () => { + let error; + try { + await expectUnderTest(Promise.reject(4)).resolves.toBe(4); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toMatchSnapshot(); + }); +}); + +test.describe('.toBe()', () => { + test('does not throw', () => { + expectUnderTest('a').not.toBe('b'); + expectUnderTest('a').toBe('a'); + expectUnderTest(1).not.toBe(2); + expectUnderTest(1).toBe(1); + expectUnderTest(null).not.toBe(undefined); + expectUnderTest(null).toBe(null); + expectUnderTest(undefined).toBe(undefined); + expectUnderTest(NaN).toBe(NaN); + expectUnderTest(BigInt(1)).not.toBe(BigInt(2)); + expectUnderTest(BigInt(1)).not.toBe(1); + expectUnderTest(BigInt(1)).toBe(BigInt(1)); + }); + + [ + [1, 2], + [true, false], + [() => { }, () => { }], + [{}, {}], + [{ a: 1 }, { a: 1 }], + [{ a: 1 }, { a: 5 }], + [ + { a: () => { }, b: 2 }, + { a: expect.any(Function), b: 2 }, + ], + [{ a: undefined, b: 2 }, { b: 2 }], + [new Date('2020-02-20'), new Date('2020-02-20')], + [new Date('2020-02-21'), new Date('2020-02-20')], + [/received/, /expected/], + [Symbol('received'), Symbol('expected')], + [new Error('received'), new Error('expected')], + ['abc', 'cde'], + ['painless JavaScript testing', 'delightful JavaScript testing'], + ['', 'compare one-line string to empty string'], + ['with \ntrailing space', 'without trailing space'], + ['four\n4\nline\nstring', '3\nline\nstring'], + [[], []], + [null, undefined], + [-0, +0], + ].forEach(([a, b]: [a: any, b: any], index) => { + test(`fails for: ${stringify(a)} and ${stringify(b)} (${index})`, () => { + expect(() => expectUnderTest(a).toBe(b)).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [BigInt(1), BigInt(2)], + [{ a: BigInt(1) }, { a: BigInt(1) }], + ].forEach(([a, b]) => { + test(`fails for: ${stringify(a)} and ${stringify(b)}`, () => { + expect(() => expectUnderTest(a).toBe(b)).toThrow('toBe'); + }); + }); + + [false, 1, 'a', undefined, null, {}, []].forEach(v => { + test(`fails for '${stringify(v)}' with '.not'`, () => { + expect(() => expectUnderTest(v).not.toBe(v)).toThrowErrorMatchingSnapshot(); + }); + }); + + [BigInt(1), BigInt('1')].forEach((v, index) => { + test(`fails for '${stringify(v)}' with '.not' (${index})}`, () => { + expect(() => expectUnderTest(v).not.toBe(v)).toThrow('toBe'); + }); + }); + + test('does not crash on circular references', () => { + const obj: any = {}; + obj.circular = obj; + + expect(() => expectUnderTest(obj).toBe({})).toThrowErrorMatchingSnapshot(); + }); + + test('assertion error matcherResult property contains matcher name, expected and actual values', () => { + const actual = { a: 1 }; + const expected = { a: 2 }; + try { + expectUnderTest(actual).toBe(expected); + } catch (error) { + expect(error.matcherResult).toEqual( + expect.objectContaining({ + actual, + expected, + name: 'toBe', + }), + ); + } + }); +}); + +test.describe('.toStrictEqual()', () => { + class TestClassA { + constructor(public a, public b) { } + } + + class TestClassB { + constructor(public a, public b) { } + } + + const TestClassC = class Child extends TestClassA { + constructor(a, b) { + super(a, b); + } + }; + + const TestClassD = class Child extends TestClassB { + constructor(a, b) { + super(a, b); + } + }; + + test('does not ignore keys with undefined values', () => { + expect({ + a: undefined, + b: 2, + }).not.toStrictEqual({ b: 2 }); + }); + + test('does not ignore keys with undefined values inside an array', () => { + expect([{ a: undefined }]).not.toStrictEqual([{}]); + }); + + test('does not ignore keys with undefined values deep inside an object', () => { + expect([{ a: [{ a: undefined }] }]).not.toStrictEqual([{ a: [{}] }]); + }); + + test('does not consider holes as undefined in sparse arrays', () => { + + expect([, , , 1, , ,]).not.toStrictEqual([, , , 1, undefined, ,]); + }); + + test('passes when comparing same type', () => { + expect({ + test: new TestClassA(1, 2), + }).toStrictEqual({ test: new TestClassA(1, 2) }); + }); + + test('matches the expected snapshot when it fails', () => { + expect(() => + expectUnderTest({ + test: 2, + }).toStrictEqual({ test: new TestClassA(1, 2) }), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest({ + test: new TestClassA(1, 2), + }).not.toStrictEqual({ test: new TestClassA(1, 2) }), + ).toThrowErrorMatchingSnapshot(); + }); + + test('displays substring diff', () => { + const expected = + 'Another caveat is that Jest will not typecheck your tests.'; + const received = + 'Because TypeScript support in Babel is just transpilation, Jest will not type-check your tests as they run.'; + expect(() => + expectUnderTest(received).toStrictEqual(expected), + ).toThrowErrorMatchingSnapshot(); + }); + + test('displays substring diff for multiple lines', () => { + const expected = [ + ' 69 | ', + " 70 | test('assert.doesNotThrow', () => {", + ' > 71 | assert.doesNotThrow(() => {', + ' | ^', + " 72 | throw Error('err!');", + ' 73 | });', + ' 74 | });', + ' at Object.doesNotThrow (__tests__/assertionError.test.js:71:10)', + ].join('\n'); + const received = [ + ' 68 | ', + " 69 | test('assert.doesNotThrow', () => {", + ' > 70 | assert.doesNotThrow(() => {', + ' | ^', + " 71 | throw Error('err!');", + ' 72 | });', + ' 73 | });', + ' at Object.doesNotThrow (__tests__/assertionError.test.js:70:10)', + ].join('\n'); + expect(() => + expectUnderTest(received).toStrictEqual(expected), + ).toThrowErrorMatchingSnapshot(); + }); + + test('does not pass for different types', () => { + expect({ + test: new TestClassA(1, 2), + }).not.toStrictEqual({ test: new TestClassB(1, 2) }); + }); + + test('does not simply compare constructor names', () => { + const c = new TestClassC(1, 2); + const d = new TestClassD(1, 2); + expect(c.constructor.name).toEqual(d.constructor.name); + expect({ test: c }).not.toStrictEqual({ test: d }); + }); + + + test('passes for matching sparse arrays', () => { + expect([, 1]).toStrictEqual([, 1]); + }); + + test('does not pass when sparseness of arrays do not match', () => { + expect([, 1]).not.toStrictEqual([undefined, 1]); + expect([undefined, 1]).not.toStrictEqual([, 1]); + expect([, , , 1]).not.toStrictEqual([, 1]); + }); + + test('does not pass when equally sparse arrays have different values', () => { + expect([, 1]).not.toStrictEqual([, 2]); + }); + + test('does not pass when ArrayBuffers are not equal', () => { + expect(Uint8Array.from([1, 2]).buffer).not.toStrictEqual( + Uint8Array.from([0, 0]).buffer, + ); + expect(Uint8Array.from([2, 1]).buffer).not.toStrictEqual( + Uint8Array.from([2, 2]).buffer, + ); + expect(Uint8Array.from([]).buffer).not.toStrictEqual( + Uint8Array.from([1]).buffer, + ); + }); + + test('passes for matching buffers', () => { + expect(Uint8Array.from([1]).buffer).toStrictEqual( + Uint8Array.from([1]).buffer, + ); + expect(Uint8Array.from([]).buffer).toStrictEqual( + Uint8Array.from([]).buffer, + ); + expect(Uint8Array.from([9, 3]).buffer).toStrictEqual( + Uint8Array.from([9, 3]).buffer, + ); + }); + + test('fails for missing keys even if backed by an asymmetric matcher accepting them', () => { + // issue 12463 + expect({ a: 1 }).not.toStrictEqual({ a: 1, b: expectUnderTestAsAny.optionalFn() }); + expect({ a: 1, b: expectUnderTestAsAny.optionalFn() }).not.toStrictEqual({ a: 1 }); + expect([1]).not.toStrictEqual([1, expectUnderTestAsAny.optionalFn()]); + expect([1, expectUnderTestAsAny.optionalFn()]).not.toStrictEqual([1]); + }); + + test('passes if keys are present and asymmetric matcher accept them', () => { + // issue 12463 + // with a proper function + expect({ a: 1, b: () => { } }).toStrictEqual({ + a: 1, + b: expectUnderTestAsAny.optionalFn(), + }); + expect({ a: 1, b: expectUnderTestAsAny.optionalFn() }).toStrictEqual({ + a: 1, + b: () => { }, + }); + expect([1, () => { }]).toStrictEqual([1, expectUnderTestAsAny.optionalFn()]); + expect([1, expectUnderTestAsAny.optionalFn()]).toStrictEqual([1, () => { }]); + // with undefined + expect({ a: 1, b: undefined }).toStrictEqual({ + a: 1, + b: expectUnderTestAsAny.optionalFn(), + }); + expect({ a: 1, b: expectUnderTestAsAny.optionalFn() }).toStrictEqual({ + a: 1, + b: undefined, + }); + expect([1, undefined]).toStrictEqual([1, expectUnderTestAsAny.optionalFn()]); + expect([1, expectUnderTestAsAny.optionalFn()]).toStrictEqual([1, undefined]); + }); + +}); + +test.describe('.toEqual()', () => { + + [ + [true, false], + [1, 2], + [0, -0], + [0, Number.MIN_VALUE], // issues/7941 + [Number.MIN_VALUE, 0], + [0, new Number(0)], + [new Number(0), 0], + [new Number(0), new Number(1)], + ['abc', new String('abc')], + [new String('abc'), 'abc'], + // @ts-ignore + [/abc/gsy, /abc/g], + [{ a: 1 }, { a: 2 }], + [{ a: 5 }, { b: 6 }], + [Object.freeze({ foo: { bar: 1 } }), { foo: {} }], + [ + { + get getterAndSetter() { + return {}; + }, + set getterAndSetter(value) { + throw new Error('noo'); + }, + }, + { getterAndSetter: { foo: 'bar' } }, + ], + [ + Object.freeze({ + get frozenGetterAndSetter() { + return {}; + }, + set frozenGetterAndSetter(value) { + throw new Error('noo'); + }, + }), + { frozenGetterAndSetter: { foo: 'bar' } }, + ], + [ + { + get getter() { + return {}; + }, + }, + { getter: { foo: 'bar' } }, + ], + [ + Object.freeze({ + get frozenGetter() { + return {}; + }, + }), + { frozenGetter: { foo: 'bar' } }, + ], + [ + { + + set setter(value) { + throw new Error('noo'); + }, + }, + { setter: { foo: 'bar' } }, + ], + [ + Object.freeze({ + + set frozenSetter(value) { + throw new Error('noo'); + }, + }), + { frozenSetter: { foo: 'bar' } }, + ], + ['banana', 'apple'], + ['1\u{00A0}234,57\u{00A0}$', '1 234,57 $'], // issues/6881 + [ + 'type TypeName = T extends Function ? "function" : "object";', + 'type TypeName = T extends Function\n? "function"\n: "object";', + ], + [null, undefined], + [[1], [2]], + [ + [1, 2], + [2, 1], + ], + [Immutable.List([1]), Immutable.List([2])], + [Immutable.List([1, 2]), Immutable.List([2, 1])], + [new Map(), new Set()], + [new Set([1, 2]), new Set()], + [new Set([1, 2]), new Set([1, 2, 3])], + [new Set([[1], [2]]), new Set([[1], [2], [3]])], + [new Set([[1], [2]]), new Set([[1], [2], [2]])], + [ + new Set([new Set([1]), new Set([2])]), + new Set([new Set([1]), new Set([3])]), + ], + [Immutable.Set([1, 2]), Immutable.Set()], + [Immutable.Set([1, 2]), Immutable.Set([1, 2, 3])], + [Immutable.OrderedSet([1, 2]), Immutable.OrderedSet([2, 1])], + [ + new Map([ + [1, 'one'], + [2, 'two'], + ]), + new Map([[1, 'one']]), + ], + [new Map([['a', 0]]), new Map([['b', 0]])], + [new Map([['v', 1]]), new Map([['v', 2]])], + [new Map([[['v'], 1]]), new Map([[['v'], 2]])], + [ + new Map([[[1], new Map([[[1], 'one']])]]), + new Map([[[1], new Map([[[1], 'two']])]]), + ], + [Immutable.Map({ a: 0 }), Immutable.Map({ b: 0 })], + [Immutable.Map({ v: 1 }), Immutable.Map({ v: 2 })], + [ + Immutable.OrderedMap().set(1, 'one').set(2, 'two'), + Immutable.OrderedMap().set(2, 'two').set(1, 'one'), + ], + [ + Immutable.Map({ 1: Immutable.Map({ 2: { a: 99 } }) }), + Immutable.Map({ 1: Immutable.Map({ 2: { a: 11 } }) }), + ], + [new Uint8Array([97, 98, 99]), new Uint8Array([97, 98, 100])], + [{ a: 1, b: 2 }, expectUnderTest.objectContaining({ a: 2 })], + [false, expectUnderTest.objectContaining({ a: 2 })], + [[1, 3], expectUnderTest.arrayContaining([1, 2])], + [1, expectUnderTest.arrayContaining([1, 2])], + ['abd', expectUnderTest.stringContaining('bc')], + ['abd', expectUnderTest.stringMatching(/bc/i)], + [undefined, expectUnderTest.anything()], + [undefined, expectUnderTest.any(Function)], + [ + 'Eve', + { + asymmetricMatch: function asymmetricMatch(who) { + return who === 'Alice' || who === 'Bob'; + }, + }, + ], + [ + { + target: { + nodeType: 1, + value: 'a', + }, + }, + { + target: { + nodeType: 1, + value: 'b', + }, + }, + ], + [ + { + nodeName: 'div', + nodeType: 1, + }, + { + nodeName: 'p', + nodeType: 1, + }, + ], + [ + { + [Symbol.for('foo')]: 1, + [Symbol.for('bar')]: 2, + }, + { + [Symbol.for('foo')]: expectUnderTest.any(Number), + [Symbol.for('bar')]: 1, + }, + ], + [ + + [, , 1, ,], + + [, , 2, ,], + ], + [ + Object.assign([], { 4294967295: 1 }), + Object.assign([], { 4294967295: 2 }), // issue 11056 + ], + [ + + Object.assign([], { ['-0']: 1 }), + + Object.assign([], { ['0']: 1 }), // issue 11056: also check (-0, 0) + ], + [ + Object.assign([], { a: 1 }), + Object.assign([], { b: 1 }), // issue 11056: also check strings + ], + [ + Object.assign([], { [Symbol()]: 1 }), + Object.assign([], { [Symbol()]: 1 }), // issue 11056: also check symbols + ], + ].forEach(([a, b], index) => { + test(`{pass: false} expect(${stringify(a)}).toEqual(${stringify( + b, + )} (${index}))`, () => { + expect(() => expectUnderTest(a).toEqual(b)).toThrowErrorMatchingSnapshot(); + expectUnderTest(a).not.toEqual(b); + }); + }); + + [ + [BigInt(1), BigInt(2)], + [BigInt(1), 1], + ].forEach(([a, b]) => { + test(`{pass: false} expect(${stringify(a)}).toEqual(${stringify( + b, + )})`, () => { + expect(() => expectUnderTest(a).toEqual(b)).toThrow('toEqual'); + expectUnderTest(a).not.toEqual(b); + }); + }); + + [ + [true, true], + [1, 1], + [NaN, NaN], + [0, Number(0)], + [Number(0), 0], + [new Number(0), new Number(0)], + ['abc', 'abc'], + [String('abc'), 'abc'], + ['abc', String('abc')], + [[1], [1]], + [ + [1, 2], + [1, 2], + ], + [Immutable.List([1]), Immutable.List([1])], + [Immutable.List([1, 2]), Immutable.List([1, 2])], + [{}, {}], + [{ a: 99 }, { a: 99 }], + [new Set(), new Set()], + [new Set([1, 2]), new Set([1, 2])], + [new Set([1, 2]), new Set([2, 1])], + [new Set([[1], [2]]), new Set([[2], [1]])], + [ + new Set([new Set([[1]]), new Set([[2]])]), + new Set([new Set([[2]]), new Set([[1]])]), + ], + [new Set([[1], [2], [3], [3]]), new Set([[3], [3], [2], [1]])], + [new Set([{ a: 1 }, { b: 2 }]), new Set([{ b: 2 }, { a: 1 }])], + [Immutable.Set(), Immutable.Set()], + [Immutable.Set([1, 2]), Immutable.Set([1, 2])], + [Immutable.Set([1, 2]), Immutable.Set([2, 1])], + [Immutable.OrderedSet(), Immutable.OrderedSet()], + [Immutable.OrderedSet([1, 2]), Immutable.OrderedSet([1, 2])], + [new Map(), new Map()], + [ + new Map([ + [1, 'one'], + [2, 'two'], + ]), + new Map([ + [1, 'one'], + [2, 'two'], + ]), + ], + [ + new Map([ + [1, 'one'], + [2, 'two'], + ]), + new Map([ + [2, 'two'], + [1, 'one'], + ]), + ], + [ + new Map([ + [[1], 'one'], + [[2], 'two'], + [[3], 'three'], + [[3], 'four'], + ]), + new Map([ + [[3], 'three'], + [[3], 'four'], + [[2], 'two'], + [[1], 'one'], + ]), + ], + [ + new Map([ + [[1], new Map([[[1], 'one']])], + [[2], new Map([[[2], 'two']])], + ]), + new Map([ + [[2], new Map([[[2], 'two']])], + [[1], new Map([[[1], 'one']])], + ]), + ], + [ + new Map([ + [[1], 'one'], + [[2], 'two'], + ]), + new Map([ + [[2], 'two'], + [[1], 'one'], + ]), + ], + [ + new Map([ + [{ a: 1 }, 'one'], + [{ b: 2 }, 'two'], + ]), + new Map([ + [{ b: 2 }, 'two'], + [{ a: 1 }, 'one'], + ]), + ], + [ + new Map([ + [1, ['one']], + [2, ['two']], + ]), + new Map([ + [2, ['two']], + [1, ['one']], + ]), + ], + [Immutable.Map(), Immutable.Map()], + [ + Immutable.Map().set(1, 'one').set(2, 'two'), + Immutable.Map().set(1, 'one').set(2, 'two'), + ], + [ + Immutable.Map().set(1, 'one').set(2, 'two'), + Immutable.Map().set(2, 'two').set(1, 'one'), + ], + [ + Immutable.OrderedMap().set(1, 'one').set(2, 'two'), + Immutable.OrderedMap().set(1, 'one').set(2, 'two'), + ], + [ + Immutable.Map({ 1: Immutable.Map({ 2: { a: 99 } }) }), + Immutable.Map({ 1: Immutable.Map({ 2: { a: 99 } }) }), + ], + [new Uint8Array([97, 98, 99]), new Uint8Array([97, 98, 99])], + [{ a: 1, b: 2 }, expectUnderTest.objectContaining({ a: 1 })], + [[1, 2, 3], expectUnderTest.arrayContaining([2, 3])], + ['abcd', expectUnderTest.stringContaining('bc')], + ['abcd', expectUnderTest.stringMatching('bc')], + [true, expectUnderTest.anything()], + [() => { }, expectUnderTest.any(Function)], + [ + { + a: 1, + b: function b() { }, + c: true, + }, + { + a: 1, + b: expectUnderTest.any(Function), + c: expectUnderTest.anything(), + }, + ], + [ + 'Alice', + { + asymmetricMatch: function asymmetricMatch(who) { + return who === 'Alice' || who === 'Bob'; + }, + }, + ], + [ + { + nodeName: 'div', + nodeType: 1, + }, + { + nodeName: 'div', + nodeType: 1, + }, + ], + [ + { + [Symbol.for('foo')]: 1, + [Symbol.for('bar')]: 2, + }, + { + [Symbol.for('foo')]: expectUnderTest.any(Number), + [Symbol.for('bar')]: 2, + }, + ], + [ + + [, , 1, ,], + + [, , 1, ,], + ], + [ + + [, , 1, , ,], + + [, , 1, undefined, ,], // same length but hole replaced by undefined + ], + // issue 12463 - "matcher" vs "proper function" + [ + { a: 1, b: () => { } }, + { a: 1, b: expectUnderTestAsAny.optionalFn() }, + ], + [ + { a: 1, b: expectUnderTestAsAny.optionalFn() }, + { a: 1, b: () => { } }, + ], + [ + [1, () => { }], + [1, expectUnderTestAsAny.optionalFn()], + ], + [ + [1, expectUnderTestAsAny.optionalFn()], + [1, () => { }], + ], + // issue 12463 - "matcher" vs "undefined" + [ + { a: 1, b: undefined }, + { a: 1, b: expectUnderTestAsAny.optionalFn() }, + ], + [ + { a: 1, b: expectUnderTestAsAny.optionalFn() }, + { a: 1, b: undefined }, + ], + [ + [1, undefined], + [1, expectUnderTestAsAny.optionalFn()], + ], + [ + [1, expectUnderTestAsAny.optionalFn()], + [1, undefined], + ], + // issue 12463 - "matcher" vs "missing" + [{ a: 1 }, { a: 1, b: expectUnderTestAsAny.optionalFn() }], + [{ a: 1, b: expectUnderTestAsAny.optionalFn() }, { a: 1 }], + [[1], [1, expectUnderTestAsAny.optionalFn()]], + [[1, expectUnderTestAsAny.optionalFn()], [1]], + ].forEach(([a, b], index) => { + test(`{pass: true} expect(${stringify(a)}).not.toEqual(${stringify( + b, + )}) (${index})`, () => { + expectUnderTest(a).toEqual(b); + expect(() => expectUnderTest(a).not.toEqual(b)).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [BigInt(1), BigInt(1)], + [BigInt(0), BigInt('0')], + [[BigInt(1)], [BigInt(1)]], + [ + [BigInt(1), 2], + [BigInt(1), 2], + ], + [Immutable.List([BigInt(1)]), Immutable.List([BigInt(1)])], + [{ a: BigInt(99) }, { a: BigInt(99) }], + [new Set([BigInt(1), BigInt(2)]), new Set([BigInt(1), BigInt(2)])], + ].forEach(([a, b]) => { + test(`{pass: true} expect(${stringify(a)}).not.toEqual(${stringify( + b, + )})`, () => { + expectUnderTest(a).toEqual(b); + expect(() => expectUnderTest(a).not.toEqual(b)).toThrow('toEqual'); + }); + }); + + test('assertion error matcherResult property contains matcher name, expected and actual values', () => { + const actual = { a: 1 }; + const expected = { a: 2 }; + try { + expectUnderTest(actual).toEqual(expected); + } catch (error) { + expect(error.matcherResult).toEqual( + expect.objectContaining({ + actual, + expected, + name: 'toEqual', + }), + ); + } + }); + + test('symbol based keys in arrays are processed correctly', () => { + const mySymbol = Symbol('test'); + const actual1 = []; + actual1[mySymbol] = 3; + const actual2 = []; + actual2[mySymbol] = 4; + const expected = []; + expected[mySymbol] = 3; + + expect(actual1).toEqual(expected); + expect(actual2).not.toEqual(expected); + }); + + test('non-enumerable members should be skipped during equal', () => { + const actual = { + x: 3, + }; + Object.defineProperty(actual, 'test', { + enumerable: false, + value: 5, + }); + expect(actual).toEqual({ x: 3 }); + }); + + test('non-enumerable symbolic members should be skipped during equal', () => { + const actual = { + x: 3, + }; + const mySymbol = Symbol('test'); + Object.defineProperty(actual, mySymbol, { + enumerable: false, + value: 5, + }); + expect(actual).toEqual({ x: 3 }); + }); + + test.describe('cyclic object equality', () => { + test('properties with the same circularity are equal', () => { + const a: any = {}; + a.x = a; + const b: any = {}; + b.x = b; + expect(a).toEqual(b); + expect(b).toEqual(a); + + const c: any = {}; + c.x = a; + const d: any = {}; + d.x = b; + expect(c).toEqual(d); + expect(d).toEqual(c); + }); + + test('properties with different circularity are not equal', () => { + const a: any = {}; + a.x = { y: a }; + const b: any = {}; + const bx: any = {}; + b.x = bx; + bx.y = bx; + expect(a).not.toEqual(b); + expect(b).not.toEqual(a); + + const c: any = {}; + c.x = a; + const d: any = {}; + d.x = b; + expect(c).not.toEqual(d); + expect(d).not.toEqual(c); + }); + + test('are not equal if circularity is not on the same property', () => { + const a: any = {}; + const b: any = {}; + a.a = a; + b.a = {}; + b.a.a = a; + expect(a).not.toEqual(b); + expect(b).not.toEqual(a); + + const c: any = {}; + c.x = { x: c }; + const d: any = {}; + d.x = d; + expect(c).not.toEqual(d); + expect(d).not.toEqual(c); + }); + }); + +}); + +test.describe('.toBeInstanceOf()', () => { + class A { } + class B { } + class C extends B { } + class D extends C { } + class E extends D { } + + class SubHasStaticNameMethod extends B { + constructor() { + super(); + } + static name() { } + } + + class HasStaticNameMethod { + constructor() { } + static name() { } + } + + function DefinesNameProp() { } + Object.defineProperty(DefinesNameProp, 'name', { + configurable: true, + enumerable: false, + value: '', + writable: true, + }); + // @ts-ignore + class SubHasNameProp extends DefinesNameProp { } + + [ + [new Map(), Map], + [[], Array], + [new A(), A], + [new C(), B], // C extends B + [new E(), B], // E extends … extends B + [new SubHasNameProp(), DefinesNameProp], // omit extends + [new SubHasStaticNameMethod(), B], // Received + [new HasStaticNameMethod(), HasStaticNameMethod], // Expected + ].forEach(([a, b], index) => { + test(`passing ${stringify(a)} and ${stringify(b)} (${index})`, () => { + expect(() => + expectUnderTest(a).not.toBeInstanceOf(b), + ).toThrowErrorMatchingSnapshot(); + + expectUnderTest(a).toBeInstanceOf(b); + }); + }); + + [ + ['a', String], + [1, Number], + [true, Boolean], + [new A(), B], + [Object.create(null), A], + [undefined, String], + [null, String], + [/\w+/, function() { }], + [new DefinesNameProp(), RegExp], + ].forEach(([a, b], index) => { + test(`failing ${stringify(a)} and ${stringify(b)} (${index})`, () => { + expect(() => + expectUnderTest(a).toBeInstanceOf(b), + ).toThrowErrorMatchingSnapshot(); + + expectUnderTest(a).not.toBeInstanceOf(b); + }); + }); + + test('throws if constructor is not a function', () => { + expect(() => + expectUnderTest({}).toBeInstanceOf(4), + ).toThrowErrorMatchingSnapshot(); + }); +}); + +test.describe('.toBeTruthy(), .toBeFalsy()', () => { + test('does not accept arguments', () => { + expect(() => expectUnderTestAsAny(0).toBeTruthy(null)).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTestAsAny(0).not.toBeFalsy(null), + ).toThrowErrorMatchingSnapshot(); + }); + + [{}, [], true, 1, 'a', 0.5, new Map(), () => { }, Infinity].forEach(v => { + test(`'${stringify(v)}' is truthy`, () => { + expectUnderTest(v).toBeTruthy(); + expectUnderTest(v).not.toBeFalsy(); + + expect(() => + expectUnderTest(v).not.toBeTruthy(), + ).toThrowErrorMatchingSnapshot(); + + expect(() => expectUnderTest(v).toBeFalsy()).toThrowErrorMatchingSnapshot(); + }); + }); + + [BigInt(1)].forEach(v => { + test(`'${stringify(v)}' is truthy`, () => { + expectUnderTest(v).toBeTruthy(); + expectUnderTest(v).not.toBeFalsy(); + + expect(() => expectUnderTest(v).not.toBeTruthy()).toThrow('toBeTruthy'); + + expect(() => expectUnderTest(v).toBeFalsy()).toThrow('toBeFalsy'); + }); + }); + + [false, null, NaN, 0, '', undefined].forEach(v => { + test(`'${stringify(v)}' is falsy`, () => { + expectUnderTest(v).toBeFalsy(); + expectUnderTest(v).not.toBeTruthy(); + + expect(() => expectUnderTest(v).toBeTruthy()).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(v).not.toBeFalsy(), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [BigInt(0)].forEach(v => { + test(`'${stringify(v)}' is falsy`, () => { + expectUnderTest(v).toBeFalsy(); + expectUnderTest(v).not.toBeTruthy(); + + expect(() => expectUnderTest(v).toBeTruthy()).toThrow('toBeTruthy'); + + expect(() => expectUnderTest(v).not.toBeFalsy()).toThrow('toBeFalsy'); + }); + }); +}); + +test.describe('.toBeNaN()', () => { + test('{pass: true} expect(NaN).toBeNaN()', () => { + [NaN, Math.sqrt(-1), Infinity - Infinity, 0 / 0].forEach(v => { + expectUnderTest(v).toBeNaN(); + + expect(() => expectUnderTest(v).not.toBeNaN()).toThrowErrorMatchingSnapshot(); + }); + }); + + test('throws', () => { + [1, '', null, undefined, {}, [], 0.2, 0, Infinity, -Infinity].forEach(v => { + expect(() => expectUnderTest(v).toBeNaN()).toThrowErrorMatchingSnapshot(); + + expectUnderTest(v).not.toBeNaN(); + }); + }); +}); + +test.describe('.toBeNull()', () => { + [{}, [], true, 1, 'a', 0.5, new Map(), () => { }, Infinity].forEach(v => { + test(`fails for '${stringify(v)}'`, () => { + expectUnderTest(v).not.toBeNull(); + + expect(() => expectUnderTest(v).toBeNull()).toThrowErrorMatchingSnapshot(); + }); + }); + + test('fails for null with .not', () => { + expect(() => + expectUnderTest(null).not.toBeNull(), + ).toThrowErrorMatchingSnapshot(); + }); + + test('pass for null', () => { + expectUnderTest(null).toBeNull(); + }); +}); + +test.describe('.toBeDefined(), .toBeUndefined()', () => { + [{}, [], true, 1, 'a', 0.5, new Map(), () => { }, Infinity].forEach(v => { + test(`'${stringify(v)}' is defined`, () => { + expectUnderTest(v).toBeDefined(); + expectUnderTest(v).not.toBeUndefined(); + + expect(() => + expectUnderTest(v).not.toBeDefined(), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(v).toBeUndefined(), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [BigInt(1)].forEach(v => { + test(`'${stringify(v)}' is defined`, () => { + expectUnderTest(v).toBeDefined(); + expectUnderTest(v).not.toBeUndefined(); + + expect(() => expectUnderTest(v).not.toBeDefined()).toThrow('toBeDefined'); + + expect(() => expectUnderTest(v).toBeUndefined()).toThrow('toBeUndefined'); + }); + }); + + test('undefined is undefined', () => { + expectUnderTest(undefined).toBeUndefined(); + expectUnderTest(undefined).not.toBeDefined(); + + expect(() => + expectUnderTest(undefined).toBeDefined(), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(undefined).not.toBeUndefined(), + ).toThrowErrorMatchingSnapshot(); + }); +}); + +test.describe( + '.toBeGreaterThan(), .toBeLessThan(), ' + + '.toBeGreaterThanOrEqual(), .toBeLessThanOrEqual()', + () => { + [ + [1, 2], + [-Infinity, Infinity], + [Number.MIN_VALUE, Number.MAX_VALUE], + [0x11, 0x22], + [0b11, 0b111], + [0o11, 0o22], + [0.1, 0.2], + ].forEach(([small, big]) => { + test(`{pass: true} expect(${small}).toBeLessThan(${big})`, () => { + expectUnderTest(small).toBeLessThan(big); + }); + + test(`{pass: false} expect(${big}).toBeLessThan(${small})`, () => { + expectUnderTest(big).not.toBeLessThan(small); + }); + + test(`{pass: true} expect(${big}).toBeGreaterThan(${small})`, () => { + expectUnderTest(big).toBeGreaterThan(small); + }); + + test(`{pass: false} expect(${small}).toBeGreaterThan(${big})`, () => { + expectUnderTest(small).not.toBeGreaterThan(big); + }); + + test(`{pass: true} expect(${small}).toBeLessThanOrEqual(${big})`, () => { + expectUnderTest(small).toBeLessThanOrEqual(big); + }); + + test(`{pass: false} expect(${big}).toBeLessThanOrEqual(${small})`, () => { + expectUnderTest(big).not.toBeLessThanOrEqual(small); + }); + + test(`{pass: true} expect(${big}).toBeGreaterThanOrEqual(${small})`, () => { + expectUnderTest(big).toBeGreaterThanOrEqual(small); + }); + + test(`{pass: false} expect(${small}).toBeGreaterThanOrEqual(${big})`, () => { + expectUnderTest(small).not.toBeGreaterThanOrEqual(big); + }); + + test(`throws: [${small}, ${big}]`, () => { + expect(() => + expectUnderTest(small).toBeGreaterThan(big), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(small).not.toBeLessThan(big), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(big).not.toBeGreaterThan(small), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(big).toBeLessThan(small), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(small).toBeGreaterThanOrEqual(big), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(small).not.toBeLessThanOrEqual(big), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(big).not.toBeGreaterThanOrEqual(small), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(big).toBeLessThanOrEqual(small), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('can compare BigInt to Numbers', () => { + const a = BigInt(2); + expectUnderTest(a).toBeGreaterThan(1); + expectUnderTest(a).toBeGreaterThanOrEqual(2); + expectUnderTest(2).toBeLessThanOrEqual(a); + expectUnderTest(a).toBeLessThan(3); + expectUnderTest(a).toBeLessThanOrEqual(2); + }); + [ + [BigInt(1), BigInt(2)], + [BigInt(0x11), BigInt(0x22)], + [-1, BigInt(2)], + ].forEach(([small, big]) => { + test(`{pass: true} expect(${stringify(small)}).toBeLessThan(${stringify( + big, + )})`, () => { + expectUnderTest(small).toBeLessThan(big); + }); + + test(`{pass: false} expect(${stringify(big)}).toBeLessThan(${stringify( + small, + )})`, () => { + expectUnderTest(big).not.toBeLessThan(small); + }); + + test(`{pass: true} expect(${stringify(big)}).toBeGreaterThan(${stringify( + small, + )})`, () => { + expectUnderTest(big).toBeGreaterThan(small); + }); + + test(`{pass: false} expect(${stringify(small)}).toBeGreaterThan(${stringify( + big, + )})`, () => { + expectUnderTest(small).not.toBeGreaterThan(big); + }); + + test(`{pass: true} expect(${stringify( + small, + )}).toBeLessThanOrEqual(${stringify(big)})`, () => { + expectUnderTest(small).toBeLessThanOrEqual(big); + }); + + test(`{pass: false} expect(${stringify( + big, + )}).toBeLessThanOrEqual(${stringify(small)})`, () => { + expectUnderTest(big).not.toBeLessThanOrEqual(small); + }); + + test(`{pass: true} expect(${stringify( + big, + )}).toBeGreaterThanOrEqual(${stringify(small)})`, () => { + expectUnderTest(big).toBeGreaterThanOrEqual(small); + }); + + test(`{pass: false} expect(${stringify( + small, + )}).toBeGreaterThanOrEqual(${stringify(big)})`, () => { + expectUnderTest(small).not.toBeGreaterThanOrEqual(big); + }); + + test(`throws: [${stringify(small)}, ${stringify(big)}]`, () => { + expect(() => expectUnderTest(small).toBeGreaterThan(big)).toThrow( + 'toBeGreaterThan', + ); + + expect(() => expectUnderTest(small).not.toBeLessThan(big)).toThrow( + 'toBeLessThan', + ); + + expect(() => expectUnderTest(big).not.toBeGreaterThan(small)).toThrow( + 'toBeGreaterThan', + ); + + expect(() => expectUnderTest(big).toBeLessThan(small)).toThrow( + 'toBeLessThan', + ); + + expect(() => expectUnderTest(small).toBeGreaterThanOrEqual(big)).toThrow( + 'toBeGreaterThanOrEqual', + ); + + expect(() => expectUnderTest(small).not.toBeLessThanOrEqual(big)).toThrow( + 'toBeLessThanOrEqual', + ); + + expect(() => expectUnderTest(big).not.toBeGreaterThanOrEqual(small)).toThrow( + 'toBeGreaterThanOrEqual', + ); + + expect(() => expectUnderTest(big).toBeLessThanOrEqual(small)).toThrow( + 'toBeLessThanOrEqual', + ); + }); + }); + + [ + [1, 1], + [Number.MIN_VALUE, Number.MIN_VALUE], + [Number.MAX_VALUE, Number.MAX_VALUE], + [Infinity, Infinity], + [-Infinity, -Infinity], + ].forEach(([n1, n2]) => { + test(`equal numbers: [${n1}, ${n2}]`, () => { + expectUnderTest(n1).toBeGreaterThanOrEqual(n2); + expectUnderTest(n1).toBeLessThanOrEqual(n2); + + expect(() => + expectUnderTest(n1).not.toBeGreaterThanOrEqual(n2), + ).toThrowErrorMatchingSnapshot(); + + expect(() => + expectUnderTest(n1).not.toBeLessThanOrEqual(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [BigInt(1), BigInt(1)], + [BigInt(Number.MAX_SAFE_INTEGER), BigInt(Number.MAX_SAFE_INTEGER)], + ].forEach(([n1, n2], index) => { + test(`equal numbers: [${n1}, ${n2}] (${index})`, () => { + expectUnderTest(n1).toBeGreaterThanOrEqual(n2); + expectUnderTest(n1).toBeLessThanOrEqual(n2); + + expect(() => expectUnderTest(n1).not.toBeGreaterThanOrEqual(n2)).toThrow( + 'toBeGreaterThanOrEqual', + ); + + expect(() => expectUnderTest(n1).not.toBeLessThanOrEqual(n2)).toThrow( + 'toBeLessThanOrEqual', + ); + }); + }); + }, +); + +test.describe('.toContain(), .toContainEqual()', () => { + const typedArray = new Int8Array(2); + typedArray[0] = 0; + typedArray[1] = 1; + + test('iterable', () => { + // different node versions print iterable differently, so we can't + // use snapshots here. + const iterable = { + *[Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + }, + }; + + expectUnderTest(iterable).toContain(2); + expectUnderTest(iterable).toContainEqual(2); + expect(() => expectUnderTest(iterable).not.toContain(1)).toThrow('toContain'); + expect(() => expectUnderTest(iterable).not.toContainEqual(1)).toThrow( + 'toContainEqual', + ); + }); + + [ + [[1, 2, 3, 4], 1], + [['a', 'b', 'c', 'd'], 'a'], + [[undefined, null], null], + [[undefined, null], undefined], + [[Symbol.for('a')], Symbol.for('a')], + ['abcdef', 'abc'], + ['11112111', '2'], + [new Set(['abc', 'def']), 'abc'], + [typedArray, 1], + ].forEach(([list, v]) => { + test(`'${stringify(list)}' contains '${stringify(v)}'`, () => { + expectUnderTest(list).toContain(v); + + expect(() => + expectUnderTest(list).not.toContain(v), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [[BigInt(1), BigInt(2), BigInt(3), BigInt(4)], BigInt(1)], + [[1, 2, 3, BigInt(3), 4], BigInt(3)], + ].forEach(([list, v]) => { + test(`'${stringify(list)}' contains '${stringify(v)}'`, () => { + expectUnderTest(list).toContain(v); + + expect(() => expectUnderTest(list).not.toContain(v)).toThrow('toContain'); + }); + }); + + [ + [[1, 2, 3], 4], + [[null, undefined], 1], + [[{}, []], []], + [[{}, []], {}], + ].forEach(([list, v]) => { + test(`'${stringify(list)}' does not contain '${stringify(v)}'`, () => { + expectUnderTest(list).not.toContain(v); + + expect(() => + expectUnderTest(list).toContain(v), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [[[BigInt(1), BigInt(2), BigInt(3)], 3]].forEach(([list, v]) => { + test(`'${stringify(list)}' does not contain '${stringify(v)}'`, () => { + expectUnderTest(list).not.toContain(v); + + expect(() => expectUnderTest(list).toContain(v)).toThrow('toContain'); + }); + }); + + test('error cases', () => { + expect(() => expectUnderTest(null).toContain(1)).toThrowErrorMatchingSnapshot(); + expect(() => expectUnderTest('-0').toContain(-0)).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest('null').toContain(null), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest('undefined').toContain(undefined), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest('false').toContain(false), + ).toThrowErrorMatchingSnapshot(); + expect(() => expectUnderTest('1').toContain(BigInt(1))).toThrow('toContain'); + }); + + [ + [[1, 2, 3, 4], 1], + [['a', 'b', 'c', 'd'], 'a'], + [[undefined, null], null], + [[undefined, null], undefined], + [[Symbol.for('a')], Symbol.for('a')], + [[{ a: 'b' }, { a: 'c' }], { a: 'b' }], + [new Set([1, 2, 3, 4]), 1], + [typedArray, 1], + ].forEach(([list, v]) => { + test(`'${stringify(list)}' contains a value equal to '${stringify( + v, + )}'`, () => { + expectUnderTest(list).toContainEqual(v); + expect(() => + expectUnderTest(list).not.toContainEqual(v), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [[[{ a: 'b' }, { a: 'c' }], { a: 'd' }]].forEach(([list, v]) => { + test(`'${stringify(list)}' does not contain a value equal to'${stringify( + v, + )}'`, () => { + expectUnderTest(list).not.toContainEqual(v); + + expect(() => + expectUnderTest(list).toContainEqual(v), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('error cases for toContainEqual', () => { + expect(() => + expectUnderTest(null).toContainEqual(1), + ).toThrowErrorMatchingSnapshot(); + }); +}); + +test.describe('.toBeCloseTo', () => { + [ + [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(([n1, n2]) => { + test(`{pass: true} expect(${n1}).toBeCloseTo(${n2})`, () => { + expectUnderTest(n1).toBeCloseTo(n2); + + expect(() => + expectUnderTest(n1).not.toBeCloseTo(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [0, 0.01], + [1, 1.23], + [1.23, 1.2249999], + [Infinity, -Infinity], + [Infinity, 1.23], + [-Infinity, -1.23], + ].forEach(([n1, n2]) => { + test(`{pass: false} expect(${n1}).toBeCloseTo(${n2})`, () => { + expectUnderTest(n1).not.toBeCloseTo(n2); + + expect(() => + expectUnderTest(n1).toBeCloseTo(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [3.141592e-7, 3e-7, 8], + [56789, 51234, -4], + ].forEach(([n1, n2, p]) => { + test(`{pass: false} expect(${n1}).toBeCloseTo(${n2}, ${p})`, () => { + expectUnderTest(n1).not.toBeCloseTo(n2, p); + + expect(() => + expectUnderTest(n1).toBeCloseTo(n2, p), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [0, 0.1, 0], + [0, 0.0001, 3], + [0, 0.000004, 5], + [2.0000002, 2, 5], + ].forEach(([n1, n2, p]) => { + test(`{pass: true} expect(${n1}).toBeCloseTo(${n2}, ${p})`, () => { + expectUnderTest(n1).toBeCloseTo(n2, p); + + expect(() => + expectUnderTest(n1).not.toBeCloseTo(n2, p), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test.describe('throws: Matcher error', () => { + test('promise empty isNot false received', () => { + const precision = 3; + const expected = 0; + const received = ''; + expect(() => { + expectUnderTest(received).toBeCloseTo(expected, precision); + }).toThrowErrorMatchingSnapshot(); + }); + + test('promise empty isNot true expected', () => { + const received = 0.1; + // expected is undefined + expect(() => { + expectUnderTestAsAny(received).not.toBeCloseTo(); + }).toThrowErrorMatchingSnapshot(); + }); + + test('promise rejects isNot false expected', () => { + const expected = '0'; + const received = Promise.reject(0.01); + return expect( + expectUnderTestAsAny(received).rejects.toBeCloseTo(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('promise rejects isNot true received', () => { + const expected = 0; + const received = Promise.reject(Symbol('0.1')); + return expect( + expectUnderTest(received).rejects.not.toBeCloseTo(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('promise resolves isNot false received', () => { + const precision = 3; + const expected = 0; + const received = Promise.resolve(false); + return expect( + expectUnderTest(received).resolves.toBeCloseTo(expected, precision), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('promise resolves isNot true expected', () => { + const precision = 3; + const expected = null; + const received = Promise.resolve(0.1); + return expect( + expectUnderTest(received).resolves.not.toBeCloseTo(expected, precision), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + }); +}); + +test.describe('.toMatch()', () => { + [ + ['foo', 'foo'], + ['Foo bar', /^foo/i], + ].forEach(([n1, n2]) => { + test(`{pass: true} expect(${n1}).toMatch(${n2})`, () => { + expectUnderTest(n1).toMatch(n2); + + expect(() => + expectUnderTest(n1).not.toMatch(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + ['bar', 'foo'], + ['bar', /foo/], + ].forEach(([n1, n2]) => { + test(`throws: [${n1}, ${n2}]`, () => { + expect(() => expectUnderTest(n1).toMatch(n2)).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [1, 'foo'], + [{}, 'foo'], + [[], 'foo'], + [true, 'foo'], + [/foo/i, 'foo'], + [() => { }, 'foo'], + [undefined, 'foo'], + ].forEach(([n1, n2]) => { + test( + 'throws if non String actual value passed:' + + ` [${stringify(n1)}, ${stringify(n2)}]`, + () => { + // @ts-ignore + expect(() => expectUnderTest(n1).toMatch(n2)).toThrowErrorMatchingSnapshot(); + }, + ); + }); + + [ + ['foo', 1], + ['foo', {}], + ['foo', []], + ['foo', true], + ['foo', () => { }], + ['foo', undefined], + ].forEach(([n1, n2]) => { + test( + 'throws if non String/RegExp expected value passed:' + + ` [${stringify(n1)}, ${stringify(n2)}]`, + () => { + // @ts-ignore + expect(() => expectUnderTest(n1).toMatch(n2)).toThrowErrorMatchingSnapshot(); + }, + ); + }); + + test('escapes strings properly', () => { + expectUnderTest('this?: throws').toMatch('this?: throws'); + }); + + test('does not maintain RegExp state between calls', () => { + const regex = /[f]\d+/gi; + expectUnderTest('f123').toMatch(regex); + expectUnderTest('F456').toMatch(regex); + expectUnderTest(regex.lastIndex).toBe(0); + }); +}); + +test.describe('.toHaveLength', () => { + [ + [[1, 2], 2], + [[], 0], + [['a', 'b'], 2], + ['abc', 3], + ['', 0], + [() => { }, 0], + ].forEach(([received, length]) => { + test(`{pass: true} expect(${stringify( + received, + )}).toHaveLength(${length})`, () => { + expectUnderTestAsAny(received).toHaveLength(length); + expect(() => + expectUnderTestAsAny(received).not.toHaveLength(length), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [[1, 2], 3], + [[], 1], + [['a', 'b'], 99], + ['abc', 66], + ['', 1], + ].forEach(([received, length]) => { + test(`{pass: false} expect(${stringify( + received, + )}).toHaveLength(${length})`, () => { + expectUnderTestAsAny(received).not.toHaveLength(length); + expect(() => + expectUnderTestAsAny(received).toHaveLength(length), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('error cases', () => { + expect(() => + expectUnderTest({ a: 9 }).toHaveLength(1), + ).toThrowErrorMatchingSnapshot(); + expect(() => expectUnderTest(0).toHaveLength(1)).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(undefined).not.toHaveLength(1), + ).toThrowErrorMatchingSnapshot(); + }); + + test.describe('matcher error expected length', () => { + test('not number', () => { + const expected = '3'; + const received = 'abc'; + expect(() => { + expectUnderTestAsAny(received).not.toHaveLength(expected); + }).toThrowErrorMatchingSnapshot(); + }); + + test('number Infinity', () => { + const expected = Infinity; + const received = Promise.reject('abc'); + return expect( + expectUnderTest(received).rejects.toHaveLength(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('number NaN', () => { + const expected = NaN; + const received = Promise.reject('abc'); + return expect( + expectUnderTest(received).rejects.not.toHaveLength(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('number float', () => { + const expected = 0.5; + const received = Promise.resolve('abc'); + return expect( + expectUnderTest(received).resolves.toHaveLength(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + + test('number negative integer', () => { + const expected = -3; + const received = Promise.resolve('abc'); + return expect( + expectUnderTest(received).resolves.not.toHaveLength(expected), + // @ts-ignore + ).rejects.toThrowErrorMatchingSnapshotAsync(); + }); + }); +}); + +test.describe('.toHaveProperty()', () => { + class Foo { + val: any; + get a() { + return undefined; + } + get b() { + return 'b'; + } + + set setter(val) { + this.val = val; + } + } + + class Foo2 extends Foo { + get c() { + return 'c'; + } + } + const foo2 = new Foo2(); + foo2.setter = true; + + function E(nodeName) { + this.nodeName = nodeName.toUpperCase(); + } + E.prototype.nodeType = 1; + + const memoized = function() { }; + memoized.memo = []; + + const pathDiff = ['children', 0]; + + const receivedDiffSingle = { + children: ['"That cartoon"'], + props: null, + type: 'p', + }; + const valueDiffSingle = '"That cat cartoon"'; + + const receivedDiffMultiple = { + children: [ + 'Roses are red.\nViolets are blue.\nTesting with Jest is good for you.', + ], + props: null, + type: 'pre', + }; + const valueDiffMultiple = + 'Roses are red, violets are blue.\nTesting with Jest\nIs good for you.'; + + [ + [{ a: { b: { c: { d: 1 } } } }, 'a.b.c.d', 1], + [{ a: { b: { c: { d: 1 } } } }, ['a', 'b', 'c', 'd'], 1], + [{ 'a.b.c.d': 1 }, ['a.b.c.d'], 1], + [{ a: { b: [1, 2, 3] } }, ['a', 'b', 1], 2], + [{ a: { b: [1, 2, 3] } }, ['a', 'b', 1], expect.any(Number)], + [{ a: 0 }, 'a', 0], + [{ a: { b: undefined } }, 'a.b', undefined], + [{ a: { b: { c: 5 } } }, 'a.b', { c: 5 }], + [{ a: { b: [{ c: [{ d: 1 }] }] } }, 'a.b[0].c[0].d', 1], + [{ a: { b: [{ c: { d: [{ e: 1 }, { f: 2 }] } }] } }, 'a.b[0].c.d[1].f', 2], + [{ a: { b: [[{ c: [{ d: 1 }] }]] } }, 'a.b[0][0].c[0].d', 1], + [Object.assign(Object.create(null), { property: 1 }), 'property', 1], + [new Foo(), 'a', undefined], + [new Foo(), 'b', 'b'], + [new Foo(), 'setter', undefined], + [foo2, 'a', undefined], + [foo2, 'c', 'c'], + [foo2, 'val', true], + [new E('div'), 'nodeType', 1], + ['', 'length', 0], + [memoized, 'memo', []], + [{ '': 1 }, '', 1], + ].forEach(([obj, keyPath, value]) => { + test(`{pass: true} expect(${stringify( + obj, + )}).toHaveProperty('${keyPath}', ${stringify(value)})`, () => { + expectUnderTestAsAny(obj).toHaveProperty(keyPath, value); + expect(() => + expectUnderTestAsAny(obj).not.toHaveProperty(keyPath, value), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [{ a: { b: { c: { d: 1 } } } }, 'a.b.ttt.d', 1], + [{ a: { b: { c: { d: 1 } } } }, 'a.b.c.d', 2], + [{ 'a.b.c.d': 1 }, 'a.b.c.d', 2], + [{ 'a.b.c.d': 1 }, ['a.b.c.d'], 2], + [receivedDiffSingle, pathDiff, valueDiffSingle], + [receivedDiffMultiple, pathDiff, valueDiffMultiple], + [{ a: { b: { c: { d: 1 } } } }, ['a', 'b', 'c', 'd'], 2], + [{ a: { b: { c: {} } } }, 'a.b.c.d', 1], + [{ a: 1 }, 'a.b.c.d', 5], + [{}, 'a', 'test'], + [{ a: { b: 3 } }, 'a.b', undefined], + [1, 'a.b.c', 'test'], + ['abc', 'a.b.c', { a: 5 }], + [{ a: { b: { c: 5 } } }, 'a.b', { c: 4 }], + [new Foo(), 'a', 'a'], + [new Foo(), 'b', undefined], + [{ a: {} }, 'a.b', undefined], + ].forEach(([obj, keyPath, value], index) => { + test(`{pass: false} expect(${stringify( + obj, + )}).toHaveProperty('${keyPath}', ${stringify(value)}) (${index})`, () => { + expect(() => + expectUnderTestAsAny(obj).toHaveProperty(keyPath, value), + ).toThrowErrorMatchingSnapshot(); + expectUnderTestAsAny(obj).not.toHaveProperty(keyPath, value); + }); + }); + + [ + [{ a: { b: { c: { d: 1 } } } }, 'a.b.c.d'], + [{ a: { b: { c: { d: 1 } } } }, ['a', 'b', 'c', 'd']], + [{ 'a.b.c.d': 1 }, ['a.b.c.d']], + [{ a: { b: [1, 2, 3] } }, ['a', 'b', 1]], + [{ a: 0 }, 'a'], + [{ a: { b: undefined } }, 'a.b'], + ].forEach(([obj, keyPath]) => { + test(`{pass: true} expect(${stringify( + obj, + )}).toHaveProperty('${keyPath}')`, () => { + expectUnderTestAsAny(obj).toHaveProperty(keyPath); + expect(() => + expectUnderTestAsAny(obj).not.toHaveProperty(keyPath), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + [ + [{ a: { b: { c: {} } } }, 'a.b.c.d'], + [{ a: { b: { c: {} } } }, '.a.b.c'], + [{ a: 1 }, 'a.b.c.d'], + [{}, 'a'], + [1, 'a.b.c'], + ['abc', 'a.b.c'], + [false, 'key'], + [0, 'key'], + ['', 'key'], + [Symbol(), 'key'], + [Object.assign(Object.create(null), { key: 1 }), 'not'], + ].forEach(([obj, keyPath]) => { + test(`{pass: false} expect(${stringify( + obj, + )}).toHaveProperty('${keyPath}')`, () => { + expect(() => + expectUnderTest(obj).toHaveProperty(keyPath), + ).toThrowErrorMatchingSnapshot(); + expectUnderTest(obj).not.toHaveProperty(keyPath); + }); + }); + + [ + [null, 'a.b'], + [undefined, 'a'], + [{ a: { b: {} } }, undefined], + [{ a: { b: {} } }, null], + [{ a: { b: {} } }, 1], + [{}, []], // Residue: pass must be initialized + ].forEach(([obj, keyPath]) => { + test(`{error} expect(${stringify( + obj, + )}).toHaveProperty('${keyPath}')`, () => { + expect(() => + expectUnderTestAsAny(obj).toHaveProperty(keyPath), + ).toThrowErrorMatchingSnapshot(); + }); + }); +}); + +test.describe('toMatchObject()', () => { + class Foo { + get a() { + return undefined; + } + get b() { + return 'b'; + } + } + + class Sub extends Foo { + get c() { + return 'c'; + } + } + + const withDefineProperty = (obj, key, val) => { + Object.defineProperty(obj, key, { + get() { + return val; + }, + }); + + return obj; + }; + + const testNotToMatchSnapshots = tuples => { + tuples.forEach(([n1, n2]) => { + test(`{pass: true} expect(${stringify(n1)}).toMatchObject(${stringify( + n2, + )})`, () => { + expectUnderTest(n1).toMatchObject(n2); + expect(() => + expectUnderTest(n1).not.toMatchObject(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + }; + + const testToMatchSnapshots = tuples => { + tuples.forEach(([n1, n2]) => { + test(`{pass: false} expect(${stringify(n1)}).toMatchObject(${stringify( + n2, + )})`, () => { + expectUnderTest(n1).not.toMatchObject(n2); + expect(() => + expectUnderTest(n1).toMatchObject(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + }; + + test.describe('circular references', () => { + test.describe('simple circular references', () => { + const circularObjA1: any = { a: 'hello' }; + circularObjA1.ref = circularObjA1; + + const circularObjB: any = { a: 'world' }; + circularObjB.ref = circularObjB; + + const circularObjA2: any = { a: 'hello' }; + circularObjA2.ref = circularObjA2; + + const primitiveInsteadOfRef: any = {}; + primitiveInsteadOfRef.ref = 'not a ref'; + + testNotToMatchSnapshots([ + [circularObjA1, {}], + [circularObjA2, circularObjA1], + ]); + + testToMatchSnapshots([ + [{}, circularObjA1], + [circularObjA1, circularObjB], + [primitiveInsteadOfRef, circularObjA1], + ]); + }); + + test.describe('transitive circular references', () => { + const transitiveCircularObjA1: any = { a: 'hello' }; + transitiveCircularObjA1.nestedObj = { parentObj: transitiveCircularObjA1 }; + + const transitiveCircularObjA2: any = { a: 'hello' }; + transitiveCircularObjA2.nestedObj = { + parentObj: transitiveCircularObjA2, + }; + + const transitiveCircularObjB: any = { a: 'world' }; + transitiveCircularObjB.nestedObj = { + parentObj: transitiveCircularObjB, + }; + + const primitiveInsteadOfRef: any = {}; + primitiveInsteadOfRef.nestedObj = { + parentObj: 'not the parent ref', + }; + + testNotToMatchSnapshots([ + [transitiveCircularObjA1, {}], + [transitiveCircularObjA2, transitiveCircularObjA1], + ]); + + testToMatchSnapshots([ + [{}, transitiveCircularObjA1], + [transitiveCircularObjB, transitiveCircularObjA1], + [primitiveInsteadOfRef, transitiveCircularObjA1], + ]); + }); + }); + + testNotToMatchSnapshots([ + [{ a: 'b', c: 'd' }, { a: 'b' }], + [ + { a: 'b', c: 'd' }, + { a: 'b', c: 'd' }, + ], + [ + { a: 'b', t: { x: { r: 'r' }, z: 'z' } }, + { a: 'b', t: { z: 'z' } }, + ], + [{ a: 'b', t: { x: { r: 'r' }, z: 'z' } }, { t: { x: { r: 'r' } } }], + [{ a: [3, 4, 5], b: 'b' }, { a: [3, 4, 5] }], + [{ a: [3, 4, 5, 'v'], b: 'b' }, { a: [3, 4, 5, 'v'] }], + [{ a: 1, c: 2 }, { a: expectUnderTest.any(Number) }], + [{ a: { x: 'x', y: 'y' } }, { a: { x: expectUnderTest.any(String) } }], + [new Set([1, 2]), new Set([1, 2])], + [new Set([1, 2]), new Set([2, 1])], + [new Date('2015-11-30'), new Date('2015-11-30')], + [{ a: new Date('2015-11-30'), b: 'b' }, { a: new Date('2015-11-30') }], + [{ a: null, b: 'b' }, { a: null }], + [{ a: undefined, b: 'b' }, { a: undefined }], + [{ a: [{ a: 'a', b: 'b' }] }, { a: [{ a: 'a' }] }], + [ + [1, 2], + [1, 2], + ], + [{ a: undefined }, { a: undefined }], + [[], []], + [new Error('foo'), new Error('foo')], + [new Error('bar'), { message: 'bar' }], + [new Foo(), { a: undefined, b: 'b' }], + [Object.assign(Object.create(null), { a: 'b' }), { a: 'b' }], + [ + { a: 'b', c: 'd', [Symbol.for('jest')]: 'jest' }, + { a: 'b', [Symbol.for('jest')]: 'jest' }, + ], + [ + { a: 'b', c: 'd', [Symbol.for('jest')]: 'jest' }, + { a: 'b', c: 'd', [Symbol.for('jest')]: 'jest' }, + ], + // These snapshots will show {} as the object because the properties + // are not enumerable. We will need to somehow make the serialization of + // these keys a little smarter before reporting accurately. + [new Sub(), { a: undefined, b: 'b', c: 'c' }], + [withDefineProperty(new Sub(), 'd', 4), { d: 4 }], + [{ a: 'b', toString() { } }, { toString: expectUnderTest.any(Function) }], + ]); + + testToMatchSnapshots([ + [{ a: 'b', c: 'd' }, { e: 'b' }], + [ + { a: 'b', c: 'd' }, + { a: 'b!', c: 'd' }, + ], + [{ a: 'a', c: 'd' }, { a: expectUnderTest.any(Number) }], + [ + { a: 'b', t: { x: { r: 'r' }, z: 'z' } }, + { a: 'b', t: { z: [3] } }, + ], + [{ a: 'b', t: { x: { r: 'r' }, z: 'z' } }, { t: { l: { r: 'r' } } }], + [{ a: [3, 4, 5], b: 'b' }, { a: [3, 4, 5, 6] }], + [{ a: [3, 4, 5], b: 'b' }, { a: [3, 4] }], + [{ a: [3, 4, 'v'], b: 'b' }, { a: ['v'] }], + [{ a: [3, 4, 5], b: 'b' }, { a: { b: 4 } }], + [{ a: [3, 4, 5], b: 'b' }, { a: { b: expectUnderTest.any(String) } }], + [ + [1, 2], + [1, 3], + ], + [[0], [-0]], + [new Set([1, 2]), new Set([2])], + [new Date('2015-11-30'), new Date('2015-10-10')], + [{ a: new Date('2015-11-30'), b: 'b' }, { a: new Date('2015-10-10') }], + [{ a: null, b: 'b' }, { a: '4' }], + [{ a: null, b: 'b' }, { a: undefined }], + [{ a: undefined }, { a: null }], + [{ a: [{ a: 'a', b: 'b' }] }, { a: [{ a: 'c' }] }], + [{ a: 1, b: 1, c: 1, d: { e: { f: 555 } } }, { d: { e: { f: 222 } } }], + [{}, { a: undefined }], + [ + [1, 2, 3], + [2, 3, 1], + ], + [ + [1, 2, 3], + [1, 2, 2], + ], + [new Error('foo'), new Error('bar')], + [Object.assign(Object.create(null), { a: 'b' }), { c: 'd' }], + [ + { a: 'b', c: 'd', [Symbol.for('jest')]: 'jest' }, + { a: 'c', [Symbol.for('jest')]: expect.any(String) }, + ], + [{ a: 'b' }, { toString: expectUnderTest.any(Function) }], + ]); + + [ + [null, {}], + [4, {}], + ['44', {}], + [true, {}], + [undefined, {}], + [{}, null], + [{}, 4], + [{}, 'some string'], + [{}, true], + [{}, undefined], + ].forEach(([n1, n2]: [any, any, string]) => { + test(`throws expect(${stringify(n1)}).toMatchObject(${stringify( + n2, + )})`, () => { + expect(() => + expectUnderTest(n1).toMatchObject(n2), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('does not match properties up in the prototype chain', () => { + const a: any = {}; + a.ref = a; + + const b = Object.create(a); + b.other = 'child'; + + const matcher: any = { other: 'child' }; + matcher.ref = matcher; + + expectUnderTest(b).not.toMatchObject(matcher); + expect(() => + expectUnderTest(b).toMatchObject(matcher), + ).toThrowErrorMatchingSnapshot(); + }); + + test('toMatchObject ignores symbol key properties', () => { + // issue 13638 + const sym = Symbol('foo'); + const sym2 = Symbol('foo2'); + expectUnderTestAsAny({}).not.toMatchObject({ [sym]: true }); + expectUnderTestAsAny({ [sym]: true }).not.toMatchObject({ [sym2]: true }); + expectUnderTestAsAny({ [sym]: true }).not.toMatchObject({ [sym]: false }); + expectUnderTestAsAny({ example: 10, [sym]: true }).not.toMatchObject({ + example: 12, + [sym]: true, + }); + expectUnderTestAsAny({ [sym]: true }).toMatchObject({ [sym]: true }); + expectUnderTestAsAny({ example: 10, [sym]: true }).toMatchObject({ + example: 10, + [sym]: true, + }); + }); +}); diff --git a/tests/expect/spyMatchers.snapshots.js b/tests/expect/spyMatchers.snapshots.js new file mode 100644 index 0000000000..720620fae6 --- /dev/null +++ b/tests/expect/spyMatchers.snapshots.js @@ -0,0 +1,2600 @@ +module.exports["toBeCalled works only on spies or mock.fn"] = `expect(received).toBeCalled() + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toBeCalled passes when called"] = `expect(jest.fn()).not.toBeCalled() + +Expected number of calls: 0 +Received number of calls: 1 + +1: "arg0", "arg1", "arg2"`; + +module.exports["toBeCalled .not passes when called"] = `expect(spy).toBeCalled() + +Expected number of calls: >= 1 +Received number of calls: 0`; + +module.exports["toBeCalled fails with any argument passed"] = `expect(received).toBeCalled() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toBeCalled .not fails with any argument passed"] = `expect(received).not.toBeCalled() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toBeCalled includes the custom mock name in the error message"] = `expect(named-mock).not.toBeCalled() + +Expected number of calls: 0 +Received number of calls: 1 + +1: called with 0 arguments`; + +module.exports["toHaveBeenCalled works only on spies or mock.fn"] = `expect(received).toHaveBeenCalled() + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveBeenCalled passes when called"] = `expect(jest.fn()).not.toHaveBeenCalled() + +Expected number of calls: 0 +Received number of calls: 1 + +1: "arg0", "arg1", "arg2"`; + +module.exports["toHaveBeenCalled .not passes when called"] = `expect(spy).toHaveBeenCalled() + +Expected number of calls: >= 1 +Received number of calls: 0`; + +module.exports["toHaveBeenCalled fails with any argument passed"] = `expect(received).toHaveBeenCalled() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toHaveBeenCalled .not fails with any argument passed"] = `expect(received).not.toHaveBeenCalled() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toHaveBeenCalled includes the custom mock name in the error message"] = `expect(named-mock).not.toHaveBeenCalled() + +Expected number of calls: 0 +Received number of calls: 1 + +1: called with 0 arguments`; + +module.exports["toBeCalledTimes .not works only on spies or mock.fn"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toBeCalledTimes only accepts a number argument"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toBeCalledTimes only accepts a number argument #1"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toBeCalledTimes only accepts a number argument #2"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toBeCalledTimes only accepts a number argument #3"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toBeCalledTimes only accepts a number argument #4"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toBeCalledTimes only accepts a number argument #5"] = `expect(received).toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toBeCalledTimes .not only accepts a number argument"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toBeCalledTimes .not only accepts a number argument #1"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toBeCalledTimes .not only accepts a number argument #2"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toBeCalledTimes .not only accepts a number argument #3"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toBeCalledTimes .not only accepts a number argument #4"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toBeCalledTimes .not only accepts a number argument #5"] = `expect(received).not.toBeCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toBeCalledTimes passes if function called equal to expected times"] = `expect(spy).not.toBeCalledTimes(expected) + +Expected number of calls: not 2`; + +module.exports["toBeCalledTimes .not passes if function called more than expected times"] = `expect(jest.fn()).toBeCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 3`; + +module.exports["toBeCalledTimes .not passes if function called less than expected times"] = `expect(jest.fn()).toBeCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 1`; + +module.exports["toBeCalledTimes includes the custom mock name in the error message"] = `expect(named-mock).toBeCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 1`; + +module.exports["toHaveBeenCalledTimes .not works only on spies or mock.fn"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument #1"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument #2"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument #3"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument #4"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toHaveBeenCalledTimes only accepts a number argument #5"] = `expect(received).toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument #1"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument #2"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument #3"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument #4"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toHaveBeenCalledTimes .not only accepts a number argument #5"] = `expect(received).not.toHaveBeenCalledTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toHaveBeenCalledTimes passes if function called equal to expected times"] = `expect(spy).not.toHaveBeenCalledTimes(expected) + +Expected number of calls: not 2`; + +module.exports["toHaveBeenCalledTimes .not passes if function called more than expected times"] = `expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 3`; + +module.exports["toHaveBeenCalledTimes .not passes if function called less than expected times"] = `expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 1`; + +module.exports["toHaveBeenCalledTimes includes the custom mock name in the error message"] = `expect(named-mock).toHaveBeenCalledTimes(expected) + +Expected number of calls: 2 +Received number of calls: 1`; + +module.exports["lastCalledWith works only on spies or mock.fn"] = `expect(received).lastCalledWith(...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["lastCalledWith works when not called"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["lastCalledWith works with arguments that don't match"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that match"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["lastCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["lastCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["lastCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["lastCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["lastCalledWith works with Map"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["lastCalledWith works with Map #1"] = `expect(jest.fn()).lastCalledWith(...expected) + +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["lastCalledWith works with Set"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["lastCalledWith works with Set #1"] = `expect(jest.fn()).lastCalledWith(...expected) + +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["lastCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["lastCalledWith works with many arguments"] = `expect(jest.fn()).not.lastCalledWith(...expected) + +Expected: not "foo", "bar" +Received + 2: "foo", "bar1" +-> 3: "foo", "bar" + +Number of calls: 3`; + +module.exports["lastCalledWith works with many arguments that don't match"] = `expect(jest.fn()).lastCalledWith(...expected) + +Expected: "foo", "bar" +Received + 2: "foo", "bar2" +-> 3: "foo", "bar3" + +Number of calls: 3`; + +module.exports["lastCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.lastCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works only on spies or mock.fn"] = `expect(received).toHaveBeenLastCalledWith(...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveBeenLastCalledWith works when not called"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["toHaveBeenLastCalledWith works with arguments that don't match"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that match"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with Map"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with Map #1"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with Set"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with Set #1"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["toHaveBeenLastCalledWith works with many arguments"] = `expect(jest.fn()).not.toHaveBeenLastCalledWith(...expected) + +Expected: not "foo", "bar" +Received + 2: "foo", "bar1" +-> 3: "foo", "bar" + +Number of calls: 3`; + +module.exports["toHaveBeenLastCalledWith works with many arguments that don't match"] = `expect(jest.fn()).toHaveBeenLastCalledWith(...expected) + +Expected: "foo", "bar" +Received + 2: "foo", "bar2" +-> 3: "foo", "bar3" + +Number of calls: 3`; + +module.exports["toHaveBeenLastCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.toHaveBeenLastCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["nthCalledWith works only on spies or mock.fn"] = `expect(received).nthCalledWith(n, ...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["nthCalledWith works when not called"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["nthCalledWith works with arguments that don't match"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that match"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["nthCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["nthCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["nthCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["nthCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["nthCalledWith works with Map"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["nthCalledWith works with Map #1"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["nthCalledWith works with Set"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["nthCalledWith works with Set #1"] = `expect(jest.fn()).nthCalledWith(n, ...expected) + +n: 1 +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["nthCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["nthCalledWith works with three calls"] = `expect(jest.fn()).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo1", "bar" +Received +-> 1: "foo1", "bar" + 2: "foo", "bar1" + +Number of calls: 3`; + +module.exports["nthCalledWith positive throw matcher error for n that is not positive integer"] = `expect(received).nthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0`; + +module.exports["nthCalledWith positive throw matcher error for n that is not integer"] = `expect(received).nthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0.1`; + +module.exports["nthCalledWith negative throw matcher error for n that is not integer"] = `expect(received).not.nthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: Infinity`; + +module.exports["nthCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.nthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works only on spies or mock.fn"] = `expect(received).toHaveBeenNthCalledWith(n, ...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveBeenNthCalledWith works when not called"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["toHaveBeenNthCalledWith works with arguments that don't match"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that match"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with Map"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with Map #1"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with Set"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with Set #1"] = `expect(jest.fn()).toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["toHaveBeenNthCalledWith works with three calls"] = `expect(jest.fn()).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo1", "bar" +Received +-> 1: "foo1", "bar" + 2: "foo", "bar1" + +Number of calls: 3`; + +module.exports["toHaveBeenNthCalledWith positive throw matcher error for n that is not positive integer"] = `expect(received).toHaveBeenNthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0`; + +module.exports["toHaveBeenNthCalledWith positive throw matcher error for n that is not integer"] = `expect(received).toHaveBeenNthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0.1`; + +module.exports["toHaveBeenNthCalledWith negative throw matcher error for n that is not integer"] = `expect(received).not.toHaveBeenNthCalledWith(n, ...expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: Infinity`; + +module.exports["toHaveBeenNthCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.toHaveBeenNthCalledWith(n, ...expected) + +n: 1 +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toBeCalledWith works only on spies or mock.fn"] = `expect(received).toBeCalledWith(...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toBeCalledWith works when not called"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["toBeCalledWith works with arguments that don't match"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that match"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toBeCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["toBeCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toBeCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["toBeCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["toBeCalledWith works with Map"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["toBeCalledWith works with Map #1"] = `expect(jest.fn()).toBeCalledWith(...expected) + +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["toBeCalledWith works with Set"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["toBeCalledWith works with Set #1"] = `expect(jest.fn()).toBeCalledWith(...expected) + +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["toBeCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["toBeCalledWith works with many arguments"] = `expect(jest.fn()).not.toBeCalledWith(...expected) + +Expected: not "foo", "bar" +Received + 3: "foo", "bar" + +Number of calls: 3`; + +module.exports["toBeCalledWith works with many arguments that don't match"] = `expect(jest.fn()).toBeCalledWith(...expected) + +Expected: "foo", "bar" +Received + 1: "foo", "bar1" + 2: "foo", "bar2" + 3: "foo", "bar3" + +Number of calls: 3`; + +module.exports["toBeCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.toBeCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works only on spies or mock.fn"] = `expect(received).toHaveBeenCalledWith(...expected) + +Matcher error: received value must be a mock or spy function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveBeenCalledWith works when not called"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", "bar" + +Number of calls: 0`; + +module.exports["toHaveBeenCalledWith works with arguments that don't match"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar1" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that don't match in number of arguments"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", "bar" +Received: "foo", "bar", "plop" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that don't match with matchers"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: Any, Any +Received: "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that don't match with matchers even when argument is undefined"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", Any +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that don't match in size even if one is an optional matcher"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", optionalFn<> +Received: "foo" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that match"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with arguments that match with matchers"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not Any, Any +Received: 0, ["foo", "bar"] + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with trailing undefined arguments"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo" +Received: "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with trailing undefined arguments if requested by the match query"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not "foo", undefined + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with trailing undefined arguments when explicitly requested as optional by matcher"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not "foo", optionalFn<> +Received: 0, ["foo", undefined] + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with Map"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with Map #1"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +- Expected ++ Received + + Map { +- "a" => "b", +- "b" => "a", ++ 1 => 2, ++ 2 => 1, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with Set"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not Set {1, 2} + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with Set #1"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +- Expected ++ Received + + Set { +- 3, +- 4, ++ 1, ++ 2, + }, + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with Immutable.js objects"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not Immutable.Map {"a": {"b": "c"}}, Immutable.Map {"a": {"b": "c"}} + +Number of calls: 1`; + +module.exports["toHaveBeenCalledWith works with many arguments"] = `expect(jest.fn()).not.toHaveBeenCalledWith(...expected) + +Expected: not "foo", "bar" +Received + 3: "foo", "bar" + +Number of calls: 3`; + +module.exports["toHaveBeenCalledWith works with many arguments that don't match"] = `expect(jest.fn()).toHaveBeenCalledWith(...expected) + +Expected: "foo", "bar" +Received + 1: "foo", "bar1" + 2: "foo", "bar2" + 3: "foo", "bar3" + +Number of calls: 3`; + +module.exports["toHaveBeenCalledWith includes the custom mock name in the error message"] = `expect(named-mock).not.toHaveBeenCalledWith(...expected) + +Expected: not "foo", "bar" + +Number of calls: 1`; + +module.exports["toReturn .not works only on mock.fn"] = `expect(received).not.toReturn() + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toReturn throw matcher error if received is spy"] = `expect(received).toReturn() + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function spy]`; + +module.exports["toReturn passes when returned"] = `expect(jest.fn()).not.toReturn() + +Expected number of returns: 0 +Received number of returns: 1 + +1: 42`; + +module.exports["toReturn passes when undefined is returned"] = `expect(jest.fn()).not.toReturn() + +Expected number of returns: 0 +Received number of returns: 1 + +1: undefined`; + +module.exports["toReturn passes when at least one call does not throw"] = `expect(jest.fn()).not.toReturn() + +Expected number of returns: 0 +Received number of returns: 2 + +1: 42 +3: 42 + +Received number of calls: 3`; + +module.exports["toReturn .not passes when not returned"] = `expect(jest.fn()).toReturn() + +Expected number of returns: >= 1 +Received number of returns: 0`; + +module.exports["toReturn .not passes when all calls throw"] = `expect(jest.fn()).toReturn() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 2`; + +module.exports["toReturn .not passes when a call throws undefined"] = `expect(jest.fn()).toReturn() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 1`; + +module.exports["toReturn fails with any argument passed"] = `expect(received).toReturn() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toReturn .not fails with any argument passed"] = `expect(received).not.toReturn() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toReturn includes the custom mock name in the error message"] = `expect(named-mock).not.toReturn() + +Expected number of returns: 0 +Received number of returns: 1 + +1: 42`; + +module.exports["toReturn incomplete recursive calls are handled properly"] = `expect(jest.fn()).toReturn() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 4`; + +module.exports["toHaveReturned .not works only on mock.fn"] = `expect(received).not.toHaveReturned() + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveReturned throw matcher error if received is spy"] = `expect(received).toHaveReturned() + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function spy]`; + +module.exports["toHaveReturned passes when returned"] = `expect(jest.fn()).not.toHaveReturned() + +Expected number of returns: 0 +Received number of returns: 1 + +1: 42`; + +module.exports["toHaveReturned passes when undefined is returned"] = `expect(jest.fn()).not.toHaveReturned() + +Expected number of returns: 0 +Received number of returns: 1 + +1: undefined`; + +module.exports["toHaveReturned passes when at least one call does not throw"] = `expect(jest.fn()).not.toHaveReturned() + +Expected number of returns: 0 +Received number of returns: 2 + +1: 42 +3: 42 + +Received number of calls: 3`; + +module.exports["toHaveReturned .not passes when not returned"] = `expect(jest.fn()).toHaveReturned() + +Expected number of returns: >= 1 +Received number of returns: 0`; + +module.exports["toHaveReturned .not passes when all calls throw"] = `expect(jest.fn()).toHaveReturned() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 2`; + +module.exports["toHaveReturned .not passes when a call throws undefined"] = `expect(jest.fn()).toHaveReturned() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 1`; + +module.exports["toHaveReturned fails with any argument passed"] = `expect(received).toHaveReturned() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toHaveReturned .not fails with any argument passed"] = `expect(received).not.toHaveReturned() + +Matcher error: this matcher must not have an expected argument + +Expected has type: number +Expected has value: 555`; + +module.exports["toHaveReturned includes the custom mock name in the error message"] = `expect(named-mock).not.toHaveReturned() + +Expected number of returns: 0 +Received number of returns: 1 + +1: 42`; + +module.exports["toHaveReturned incomplete recursive calls are handled properly"] = `expect(jest.fn()).toHaveReturned() + +Expected number of returns: >= 1 +Received number of returns: 0 +Received number of calls: 4`; + +module.exports["toReturnTimes throw matcher error if received is spy"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function spy]`; + +module.exports["toReturnTimes only accepts a number argument"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toReturnTimes only accepts a number argument #1"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toReturnTimes only accepts a number argument #2"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toReturnTimes only accepts a number argument #3"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toReturnTimes only accepts a number argument #4"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toReturnTimes only accepts a number argument #5"] = `expect(received).toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toReturnTimes .not only accepts a number argument"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toReturnTimes .not only accepts a number argument #1"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toReturnTimes .not only accepts a number argument #2"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toReturnTimes .not only accepts a number argument #3"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toReturnTimes .not only accepts a number argument #4"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toReturnTimes .not only accepts a number argument #5"] = `expect(received).not.toReturnTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toReturnTimes passes if function returned equal to expected times"] = `expect(jest.fn()).not.toReturnTimes(expected) + +Expected number of returns: not 2`; + +module.exports["toReturnTimes calls that return undefined are counted as returns"] = `expect(jest.fn()).not.toReturnTimes(expected) + +Expected number of returns: not 2`; + +module.exports["toReturnTimes .not passes if function returned more than expected times"] = `expect(jest.fn()).toReturnTimes(expected) + +Expected number of returns: 2 +Received number of returns: 3`; + +module.exports["toReturnTimes .not passes if function called less than expected times"] = `expect(jest.fn()).toReturnTimes(expected) + +Expected number of returns: 2 +Received number of returns: 1`; + +module.exports["toReturnTimes calls that throw are not counted"] = `expect(jest.fn()).toReturnTimes(expected) + +Expected number of returns: 3 +Received number of returns: 2 +Received number of calls: 3`; + +module.exports["toReturnTimes calls that throw undefined are not counted"] = `expect(jest.fn()).not.toReturnTimes(expected) + +Expected number of returns: not 2 + +Received number of calls: 3`; + +module.exports["toReturnTimes includes the custom mock name in the error message"] = `expect(named-mock).toReturnTimes(expected) + +Expected number of returns: 1 +Received number of returns: 2`; + +module.exports["toReturnTimes incomplete recursive calls are handled properly"] = `expect(jest.fn()).not.toReturnTimes(expected) + +Expected number of returns: not 2 + +Received number of calls: 4`; + +module.exports["toHaveReturnedTimes throw matcher error if received is spy"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function spy]`; + +module.exports["toHaveReturnedTimes only accepts a number argument"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toHaveReturnedTimes only accepts a number argument #1"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toHaveReturnedTimes only accepts a number argument #2"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toHaveReturnedTimes only accepts a number argument #3"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toHaveReturnedTimes only accepts a number argument #4"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toHaveReturnedTimes only accepts a number argument #5"] = `expect(received).toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: object +Expected has value: {}`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument #1"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: array +Expected has value: []`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument #2"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: boolean +Expected has value: true`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument #3"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: string +Expected has value: "a"`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument #4"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: map +Expected has value: Map {}`; + +module.exports["toHaveReturnedTimes .not only accepts a number argument #5"] = `expect(received).not.toHaveReturnedTimes(expected) + +Matcher error: expected value must be a non-negative integer + +Expected has type: function +Expected has value: [Function anonymous]`; + +module.exports["toHaveReturnedTimes passes if function returned equal to expected times"] = `expect(jest.fn()).not.toHaveReturnedTimes(expected) + +Expected number of returns: not 2`; + +module.exports["toHaveReturnedTimes calls that return undefined are counted as returns"] = `expect(jest.fn()).not.toHaveReturnedTimes(expected) + +Expected number of returns: not 2`; + +module.exports["toHaveReturnedTimes .not passes if function returned more than expected times"] = `expect(jest.fn()).toHaveReturnedTimes(expected) + +Expected number of returns: 2 +Received number of returns: 3`; + +module.exports["toHaveReturnedTimes .not passes if function called less than expected times"] = `expect(jest.fn()).toHaveReturnedTimes(expected) + +Expected number of returns: 2 +Received number of returns: 1`; + +module.exports["toHaveReturnedTimes calls that throw are not counted"] = `expect(jest.fn()).toHaveReturnedTimes(expected) + +Expected number of returns: 3 +Received number of returns: 2 +Received number of calls: 3`; + +module.exports["toHaveReturnedTimes calls that throw undefined are not counted"] = `expect(jest.fn()).not.toHaveReturnedTimes(expected) + +Expected number of returns: not 2 + +Received number of calls: 3`; + +module.exports["toHaveReturnedTimes includes the custom mock name in the error message"] = `expect(named-mock).toHaveReturnedTimes(expected) + +Expected number of returns: 1 +Received number of returns: 2`; + +module.exports["toHaveReturnedTimes incomplete recursive calls are handled properly"] = `expect(jest.fn()).not.toHaveReturnedTimes(expected) + +Expected number of returns: not 2 + +Received number of calls: 4`; + +module.exports["lastReturnedWith works only on spies or mock.fn"] = `expect(received).lastReturnedWith(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["lastReturnedWith works when not called"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["lastReturnedWith works with argument that does not match"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["lastReturnedWith works with argument that does match"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not "foo" + +Number of returns: 1`; + +module.exports["lastReturnedWith works with undefined"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not undefined + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Map"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Map #1"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Set"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Set #1"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["lastReturnedWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["lastReturnedWith a call that throws is not considered to have returned"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["lastReturnedWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["lastReturnedWith returnedWith works with more calls than the limit"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: "bar" +Received + 5: "foo5" +-> 6: "foo6" + +Number of returns: 6`; + +module.exports["lastReturnedWith returnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: undefined +Received + 3: function call has not returned yet +-> 4: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["lastReturnedWith lastReturnedWith works with three calls"] = `expect(jest.fn()).not.lastReturnedWith(expected) + +Expected: not "foo3" +Received + 2: "foo2" +-> 3: "foo3" + +Number of returns: 3`; + +module.exports["lastReturnedWith lastReturnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).lastReturnedWith(expected) + +Expected: 0 +Received + 3: function call has not returned yet +-> 4: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["lastReturnedWith includes the custom mock name in the error message"] = `expect(named-mock).lastReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveLastReturnedWith works only on spies or mock.fn"] = `expect(received).toHaveLastReturnedWith(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveLastReturnedWith works when not called"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveLastReturnedWith works with argument that does not match"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with argument that does match"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not "foo" + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with undefined"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not undefined + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Map"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Map #1"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Set"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Set #1"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveLastReturnedWith a call that throws is not considered to have returned"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveLastReturnedWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveLastReturnedWith returnedWith works with more calls than the limit"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: "bar" +Received + 5: "foo5" +-> 6: "foo6" + +Number of returns: 6`; + +module.exports["toHaveLastReturnedWith returnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: undefined +Received + 3: function call has not returned yet +-> 4: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["toHaveLastReturnedWith lastReturnedWith works with three calls"] = `expect(jest.fn()).not.toHaveLastReturnedWith(expected) + +Expected: not "foo3" +Received + 2: "foo2" +-> 3: "foo3" + +Number of returns: 3`; + +module.exports["toHaveLastReturnedWith lastReturnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).toHaveLastReturnedWith(expected) + +Expected: 0 +Received + 3: function call has not returned yet +-> 4: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["toHaveLastReturnedWith includes the custom mock name in the error message"] = `expect(named-mock).toHaveLastReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["nthReturnedWith works only on spies or mock.fn"] = `expect(received).nthReturnedWith(n, expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["nthReturnedWith works when not called"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: "foo" + +Number of returns: 0`; + +module.exports["nthReturnedWith works with argument that does not match"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["nthReturnedWith works with argument that does match"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not "foo" + +Number of returns: 1`; + +module.exports["nthReturnedWith works with undefined"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not undefined + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Map"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Map #1"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Set"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Set #1"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["nthReturnedWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["nthReturnedWith a call that throws is not considered to have returned"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["nthReturnedWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["nthReturnedWith nthReturnedWith works with three calls"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not "foo1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["nthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: "bar1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["nthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third #1"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 1 +Expected: not "foo1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["nthReturnedWith nthReturnedWith positive throw matcher error for n that is not positive integer"] = `expect(received).nthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0`; + +module.exports["nthReturnedWith nthReturnedWith should reject nth value greater than number of calls"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 4 +Expected: "foo" +Received + 3: "foo" + +Number of returns: 3`; + +module.exports["nthReturnedWith nthReturnedWith positive throw matcher error for n that is not integer"] = `expect(received).nthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0.1`; + +module.exports["nthReturnedWith nthReturnedWith negative throw matcher error for n that is not number"] = `expect(received).not.nthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has value: undefined`; + +module.exports["nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 1 +Expected: 6 +Received +-> 1: function call has not returned yet + 2: function call has not returned yet + +Number of returns: 2 +Number of calls: 4`; + +module.exports["nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #1"] = `expect(jest.fn()).nthReturnedWith(n, expected) + +n: 2 +Expected: 3 +Received + 1: function call has not returned yet +-> 2: function call has not returned yet + 3: 1 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #2"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 3 +Expected: not 1 +Received + 2: function call has not returned yet +-> 3: 1 + 4: 0 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["nthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #3"] = `expect(jest.fn()).not.nthReturnedWith(n, expected) + +n: 4 +Expected: not 0 +Received + 3: 1 +-> 4: 0 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["nthReturnedWith includes the custom mock name in the error message"] = `expect(named-mock).nthReturnedWith(n, expected) + +n: 1 +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveNthReturnedWith works only on spies or mock.fn"] = `expect(received).toHaveNthReturnedWith(n, expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveNthReturnedWith works when not called"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveNthReturnedWith works with argument that does not match"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with argument that does match"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not "foo" + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with undefined"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not undefined + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Map"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Map #1"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Set"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Set #1"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveNthReturnedWith a call that throws is not considered to have returned"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveNthReturnedWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveNthReturnedWith nthReturnedWith works with three calls"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not "foo1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["toHaveNthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: "bar1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["toHaveNthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third #1"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: not "foo1" +Received +-> 1: "foo1" + 2: "foo2" + +Number of returns: 3`; + +module.exports["toHaveNthReturnedWith nthReturnedWith positive throw matcher error for n that is not positive integer"] = `expect(received).toHaveNthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0`; + +module.exports["toHaveNthReturnedWith nthReturnedWith should reject nth value greater than number of calls"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 4 +Expected: "foo" +Received + 3: "foo" + +Number of returns: 3`; + +module.exports["toHaveNthReturnedWith nthReturnedWith positive throw matcher error for n that is not integer"] = `expect(received).toHaveNthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has type: number +n has value: 0.1`; + +module.exports["toHaveNthReturnedWith nthReturnedWith negative throw matcher error for n that is not number"] = `expect(received).not.toHaveNthReturnedWith(n, expected) + +Matcher error: n must be a positive integer + +n has value: undefined`; + +module.exports["toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: 6 +Received +-> 1: function call has not returned yet + 2: function call has not returned yet + +Number of returns: 2 +Number of calls: 4`; + +module.exports["toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #1"] = `expect(jest.fn()).toHaveNthReturnedWith(n, expected) + +n: 2 +Expected: 3 +Received + 1: function call has not returned yet +-> 2: function call has not returned yet + 3: 1 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #2"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 3 +Expected: not 1 +Received + 2: function call has not returned yet +-> 3: 1 + 4: 0 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["toHaveNthReturnedWith nthReturnedWith incomplete recursive calls are handled properly #3"] = `expect(jest.fn()).not.toHaveNthReturnedWith(n, expected) + +n: 4 +Expected: not 0 +Received + 3: 1 +-> 4: 0 + +Number of returns: 2 +Number of calls: 4`; + +module.exports["toHaveNthReturnedWith includes the custom mock name in the error message"] = `expect(named-mock).toHaveNthReturnedWith(n, expected) + +n: 1 +Expected: "foo" + +Number of returns: 0`; + +module.exports["toReturnWith works only on spies or mock.fn"] = `expect(received).toReturnWith(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toReturnWith works when not called"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["toReturnWith works with argument that does not match"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["toReturnWith works with argument that does match"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not "foo" + +Number of returns: 1`; + +module.exports["toReturnWith works with undefined"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not undefined + +Number of returns: 1`; + +module.exports["toReturnWith works with Map"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toReturnWith works with Map #1"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toReturnWith works with Set"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["toReturnWith works with Set #1"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["toReturnWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toReturnWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.toReturnWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toReturnWith a call that throws is not considered to have returned"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toReturnWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toReturnWith returnedWith works with more calls than the limit"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: "bar" +Received + 1: "foo1" + 2: "foo2" + 3: "foo3" + +Number of returns: 6`; + +module.exports["toReturnWith returnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).toReturnWith(expected) + +Expected: undefined +Received + 1: function call has not returned yet + 2: function call has not returned yet + 3: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["toReturnWith includes the custom mock name in the error message"] = `expect(named-mock).toReturnWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveReturnedWith works only on spies or mock.fn"] = `expect(received).toHaveReturnedWith(expected) + +Matcher error: received value must be a mock function + +Received has type: function +Received has value: [Function fn]`; + +module.exports["toHaveReturnedWith works when not called"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + +module.exports["toHaveReturnedWith works with argument that does not match"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: "bar" +Received: "foo" + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with argument that does match"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not "foo" + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with undefined"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not undefined + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Map"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Map #1"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: Map {"a" => "b", "b" => "a"} +Received: Map {1 => 2, 2 => 1} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Set"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Set #1"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: Set {3, 4} +Received: Set {1, 2} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Immutable.js objects directly created"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith works with Immutable.js objects indirectly created"] = `expect(jest.fn()).not.toHaveReturnedWith(expected) + +Expected: not Immutable.Map {"a": {"b": "c"}} + +Number of returns: 1`; + +module.exports["toHaveReturnedWith a call that throws is not considered to have returned"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveReturnedWith a call that throws undefined is not considered to have returned"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: undefined +Received: function call threw an error + +Number of returns: 0 +Number of calls: 1`; + +module.exports["toHaveReturnedWith returnedWith works with more calls than the limit"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: "bar" +Received + 1: "foo1" + 2: "foo2" + 3: "foo3" + +Number of returns: 6`; + +module.exports["toHaveReturnedWith returnedWith incomplete recursive calls are handled properly"] = `expect(jest.fn()).toHaveReturnedWith(expected) + +Expected: undefined +Received + 1: function call has not returned yet + 2: function call has not returned yet + 3: function call has not returned yet + +Number of returns: 0 +Number of calls: 4`; + +module.exports["toHaveReturnedWith includes the custom mock name in the error message"] = `expect(named-mock).toHaveReturnedWith(expected) + +Expected: "foo" + +Number of returns: 0`; + diff --git a/tests/expect/spyMatchers.test.ts b/tests/expect/spyMatchers.test.ts new file mode 100644 index 0000000000..bb3b58107b --- /dev/null +++ b/tests/expect/spyMatchers.test.ts @@ -0,0 +1,1499 @@ +/** + * 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'; +import Immutable from 'immutable'; + +const expectUnderTestAsAny = expectUnderTest as any; + +expectUnderTest.extend({ + optionalFn(fn?: unknown) { + const pass = fn === undefined || typeof fn === 'function'; + return { message: () => 'expect either a function or undefined', pass }; + }, +}); + + +// Given a Jest mock function, return a minimal mock of a spy. +const createSpy = (fn: mock.Mock) => { + const spy = function() { }; + + spy.calls = { + all() { + return fn.mock.calls.map(args => ({ args })); + }, + count() { + return fn.mock.calls.length; + }, + }; + + return spy; +}; + +for (const called of ['toBeCalled', 'toHaveBeenCalled']) { + test.describe(called, () => { + test('works only on spies or mock.fn', () => { + const fn = function fn() { }; + + expect(() => expectUnderTest(fn)[called]()).toThrowErrorMatchingSnapshot(); + }); + + test('passes when called', () => { + const fn = mock.fn(); + fn('arg0', 'arg1', 'arg2'); + expectUnderTest(createSpy(fn))[called](); + expectUnderTest(fn)[called](); + expect(() => expectUnderTest(fn).not[called]()).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes when called', () => { + const fn = mock.fn(); + const spy = createSpy(fn); + + expectUnderTest(spy).not[called](); + expectUnderTest(fn).not[called](); + expect(() => expectUnderTest(spy)[called]()).toThrowErrorMatchingSnapshot(); + }); + + test('fails with any argument passed', () => { + const fn = mock.fn(); + + fn(); + expect(() => expectUnderTest(fn)[called](555)).toThrowErrorMatchingSnapshot(); + }); + + test('.not fails with any argument passed', () => { + const fn = mock.fn(); + + expect(() => + expectUnderTest(fn).not[called](555), + ).toThrowErrorMatchingSnapshot(); + }); + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn().mockName('named-mock'); + + fn(); + expectUnderTest(fn)[called](); + expect(() => expectUnderTest(fn).not[called]()).toThrowErrorMatchingSnapshot(); + }); + }); +} + +for (const calledTimes of ['toBeCalledTimes', 'toHaveBeenCalledTimes']) { + test.describe(calledTimes, () => { + test('.not works only on spies or mock.fn', () => { + const fn = function fn() { }; + + expect(() => + expectUnderTest(fn).not[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('only accepts a number argument', () => { + const fn = mock.fn(); + fn(); + expectUnderTest(fn)[calledTimes](1); + + [{}, [], true, 'a', new Map(), () => { }].forEach(value => { + expect(() => + expectUnderTest(fn)[calledTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('.not only accepts a number argument', () => { + const fn = mock.fn(); + expectUnderTest(fn).not[calledTimes](1); + + [{}, [], true, 'a', new Map(), () => { }].forEach(value => { + expect(() => + expectUnderTest(fn).not[calledTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('passes if function called equal to expected times', () => { + const fn = mock.fn(); + fn(); + fn(); + + const spy = createSpy(fn); + expectUnderTest(spy)[calledTimes](2); + expectUnderTest(fn)[calledTimes](2); + + expect(() => + expectUnderTest(spy).not[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes if function called more than expected times', () => { + const fn = mock.fn(); + fn(); + fn(); + fn(); + + const spy = createSpy(fn); + expectUnderTest(spy)[calledTimes](3); + expectUnderTest(spy).not[calledTimes](2); + + expectUnderTest(fn)[calledTimes](3); + expectUnderTest(fn).not[calledTimes](2); + + expect(() => + expectUnderTest(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes if function called less than expected times', () => { + const fn = mock.fn(); + fn(); + + const spy = createSpy(fn); + expectUnderTest(spy)[calledTimes](1); + expectUnderTest(spy).not[calledTimes](2); + + expectUnderTest(fn)[calledTimes](1); + expectUnderTest(fn).not[calledTimes](2); + + expect(() => + expectUnderTest(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn().mockName('named-mock'); + fn(); + + expect(() => + expectUnderTest(fn)[calledTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + }); +} + +for (const calledWith of [ + 'lastCalledWith', + 'toHaveBeenLastCalledWith', + 'nthCalledWith', + 'toHaveBeenNthCalledWith', + 'toBeCalledWith', + 'toHaveBeenCalledWith', +]) { + test.describe(calledWith, () => { + function isToHaveNth( + calledWith: string, + ): calledWith is 'nthCalledWith' | 'toHaveBeenNthCalledWith' { + return ( + calledWith === 'nthCalledWith' || calledWith === 'toHaveBeenNthCalledWith' + ); + } + + test('works only on spies or mock.fn', () => { + const fn = function fn() { }; + + if (isToHaveNth(calledWith)) { + expect(() => + expectUnderTest(fn)[calledWith](3), + ).toThrowErrorMatchingSnapshot(); + } else { + expect(() => expectUnderTest(fn)[calledWith]()).toThrowErrorMatchingSnapshot(); + } + }); + + test('works when not called', () => { + const fn = mock.fn(); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar'); + expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar'); + expectUnderTest(fn).not[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with no arguments', () => { + const fn = mock.fn(); + fn(); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn))[calledWith](1); + expectUnderTest(fn)[calledWith](1); + } else { + expectUnderTest(createSpy(fn))[calledWith](); + expectUnderTest(fn)[calledWith](); + } + }); + + test("works with arguments that don't match", () => { + const fn = mock.fn(); + fn('foo', 'bar1'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar'); + expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar'); + expectUnderTest(fn).not[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test("works with arguments that don't match in number of arguments", () => { + const fn = mock.fn(); + fn('foo', 'bar', 'plop'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar'); + expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar'); + expectUnderTest(fn).not[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test("works with arguments that don't match with matchers", () => { + const fn = mock.fn(); + fn('foo', 'bar'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn)).not[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(Number), + ); + expectUnderTest(fn).not[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(Number), + ); + + expect(() => + expectUnderTest(fn)[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(Number), + ), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn)).not[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(Number), + ); + expectUnderTest(fn).not[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(Number), + ); + + expect(() => + expectUnderTest(fn)[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(Number), + ), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test("works with arguments that don't match with matchers even when argument is undefined", () => { + const fn = mock.fn(); + fn('foo', undefined); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn)).not[calledWith]( + 1, + 'foo', + expectUnderTest.any(String), + ); + expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTest.any(String)); + + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTest.any(String)), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn)).not[calledWith]('foo', expectUnderTest.any(String)); + expectUnderTest(fn).not[calledWith]('foo', expectUnderTest.any(String)); + + expect(() => + expectUnderTest(fn)[calledWith]('foo', expectUnderTest.any(String)), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test("works with arguments that don't match in size even if one is an optional matcher", () => { + // issue 12463 + const fn = mock.fn(); + fn('foo'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()); + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn).not[calledWith]('foo', expectUnderTestAsAny.optionalFn()); + expect(() => + expectUnderTest(fn)[calledWith]('foo', expectUnderTestAsAny.optionalFn()), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with arguments that match', () => { + const fn = mock.fn(); + fn('foo', 'bar'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn))[calledWith](1, 'foo', 'bar'); + expectUnderTest(fn)[calledWith](1, 'foo', 'bar'); + + expect(() => + expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn))[calledWith]('foo', 'bar'); + expectUnderTest(fn)[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn).not[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with arguments that match with matchers', () => { + const fn = mock.fn(); + fn('foo', 'bar'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(createSpy(fn))[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(String), + ); + expectUnderTest(fn)[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(String), + ); + + expect(() => + expectUnderTest(fn).not[calledWith]( + 1, + expectUnderTest.any(String), + expectUnderTest.any(String), + ), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(createSpy(fn))[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(String), + ); + expectUnderTest(fn)[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(String), + ); + + expect(() => + expectUnderTest(fn).not[calledWith]( + expectUnderTest.any(String), + expectUnderTest.any(String), + ), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with trailing undefined arguments', () => { + const fn = mock.fn(); + fn('foo', undefined); + + if (isToHaveNth(calledWith)) { + expect(() => + expectUnderTest(fn)[calledWith](1, 'foo'), + ).toThrowErrorMatchingSnapshot(); + } else { + expect(() => + expectUnderTest(fn)[calledWith]('foo'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with trailing undefined arguments if requested by the match query', () => { + const fn = mock.fn(); + fn('foo', undefined); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, 'foo', undefined); + expect(() => + expectUnderTest(fn).not[calledWith](1, 'foo', undefined), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith]('foo', undefined); + expect(() => + expectUnderTest(fn).not[calledWith]('foo', undefined), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with trailing undefined arguments when explicitly requested as optional by matcher', () => { + // issue 12463 + const fn = mock.fn(); + fn('foo', undefined); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()); + expect(() => + expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith]('foo', expectUnderTestAsAny.optionalFn()); + expect(() => + expectUnderTest(fn).not[calledWith]('foo', expectUnderTestAsAny.optionalFn()), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Map', () => { + const fn = mock.fn(); + + const m1 = new Map([ + [1, 2], + [2, 1], + ]); + const m2 = new Map([ + [1, 2], + [2, 1], + ]); + const m3 = new Map([ + ['a', 'b'], + ['b', 'a'], + ]); + + fn(m1); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, m2); + expectUnderTest(fn).not[calledWith](1, m3); + + expect(() => + expectUnderTest(fn).not[calledWith](1, m2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[calledWith](1, m3), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith](m2); + expectUnderTest(fn).not[calledWith](m3); + + expect(() => + expectUnderTest(fn).not[calledWith](m2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[calledWith](m3), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Set', () => { + const fn = mock.fn(); + + const s1 = new Set([1, 2]); + const s2 = new Set([1, 2]); + const s3 = new Set([3, 4]); + + fn(s1); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, s2); + expectUnderTest(fn).not[calledWith](1, s3); + + expect(() => + expectUnderTest(fn).not[calledWith](1, s2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[calledWith](1, s3), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith](s2); + expectUnderTest(fn).not[calledWith](s3); + + expect(() => + expectUnderTest(fn).not[calledWith](s2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[calledWith](s3), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Immutable.js objects', () => { + const fn = mock.fn(); + const directlyCreated = Immutable.Map([['a', { b: 'c' }]]); + const indirectlyCreated = Immutable.Map().set('a', { b: 'c' }); + fn(directlyCreated, indirectlyCreated); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, indirectlyCreated, directlyCreated); + + expect(() => + expectUnderTest(fn).not[calledWith](1, indirectlyCreated, directlyCreated), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith](indirectlyCreated, directlyCreated); + + expect(() => + expectUnderTest(fn).not[calledWith](indirectlyCreated, directlyCreated), + ).toThrowErrorMatchingSnapshot(); + } + }); + + if (!isToHaveNth(calledWith)) { + test('works with many arguments', () => { + const fn = mock.fn(); + fn('foo1', 'bar'); + fn('foo', 'bar1'); + fn('foo', 'bar'); + + expectUnderTest(fn)[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn).not[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); + + test("works with many arguments that don't match", () => { + const fn = mock.fn(); + fn('foo', 'bar1'); + fn('foo', 'bar2'); + fn('foo', 'bar3'); + + expectUnderTest(fn).not[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn)[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + }); + } + + if (isToHaveNth(calledWith)) { + test('works with three calls', () => { + const fn = mock.fn(); + fn('foo1', 'bar'); + fn('foo', 'bar1'); + fn('foo', 'bar'); + + expectUnderTest(fn)[calledWith](1, 'foo1', 'bar'); + expectUnderTest(fn)[calledWith](2, 'foo', 'bar1'); + expectUnderTest(fn)[calledWith](3, 'foo', 'bar'); + + expect(() => { + expectUnderTest(fn).not[calledWith](1, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('positive throw matcher error for n that is not positive integer', async () => { + const fn = mock.fn(); + fn('foo1', 'bar'); + + expect(() => { + expectUnderTest(fn)[calledWith](0, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('positive throw matcher error for n that is not integer', async () => { + const fn = mock.fn(); + fn('foo1', 'bar'); + + expect(() => { + expectUnderTest(fn)[calledWith](0.1, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('negative throw matcher error for n that is not integer', async () => { + const fn = mock.fn(); + fn('foo1', 'bar'); + + expect(() => { + expectUnderTest(fn).not[calledWith](Infinity, 'foo1', 'bar'); + }).toThrowErrorMatchingSnapshot(); + }); + } + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn().mockName('named-mock'); + fn('foo', 'bar'); + + if (isToHaveNth(calledWith)) { + expectUnderTest(fn)[calledWith](1, 'foo', 'bar'); + + expect(() => + expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[calledWith]('foo', 'bar'); + + expect(() => + expectUnderTest(fn).not[calledWith]('foo', 'bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + }); +} + +for (const returned of ['toReturn', 'toHaveReturned']) { + test.describe(returned, () => { + test('.not works only on mock.fn', () => { + const fn = function fn() { }; + + expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('throw matcher error if received is spy', () => { + const spy = createSpy(mock.fn()); + + expect(() => expectUnderTest(spy)[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('passes when returned', () => { + const fn = mock.fn(() => 42); + fn(); + expectUnderTest(fn)[returned](); + expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('passes when undefined is returned', () => { + const fn = mock.fn(() => undefined); + fn(); + expectUnderTest(fn)[returned](); + expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('passes when at least one call does not throw', () => { + const fn = mock.fn((causeError: boolean) => { + if (causeError) + throw new Error('Error!'); + + + return 42; + }); + + fn(false); + + try { + fn(true); + } catch { + // ignore error + } + + fn(false); + + expectUnderTest(fn)[returned](); + expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes when not returned', () => { + const fn = mock.fn(); + + expectUnderTest(fn).not[returned](); + expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes when all calls throw', () => { + const fn = mock.fn(() => { + throw new Error('Error!'); + }); + + try { + fn(); + } catch { + // ignore error + } + + try { + fn(); + } catch { + // ignore error + } + + expectUnderTest(fn).not[returned](); + expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes when a call throws undefined', () => { + const fn = mock.fn(() => { + + throw undefined; + }); + + try { + fn(); + } catch { + // ignore error + } + + expectUnderTest(fn).not[returned](); + expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('fails with any argument passed', () => { + const fn = mock.fn(); + + fn(); + expect(() => expectUnderTest(fn)[returned](555)).toThrowErrorMatchingSnapshot(); + }); + + test('.not fails with any argument passed', () => { + const fn = mock.fn(); + + expect(() => + expectUnderTest(fn).not[returned](555), + ).toThrowErrorMatchingSnapshot(); + }); + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn(() => 42).mockName('named-mock'); + fn(); + expectUnderTest(fn)[returned](); + expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot(); + }); + + test('incomplete recursive calls are handled properly', () => { + // sums up all integers from 0 -> value, using recursion + const fn: mock.Mock<(value: number) => number> = mock.fn(value => { + if (value === 0) { + // Before returning from the base case of recursion, none of the + // calls have returned yet. + expectUnderTest(fn).not[returned](); + expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot(); + return 0; + } else { + return value + fn(value - 1); + } + }); + + fn(3); + }); + }); +} + +for (const returnedTimes of ['toReturnTimes', 'toHaveReturnedTimes']) { + test.describe(returnedTimes, () => { + test('throw matcher error if received is spy', () => { + const spy = createSpy(mock.fn()); + + expect(() => + expectUnderTest(spy).not[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('only accepts a number argument', () => { + const fn = mock.fn(() => 42); + fn(); + expectUnderTest(fn)[returnedTimes](1); + + [{}, [], true, 'a', new Map(), () => { }].forEach(value => { + expect(() => + expectUnderTest(fn)[returnedTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('.not only accepts a number argument', () => { + const fn = mock.fn(() => 42); + expectUnderTest(fn).not[returnedTimes](2); + + [{}, [], true, 'a', new Map(), () => { }].forEach(value => { + expect(() => + expectUnderTest(fn).not[returnedTimes](value), + ).toThrowErrorMatchingSnapshot(); + }); + }); + + test('passes if function returned equal to expected times', () => { + const fn = mock.fn(() => 42); + fn(); + fn(); + + expectUnderTest(fn)[returnedTimes](2); + + expect(() => + expectUnderTest(fn).not[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('calls that return undefined are counted as returns', () => { + const fn = mock.fn(() => undefined); + fn(); + fn(); + + expectUnderTest(fn)[returnedTimes](2); + + expect(() => + expectUnderTest(fn).not[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes if function returned more than expected times', () => { + const fn = mock.fn(() => 42); + fn(); + fn(); + fn(); + + expectUnderTest(fn)[returnedTimes](3); + expectUnderTest(fn).not[returnedTimes](2); + + expect(() => + expectUnderTest(fn)[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('.not passes if function called less than expected times', () => { + const fn = mock.fn(() => 42); + fn(); + + expectUnderTest(fn)[returnedTimes](1); + expectUnderTest(fn).not[returnedTimes](2); + + expect(() => + expectUnderTest(fn)[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('calls that throw are not counted', () => { + const fn = mock.fn((causeError: boolean) => { + if (causeError) + throw new Error('Error!'); + + + return 42; + }); + + fn(false); + + try { + fn(true); + } catch { + // ignore error + } + + fn(false); + + expectUnderTest(fn).not[returnedTimes](3); + + expect(() => + expectUnderTest(fn)[returnedTimes](3), + ).toThrowErrorMatchingSnapshot(); + }); + + test('calls that throw undefined are not counted', () => { + const fn = mock.fn((causeError: boolean) => { + if (causeError) + + throw undefined; + + + return 42; + }); + + fn(false); + + try { + fn(true); + } catch { + // ignore error + } + + fn(false); + + expectUnderTest(fn)[returnedTimes](2); + + expect(() => + expectUnderTest(fn).not[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + }); + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn(() => 42).mockName('named-mock'); + fn(); + fn(); + + expectUnderTest(fn)[returnedTimes](2); + + expect(() => + expectUnderTest(fn)[returnedTimes](1), + ).toThrowErrorMatchingSnapshot(); + }); + + test('incomplete recursive calls are handled properly', () => { + // sums up all integers from 0 -> value, using recursion + const fn: mock.Mock<(value: number) => number> = mock.fn(value => { + if (value === 0) { + return 0; + } else { + const recursiveResult = fn(value - 1); + + if (value === 2) { + // Only 2 of the recursive calls have returned at this point + expectUnderTest(fn)[returnedTimes](2); + expect(() => + expectUnderTest(fn).not[returnedTimes](2), + ).toThrowErrorMatchingSnapshot(); + } + + return value + recursiveResult; + } + }); + + fn(3); + }); + }); +} + +for (const returnedWith of [ + 'lastReturnedWith', + 'toHaveLastReturnedWith', + 'nthReturnedWith', + 'toHaveNthReturnedWith', + 'toReturnWith', + 'toHaveReturnedWith', +]) { + test.describe(returnedWith, () => { + function isToHaveNth( + returnedWith: string, + ): returnedWith is 'nthReturnedWith' | 'toHaveNthReturnedWith' { + return ( + returnedWith === 'nthReturnedWith' || + returnedWith === 'toHaveNthReturnedWith' + ); + } + + function isToHaveLast( + returnedWith: string, + ): returnedWith is 'lastReturnedWith' | 'toHaveLastReturnedWith' { + return ( + returnedWith === 'lastReturnedWith' || + returnedWith === 'toHaveLastReturnedWith' + ); + } + test('works only on spies or mock.fn', () => { + const fn = function fn() { }; + + expect(() => expectUnderTest(fn)[returnedWith]()).toThrowErrorMatchingSnapshot(); + }); + + test('works when not called', () => { + const fn = mock.fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn).not[returnedWith](1, 'foo'); + + expect(() => + expectUnderTest(fn)[returnedWith](1, 'foo'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn).not[returnedWith]('foo'); + + expect(() => + expectUnderTest(fn)[returnedWith]('foo'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with no arguments', () => { + const fn = mock.fn(); + fn(); + + if (isToHaveNth(returnedWith)) + expectUnderTest(fn)[returnedWith](1); + else + expectUnderTest(fn)[returnedWith](); + + }); + + test('works with argument that does not match', () => { + const fn = mock.fn(() => 'foo'); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn).not[returnedWith](1, 'bar'); + + expect(() => + expectUnderTest(fn)[returnedWith](1, 'bar'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn).not[returnedWith]('bar'); + + expect(() => + expectUnderTest(fn)[returnedWith]('bar'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with argument that does match', () => { + const fn = mock.fn(() => 'foo'); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, 'foo'); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, 'foo'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith]('foo'); + + expect(() => + expectUnderTest(fn).not[returnedWith]('foo'), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with undefined', () => { + const fn = mock.fn(() => undefined); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, undefined); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, undefined), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith](undefined); + + expect(() => + expectUnderTest(fn).not[returnedWith](undefined), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Map', () => { + const m1 = new Map([ + [1, 2], + [2, 1], + ]); + const m2 = new Map([ + [1, 2], + [2, 1], + ]); + const m3 = new Map([ + ['a', 'b'], + ['b', 'a'], + ]); + + const fn = mock.fn(() => m1); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, m2); + expectUnderTest(fn).not[returnedWith](1, m3); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, m2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[returnedWith](1, m3), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith](m2); + expectUnderTest(fn).not[returnedWith](m3); + + expect(() => + expectUnderTest(fn).not[returnedWith](m2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[returnedWith](m3), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Set', () => { + const s1 = new Set([1, 2]); + const s2 = new Set([1, 2]); + const s3 = new Set([3, 4]); + + const fn = mock.fn(() => s1); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, s2); + expectUnderTest(fn).not[returnedWith](1, s3); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, s2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[returnedWith](1, s3), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith](s2); + expectUnderTest(fn).not[returnedWith](s3); + + expect(() => + expectUnderTest(fn).not[returnedWith](s2), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[returnedWith](s3), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Immutable.js objects directly created', () => { + const directlyCreated = Immutable.Map([['a', { b: 'c' }]]); + const fn = mock.fn(() => directlyCreated); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, directlyCreated); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, directlyCreated), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith](directlyCreated); + + expect(() => + expectUnderTest(fn).not[returnedWith](directlyCreated), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('works with Immutable.js objects indirectly created', () => { + const indirectlyCreated = Immutable.Map().set('a', { b: 'c' }); + const fn = mock.fn(() => indirectlyCreated); + fn(); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn)[returnedWith](1, indirectlyCreated); + + expect(() => + expectUnderTest(fn).not[returnedWith](1, indirectlyCreated), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn)[returnedWith](indirectlyCreated); + + expect(() => + expectUnderTest(fn).not[returnedWith](indirectlyCreated), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('a call that throws is not considered to have returned', () => { + const fn = mock.fn(() => { + throw new Error('Error!'); + }); + + try { + fn(); + } catch { + // ignore error + } + + if (isToHaveNth(returnedWith)) { + // It doesn't matter what return value is tested if the call threw + expectUnderTest(fn).not[returnedWith](1, 'foo'); + expectUnderTest(fn).not[returnedWith](1, null); + expectUnderTest(fn).not[returnedWith](1, undefined); + + expect(() => + expectUnderTest(fn)[returnedWith](1, undefined), + ).toThrowErrorMatchingSnapshot(); + } else { + // It doesn't matter what return value is tested if the call threw + expectUnderTest(fn).not[returnedWith]('foo'); + expectUnderTest(fn).not[returnedWith](null); + expectUnderTest(fn).not[returnedWith](undefined); + + expect(() => + expectUnderTest(fn)[returnedWith](undefined), + ).toThrowErrorMatchingSnapshot(); + } + }); + + test('a call that throws undefined is not considered to have returned', () => { + const fn = mock.fn(() => { + + throw undefined; + }); + + try { + fn(); + } catch { + // ignore error + } + + if (isToHaveNth(returnedWith)) { + // It doesn't matter what return value is tested if the call threw + expectUnderTest(fn).not[returnedWith](1, 'foo'); + expectUnderTest(fn).not[returnedWith](1, null); + expectUnderTest(fn).not[returnedWith](1, undefined); + + expect(() => + expectUnderTest(fn)[returnedWith](1, undefined), + ).toThrowErrorMatchingSnapshot(); + } else { + // It doesn't matter what return value is tested if the call threw + expectUnderTest(fn).not[returnedWith]('foo'); + expectUnderTest(fn).not[returnedWith](null); + expectUnderTest(fn).not[returnedWith](undefined); + + expect(() => + expectUnderTest(fn)[returnedWith](undefined), + ).toThrowErrorMatchingSnapshot(); + } + }); + + if (!isToHaveNth(returnedWith)) { + test.describe('returnedWith', () => { + test('works with more calls than the limit', () => { + const fn = mock.fn<() => string>(); + fn.mockReturnValueOnce('foo1'); + fn.mockReturnValueOnce('foo2'); + fn.mockReturnValueOnce('foo3'); + fn.mockReturnValueOnce('foo4'); + fn.mockReturnValueOnce('foo5'); + fn.mockReturnValueOnce('foo6'); + + fn(); + fn(); + fn(); + fn(); + fn(); + fn(); + + expectUnderTest(fn).not[returnedWith]('bar'); + + expect(() => { + expectUnderTest(fn)[returnedWith]('bar'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('incomplete recursive calls are handled properly', () => { + // sums up all integers from 0 -> value, using recursion + const fn: mock.Mock<(value: number) => number> = mock.fn(value => { + if (value === 0) { + // Before returning from the base case of recursion, none of the + // calls have returned yet. + // This test ensures that the incomplete calls are not incorrectly + // interpreted as have returned undefined + expectUnderTest(fn).not[returnedWith](undefined); + expect(() => + expectUnderTest(fn)[returnedWith](undefined), + ).toThrowErrorMatchingSnapshot(); + + return 0; + } else { + return value + fn(value - 1); + } + }); + + fn(3); + }); + }); + } + + if (isToHaveNth(returnedWith)) { + test.describe('nthReturnedWith', () => { + test('works with three calls', () => { + const fn = mock.fn<() => string>(); + fn.mockReturnValueOnce('foo1'); + fn.mockReturnValueOnce('foo2'); + fn.mockReturnValueOnce('foo3'); + fn(); + fn(); + fn(); + + expectUnderTest(fn)[returnedWith](1, 'foo1'); + expectUnderTest(fn)[returnedWith](2, 'foo2'); + expectUnderTest(fn)[returnedWith](3, 'foo3'); + + expect(() => { + expectUnderTest(fn).not[returnedWith](1, 'foo1'); + expectUnderTest(fn).not[returnedWith](2, 'foo2'); + expectUnderTest(fn).not[returnedWith](3, 'foo3'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('should replace 1st, 2nd, 3rd with first, second, third', async () => { + const fn = mock.fn<() => string>(); + fn.mockReturnValueOnce('foo1'); + fn.mockReturnValueOnce('foo2'); + fn.mockReturnValueOnce('foo3'); + fn(); + fn(); + fn(); + + expect(() => { + expectUnderTest(fn)[returnedWith](1, 'bar1'); + expectUnderTest(fn)[returnedWith](2, 'bar2'); + expectUnderTest(fn)[returnedWith](3, 'bar3'); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + expectUnderTest(fn).not[returnedWith](1, 'foo1'); + expectUnderTest(fn).not[returnedWith](2, 'foo2'); + expectUnderTest(fn).not[returnedWith](3, 'foo3'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('positive throw matcher error for n that is not positive integer', async () => { + const fn = mock.fn(() => 'foo'); + fn(); + + expect(() => { + expectUnderTest(fn)[returnedWith](0, 'foo'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('should reject nth value greater than number of calls', async () => { + const fn = mock.fn(() => 'foo'); + fn(); + fn(); + fn(); + + expect(() => { + expectUnderTest(fn)[returnedWith](4, 'foo'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('positive throw matcher error for n that is not integer', async () => { + const fn = mock.fn<(a: string) => string>(() => 'foo'); + fn('foo'); + + expect(() => { + expectUnderTest(fn)[returnedWith](0.1, 'foo'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('negative throw matcher error for n that is not number', async () => { + const fn = mock.fn<(a: string) => string>(() => 'foo'); + fn('foo'); + + expect(() => { + // @ts-expect-error: Testing runtime error + expectUnderTest(fn).not[returnedWith](); + }).toThrowErrorMatchingSnapshot(); + }); + + test('incomplete recursive calls are handled properly', () => { + // sums up all integers from 0 -> value, using recursion + const fn: mock.Mock<(value: number) => number> = mock.fn(value => { + if (value === 0) { + return 0; + } else { + const recursiveResult = fn(value - 1); + + if (value === 2) { + // Only 2 of the recursive calls have returned at this point + expectUnderTest(fn).not[returnedWith](1, 6); + expectUnderTest(fn).not[returnedWith](2, 3); + expectUnderTest(fn)[returnedWith](3, 1); + expectUnderTest(fn)[returnedWith](4, 0); + + expect(() => + expectUnderTest(fn)[returnedWith](1, 6), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn)[returnedWith](2, 3), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn).not[returnedWith](3, 1), + ).toThrowErrorMatchingSnapshot(); + expect(() => + expectUnderTest(fn).not[returnedWith](4, 0), + ).toThrowErrorMatchingSnapshot(); + } + + return value + recursiveResult; + } + }); + + fn(3); + }); + }); + } + + if (isToHaveLast(returnedWith)) { + test.describe('lastReturnedWith', () => { + test('works with three calls', () => { + const fn = mock.fn<() => string>(); + fn.mockReturnValueOnce('foo1'); + fn.mockReturnValueOnce('foo2'); + fn.mockReturnValueOnce('foo3'); + fn(); + fn(); + fn(); + + expectUnderTest(fn)[returnedWith]('foo3'); + + expect(() => { + expectUnderTest(fn).not[returnedWith]('foo3'); + }).toThrowErrorMatchingSnapshot(); + }); + + test('incomplete recursive calls are handled properly', () => { + // sums up all integers from 0 -> value, using recursion + const fn: mock.Mock<(value: number) => number> = mock.fn(value => { + if (value === 0) { + // Before returning from the base case of recursion, none of the + // calls have returned yet. + expectUnderTest(fn).not[returnedWith](0); + expect(() => + expectUnderTest(fn)[returnedWith](0), + ).toThrowErrorMatchingSnapshot(); + return 0; + } else { + return value + fn(value - 1); + } + }); + + fn(3); + }); + }); + } + + test('includes the custom mock name in the error message', () => { + const fn = mock.fn().mockName('named-mock'); + + if (isToHaveNth(returnedWith)) { + expectUnderTest(fn).not[returnedWith](1, 'foo'); + + expect(() => + expectUnderTest(fn)[returnedWith](1, 'foo'), + ).toThrowErrorMatchingSnapshot(); + } else { + expectUnderTest(fn).not[returnedWith]('foo'); + + expect(() => + expectUnderTest(fn)[returnedWith]('foo'), + ).toThrowErrorMatchingSnapshot(); + } + }); + }); +} diff --git a/tests/expect/stacktrace.test.ts b/tests/expect/stacktrace.test.ts new file mode 100644 index 0000000000..6f5cf8bcc7 --- /dev/null +++ b/tests/expect/stacktrace.test.ts @@ -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:'); + } +}); diff --git a/tests/expect/symbolInObjects.test.ts b/tests/expect/symbolInObjects.test.ts new file mode 100644 index 0000000000..011d87e72d --- /dev/null +++ b/tests/expect/symbolInObjects.test.ts @@ -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); + }); +}); diff --git a/tests/expect/toThrowMatchers.snapshots.js b/tests/expect/toThrowMatchers.snapshots.js new file mode 100644 index 0000000000..c1243e0f0b --- /dev/null +++ b/tests/expect/toThrowMatchers.snapshots.js @@ -0,0 +1,456 @@ +module.exports["toThrowError substring did not throw at all"] = `expect(received).toThrowError(expected) + +Expected substring: "apple" + +Received function did not throw`; + +module.exports["toThrowError substring threw, but message did not match (error)"] = `expect(received).toThrowError(expected) + +Expected substring: "banana" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError substring threw, but message did not match (non-error falsey)"] = `expect(received).toThrowError(expected) + +Expected substring: "Server Error" +Received value: "" +`; + +module.exports["toThrowError substring threw, but message should not match (error)"] = `expect(received).not.toThrowError(expected) + +Expected substring: not "array" +Received message: "Invalid array length" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError substring threw, but message should not match (non-error truthy)"] = `expect(received).not.toThrowError(expected) + +Expected substring: not "Server Error" +Received value: "Internal Server Error" +`; + +module.exports["toThrowError regexp did not throw at all"] = `expect(received).toThrowError(expected) + +Expected pattern: /apple/ + +Received function did not throw`; + +module.exports["toThrowError regexp threw, but message did not match (error)"] = `expect(received).toThrowError(expected) + +Expected pattern: /banana/ +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError regexp threw, but message did not match (non-error falsey)"] = `expect(received).toThrowError(expected) + +Expected pattern: /^[123456789]\\d*/ +Received value: 0 +`; + +module.exports["toThrowError regexp threw, but message should not match (error)"] = `expect(received).not.toThrowError(expected) + +Expected pattern: not / array / +Received message: "Invalid array length" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError regexp threw, but message should not match (non-error truthy)"] = `expect(received).not.toThrowError(expected) + +Expected pattern: not /^[123456789]\\d*/ +Received value: 404 +`; + +module.exports["toThrowError error class did not throw at all"] = `expect(received).toThrowError(expected) + +Expected constructor: Err + +Received function did not throw`; + +module.exports["toThrowError error class threw, but class did not match (error)"] = `expect(received).toThrowError(expected) + +Expected constructor: Err2 +Received constructor: Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError error class threw, but class did not match (non-error falsey)"] = `expect(received).toThrowError(expected) + +Expected constructor: Err2 + +Received value: undefined +`; + +module.exports["toThrowError error class threw, but class should not match (error)"] = `expect(received).not.toThrowError(expected) + +Expected constructor: not Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError error class threw, but class should not match (error subclass)"] = `expect(received).not.toThrowError(expected) + +Expected constructor: not Err +Received constructor: SubErr extends Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError error class threw, but class should not match (error subsubclass)"] = `expect(received).not.toThrowError(expected) + +Expected constructor: not Err +Received constructor: SubSubErr extends … extends Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError error-message fail isNot false"] = `expect(received).toThrowError(expected) + +Expected message: "apple" +Received message: "banana" +`; + +module.exports["toThrowError error-message fail isNot true"] = `expect(received).not.toThrowError(expected) + +Expected message: not "Invalid array length" +`; + +module.exports["toThrowError error-message fail multiline diff highlight incorrect expected space"] = `expect(received).toThrowError(expected) + +- Expected message - 1 ++ Received message + 1 + +- There is no route defined for key Settings. ++ There is no route defined for key Settings. + Must be one of: 'Home' +`; + +module.exports["toThrowError asymmetric any-Class fail isNot false"] = `expect(received).toThrowError(expected) + +Expected asymmetric matcher: Any + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric any-Class fail isNot true"] = `expect(received).not.toThrowError(expected) + +Expected asymmetric matcher: not Any + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric anything fail isNot false"] = `expect(received).toThrowError(expected) + +Expected asymmetric matcher: Anything + +Thrown value: null +`; + +module.exports["toThrowError asymmetric anything fail isNot true"] = `expect(received).not.toThrowError(expected) + +Expected asymmetric matcher: not Anything + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric no-symbol fail isNot false"] = `expect(received).toThrowError(expected) + +Expected asymmetric matcher: {"asymmetricMatch": [Function asymmetricMatch]} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric no-symbol fail isNot true"] = `expect(received).not.toThrowError(expected) + +Expected asymmetric matcher: not {"asymmetricMatch": [Function asymmetricMatch]} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric objectContaining fail isNot false"] = `expect(received).toThrowError(expected) + +Expected asymmetric matcher: ObjectContaining {"name": "NotError"} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrowError asymmetric objectContaining fail isNot true"] = `expect(received).not.toThrowError(expected) + +Expected asymmetric matcher: not ObjectContaining {"name": "Error"} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js: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)"] = `expect(received).not.toThrowError() + +Thrown value: null +`; + +module.exports["toThrowError invalid arguments"] = `expect(received).not.toThrowError(expected) + +Matcher error: expected value must be a string or regular expression or class or error + +Expected has type: number +Expected has value: 111`; + +module.exports["toThrowError invalid actual"] = `expect(received).toThrowError() + +Matcher error: received value must be a function + +Received has type: string +Received has value: "a string"`; + +module.exports["toThrow substring did not throw at all"] = `expect(received).toThrow(expected) + +Expected substring: "apple" + +Received function did not throw`; + +module.exports["toThrow substring threw, but message did not match (error)"] = `expect(received).toThrow(expected) + +Expected substring: "banana" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow substring threw, but message did not match (non-error falsey)"] = `expect(received).toThrow(expected) + +Expected substring: "Server Error" +Received value: "" +`; + +module.exports["toThrow substring threw, but message should not match (error)"] = `expect(received).not.toThrow(expected) + +Expected substring: not "array" +Received message: "Invalid array length" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow substring threw, but message should not match (non-error truthy)"] = `expect(received).not.toThrow(expected) + +Expected substring: not "Server Error" +Received value: "Internal Server Error" +`; + +module.exports["toThrow regexp did not throw at all"] = `expect(received).toThrow(expected) + +Expected pattern: /apple/ + +Received function did not throw`; + +module.exports["toThrow regexp threw, but message did not match (error)"] = `expect(received).toThrow(expected) + +Expected pattern: /banana/ +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow regexp threw, but message did not match (non-error falsey)"] = `expect(received).toThrow(expected) + +Expected pattern: /^[123456789]\\d*/ +Received value: 0 +`; + +module.exports["toThrow regexp threw, but message should not match (error)"] = `expect(received).not.toThrow(expected) + +Expected pattern: not / array / +Received message: "Invalid array length" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow regexp threw, but message should not match (non-error truthy)"] = `expect(received).not.toThrow(expected) + +Expected pattern: not /^[123456789]\\d*/ +Received value: 404 +`; + +module.exports["toThrow error class did not throw at all"] = `expect(received).toThrow(expected) + +Expected constructor: Err + +Received function did not throw`; + +module.exports["toThrow error class threw, but class did not match (error)"] = `expect(received).toThrow(expected) + +Expected constructor: Err2 +Received constructor: Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow error class threw, but class did not match (non-error falsey)"] = `expect(received).toThrow(expected) + +Expected constructor: Err2 + +Received value: undefined +`; + +module.exports["toThrow error class threw, but class should not match (error)"] = `expect(received).not.toThrow(expected) + +Expected constructor: not Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow error class threw, but class should not match (error subclass)"] = `expect(received).not.toThrow(expected) + +Expected constructor: not Err +Received constructor: SubErr extends Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow error class threw, but class should not match (error subsubclass)"] = `expect(received).not.toThrow(expected) + +Expected constructor: not Err +Received constructor: SubSubErr extends … extends Err + +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow error-message fail isNot false"] = `expect(received).toThrow(expected) + +Expected message: "apple" +Received message: "banana" +`; + +module.exports["toThrow error-message fail isNot true"] = `expect(received).not.toThrow(expected) + +Expected message: not "Invalid array length" +`; + +module.exports["toThrow error-message fail multiline diff highlight incorrect expected space"] = `expect(received).toThrow(expected) + +- Expected message - 1 ++ Received message + 1 + +- There is no route defined for key Settings. ++ There is no route defined for key Settings. + Must be one of: 'Home' +`; + +module.exports["toThrow asymmetric any-Class fail isNot false"] = `expect(received).toThrow(expected) + +Expected asymmetric matcher: Any + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric any-Class fail isNot true"] = `expect(received).not.toThrow(expected) + +Expected asymmetric matcher: not Any + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric anything fail isNot false"] = `expect(received).toThrow(expected) + +Expected asymmetric matcher: Anything + +Thrown value: null +`; + +module.exports["toThrow asymmetric anything fail isNot true"] = `expect(received).not.toThrow(expected) + +Expected asymmetric matcher: not Anything + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric no-symbol fail isNot false"] = `expect(received).toThrow(expected) + +Expected asymmetric matcher: {"asymmetricMatch": [Function asymmetricMatch]} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric no-symbol fail isNot true"] = `expect(received).not.toThrow(expected) + +Expected asymmetric matcher: not {"asymmetricMatch": [Function asymmetricMatch]} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric objectContaining fail isNot false"] = `expect(received).toThrow(expected) + +Expected asymmetric matcher: ObjectContaining {"name": "NotError"} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js:24:74)`; + +module.exports["toThrow asymmetric objectContaining fail isNot true"] = `expect(received).not.toThrow(expected) + +Expected asymmetric matcher: not ObjectContaining {"name": "Error"} + +Received name: "Error" +Received message: "apple" + + at expectUnderTest (packages/expect/src/__tests__/toThrowMatchers-test.js: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)"] = `expect(received).not.toThrow() + +Thrown value: null +`; + +module.exports["toThrow invalid arguments"] = `expect(received).not.toThrow(expected) + +Matcher error: expected value must be a string or regular expression or class or error + +Expected has type: number +Expected has value: 111`; + +module.exports["toThrow invalid actual"] = `expect(received).toThrow() + +Matcher error: received value must be a function + +Received has type: string +Received has value: "a string"`; + diff --git a/tests/expect/toThrowMatchers.test.ts b/tests/expect/toThrowMatchers.test.ts new file mode 100644 index 0000000000..a5d5e52ba8 --- /dev/null +++ b/tests/expect/toThrowMatchers.test.ts @@ -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(); + }); + }); +} \ No newline at end of file diff --git a/tests/playwright-test/playwright.config.ts b/tests/playwright-test/playwright.config.ts index 34d4dc6d9f..0d94a8197d 100644 --- a/tests/playwright-test/playwright.config.ts +++ b/tests/playwright-test/playwright.config.ts @@ -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: { diff --git a/utils/check_deps.js b/utils/check_deps.js index 8943ca6800..79eca03062 100644 --- a/utils/check_deps.js +++ b/utils/check_deps.js @@ -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));