diff --git a/.github/workflows/prbot.yml b/.github/workflows/prbot.yml index 8d5f07d6221..a0aca95ceb0 100644 --- a/.github/workflows/prbot.yml +++ b/.github/workflows/prbot.yml @@ -99,6 +99,8 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: ./.github/actions/setup + - name: Install Playwright Browsers + run: npx playwright install --with-deps - run: npm test package-compatibility: name: 'Verify compatibility of packages' diff --git a/package-lock.json b/package-lock.json index 2450bf91469..d07e93f193c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "@types/node": "22.10.5", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", + "@vitest/browser": "2.1.8", "aws-sdk": "2.1692.0", "commitizen": "4.3.1", "concurrently": "9.1.2", @@ -7619,6 +7620,83 @@ "dev": true, "license": "MIT" }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cookie": "^0.7.2" + } + }, + "node_modules/@bundled-es-modules/cookie/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, + "node_modules/@bundled-es-modules/tough-cookie/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@bundled-es-modules/tough-cookie/node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@bundled-es-modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@ckeditor/jsdoc-plugins": { "version": "43.0.1", "resolved": "https://registry.npmjs.org/@ckeditor/jsdoc-plugins/-/jsdoc-plugins-43.0.1.tgz", @@ -11869,6 +11947,24 @@ "win32" ] }, + "node_modules/@mswjs/interceptors": { + "version": "0.37.5", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.37.5.tgz", + "integrity": "sha512-AAwRb5vXFcY4L+FvZ7LZusDuZ0vEe0Zm8ohn1FM6/X7A3bj4mqmkAcGRWuvC2JwSygNwHAAmMnAI73vPHeqsHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", @@ -13682,6 +13778,31 @@ "node": ">= 18" } }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, "node_modules/@phenomnomnominal/tsquery": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz", @@ -13734,6 +13855,13 @@ "node": ">=18" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true, + "license": "MIT" + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -21447,7 +21575,6 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -21467,7 +21594,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -21484,7 +21610,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -21500,7 +21625,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -21514,15 +21638,13 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@testing-library/dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -22507,6 +22629,13 @@ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "license": "MIT" }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/strip-color": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/strip-color/-/strip-color-0.1.2.tgz", @@ -23614,6 +23743,87 @@ "vue": "^3.2.25" } }, + "node_modules/@vitest/browser": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-2.1.8.tgz", + "integrity": "sha512-OWVvEJThRgxlNMYNVLEK/9qVkpRcLvyuKLngIV3Hob01P56NjPHprVBYn+rx4xAJudbM9yrCrywPIEuA3Xyo8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^10.4.0", + "@testing-library/user-event": "^14.5.2", + "@vitest/mocker": "2.1.8", + "@vitest/utils": "2.1.8", + "magic-string": "^0.30.12", + "msw": "^2.6.4", + "sirv": "^3.0.0", + "tinyrainbow": "^1.2.0", + "ws": "^8.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "2.1.8", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/@vitest/browser/node_modules/@vitest/utils": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/browser/node_modules/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/browser/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", @@ -36566,6 +36776,13 @@ "tslib": "^2.0.3" } }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/help-me": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", @@ -38212,6 +38429,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -45489,6 +45713,173 @@ "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" } }, + "node_modules/msw": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.7.0.tgz", + "integrity": "sha512-BIodwZ19RWfCbYTxWTUfTXc+sg4OwjCAgxU1ZsgmggX/7S3LdUifsbUPJs61j0rWb19CZRGY5if77duhc0uXzw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.37.0", + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.26.1", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/@inquirer/confirm": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.3.tgz", + "integrity": "sha512-fuF9laMmHoOgWapF9h9hv6opA5WvmGFHsTYGCmuFxcghIhEhb3dN0CdQR4BUMqa2H506NCj8cGX4jwMsE4t6dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.4", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/msw/node_modules/@inquirer/core": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.4.tgz", + "integrity": "sha512-5y4/PUJVnRb4bwWY67KLdebWOhOc7xj5IP2J80oWXa64mVag24rwQ1VAdnj7/eDY/odhguW0zQ1Mp1pj6fO/2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/msw/node_modules/@inquirer/type": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.2.tgz", + "integrity": "sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/msw/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/msw/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/msw/node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/msw/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/msw/node_modules/type-fest": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.32.0.tgz", + "integrity": "sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", @@ -47807,6 +48198,13 @@ "dev": true, "license": "MIT" }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true, + "license": "MIT" + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -48844,6 +49242,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -53315,6 +53714,31 @@ "node": ">=14.16" } }, + "node_modules/sirv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sirv/node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -54044,6 +54468,13 @@ "bare-events": "^2.2.0" } }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -55404,6 +55835,16 @@ "dev": true, "license": "MIT" }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tough-cookie": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.0.tgz", @@ -58995,6 +59436,7 @@ "@types/node": "22.10.5", "@types/postcss-import": "14.0.3", "@types/puppeteer": "7.0.4", + "@vitest/browser": "2.1.8", "@whitespace/storybook-addon-html": "6.1.1", "autoprefixer": "10.4.20", "axe-core": "4.10.2", @@ -59010,6 +59452,7 @@ "lit-html": "3.2.1", "local-web-server": "5.4.0", "natural-orderby": "5.0.0", + "playwright": "1.49.1", "postcss-focus-visible": "10.0.1", "postcss-import": "16.1.0", "postcss-map": "0.11.0", @@ -59025,6 +59468,7 @@ "ts-node": "10.9.2", "typescript": "5.5.4", "vite": "5.4.11", + "vitest": "2.1.8", "wait-on": "8.0.1" }, "engines": { diff --git a/package.json b/package.json index 076fe8de748..1a67e1d9bf9 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,8 @@ "rimraf": "6.0.1", "semver": "7.6.3", "typescript": "5.5.4", - "vite": "5.4.11" + "vite": "5.4.11", + "@vitest/browser": "2.1.8" }, "overrides": { "@coveo/release": { diff --git a/packages/atomic/package.json b/packages/atomic/package.json index e2ba78c56f4..333c5ecb48d 100644 --- a/packages/atomic/package.json +++ b/packages/atomic/package.json @@ -52,8 +52,8 @@ "build:locales": "npx nx build:locales atomic", "start": "nx dev atomic", "prod": "npx serve www -l 3333 --no-request-logging", - "test": "npm run build:locales && stencil test --spec", - "test:watch": "stencil test --spec --watchAll", + "test": "vitest --run && npm run build:locales && stencil test --spec -- src/utils/initialization-utils.spec.ts src/components/search/atomic-layout/search-layout.spec.ts", + "test:watch": "vitest", "e2e": "cypress run --browser chrome", "e2e:firefox": "cypress run --browser firefox", "e2e:watch": "cypress open --browser chrome --e2e", @@ -144,7 +144,10 @@ "ts-node": "10.9.2", "typescript": "5.5.4", "vite": "5.4.11", - "wait-on": "8.0.1" + "wait-on": "8.0.1", + "playwright": "1.49.1", + "@vitest/browser": "2.1.8", + "vitest": "2.1.8" }, "peerDependencies": { "@coveo/bueno": "1.0.7", diff --git a/packages/atomic/src/components/commerce/product-template/__snapshots__/product-template-common.spec.ts.snap b/packages/atomic/src/components/commerce/product-template/__snapshots__/product-template-common.spec.ts.snap index af1f2cf6576..e6096eb54e4 100644 --- a/packages/atomic/src/components/commerce/product-template/__snapshots__/product-template-common.spec.ts.snap +++ b/packages/atomic/src/components/commerce/product-template/__snapshots__/product-template-common.spec.ts.snap @@ -1,8 +1,8 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`makeMatchConditions should log a warning and return an always-false callback 1`] = `"() => false"`; +exports[`makeMatchConditions > should log a warning and return an always-false callback 1`] = `"() => false"`; -exports[`makeMatchConditions should log a warning and return an always-false callback 2`] = ` +exports[`makeMatchConditions > should log a warning and return an always-false callback 2`] = ` [ "Conflicting match conditions for field field, the template will be ignored.", Set { diff --git a/packages/atomic/src/components/commerce/product-template/product-template-common.spec.ts b/packages/atomic/src/components/commerce/product-template/product-template-common.spec.ts index ba3d26a8394..a68803c9d56 100644 --- a/packages/atomic/src/components/commerce/product-template/product-template-common.spec.ts +++ b/packages/atomic/src/components/commerce/product-template/product-template-common.spec.ts @@ -1,14 +1,23 @@ +import { + describe, + it, + expect, + beforeEach, + afterEach, + vi, + MockInstance, +} from 'vitest'; import {makeMatchConditions} from './product-template-common'; describe('makeMatchConditions', () => { - let consoleErrorSpy: jest.SpyInstance; + let consoleErrorSpy: MockInstance; beforeEach(() => { - consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { - jest.resetAllMocks(); + vi.restoreAllMocks(); }); it('should log a warning and return an always-false callback', () => { diff --git a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.spec.ts similarity index 99% rename from packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts rename to packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.spec.ts index 6fff8906bb0..81d01be2aaf 100644 --- a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts +++ b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.spec.ts @@ -1,4 +1,4 @@ -import {transformMarkdownToHtml} from './markdown-utils'; +import {transformMarkdownToHtml} from './markdown-utils.js'; describe('markdownUtils', () => { describe('transformMarkdownToHtml', () => { diff --git a/packages/atomic/src/components/search/atomic-search-interface/analytics-config.spec.ts b/packages/atomic/src/components/search/atomic-search-interface/analytics-config.spec.ts index a2c05aa80ae..502ccac5625 100644 --- a/packages/atomic/src/components/search/atomic-search-interface/analytics-config.spec.ts +++ b/packages/atomic/src/components/search/atomic-search-interface/analytics-config.spec.ts @@ -3,10 +3,16 @@ import { getSampleSearchEngineConfiguration, SearchEngineConfiguration, } from '@coveo/headless'; +import {vi} from 'vitest'; import {getAnalyticsConfig} from './analytics-config'; import {createSearchStore} from './store'; -jest.mock('../../../global/environment'); +vi.mock('../../../global/environment', () => ({ + getAtomicEnvironment: vi.fn(() => ({ + version: '0.0.0', + headlessVersion: '0.0.0', + })), +})); describe('analyticsConfig', () => { let config: SearchEngineConfiguration; diff --git a/packages/atomic/src/utils/debounce-utils.spec.ts b/packages/atomic/src/utils/debounce-utils.spec.ts index fb6a643626d..852f046ba4a 100644 --- a/packages/atomic/src/utils/debounce-utils.spec.ts +++ b/packages/atomic/src/utils/debounce-utils.spec.ts @@ -1,10 +1,12 @@ +import {vi} from 'vitest'; import {buildDebouncedQueue, DebouncedQueue} from './debounce-utils'; describe('buildDebouncedQueue', () => { let queue: DebouncedQueue; const delay = 5; + beforeEach(() => { - jest.useFakeTimers(); + vi.useFakeTimers(); queue = buildDebouncedQueue({delay}); }); @@ -13,44 +15,44 @@ describe('buildDebouncedQueue', () => { }); it('executes the first action synchronously', () => { - const action = jest.fn(); + const action = vi.fn(); queue.enqueue(action); expect(action).toHaveBeenCalledTimes(1); }); it("doesn't execute actions more than once", () => { - const action = jest.fn(); + const action = vi.fn(); queue.enqueue(action); - jest.runAllTimers(); + vi.runAllTimers(); expect(action).toHaveBeenCalledTimes(1); }); it('debounces actions by the given delay', () => { - const action = jest.fn(); + const action = vi.fn(); queue.enqueue(() => {}); queue.enqueue(action); - jest.advanceTimersByTime(delay - 1); + vi.advanceTimersByTime(delay - 1); expect(action).not.toHaveBeenCalled(); - jest.advanceTimersByTime(1); + vi.advanceTimersByTime(1); expect(action).toHaveBeenCalledTimes(1); }); it('debounces actions executed after the last action within the delay', () => { queue.enqueue(() => {}); // Finishes at 0 queue.enqueue(() => {}); // Finishes at `delay` - jest.advanceTimersByTime(delay * 2 - 1); - const action = jest.fn(); + vi.advanceTimersByTime(delay * 2 - 1); + const action = vi.fn(); queue.enqueue(action); expect(action).not.toHaveBeenCalled(); - jest.advanceTimersByTime(1); + vi.advanceTimersByTime(1); expect(action).toHaveBeenCalledTimes(1); }); it("doesn't debounce actions executed after the last action past the delay", () => { queue.enqueue(() => {}); // Finishes at 0 queue.enqueue(() => {}); // Finishes at `delay` - jest.advanceTimersByTime(delay * 2); - const action = jest.fn(); + vi.advanceTimersByTime(delay * 2); + const action = vi.fn(); queue.enqueue(action); expect(action).toHaveBeenCalledTimes(1); }); @@ -67,7 +69,7 @@ describe('buildDebouncedQueue', () => { enqueue('C'); enqueue('B'); enqueue('A'); - jest.runAllTimers(); + vi.runAllTimers(); expect(completedActions).toEqual(['C', 'B', 'A']); }); @@ -83,18 +85,18 @@ describe('buildDebouncedQueue', () => { enqueue('C'); queue.cancelActionIfQueued('B'); queue.cancelActionIfQueued('D'); - jest.runAllTimers(); + vi.runAllTimers(); expect(completedActions).toEqual(['A', 'C']); }); it('can clear the queue', () => { - const actionA = jest.fn(); - const actionB = jest.fn(); + const actionA = vi.fn(); + const actionB = vi.fn(); queue.enqueue(() => {}); queue.enqueue(actionA); queue.enqueue(actionB); queue.clear(); - jest.runAllTimers(); + vi.runAllTimers(); expect(actionA).not.toHaveBeenCalled(); expect(actionB).not.toHaveBeenCalled(); }); @@ -102,11 +104,11 @@ describe('buildDebouncedQueue', () => { it('still debounces actions enqueued within the delay after clearing', () => { queue.enqueue(() => {}); queue.clear(); - jest.advanceTimersByTime(delay - 1); - const action = jest.fn(); + vi.advanceTimersByTime(delay - 1); + const action = vi.fn(); queue.enqueue(action); expect(action).not.toHaveBeenCalled(); - jest.advanceTimersByTime(1); + vi.advanceTimersByTime(1); expect(action).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/atomic/src/utils/event-utils.spec.ts b/packages/atomic/src/utils/event-utils.spec.ts index 8af62180eaf..867ee972a5d 100644 --- a/packages/atomic/src/utils/event-utils.spec.ts +++ b/packages/atomic/src/utils/event-utils.spec.ts @@ -1,8 +1,9 @@ +import {vi} from 'vitest'; import {listenOnce} from './event-utils'; describe('listenOnce', () => { it('only listens to an event once', () => { - const myFunction = jest.fn(); + const myFunction = vi.fn(); const element = document.createElement('div'); listenOnce(element, 'click', myFunction); element.click(); diff --git a/packages/atomic/src/utils/local-storage-utils.spec.ts b/packages/atomic/src/utils/local-storage-utils.spec.ts index 32ec3c4b719..6f72492eafb 100644 --- a/packages/atomic/src/utils/local-storage-utils.spec.ts +++ b/packages/atomic/src/utils/local-storage-utils.spec.ts @@ -2,6 +2,7 @@ import { buildSearchEngine, getSampleSearchEngineConfiguration, } from '@coveo/headless'; +import {vi} from 'vitest'; import {SafeStorage, StorageItems} from './local-storage-utils'; describe('Safe local storage', () => { @@ -14,10 +15,6 @@ describe('Safe local storage', () => { storage = new SafeStorage(); }); - afterEach(() => { - jest.clearAllMocks(); - }); - it('allows to save and retrieve an item', () => { storage.setItem(StorageItems.RECENT_QUERIES, 'foo'); expect(storage.getItem(StorageItems.RECENT_QUERIES)).toEqual('foo'); @@ -33,18 +30,24 @@ describe('Safe local storage', () => { }); it('fails gracefully when local storage throws', () => { - (localStorage.setItem as jest.Mock).mockImplementationOnce(() => { - throw new Error('🤯'); + vi.stubGlobal('localStorage', { + setItem: vi.fn().mockImplementationOnce(() => { + throw new Error('🤯'); + }), }); + expect(() => { storage.setItem(StorageItems.RECENT_QUERIES, 'foo'); }).not.toThrowError(); }); it('returns fallback object when local storage throws', () => { - (localStorage.getItem as jest.Mock).mockImplementationOnce(() => { - throw new Error('🤯'); + vi.stubGlobal('localStorage', { + getItem: vi.fn().mockImplementationOnce(() => { + throw new Error('🤯'); + }), }); + expect(storage.getParsedJSON(StorageItems.RECENT_QUERIES, 'foo')).toEqual( 'foo' ); diff --git a/packages/atomic/src/utils/result-utils.spec.ts b/packages/atomic/src/utils/result-utils.spec.ts index eb3676bf98e..9faf4e68dd4 100644 --- a/packages/atomic/src/utils/result-utils.spec.ts +++ b/packages/atomic/src/utils/result-utils.spec.ts @@ -4,16 +4,17 @@ import { Raw, Result, } from '@coveo/headless'; +import {vi} from 'vitest'; import {Bindings} from '../components/search/atomic-search-interface/atomic-search-interface'; import {buildStringTemplateFromResult} from './result-utils'; describe('buildStringTemplateFromResult', () => { - const mockRaw = jest.mocked({source: 'the source'} as Raw); - const mockResult = jest.mocked({ + const mockRaw = {source: 'the source'} as Raw; + const mockResult = { title: 'foo', uri: 'http://uri.foo.com', raw: mockRaw, - } as Result); + } as Result; const engine = buildSearchEngine({ configuration: getSampleSearchEngineConfiguration(), }); @@ -25,7 +26,7 @@ describe('buildStringTemplateFromResult', () => { {in: '${title}bar', out: 'foobar'}, {in: '${raw.source}', out: 'the source'}, {in: '${uri}/abc', out: 'http://uri.foo.com/abc'}, - {in: '${window.location.hostname}', out: 'testing.stenciljs.com'}, + {in: '${window.location.hostname}', out: 'localhost'}, ]; templates.forEach((template) => @@ -36,7 +37,7 @@ describe('buildStringTemplateFromResult', () => { }); it('should snip out objects that cannot be evaluated properly and log a warning', () => { - jest.spyOn(engine.logger, 'warn'); + const warnSpy = vi.spyOn(engine.logger, 'warn'); expect( buildStringTemplateFromResult( '${title}/${raw.notafield}', @@ -44,6 +45,6 @@ describe('buildStringTemplateFromResult', () => { bindings ) ).toBe('foo/'); - expect(engine.logger.warn).toHaveBeenCalled(); + expect(warnSpy).toHaveBeenCalled(); }); }); diff --git a/packages/atomic/src/utils/utils.spec.ts b/packages/atomic/src/utils/utils.spec.ts index a3721f6d513..b6cca5ee6bc 100644 --- a/packages/atomic/src/utils/utils.spec.ts +++ b/packages/atomic/src/utils/utils.spec.ts @@ -1,3 +1,4 @@ +import {vi} from 'vitest'; import { once, camelToKebab, @@ -7,9 +8,15 @@ import { aggregate, } from './utils'; +vi.mock('@stencil/core', () => ({ + getAssetPath: vi.fn((path: string) => { + return `${path}`; + }), +})); + describe('once', () => { it('should call the function only once', () => { - const myFunction = jest.fn(); + const myFunction = vi.fn(); const executeOnce = once(myFunction); executeOnce(); executeOnce(); diff --git a/packages/atomic/vitest.config.ts b/packages/atomic/vitest.config.ts new file mode 100644 index 00000000000..fab20541990 --- /dev/null +++ b/packages/atomic/vitest.config.ts @@ -0,0 +1,19 @@ +import {defineConfig} from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.spec.ts'], + exclude: [ + 'src/**/initialization-utils.spec.ts', + 'src/**/search-layout.spec.ts', + ], + globals: true, + browser: { + enabled: true, + name: 'chromium', + provider: 'playwright', + // https://playwright.dev + providerOptions: {}, + }, + }, +}); diff --git a/vitest.workspace.js b/vitest.workspace.js index 0793252790a..27434d80b0f 100644 --- a/vitest.workspace.js +++ b/vitest.workspace.js @@ -8,4 +8,5 @@ export default defineWorkspace([ // eslint-disable-next-line @cspell/spellchecker './packages/samples/vuejs/vite.config.ts', './packages/headless-react/vitest.config.js', + './packages/atomic/vitest.config.ts', ]);