diff --git a/.gitignore b/.gitignore index d071a0c..bdd698c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ storybook-static *storybook.log coverage test-results/ +__screenshots__ diff --git a/apps/playground/package.json b/apps/playground/package.json index 024e141..befda68 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -7,9 +7,9 @@ "dev": "vite --host --port 3000", "build": "pnpm type-check && vite build", "preview": "vite preview", - "test": "vitest run", - "test:unit": "vitest", - "test:unit-ui": "vitest --ui", + "test": "vitest", + "test:unit": "vitest --project unit", + "test:browser": "vitest --project browser", "type-check": "vue-tsc --build tsconfig.app.json" }, "dependencies": { diff --git a/apps/playground/src/layout/v-header.vue b/apps/playground/src/layout/v-header.vue index 5433166..ff4ac9a 100644 --- a/apps/playground/src/layout/v-header.vue +++ b/apps/playground/src/layout/v-header.vue @@ -25,6 +25,7 @@ Test theme', +}) + +beforeAll(() => { + localStorage.removeItem('theme') +}) + +it('toggle theme', async () => { + const screen = await renderComponent(TestTheme) + const button = screen.getByTestId('toggle-theme') + + function getTheme() { + return document.body.classList.contains('dark') ? 'dark' : 'light' + } + + expect(getTheme()).toBe('dark') + await expect.element(button).toBeVisible() + await button.click() + expect(getTheme()).toBe('light') +}) diff --git a/apps/playground/src/pages/counter/components/counter-button.browser.test.ts b/apps/playground/src/pages/counter/components/counter-button.browser.test.ts new file mode 100644 index 0000000..fcedea4 --- /dev/null +++ b/apps/playground/src/pages/counter/components/counter-button.browser.test.ts @@ -0,0 +1,15 @@ +import { expect, it } from 'vitest' +import { renderComponent } from '@/test-utils' +import CounterButton from './counter-button.vue' + +it('counter button increments the count', async () => { + const screen = await renderComponent(CounterButton) + const button = screen.getByTestId('counter') + + await expect.element(button).toBeVisible() + await button.click() + await expect.element(button).toHaveTextContent('Count 1 * 2 = 2') + + await button.tripleClick() + await expect.element(button).toHaveTextContent('Count 4 * 2 = 8') +}) diff --git a/apps/playground/src/pages/counter/components/counter-button.vue b/apps/playground/src/pages/counter/components/counter-button.vue index 3a3650d..c47456f 100644 --- a/apps/playground/src/pages/counter/components/counter-button.vue +++ b/apps/playground/src/pages/counter/components/counter-button.vue @@ -1,5 +1,8 @@ diff --git a/apps/playground/src/pages/counter/composables/use-counter.test.ts b/apps/playground/src/pages/counter/composables/use-counter.test.ts index 8b9fceb..088f50b 100644 --- a/apps/playground/src/pages/counter/composables/use-counter.test.ts +++ b/apps/playground/src/pages/counter/composables/use-counter.test.ts @@ -1,15 +1,7 @@ -import { createPinia, setActivePinia } from 'pinia' -import { beforeEach, describe, expect, it } from 'vitest' +import { describe, expect, it } from 'vitest' import { useCounterStore } from './use-counter' describe('use-counter', () => { - beforeEach(() => { - // creates a fresh pinia and makes it active - // so it's automatically picked up by any useStore() call - // without having to pass it to it: `useStore(pinia)` - setActivePinia(createPinia()) - }) - it('increments', () => { const counter = useCounterStore() expect(counter.count).toBe(0) diff --git a/apps/playground/src/test-utils.ts b/apps/playground/src/test-utils.ts new file mode 100644 index 0000000..8e03328 --- /dev/null +++ b/apps/playground/src/test-utils.ts @@ -0,0 +1,37 @@ +import { createPinia } from 'pinia' +import { render as vitestRender } from 'vitest-browser-vue' +import { createMemoryHistory, createRouter } from 'vue-router' +import App from './app.vue' +import type { Component } from 'vue' + +export async function renderComponent( + component: Component, + options: any = {}, +) { + const router = createRouter({ + history: createMemoryHistory(), + routes: [ + { + path: '/', + component, + }, + ], + }) + + const pinia = createPinia() + + const screen = vitestRender(App, { + ...options, + global: { + plugins: [ + router, + pinia, + ], + ...options.global, + }, + }) + + await router.isReady() + + return screen +} diff --git a/apps/playground/src/test/render-component.ts b/apps/playground/src/test/render-component.ts new file mode 100644 index 0000000..b6f5476 --- /dev/null +++ b/apps/playground/src/test/render-component.ts @@ -0,0 +1,83 @@ +import { VueQueryPlugin } from '@tanstack/vue-query' +import { createPinia } from 'pinia' +import { render as vitestRender } from 'vitest-browser-vue' +import { createMemoryHistory, createRouter } from 'vue-router' +import App from '@/app.vue' +import type { ComponentMountingOptions } from '@vue/test-utils' +import type { + Locator, + LocatorSelectors, + PrettyDOMOptions, +} from 'vitest/browser' +import type { DefineComponent } from 'vue' +import type { RouteRecordRaw } from 'vue-router' + +type ComponentProps = T extends new (...args: any) => { + $props: infer P +// eslint-disable-next-line ts/no-empty-object-type +} ? NonNullable

: T extends (props: infer P, ...args: any) => any ? P : {} + +interface RenderResult extends LocatorSelectors { + container: HTMLElement + baseElement: HTMLElement + locator: Locator + debug(el?: HTMLElement | HTMLElement[] | Locator | Locator[], maxLength?: number, options?: PrettyDOMOptions): void + unmount(): void + emitted(): Record + emitted(eventName: string): undefined | T[] + rerender(props: Partial): void +} + +interface ComponentRenderOptions> extends ComponentMountingOptions { + container?: HTMLElement + baseElement?: HTMLElement + routes?: RouteRecordRaw[] +} + +export async function renderComponent any) | (new (...args: any) => any) ? T : T extends { + props?: infer Props +} ? DefineComponent | (infer PropNames)[] ? { + [key in PropNames extends string ? PropNames : string]?: any; + } : Props> : DefineComponent, P extends ComponentProps = ComponentProps>( + component: T, + options: ComponentRenderOptions = {}, +): Promise> { + const pinia = createPinia() + + const router = createRouter({ + history: createMemoryHistory(), + routes: [ + { + path: '/', + // @ts-ignore + component, + }, + ...options.routes ?? [], + ], + }) + + const screen = vitestRender(App, { + ...options, + global: { + plugins: [ + pinia, + router, + [VueQueryPlugin, { + queryClientConfig: { + defaultOptions: { + queries: { + refetchOnMount: true, + refetchOnWindowFocus: false, + }, + }, + }, + }], + ], + ...options?.global, + }, + }) + + await router.isReady() + + return screen +}; diff --git a/apps/playground/src/test/setup.ts b/apps/playground/src/test/setup.ts new file mode 100644 index 0000000..63efb97 --- /dev/null +++ b/apps/playground/src/test/setup.ts @@ -0,0 +1,14 @@ +import { enableAutoUnmount } from '@vue/test-utils' +import { createPinia, setActivePinia } from 'pinia' +import { afterEach, beforeEach } from 'vitest' + +// import '../main.scss' + +beforeEach(() => { + // creates a fresh pinia and makes it active + // so it's automatically picked up by any useStore() call + // without having to pass it to it: `useStore(pinia)` + setActivePinia(createPinia()) +}) + +enableAutoUnmount(afterEach) diff --git a/apps/playground/vitest.config.ts b/apps/playground/vitest.config.ts index 2ce7508..308f70f 100644 --- a/apps/playground/vitest.config.ts +++ b/apps/playground/vitest.config.ts @@ -1,12 +1,40 @@ +import { playwright } from '@vitest/browser-playwright' import { defineConfig, mergeConfig } from 'vitest/config' import viteConfig from './vite.config' -export default mergeConfig( - viteConfig, - defineConfig({ - test: { - environment: 'happy-dom', - setupFiles: './vitest.setup.ts', - }, - }), -) +export default mergeConfig(viteConfig, defineConfig({ + test: { + projects: [ + { + extends: true, + test: { + name: 'unit', + environment: 'happy-dom', + setupFiles: './src/test/setup.ts', + include: ['./src/**/*.test.ts'], + exclude: ['./src/**/*.browser.test.ts'], + }, + }, + { + extends: true, + test: { + name: 'browser', + setupFiles: './src/test/setup.ts', + include: ['./src/**/*.browser.test.ts'], + browser: { + enabled: true, + headless: true, + provider: playwright(), + instances: [ + { browser: 'chromium' }, + ], + viewport: { + width: 1280, + height: 720, + }, + }, + }, + }, + ], + }, +})) diff --git a/apps/playground/vitest.setup.ts b/apps/playground/vitest.setup.ts deleted file mode 100644 index 89fbc6a..0000000 --- a/apps/playground/vitest.setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@vue/test-utils' diff --git a/eslint.config.js b/eslint.config.js index c259647..28f5311 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -97,6 +97,7 @@ export default antfu({ 'no-alert': 'off', 'no-console': 'off', 'no-cond-assign': 'off', + 'no-unused-vars': 'off', 'no-template-curly-in-string': 'off', 'ts/no-redeclare': 'off', 'ts/ban-ts-comment': 'off', @@ -111,7 +112,6 @@ export default antfu({ 'regexp/no-super-linear-backtracking': 'off', // warns - 'no-unused-vars': 'warn', 'unused-imports/no-unused-imports': 'warn', // errors diff --git a/package.json b/package.json index 4540e00..a665600 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,6 @@ "build:ui": "turbo run build --filter=./packages/ui", "build:packages": "turbo run build --filter=./packages/*", "type-check": "turbo run type-check", - "test": "vitest run", - "test:unit": "vitest", - "test:unit-ui": "vitest --ui", "lint": "eslint . --cache", "lint:fix": "eslint . --fix --cache", "generate-api": "pnpm --filter=@vue-workspace/api generate-api", @@ -32,15 +29,16 @@ "@types/jscodeshift": "17.3.0", "@types/node": "24.10.9", "@vitejs/plugin-vue": "6.0.2", - "@vitest/ui": "4.0.14", + "@vitest/browser-playwright": "4.0.18", + "@vitest/ui": "4.0.18", "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.8.1", "eslint": "9.39.2", "eslint-plugin-format": "1.3.1", "eslint-plugin-pinia": "0.4.2", - "happy-dom": "20.0.11", + "happy-dom": "20.3.9", "jscodeshift": "17.3.0", - "playwright": "1.57.0", + "playwright": "1.58.0", "prettier-plugin-css-order": "2.2.0", "sass-embedded": "1.93.3", "tsx": "4.20.6", @@ -51,7 +49,8 @@ "vite": "7.2.4", "vite-plugin-static-copy": "3.1.4", "vite-plugin-vue-devtools": "8.0.5", - "vitest": "4.0.14", + "vitest": "4.0.18", + "vitest-browser-vue": "2.0.2", "vue-tsc": "3.1.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5be1560..9986064 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,7 +15,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 7.0.1 - version: 7.0.1(@vue/compiler-sfc@3.5.25)(eslint-plugin-format@1.3.1(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14) + version: 7.0.1(@vue/compiler-sfc@3.5.25)(eslint-plugin-format@1.3.1(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18) '@iconify-json/heroicons-outline': specifier: 1.2.1 version: 1.2.1 @@ -31,9 +31,12 @@ importers: '@vitejs/plugin-vue': specifier: 6.0.2 version: 6.0.2(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + '@vitest/browser-playwright': + specifier: 4.0.18 + version: 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(playwright@1.58.0)(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vitest@4.0.18) '@vitest/ui': - specifier: 4.0.14 - version: 4.0.14(vitest@4.0.14) + specifier: 4.0.18 + version: 4.0.18(vitest@4.0.18) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -50,14 +53,14 @@ importers: specifier: 0.4.2 version: 0.4.2(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) happy-dom: - specifier: 20.0.11 - version: 20.0.11 + specifier: 20.3.9 + version: 20.3.9 jscodeshift: specifier: 17.3.0 version: 17.3.0 playwright: - specifier: 1.57.0 - version: 1.57.0 + specifier: 1.58.0 + version: 1.58.0 prettier-plugin-css-order: specifier: 2.2.0 version: 2.2.0(postcss@8.5.6)(prettier@3.8.0) @@ -89,8 +92,11 @@ importers: specifier: 8.0.5 version: 8.0.5(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) vitest: - specifier: 4.0.14 - version: 4.0.14(@types/node@24.10.9)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + specifier: 4.0.18 + version: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + vitest-browser-vue: + specifier: 2.0.2 + version: 2.0.2(vitest@4.0.18)(vue@3.5.25(typescript@5.9.3)) vue-tsc: specifier: 3.1.5 version: 3.1.5(typescript@5.9.3) @@ -1428,9 +1434,6 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@20.19.10': - resolution: {integrity: sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ==} - '@types/node@24.10.9': resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} @@ -1446,6 +1449,9 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@typescript-eslint/eslint-plugin@8.53.0': resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1515,6 +1521,17 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 + '@vitest/browser-playwright@4.0.18': + resolution: {integrity: sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==} + peerDependencies: + playwright: '*' + vitest: 4.0.18 + + '@vitest/browser@4.0.18': + resolution: {integrity: sha512-gVQqh7paBz3gC+ZdcCmNSWJMk70IUjDeVqi+5m5vYpEHsIwRgw3Y545jljtajhkekIpIp5Gg8oK7bctgY0E2Ng==} + peerDependencies: + vitest: 4.0.18 + '@vitest/eslint-plugin@1.6.6': resolution: {integrity: sha512-bwgQxQWRtnTVzsUHK824tBmHzjV0iTx3tZaiQIYDjX3SA7TsQS8CuDVqxXrRY3FaOUMgbGavesCxI9MOfFLm7Q==} engines: {node: '>=18'} @@ -1528,11 +1545,11 @@ packages: vitest: optional: true - '@vitest/expect@4.0.14': - resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} + '@vitest/expect@4.0.18': + resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/mocker@4.0.14': - resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} + '@vitest/mocker@4.0.18': + resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -1542,25 +1559,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.14': - resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} + '@vitest/pretty-format@4.0.18': + resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - '@vitest/runner@4.0.14': - resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} + '@vitest/runner@4.0.18': + resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - '@vitest/snapshot@4.0.14': - resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} + '@vitest/snapshot@4.0.18': + resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - '@vitest/spy@4.0.14': - resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} + '@vitest/spy@4.0.18': + resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - '@vitest/ui@4.0.14': - resolution: {integrity: sha512-fvDz8o7SQpFLoSBo6Cudv+fE85/fPCkwTnLAN85M+Jv7k59w2mSIjT9Q5px7XwGrmYqqKBEYxh/09IBGd1E7AQ==} + '@vitest/ui@4.0.18': + resolution: {integrity: sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==} peerDependencies: - vitest: 4.0.14 + vitest: 4.0.18 - '@vitest/utils@4.0.14': - resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} + '@vitest/utils@4.0.18': + resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} '@volar/language-core@2.4.23': resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} @@ -2591,8 +2608,8 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} - happy-dom@20.0.11: - resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==} + happy-dom@20.3.9: + resolution: {integrity: sha512-OIoj0PcK2JaxQuANHxWkxFRSNXAuSgO1vCzCT66KItE0W/ieZLG+/iW8OetlxB+F9EaPB7DoFYKAubFG1f4Mvw==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -3354,6 +3371,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pixelmatch@7.1.0: + resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} + hasBin: true + pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -3364,13 +3385,13 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.57.0: - resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} + playwright-core@1.58.0: + resolution: {integrity: sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw==} engines: {node: '>=18'} hasBin: true - playwright@1.57.0: - resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} + playwright@1.58.0: + resolution: {integrity: sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ==} engines: {node: '>=18'} hasBin: true @@ -3378,6 +3399,10 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + pnpm-workspace-yaml@1.4.3: resolution: {integrity: sha512-Q8B3SWuuISy/Ciag4DFP7MCrJX07wfaekcqD2o/msdIj4x8Ql3bZ/NEKOXV7mTVh7m1YdiFWiMi9xH+0zuEGHw==} @@ -3854,9 +3879,6 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.1: resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} @@ -3982,9 +4004,6 @@ packages: ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -4193,18 +4212,24 @@ packages: yaml: optional: true - vitest@4.0.14: - resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} + vitest-browser-vue@2.0.2: + resolution: {integrity: sha512-/IM/+gOBEPL5Ocu/n28NmAvr1XgqGxzJrgwkPx9O+ioB52iuyg25nDQXlDDPSCm5PJFmwNzA6yycWxFAFTqXYA==} + peerDependencies: + vitest: ^4.0.0-0 + vue: ^3.0.0 + + vitest@4.0.18: + resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.14 - '@vitest/browser-preview': 4.0.14 - '@vitest/browser-webdriverio': 4.0.14 - '@vitest/ui': 4.0.14 + '@vitest/browser-playwright': 4.0.18 + '@vitest/browser-preview': 4.0.18 + '@vitest/browser-webdriverio': 4.0.18 + '@vitest/ui': 4.0.18 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -4404,7 +4429,7 @@ snapshots: '@akryum/tinypool@0.3.1': {} - '@antfu/eslint-config@7.0.1(@vue/compiler-sfc@3.5.25)(eslint-plugin-format@1.3.1(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14)': + '@antfu/eslint-config@7.0.1(@vue/compiler-sfc@3.5.25)(eslint-plugin-format@1.3.1(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18)': dependencies: '@antfu/install-pkg': 1.1.0 '@clack/prompts': 0.11.0 @@ -4413,7 +4438,7 @@ snapshots: '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14) + '@vitest/eslint-plugin': 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18) ansis: 4.2.0 cac: 6.7.14 eslint: 9.39.2(jiti@2.6.1) @@ -5587,10 +5612,6 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@20.19.10': - dependencies: - undici-types: 6.21.0 - '@types/node@24.10.9': dependencies: undici-types: 7.16.0 @@ -5603,6 +5624,10 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} + '@types/ws@8.18.1': + dependencies: + '@types/node': 24.10.9 + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -5702,66 +5727,96 @@ snapshots: vite: 7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) vue: 3.5.25(typescript@5.9.3) - '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14)': + '@vitest/browser-playwright@4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(playwright@1.58.0)(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vitest@4.0.18)': + dependencies: + '@vitest/browser': 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vitest@4.0.18) + '@vitest/mocker': 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2)) + playwright: 1.58.0 + tinyrainbow: 3.0.3 + vitest: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vitest@4.0.18)': + dependencies: + '@vitest/mocker': 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2)) + '@vitest/utils': 4.0.18 + magic-string: 0.30.21 + pixelmatch: 7.1.0 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.0.3 + vitest: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18)': dependencies: '@typescript-eslint/scope-manager': 8.53.0 '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.14(@types/node@24.10.9)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + vitest: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.14': + '@vitest/expect@4.0.18': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.2 - '@vitest/spy': 4.0.14 - '@vitest/utils': 4.0.14 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.14(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.14 + '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.3(@types/node@24.10.9)(typescript@5.9.3) vite: 7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) - '@vitest/pretty-format@4.0.14': + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.14': + '@vitest/runner@4.0.18': dependencies: - '@vitest/utils': 4.0.14 + '@vitest/utils': 4.0.18 pathe: 2.0.3 - '@vitest/snapshot@4.0.14': + '@vitest/snapshot@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.14 + '@vitest/pretty-format': 4.0.18 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.14': {} + '@vitest/spy@4.0.18': {} - '@vitest/ui@4.0.14(vitest@4.0.14)': + '@vitest/ui@4.0.18(vitest@4.0.18)': dependencies: - '@vitest/utils': 4.0.14 + '@vitest/utils': 4.0.18 fflate: 0.8.2 flatted: 3.3.3 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.14(@types/node@24.10.9)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + vitest: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) - '@vitest/utils@4.0.14': + '@vitest/utils@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.14 + '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 '@volar/language-core@2.4.23': @@ -6882,11 +6937,17 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 - happy-dom@20.0.11: + happy-dom@20.3.9: dependencies: - '@types/node': 20.19.10 + '@types/node': 24.10.9 '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + entities: 4.5.0 whatwg-mimetype: 3.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate has-flag@4.0.0: {} @@ -7848,6 +7909,10 @@ snapshots: pirates@4.0.7: {} + pixelmatch@7.1.0: + dependencies: + pngjs: 7.0.0 + pkg-dir@3.0.0: dependencies: find-up: 3.0.0 @@ -7864,16 +7929,18 @@ snapshots: exsolve: 1.0.7 pathe: 2.0.3 - playwright-core@1.57.0: {} + playwright-core@1.58.0: {} - playwright@1.57.0: + playwright@1.58.0: dependencies: - playwright-core: 1.57.0 + playwright-core: 1.58.0 optionalDependencies: fsevents: 2.3.2 pluralize@8.0.0: {} + pngjs@7.0.0: {} + pnpm-workspace-yaml@1.4.3: dependencies: yaml: 2.8.2 @@ -8312,8 +8379,6 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.2: {} - tinyexec@1.0.1: {} tinyexec@1.0.2: {} @@ -8417,8 +8482,6 @@ snapshots: ufo@1.6.1: {} - undici-types@6.21.0: {} - undici-types@7.16.0: {} unicorn-magic@0.3.0: {} @@ -8643,15 +8706,21 @@ snapshots: tsx: 4.20.6 yaml: 2.8.2 - vitest@4.0.14(@types/node@24.10.9)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2): + vitest-browser-vue@2.0.2(vitest@4.0.18)(vue@3.5.25(typescript@5.9.3)): + dependencies: + '@vue/test-utils': 2.4.6 + vitest: 4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) + vue: 3.5.25(typescript@5.9.3) + + vitest@4.0.18(@types/node@24.10.9)(@vitest/browser-playwright@4.0.18)(@vitest/ui@4.0.18)(happy-dom@20.3.9)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.14 - '@vitest/mocker': 4.0.14(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.14 - '@vitest/runner': 4.0.14 - '@vitest/snapshot': 4.0.14 - '@vitest/spy': 4.0.14 - '@vitest/utils': 4.0.14 + '@vitest/expect': 4.0.18 + '@vitest/mocker': 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.18 + '@vitest/runner': 4.0.18 + '@vitest/snapshot': 4.0.18 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 @@ -8660,15 +8729,16 @@ snapshots: picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 vite: 7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.10.9 - '@vitest/ui': 4.0.14(vitest@4.0.14) - happy-dom: 20.0.11 + '@vitest/browser-playwright': 4.0.18(msw@2.12.3(@types/node@24.10.9)(typescript@5.9.3))(playwright@1.58.0)(vite@7.2.4(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(tsx@4.20.6)(yaml@2.8.2))(vitest@4.0.18) + '@vitest/ui': 4.0.18(vitest@4.0.18) + happy-dom: 20.3.9 jsdom: 27.4.0 transitivePeerDependencies: - jiti diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index ed8993d..0000000 --- a/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - projects: [ - 'apps/*', - 'packages/*', - ], - }, -})