diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17700897d4..b0a75ba577 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,7 +122,7 @@ jobs: fail-fast: false matrix: include: - # - os: windows-latest + - os: ubuntu-latest - os: namespace-profile-mac-default runs-on: ${{ matrix.os }} steps: @@ -150,6 +150,9 @@ jobs: - name: Run CLI lint run: pnpm lint + - name: Install Playwright browsers + run: pnpx playwright install chromium + - name: Run CLI E2E tests run: | pnpm test diff --git a/packages/cli/package.json b/packages/cli/package.json index ee3f2fa697..3999fe1aad 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -45,7 +45,9 @@ "devDependencies": { "@napi-rs/cli": "catalog:", "@oxc-node/core": "catalog:", + "@vitest/browser": "catalog:", "@voidzero-dev/vite-plus-tools": "workspace:", + "playwright": "catalog:", "rolldown": "catalog:" }, "napi": { diff --git a/packages/cli/snap-tests/fingerprint-ignore-test/steps.json b/packages/cli/snap-tests/fingerprint-ignore-test/steps.json index f32c1d4f38..b1847f1915 100644 --- a/packages/cli/snap-tests/fingerprint-ignore-test/steps.json +++ b/packages/cli/snap-tests/fingerprint-ignore-test/steps.json @@ -1,4 +1,5 @@ { + "ignoredPlatforms": ["linux"], "env": { "VITE_DISABLE_AUTO_INSTALL": "1" }, diff --git a/packages/cli/snap-tests/vitest-browser-mode/package.json b/packages/cli/snap-tests/vitest-browser-mode/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/packages/cli/snap-tests/vitest-browser-mode/snap.txt b/packages/cli/snap-tests/vitest-browser-mode/snap.txt new file mode 100644 index 0000000000..43f06ca438 --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/snap.txt @@ -0,0 +1,42 @@ +> vite test + + RUN v + + ✓ |chromium| src/foo.test.js (1 test) ms + + Test Files 1 passed (1) + Tests 1 passed (1) + Start at + Duration ms (transform ms, setup ms, collect ms, tests ms, environment ms, prepare ms) + + + +> echo //comment >> src/foo.js +> vite test +✗ cache miss: content of input 'src/foo.js' changed, executing + + RUN v + + ✓ |chromium| src/foo.test.js (1 test) ms + + Test Files 1 passed (1) + Tests 1 passed (1) + Start at + Duration ms (transform ms, setup ms, collect ms, tests ms, environment ms, prepare ms) + + + +> echo //comment >> src/bar.js +> vite test +✓ cache hit, replaying + + RUN v + + ✓ |chromium| src/foo.test.js (1 test) ms + + Test Files 1 passed (1) + Tests 1 passed (1) + Start at + Duration ms (transform ms, setup ms, collect ms, tests ms, environment ms, prepare ms) + + diff --git a/packages/cli/snap-tests/vitest-browser-mode/src/bar.js b/packages/cli/snap-tests/vitest-browser-mode/src/bar.js new file mode 100644 index 0000000000..d9a5cffdad --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/src/bar.js @@ -0,0 +1 @@ +export default 'bar'; diff --git a/packages/cli/snap-tests/vitest-browser-mode/src/foo.js b/packages/cli/snap-tests/vitest-browser-mode/src/foo.js new file mode 100644 index 0000000000..d02ba545bd --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/src/foo.js @@ -0,0 +1 @@ +export default 'foo'; diff --git a/packages/cli/snap-tests/vitest-browser-mode/src/foo.test.js b/packages/cli/snap-tests/vitest-browser-mode/src/foo.test.js new file mode 100644 index 0000000000..819f0a6eeb --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/src/foo.test.js @@ -0,0 +1,8 @@ +import { describe, expect, it } from 'vitest'; +import foo from './foo'; + +describe('foo', () => { + it('should equal "foo"', () => { + expect(foo).toBe('foo'); + }); +}); diff --git a/packages/cli/snap-tests/vitest-browser-mode/steps.json b/packages/cli/snap-tests/vitest-browser-mode/steps.json new file mode 100644 index 0000000000..07ef1a0f11 --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/steps.json @@ -0,0 +1,13 @@ +{ + "ignoredPlatforms": ["linux"], + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vite test", + "echo //comment >> src/foo.js", + "vite test", + "echo //comment >> src/bar.js", + "vite test" + ] +} diff --git a/packages/cli/snap-tests/vitest-browser-mode/vitest.config.ts b/packages/cli/snap-tests/vitest-browser-mode/vitest.config.ts new file mode 100644 index 0000000000..57ff7d3f1f --- /dev/null +++ b/packages/cli/snap-tests/vitest-browser-mode/vitest.config.ts @@ -0,0 +1,16 @@ +// import { defineProject } from 'vitest/config'; + +export default { + test: { + browser: { + enabled: true, + provider: 'playwright', + headless: true, + instances: [ + { + browser: 'chromium', + }, + ], + }, + }, +}; diff --git a/packages/cli/snap-tests/yarn-install-with-options/snap.txt b/packages/cli/snap-tests/yarn-install-with-options/snap.txt index 93dd8a9a28..3b3eaa4b5d 100644 --- a/packages/cli/snap-tests/yarn-install-with-options/snap.txt +++ b/packages/cli/snap-tests/yarn-install-with-options/snap.txt @@ -40,7 +40,7 @@ --mutex [:specifier] use a mutex to ensure only one yarn instance is executing --emoji [bool] enable emoji in output (default: true) -s, --silent skip Yarn console logs, other types of logs (script output) will be printed - --cwd working directory to use (default: /private) + --cwd working directory to use (default: ) --proxy --https-proxy --registry override configuration registry diff --git a/packages/cli/snap-tests/yarn-install-with-options/steps.json b/packages/cli/snap-tests/yarn-install-with-options/steps.json index 711991a482..03826bc675 100644 --- a/packages/cli/snap-tests/yarn-install-with-options/steps.json +++ b/packages/cli/snap-tests/yarn-install-with-options/steps.json @@ -1,4 +1,5 @@ { + "ignoredPlatforms": ["linux"], "env": { "VITE_DISABLE_AUTO_INSTALL": "1" }, diff --git a/packages/tools/src/snap-test.ts b/packages/tools/src/snap-test.ts index 01291a6248..73e88030c0 100755 --- a/packages/tools/src/snap-test.ts +++ b/packages/tools/src/snap-test.ts @@ -18,9 +18,17 @@ const exec = async (command: string, options: cp.ExecOptionsWithStringEncoding) import { replaceUnstableOutput } from './utils.ts'; // Create a unique temporary directory for testing -const tempTmpDir = `${tmpdir()}/vite-plus-test-${randomUUID()}`; +// On macOS, `tmpdir()` is a symlink. Resolve it so that we can replace the resolved cwd in outputs. +const tempTmpDir = `${fs.realpathSync(tmpdir())}/vite-plus-test-${randomUUID()}`; fs.mkdirSync(tempTmpDir, { recursive: true }); +// Make dependencies available in the test cases +fs.symlinkSync( + path.resolve('node_modules'), + path.join(tempTmpDir, 'node_modules'), + process.platform === 'win32' ? 'junction' : 'dir' +); + // Clean up the temporary directory on exit process.on('exit', () => fs.rmSync(tempTmpDir, { recursive: true, force: true })); @@ -41,17 +49,22 @@ for (const caseName of fs.readdirSync(casesDir)) { // await Promise.all(tasks); interface Steps { + ignoredPlatforms?: string[]; env: Record; commands: string[]; } async function runTestCase(name: string) { + const steps: Steps = JSON.parse(await fsPromises.readFile(`${casesDir}/${name}/steps.json`, 'utf-8')); + if (steps.ignoredPlatforms !== undefined && steps.ignoredPlatforms.includes(process.platform)) { + console.log('%s skipped on platform %s', name, process.platform); + return; + } + console.log('%s started', name); const caseTmpDir = `${tempTmpDir}/${name}`; await fsPromises.cp(`${casesDir}/${name}`, caseTmpDir, { recursive: true, errorOnExist: true }); - const steps: Steps = JSON.parse(await fsPromises.readFile(`${caseTmpDir}/steps.json`, 'utf-8')); - const env = { ...process.env, // Indicate CLI is running in test mode, so that it prints more detailed outputs. diff --git a/packages/tools/src/utils.ts b/packages/tools/src/utils.ts index 5720726aa9..8b5708db07 100644 --- a/packages/tools/src/utils.ts +++ b/packages/tools/src/utils.ts @@ -9,8 +9,9 @@ export function replaceUnstableOutput(output: string, cwd?: string) { .replaceAll(/([@/\s]v?)\d+\.\d+\.\d+(?:-.*)?/g, '$1') // date .replaceAll(/\d{2}:\d{2}:\d{2}/g, '') + // duration + .replaceAll(/\d+(?:\.\d+)?(?:s|ms|µs)/g, 'ms') // oxlint - .replaceAll(/\d+(?:\.\d+)?(?:s|ms)/g, 'ms') .replaceAll(/with \d+ rules/g, 'with rules') .replaceAll(/using \d+ threads/g, 'using threads') // pnpm diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f09885f874..d0161c0e82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,9 @@ catalogs: '@types/node': specifier: ^24.5.2 version: 24.5.2 + '@vitest/browser': + specifier: ^3.2.4 + version: 3.2.4 create-tsdown: specifier: 0.0.3 version: 0.0.3 @@ -51,6 +54,9 @@ catalogs: picocolors: specifier: ^1.1.1 version: 1.1.1 + playwright: + specifier: ^1.56.1 + version: 1.56.1 rolldown-vite: specifier: ^7.1.10 version: 7.1.12 @@ -107,7 +113,7 @@ importers: version: 5.9.2 vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) + version: 3.2.4(@types/node@24.5.2)(@vitest/browser@3.2.4)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) docs: devDependencies: @@ -143,7 +149,7 @@ importers: version: 2.0.0-alpha.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(oxc-minify@0.82.3)(postcss@8.5.6)(typescript@5.9.2)(yaml@2.8.1) vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) + version: 3.2.4(@types/node@24.5.2)(@vitest/browser@3.2.4)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) devDependencies: '@napi-rs/cli': specifier: 'catalog:' @@ -151,9 +157,15 @@ importers: '@oxc-node/core': specifier: 'catalog:' version: 0.0.32 + '@vitest/browser': + specifier: 'catalog:' + version: 3.2.4(playwright@1.56.1)(rolldown-vite@7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1))(vitest@3.2.4) '@voidzero-dev/vite-plus-tools': specifier: 'workspace:' version: link:../tools + playwright: + specifier: 'catalog:' + version: 1.56.1 rolldown: specifier: ^1.0.0-beta.39 version: 1.0.0-beta.39 @@ -180,7 +192,7 @@ importers: version: 7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) + version: 3.2.4(@types/node@24.5.2)(@vitest/browser@3.2.4)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) devDependencies: '@clack/prompts': specifier: 'catalog:' @@ -215,6 +227,10 @@ importers: packages: + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} @@ -232,6 +248,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} @@ -1271,6 +1291,9 @@ packages: cpu: [x64] os: [win32] + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@quansync/fs@0.1.5': resolution: {integrity: sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==} @@ -1391,9 +1414,22 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} @@ -1440,6 +1476,21 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 + '@vitest/browser@3.2.4': + resolution: {integrity: sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==} + peerDependencies: + playwright: '*' + safaridriver: '*' + vitest: 3.2.4 + webdriverio: ^7.0.0 || ^8.0.0 || ^9.0.0 + peerDependenciesMeta: + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} @@ -1582,6 +1633,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -1593,6 +1648,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1744,6 +1802,9 @@ packages: resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} engines: {node: '>=0.3.1'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dts-resolver@2.1.2: resolution: {integrity: sha512-xeXHBQkn2ISSXxbJWD828PFjtyg+/UrMDo7W4Ffcs7+YWCquxU8YjV1KoxuiL+eJ5pg3ll+bC6flVv61L3LKZg==} engines: {node: '>=20.18.0'} @@ -1828,6 +1889,11 @@ packages: focus-trap@7.6.5: resolution: {integrity: sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1888,6 +1954,9 @@ packages: resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} @@ -1992,6 +2061,10 @@ packages: loupe@3.1.4: resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} @@ -2034,6 +2107,10 @@ packages: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2144,16 +2221,33 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + playwright-core@1.56.1: + resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.56.1: + resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + engines: {node: '>=18'} + hasBin: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -2267,6 +2361,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -2361,6 +2459,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -2513,6 +2615,18 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + yaml@2.8.1: resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} @@ -2531,6 +2645,12 @@ packages: snapshots: + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/generator@7.28.3': dependencies: '@babel/parser': 7.28.4 @@ -2547,6 +2667,8 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/runtime@7.28.4': {} + '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -3304,6 +3426,8 @@ snapshots: '@oxlint/win32-x64@1.16.0': optional: true + '@polka/url@1.0.0-next.29': {} + '@quansync/fs@0.1.5': dependencies: quansync: 0.2.11 @@ -3394,11 +3518,28 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/runtime': 7.28.4 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true + '@types/aria-query@5.0.4': {} + '@types/chai@5.2.2': dependencies: '@types/deep-eql': 4.0.2 @@ -3444,6 +3585,25 @@ snapshots: vite: rolldown-vite@7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) vue: 3.5.21(typescript@5.9.2) + '@vitest/browser@3.2.4(playwright@1.56.1)(rolldown-vite@7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1))(vitest@3.2.4)': + dependencies: + '@testing-library/dom': 10.4.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) + '@vitest/mocker': 3.2.4(rolldown-vite@7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1)) + '@vitest/utils': 3.2.4 + magic-string: 0.30.19 + sirv: 3.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/node@24.5.2)(@vitest/browser@3.2.4)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1) + ws: 8.18.3 + optionalDependencies: + playwright: 1.56.1 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.2 @@ -3595,12 +3755,18 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} ansis@4.1.0: {} argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + assertion-error@2.0.1: {} ast-kit@2.1.2: @@ -3723,6 +3889,8 @@ snapshots: diff@8.0.2: {} + dom-accessibility-api@0.5.16: {} + dts-resolver@2.1.2: {} emoji-regex@10.5.0: {} @@ -3809,6 +3977,9 @@ snapshots: dependencies: tabbable: 6.2.0 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -3869,6 +4040,8 @@ snapshots: jiti@2.5.1: {} + js-tokens@4.0.0: {} + js-tokens@9.0.1: {} js-yaml@4.1.0: @@ -3962,6 +4135,8 @@ snapshots: loupe@3.1.4: {} + lz-string@1.5.0: {} + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4010,6 +4185,8 @@ snapshots: mri@1.2.0: {} + mrmime@2.0.1: {} + ms@2.1.3: {} mute-stream@2.0.0: {} @@ -4126,16 +4303,32 @@ snapshots: exsolve: 1.0.7 pathe: 2.0.3 + playwright-core@1.56.1: {} + + playwright@1.56.1: + dependencies: + playwright-core: 1.56.1 + optionalDependencies: + fsevents: 2.3.2 + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + property-information@7.1.0: {} quansync@0.2.11: {} + react-is@17.0.2: {} + readdirp@4.1.2: {} regex-recursion@6.0.2: @@ -4237,6 +4430,12 @@ snapshots: signal-exit@4.1.0: {} + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sisteransi@1.0.5: {} slice-ansi@7.1.2: @@ -4321,6 +4520,8 @@ snapshots: dependencies: is-number: 7.0.0 + totalist@3.0.1: {} + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -4474,7 +4675,7 @@ snapshots: - universal-cookie - yaml - vitest@3.2.4(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1): + vitest@3.2.4(@types/node@24.5.2)(@vitest/browser@3.2.4)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 @@ -4501,6 +4702,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.5.2 + '@vitest/browser': 3.2.4(playwright@1.56.1)(rolldown-vite@7.1.12(@types/node@24.5.2)(esbuild@0.25.8)(jiti@2.5.1)(yaml@2.8.1))(vitest@3.2.4) transitivePeerDependencies: - esbuild - jiti @@ -4546,6 +4748,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + ws@8.18.3: {} + yaml@2.8.1: {} yocto-queue@1.2.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 810500d4bf..1aa3a02122 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,7 @@ catalog: '@types/node': ^24.5.2 '@types/react': ^19.1.8 '@types/react-dom': ^19.1.6 + '@vitest/browser': ^3.2.4 create-tsdown: 0.0.3 create-vite: ^8.0.0 cross-spawn: ^7.0.5 @@ -21,6 +22,7 @@ catalog: oxlint: ^1.16.0 oxlint-tsgolint: ^0.2.0 picocolors: ^1.1.1 + playwright: ^1.56.1 react: ^19.1.0 react-dom: ^19.1.0 rolldown: ^1.0.0-beta.39