diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 329e2a2a3dd8..6b6d49536851 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,64 +53,59 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@ea251d4d2f03a9c18841ae1b752f58b82dfb4d5e # v35.3.0 + with: + files: | + docs/** + .github/** + !.github/workflows/ci.yml + **.md + - uses: ./.github/actions/setup-and-cache + if: steps.changed-files.outputs.only_changed != 'true' with: node-version: ${{ matrix.node_version }} - uses: browser-actions/setup-chrome@v1 + if: steps.changed-files.outputs.only_changed != 'true' - name: Install + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm i - name: Install Playwright Dependencies - run: pnpm exec playwright install --with-deps + if: steps.changed-files.outputs.only_changed != 'true' + run: pnpm exec playwright install chromium --with-deps - name: Build + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run build - name: Test + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test:ci - name: Test Examples + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test:examples - test-ui: - strategy: - matrix: - os: [ubuntu-latest, macos-14, windows-latest] - fail-fast: false - - runs-on: ${{ matrix.os }} - - timeout-minutes: 30 - - steps: - - uses: actions/checkout@v4 - - - uses: ./.github/actions/setup-and-cache - with: - node-version: 20 - - - name: Install - run: pnpm i - - - name: Install Playwright Dependencies - run: pnpm exec playwright install chromium - - - name: Build - run: pnpm run build - - name: Unit Test UI + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run -C packages/ui test:ui - - name: E2E Test UI - run: pnpm -C test/ui test-e2e - test-browser: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: - browser: [[chrome, chromium], [firefox, firefox], [edge, webkit]] + os: + - macos-14 + - windows-latest + browser: + - [chromium, chrome] + - [firefox, firefox] + - [webkit] fail-fast: false timeout-minutes: 30 @@ -118,66 +113,46 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@ea251d4d2f03a9c18841ae1b752f58b82dfb4d5e # v35.3.0 + with: + files: | + docs/** + .github/** + !.github/workflows/ci.yml + **.md + - uses: ./.github/actions/setup-and-cache + if: steps.changed-files.outputs.only_changed != 'true' with: node-version: 20 - uses: browser-actions/setup-chrome@v1 + if: ${{ steps.changed-files.outputs.only_changed != 'true' && matrix.browser[0] == 'chromium' }} - uses: browser-actions/setup-firefox@v1 + if: ${{ steps.changed-files.outputs.only_changed != 'true' && matrix.browser[0] == 'firefox' }} - name: Install + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm i - name: Install Playwright Dependencies - run: pnpm exec playwright install --with-deps + if: steps.changed-files.outputs.only_changed != 'true' + run: pnpm exec playwright install ${{ matrix.browser[0] }} --with-deps - name: Build + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run build - - name: Test Browser (webdriverio) - run: pnpm run test:browser:webdriverio - env: - BROWSER: ${{ matrix.browser[0] }} - - name: Test Browser (playwright) + if: steps.changed-files.outputs.only_changed != 'true' run: pnpm run test:browser:playwright env: - BROWSER: ${{ matrix.browser[1] }} - - test-browser-windows: - runs-on: windows-latest - strategy: - matrix: - browser: [[chrome, chromium], [edge, webkit]] - fail-fast: false - - timeout-minutes: 30 - - steps: - - uses: actions/checkout@v4 - - - uses: ./.github/actions/setup-and-cache - with: - node-version: 20 - - - uses: browser-actions/setup-chrome@v1 - - uses: browser-actions/setup-edge@v1 - - - name: Install - run: pnpm i - - - name: Install Playwright Dependencies - run: pnpm exec playwright install --with-deps - - - name: Build - run: pnpm run build + BROWSER: ${{ matrix.browser[0] }} - name: Test Browser (webdriverio) run: pnpm run test:browser:webdriverio - env: - BROWSER: ${{ matrix.browser[0] }} - - - name: Test Browser (playwright) - run: pnpm run test:browser:playwright + if: ${{ steps.changed-files.outputs.only_changed != 'true' && matrix.browser[1] }} env: BROWSER: ${{ matrix.browser[1] }} diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index c87d8730c247..112abf20131b 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -60,7 +60,16 @@ export default ({ mode }: { mode: string }) => { light: 'github-light', dark: 'github-dark', }, - codeTransformers: mode === 'development' ? [] : [transformerTwoslash()], + codeTransformers: mode === 'development' + ? [] + : [transformerTwoslash({ + processHoverInfo: (info) => { + if (info.includes(process.cwd())) { + return info.replace(new RegExp(process.cwd(), 'g'), '') + } + return info + }, + })], }, themeConfig: { logo: '/logo.svg', diff --git a/docs/.vitepress/scripts/cli-generator.ts b/docs/.vitepress/scripts/cli-generator.ts index 1223e3b24bf2..86497279206e 100644 --- a/docs/.vitepress/scripts/cli-generator.ts +++ b/docs/.vitepress/scripts/cli-generator.ts @@ -5,10 +5,37 @@ import type { CLIOption, CLIOptions } from '../../../packages/vitest/src/node/cl import { cliOptionsConfig } from '../../../packages/vitest/src/node/cli/cli-config' const docsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../..') -const cliTablePath = resolve(docsDir, './guide/cli-table.md') +const cliTablePath = resolve(docsDir, './guide/cli-generated.md') const nonNullable = (value: T): value is NonNullable => value !== null && value !== undefined +const skipCli = new Set([ + 'mergeReports', + 'changed', + 'shard', +]) + +const skipConfig = new Set([ + 'config', + 'api.port', + 'api.host', + 'api.strictPort', + 'coverage.watermarks.statements', + 'coverage.watermarks.lines', + 'coverage.watermarks.branches', + 'coverage.watermarks.functions', + 'coverage.thresholds.statements', + 'coverage.thresholds.branches', + 'coverage.thresholds.functions', + 'coverage.thresholds.lines', + 'standalone', + 'clearScreen', + 'color', + 'run', + 'hideSkippedTests', + 'dom', +]) + function resolveOptions(options: CLIOptions, parentName?: string) { return Object.entries(options).flatMap( ([subcommandName, subcommandConfig]) => resolveCommand( @@ -19,7 +46,7 @@ function resolveOptions(options: CLIOptions, parentName?: string) { } function resolveCommand(name: string, config: CLIOption | null): any { - if (!config) { + if (!config || skipCli.has(name)) { return null } @@ -37,17 +64,19 @@ function resolveCommand(name: string, config: CLIOption | null): any { } return { - title, + title: name, + cli: title, description: config.description, } } const options = resolveOptions(cliOptionsConfig) -const template = ` -| Options | | -| ------------- | ------------- | -${options.map(({ title, description }) => `| ${title} | ${description} |`).join('\n')} -`.trimStart() +const template = options.map((option) => { + const title = option.title + const cli = option.cli + const config = skipConfig.has(title) ? '' : `[${title}](/config/#${title.toLowerCase().replace(/\./g, '-')})` + return `### ${title}\n\n- **CLI:** ${cli}\n${config ? `- **Config:** ${config}\n` : ''}\n${option.description}\n` +}).join('\n') writeFileSync(cliTablePath, template, 'utf-8') diff --git a/docs/advanced/api.md b/docs/advanced/api.md index 3152dbfd8ce8..5429a84f0c5d 100644 --- a/docs/advanced/api.md +++ b/docs/advanced/api.md @@ -8,7 +8,7 @@ Vitest exposes experimental private API. Breaking changes might not follow SemVe You can start running Vitest tests using its Node API: -```js twoslash +```js import { startVitest } from 'vitest/node' const vitest = await startVitest('test') @@ -38,7 +38,7 @@ Alternatively, you can pass in the complete Vite config as the fourth argument, You can create Vitest instance yourself using `createVitest` function. It returns the same `Vitest` instance as `startVitest`, but it doesn't start tests and doesn't validate installed packages. -```js twoslash +```js import { createVitest } from 'vitest/node' const vitest = await createVitest('test', { @@ -50,7 +50,7 @@ const vitest = await createVitest('test', { You can use this method to parse CLI arguments. It accepts a string (where arguments are split by a single space) or a strings array of CLI arguments in the same format that Vitest CLI uses. It returns a filter and `options` that you can later pass down to `createVitest` or `startVitest` methods. -```ts twoslash +```ts import { parseCLI } from 'vitest/node' parseCLI('vitest ./files.ts --coverage --browser=chrome') diff --git a/docs/advanced/pool.md b/docs/advanced/pool.md index 0024e60d280e..2d5309be44ce 100644 --- a/docs/advanced/pool.md +++ b/docs/advanced/pool.md @@ -14,9 +14,9 @@ Vitest runs tests in pools. By default, there are several pools: You can provide your own pool by specifying a file path: -```ts twoslash +```ts import { defineConfig } from 'vitest/config' -// ---cut--- + export default defineConfig({ test: { // will run every file with a custom pool by default diff --git a/docs/advanced/reporters.md b/docs/advanced/reporters.md index c316447c5301..531dfc1dafb8 100644 --- a/docs/advanced/reporters.md +++ b/docs/advanced/reporters.md @@ -6,7 +6,7 @@ You can import reporters from `vitest/reporters` and extend them to create your In general, you don't need to create your reporter from scratch. `vitest` comes with several default reporting programs that you can extend. -```ts twoslash +```ts import { DefaultReporter } from 'vitest/reporters' export default class MyDefaultReporter extends DefaultReporter { @@ -56,6 +56,374 @@ export default defineConfig({ }) ``` +## Reported Tasks + +::: warning +This is an experimental API. Breaking changes might not follow SemVer. Please pin Vitest's version when using it. + +You can get access to this API by calling `vitest.state.getReportedEntity(runnerTask)`: + +```ts twoslash +import type { Vitest } from 'vitest/node' +import type { RunnerTestFile } from 'vitest' +import type { Reporter, TestFile } from 'vitest/reporters' + +class MyReporter implements Reporter { + ctx!: Vitest + + onInit(ctx: Vitest) { + this.ctx = ctx + } + + onFinished(files: RunnerTestFile[]) { + for (const fileTask of files) { + const testFile = this.ctx.state.getReportedEntity(fileTask) as TestFile + for (const task of testFile.children) { + // ^? + console.log('finished', task.type, task.fullName) + } + } + } +} +``` + +We are planning to stabilize this API in Vitest 2.1. +::: + +### TestCase + +`TestCase` represents a single test. + +```ts +declare class TestCase { + readonly type = 'test' | 'custom' + /** + * Task instance. + * @experimental Public task API is experimental and does not follow semver. + */ + readonly task: RunnerTestCase | RunnerCustomCase + /** + * The project associated with the test. + */ + readonly project: TestProject + /** + * Direct reference to the test file where the test is defined. + */ + readonly file: TestFile + /** + * Name of the test. + */ + readonly name: string + /** + * Full name of the test including all parent suites separated with `>`. + */ + readonly fullName: string + /** + * Unique identifier. + * This ID is deterministic and will be the same for the same test across multiple runs. + * The ID is based on the project name, file path and test position. + */ + readonly id: string + /** + * Location in the file where the test was defined. + * Locations are collected only if `includeTaskLocation` is enabled in the config. + */ + readonly location: { line: number; column: number } | undefined + /** + * Parent suite. If the test was called directly inside the file, the parent will be the file. + */ + readonly parent: TestSuite | TestFile + /** + * Options that test was initiated with. + */ + readonly options: TaskOptions + /** + * Checks if the test did not fail the suite. + * If the test is not finished yet or was skipped, it will return `true`. + */ + ok(): boolean + /** + * Custom metadata that was attached to the test during its execution. + */ + meta(): TaskMeta + /** + * Test results. Will be `undefined` if test is not finished yet or was just collected. + */ + result(): TestResult | undefined + /** + * Useful information about the test like duration, memory usage, etc. + */ + diagnostic(): TestDiagnostic | undefined +} + +export type TestResult = TestResultPassed | TestResultFailed | TestResultSkipped + +export interface TestResultPassed { + /** + * The test passed successfully. + */ + state: 'passed' + /** + * Errors that were thrown during the test execution. + * + * **Note**: If test was retried successfully, errors will still be reported. + */ + errors: TestError[] | undefined +} + +export interface TestResultFailed { + /** + * The test failed to execute. + */ + state: 'failed' + /** + * Errors that were thrown during the test execution. + */ + errors: TestError[] +} + +export interface TestResultSkipped { + /** + * The test was skipped with `only`, `skip` or `todo` flag. + * You can see which one was used in the `mode` option. + */ + state: 'skipped' + /** + * Skipped tests have no errors. + */ + errors: undefined +} + +export interface TestDiagnostic { + /** + * The amount of memory used by the test in bytes. + * This value is only available if the test was executed with `logHeapUsage` flag. + */ + heap: number | undefined + /** + * The time it takes to execute the test in ms. + */ + duration: number + /** + * The time in ms when the test started. + */ + startTime: number + /** + * The amount of times the test was retried. + */ + retryCount: number + /** + * The amount of times the test was repeated as configured by `repeats` option. + * This value can be lower if the test failed during the repeat and no `retry` is configured. + */ + repeatCount: number + /** + * If test passed on a second retry. + */ + flaky: boolean +} +``` + +### TestSuite + +`TestSuite` represents a single suite that contains tests and other suites. + +```ts +declare class TestSuite { + readonly type = 'suite' + /** + * Task instance. + * @experimental Public task API is experimental and does not follow semver. + */ + readonly task: RunnerTestSuite + /** + * The project associated with the test. + */ + readonly project: TestProject + /** + * Direct reference to the test file where the suite is defined. + */ + readonly file: TestFile + /** + * Name of the suite. + */ + readonly name: string + /** + * Full name of the suite including all parent suites separated with `>`. + */ + readonly fullName: string + /** + * Unique identifier. + * This ID is deterministic and will be the same for the same test across multiple runs. + * The ID is based on the project name, file path and test position. + */ + readonly id: string + /** + * Location in the file where the suite was defined. + * Locations are collected only if `includeTaskLocation` is enabled in the config. + */ + readonly location: { line: number; column: number } | undefined + /** + * Collection of suites and tests that are part of this suite. + */ + readonly children: TaskCollection + /** + * Options that the suite was initiated with. + */ + readonly options: TaskOptions +} +``` + +### TestFile + +`TestFile` represents a single file that contains suites and tests. + +```ts +declare class TestFile extends SuiteImplementation { + readonly type = 'file' + /** + * Task instance. + * @experimental Public task API is experimental and does not follow semver. + */ + readonly task: RunnerTestFile + /** + * Collection of suites and tests that are part of this file. + */ + readonly children: TestCollection + /** + * This is usually an absolute Unix file path. + * It can be a virtual id if the file is not on the disk. + * This value corresponds to Vite's `ModuleGraph` id. + */ + readonly moduleId: string + /** + * Useful information about the file like duration, memory usage, etc. + * If the file was not executed yet, all diagnostic values will return `0`. + */ + diagnostic(): FileDiagnostic +} + +export interface FileDiagnostic { + /** + * The time it takes to import and initiate an environment. + */ + environmentSetupDuration: number + /** + * The time it takes Vitest to setup test harness (runner, mocks, etc.). + */ + prepareDuration: number + /** + * The time it takes to import the test file. + * This includes importing everything in the file and executing suite callbacks. + */ + collectDuration: number + /** + * The time it takes to import the setup file. + */ + setupDuration: number + /** + * Accumulated duration of all tests and hooks in the file. + */ + duration: number +} +``` + +### TestCollection + +`TestCollection` represents a collection of suites and tests. It also provides useful methods to iterate over itself. + +```ts +declare class TestCollection { + /** + * Returns the test or suite at a specific index in the array. + */ + at(index: number): TestCase | TestSuite | undefined + /** + * The number of tests and suites in the collection. + */ + size: number + /** + * Returns the collection in array form for easier manipulation. + */ + array(): (TestCase | TestSuite)[] + /** + * Filters all suites that are part of this collection and its children. + */ + allSuites(): IterableIterator + /** + * Filters all tests that are part of this collection and its children. + */ + allTests(state?: TestResult['state'] | 'running'): IterableIterator + /** + * Filters only the tests that are part of this collection. + */ + tests(state?: TestResult['state'] | 'running'): IterableIterator + /** + * Filters only the suites that are part of this collection. + */ + suites(): IterableIterator; + [Symbol.iterator](): IterableIterator +} +``` + +For example, you can iterate over all tests inside a file by calling `testFile.children.allTests()`: + +```ts +function onFileCollected(testFile: TestFile): void { + console.log('collecting tests in', testFile.moduleId) + + // iterate over all tests and suites in the file + for (const task of testFile.children.allTests()) { + console.log('collected', task.type, task.fullName) + } +} +``` + +### TestProject + +`TestProject` is a project assosiated with the file. Every test and suite inside that file will reference the same project. + +Project is useful to get the configuration or provided context. + +```ts +declare class TestProject { + /** + * The global vitest instance. + * @experimental The public Vitest API is experimental and does not follow semver. + */ + readonly vitest: Vitest + /** + * The workspace project this test project is associated with. + * @experimental The public Vitest API is experimental and does not follow semver. + */ + readonly workspaceProject: WorkspaceProject + /** + * Resolved project configuration. + */ + readonly config: ResolvedProjectConfig + /** + * Resolved global configuration. If there are no workspace projects, this will be the same as `config`. + */ + readonly globalConfig: ResolvedConfig + /** + * Serialized project configuration. This is the config that tests receive. + */ + get serializedConfig(): SerializedConfig + /** + * The name of the project or an empty string if not set. + */ + name(): string + /** + * Custom context provided to the project. + */ + context(): ProvidedContext + /** + * Provide a custom serializable context to the project. This context will be available for tests once they run. + */ + provide(key: T, value: ProvidedContext[T]): void +} +``` + ## Exported Reporters `vitest` comes with a few [built-in reporters](/guide/reporters) that you can use out of the box. diff --git a/docs/advanced/runner.md b/docs/advanced/runner.md index 7b724b2173b1..da8bf1a99d1e 100644 --- a/docs/advanced/runner.md +++ b/docs/advanced/runner.md @@ -110,7 +110,7 @@ Snapshot support and some other features depend on the runner. If you don't want You can extend Vitest task system with your tasks. A task is an object that is part of a suite. It is automatically added to the current suite with a `suite.task` method: -```js twoslash +```js // ./utils/custom.js import { createTaskCollector, getCurrentSuite, setFn } from 'vitest/suite' @@ -134,7 +134,7 @@ export const myCustomTask = createTaskCollector( ) ``` -```js twoslash +```js // ./garden/tasks.test.js import { afterAll, beforeAll, describe, myCustomTask } from '../custom.js' import { gardener } from './gardener.js' diff --git a/docs/api/expect-typeof.md b/docs/api/expect-typeof.md index 4857acd57438..d3fce9ce7d7e 100644 --- a/docs/api/expect-typeof.md +++ b/docs/api/expect-typeof.md @@ -18,7 +18,7 @@ You can negate all assertions, using `.not` property. This matcher will check if the types are fully equal to each other. This matcher will not fail if two objects have different values, but the same type. It will fail however if an object is missing a property. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() @@ -33,13 +33,13 @@ expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() This matcher checks if expect type extends provided type. It is different from `toEqual` and is more similar to [expect's](/api/expect) `toMatchObject()`. With this matcher, you can check if an object “matches” a type. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 1 }) expectTypeOf().toMatchTypeOf() expectTypeOf().not.toMatchTypeOf() - ``` +``` ## extract @@ -47,7 +47,7 @@ expectTypeOf().not.toMatchTypeOf() You can use `.extract` to narrow down types for further testing. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } @@ -79,7 +79,7 @@ If no type is found in the union, `.extract` will return `never`. You can use `.exclude` to remove types from a union for further testing. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } @@ -108,7 +108,7 @@ If no type is found in the union, `.exclude` will return `never`. You can use `.returns` to extract return value of a function type. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(() => {}).returns.toBeVoid() @@ -125,7 +125,7 @@ If used on a non-function type, it will return `never`, so you won't be able to You can extract function arguments with `.parameters` to perform assertions on its value. Parameters are returned as an array. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' type NoParam = () => void @@ -149,7 +149,7 @@ You can also use [`.toBeCallableWith`](#tobecallablewith) matcher as a more expr You can extract a certain function argument with `.parameter(number)` call to perform other assertions on it. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' function foo(a: number, b: string) { @@ -170,7 +170,7 @@ If used on a non-function type, it will return `never`, so you won't be able to You can extract constructor parameters as an array of values and perform assertions on them with this method. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).constructorParameters.toEqualTypeOf<[] | [string | number | Date]>() @@ -190,7 +190,7 @@ You can also use [`.toBeConstructibleWith`](#tobeconstructiblewith) matcher as a This property gives access to matchers that can be performed on an instance of the provided class. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).instance.toHaveProperty('toISOString') @@ -206,7 +206,7 @@ If used on a non-function type, it will return `never`, so you won't be able to You can get array item type with `.items` to perform further assertions. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf([1, 2, 3]).items.toEqualTypeOf() @@ -219,7 +219,7 @@ expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf() This matcher extracts resolved value of a `Promise`, so you can perform other assertions on it. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' async function asyncFunc() { @@ -240,7 +240,7 @@ If used on a non-promise type, it will return `never`, so you won't be able to c This matcher extracts guard value (e.g., `v is number`), so you can perform assertions on it. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' function isString(v: any): v is string { @@ -259,7 +259,7 @@ Returns `never`, if the value is not a guard function, so you won't be able to c This matcher extracts assert value (e.g., `assert v is number`), so you can perform assertions on it. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' function assertNumber(v: any): asserts v is number { @@ -281,7 +281,7 @@ Returns `never`, if the value is not an assert function, so you won't be able to With this matcher you can check, if provided type is `any` type. If the type is too specific, the test will fail. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeAny() @@ -295,7 +295,7 @@ expectTypeOf('string').not.toBeAny() This matcher checks, if provided type is `unknown` type. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf().toBeUnknown() @@ -335,7 +335,7 @@ expectTypeOf((): never => {}).toBeFunction() This matcher checks, if provided type is an `object`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeObject() @@ -348,7 +348,7 @@ expectTypeOf({}).toBeObject() This matcher checks, if provided type is `Array`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeArray() @@ -363,7 +363,7 @@ expectTypeOf([{}, 42]).toBeArray() This matcher checks, if provided type is a `string`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeString() @@ -377,7 +377,7 @@ expectTypeOf('a').toBeString() This matcher checks, if provided type is `boolean`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(42).not.toBeBoolean() @@ -391,7 +391,7 @@ expectTypeOf().toBeBoolean() This matcher checks, if provided type is `void`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(() => {}).returns.toBeVoid() @@ -404,7 +404,7 @@ expectTypeOf().toBeVoid() This matcher checks, if provided type is a `symbol`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(Symbol(1)).toBeSymbol() @@ -417,7 +417,7 @@ expectTypeOf().toBeSymbol() This matcher checks, if provided type is `null`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(null).toBeNull() @@ -431,7 +431,7 @@ expectTypeOf(undefined).not.toBeNull() This matcher checks, if provided type is `undefined`. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(undefined).toBeUndefined() @@ -445,12 +445,12 @@ expectTypeOf(null).not.toBeUndefined() This matcher checks, if you can use `null` or `undefined` with provided type. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' -expectTypeOf<1 | undefined>().toBeNullable() -expectTypeOf<1 | null>().toBeNullable() -expectTypeOf<1 | undefined | null>().toBeNullable() +expectTypeOf().toBeNullable() +expectTypeOf().toBeNullable() +expectTypeOf().toBeNullable() ``` ## toBeCallableWith @@ -459,7 +459,7 @@ expectTypeOf<1 | undefined | null>().toBeNullable() This matcher ensures you can call provided function with a set of parameters. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' type NoParam = () => void @@ -479,7 +479,7 @@ If used on a non-function type, it will return `never`, so you won't be able to This matcher ensures you can create a new instance with a set of constructor parameters. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' expectTypeOf(Date).toBeConstructibleWith(new Date()) @@ -496,7 +496,7 @@ If used on a non-function type, it will return `never`, so you won't be able to This matcher checks if a property exists on the provided object. If it exists, it also returns the same set of matchers for the type of this property, so you can chain assertions one after another. -```ts twoslash +```ts import { expectTypeOf } from 'vitest' const obj = { a: 1, b: '' } diff --git a/docs/api/expect.md b/docs/api/expect.md index d61b99d8a452..caa88491d735 100644 --- a/docs/api/expect.md +++ b/docs/api/expect.md @@ -33,19 +33,19 @@ Also, `expect` can be used statically to access matcher functions, described lat `expect.soft` functions similarly to `expect`, but instead of terminating the test execution upon a failed assertion, it continues running and marks the failure as a test failure. All errors encountered during the test will be displayed until the test is completed. -```ts twoslash +```ts import { expect, test } from 'vitest' test('expect.soft test', () => { expect.soft(1 + 1).toBe(3) // mark the test as fail and continue expect.soft(1 + 2).toBe(4) // mark the test as fail and continue }) -// At the end of the test, the above errors will be output. +// reporter will report both errors at the end of the run ``` It can also be used with `expect`. if `expect` assertion fails, the test will be terminated and all errors will be displayed. -```ts twoslash +```ts import { expect, test } from 'vitest' test('expect.soft test', () => { @@ -67,12 +67,7 @@ test('expect.soft test', () => { If an error is thrown inside the `expect.poll` callback, Vitest will retry again until the timeout runs out. -```ts twoslash -function asyncInjectElement() { - // example function -} - -// ---cut--- +```ts import { expect, test } from 'vitest' test('element exists', async () => { @@ -104,7 +99,7 @@ expect(flakyValue).toMatchSnapshot() Using `not` will negate the assertion. For example, this code asserts that an `input` value is not equal to `2`. If it's equal, the assertion will throw an error, and the test will fail. -```ts twoslash +```ts import { expect, test } from 'vitest' const input = Math.sqrt(16) @@ -121,7 +116,7 @@ expect(input).not.toBe(2) // jest API For example, the code below checks if the trader has 13 apples. -```ts twoslash +```ts import { expect, test } from 'vitest' const stock = { @@ -149,7 +144,7 @@ Try not to use `toBe` with floating-point numbers. Since JavaScript rounds them, Use `toBeCloseTo` to compare floating-point numbers. The optional `numDigits` argument limits the number of digits to check _after_ the decimal point. For example: -```ts twoslash +```ts import { expect, test } from 'vitest' test.fails('decimals are not equal in javascript', () => { @@ -170,7 +165,7 @@ test('decimals are rounded to 5 after the point', () => { `toBeDefined` asserts that the value is not equal to `undefined`. Useful use case would be to check if function _returned_ anything. -```ts twoslash +```ts import { expect, test } from 'vitest' function getApples() { @@ -188,7 +183,7 @@ test('function returned something', () => { Opposite of `toBeDefined`, `toBeUndefined` asserts that the value _is_ equal to `undefined`. Useful use case would be to check if function hasn't _returned_ anything. -```ts twoslash +```ts import { expect, test } from 'vitest' function getApplesFromStock(stock: string) { @@ -276,7 +271,7 @@ Everything in JavaScript is truthy, except `false`, `null`, `undefined`, `NaN`, `toBeNull` simply asserts if something is `null`. Alias for `.toBe(null)`. -```ts twoslash +```ts import { expect, test } from 'vitest' function apples() { @@ -294,7 +289,7 @@ test('we don\'t have apples', () => { `toBeNaN` simply asserts if something is `NaN`. Alias for `.toBe(NaN)`. -```ts twoslash +```ts import { expect, test } from 'vitest' let i = 0 @@ -316,7 +311,7 @@ test('getApplesCount has some unusual side effects...', () => { `toBeTypeOf` asserts if an actual value is of type of received type. -```ts twoslash +```ts import { expect, test } from 'vitest' const actual = 'stock' @@ -409,7 +404,7 @@ test('have 11 apples or less', () => { `toEqual` asserts if actual value is equal to received one or has the same structure, if it is an object (compares them recursively). You can see the difference between `toEqual` and [`toBe`](#tobe) in this example: -```ts twoslash +```ts import { expect, test } from 'vitest' const stockBill = { @@ -505,7 +500,7 @@ test('apple available', () => { `toHaveLength` asserts if an object has a `.length` property and it is set to a certain numeric value. -```ts twoslash +```ts import { expect, test } from 'vitest' test('toHaveLength', () => { @@ -525,7 +520,7 @@ test('toHaveLength', () => { You can provide an optional value argument also known as deep equality, like the `toEqual` matcher to compare the received property value. -```ts twoslash +```ts import { expect, test } from 'vitest' const invoice = { @@ -579,7 +574,7 @@ test('John Doe Invoice', () => { `toMatch` asserts if a string matches a regular expression or a string. -```ts twoslash +```ts import { expect, test } from 'vitest' test('top fruits', () => { @@ -596,7 +591,7 @@ test('top fruits', () => { You can also pass an array of objects. This is useful if you want to check that two arrays match in their number of elements, as opposed to `arrayContaining`, which allows for extra elements in the received array. -```ts twoslash +```ts import { expect, test } from 'vitest' const johnInvoice = { @@ -659,7 +654,7 @@ You must wrap the code in a function, otherwise the error will not be caught, an For example, if we want to test that `getFruitStock('pineapples')` throws, we could write: -```ts twoslash +```ts import { expect, test } from 'vitest' function getFruitStock(type: string) { @@ -685,7 +680,7 @@ test('throws on pineapples', () => { :::tip To test async functions, use in combination with [rejects](#rejects). -```js twoslash +```js function getAsyncFruitStock() { return Promise.reject(new Error('empty')) } @@ -708,7 +703,7 @@ You can provide an optional `hint` string argument that is appended to the test When snapshot mismatch and causing the test failing, if the mismatch is expected, you can press `u` key to update the snapshot for once. Or you can pass `-u` or `--update` CLI options to make Vitest always update the tests. ::: -```ts twoslash +```ts import { expect, test } from 'vitest' test('matches snapshot', () => { @@ -719,7 +714,7 @@ test('matches snapshot', () => { You can also provide a shape of an object, if you are testing just a shape of an object, and don't need it to be 100% compatible: -```ts twoslash +```ts import { expect, test } from 'vitest' test('matches snapshot', () => { @@ -736,7 +731,7 @@ This ensures that a value matches the most recent snapshot. Vitest adds and updates the inlineSnapshot string argument to the matcher in the test file (instead of an external `.snap` file). -```ts twoslash +```ts import { expect, test } from 'vitest' test('matches inline snapshot', () => { @@ -755,7 +750,7 @@ test('matches inline snapshot', () => { You can also provide a shape of an object, if you are testing just a shape of an object, and don't need it to be 100% compatible: -```ts twoslash +```ts import { expect, test } from 'vitest' test('matches snapshot', () => { @@ -806,7 +801,7 @@ The same as [`toMatchInlineSnapshot`](#tomatchinlinesnapshot), but expects the s This assertion is useful for testing that a function has been called. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' const market = { @@ -832,7 +827,7 @@ test('spy function', () => { This assertion checks if a function was called a certain amount of times. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' const market = { @@ -857,7 +852,7 @@ test('spy function called two times', () => { This assertion checks if a function was called at least once with certain parameters. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' const market = { @@ -883,7 +878,7 @@ test('spy function', () => { This assertion checks if a function was called with certain parameters at its last invocation. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' const market = { @@ -911,7 +906,7 @@ This assertion checks if a function was called with certain parameters at the ce Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' const market = { @@ -936,7 +931,7 @@ test('first call of spy function called with right params', () => { This assertion checks if a function has successfully returned a value at least once (i.e., did not throw an error). Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' function getApplesPrice(amount: number) { @@ -960,7 +955,7 @@ test('spy function returned a value', () => { This assertion checks if a function has successfully returned a value an exact amount of times (i.e., did not throw an error). Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function returns a value two times', () => { @@ -979,7 +974,7 @@ test('spy function returns a value two times', () => { You can call this assertion to check if a function has successfully returned a value with certain parameters at least once. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function returns a product', () => { @@ -997,7 +992,7 @@ test('spy function returns a product', () => { You can call this assertion to check if a function has successfully returned a certain value when it was last invoked. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function returns bananas on a last call', () => { @@ -1016,7 +1011,7 @@ test('spy function returns bananas on a last call', () => { You can call this assertion to check if a function has successfully returned a value with certain parameters on a certain call. Requires a spy function to be passed to `expect`. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function returns bananas on second call', () => { @@ -1037,13 +1032,7 @@ This assertion checks if a function has successfully resolved a value at least o If the function returned a promise, but it was not resolved yet, this will fail. -```ts twoslash -// @filename: db/apples.js -/** @type {any} */ -const db = {} -export default db -// @filename: test.ts -// ---cut--- +```ts import { expect, test, vi } from 'vitest' import db from './db/apples.js' @@ -1069,7 +1058,7 @@ This assertion checks if a function has successfully resolved a value an exact a This will only count resolved promises. If the function returned a promise, but it was not resolved yet, it will not be counted. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function resolved a value two times', async () => { @@ -1090,7 +1079,7 @@ You can call this assertion to check if a function has successfully resolved a c If the function returned a promise, but it was not resolved yet, this will fail. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function resolved a product', async () => { @@ -1110,7 +1099,7 @@ You can call this assertion to check if a function has successfully resolved a c If the function returned a promise, but it was not resolved yet, this will fail. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function resolves bananas on a last call', async () => { @@ -1131,7 +1120,7 @@ You can call this assertion to check if a function has successfully resolved a c If the function returned a promise, but it was not resolved yet, this will fail. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('spy function returns bananas on second call', async () => { @@ -1150,7 +1139,7 @@ test('spy function returns bananas on second call', async () => { This assertion checks if a value satisfies a certain predicate. -```ts twoslash +```ts import { describe, expect, it } from 'vitest' describe('toSatisfy()', () => { const isOdd = (value: number) => value % 2 !== 0 @@ -1395,7 +1384,7 @@ test('compare float in object properties', () => { When used with an equality check, this asymmetric matcher will return `true` if the value is an array and contains specified items. -```ts twoslash +```ts import { expect, test } from 'vitest' test('basket includes fuji', () => { @@ -1424,7 +1413,7 @@ You can use `expect.not` with this matcher to negate the expected value. When used with an equality check, this asymmetric matcher will return `true` if the value has a similar shape. -```ts twoslash +```ts import { expect, test } from 'vitest' test('basket has empire apples', () => { @@ -1454,7 +1443,7 @@ You can use `expect.not` with this matcher to negate the expected value. When used with an equality check, this asymmetric matcher will return `true` if the value is a string and contains a specified substring. -```ts twoslash +```ts import { expect, test } from 'vitest' test('variety has "Emp" in its name', () => { @@ -1479,7 +1468,7 @@ You can use `expect.not` with this matcher to negate the expected value. When used with an equality check, this asymmetric matcher will return `true` if the value is a string and contains a specified substring or if the string matches a regular expression. -```ts twoslash +```ts import { expect, test } from 'vitest' test('variety ends with "re"', () => { @@ -1571,7 +1560,7 @@ If you want to know more, checkout [guide on extending matchers](/guide/extendin You can use this method to define custom testers, which are methods used by matchers, to test if two objects are equal. It is compatible with Jest's `expect.addEqualityTesters`. -```ts twoslash +```ts import { expect, test } from 'vitest' class AnagramComparator { diff --git a/docs/api/index.md b/docs/api/index.md index 7af5f6c7d36b..3a9b89debaa3 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -50,14 +50,14 @@ In Jest, `TestFunction` can also be of type `(done: DoneCallback) => void`. If t Most options support both dot-syntax and object-syntax allowing you to use whatever style you prefer. :::code-group -```ts [dot-syntax] twoslash +```ts [dot-syntax] import { test } from 'vitest' test.skip('skipped test', () => { // some logic that fails right now }) ``` -```ts [object-syntax] twoslash +```ts [object-syntax] import { test } from 'vitest' test('skipped test', { skip: true }, () => { @@ -74,7 +74,7 @@ test('skipped test', { skip: true }, () => { Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds, and can be configured globally with [testTimeout](/config/#testtimeout) -```ts twoslash +```ts import { expect, test } from 'vitest' test('should work as expected', () => { @@ -117,7 +117,7 @@ myTest('add item', ({ todos }) => { If you want to skip running certain tests, but you don't want to delete the code due to any reason, you can use `test.skip` to avoid running them. -```ts twoslash +```ts import { assert, test } from 'vitest' test.skip('skipped test', () => { @@ -128,7 +128,7 @@ test.skip('skipped test', () => { You can also skip test by calling `skip` on its [context](/guide/test-context) dynamically: -```ts twoslash +```ts import { assert, test } from 'vitest' test('skipped test', (context) => { @@ -144,7 +144,7 @@ test('skipped test', (context) => { In some cases you might run tests multiple times with different environments, and some of the tests might be environment-specific. Instead of wrapping the test code with `if`, you can use `test.skipIf` to skip the test whenever the condition is truthy. -```ts twoslash +```ts import { assert, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' @@ -164,7 +164,7 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t Opposite of [test.skipIf](#test-skipif). -```ts twoslash +```ts import { assert, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' @@ -186,7 +186,7 @@ Use `test.only` to only run certain tests in a given suite. This is useful when Optionally, you can provide a timeout (in milliseconds) for specifying how long to wait before terminating. The default is 5 seconds, and can be configured globally with [testTimeout](/config/#testtimeout). -```ts twoslash +```ts import { assert, test } from 'vitest' test.only('test', () => { @@ -208,7 +208,7 @@ In order to do that run `vitest` with specific file containing the tests in ques `test.concurrent` marks consecutive tests to be run in parallel. It receives the test name, an async function with the tests to collect, and an optional timeout (in milliseconds). -```ts twoslash +```ts import { describe, test } from 'vitest' // The two tests marked with concurrent will be run in parallel @@ -249,10 +249,9 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t `test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. -```ts twoslash +```ts import { describe, test } from 'vitest' -// ---cut--- // with config option { sequence: { concurrent: true } } test('concurrent test 1', async () => { /* ... */ }) test('concurrent test 2', async () => { /* ... */ }) @@ -287,7 +286,7 @@ test.todo('unimplemented test') Use `test.fails` to indicate that an assertion will fail explicitly. -```ts twoslash +```ts import { expect, test } from 'vitest' function myAsyncFunc() { @@ -323,10 +322,9 @@ You can inject parameters with [printf formatting](https://nodejs.org/api/util.h - `%#`: index of the test case - `%%`: single percent sign ('%') -```ts twoslash +```ts import { expect, test } from 'vitest' -// ---cut--- test.each([ [1, 1, 2], [1, 2, 3], @@ -381,10 +379,9 @@ Starting from Vitest 0.25.3, you can also use template string table. * First row should be column names, separated by `|`; * One or more subsequent rows of data supplied as template literal expressions using `${value}` syntax. -```ts twoslash +```ts import { expect, test } from 'vitest' -// ---cut--- test.each` a | b | expected ${1} | ${1} | ${2} @@ -454,7 +451,7 @@ test.concurrent.for([ Vitest uses [`tinybench`](https://github.com/tinylibs/tinybench) library under the hood, inheriting all its options that can be used as a third argument. -```ts twoslash +```ts import { bench } from 'vitest' bench('normal sorting', () => { @@ -519,7 +516,7 @@ export interface Options { You can use `bench.skip` syntax to skip running certain benchmarks. -```ts twoslash +```ts import { bench } from 'vitest' bench.skip('normal sorting', () => { @@ -536,7 +533,7 @@ bench.skip('normal sorting', () => { Use `bench.only` to only run certain benchmarks in a given suite. This is useful when debugging. -```ts twoslash +```ts import { bench } from 'vitest' bench.only('normal sorting', () => { @@ -553,7 +550,7 @@ bench.only('normal sorting', () => { Use `bench.todo` to stub benchmarks to be implemented later. -```ts twoslash +```ts import { bench } from 'vitest' bench.todo('unimplemented test') @@ -563,7 +560,7 @@ bench.todo('unimplemented test') When you use `test` or `bench` in the top level of file, they are collected as part of the implicit suite for it. Using `describe` you can define a new suite in the current context, as a set of related tests or benchmarks and other nested suites. A suite lets you organize your tests and benchmarks so reports are more clear. -```ts twoslash +```ts // basic.spec.ts // organizing tests @@ -589,7 +586,7 @@ describe('person', () => { }) ``` -```ts twoslash +```ts // basic.bench.ts // organizing benchmarks @@ -614,7 +611,7 @@ describe('sort', () => { You can also nest describe blocks if you have a hierarchy of tests or benchmarks: -```ts twoslash +```ts import { describe, expect, test } from 'vitest' function numberToCurrency(value: number | string) { @@ -646,7 +643,7 @@ describe('numberToCurrency', () => { Use `describe.skip` in a suite to avoid running a particular describe block. -```ts twoslash +```ts import { assert, describe, test } from 'vitest' describe.skip('skipped suite', () => { @@ -663,7 +660,7 @@ describe.skip('skipped suite', () => { In some cases, you might run suites multiple times with different environments, and some of the suites might be environment-specific. Instead of wrapping the suite with `if`, you can use `describe.skipIf` to skip the suite whenever the condition is truthy. -```ts twoslash +```ts import { describe, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' @@ -683,7 +680,7 @@ You cannot use this syntax when using Vitest as [type checker](/guide/testing-ty Opposite of [describe.skipIf](#describe-skipif). -```ts twoslash +```ts import { assert, describe, test } from 'vitest' const isDev = process.env.NODE_ENV === 'development' @@ -703,9 +700,9 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t Use `describe.only` to only run certain suites -```ts twoslash +```ts import { assert, describe, test } from 'vitest' -// ---cut--- + // Only this suite (and others marked with only) are run describe.only('suite', () => { test('sqrt', () => { @@ -731,9 +728,9 @@ In order to do that run `vitest` with specific file containing the tests in ques `describe.concurrent` runs all inner suites and tests in parallel -```ts twoslash +```ts import { describe, test } from 'vitest' -// ---cut--- + // All suites and tests within this suite will be run in parallel describe.concurrent('suite', () => { test('concurrent test 1', async () => { /* ... */ }) @@ -777,9 +774,9 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t `describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. -```ts twoslash +```ts import { describe, test } from 'vitest' -// ---cut--- + describe.concurrent('suite', () => { test('concurrent test 1', async () => { /* ... */ }) test('concurrent test 2', async () => { /* ... */ }) @@ -797,9 +794,9 @@ describe.concurrent('suite', () => { Vitest provides a way to run all tests in random order via CLI flag [`--sequence.shuffle`](/guide/cli) or config option [`sequence.shuffle`](/config/#sequence-shuffle), but if you want to have only part of your test suite to run tests in random order, you can mark it with this flag. -```ts twoslash +```ts import { describe, test } from 'vitest' -// ---cut--- + describe.shuffle('suite', () => { test('random test 1', async () => { /* ... */ }) test('random test 2', async () => { /* ... */ }) @@ -831,9 +828,9 @@ describe.todo('unimplemented suite') Use `describe.each` if you have more than one test that depends on the same data. -```ts twoslash +```ts import { describe, expect, test } from 'vitest' -// ---cut--- + describe.each([ { a: 1, b: 1, expected: 2 }, { a: 1, b: 2, expected: 3 }, @@ -858,9 +855,9 @@ Starting from Vitest 0.25.3, you can also use template string table. * First row should be column names, separated by `|`; * One or more subsequent rows of data supplied as template literal expressions using `${value}` syntax. -```ts twoslash +```ts import { describe, expect, test } from 'vitest' -// ---cut--- + describe.each` a | b | expected ${1} | ${1} | ${2} diff --git a/docs/api/mock.md b/docs/api/mock.md index 4addb63fcf3c..17843f0d6db2 100644 --- a/docs/api/mock.md +++ b/docs/api/mock.md @@ -56,9 +56,7 @@ Sets internal mock name. Useful to see the name of the mock if assertion fails. Accepts a function that will be used as an implementation of the mock. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1) // or: vi.fn(apples => apples + 1); @@ -78,9 +76,7 @@ mockFn.mock.calls[1][0] === 1 // true Accepts a function that will be used as mock's implementation during the next call. Can be chained so that multiple function calls produce different results. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const myMockFn = vi .fn() .mockImplementationOnce(() => true) @@ -92,9 +88,7 @@ myMockFn() // false When the mocked function runs out of implementations, it will invoke the default implementation that was set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called: -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const myMockFn = vi .fn(() => 'default') .mockImplementationOnce(() => 'first call') @@ -111,9 +105,7 @@ console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()) Overrides the original mock implementation temporarily while the callback is being executed. -```js twoslash -import { vi } from 'vitest' -// ---cut--- +```js const myMockFn = vi.fn(() => 'original') myMockFn.withImplementation(() => 'temp', () => { @@ -149,9 +141,7 @@ Note that this method takes precedence over the [`mockImplementationOnce`](#mock Accepts an error that will be rejected when async function is called. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const asyncMock = vi.fn().mockRejectedValue(new Error('Async error')) await asyncMock() // throws "Async error" @@ -163,9 +153,7 @@ await asyncMock() // throws "Async error" Accepts a value that will be rejected during the next function call. If chained, every consecutive call will reject specified value. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const asyncMock = vi .fn() .mockResolvedValueOnce('first call') @@ -199,9 +187,7 @@ If you want this method to be called before each test automatically, you can ena Accepts a value that will be resolved when async function is called. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const asyncMock = vi.fn().mockResolvedValue(42) await asyncMock() // 42 @@ -213,9 +199,7 @@ await asyncMock() // 42 Accepts a value that will be resolved during the next function call. If chained, every consecutive call will resolve specified value. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const asyncMock = vi .fn() .mockResolvedValue('default') @@ -246,9 +230,7 @@ spy.mockImplementation(function () { Accepts a value that will be returned whenever the mock function is called. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const mock = vi.fn() mock.mockReturnValue(42) mock() // 42 @@ -264,9 +246,7 @@ Accepts a value that will be returned during the next function call. If chained, When there are no more `mockReturnValueOnce` values to use, mock will fallback to previously defined implementation if there is one. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts const myMockFn = vi .fn() .mockReturnValue('default') diff --git a/docs/api/vi.md b/docs/api/vi.md index 4f2d967b11b9..47a94b99daa5 100644 --- a/docs/api/vi.md +++ b/docs/api/vi.md @@ -31,45 +31,21 @@ Vitest will not mock modules that were imported inside a [setup file](/config/#s If `factory` is defined, all imports will return its result. Vitest calls factory only once and caches results for all subsequent imports until [`vi.unmock`](#vi-unmock) or [`vi.doUnmock`](#vi-dounmock) is called. -Unlike in `jest`, the factory can be asynchronous. You can use [`vi.importActual`](#vi-importactual) or a helper with the factory passed in as the first argument, and get the original module inside. +Unlike in `jest`, the factory can be asynchronous. You can use [`vi.importActual`](#vi-importactual) or a helper with the factory passed in as the first argument, and get the original module inside. Vitest also supports a module promise instead of a string in `vi.mock` method for better IDE support (when file is moved, path will be updated, `importOriginal` also inherits the type automatically). -```js twoslash +```ts twoslash +// @filename: ./path/to/module.js +export declare function total(...numbers: number[]): number +// @filename: test.js import { vi } from 'vitest' // ---cut--- -// when using JavaScript - -vi.mock('./path/to/module.js', async (importOriginal) => { - const mod = await importOriginal() - return { - ...mod, - // replace some exports - namedExport: vi.fn(), - } -}) -``` - -```ts -// when using TypeScript - -vi.mock('./path/to/module.js', async (importOriginal) => { - const mod = await importOriginal() - return { - ...mod, - // replace some exports - namedExport: vi.fn(), - } -}) -``` - -Vitest supports a module promise instead of a string in `vi.mock` method for better IDE support (when file is moved, path will be updated, `importOriginal` also inherits the type automatically). - -```ts vi.mock(import('./path/to/module.js'), async (importOriginal) => { const mod = await importOriginal() // type is inferred + // ^? return { ...mod, // replace some exports - namedExport: vi.fn(), + total: vi.fn(), } }) ``` @@ -363,9 +339,7 @@ This section describes how to work with [method mocks](/api/mock) and replace en Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](/api/mock). If no function is given, mock will return `undefined`, when invoked. -```ts twoslash -import { expect, vi } from 'vitest' -// ---cut--- +```ts const getApples = vi.fn(() => 0) getApples() @@ -404,9 +378,7 @@ Will call [`.mockRestore()`](/api/mock#mockrestore) on all spies. This will clea Creates a spy on a method or getter/setter of an object similar to [`vi.fn()`](#vi-fn). It returns a [mock function](/api/mock). -```ts twoslash -import { expect, vi } from 'vitest' -// ---cut--- +```ts let apples = 0 const cart = { getApples: () => 42, @@ -502,7 +474,7 @@ import.meta.env.NODE_ENV === 'development' Changes the value of global variable. You can restore its original value by calling `vi.unstubAllGlobals`. -```ts twoslash +```ts import { vi } from 'vitest' // `innerWidth` is "0" before calling stubGlobal @@ -564,9 +536,7 @@ This sections descibes how to work with [fake timers](/guide/mocking#timers). This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts let i = 0 setInterval(() => console.log(++i), 50) @@ -583,9 +553,7 @@ vi.advanceTimersByTime(150) This method will invoke every initiated timer until the specified number of milliseconds is passed or the queue is empty - whatever comes first. This will include asynchronously set timers. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts let i = 0 setInterval(() => Promise.resolve().then(() => console.log(++i)), 50) @@ -602,9 +570,7 @@ await vi.advanceTimersByTimeAsync(150) Will call next available timer. Useful to make assertions between each timer call. You can chain call it to manage timers by yourself. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts let i = 0 setInterval(() => console.log(++i), 50) @@ -619,9 +585,7 @@ vi.advanceTimersToNextTimer() // log: 1 Will call next available timer and wait until it's resolved if it was set asynchronously. Useful to make assertions between each timer call. -```ts twoslash -import { expect, vi } from 'vitest' -// ---cut--- +```ts let i = 0 setInterval(() => Promise.resolve().then(() => console.log(++i)), 50) @@ -666,9 +630,7 @@ Calls every microtask that was queued by `process.nextTick`. This will also run This method will invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimers` will be fired. If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](/config/#faketimers-looplimit)). -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts let i = 0 setTimeout(() => console.log(++i)) const interval = setInterval(() => { @@ -692,9 +654,7 @@ vi.runAllTimers() This method will asynchronously invoke every initiated timer until the timer queue is empty. It means that every timer called during `runAllTimersAsync` will be fired even asynchronous timers. If you have an infinite interval, it will throw after 10 000 tries (can be configured with [`fakeTimers.loopLimit`](/config/#faketimers-looplimit)). -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts setTimeout(async () => { console.log(await Promise.resolve('result')) }, 100) @@ -710,9 +670,7 @@ await vi.runAllTimersAsync() This method will call every timer that was initiated after [`vi.useFakeTimers`](#vi-usefaketimers) call. It will not fire any timer that was initiated during its call. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts let i = 0 setInterval(() => console.log(++i), 50) @@ -727,9 +685,7 @@ vi.runOnlyPendingTimers() This method will asynchronously call every timer that was initiated after [`vi.useFakeTimers`](#vi-usefaketimers) call, even asynchronous ones. It will not fire any timer that was initiated during its call. -```ts twoslash -import { vi } from 'vitest' -// ---cut--- +```ts setTimeout(() => { console.log(1) }, 100) @@ -758,9 +714,7 @@ If fake timers are enabled, this method simulates a user changing the system clo Useful if you need to test anything that depends on the current date - for example [Luxon](https://github.com/moment/luxon/) calls inside your code. -```ts twoslash -import { expect, vi } from 'vitest' -// ---cut--- +```ts const date = new Date(1998, 11, 19) vi.useFakeTimers() @@ -870,7 +824,7 @@ This is similar to `vi.waitFor`, but if the callback throws any errors, executio Look at the example below. We can use `vi.waitUntil` to wait for the element to appear on the page, and then we can do something with the element. -```ts twoslash +```ts import { expect, test, vi } from 'vitest' test('Element render correctly', async () => { diff --git a/docs/config/file.md b/docs/config/file.md index 7fdfc47a665a..c92899ce0629 100644 --- a/docs/config/file.md +++ b/docs/config/file.md @@ -14,7 +14,7 @@ To configure `vitest` itself, add `test` property in your Vite config. You'll al Using `defineConfig` from `vite` you should follow this: -```ts twoslash +```ts /// import { defineConfig } from 'vite' @@ -27,7 +27,7 @@ export default defineConfig({ Using `defineConfig` from `vitest/config` you should follow this: -```ts twoslash +```ts import { defineConfig } from 'vitest/config' export default defineConfig({ diff --git a/docs/config/index.md b/docs/config/index.md index 6f768ab4cf62..917c431508e5 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -571,6 +571,14 @@ Enable watch mode Project root +### dir + +- **Type:** `string` +- **CLI:** `--dir=` +- **Default:** same as `root` + +Base directory to scan for the test files. You can specify this option to speed up test discovery if your root covers the whole project + ### reporters - **Type:** `Reporter | Reporter[]` diff --git a/docs/guide/browser/context.md b/docs/guide/browser/context.md index 7ef22cd13fd5..097dd4f87d7d 100644 --- a/docs/guide/browser/context.md +++ b/docs/guide/browser/context.md @@ -67,7 +67,7 @@ export const page: { /** * Serialized test config. */ - config: ResolvedConfig + config: SerializedConfig /** * Change the size of iframe's viewport. */ diff --git a/docs/guide/browser/index.md b/docs/guide/browser/index.md index 2224255d016f..32eb10f92580 100644 --- a/docs/guide/browser/index.md +++ b/docs/guide/browser/index.md @@ -93,7 +93,7 @@ export default defineConfig({ browser: { provider: 'playwright', // or 'webdriverio' enabled: true, - name: 'chrome', // browser name is required + name: 'chromium', // browser name is required }, } }) @@ -112,7 +112,7 @@ export default defineConfig({ browser: { enabled: true, provider: 'playwright', - name: 'chrome', + name: 'chromium', } } }) @@ -127,7 +127,7 @@ export default defineConfig({ browser: { enabled: true, provider: 'playwright', - name: 'chrome', + name: 'chromium', } } }) @@ -142,7 +142,7 @@ export default defineConfig({ browser: { enabled: true, provider: 'playwright', - name: 'chrome', + name: 'chromium', } } }) @@ -157,7 +157,7 @@ export default defineConfig({ browser: { enabled: true, provider: 'playwright', - name: 'chrome', + name: 'chromium', } } }) diff --git a/docs/guide/browser/interactivity-api.md b/docs/guide/browser/interactivity-api.md index c187e3d7b574..b10169e3635f 100644 --- a/docs/guide/browser/interactivity-api.md +++ b/docs/guide/browser/interactivity-api.md @@ -29,6 +29,29 @@ Almost every `userEvent` method inherits its provider options. To see all availa ``` ::: +## userEvent.setup + +- **Type:** `() => UserEvent` + +Creates a new user event instance. This is useful if you need to keep the state of keyboard to press and release buttons correctly. + +::: warning +Unlike `@testing-library/user-event`, the default `userEvent` instance from `@vitest/browser/context` is created once, not every time its methods are called! You can see the difference in how it works in this snippet: + +```ts +import { userEvent as vitestUserEvent } from '@vitest/browser/context' +import { userEvent as originalUserEvent } from '@testing-library/user-event' + +await vitestUserEvent.keyboard('{Shift}') // press shift without releasing +await vitestUserEvent.keyboard('{/Shift}') // releases shift + +await originalUserEvent.keyboard('{Shift}') // press shift without releasing +await originalUserEvent.keyboard('{/Shift}') // DID NOT release shift because the state is different +``` + +This behaviour is more useful because we do not emulate the keyboard, we actually press the Shift, so keeping the original behaviour would cause unexpected issues when typing in the field. +::: + ## userEvent.click - **Type:** `(element: Element, options?: UserEventClickOptions) => Promise` @@ -163,7 +186,7 @@ test('trigger keystrokes', async () => { References: -- [Playwright `locator.press` API](https://playwright.dev/docs/api/class-locator#locator-press) +- [Playwright `Keyboard` API](https://playwright.dev/docs/api/class-keyboard) - [WebdriverIO `action('key')` API](https://webdriver.io/docs/api/browser/action#key-input-source) - [testing-library `type` API](https://testing-library.com/docs/user-event/utility/#type) @@ -194,7 +217,7 @@ test('tab works', async () => { References: -- [Playwright `locator.press` API](https://playwright.dev/docs/api/class-locator#locator-press) +- [Playwright `Keyboard` API](https://playwright.dev/docs/api/class-keyboard) - [WebdriverIO `action('key')` API](https://webdriver.io/docs/api/browser/action#key-input-source) - [testing-library `tab` API](https://testing-library.com/docs/user-event/convenience/#tab) diff --git a/docs/guide/cli-generated.md b/docs/guide/cli-generated.md new file mode 100644 index 000000000000..80e1343818e3 --- /dev/null +++ b/docs/guide/cli-generated.md @@ -0,0 +1,828 @@ +### root + +- **CLI:** `-r, --root ` +- **Config:** [root](/config/#root) + +Root path + +### config + +- **CLI:** `-c, --config ` + +Path to config file + +### update + +- **CLI:** `-u, --update` +- **Config:** [update](/config/#update) + +Update snapshot + +### watch + +- **CLI:** `-w, --watch` +- **Config:** [watch](/config/#watch) + +Enable watch mode + +### testNamePattern + +- **CLI:** `-t, --testNamePattern ` +- **Config:** [testNamePattern](/config/#testnamepattern) + +Run tests with full names matching the specified regexp pattern + +### dir + +- **CLI:** `--dir ` +- **Config:** [dir](/config/#dir) + +Base directory to scan for the test files + +### ui + +- **CLI:** `--ui` +- **Config:** [ui](/config/#ui) + +Enable UI + +### open + +- **CLI:** `--open` +- **Config:** [open](/config/#open) + +Open UI automatically (default: `!process.env.CI`) + +### api.port + +- **CLI:** `--api.port [port]` + +Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `51204` + +### api.host + +- **CLI:** `--api.host [host]` + +Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses + +### api.strictPort + +- **CLI:** `--api.strictPort` + +Set to true to exit if port is already in use, instead of automatically trying the next available port + +### silent + +- **CLI:** `--silent` +- **Config:** [silent](/config/#silent) + +Silent console output from tests + +### hideSkippedTests + +- **CLI:** `--hideSkippedTests` + +Hide logs for skipped tests + +### reporters + +- **CLI:** `--reporter ` +- **Config:** [reporters](/config/#reporters) + +Specify reporters + +### outputFile + +- **CLI:** `--outputFile ` +- **Config:** [outputFile](/config/#outputfile) + +Write test results to a file when supporter reporter is also specified, use cac's dot notation for individual outputs of multiple reporters (example: `--outputFile.tap=./tap.txt`) + +### coverage.all + +- **CLI:** `--coverage.all` +- **Config:** [coverage.all](/config/#coverage-all) + +Whether to include all files, including the untested ones into report + +### coverage.provider + +- **CLI:** `--coverage.provider ` +- **Config:** [coverage.provider](/config/#coverage-provider) + +Select the tool for coverage collection, available values are: "v8", "istanbul" and "custom" + +### coverage.enabled + +- **CLI:** `--coverage.enabled` +- **Config:** [coverage.enabled](/config/#coverage-enabled) + +Enables coverage collection. Can be overridden using the `--coverage` CLI option (default: `false`) + +### coverage.include + +- **CLI:** `--coverage.include ` +- **Config:** [coverage.include](/config/#coverage-include) + +Files included in coverage as glob patterns. May be specified more than once when using multiple patterns (default: `**`) + +### coverage.exclude + +- **CLI:** `--coverage.exclude ` +- **Config:** [coverage.exclude](/config/#coverage-exclude) + +Files to be excluded in coverage. May be specified more than once when using multiple extensions (default: Visit [`coverage.exclude`](https://vitest.dev/config/#coverage-exclude)) + +### coverage.extension + +- **CLI:** `--coverage.extension ` +- **Config:** [coverage.extension](/config/#coverage-extension) + +Extension to be included in coverage. May be specified more than once when using multiple extensions (default: `[".js", ".cjs", ".mjs", ".ts", ".mts", ".tsx", ".jsx", ".vue", ".svelte"]`) + +### coverage.clean + +- **CLI:** `--coverage.clean` +- **Config:** [coverage.clean](/config/#coverage-clean) + +Clean coverage results before running tests (default: true) + +### coverage.cleanOnRerun + +- **CLI:** `--coverage.cleanOnRerun` +- **Config:** [coverage.cleanOnRerun](/config/#coverage-cleanonrerun) + +Clean coverage report on watch rerun (default: true) + +### coverage.reportsDirectory + +- **CLI:** `--coverage.reportsDirectory ` +- **Config:** [coverage.reportsDirectory](/config/#coverage-reportsdirectory) + +Directory to write coverage report to (default: ./coverage) + +### coverage.reporter + +- **CLI:** `--coverage.reporter ` +- **Config:** [coverage.reporter](/config/#coverage-reporter) + +Coverage reporters to use. Visit [`coverage.reporter`](https://vitest.dev/config/#coverage-reporter) for more information (default: `["text", "html", "clover", "json"]`) + +### coverage.reportOnFailure + +- **CLI:** `--coverage.reportOnFailure` +- **Config:** [coverage.reportOnFailure](/config/#coverage-reportonfailure) + +Generate coverage report even when tests fail (default: `false`) + +### coverage.allowExternal + +- **CLI:** `--coverage.allowExternal` +- **Config:** [coverage.allowExternal](/config/#coverage-allowexternal) + +Collect coverage of files outside the project root (default: `false`) + +### coverage.skipFull + +- **CLI:** `--coverage.skipFull` +- **Config:** [coverage.skipFull](/config/#coverage-skipfull) + +Do not show files with 100% statement, branch, and function coverage (default: `false`) + +### coverage.thresholds.100 + +- **CLI:** `--coverage.thresholds.100` +- **Config:** [coverage.thresholds.100](/config/#coverage-thresholds-100) + +Shortcut to set all coverage thresholds to 100 (default: `false`) + +### coverage.thresholds.perFile + +- **CLI:** `--coverage.thresholds.perFile` +- **Config:** [coverage.thresholds.perFile](/config/#coverage-thresholds-perfile) + +Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`) + +### coverage.thresholds.autoUpdate + +- **CLI:** `--coverage.thresholds.autoUpdate` +- **Config:** [coverage.thresholds.autoUpdate](/config/#coverage-thresholds-autoupdate) + +Update threshold values: "lines", "functions", "branches" and "statements" to configuration file when current coverage is above the configured thresholds (default: `false`) + +### coverage.thresholds.lines + +- **CLI:** `--coverage.thresholds.lines ` + +Threshold for lines. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers + +### coverage.thresholds.functions + +- **CLI:** `--coverage.thresholds.functions ` + +Threshold for functions. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers + +### coverage.thresholds.branches + +- **CLI:** `--coverage.thresholds.branches ` + +Threshold for branches. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers + +### coverage.thresholds.statements + +- **CLI:** `--coverage.thresholds.statements ` + +Threshold for statements. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers + +### coverage.ignoreClassMethods + +- **CLI:** `--coverage.ignoreClassMethods ` +- **Config:** [coverage.ignoreClassMethods](/config/#coverage-ignoreclassmethods) + +Array of class method names to ignore for coverage. Visit [istanbuljs](https://github.com/istanbuljs/nyc#ignoring-methods) for more information. This option is only available for the istanbul providers (default: `[]`) + +### coverage.processingConcurrency + +- **CLI:** `--coverage.processingConcurrency ` +- **Config:** [coverage.processingConcurrency](/config/#coverage-processingconcurrency) + +Concurrency limit used when processing the coverage results. (default min between 20 and the number of CPUs) + +### coverage.customProviderModule + +- **CLI:** `--coverage.customProviderModule ` +- **Config:** [coverage.customProviderModule](/config/#coverage-customprovidermodule) + +Specifies the module name or path for the custom coverage provider module. Visit [Custom Coverage Provider](https://vitest.dev/guide/coverage#custom-coverage-provider) for more information. This option is only available for custom providers + +### coverage.watermarks.statements + +- **CLI:** `--coverage.watermarks.statements ` + +High and low watermarks for statements in the format of `,` + +### coverage.watermarks.lines + +- **CLI:** `--coverage.watermarks.lines ` + +High and low watermarks for lines in the format of `,` + +### coverage.watermarks.branches + +- **CLI:** `--coverage.watermarks.branches ` + +High and low watermarks for branches in the format of `,` + +### coverage.watermarks.functions + +- **CLI:** `--coverage.watermarks.functions ` + +High and low watermarks for functions in the format of `,` + +### mode + +- **CLI:** `--mode ` +- **Config:** [mode](/config/#mode) + +Override Vite mode (default: `test` or `benchmark`) + +### workspace + +- **CLI:** `--workspace ` +- **Config:** [workspace](/config/#workspace) + +Path to a workspace configuration file + +### isolate + +- **CLI:** `--isolate` +- **Config:** [isolate](/config/#isolate) + +Run every test file in isolation. To disable isolation, use `--no-isolate` (default: `true`) + +### globals + +- **CLI:** `--globals` +- **Config:** [globals](/config/#globals) + +Inject apis globally + +### dom + +- **CLI:** `--dom` + +Mock browser API with happy-dom + +### browser.enabled + +- **CLI:** `--browser.enabled` +- **Config:** [browser.enabled](/config/#browser-enabled) + +Run tests in the browser. Equivalent to `--browser.enabled` (default: `false`) + +### browser.name + +- **CLI:** `--browser.name ` +- **Config:** [browser.name](/config/#browser-name) + +Run all tests in a specific browser. Some browsers are only available for specific providers (see `--browser.provider`). Visit [`browser.name`](https://vitest.dev/config/#browser-name) for more information + +### browser.headless + +- **CLI:** `--browser.headless` +- **Config:** [browser.headless](/config/#browser-headless) + +Run the browser in headless mode (i.e. without opening the GUI (Graphical User Interface)). If you are running Vitest in CI, it will be enabled by default (default: `process.env.CI`) + +### browser.api.port + +- **CLI:** `--browser.api.port [port]` +- **Config:** [browser.api.port](/config/#browser-api-port) + +Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `63315` + +### browser.api.host + +- **CLI:** `--browser.api.host [host]` +- **Config:** [browser.api.host](/config/#browser-api-host) + +Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses + +### browser.api.strictPort + +- **CLI:** `--browser.api.strictPort` +- **Config:** [browser.api.strictPort](/config/#browser-api-strictport) + +Set to true to exit if port is already in use, instead of automatically trying the next available port + +### browser.provider + +- **CLI:** `--browser.provider ` +- **Config:** [browser.provider](/config/#browser-provider) + +Provider used to run browser tests. Some browsers are only available for specific providers. Can be "webdriverio", "playwright", "preview", or the path to a custom provider. Visit [`browser.provider`](https://vitest.dev/config/#browser-provider) for more information (default: `"preview"`) + +### browser.providerOptions + +- **CLI:** `--browser.providerOptions ` +- **Config:** [browser.providerOptions](/config/#browser-provideroptions) + +Options that are passed down to a browser provider. Visit [`browser.providerOptions`](https://vitest.dev/config/#browser-provideroptions) for more information + +### browser.isolate + +- **CLI:** `--browser.isolate` +- **Config:** [browser.isolate](/config/#browser-isolate) + +Run every browser test file in isolation. To disable isolation, use `--browser.isolate=false` (default: `true`) + +### browser.ui + +- **CLI:** `--browser.ui` +- **Config:** [browser.ui](/config/#browser-ui) + +Show Vitest UI when running tests (default: `!process.env.CI`) + +### browser.fileParallelism + +- **CLI:** `--browser.fileParallelism` +- **Config:** [browser.fileParallelism](/config/#browser-fileparallelism) + +Should browser test files run in parallel. Use `--browser.fileParallelism=false` to disable (default: `true`) + +### pool + +- **CLI:** `--pool ` +- **Config:** [pool](/config/#pool) + +Specify pool, if not running in the browser (default: `threads`) + +### poolOptions.threads.isolate + +- **CLI:** `--poolOptions.threads.isolate` +- **Config:** [poolOptions.threads.isolate](/config/#pooloptions-threads-isolate) + +Isolate tests in threads pool (default: `true`) + +### poolOptions.threads.singleThread + +- **CLI:** `--poolOptions.threads.singleThread` +- **Config:** [poolOptions.threads.singleThread](/config/#pooloptions-threads-singlethread) + +Run tests inside a single thread (default: `false`) + +### poolOptions.threads.maxThreads + +- **CLI:** `--poolOptions.threads.maxThreads ` +- **Config:** [poolOptions.threads.maxThreads](/config/#pooloptions-threads-maxthreads) + +Maximum number or percentage of threads to run tests in + +### poolOptions.threads.minThreads + +- **CLI:** `--poolOptions.threads.minThreads ` +- **Config:** [poolOptions.threads.minThreads](/config/#pooloptions-threads-minthreads) + +Minimum number or percentage of threads to run tests in + +### poolOptions.threads.useAtomics + +- **CLI:** `--poolOptions.threads.useAtomics` +- **Config:** [poolOptions.threads.useAtomics](/config/#pooloptions-threads-useatomics) + +Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) + +### poolOptions.vmThreads.isolate + +- **CLI:** `--poolOptions.vmThreads.isolate` +- **Config:** [poolOptions.vmThreads.isolate](/config/#pooloptions-vmthreads-isolate) + +Isolate tests in threads pool (default: `true`) + +### poolOptions.vmThreads.singleThread + +- **CLI:** `--poolOptions.vmThreads.singleThread` +- **Config:** [poolOptions.vmThreads.singleThread](/config/#pooloptions-vmthreads-singlethread) + +Run tests inside a single thread (default: `false`) + +### poolOptions.vmThreads.maxThreads + +- **CLI:** `--poolOptions.vmThreads.maxThreads ` +- **Config:** [poolOptions.vmThreads.maxThreads](/config/#pooloptions-vmthreads-maxthreads) + +Maximum number or percentage of threads to run tests in + +### poolOptions.vmThreads.minThreads + +- **CLI:** `--poolOptions.vmThreads.minThreads ` +- **Config:** [poolOptions.vmThreads.minThreads](/config/#pooloptions-vmthreads-minthreads) + +Minimum number or percentage of threads to run tests in + +### poolOptions.vmThreads.useAtomics + +- **CLI:** `--poolOptions.vmThreads.useAtomics` +- **Config:** [poolOptions.vmThreads.useAtomics](/config/#pooloptions-vmthreads-useatomics) + +Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) + +### poolOptions.vmThreads.memoryLimit + +- **CLI:** `--poolOptions.vmThreads.memoryLimit ` +- **Config:** [poolOptions.vmThreads.memoryLimit](/config/#pooloptions-vmthreads-memorylimit) + +Memory limit for VM threads pool. If you see memory leaks, try to tinker this value. + +### poolOptions.forks.isolate + +- **CLI:** `--poolOptions.forks.isolate` +- **Config:** [poolOptions.forks.isolate](/config/#pooloptions-forks-isolate) + +Isolate tests in forks pool (default: `true`) + +### poolOptions.forks.singleFork + +- **CLI:** `--poolOptions.forks.singleFork` +- **Config:** [poolOptions.forks.singleFork](/config/#pooloptions-forks-singlefork) + +Run tests inside a single child_process (default: `false`) + +### poolOptions.forks.maxForks + +- **CLI:** `--poolOptions.forks.maxForks ` +- **Config:** [poolOptions.forks.maxForks](/config/#pooloptions-forks-maxforks) + +Maximum number or percentage of processes to run tests in + +### poolOptions.forks.minForks + +- **CLI:** `--poolOptions.forks.minForks ` +- **Config:** [poolOptions.forks.minForks](/config/#pooloptions-forks-minforks) + +Minimum number or percentage of processes to run tests in + +### poolOptions.vmForks.isolate + +- **CLI:** `--poolOptions.vmForks.isolate` +- **Config:** [poolOptions.vmForks.isolate](/config/#pooloptions-vmforks-isolate) + +Isolate tests in forks pool (default: `true`) + +### poolOptions.vmForks.singleFork + +- **CLI:** `--poolOptions.vmForks.singleFork` +- **Config:** [poolOptions.vmForks.singleFork](/config/#pooloptions-vmforks-singlefork) + +Run tests inside a single child_process (default: `false`) + +### poolOptions.vmForks.maxForks + +- **CLI:** `--poolOptions.vmForks.maxForks ` +- **Config:** [poolOptions.vmForks.maxForks](/config/#pooloptions-vmforks-maxforks) + +Maximum number or percentage of processes to run tests in + +### poolOptions.vmForks.minForks + +- **CLI:** `--poolOptions.vmForks.minForks ` +- **Config:** [poolOptions.vmForks.minForks](/config/#pooloptions-vmforks-minforks) + +Minimum number or percentage of processes to run tests in + +### poolOptions.vmForks.memoryLimit + +- **CLI:** `--poolOptions.vmForks.memoryLimit ` +- **Config:** [poolOptions.vmForks.memoryLimit](/config/#pooloptions-vmforks-memorylimit) + +Memory limit for VM forks pool. If you see memory leaks, try to tinker this value. + +### fileParallelism + +- **CLI:** `--fileParallelism` +- **Config:** [fileParallelism](/config/#fileparallelism) + +Should all test files run in parallel. Use `--no-file-parallelism` to disable (default: `true`) + +### maxWorkers + +- **CLI:** `--maxWorkers ` +- **Config:** [maxWorkers](/config/#maxworkers) + +Maximum number or percentage of workers to run tests in + +### minWorkers + +- **CLI:** `--minWorkers ` +- **Config:** [minWorkers](/config/#minworkers) + +Minimum number or percentage of workers to run tests in + +### environment + +- **CLI:** `--environment ` +- **Config:** [environment](/config/#environment) + +Specify runner environment, if not running in the browser (default: `node`) + +### passWithNoTests + +- **CLI:** `--passWithNoTests` +- **Config:** [passWithNoTests](/config/#passwithnotests) + +Pass when no tests are found + +### logHeapUsage + +- **CLI:** `--logHeapUsage` +- **Config:** [logHeapUsage](/config/#logheapusage) + +Show the size of heap for each test when running in node + +### allowOnly + +- **CLI:** `--allowOnly` +- **Config:** [allowOnly](/config/#allowonly) + +Allow tests and suites that are marked as only (default: `!process.env.CI`) + +### dangerouslyIgnoreUnhandledErrors + +- **CLI:** `--dangerouslyIgnoreUnhandledErrors` +- **Config:** [dangerouslyIgnoreUnhandledErrors](/config/#dangerouslyignoreunhandlederrors) + +Ignore any unhandled errors that occur + +### sequence.shuffle.files + +- **CLI:** `--sequence.shuffle.files` +- **Config:** [sequence.shuffle.files](/config/#sequence-shuffle-files) + +Run files in a random order. Long running tests will not start earlier if you enable this option. (default: `false`) + +### sequence.shuffle.tests + +- **CLI:** `--sequence.shuffle.tests` +- **Config:** [sequence.shuffle.tests](/config/#sequence-shuffle-tests) + +Run tests in a random order (default: `false`) + +### sequence.concurrent + +- **CLI:** `--sequence.concurrent` +- **Config:** [sequence.concurrent](/config/#sequence-concurrent) + +Make tests run in parallel (default: `false`) + +### sequence.seed + +- **CLI:** `--sequence.seed ` +- **Config:** [sequence.seed](/config/#sequence-seed) + +Set the randomization seed. This option will have no effect if `--sequence.shuffle` is falsy. Visit ["Random Seed" page](https://en.wikipedia.org/wiki/Random_seed) for more information + +### sequence.hooks + +- **CLI:** `--sequence.hooks ` +- **Config:** [sequence.hooks](/config/#sequence-hooks) + +Changes the order in which hooks are executed. Accepted values are: "stack", "list" and "parallel". Visit [`sequence.hooks`](https://vitest.dev/config/#sequence-hooks) for more information (default: `"parallel"`) + +### sequence.setupFiles + +- **CLI:** `--sequence.setupFiles ` +- **Config:** [sequence.setupFiles](/config/#sequence-setupfiles) + +Changes the order in which setup files are executed. Accepted values are: "list" and "parallel". If set to "list", will run setup files in the order they are defined. If set to "parallel", will run setup files in parallel (default: `"parallel"`) + +### inspect + +- **CLI:** `--inspect [[host:]port]` +- **Config:** [inspect](/config/#inspect) + +Enable Node.js inspector (default: `127.0.0.1:9229`) + +### inspectBrk + +- **CLI:** `--inspectBrk [[host:]port]` +- **Config:** [inspectBrk](/config/#inspectbrk) + +Enable Node.js inspector and break before the test starts + +### testTimeout + +- **CLI:** `--testTimeout ` +- **Config:** [testTimeout](/config/#testtimeout) + +Default timeout of a test in milliseconds (default: `5000`) + +### hookTimeout + +- **CLI:** `--hookTimeout ` +- **Config:** [hookTimeout](/config/#hooktimeout) + +Default hook timeout in milliseconds (default: `10000`) + +### bail + +- **CLI:** `--bail ` +- **Config:** [bail](/config/#bail) + +Stop test execution when given number of tests have failed (default: `0`) + +### retry + +- **CLI:** `--retry ` +- **Config:** [retry](/config/#retry) + +Retry the test specific number of times if it fails (default: `0`) + +### diff + +- **CLI:** `--diff ` +- **Config:** [diff](/config/#diff) + +Path to a diff config that will be used to generate diff interface + +### exclude + +- **CLI:** `--exclude ` +- **Config:** [exclude](/config/#exclude) + +Additional file globs to be excluded from test + +### expandSnapshotDiff + +- **CLI:** `--expandSnapshotDiff` +- **Config:** [expandSnapshotDiff](/config/#expandsnapshotdiff) + +Show full diff when snapshot fails + +### disableConsoleIntercept + +- **CLI:** `--disableConsoleIntercept` +- **Config:** [disableConsoleIntercept](/config/#disableconsoleintercept) + +Disable automatic interception of console logging (default: `false`) + +### typecheck.enabled + +- **CLI:** `--typecheck.enabled` +- **Config:** [typecheck.enabled](/config/#typecheck-enabled) + +Enable typechecking alongside tests (default: `false`) + +### typecheck.only + +- **CLI:** `--typecheck.only` +- **Config:** [typecheck.only](/config/#typecheck-only) + +Run only typecheck tests. This automatically enables typecheck (default: `false`) + +### typecheck.checker + +- **CLI:** `--typecheck.checker ` +- **Config:** [typecheck.checker](/config/#typecheck-checker) + +Specify the typechecker to use. Available values are: "tsc" and "vue-tsc" and a path to an executable (default: `"tsc"`) + +### typecheck.allowJs + +- **CLI:** `--typecheck.allowJs` +- **Config:** [typecheck.allowJs](/config/#typecheck-allowjs) + +Allow JavaScript files to be typechecked. By default takes the value from tsconfig.json + +### typecheck.ignoreSourceErrors + +- **CLI:** `--typecheck.ignoreSourceErrors` +- **Config:** [typecheck.ignoreSourceErrors](/config/#typecheck-ignoresourceerrors) + +Ignore type errors from source files + +### typecheck.tsconfig + +- **CLI:** `--typecheck.tsconfig ` +- **Config:** [typecheck.tsconfig](/config/#typecheck-tsconfig) + +Path to a custom tsconfig file + +### project + +- **CLI:** `--project ` +- **Config:** [project](/config/#project) + +The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*` + +### slowTestThreshold + +- **CLI:** `--slowTestThreshold ` +- **Config:** [slowTestThreshold](/config/#slowtestthreshold) + +Threshold in milliseconds for a test to be considered slow (default: `300`) + +### teardownTimeout + +- **CLI:** `--teardownTimeout ` +- **Config:** [teardownTimeout](/config/#teardowntimeout) + +Default timeout of a teardown function in milliseconds (default: `10000`) + +### maxConcurrency + +- **CLI:** `--maxConcurrency ` +- **Config:** [maxConcurrency](/config/#maxconcurrency) + +Maximum number of concurrent tests in a suite (default: `5`) + +### expect.requireAssertions + +- **CLI:** `--expect.requireAssertions` +- **Config:** [expect.requireAssertions](/config/#expect-requireassertions) + +Require that all tests have at least one assertion + +### expect.poll.interval + +- **CLI:** `--expect.poll.interval ` +- **Config:** [expect.poll.interval](/config/#expect-poll-interval) + +Poll interval in milliseconds for `expect.poll()` assertions (default: `50`) + +### expect.poll.timeout + +- **CLI:** `--expect.poll.timeout ` +- **Config:** [expect.poll.timeout](/config/#expect-poll-timeout) + +Poll timeout in milliseconds for `expect.poll()` assertions (default: `1000`) + +### printConsoleTrace + +- **CLI:** `--printConsoleTrace` +- **Config:** [printConsoleTrace](/config/#printconsoletrace) + +Always print console stack traces + +### run + +- **CLI:** `--run` + +Disable watch mode + +### color + +- **CLI:** `--no-color` + +Removes colors from the console output + +### clearScreen + +- **CLI:** `--clearScreen` + +Clear terminal screen when re-running tests during watch mode (default: `true`) + +### standalone + +- **CLI:** `--standalone` + +Start Vitest without running tests. File filters will be ignored, tests will be running only on change (default: `false`) diff --git a/docs/guide/cli-table.md b/docs/guide/cli-table.md deleted file mode 100644 index 1ffef7e1f322..000000000000 --- a/docs/guide/cli-table.md +++ /dev/null @@ -1,126 +0,0 @@ -| Options | | -| ------------- | ------------- | -| `-r, --root ` | Root path | -| `-c, --config ` | Path to config file | -| `-u, --update` | Update snapshot | -| `-w, --watch` | Enable watch mode | -| `-t, --testNamePattern ` | Run tests with full names matching the specified regexp pattern | -| `--dir ` | Base directory to scan for the test files | -| `--ui` | Enable UI | -| `--open` | Open UI automatically (default: `!process.env.CI`) | -| `--api.port [port]` | Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `51204` | -| `--api.host [host]` | Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses | -| `--api.strictPort` | Set to true to exit if port is already in use, instead of automatically trying the next available port | -| `--silent` | Silent console output from tests | -| `--hideSkippedTests` | Hide logs for skipped tests | -| `--reporter ` | Specify reporters | -| `--outputFile ` | Write test results to a file when supporter reporter is also specified, use cac's dot notation for individual outputs of multiple reporters (example: --outputFile.tap=./tap.txt) | -| `--coverage.all` | Whether to include all files, including the untested ones into report | -| `--coverage.provider ` | Select the tool for coverage collection, available values are: "v8", "istanbul" and "custom" | -| `--coverage.enabled` | Enables coverage collection. Can be overridden using the `--coverage` CLI option (default: `false`) | -| `--coverage.include ` | Files included in coverage as glob patterns. May be specified more than once when using multiple patterns (default: `**`) | -| `--coverage.exclude ` | Files to be excluded in coverage. May be specified more than once when using multiple extensions (default: Visit [`coverage.exclude`](https://vitest.dev/config/#coverage-exclude)) | -| `--coverage.extension ` | Extension to be included in coverage. May be specified more than once when using multiple extensions (default: `[".js", ".cjs", ".mjs", ".ts", ".mts", ".tsx", ".jsx", ".vue", ".svelte"]`) | -| `--coverage.clean` | Clean coverage results before running tests (default: true) | -| `--coverage.cleanOnRerun` | Clean coverage report on watch rerun (default: true) | -| `--coverage.reportsDirectory ` | Directory to write coverage report to (default: ./coverage) | -| `--coverage.reporter ` | Coverage reporters to use. Visit [`coverage.reporter`](https://vitest.dev/config/#coverage-reporter) for more information (default: `["text", "html", "clover", "json"]`) | -| `--coverage.reportOnFailure` | Generate coverage report even when tests fail (default: `false`) | -| `--coverage.allowExternal` | Collect coverage of files outside the project root (default: `false`) | -| `--coverage.skipFull` | Do not show files with 100% statement, branch, and function coverage (default: `false`) | -| `--coverage.thresholds.100` | Shortcut to set all coverage thresholds to 100 (default: `false`) | -| `--coverage.thresholds.perFile` | Check thresholds per file. See `--coverage.thresholds.lines`, `--coverage.thresholds.functions`, `--coverage.thresholds.branches` and `--coverage.thresholds.statements` for the actual thresholds (default: `false`) | -| `--coverage.thresholds.autoUpdate` | Update threshold values: "lines", "functions", "branches" and "statements" to configuration file when current coverage is above the configured thresholds (default: `false`) | -| `--coverage.thresholds.lines ` | Threshold for lines. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers | -| `--coverage.thresholds.functions ` | Threshold for functions. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers | -| `--coverage.thresholds.branches ` | Threshold for branches. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers | -| `--coverage.thresholds.statements ` | Threshold for statements. Visit [istanbuljs](https://github.com/istanbuljs/nyc#coverage-thresholds) for more information. This option is not available for custom providers | -| `--coverage.ignoreClassMethods ` | Array of class method names to ignore for coverage. Visit [istanbuljs](https://github.com/istanbuljs/nyc#ignoring-methods) for more information. This option is only available for the istanbul providers (default: `[]`) | -| `--coverage.processingConcurrency ` | Concurrency limit used when processing the coverage results. (default min between 20 and the number of CPUs) | -| `--coverage.customProviderModule ` | Specifies the module name or path for the custom coverage provider module. Visit [Custom Coverage Provider](https://vitest.dev/guide/coverage#custom-coverage-provider) for more information. This option is only available for custom providers | -| `--coverage.watermarks.statements ` | High and low watermarks for statements in the format of `,` | -| `--coverage.watermarks.lines ` | High and low watermarks for lines in the format of `,` | -| `--coverage.watermarks.branches ` | High and low watermarks for branches in the format of `,` | -| `--coverage.watermarks.functions ` | High and low watermarks for functions in the format of `,` | -| `--mode ` | Override Vite mode (default: `test` or `benchmark`) | -| `--workspace ` | Path to a workspace configuration file | -| `--isolate` | Run every test file in isolation. To disable isolation, use `--no-isolate` (default: `true`) | -| `--globals` | Inject apis globally | -| `--dom` | Mock browser API with happy-dom | -| `--browser.enabled` | Run tests in the browser. Equivalent to `--browser.enabled` (default: `false`) | -| `--browser.name ` | Run all tests in a specific browser. Some browsers are only available for specific providers (see `--browser.provider`). Visit [`browser.name`](https://vitest.dev/config/#browser-name) for more information | -| `--browser.headless` | Run the browser in headless mode (i.e. without opening the GUI (Graphical User Interface)). If you are running Vitest in CI, it will be enabled by default (default: `process.env.CI`) | -| `--browser.api.port [port]` | Specify server port. Note if the port is already being used, Vite will automatically try the next available port so this may not be the actual port the server ends up listening on. If true will be set to `63315` | -| `--browser.api.host [host]` | Specify which IP addresses the server should listen on. Set this to `0.0.0.0` or `true` to listen on all addresses, including LAN and public addresses | -| `--browser.api.strictPort` | Set to true to exit if port is already in use, instead of automatically trying the next available port | -| `--browser.provider ` | Provider used to run browser tests. Some browsers are only available for specific providers. Can be "webdriverio", "playwright", "preview", or the path to a custom provider. Visit [`browser.provider`](https://vitest.dev/config/#browser-provider) for more information (default: `"preview"`) | -| `--browser.providerOptions ` | Options that are passed down to a browser provider. Visit [`browser.providerOptions`](https://vitest.dev/config/#browser-provideroptions) for more information | -| `--browser.isolate` | Run every browser test file in isolation. To disable isolation, use `--browser.isolate=false` (default: `true`) | -| `--browser.ui` | Show Vitest UI when running tests (default: `!process.env.CI`) | -| `--browser.fileParallelism` | Should browser test files run in parallel. Use `--browser.fileParallelism=false` to disable (default: `true`) | -| `--pool ` | Specify pool, if not running in the browser (default: `threads`) | -| `--poolOptions.threads.isolate` | Isolate tests in threads pool (default: `true`) | -| `--poolOptions.threads.singleThread` | Run tests inside a single thread (default: `false`) | -| `--poolOptions.threads.maxThreads ` | Maximum number or percentage of threads to run tests in | -| `--poolOptions.threads.minThreads ` | Minimum number or percentage of threads to run tests in | -| `--poolOptions.threads.useAtomics` | Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) | -| `--poolOptions.vmThreads.isolate` | Isolate tests in threads pool (default: `true`) | -| `--poolOptions.vmThreads.singleThread` | Run tests inside a single thread (default: `false`) | -| `--poolOptions.vmThreads.maxThreads ` | Maximum number or percentage of threads to run tests in | -| `--poolOptions.vmThreads.minThreads ` | Minimum number or percentage of threads to run tests in | -| `--poolOptions.vmThreads.useAtomics` | Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) | -| `--poolOptions.vmThreads.memoryLimit ` | Memory limit for VM threads pool. If you see memory leaks, try to tinker this value. | -| `--poolOptions.forks.isolate` | Isolate tests in forks pool (default: `true`) | -| `--poolOptions.forks.singleFork` | Run tests inside a single child_process (default: `false`) | -| `--poolOptions.forks.maxForks ` | Maximum number or percentage of processes to run tests in | -| `--poolOptions.forks.minForks ` | Minimum number or percentage of processes to run tests in | -| `--poolOptions.vmForks.isolate` | Isolate tests in forks pool (default: `true`) | -| `--poolOptions.vmForks.singleFork` | Run tests inside a single child_process (default: `false`) | -| `--poolOptions.vmForks.maxForks ` | Maximum number or percentage of processes to run tests in | -| `--poolOptions.vmForks.minForks ` | Minimum number or percentage of processes to run tests in | -| `--poolOptions.vmForks.memoryLimit ` | Memory limit for VM forks pool. If you see memory leaks, try to tinker this value. | -| `--fileParallelism` | Should all test files run in parallel. Use `--no-file-parallelism` to disable (default: `true`) | -| `--maxWorkers ` | Maximum number or percentage of workers to run tests in | -| `--minWorkers ` | Minimum number or percentage of workers to run tests in | -| `--environment ` | Specify runner environment, if not running in the browser (default: `node`) | -| `--passWithNoTests` | Pass when no tests are found | -| `--logHeapUsage` | Show the size of heap for each test when running in node | -| `--allowOnly` | Allow tests and suites that are marked as only (default: `!process.env.CI`) | -| `--dangerouslyIgnoreUnhandledErrors` | Ignore any unhandled errors that occur | -| `--shard ` | Test suite shard to execute in a format of `/` | -| `--changed [since]` | Run tests that are affected by the changed files (default: `false`) | -| `--sequence.shuffle.files` | Run files in a random order. Long running tests will not start earlier if you enable this option. (default: `false`) | -| `--sequence.shuffle.tests` | Run tests in a random order (default: `false`) | -| `--sequence.concurrent` | Make tests run in parallel (default: `false`) | -| `--sequence.seed ` | Set the randomization seed. This option will have no effect if --sequence.shuffle is falsy. Visit ["Random Seed" page](https://en.wikipedia.org/wiki/Random_seed) for more information | -| `--sequence.hooks ` | Changes the order in which hooks are executed. Accepted values are: "stack", "list" and "parallel". Visit [`sequence.hooks`](https://vitest.dev/config/#sequence-hooks) for more information (default: `"parallel"`) | -| `--sequence.setupFiles ` | Changes the order in which setup files are executed. Accepted values are: "list" and "parallel". If set to "list", will run setup files in the order they are defined. If set to "parallel", will run setup files in parallel (default: `"parallel"`) | -| `--inspect [[host:]port]` | Enable Node.js inspector (default: `127.0.0.1:9229`) | -| `--inspectBrk [[host:]port]` | Enable Node.js inspector and break before the test starts | -| `--testTimeout ` | Default timeout of a test in milliseconds (default: `5000`) | -| `--hookTimeout ` | Default hook timeout in milliseconds (default: `10000`) | -| `--bail ` | Stop test execution when given number of tests have failed (default: `0`) | -| `--retry ` | Retry the test specific number of times if it fails (default: `0`) | -| `--diff ` | Path to a diff config that will be used to generate diff interface | -| `--exclude ` | Additional file globs to be excluded from test | -| `--expandSnapshotDiff` | Show full diff when snapshot fails | -| `--disableConsoleIntercept` | Disable automatic interception of console logging (default: `false`) | -| `--typecheck.enabled` | Enable typechecking alongside tests (default: `false`) | -| `--typecheck.only` | Run only typecheck tests. This automatically enables typecheck (default: `false`) | -| `--typecheck.checker ` | Specify the typechecker to use. Available values are: "tsc" and "vue-tsc" and a path to an executable (default: `"tsc"`) | -| `--typecheck.allowJs` | Allow JavaScript files to be typechecked. By default takes the value from tsconfig.json | -| `--typecheck.ignoreSourceErrors` | Ignore type errors from source files | -| `--typecheck.tsconfig ` | Path to a custom tsconfig file | -| `--project ` | The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*` | -| `--slowTestThreshold ` | Threshold in milliseconds for a test to be considered slow (default: `300`) | -| `--teardownTimeout ` | Default timeout of a teardown function in milliseconds (default: `10000`) | -| `--maxConcurrency ` | Maximum number of concurrent tests in a suite (default: `5`) | -| `--expect.requireAssertions` | Require that all tests have at least one assertion | -| `--expect.poll.interval ` | Poll interval in milliseconds for `expect.poll()` assertions (default: `50`) | -| `--expect.poll.timeout ` | Poll timeout in milliseconds for `expect.poll()` assertions (default: `1000`) | -| `--printConsoleTrace` | Always print console stack traces | -| `--run` | Disable watch mode | -| `--no-color` | Removes colors from the console output | -| `--clearScreen` | Clear terminal screen when re-running tests during watch mode (default: `true`) | -| `--standalone` | Start Vitest without running tests. File filters will be ignored, tests will be running only on change (default: `false`) | -| `--mergeReports [path]` | Paths to blob reports directory. If this options is used, Vitest won't run any tests, it will only report previously recorded tests | diff --git a/docs/guide/cli.md b/docs/guide/cli.md index 8b636ca27657..9041fc80e828 100644 --- a/docs/guide/cli.md +++ b/docs/guide/cli.md @@ -1,5 +1,6 @@ --- title: Command Line Interface | Guide +outline: deep --- # Command Line Interface @@ -87,8 +88,6 @@ If `--json` flag doesn't receive a value, it will output the JSON into stdout. ## Options - - ::: tip Vitest supports both camel case and kebab case for CLI arguments. For example, `--passWithNoTests` and `--pass-with-no-tests` will both work (`--no-color` and `--inspect-brk` are the exceptions). @@ -108,36 +107,38 @@ vitest --api=false ``` ::: + + ### changed - **Type**: `boolean | string` - **Default**: false - Run tests only against changed files. If no value is provided, it will run tests against uncommitted changes (including staged and unstaged). +Run tests only against changed files. If no value is provided, it will run tests against uncommitted changes (including staged and unstaged). - To run tests against changes made in the last commit, you can use `--changed HEAD~1`. You can also pass commit hash (e.g. `--changed 09a9920`) or branch name (e.g. `--changed origin/develop`). +To run tests against changes made in the last commit, you can use `--changed HEAD~1`. You can also pass commit hash (e.g. `--changed 09a9920`) or branch name (e.g. `--changed origin/develop`). - When used with code coverage the report will contain only the files that were related to the changes. +When used with code coverage the report will contain only the files that were related to the changes. - If paired with the [`forceRerunTriggers`](/config/#forcereruntriggers) config option it will run the whole test suite if at least one of the files listed in the `forceRerunTriggers` list changes. By default, changes to the Vitest config file and `package.json` will always rerun the whole suite. +If paired with the [`forceRerunTriggers`](/config/#forcereruntriggers) config option it will run the whole test suite if at least one of the files listed in the `forceRerunTriggers` list changes. By default, changes to the Vitest config file and `package.json` will always rerun the whole suite. ### shard - **Type**: `string` - **Default**: disabled - Test suite shard to execute in a format of ``/``, where +Test suite shard to execute in a format of ``/``, where - - `count` is a positive integer, count of divided parts - - `index` is a positive integer, index of divided part +- `count` is a positive integer, count of divided parts +- `index` is a positive integer, index of divided part - This command will divide all tests into `count` equal parts, and will run only those that happen to be in an `index` part. For example, to split your tests suite into three parts, use this: +This command will divide all tests into `count` equal parts, and will run only those that happen to be in an `index` part. For example, to split your tests suite into three parts, use this: - ```sh - vitest run --shard=1/3 - vitest run --shard=2/3 - vitest run --shard=3/3 - ``` +```sh +vitest run --shard=1/3 +vitest run --shard=2/3 +vitest run --shard=3/3 +``` :::warning You cannot use this option with `--watch` enabled (enabled in dev by default). diff --git a/docs/guide/common-errors.md b/docs/guide/common-errors.md index b0b5082d7f58..a5f5044af6a9 100644 --- a/docs/guide/common-errors.md +++ b/docs/guide/common-errors.md @@ -10,7 +10,7 @@ If you receive an error that module cannot be found, it might mean several diffe - 1. You misspelled the path. Make sure the path is correct. -- 2. It's possible that your rely on `baseUrl` in your `tsconfig.json`. Vite doesn't take into account `tsconfig.json` by default, so you might need to install [`vite-tsconfig-paths`](https://www.npmjs.com/package/vite-tsconfig-paths) yourself, if you rely on this behaviour. +- 2. It's possible that you rely on `baseUrl` in your `tsconfig.json`. Vite doesn't take into account `tsconfig.json` by default, so you might need to install [`vite-tsconfig-paths`](https://www.npmjs.com/package/vite-tsconfig-paths) yourself, if you rely on this behaviour. ```ts import { defineConfig } from 'vitest/config' diff --git a/docs/guide/coverage.md b/docs/guide/coverage.md index b62628b942aa..c1072a9d4ab9 100644 --- a/docs/guide/coverage.md +++ b/docs/guide/coverage.md @@ -12,7 +12,7 @@ Both `v8` and `istanbul` support are optional. By default, `v8` will be used. You can select the coverage tool by setting `test.coverage.provider` to `v8` or `istanbul`: -```ts twoslash +```ts // vitest.config.ts import { defineConfig } from 'vitest/config' @@ -58,7 +58,7 @@ By default, reporter `['text', 'html', 'clover', 'json']` will be used. To configure it, set `test.coverage` options in your config file: -```ts twoslash +```ts // vitest.config.ts import { defineConfig } from 'vitest/config' @@ -95,7 +95,7 @@ export default defineConfig({ Custom reporters are loaded by Istanbul and must match its reporter interface. See [built-in reporters' implementation](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-reports/lib) for reference. -```js twoslash +```js // custom-reporter.cjs const { ReportBase } = require('istanbul-lib-report') @@ -123,7 +123,7 @@ module.exports = class CustomReporter extends ReportBase { It's also possible to provide your custom coverage provider by passing `'custom'` in `test.coverage.provider`: -```ts twoslash +```ts // vitest.config.ts import { defineConfig } from 'vitest/config' @@ -141,7 +141,12 @@ The custom providers require a `customProviderModule` option which is a module n ```ts // my-custom-coverage-provider.ts -import type { CoverageProvider, CoverageProviderModule, ResolvedCoverageOptions, Vitest } from 'vitest' +import type { + CoverageProvider, + CoverageProviderModule, + ResolvedCoverageOptions, + Vitest +} from 'vitest' const CustomCoverageProviderModule: CoverageProviderModule = { getProvider(): CoverageProvider { @@ -171,7 +176,7 @@ Please refer to the type definition for more details. When running a coverage report, a `coverage` folder is created in the root directory of your project. If you want to move it to a different directory, use the `test.coverage.reportsDirectory` property in the `vite.config.js` file. -```js twoslash +```js import { defineConfig } from 'vite' export default defineConfig({ diff --git a/docs/guide/environment.md b/docs/guide/environment.md index 88816518a91c..4da5f0ea4884 100644 --- a/docs/guide/environment.md +++ b/docs/guide/environment.md @@ -23,7 +23,7 @@ Since Vitest 2.0.4 the `require` of CSS and assets inside the external dependenc When setting `environment` option in your config, it will apply to all the test files in your project. To have more fine-grained control, you can use control comments to specify environment for specific files. Control comments are comments that start with `@vitest-environment` and are followed by the environment name: -```ts twoslash +```ts // @vitest-environment jsdom import { expect, test } from 'vitest' @@ -39,7 +39,7 @@ Or you can also set [`environmentMatchGlobs`](https://vitest.dev/config/#environ You can create your own package to extend Vitest environment. To do so, create package with the name `vitest-environment-${name}` or specify a path to a valid JS/TS file. That package should export an object with the shape of `Environment`: -```ts twoslash +```ts import type { Environment } from 'vitest' export default { @@ -75,7 +75,7 @@ Vitest requires `transformMode` option on environment object. It should be equal You also have access to default Vitest environments through `vitest/environments` entry: -```ts twoslash +```ts import { builtinEnvironments, populateGlobal } from 'vitest/environments' console.log(builtinEnvironments) // { jsdom, happy-dom, node, edge-runtime } diff --git a/docs/guide/features.md b/docs/guide/features.md index 5ea007d88c9d..b02be0e4d31d 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -34,7 +34,7 @@ Out-of-the-box ES Module / TypeScript / JSX support / PostCSS ## Threads -By default Vitest runs test files in multiple threads using [`node:worker_threads`](https://nodejs.org/api/worker_threads.html) via [Tinypool](https://github.com/tinylibs/tinypool) (a lightweight fork of [Piscina](https://github.com/piscinajs/piscina)), allowing tests to run simultaneously. If your tests are running code that is not compatible with multi-threading, you can switch to [`--pool=forks`](/config/#pool) which runs tests in multiple processes using [`node:child_process`](https://nodejs.org/api/child_process.html) via Tinypool. +By default Vitest runs test files in multiple processes using [`node:child_process`](https://nodejs.org/api/child_process.html) via [Tinypool](https://github.com/tinylibs/tinypool) (a lightweight fork of [Piscina](https://github.com/piscinajs/piscina)), allowing tests to run simultaneously. If you want to speed up your test suite even further, consider enabling `--pool=threads` to run tests using [`node:worker_threads`](https://nodejs.org/api/worker_threads.html) (beware that some packages might not work with this setup). To run tests in a single thread or process, see [`poolOptions`](/config/#pooloptions). @@ -48,12 +48,12 @@ Learn more about [Test Filtering](/guide/filtering). ## Running Tests Concurrently -Use `.concurrent` in consecutive tests to run them in parallel. +Use `.concurrent` in consecutive tests to start them in parallel. -```ts twoslash +```ts import { describe, it } from 'vitest' -// The two tests marked with concurrent will be run in parallel +// The two tests marked with concurrent will be started in parallel describe('suite', () => { it('serial test', async () => { /* ... */ }) it.concurrent('concurrent test 1', async ({ expect }) => { /* ... */ }) @@ -61,12 +61,12 @@ describe('suite', () => { }) ``` -If you use `.concurrent` on a suite, every test in it will be run in parallel. +If you use `.concurrent` on a suite, every test in it will be started in parallel. -```ts twoslash +```ts import { describe, it } from 'vitest' -// All tests within this suite will be run in parallel +// All tests within this suite will be started in parallel describe.concurrent('suite', () => { it('concurrent test 1', async ({ expect }) => { /* ... */ }) it('concurrent test 2', async ({ expect }) => { /* ... */ }) @@ -97,15 +97,15 @@ Learn more at [Snapshot](/guide/snapshot). ## Chai and Jest `expect` Compatibility -[Chai](https://www.chaijs.com/) is built-in for assertions plus [Jest `expect`](https://jestjs.io/docs/expect)-compatible APIs. +[Chai](https://www.chaijs.com/) is built-in for assertions with [Jest `expect`](https://jestjs.io/docs/expect)-compatible APIs. -Notice that if you are using third-party libraries that add matchers, setting `test.globals` to `true` will provide better compatibility. +Notice that if you are using third-party libraries that add matchers, setting [`test.globals`](/config/#globals) to `true` will provide better compatibility. ## Mocking [Tinyspy](https://github.com/tinylibs/tinyspy) is built-in for mocking with `jest`-compatible APIs on `vi` object. -```ts twoslash +```ts import { expect, vi } from 'vitest' const fn = vi.fn() @@ -122,7 +122,7 @@ fn('world', 2) expect(fn.mock.results[1].value).toBe('world') ``` -Vitest supports both [happy-dom](https://github.com/capricorn86/happy-dom) or [jsdom](https://github.com/jsdom/jsdom) for mocking DOM and browser APIs. They don't come with Vitest, you might need to install them: +Vitest supports both [happy-dom](https://github.com/capricorn86/happy-dom) or [jsdom](https://github.com/jsdom/jsdom) for mocking DOM and browser APIs. They don't come with Vitest, you will need to install them separately: ```bash $ npm i -D happy-dom @@ -132,7 +132,7 @@ $ npm i -D jsdom After that, change the `environment` option in your config file: -```ts twoslash +```ts // vitest.config.ts import { defineConfig } from 'vitest/config' @@ -170,7 +170,7 @@ This makes the tests share the same closure as the implementations and able to t // src/index.ts // the implementation -export function add(...args: number[]) { +export function add(...args: number[]): number { return args.reduce((a, b) => a + b, 0) } @@ -191,7 +191,7 @@ Learn more at [In-source testing](/guide/in-source). You can run benchmark tests with [`bench`](/api/#bench) function via [Tinybench](https://github.com/tinylibs/tinybench) to compare performance results. -```ts twoslash +```ts import { bench, describe } from 'vitest' describe('sort', () => { @@ -219,7 +219,7 @@ describe('sort', () => { You can [write tests](/guide/testing-types) to catch type regressions. Vitest comes with [`expect-type`](https://github.com/mmkal/expect-type) package to provide you with a similar and easy to understand API. ```ts -import { assertType, expectTypeOf } from 'vitest' +import { assertType, expectTypeOf, test } from 'vitest' import { mount } from './mount.js' test('my types work properly', () => { @@ -248,7 +248,7 @@ See [`Improving Performance | Sharding`](/guide/improving-performance#sharding) Vitest exclusively autoloads environment variables prefixed with `VITE_` from `.env` files to maintain compatibility with frontend-related tests, adhering to [Vite's established convention](https://vitejs.dev/guide/env-and-mode.html#env-files). To load every environmental variable from `.env` files anyway, you can use `loadEnv` method imported from `vite`: -```ts twoslash +```ts import { loadEnv } from 'vite' import { defineConfig } from 'vitest/config' @@ -258,3 +258,4 @@ export default defineConfig(({ mode }) => ({ env: loadEnv(mode, process.cwd(), ''), }, })) +``` diff --git a/docs/guide/filtering.md b/docs/guide/filtering.md index bc11d553aa66..462d3cf95674 100644 --- a/docs/guide/filtering.md +++ b/docs/guide/filtering.md @@ -28,7 +28,7 @@ You can also use the `-t, --testNamePattern ` option to filter tests by You can optionally pass a timeout in milliseconds as third argument to tests. The default is 5 seconds. -```ts twoslash +```ts import { test } from 'vitest' test('name', async () => { /* ... */ }, 1000) @@ -36,7 +36,7 @@ test('name', async () => { /* ... */ }, 1000) Hooks also can receive a timeout, with the same 5 seconds default. -```ts twoslash +```ts import { beforeAll } from 'vitest' beforeAll(async () => { /* ... */ }, 1000) @@ -46,7 +46,7 @@ beforeAll(async () => { /* ... */ }, 1000) Use `.skip` to avoid running certain suites or tests -```ts twoslash +```ts import { assert, describe, it } from 'vitest' describe.skip('skipped suite', () => { @@ -68,7 +68,7 @@ describe('suite', () => { Use `.only` to only run certain suites or tests -```ts twoslash +```ts import { assert, describe, it } from 'vitest' // Only this suite (and others marked with only) are run @@ -95,7 +95,7 @@ describe('another suite', () => { Use `.todo` to stub suites and tests that should be implemented -```ts twoslash +```ts import { describe, it } from 'vitest' // An entry will be shown in the report for this suite diff --git a/docs/guide/index.md b/docs/guide/index.md index db73d4011bdd..e3a87fe605b3 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -34,7 +34,7 @@ bun add -D vitest ::: :::tip -Vitest 1.0 requires Vite >=v5.0.0 and Node >=v18.0.0 +Vitest requires Vite >=v5.0.0 and Node >=v18.0.0 ::: It is recommended that you install a copy of `vitest` in your `package.json`, using one of the methods listed above. However, if you would prefer to run `vitest` directly, you can use `npx vitest` (the `npx` tool comes with npm and Node.js). @@ -55,7 +55,7 @@ export function sum(a, b) { ``` js // sum.test.js import { expect, test } from 'vitest' -import { sum } from './sum' +import { sum } from './sum.js' test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3) @@ -76,18 +76,22 @@ Next, in order to execute the test, add the following section to your `package.j } ``` -Finally, run `npm run test`, `yarn test`, or `pnpm test`, depending on your package manager, and Vitest will print this message: +Finally, run `npm run test`, `yarn test` or `pnpm test`, depending on your package manager, and Vitest will print this message: ```txt ✓ sum.test.js (1) ✓ adds 1 + 2 to equal 3 Test Files 1 passed (1) - Tests 1 passed (1) + Tests 1 passed (1) Start at 02:15:44 Duration 311ms ``` +::: warning +If you are using Bun as your package manager, make sure to use `bun run test` command instead of `bun test`, otherwise Bun will run its own test runner. +::: + Learn more about the usage of Vitest, see the [API](https://vitest.dev/api/) section. ## Configuring Vitest @@ -102,7 +106,7 @@ Vitest supports the same extensions for your configuration file as Vite does: `. If you are not using Vite as your build tool, you can configure Vitest using the `test` property in your config file: -```ts twoslash +```ts import { defineConfig } from 'vitest/config' export default defineConfig({ @@ -142,7 +146,7 @@ import viteConfig from './vite.config.mjs' export default mergeConfig(viteConfig, defineConfig({ test: { // ... - } + }, })) ``` @@ -155,14 +159,14 @@ export default defineConfig({ }) ``` -But we recommend to use the same file for both Vite and Vitest instead of creating two separate files. +However, we recommend using the same file for both Vite and Vitest, instead of creating two separate files. ::: ## Workspaces Support Run different project configurations inside the same project with [Vitest Workspaces](/guide/workspace). You can define a list of files and folders that define your workspace in `vitest.workspace` file. The file supports `js`/`ts`/`json` extensions. This feature works great with monorepo setups. -```ts twoslash +```ts import { defineWorkspace } from 'vitest/config' export default defineWorkspace([ diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 8083b68b1344..b0d4055eec74 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -335,7 +335,7 @@ server.deps.inline: ["lib-name"] Vitest's `test` names are joined with a `>` symbol to make it easier to distinguish tests from suites, while Jest uses an empty space (` `). -``` +```diff - `${describeTitle} ${testTitle}` + `${describeTitle} > ${testTitle}` ``` @@ -409,9 +409,8 @@ vi.setConfig({ testTimeout: 5_000 }) // [!code ++] This is not a Jest-specific feature, but if you previously were using Jest with vue-cli preset, you will need to install [`jest-serializer-vue`](https://github.com/eddyerburgh/jest-serializer-vue) package, and use it inside [setupFiles](/config/#setupfiles): -`vite.config.js` - -```js twoslash +:::code-group +```js [vite.config.js] import { defineConfig } from 'vite' export default defineConfig({ @@ -420,13 +419,11 @@ export default defineConfig({ } }) ``` - -`tests/unit/setup.js` - -```js +```js [tests/unit/setup.js] import vueSnapshotSerializer from 'jest-serializer-vue' expect.addSnapshotSerializer(vueSnapshotSerializer) ``` +::: Otherwise your snapshots will have a lot of escaped `"` characters. diff --git a/docs/guide/mocking.md b/docs/guide/mocking.md index 604913bcc371..fb841dc839ed 100644 --- a/docs/guide/mocking.md +++ b/docs/guide/mocking.md @@ -18,7 +18,7 @@ Sometimes you need to be in control of the date to ensure consistency when testi ### Example -```js twoslash +```js import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const businessHours = [9, 17] @@ -77,7 +77,7 @@ We use [Tinyspy](https://github.com/tinylibs/tinyspy) as a base for mocking func ### Example -```js twoslash +```js import { afterEach, describe, expect, it, vi } from 'vitest' const messages = { @@ -138,7 +138,7 @@ describe('reading messages', () => { You can mock global variables that are not present with `jsdom` or `node` by using [`vi.stubGlobal`](/api/vi#vi-stubglobal) helper. It will put the value of the global variable into a `globalThis` object. -```ts twoslash +```ts import { vi } from 'vitest' const IntersectionObserverMock = vi.fn(() => ({ @@ -256,7 +256,7 @@ export function foo() { } export function foobar(injectedFoo) { - return injectedFoo !== foo // false + return injectedFoo === foo // false } ``` @@ -383,11 +383,11 @@ module.exports = fs.promises ::: ```ts -// hello-world.js +// read-hello-world.js import { readFileSync } from 'node:fs' export function readHelloWorld(path) { - return readFileSync('./hello-world.txt') + return readFileSync(path) } ``` @@ -395,7 +395,7 @@ export function readHelloWorld(path) { // hello-world.test.js import { beforeEach, expect, it, vi } from 'vitest' import { fs, vol } from 'memfs' -import { readHelloWorld } from './hello-world.js' +import { readHelloWorld } from './read-hello-world.js' // tell vitest to use fs mock from __mocks__ folder // this can be done in a setup file if fs should always be mocked @@ -408,7 +408,7 @@ beforeEach(() => { }) it('should return correct text', () => { - const path = './hello-world.txt' + const path = '/hello-world.txt' fs.writeFileSync(path, 'hello world') const text = readHelloWorld(path) @@ -423,7 +423,7 @@ it('can return a value multiple times', () => { './dir2/hw.txt': 'hello dir2', }, // default cwd - '/tmp' + '/tmp', ) expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1') @@ -440,7 +440,7 @@ Mock Service Worker (MSW) works by intercepting the requests your tests make, al ### Configuration You can use it like below in your [setup file](/config/#setupfiles) -```js twoslash +```js import { afterAll, afterEach, beforeAll } from 'vitest' import { setupServer } from 'msw/node' import { HttpResponse, graphql, http } from 'msw' @@ -496,7 +496,7 @@ See the [`vi.useFakeTimers` API section](/api/vi#vi-usefaketimers) for a more in ### Example -```js twoslash +```js import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' function executeAfterTwoHours(func) { @@ -759,9 +759,9 @@ it('the value is restored before running an other test', () => { ```ts // vitest.config.ts -export default { +export default defineConfig({ test: { unstubAllEnvs: true, } -} +}) ``` diff --git a/docs/guide/reporters.md b/docs/guide/reporters.md index 28399a03f532..70907c03c23d 100644 --- a/docs/guide/reporters.md +++ b/docs/guide/reporters.md @@ -15,7 +15,7 @@ npx vitest --reporter=verbose Using reporters via [`vitest.config.ts`](/config/): -```ts twoslash +```ts /// import { defineConfig } from 'vite' @@ -81,10 +81,12 @@ When using multiple reporters, it's also possible to designate multiple output f ```ts export default defineConfig({ - reporters: ['junit', 'json', 'verbose'], - outputFile: { - junit: './junit-report.xml', - json: './json-report.json', + test: { + reporters: ['junit', 'json', 'verbose'], + outputFile: { + junit: './junit-report.xml', + json: './json-report.json', + }, }, }) ``` @@ -311,7 +313,8 @@ Example of a JSON report: "location": { "line": 20, "column": 28 - } + }, + "meta": {} } ], "startTime": 1697737019787, diff --git a/docs/guide/snapshot.md b/docs/guide/snapshot.md index 756a5a64b874..906cd231d979 100644 --- a/docs/guide/snapshot.md +++ b/docs/guide/snapshot.md @@ -14,11 +14,7 @@ When using snapshot, Vitest will take a snapshot of the given value, then compar To snapshot a value, you can use the [`toMatchSnapshot()`](/api/expect#tomatchsnapshot) from `expect()` API: -```ts twoslash -function toUpperCase(str: string) { - return str -} -// ---cut--- +```ts import { expect, it } from 'vitest' it('toUpperCase', () => { @@ -45,11 +41,7 @@ When using Snapshots with async concurrent tests, `expect` from the local [Test Similarly, you can use the [`toMatchInlineSnapshot()`](/api/expect#tomatchinlinesnapshot) to store the snapshot inline within the test file. -```ts twoslash -function toUpperCase(str: string) { - return str -} -// ---cut--- +```ts import { expect, it } from 'vitest' it('toUpperCase', () => { @@ -60,11 +52,7 @@ it('toUpperCase', () => { Instead of creating a snapshot file, Vitest will modify the test file directly to update the snapshot as a string: -```ts twoslash -function toUpperCase(str: string) { - return str -} -// ---cut--- +```ts import { expect, it } from 'vitest' it('toUpperCase', () => { @@ -95,7 +83,7 @@ vitest -u When calling `toMatchSnapshot()`, we store all snapshots in a formatted snap file. That means we need to escape some characters (namely the double-quote `"` and backtick `` ` ``) in the snapshot string. Meanwhile, you might lose the syntax highlighting for the snapshot content (if they are in some language). -To improve this case, we introduce [`toMatchFileSnapshot()`](/api/expect#tomatchfilesnapshot) to explicitly snapshot in a file. This allows you to assign any file extension to the snapshot file, and making them more readable. +In light of this, we introduced [`toMatchFileSnapshot()`](/api/expect#tomatchfilesnapshot) to explicitly match against a file. This allows you to assign any file extension to the snapshot file, and makes them more readable. ```ts import { expect, it } from 'vitest' @@ -222,7 +210,7 @@ This does not really affect the functionality but might affect your commit diff Both Jest and Vitest's snapshots are powered by [`pretty-format`](https://github.com/facebook/jest/blob/main/packages/pretty-format). In Vitest we set `printBasicPrototype` default to `false` to provide a cleaner snapshot output, while in Jest <29.0.0 it's `true` by default. -```ts twoslash +```ts import { expect, test } from 'vitest' test('snapshot', () => { @@ -290,29 +278,18 @@ exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`; #### 4. default `Error` snapshot is different for `toThrowErrorMatchingSnapshot` and `toThrowErrorMatchingInlineSnapshot` -```js twoslash +```js import { expect, test } from 'vitest' -// ---cut--- -test('snapshot', () => { - // - // in Jest - // +test('snapshot', () => { + // in Jest and Vitest expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`) // Jest snapshots `Error.message` for `Error` instance + // Vitest prints the same value as toMatchInlineSnapshot expect(() => { throw new Error('error') - }).toThrowErrorMatchingInlineSnapshot(`"error"`) - - // - // in Vitest - // - - expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`) - - expect(() => { - throw new Error('error') - }).toThrowErrorMatchingInlineSnapshot(`[Error: error]`) + }).toThrowErrorMatchingInlineSnapshot(`"error"`) // [!code --] + }).toThrowErrorMatchingInlineSnapshot(`[Error: error]`) // [!code ++] }) ``` diff --git a/docs/guide/test-context.md b/docs/guide/test-context.md index 88dd8e0930d0..ea5f483dc78d 100644 --- a/docs/guide/test-context.md +++ b/docs/guide/test-context.md @@ -10,7 +10,7 @@ Inspired by [Playwright Fixtures](https://playwright.dev/docs/test-fixtures), Vi The first argument for each test callback is a test context. -```ts twoslash +```ts import { it } from 'vitest' it('should work', (ctx) => { @@ -29,7 +29,7 @@ A readonly object containing metadata about the test. The `expect` API bound to the current test: -```ts twoslash +```ts import { it } from 'vitest' it('math is easy', ({ expect }) => { @@ -39,7 +39,7 @@ it('math is easy', ({ expect }) => { This API is useful for running snapshot tests concurrently because global expect cannot track them: -```ts twoslash +```ts import { it } from 'vitest' it.concurrent('math is easy', ({ expect }) => { diff --git a/docs/guide/workspace.md b/docs/guide/workspace.md index 70818b605ca1..c52c1fd1cc5f 100644 --- a/docs/guide/workspace.md +++ b/docs/guide/workspace.md @@ -51,7 +51,7 @@ If you are referencing filenames with glob pattern, make sure your config file s You can also define projects with inline config. Workspace file supports using both syntaxes at the same time. :::code-group -```ts [vitest.workspace.ts] twoslash +```ts [vitest.workspace.ts] import { defineWorkspace } from 'vitest/config' // defineWorkspace provides a nice type hinting DX @@ -96,6 +96,7 @@ Workspace projects don't support all configuration properties. For better type s :::code-group ```ts [packages/a/vitest.config.ts] twoslash +// @errors: 2769 import { defineProject } from 'vitest/config' export default defineProject({ @@ -156,7 +157,7 @@ npm run test --project e2e --project unit None of the configuration options are inherited from the root-level config file. You can create a shared config file and merge it with the project config yourself: -:::code-group +::: code-group ```ts [packages/a/vitest.config.ts] import { defineProject, mergeConfig } from 'vitest/config' import configShared from '../vitest.shared.js' @@ -172,6 +173,30 @@ export default mergeConfig( ``` ::: +At the `defineWorkspace` level you can also use the `extends` option instead to inherit from your root-level config. +::: code-group +```ts [packages/a/vitest.config.ts] +import { defineWorkspace } from 'vitest/config' + +export default defineWorkspace([ + { + extends: './vitest.config.ts', + test: { + name: 'unit', + include: ['**/*.unit.test.ts'], + }, + }, + { + extends: './vitest.config.ts', + test: { + name: 'integration', + include: ['**/*.integration.test.ts'], + }, + }, +]) +``` +::: + Also, some of the configuration options are not allowed in a project config. Most notably: - `coverage`: coverage is done for the whole workspace diff --git a/docs/package.json b/docs/package.json index eec305b69e57..4a100b3c9b96 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,20 +15,20 @@ }, "dependencies": { "@vueuse/core": "^10.11.0", - "vue": "^3.4.31" + "vue": "^3.4.33" }, "devDependencies": { "@iconify-json/carbon": "^1.1.36", "@iconify-json/logos": "^1.1.43", - "@shikijs/vitepress-twoslash": "^1.10.3", - "@unocss/reset": "^0.61.3", + "@shikijs/vitepress-twoslash": "^1.11.0", + "@unocss/reset": "^0.61.5", "@vite-pwa/assets-generator": "^0.2.4", "@vite-pwa/vitepress": "^0.5.0", - "@vitejs/plugin-vue": "latest", + "@vitejs/plugin-vue": "^5.0.5", "fast-glob": "^3.3.2", "https-localhost": "^4.7.1", - "unocss": "^0.61.3", - "unplugin-vue-components": "^0.27.2", + "unocss": "^0.61.5", + "unplugin-vue-components": "^0.27.3", "vite": "^5.2.8", "vite-plugin-pwa": "^0.20.0", "vitepress": "^1.3.1", diff --git a/eslint.config.js b/eslint.config.js index 6d2c55325d3e..9e6d32aedb35 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -26,6 +26,8 @@ export default antfu( 'examples/**/mockServiceWorker.js', 'examples/sveltekit/.svelte-kit', 'packages/browser/**/esm-client-injector.js', + // contains technically invalid code to display pretty diff + 'docs/guide/snapshot.md', ], }, { diff --git a/netlify.toml b/netlify.toml index e7848797fbad..29eeea9bced9 100755 --- a/netlify.toml +++ b/netlify.toml @@ -1,7 +1,7 @@ [build] publish = "docs/.vitepress/dist" command = "pnpm ci:docs" -ignore = "git diff --quiet $COMMIT_REF $CACHED_COMMIT_REF -- docs/ package.json pnpm-lock.yaml" +ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF docs/ package.json pnpm-lock.yaml" [build.environment] NODE_VERSION = "20" diff --git a/package.json b/package.json index 91e6f68f4326..4362c3acb334 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@vitest/monorepo", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "private": true, - "packageManager": "pnpm@9.5.0", + "packageManager": "pnpm@9.6.0", "description": "Next generation testing framework powered by Vite", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -36,13 +36,13 @@ "test:browser:playwright": "pnpm -C test/browser run test:playwright" }, "devDependencies": { - "@antfu/eslint-config": "^2.22.2", + "@antfu/eslint-config": "^2.23.2", "@antfu/ni": "^0.22.0", - "@playwright/test": "^1.45.1", + "@playwright/test": "^1.45.3", "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.2.3", - "@types/node": "^20.14.10", + "@types/node": "^20.14.11", "@types/ws": "^8.5.11", "@vitest/browser": "workspace:*", "@vitest/coverage-istanbul": "workspace:*", @@ -55,18 +55,19 @@ "magic-string": "^0.30.10", "pathe": "^1.1.2", "rimraf": "^6.0.1", - "rollup": "^4.18.1", + "rollup": "^4.19.0", "rollup-plugin-dts": "^6.1.1", "rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-license": "^3.5.2", "tsx": "^4.16.2", - "typescript": "^5.5.3", + "typescript": "^5.5.4", "vite": "^5.3.3", "vitest": "workspace:*", "zx": "^8.1.4" }, "pnpm": { "overrides": { + "acorn": "8.11.3", "mlly": "^1.7.1", "rollup": "$rollup", "vite": "$vite", diff --git a/packages/browser/context.d.ts b/packages/browser/context.d.ts index 167af84420ab..6f755e3aa260 100644 --- a/packages/browser/context.d.ts +++ b/packages/browser/context.d.ts @@ -1,4 +1,4 @@ -import type { ResolvedConfig } from 'vitest' +import type { SerializedConfig } from 'vitest' export type BufferEncoding = | 'ascii' @@ -49,6 +49,14 @@ export interface BrowserCommands { } export interface UserEvent { + /** + * Creates a new user event instance. This is useful if you need to keep the + * state of keyboard to press and release buttons correctly. + * + * **Note:** Unlike `@testing-library/user-event`, the default `userEvent` instance + * from `@vitest/browser/context` is created once, not every time its methods are called! + * @see {@link https://vitest.dev/guide/browser/interactivity-api.html#userevent-setup} + */ setup: () => UserEvent /** * Click on an element. Uses provider's API under the hood and supports all its options. @@ -103,7 +111,7 @@ export interface UserEvent { * await userEvent.keyboard('foo') // translates to: f, o, o * await userEvent.keyboard('{{a[[') // translates to: {, a, [ * await userEvent.keyboard('{Shift}{f}{o}{o}') // translates to: Shift, f, o, o - * @see {@link https://playwright.dev/docs/api/class-locator#locator-press} Playwright API + * @see {@link https://playwright.dev/docs/api/class-keyboard} Playwright API * @see {@link https://webdriver.io/docs/api/browser/keys} WebdriverIO API * @see {@link https://testing-library.com/docs/user-event/keyboard} testing-library API */ @@ -129,7 +137,7 @@ export interface UserEvent { clear: (element: Element) => Promise /** * Sends a `Tab` key event. Uses provider's API under the hood. - * @see {@link https://playwright.dev/docs/api/class-locator#locator-press} Playwright API + * @see {@link https://playwright.dev/docs/api/class-keyboard} Playwright API * @see {@link https://webdriver.io/docs/api/element/keys} WebdriverIO API * @see {@link https://testing-library.com/docs/user-event/convenience/#tab} testing-library API */ @@ -245,7 +253,7 @@ export interface BrowserPage { /** * Serialized test config. */ - config: ResolvedConfig + config: SerializedConfig /** * Change the size of iframe's viewport. */ diff --git a/packages/browser/package.json b/packages/browser/package.json index cec5746b957b..c6bf26de619f 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/browser", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Browser running for Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", @@ -76,16 +76,16 @@ } }, "dependencies": { - "@testing-library/dom": "^10.3.1", + "@testing-library/dom": "^10.4.0", "@testing-library/user-event": "^14.5.2", "@vitest/utils": "workspace:*", "magic-string": "^0.30.10", - "msw": "^2.3.1", + "msw": "^2.3.2", "sirv": "^2.0.4", "ws": "^8.18.0" }, "devDependencies": { - "@testing-library/jest-dom": "^6.4.6", + "@testing-library/jest-dom": "^6.4.7", "@types/ws": "^8.5.11", "@vitest/runner": "workspace:*", "@vitest/ui": "workspace:*", @@ -95,8 +95,8 @@ "flatted": "^3.3.1", "pathe": "^1.1.2", "periscopic": "^4.0.2", - "playwright": "^1.45.1", - "playwright-core": "^1.45.1", + "playwright": "^1.45.3", + "playwright-core": "^1.45.3", "safaridriver": "^0.1.2", "vitest": "workspace:*", "webdriverio": "^8.39.1" diff --git a/packages/browser/rollup.config.js b/packages/browser/rollup.config.js index 64987eb9cb74..f846fb865e0b 100644 --- a/packages/browser/rollup.config.js +++ b/packages/browser/rollup.config.js @@ -43,7 +43,22 @@ export default () => format: 'esm', }, external, - plugins, + plugins: [ + { + name: 'no-side-effects', + async resolveId(id, importer) { + // Clipboard injects "afterEach" callbacks + // We mark it as having no side effects to prevent it from being included in the bundle + if (id.includes('dataTransfer/Clipboard')) { + return { + ...await this.resolve(id, importer), + moduleSideEffects: false, + } + } + }, + }, + ...plugins, + ], }, { input: './src/client/tester/context.ts', diff --git a/packages/browser/src/client/orchestrator.ts b/packages/browser/src/client/orchestrator.ts index 589856491dd2..975048373c40 100644 --- a/packages/browser/src/client/orchestrator.ts +++ b/packages/browser/src/client/orchestrator.ts @@ -1,8 +1,8 @@ -import type { ResolvedConfig } from 'vitest' import { channel, client } from '@vitest/browser/client' import { generateHash } from '@vitest/runner/utils' import { type GlobalChannelIncomingEvent, type IframeChannelEvent, type IframeChannelIncomingEvent, globalChannel } from '@vitest/browser/client' import { relative } from 'pathe' +import type { SerializedConfig } from 'vitest' import { getBrowserState, getConfig } from './utils' import { getUiAPI } from './ui' import { createModuleMocker } from './tester/msw' @@ -230,7 +230,7 @@ async function done() { await client.rpc.finishBrowserTests(getBrowserState().contextId) } -async function getContainer(config: ResolvedConfig): Promise { +async function getContainer(config: SerializedConfig): Promise { if (config.browser.ui) { const element = document.querySelector('#tester-ui') if (!element) { diff --git a/packages/browser/src/client/tester/context.ts b/packages/browser/src/client/tester/context.ts index b23d36df426e..54bf7847044b 100644 --- a/packages/browser/src/client/tester/context.ts +++ b/packages/browser/src/client/tester/context.ts @@ -1,6 +1,6 @@ import type { Task, WorkerGlobalState } from 'vitest' import type { BrowserRPC } from '@vitest/browser/client' -import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context' +import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventHoverOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context' import type { BrowserRunnerState } from '../utils' // this file should not import anything directly, only types @@ -32,6 +32,36 @@ function convertElementToCssSelector(element: Element) { return getUniqueCssSelector(element) } +function escapeIdForCSSSelector(id: string) { + return id + .split('') + .map((char) => { + const code = char.charCodeAt(0) + + if (char === ' ' || char === '#' || char === '.' || char === ':' || char === '[' || char === ']' || char === '>' || char === '+' || char === '~' || char === '\\') { + // Escape common special characters with backslashes + return `\\${char}` + } + else if (code >= 0x10000) { + // Unicode escape for characters outside the BMP + return `\\${code.toString(16).toUpperCase().padStart(6, '0')} ` + } + else if (code < 0x20 || code === 0x7F) { + // Non-printable ASCII characters (0x00-0x1F and 0x7F) are escaped + return `\\${code.toString(16).toUpperCase().padStart(2, '0')} ` + } + else if (code >= 0x80) { + // Non-ASCII characters (0x80 and above) are escaped + return `\\${code.toString(16).toUpperCase().padStart(2, '0')} ` + } + else { + // Allowable characters are used directly + return char + } + }) + .join('') +} + function getUniqueCssSelector(el: Element) { const path = [] let parent: null | ParentNode @@ -44,10 +74,10 @@ function getUniqueCssSelector(el: Element) { const tag = el.tagName if (el.id) { - path.push(`#${el.id}`) + path.push(`#${escapeIdForCSSSelector(el.id)}`) } else if (!el.nextElementSibling && !el.previousElementSibling) { - path.push(tag) + path.push(tag.toLowerCase()) } else { let index = 0 @@ -65,15 +95,15 @@ function getUniqueCssSelector(el: Element) { } if (sameTagSiblings > 1) { - path.push(`${tag}:nth-child(${elementIndex})`) + path.push(`${tag.toLowerCase()}:nth-child(${elementIndex})`) } else { - path.push(tag) + path.push(tag.toLowerCase()) } } el = parent as Element }; - return `${provider === 'webdriverio' && hasShadowRoot ? '>>>' : ''}${path.reverse().join(' > ')}`.toLowerCase() + return `${provider === 'webdriverio' && hasShadowRoot ? '>>>' : ''}${path.reverse().join(' > ')}` } function getParent(el: Element) { @@ -84,65 +114,83 @@ function getParent(el: Element) { return parent } -export const userEvent: UserEvent = { - // TODO: actually setup userEvent with config options - setup() { - return userEvent - }, - click(element: Element, options: UserEventClickOptions = {}) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_click', css, options) - }, - dblClick(element: Element, options: UserEventClickOptions = {}) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_dblClick', css, options) - }, - tripleClick(element: Element, options: UserEventClickOptions = {}) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_tripleClick', css, options) - }, - selectOptions(element, value) { - const values = provider === 'webdriverio' - ? getWebdriverioSelectOptions(element, value) - : getSimpleSelectOptions(element, value) - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_selectOptions', css, values) - }, - type(element: Element, text: string, options: UserEventTypeOptions = {}) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_type', css, text, options) - }, - clear(element: Element) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_clear', css) - }, - tab(options: UserEventTabOptions = {}) { - return triggerCommand('__vitest_tab', options) - }, - keyboard(text: string) { - return triggerCommand('__vitest_keyboard', text) - }, - hover(element: Element) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_hover', css) - }, - unhover(element: Element) { - const css = convertElementToCssSelector(element.ownerDocument.body) - return triggerCommand('__vitest_hover', css) - }, +function createUserEvent(): UserEvent { + const keyboard = { + unreleased: [] as string[], + } - // non userEvent events, but still useful - fill(element: Element, text: string, options) { - const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_fill', css, text, options) - }, - dragAndDrop(source: Element, target: Element, options = {}) { - const sourceCss = convertElementToCssSelector(source) - const targetCss = convertElementToCssSelector(target) - return triggerCommand('__vitest_dragAndDrop', sourceCss, targetCss, options) - }, + return { + setup() { + return createUserEvent() + }, + click(element: Element, options: UserEventClickOptions = {}) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_click', css, options) + }, + dblClick(element: Element, options: UserEventClickOptions = {}) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_dblClick', css, options) + }, + tripleClick(element: Element, options: UserEventClickOptions = {}) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_tripleClick', css, options) + }, + selectOptions(element, value) { + const values = provider === 'webdriverio' + ? getWebdriverioSelectOptions(element, value) + : getSimpleSelectOptions(element, value) + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_selectOptions', css, values) + }, + async type(element: Element, text: string, options: UserEventTypeOptions = {}) { + const css = convertElementToCssSelector(element) + const { unreleased } = await triggerCommand<{ unreleased: string[] }>( + '__vitest_type', + css, + text, + { ...options, unreleased: keyboard.unreleased }, + ) + keyboard.unreleased = unreleased + }, + clear(element: Element) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_clear', css) + }, + tab(options: UserEventTabOptions = {}) { + return triggerCommand('__vitest_tab', options) + }, + async keyboard(text: string) { + const { unreleased } = await triggerCommand<{ unreleased: string[] }>( + '__vitest_keyboard', + text, + keyboard, + ) + keyboard.unreleased = unreleased + }, + hover(element: Element, options: UserEventHoverOptions = {}) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_hover', css, options) + }, + unhover(element: Element, options: UserEventHoverOptions = {}) { + const css = convertElementToCssSelector(element.ownerDocument.body) + return triggerCommand('__vitest_hover', css, options) + }, + + // non userEvent events, but still useful + fill(element: Element, text: string, options) { + const css = convertElementToCssSelector(element) + return triggerCommand('__vitest_fill', css, text, options) + }, + dragAndDrop(source: Element, target: Element, options = {}) { + const sourceCss = convertElementToCssSelector(source) + const targetCss = convertElementToCssSelector(target) + return triggerCommand('__vitest_dragAndDrop', sourceCss, targetCss, options) + }, + } } +export const userEvent: UserEvent = createUserEvent() + function getWebdriverioSelectOptions(element: Element, value: string | string[] | HTMLElement[] | HTMLElement) { const options = [...element.querySelectorAll('option')] as HTMLOptionElement[] diff --git a/packages/browser/src/client/tester/mocker.ts b/packages/browser/src/client/tester/mocker.ts index 7b6dd34dee53..b5f95f4c3657 100644 --- a/packages/browser/src/client/tester/mocker.ts +++ b/packages/browser/src/client/tester/mocker.ts @@ -59,12 +59,19 @@ export class VitestBrowserClientMocker { ) } const ext = extname(resolved.id) - const url = new URL(`/@id/${resolved.id}`, location.href) - const query = `_vitest_original&ext.${ext}` + const url = new URL(resolved.url, location.href) + const query = `_vitest_original&ext${ext}` const actualUrl = `${url.pathname}${ url.search ? `${url.search}&${query}` : `?${query}` }${url.hash}` - return getBrowserState().wrapModule(() => import(/* @vite-ignore */ actualUrl)) + return getBrowserState().wrapModule(() => import(/* @vite-ignore */ actualUrl)).then((mod) => { + if (!resolved.optimized || typeof mod.default === 'undefined') { + return mod + } + // vite injects this helper for optimized modules, so we try to follow the same behavior + const m = mod.default + return m?.__esModule ? m : { ...((typeof m === 'object' && !Array.isArray(m)) || typeof m === 'function' ? m : {}), default: m } + }) } public async importMock(rawId: string, importer: string) { diff --git a/packages/browser/src/client/tester/runner.ts b/packages/browser/src/client/tester/runner.ts index ff4212c73ff2..90eab69ce85a 100644 --- a/packages/browser/src/client/tester/runner.ts +++ b/packages/browser/src/client/tester/runner.ts @@ -1,5 +1,5 @@ import type { CancelReason, File, Suite, Task, TaskResultPack, VitestRunner } from '@vitest/runner' -import type { ResolvedConfig, WorkerGlobalState } from 'vitest' +import type { SerializedConfig, WorkerGlobalState } from 'vitest' import type { VitestExecutor } from 'vitest/execute' import { NodeBenchmarkRunner, VitestTestRunner } from 'vitest/runners' import { loadDiffConfig, loadSnapshotSerializers, takeCoverageInsideWorker } from 'vitest/browser' @@ -12,7 +12,7 @@ import { rpc } from './rpc' import type { VitestBrowserClientMocker } from './mocker' interface BrowserRunnerOptions { - config: ResolvedConfig + config: SerializedConfig } export const browserHashMap = new Map< @@ -25,13 +25,13 @@ interface CoverageHandler { } export function createBrowserRunner( - runnerClass: { new (config: ResolvedConfig): VitestRunner }, + runnerClass: { new (config: SerializedConfig): VitestRunner }, mocker: VitestBrowserClientMocker, state: WorkerGlobalState, coverageModule: CoverageHandler | null, ): { new (options: BrowserRunnerOptions): VitestRunner } { return class BrowserTestRunner extends runnerClass implements VitestRunner { - public config: ResolvedConfig + public config: SerializedConfig hashMap = browserHashMap public sourceMapCache = new Map() @@ -140,7 +140,7 @@ let cachedRunner: VitestRunner | null = null export async function initiateRunner( state: WorkerGlobalState, mocker: VitestBrowserClientMocker, - config: ResolvedConfig, + config: SerializedConfig, ) { if (cachedRunner) { return cachedRunner diff --git a/packages/browser/src/client/utils.ts b/packages/browser/src/client/utils.ts index 457cb495bd1f..01480e6620c4 100644 --- a/packages/browser/src/client/utils.ts +++ b/packages/browser/src/client/utils.ts @@ -1,4 +1,4 @@ -import type { ResolvedConfig, WorkerGlobalState } from 'vitest' +import type { SerializedConfig, WorkerGlobalState } from 'vitest' export async function importId(id: string) { const name = `/@id/${id}`.replace(/\\/g, '/') @@ -10,7 +10,7 @@ export async function importFs(id: string) { return getBrowserState().wrapModule(() => import(/* @vite-ignore */ name)) } -export function getConfig(): ResolvedConfig { +export function getConfig(): SerializedConfig { return getBrowserState().config } @@ -18,7 +18,7 @@ export interface BrowserRunnerState { files: string[] runningFiles: string[] moduleCache: WorkerGlobalState['moduleCache'] - config: ResolvedConfig + config: SerializedConfig provider: string viteConfig: { root: string diff --git a/packages/browser/src/node/commands/keyboard.ts b/packages/browser/src/node/commands/keyboard.ts index 08fd74292e28..ec3fe9a24f38 100644 --- a/packages/browser/src/node/commands/keyboard.ts +++ b/packages/browser/src/node/commands/keyboard.ts @@ -3,12 +3,16 @@ import { defaultKeyMap } from '@testing-library/user-event/dist/esm/keyboard/key import type { BrowserProvider } from 'vitest/node' import { PlaywrightBrowserProvider } from '../providers/playwright' import { WebdriverBrowserProvider } from '../providers/webdriver' -import type { UserEvent } from '../../../context' import type { UserEventCommand } from './utils' -export const keyboard: UserEventCommand = async ( +export interface KeyboardState { + unreleased: string[] +} + +export const keyboard: UserEventCommand<(text: string, state: KeyboardState) => Promise<{ unreleased: string[] }>> = async ( context, text, + state, ) => { function focusIframe() { if ( @@ -28,7 +32,10 @@ export const keyboard: UserEventCommand = async ( await context.browser.execute(focusIframe) } + const pressed = new Set(state.unreleased) + await keyboardImplementation( + pressed, context.provider, context.contextId, text, @@ -52,17 +59,20 @@ export const keyboard: UserEventCommand = async ( }, true, ) + + return { + unreleased: Array.from(pressed), + } } export async function keyboardImplementation( + pressed: Set, provider: BrowserProvider, contextId: string, text: string, selectAll: () => Promise, skipRelease: boolean, ) { - const pressed = new Set() - if (provider instanceof PlaywrightBrowserProvider) { const page = provider.getPage(contextId) const actions = parseKeyDef(defaultKeyMap, text) @@ -145,7 +155,10 @@ export async function keyboardImplementation( } } - await keyboard.perform(skipRelease) + // seems like webdriverio doesn't release keys automatically if skipRelease is true and all events are keyUp + const allRelease = keyboard.toJSON().actions.every(action => action.type === 'keyUp') + + await keyboard.perform(allRelease ? false : skipRelease) } return { diff --git a/packages/browser/src/node/commands/screenshot.ts b/packages/browser/src/node/commands/screenshot.ts index d81b0932b7d9..6426a5650689 100644 --- a/packages/browser/src/node/commands/screenshot.ts +++ b/packages/browser/src/node/commands/screenshot.ts @@ -1,8 +1,7 @@ import { mkdir } from 'node:fs/promises' import { normalize } from 'node:path' -import type { BrowserCommand } from 'vitest/node' +import type { BrowserCommand, ResolvedConfig } from 'vitest/node' import { basename, dirname, relative, resolve } from 'pathe' -import type { ResolvedConfig } from 'vitest' import type { ScreenshotOptions } from '../../../context' import { PlaywrightBrowserProvider } from '../providers/playwright' import { WebdriverBrowserProvider } from '../providers/webdriver' diff --git a/packages/browser/src/node/commands/type.ts b/packages/browser/src/node/commands/type.ts index ff79fb7e9c34..c211d1e6a697 100644 --- a/packages/browser/src/node/commands/type.ts +++ b/packages/browser/src/node/commands/type.ts @@ -11,6 +11,7 @@ export const type: UserEventCommand = async ( options = {}, ) => { const { skipClick = false, skipAutoClose = false } = options + const unreleased = new Set(Reflect.get(options, 'unreleased') as string[] ?? []) if (context.provider instanceof PlaywrightBrowserProvider) { const { iframe } = context @@ -21,6 +22,7 @@ export const type: UserEventCommand = async ( } await keyboardImplementation( + unreleased, context.provider, context.contextId, text, @@ -37,6 +39,7 @@ export const type: UserEventCommand = async ( } await keyboardImplementation( + unreleased, context.provider, context.contextId, text, @@ -52,4 +55,8 @@ export const type: UserEventCommand = async ( else { throw new TypeError(`Provider "${context.provider.name}" does not support typing`) } + + return { + unreleased: Array.from(unreleased), + } } diff --git a/packages/browser/src/node/plugins/pluginContext.ts b/packages/browser/src/node/plugins/pluginContext.ts index 6802ca12e874..6546d5b48a03 100644 --- a/packages/browser/src/node/plugins/pluginContext.ts +++ b/packages/browser/src/node/plugins/pluginContext.ts @@ -94,10 +94,17 @@ function getUserEvent(provider: BrowserProvider) { } // TODO: have this in a separate file return `{ - ...__vitest_user_event__, - fill: async (element, text) => { - await __vitest_user_event__.clear(element) - await __vitest_user_event__.type(element, text) + ..._userEventSetup, + setup() { + const userEvent = __vitest_user_event__.setup() + userEvent.setup = this.setup + userEvent.fill = this.fill.bind(userEvent) + userEvent.dragAndDrop = this.dragAndDrop + return userEvent + }, + async fill(element, text) { + await this.clear(element) + await this.type(element, text) }, dragAndDrop: async () => { throw new Error('Provider "preview" does not support dragging elements') @@ -115,5 +122,5 @@ async function getUserEventImport(provider: BrowserProvider, resolve: (id: strin } return `import { userEvent as __vitest_user_event__ } from '${slash( `/@fs/${resolved.id}`, - )}'` + )}'\nconst _userEventSetup = __vitest_user_event__.setup()\n` } diff --git a/packages/browser/src/node/resolveMock.ts b/packages/browser/src/node/resolveMock.ts index 6326883d9cb3..fc41c8ebf894 100644 --- a/packages/browser/src/node/resolveMock.ts +++ b/packages/browser/src/node/resolveMock.ts @@ -2,9 +2,8 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs' import { builtinModules } from 'node:module' import { basename, dirname, extname, isAbsolute, join, resolve } from 'pathe' import type { PartialResolvedId } from 'rollup' -import type { ResolvedConfig } from 'vitest' +import type { ResolvedConfig, WorkspaceProject } from 'vitest/node' import type { ResolvedConfig as ViteConfig } from 'vite' -import type { WorkspaceProject } from 'vitest/node' export async function resolveMock( project: WorkspaceProject, diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts index dd7991141622..17740981733d 100644 --- a/packages/browser/src/node/rpc.ts +++ b/packages/browser/src/node/rpc.ts @@ -1,5 +1,5 @@ import { existsSync, promises as fs } from 'node:fs' -import { dirname } from 'pathe' +import { dirname, isAbsolute, join } from 'pathe' import { createBirpc } from 'birpc' import { parse, stringify } from 'flatted' import type { WebSocket } from 'ws' @@ -8,11 +8,12 @@ import type { BrowserCommandContext } from 'vitest/node' import { createDebugger, isFileServingAllowed } from 'vitest/node' import type { WebSocketBrowserEvents, WebSocketBrowserHandlers } from './types' import type { BrowserServer } from './server' -import { resolveMock } from './resolveMock' +import { cleanUrl, resolveMock } from './resolveMock' const debug = createDebugger('vitest:browser:api') const BROWSER_API_PATH = '/__vitest_browser_api__' +const VALID_ID_PREFIX = '/@id/' export function setupBrowserRpc( server: BrowserServer, @@ -69,7 +70,7 @@ export function setupBrowserRpc( ctx.state.catchError(error, type) }, async onCollected(files) { - ctx.state.collectFiles(files) + ctx.state.collectFiles(project, files) await ctx.report('onCollected', files) }, async onTaskUpdate(packs) { @@ -118,14 +119,44 @@ export function setupBrowserRpc( ctx.cancelCurrentRun(reason) }, async resolveId(id, importer) { - const result = await project.server.pluginContainer.resolveId( + const resolved = await vite.pluginContainer.resolveId( id, importer, { ssr: false, }, ) - return result + if (!resolved) { + return null + } + const isOptimized = resolved.id.startsWith(withTrailingSlash(vite.config.cacheDir)) + let url: string + // normalise the URL to be acceptible by the browser + // https://github.com/vitejs/vite/blob/e833edf026d495609558fd4fb471cf46809dc369/packages/vite/src/node/plugins/importAnalysis.ts#L335 + const root = vite.config.root + if (resolved.id.startsWith(withTrailingSlash(root))) { + url = resolved.id.slice(root.length) + } + else if ( + resolved.id !== '/@react-refresh' + && isAbsolute(resolved.id) + && existsSync(cleanUrl(resolved.id)) + ) { + url = join('/@fs/', resolved.id) + } + else { + url = resolved.id + } + if (url[0] !== '.' && url[0] !== '/') { + url = id.startsWith(VALID_ID_PREFIX) + ? id + : VALID_ID_PREFIX + id.replace('\0', '__x00__') + } + return { + id: resolved.id, + url, + optimized: isOptimized, + } }, debug(...args) { ctx.logger.console.debug(...args) @@ -242,3 +273,11 @@ export function stringifyReplace(key: string, value: any) { return value } } + +function withTrailingSlash(path: string): string { + if (path[path.length - 1] !== '/') { + return `${path}/` + } + + return path +} diff --git a/packages/browser/src/node/server.ts b/packages/browser/src/node/server.ts index ca7bc8173d6a..b3ac794344a3 100644 --- a/packages/browser/src/node/server.ts +++ b/packages/browser/src/node/server.ts @@ -11,8 +11,8 @@ import type { import { join, resolve } from 'pathe' import type { ErrorWithDiff } from '@vitest/utils' import { slash } from '@vitest/utils' -import type { ResolvedConfig } from 'vitest' import { type StackTraceParserOptions, parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map' +import type { SerializedConfig } from 'vitest' import { BrowserServerState } from './state' import { getBrowserProvider } from './utils' import { BrowserServerCDPHandler } from './cdp' @@ -224,7 +224,7 @@ export class BrowserServer implements IBrowserServer { } } -function wrapConfig(config: ResolvedConfig): ResolvedConfig { +function wrapConfig(config: SerializedConfig): SerializedConfig { return { ...config, // workaround RegExp serialization diff --git a/packages/browser/src/node/serverOrchestrator.ts b/packages/browser/src/node/serverOrchestrator.ts index cffe6c21d3c8..cad63b0c591d 100644 --- a/packages/browser/src/node/serverOrchestrator.ts +++ b/packages/browser/src/node/serverOrchestrator.ts @@ -17,14 +17,13 @@ export async function resolveOrchestrator( const files = server.state.getContext(contextId!)?.files ?? [] - const config = server.getSerializableConfig() const injectorJs = typeof server.injectorJs === 'string' ? server.injectorJs : await server.injectorJs const injector = replacer(injectorJs, { __VITEST_PROVIDER__: JSON.stringify(server.provider.name), - __VITEST_CONFIG__: JSON.stringify(config), + __VITEST_CONFIG__: JSON.stringify(server.getSerializableConfig()), __VITEST_VITE_CONFIG__: JSON.stringify({ root: server.vite.config.root, }), diff --git a/packages/browser/src/node/serverTester.ts b/packages/browser/src/node/serverTester.ts index 427b0e733139..517c69892812 100644 --- a/packages/browser/src/node/serverTester.ts +++ b/packages/browser/src/node/serverTester.ts @@ -38,11 +38,9 @@ export async function resolveTester( ? server.injectorJs : await server.injectorJs - const config = server.getSerializableConfig() - const injector = replacer(injectorJs, { __VITEST_PROVIDER__: JSON.stringify(server.provider.name), - __VITEST_CONFIG__: JSON.stringify(config), + __VITEST_CONFIG__: JSON.stringify(server.getSerializableConfig()), __VITEST_FILES__: JSON.stringify(files), __VITEST_VITE_CONFIG__: JSON.stringify({ root: server.vite.config.root, @@ -57,7 +55,7 @@ export async function resolveTester( const testerScripts = await server.formatScripts( project.config.browser.testerScripts, ) - const clientScript = `` + const clientScript = `` const stateJs = typeof server.stateJs === 'string' ? server.stateJs : await server.stateJs diff --git a/packages/browser/src/node/types.ts b/packages/browser/src/node/types.ts index 051b0b7bf8b6..8f783cdc34fe 100644 --- a/packages/browser/src/node/types.ts +++ b/packages/browser/src/node/types.ts @@ -20,7 +20,7 @@ export interface WebSocketBrowserHandlers { resolveId: ( id: string, importer?: string - ) => Promise<{ id: string } | null> + ) => Promise<{ id: string; url: string; optimized: boolean } | null> triggerCommand: ( contextId: string, command: string, diff --git a/packages/coverage-istanbul/package.json b/packages/coverage-istanbul/package.json index cca9d12085b0..0a3729dd6c0b 100644 --- a/packages/coverage-istanbul/package.json +++ b/packages/coverage-istanbul/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/coverage-istanbul", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Istanbul coverage provider for Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/coverage-v8/package.json b/packages/coverage-v8/package.json index 89942b95ef2d..ac984e78236c 100644 --- a/packages/coverage-v8/package.json +++ b/packages/coverage-v8/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/coverage-v8", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "V8 coverage provider for Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/expect/package.json b/packages/expect/package.json index 1423a9a504b4..5f3b96c1e842 100644 --- a/packages/expect/package.json +++ b/packages/expect/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/expect", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Jest's expect matchers as a Chai plugin", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/expect/src/jest-matcher-utils.ts b/packages/expect/src/jest-matcher-utils.ts index b206802f3223..918b3be1ca14 100644 --- a/packages/expect/src/jest-matcher-utils.ts +++ b/packages/expect/src/jest-matcher-utils.ts @@ -1,97 +1,101 @@ import { getType, stringify } from '@vitest/utils' import c from 'tinyrainbow' +import { diff, printDiffOrStringify } from '@vitest/utils/diff' import type { MatcherHintOptions, Tester } from './types' import { JEST_MATCHERS_OBJECT } from './constants' export { diff } from '@vitest/utils/diff' export { stringify } -export function getMatcherUtils() { - const EXPECTED_COLOR = c.green - const RECEIVED_COLOR = c.red - const INVERTED_COLOR = c.inverse - const BOLD_WEIGHT = c.bold - const DIM_COLOR = c.dim - - function matcherHint( - matcherName: string, - received = 'received', - expected = 'expected', - options: MatcherHintOptions = {}, - ) { - const { - comment = '', - isDirectExpectCall = false, // seems redundant with received === '' - isNot = false, - promise = '', - secondArgument = '', - expectedColor = EXPECTED_COLOR, - receivedColor = RECEIVED_COLOR, - secondArgumentColor = EXPECTED_COLOR, - } = options - let hint = '' - let dimString = 'expect' // concatenate adjacent dim substrings - - if (!isDirectExpectCall && received !== '') { - hint += DIM_COLOR(`${dimString}(`) + receivedColor(received) - dimString = ')' - } - - if (promise !== '') { - hint += DIM_COLOR(`${dimString}.`) + promise - dimString = '' - } +const EXPECTED_COLOR = c.green +const RECEIVED_COLOR = c.red +const INVERTED_COLOR = c.inverse +const BOLD_WEIGHT = c.bold +const DIM_COLOR = c.dim + +function matcherHint( + matcherName: string, + received = 'received', + expected = 'expected', + options: MatcherHintOptions = {}, +) { + const { + comment = '', + isDirectExpectCall = false, // seems redundant with received === '' + isNot = false, + promise = '', + secondArgument = '', + expectedColor = EXPECTED_COLOR, + receivedColor = RECEIVED_COLOR, + secondArgumentColor = EXPECTED_COLOR, + } = options + let hint = '' + let dimString = 'expect' // concatenate adjacent dim substrings + + if (!isDirectExpectCall && received !== '') { + hint += DIM_COLOR(`${dimString}(`) + receivedColor(received) + dimString = ')' + } - if (isNot) { - hint += `${DIM_COLOR(`${dimString}.`)}not` - dimString = '' - } + if (promise !== '') { + hint += DIM_COLOR(`${dimString}.`) + promise + dimString = '' + } - if (matcherName.includes('.')) { - // Old format: for backward compatibility, - // especially without promise or isNot options - dimString += matcherName - } - else { - // New format: omit period from matcherName arg - hint += DIM_COLOR(`${dimString}.`) + matcherName - dimString = '' - } + if (isNot) { + hint += `${DIM_COLOR(`${dimString}.`)}not` + dimString = '' + } - if (expected === '') { - dimString += '()' - } - else { - hint += DIM_COLOR(`${dimString}(`) + expectedColor(expected) - if (secondArgument) { - hint += DIM_COLOR(', ') + secondArgumentColor(secondArgument) - } - dimString = ')' - } + if (matcherName.includes('.')) { + // Old format: for backward compatibility, + // especially without promise or isNot options + dimString += matcherName + } + else { + // New format: omit period from matcherName arg + hint += DIM_COLOR(`${dimString}.`) + matcherName + dimString = '' + } - if (comment !== '') { - dimString += ` // ${comment}` + if (expected === '') { + dimString += '()' + } + else { + hint += DIM_COLOR(`${dimString}(`) + expectedColor(expected) + if (secondArgument) { + hint += DIM_COLOR(', ') + secondArgumentColor(secondArgument) } + dimString = ')' + } - if (dimString !== '') { - hint += DIM_COLOR(dimString) - } + if (comment !== '') { + dimString += ` // ${comment}` + } - return hint + if (dimString !== '') { + hint += DIM_COLOR(dimString) } - const SPACE_SYMBOL = '\u{00B7}' // middle dot + return hint +} + +const SPACE_SYMBOL = '\u{00B7}' // middle dot - // Instead of inverse highlight which now implies a change, - // replace common spaces with middle dot at the end of any line. - const replaceTrailingSpaces = (text: string): string => - text.replace(/\s+$/gm, spaces => SPACE_SYMBOL.repeat(spaces.length)) +// Instead of inverse highlight which now implies a change, +// replace common spaces with middle dot at the end of any line. +function replaceTrailingSpaces(text: string): string { + return text.replace(/\s+$/gm, spaces => SPACE_SYMBOL.repeat(spaces.length)) +} - const printReceived = (object: unknown): string => - RECEIVED_COLOR(replaceTrailingSpaces(stringify(object))) - const printExpected = (value: unknown): string => - EXPECTED_COLOR(replaceTrailingSpaces(stringify(value))) +function printReceived(object: unknown): string { + return RECEIVED_COLOR(replaceTrailingSpaces(stringify(object))) +} +function printExpected(value: unknown): string { + return EXPECTED_COLOR(replaceTrailingSpaces(stringify(value))) +} +export function getMatcherUtils() { return { EXPECTED_COLOR, RECEIVED_COLOR, @@ -99,9 +103,11 @@ export function getMatcherUtils() { BOLD_WEIGHT, DIM_COLOR, + diff, matcherHint, printReceived, printExpected, + printDiffOrStringify, } } diff --git a/packages/pretty-format/package.json b/packages/pretty-format/package.json index 5dc54503ea7c..d61ddf00ef58 100644 --- a/packages/pretty-format/package.json +++ b/packages/pretty-format/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/pretty-format", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Fork of pretty-format with support for ESM", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/runner/package.json b/packages/runner/package.json index 8a03f6168885..60e97a6d7066 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/runner", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Vitest test runner", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/runner/src/collect.ts b/packages/runner/src/collect.ts index 74c2d1230095..55ac27428546 100644 --- a/packages/runner/src/collect.ts +++ b/packages/runner/src/collect.ts @@ -1,4 +1,5 @@ import { processError } from '@vitest/utils/error' +import { toArray } from '@vitest/utils' import type { File, SuiteHooks } from './types/tasks' import type { VitestRunner } from './types/runner' import { @@ -34,11 +35,18 @@ export async function collectTests( clearCollectorContext(filepath, runner) try { - const setupStart = now() - await runSetupFiles(config, runner) + const setupFiles = toArray(config.setupFiles) + if (setupFiles.length) { + const setupStart = now() + await runSetupFiles(config, setupFiles, runner) + const setupEnd = now() + file.setupDuration = setupEnd - setupStart + } + else { + file.setupDuration = 0 + } const collectStart = now() - file.setupDuration = collectStart - setupStart await runner.importFile(filepath, 'collect') @@ -77,6 +85,14 @@ export async function collectTests( calculateSuiteHash(file) + file.tasks.forEach((task) => { + // task.suite refers to the internal default suite object + // it should not be reported + if (task.suite?.id === '') { + delete task.suite + } + }) + const hasOnlyTasks = someTasksAreOnly(file) interpretTaskModes( file, @@ -86,13 +102,6 @@ export async function collectTests( config.allowOnly, ) - file.tasks.forEach((task) => { - // task.suite refers to the internal default suite object - // it should not be reported - if (task.suite?.id === '') { - delete task.suite - } - }) files.push(file) } diff --git a/packages/runner/src/hooks.ts b/packages/runner/src/hooks.ts index 44ea8eea2a14..aa8ae3a82cf6 100644 --- a/packages/runner/src/hooks.ts +++ b/packages/runner/src/hooks.ts @@ -26,12 +26,13 @@ function getDefaultHookTimeout() { * @param {Function} fn - The callback function to be executed before all tests. * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @returns {void} - * * @example + * ```ts * // Example of using beforeAll to set up a database connection * beforeAll(async () => { * await database.connect(); * }); + * ``` */ export function beforeAll(fn: BeforeAllListener, timeout?: number): void { return getCurrentSuite().on( @@ -49,12 +50,13 @@ export function beforeAll(fn: BeforeAllListener, timeout?: number): void { * @param {Function} fn - The callback function to be executed after all tests. * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @returns {void} - * * @example + * ```ts * // Example of using afterAll to close a database connection * afterAll(async () => { * await database.disconnect(); * }); + * ``` */ export function afterAll(fn: AfterAllListener, timeout?: number): void { return getCurrentSuite().on( @@ -72,12 +74,13 @@ export function afterAll(fn: AfterAllListener, timeout?: number): void { * @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed. * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @returns {void} - * * @example + * ```ts * // Example of using beforeEach to reset a database state * beforeEach(async () => { * await database.reset(); * }); + * ``` */ export function beforeEach( fn: BeforeEachListener, @@ -98,12 +101,13 @@ export function beforeEach( * @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed. * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @returns {void} - * * @example + * ```ts * // Example of using afterEach to delete temporary files created during a test * afterEach(async () => { * await fileSystem.deleteTempFiles(); * }); + * ``` */ export function afterEach( fn: AfterEachListener, @@ -125,12 +129,13 @@ export function afterEach( * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @throws {Error} Throws an error if the function is not called within a test. * @returns {void} - * * @example + * ```ts * // Example of using onTestFailed to log failure details * onTestFailed(({ errors }) => { * console.log(`Test failed: ${test.name}`, errors); * }); + * ``` */ export const onTestFailed: TaskHook = createTestHook( 'onTestFailed', @@ -154,13 +159,14 @@ export const onTestFailed: TaskHook = createTestHook( * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used. * @throws {Error} Throws an error if the function is not called within a test. * @returns {void} - * * @example + * ```ts * // Example of using onTestFinished for cleanup * const db = await connectToDatabase(); * onTestFinished(async () => { * await db.disconnect(); * }); + * ``` */ export const onTestFinished: TaskHook = createTestHook( 'onTestFinished', diff --git a/packages/runner/src/setup.ts b/packages/runner/src/setup.ts index ea3a129263e2..f6ea1d722f77 100644 --- a/packages/runner/src/setup.ts +++ b/packages/runner/src/setup.ts @@ -1,11 +1,10 @@ -import { toArray } from '@vitest/utils' import type { VitestRunner, VitestRunnerConfig } from './types/runner' export async function runSetupFiles( config: VitestRunnerConfig, + files: string[], runner: VitestRunner, ): Promise { - const files = toArray(config.setupFiles) if (config.sequence.setupFiles === 'parallel') { await Promise.all( files.map(async (fsPath) => { diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 93c6cf4bd1a9..0c3cfaf1b7df 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -45,8 +45,8 @@ import { getCurrentTest } from './test-state' * * @param {string} name - The name of the suite, used for identification and reporting. * @param {Function} fn - A function that defines the tests and suites within this suite. - * * @example + * ```ts * // Define a suite with two tests * suite('Math operations', () => { * test('should add two numbers', () => { @@ -57,8 +57,9 @@ import { getCurrentTest } from './test-state' * expect(subtract(5, 2)).toBe(3); * }); * }); - * + * ``` * @example + * ```ts * // Define nested suites * suite('String operations', () => { * suite('Trimming', () => { @@ -73,6 +74,7 @@ import { getCurrentTest } from './test-state' * }); * }); * }); + * ``` */ export const suite: SuiteAPI = createSuite() /** @@ -82,18 +84,20 @@ export const suite: SuiteAPI = createSuite() * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided. * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters. * @throws {Error} If called inside another test function. - * * @example + * ```ts * // Define a simple test * test('should add two numbers', () => { * expect(add(1, 2)).toBe(3); * }); - * + * ``` * @example + * ```ts * // Define a test with options * test('should subtract two numbers', { retry: 3 }, () => { * expect(subtract(5, 2)).toBe(3); * }); + * ``` */ export const test: TestAPI = createTest(function ( name: string | Function, @@ -120,8 +124,8 @@ export const test: TestAPI = createTest(function ( * * @param {string} name - The name of the suite, used for identification and reporting. * @param {Function} fn - A function that defines the tests and suites within this suite. - * * @example + * ```ts * // Define a suite with two tests * describe('Math operations', () => { * test('should add two numbers', () => { @@ -132,8 +136,9 @@ export const test: TestAPI = createTest(function ( * expect(subtract(5, 2)).toBe(3); * }); * }); - * + * ``` * @example + * ```ts * // Define nested suites * describe('String operations', () => { * describe('Trimming', () => { @@ -148,6 +153,7 @@ export const test: TestAPI = createTest(function ( * }); * }); * }); + * ``` */ export const describe: SuiteAPI = suite /** @@ -157,18 +163,20 @@ export const describe: SuiteAPI = suite * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided. * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters. * @throws {Error} If called inside another test function. - * * @example + * ```ts * // Define a simple test * it('adds two numbers', () => { * expect(add(1, 2)).toBe(3); * }); - * + * ``` * @example + * ```ts * // Define a test with options * it('subtracts two numbers', { retry: 3 }, () => { * expect(subtract(5, 2)).toBe(3); * }); + * ``` */ export const it: TestAPI = test diff --git a/packages/runner/src/types/runner.ts b/packages/runner/src/types/runner.ts index 3c237fae1e9e..8fa28abb680c 100644 --- a/packages/runner/src/types/runner.ts +++ b/packages/runner/src/types/runner.ts @@ -14,8 +14,8 @@ import type { export interface VitestRunnerConfig { root: string - setupFiles: string[] | string - name: string + setupFiles: string[] + name?: string passWithNoTests: boolean testNamePattern?: RegExp allowOnly?: boolean diff --git a/packages/runner/src/utils/collect.ts b/packages/runner/src/utils/collect.ts index 376994ca9b0f..5f992fef962e 100644 --- a/packages/runner/src/utils/collect.ts +++ b/packages/runner/src/utils/collect.ts @@ -117,7 +117,7 @@ export function calculateSuiteHash(parent: Suite): void { export function createFileTask( filepath: string, root: string, - projectName: string, + projectName: string | undefined, pool?: string, ): File { const path = relative(root, filepath) diff --git a/packages/snapshot/package.json b/packages/snapshot/package.json index 4e6d0bc8d87c..3a764c062eb7 100644 --- a/packages/snapshot/package.json +++ b/packages/snapshot/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/snapshot", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Vitest snapshot manager", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/spy/package.json b/packages/spy/package.json index f05d1ac2a46e..885c3b1f7934 100644 --- a/packages/spy/package.json +++ b/packages/spy/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/spy", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Lightweight Jest compatible spy implementation", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/ui/client/composables/client/index.ts b/packages/ui/client/composables/client/index.ts index 56ed67f154b5..f590b38dcf97 100644 --- a/packages/ui/client/composables/client/index.ts +++ b/packages/ui/client/composables/client/index.ts @@ -1,6 +1,6 @@ import { createClient, getTasks } from '@vitest/ws-client' import type { WebSocketStatus } from '@vueuse/core' -import type { File, ResolvedConfig, TaskResultPack } from 'vitest' +import type { File, SerializedConfig, TaskResultPack } from 'vitest' import { reactive as reactiveVue } from 'vue' import { createFileTask } from '@vitest/runner/utils' import type { BrowserRunnerState } from '../../../types' @@ -45,7 +45,7 @@ export const client = (function createVitestClient() { } })() -export const config = shallowRef({} as any) +export const config = shallowRef({} as any) export const status = ref('CONNECTING') export const current = computed(() => { diff --git a/packages/ui/client/composables/client/static.ts b/packages/ui/client/composables/client/static.ts index abf3e778fc95..21d8020d0441 100644 --- a/packages/ui/client/composables/client/static.ts +++ b/packages/ui/client/composables/client/static.ts @@ -3,18 +3,18 @@ import type { VitestClient } from '@vitest/ws-client' import type { File, ModuleGraphData, - ResolvedConfig, + SerializedConfig, WebSocketEvents, WebSocketHandlers, } from 'vitest' import { parse } from 'flatted' import { decompressSync, strFromU8 } from 'fflate' -import { StateManager } from '../../../../vitest/src/node/state' +import { StateManager } from '../../../../ws-client/src/state' interface HTMLReportMetadata { paths: string[] files: File[] - config: ResolvedConfig + config: SerializedConfig moduleGraph: Record> unhandledErrors: unknown[] // filename -> source @@ -55,7 +55,6 @@ export function createStaticClient(): VitestClient { }, getTransformResult: asyncNoop, onDone: noop, - onCollected: asyncNoop, onTaskUpdate: noop, writeFile: asyncNoop, rerun: asyncNoop, diff --git a/packages/ui/client/composables/navigation.ts b/packages/ui/client/composables/navigation.ts index c5cf8e28af44..353f73ef50e0 100644 --- a/packages/ui/client/composables/navigation.ts +++ b/packages/ui/client/composables/navigation.ts @@ -12,9 +12,7 @@ export const coverageConfigured = computed(() => coverage.value?.enabled) export const coverageEnabled = computed(() => { return ( coverageConfigured.value - && coverage.value.reporter - .map(([reporterName]) => reporterName) - .includes('html') + && !!coverage.value.htmlReporter ) }) export const detailSizes = useLocalStorage<[left: number, right: number]>( @@ -31,16 +29,10 @@ export const detailSizes = useLocalStorage<[left: number, right: number]>( export const coverageUrl = computed(() => { if (coverageEnabled.value) { const idx = coverage.value!.reportsDirectory.lastIndexOf('/') - const htmlReporter = coverage.value!.reporter.find((reporter) => { - if (reporter[0] !== 'html') { - return undefined - } - - return reporter - }) - return htmlReporter && 'subdir' in htmlReporter[1] + const htmlReporterSubdir = coverage.value!.htmlReporter?.subdir + return htmlReporterSubdir ? `/${coverage.value!.reportsDirectory.slice(idx + 1)}/${ - htmlReporter[1].subdir + htmlReporterSubdir }/index.html` : `/${coverage.value!.reportsDirectory.slice(idx + 1)}/index.html` } diff --git a/packages/ui/node/reporter.ts b/packages/ui/node/reporter.ts index 1389affefca9..7398b9c7578b 100644 --- a/packages/ui/node/reporter.ts +++ b/packages/ui/node/reporter.ts @@ -10,7 +10,7 @@ import type { File, ModuleGraphData, Reporter, - ResolvedConfig, + SerializedConfig, Vitest, } from 'vitest' import type { HTMLOptions } from 'vitest/node' @@ -35,7 +35,7 @@ function getOutputFile(config: PotentialConfig | undefined) { interface HTMLReportData { paths: string[] files: File[] - config: ResolvedConfig + config: SerializedConfig moduleGraph: Record> unhandledErrors: unknown[] // filename -> source @@ -63,7 +63,7 @@ export default class HTMLReporter implements Reporter { const result: HTMLReportData = { paths: this.ctx.state.getPaths(), files: this.ctx.state.getFiles(), - config: this.ctx.config, + config: this.ctx.getCoreWorkspaceProject().getSerializableConfig(), unhandledErrors: this.ctx.state.getUnhandledErrors(), moduleGraph: {}, sources: {}, diff --git a/packages/ui/package.json b/packages/ui/package.json index c752d3252bf8..c012fe5f0d00 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/ui", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "UI for Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", @@ -64,7 +64,7 @@ "@types/d3-force": "^3.0.10", "@types/d3-selection": "^3.0.10", "@types/ws": "^8.5.11", - "@unocss/reset": "^0.61.3", + "@unocss/reset": "^0.61.5", "@vitejs/plugin-vue": "^5.0.5", "@vitest/runner": "workspace:*", "@vitest/ws-client": "workspace:*", @@ -72,17 +72,17 @@ "@vueuse/core": "^10.11.0", "ansi-to-html": "^0.7.2", "birpc": "0.2.17", - "codemirror": "^5.65.16", + "codemirror": "^5.65.17", "codemirror-theme-vars": "^0.1.2", "d3-graph-controller": "^3.0.10", "floating-vue": "^5.2.2", "splitpanes": "^3.1.5", - "unocss": "^0.61.3", + "unocss": "^0.61.5", "unplugin-auto-import": "^0.18.0", - "unplugin-vue-components": "^0.27.2", + "unplugin-vue-components": "^0.27.3", "vite": "^5.0.0", "vite-plugin-pages": "^0.32.3", - "vue": "^3.4.31", + "vue": "^3.4.33", "vue-router": "^4.4.0", "vue-virtual-scroller": "2.0.0-beta.8" } diff --git a/packages/ui/types.ts b/packages/ui/types.ts index b90b49d89ef8..172d11eb9819 100644 --- a/packages/ui/types.ts +++ b/packages/ui/types.ts @@ -1,4 +1,4 @@ -import type { ResolvedConfig } from 'vitest' +import type { SerializedConfig } from 'vitest' export interface WSMessage { /** @@ -16,7 +16,7 @@ export type RunState = 'idle' | 'running' export interface BrowserRunnerState { files: string[] - config: ResolvedConfig + config: SerializedConfig type: 'orchestrator' wrapModule: (module: () => T) => T } diff --git a/packages/utils/package.json b/packages/utils/package.json index 3d4d989d1f00..c9822cc6eae2 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/utils", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Shared Vitest utility functions", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/utils/src/diff/index.ts b/packages/utils/src/diff/index.ts index 77a0da76ec67..d6dc8a084a83 100644 --- a/packages/utils/src/diff/index.ts +++ b/packages/utils/src/diff/index.ts @@ -12,6 +12,9 @@ import { format as prettyFormat, plugins as prettyFormatPlugins, } from '@vitest/pretty-format' +import c from 'tinyrainbow' +import { stringify } from '../display' +import { deepClone, getOwnProperties, getType as getSimpleType } from '../helpers' import { getType } from './getType' import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff } from './cleanupSemantic' import { NO_DIFF_MESSAGE, SIMILAR_MESSAGE } from './constants' @@ -66,7 +69,7 @@ const FALLBACK_FORMAT_OPTIONS = { * @param options Diff options * @returns {string | null} a string diff */ -export function diff(a: any, b: any, options?: DiffOptions): string | null { +export function diff(a: any, b: any, options?: DiffOptions): string | undefined { if (Object.is(a, b)) { return '' } @@ -77,11 +80,11 @@ export function diff(a: any, b: any, options?: DiffOptions): string | null { if (aType === 'object' && typeof a.asymmetricMatch === 'function') { if (a.$$typeof !== Symbol.for('jest.asymmetricMatcher')) { // Do not know expected type of user-defined asymmetric matcher. - return null + return undefined } if (typeof a.getExpectedType !== 'function') { // For example, expect.anything() matches either null or undefined - return null + return undefined } expectedType = a.getExpectedType() // Primitive types boolean and number omit difference below. @@ -101,7 +104,7 @@ export function diff(a: any, b: any, options?: DiffOptions): string | null { } if (omitDifference) { - return null + return undefined } switch (aType) { @@ -211,3 +214,160 @@ function getObjectsDifference( ) } } + +const MAX_DIFF_STRING_LENGTH = 20_000 + +function isAsymmetricMatcher(data: any) { + const type = getSimpleType(data) + return type === 'Object' && typeof data.asymmetricMatch === 'function' +} + +function isReplaceable(obj1: any, obj2: any) { + const obj1Type = getSimpleType(obj1) + const obj2Type = getSimpleType(obj2) + return ( + obj1Type === obj2Type && (obj1Type === 'Object' || obj1Type === 'Array') + ) +} + +export function printDiffOrStringify( + expected: unknown, + received: unknown, + options?: DiffOptions, +): string | undefined { + const { aAnnotation, bAnnotation } = normalizeDiffOptions(options) + + if ( + typeof expected === 'string' + && typeof received === 'string' + && expected.length > 0 + && received.length > 0 + && expected.length <= MAX_DIFF_STRING_LENGTH + && received.length <= MAX_DIFF_STRING_LENGTH + && expected !== received + ) { + if (expected.includes('\n') || received.includes('\n')) { + return diffStringsUnified(received, expected, options) + } + + const [diffs] = diffStringsRaw(received, expected, true) + const hasCommonDiff = diffs.some(diff => diff[0] === DIFF_EQUAL) + + const printLabel = getLabelPrinter(aAnnotation, bAnnotation) + const expectedLine + = printLabel(aAnnotation) + + printExpected( + getCommonAndChangedSubstrings(diffs, DIFF_DELETE, hasCommonDiff), + ) + const receivedLine + = printLabel(bAnnotation) + + printReceived( + getCommonAndChangedSubstrings(diffs, DIFF_INSERT, hasCommonDiff), + ) + + return `${expectedLine}\n${receivedLine}` + } + + // if (isLineDiffable(expected, received)) { + const clonedExpected = deepClone(expected, { forceWritable: true }) + const clonedReceived = deepClone(received, { forceWritable: true }) + const { replacedExpected, replacedActual } = replaceAsymmetricMatcher(clonedExpected, clonedReceived) + const difference = diff(replacedExpected, replacedActual, options) + + return difference + // } + + // const printLabel = getLabelPrinter(aAnnotation, bAnnotation) + // const expectedLine = printLabel(aAnnotation) + printExpected(expected) + // const receivedLine + // = printLabel(bAnnotation) + // + (stringify(expected) === stringify(received) + // ? 'serializes to the same string' + // : printReceived(received)) + + // return `${expectedLine}\n${receivedLine}` +} + +export function replaceAsymmetricMatcher( + actual: any, + expected: any, + actualReplaced: WeakSet = new WeakSet(), + expectedReplaced: WeakSet = new WeakSet(), +): { + replacedActual: any + replacedExpected: any + } { + if (!isReplaceable(actual, expected)) { + return { replacedActual: actual, replacedExpected: expected } + } + if (actualReplaced.has(actual) || expectedReplaced.has(expected)) { + return { replacedActual: actual, replacedExpected: expected } + } + actualReplaced.add(actual) + expectedReplaced.add(expected) + getOwnProperties(expected).forEach((key) => { + const expectedValue = expected[key] + const actualValue = actual[key] + if (isAsymmetricMatcher(expectedValue)) { + if (expectedValue.asymmetricMatch(actualValue)) { + actual[key] = expectedValue + } + } + else if (isAsymmetricMatcher(actualValue)) { + if (actualValue.asymmetricMatch(expectedValue)) { + expected[key] = actualValue + } + } + else if (isReplaceable(actualValue, expectedValue)) { + const replaced = replaceAsymmetricMatcher( + actualValue, + expectedValue, + actualReplaced, + expectedReplaced, + ) + actual[key] = replaced.replacedActual + expected[key] = replaced.replacedExpected + } + }) + return { + replacedActual: actual, + replacedExpected: expected, + } +} + +type PrintLabel = (string: string) => string +export function getLabelPrinter(...strings: Array): PrintLabel { + const maxLength = strings.reduce( + (max, string) => (string.length > max ? string.length : max), + 0, + ) + return (string: string): string => + `${string}: ${' '.repeat(maxLength - string.length)}` +} + +const SPACE_SYMBOL = '\u{00B7}' // middle dot +function replaceTrailingSpaces(text: string): string { + return text.replace(/\s+$/gm, spaces => SPACE_SYMBOL.repeat(spaces.length)) +} + +function printReceived(object: unknown): string { + return c.red(replaceTrailingSpaces(stringify(object))) +} +function printExpected(value: unknown): string { + return c.green(replaceTrailingSpaces(stringify(value))) +} + +function getCommonAndChangedSubstrings(diffs: Array, op: number, hasCommonDiff: boolean): string { + return diffs.reduce( + (reduced: string, diff: Diff): string => + reduced + + (diff[0] === DIFF_EQUAL + ? diff[1] + : diff[0] === op + ? hasCommonDiff + ? c.inverse(diff[1]) + : diff[1] + : ''), + '', + ) +} diff --git a/packages/utils/src/error.ts b/packages/utils/src/error.ts index 040aef67dcc8..f675d949137c 100644 --- a/packages/utils/src/error.ts +++ b/packages/utils/src/error.ts @@ -1,6 +1,6 @@ -import { type DiffOptions, diff } from './diff' +import { type DiffOptions, printDiffOrStringify } from './diff' import { format, stringify } from './display' -import { deepClone, getOwnProperties, getType } from './helpers' +import type { TestError } from './types' // utils is bundled for any environment and might not support `Element` declare class Element { @@ -27,7 +27,7 @@ function getUnserializableMessage(err: unknown) { } // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm -export function serializeError(val: any, seen: WeakMap = new WeakMap()): any { +export function serializeValue(val: any, seen: WeakMap = new WeakMap()): any { if (!val || typeof val === 'string') { return val } @@ -42,7 +42,7 @@ export function serializeError(val: any, seen: WeakMap = new WeakM } // cannot serialize immutables as immutables if (isImmutable(val)) { - return serializeError(val.toJSON(), seen) + return serializeValue(val.toJSON(), seen) } if ( val instanceof Promise @@ -57,7 +57,7 @@ export function serializeError(val: any, seen: WeakMap = new WeakM return `${val.toString()} ${format(val.sample)}` } if (typeof val.toJSON === 'function') { - return serializeError(val.toJSON(), seen) + return serializeValue(val.toJSON(), seen) } if (seen.has(val)) { @@ -70,7 +70,7 @@ export function serializeError(val: any, seen: WeakMap = new WeakM seen.set(val, clone) val.forEach((e, i) => { try { - clone[i] = serializeError(e, seen) + clone[i] = serializeValue(e, seen) } catch (err) { clone[i] = getUnserializableMessage(err) @@ -91,7 +91,7 @@ export function serializeError(val: any, seen: WeakMap = new WeakM return } try { - clone[key] = serializeError(val[key], seen) + clone[key] = serializeValue(val[key], seen) } catch (err) { // delete in case it has a setter from prototype that might throw @@ -105,18 +105,22 @@ export function serializeError(val: any, seen: WeakMap = new WeakM } } +export { serializeValue as serializeError } + function normalizeErrorMessage(message: string) { return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, '') } export function processError( - err: any, + _err: any, diffOptions?: DiffOptions, seen: WeakSet = new WeakSet(), ): any { - if (!err || typeof err !== 'object') { - return { message: err } + if (!_err || typeof _err !== 'object') { + return { message: String(_err) } } + const err = _err as TestError + // stack is not serialized in worker communication // we stringify it first if (err.stack) { @@ -132,16 +136,9 @@ export function processError( && err.expected !== undefined && err.actual !== undefined) ) { - const clonedActual = deepClone(err.actual, { forceWritable: true }) - const clonedExpected = deepClone(err.expected, { forceWritable: true }) - - const { replacedActual, replacedExpected } = replaceAsymmetricMatcher( - clonedActual, - clonedExpected, - ) - err.diff = diff(replacedExpected, replacedActual, { + err.diff = printDiffOrStringify(err.actual, err.expected, { ...diffOptions, - ...err.diffOptions, + ...err.diffOptions as DiffOptions, }) } @@ -171,73 +168,13 @@ export function processError( catch {} try { - return serializeError(err) + return serializeValue(err) } catch (e: any) { - return serializeError( + return serializeValue( new Error( `Failed to fully serialize error: ${e?.message}\nInner error message: ${err?.message}`, ), ) } } - -function isAsymmetricMatcher(data: any) { - const type = getType(data) - return type === 'Object' && typeof data.asymmetricMatch === 'function' -} - -function isReplaceable(obj1: any, obj2: any) { - const obj1Type = getType(obj1) - const obj2Type = getType(obj2) - return ( - obj1Type === obj2Type && (obj1Type === 'Object' || obj1Type === 'Array') - ) -} - -export function replaceAsymmetricMatcher( - actual: any, - expected: any, - actualReplaced: WeakSet = new WeakSet(), - expectedReplaced: WeakSet = new WeakSet(), -): { - replacedActual: any - replacedExpected: any - } { - if (!isReplaceable(actual, expected)) { - return { replacedActual: actual, replacedExpected: expected } - } - if (actualReplaced.has(actual) || expectedReplaced.has(expected)) { - return { replacedActual: actual, replacedExpected: expected } - } - actualReplaced.add(actual) - expectedReplaced.add(expected) - getOwnProperties(expected).forEach((key) => { - const expectedValue = expected[key] - const actualValue = actual[key] - if (isAsymmetricMatcher(expectedValue)) { - if (expectedValue.asymmetricMatch(actualValue)) { - actual[key] = expectedValue - } - } - else if (isAsymmetricMatcher(actualValue)) { - if (actualValue.asymmetricMatch(expectedValue)) { - expected[key] = actualValue - } - } - else if (isReplaceable(actualValue, expectedValue)) { - const replaced = replaceAsymmetricMatcher( - actualValue, - expectedValue, - actualReplaced, - expectedReplaced, - ) - actual[key] = replaced.replacedActual - expected[key] = replaced.replacedExpected - } - }) - return { - replacedActual: actual, - replacedExpected: expected, - } -} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index dce716edf4b4..6b87a5c4fcb2 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -47,4 +47,6 @@ export type { Constructable, ParsedStack, ErrorWithDiff, + SerializedError, + TestError, } from './types' diff --git a/packages/utils/src/source-map.ts b/packages/utils/src/source-map.ts index c549c290772e..f1cd145ef419 100644 --- a/packages/utils/src/source-map.ts +++ b/packages/utils/src/source-map.ts @@ -15,7 +15,7 @@ export interface StackTraceParserOptions { ignoreStackEntries?: (RegExp | string)[] getSourceMap?: (file: string) => unknown getFileName?: (id: string) => string - frameFilter?: (error: Error, frame: ParsedStack) => boolean | void + frameFilter?: (error: ErrorWithDiff, frame: ParsedStack) => boolean | void } const CHROME_IE_STACK_REGEXP = /^\s*at .*(?:\S:\d+|\(native\))/m diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index e5c249bceaa4..8e3c3c229de8 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -32,8 +32,29 @@ export interface ParsedStack { column: number } -export interface ErrorWithDiff extends Error { - name: string +export interface SerializedError { + message: string + stack?: string + name?: string + stacks?: ParsedStack[] + cause?: SerializedError + [key: string]: unknown +} + +export interface TestError extends SerializedError { + cause?: TestError + diff?: string + actual?: string + expected?: string +} + +/** + * @deprecated Use `TestError` instead + */ +export interface ErrorWithDiff { + message: string + name?: string + cause?: unknown nameStr?: string stack?: string stackStr?: string diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 985928a1c48b..b00b8291bd7e 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -1,7 +1,7 @@ { "name": "vite-node", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Vite as Node.js runtime", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/vitest/LICENSE.md b/packages/vitest/LICENSE.md index c98f8251bc14..e012ba88698a 100644 --- a/packages/vitest/LICENSE.md +++ b/packages/vitest/LICENSE.md @@ -438,6 +438,27 @@ License: MIT By: Mathias Bynens Repository: https://github.com/mathiasbynens/emoji-regex.git +> Copyright Mathias Bynens +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + --------------------------------------- ## expect-type diff --git a/packages/vitest/package.json b/packages/vitest/package.json index ae90696c5a5c..518a0fd093cd 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -1,7 +1,7 @@ { "name": "vitest", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Next generation testing framework powered by Vite", "author": "Anthony Fu ", "license": "MIT", @@ -177,7 +177,7 @@ "@types/istanbul-reports": "^3.0.4", "@types/jsdom": "^21.1.7", "@types/micromatch": "^4.0.9", - "@types/node": "^20.14.10", + "@types/node": "^20.14.11", "@types/prompts": "^2.4.9", "@types/sinonjs__fake-timers": "^8.1.5", "acorn-walk": "^8.3.3", @@ -189,9 +189,9 @@ "fast-glob": "^3.3.2", "find-up": "^6.3.0", "flatted": "^3.3.1", - "get-tsconfig": "^4.7.5", + "get-tsconfig": "^4.7.6", "happy-dom": "^14.12.3", - "jsdom": "^24.1.0", + "jsdom": "^24.1.1", "local-pkg": "^0.5.0", "log-update": "^5.0.1", "micromatch": "^4.0.7", diff --git a/packages/vitest/rollup.config.js b/packages/vitest/rollup.config.js index 76146f668528..4652deaec581 100644 --- a/packages/vitest/rollup.config.js +++ b/packages/vitest/rollup.config.js @@ -1,7 +1,7 @@ import fs from 'node:fs' import { builtinModules, createRequire } from 'node:module' import { fileURLToPath } from 'node:url' -import { dirname, join, normalize, relative, resolve } from 'pathe' +import { dirname, join, normalize, resolve } from 'pathe' import esbuild from 'rollup-plugin-esbuild' import dts from 'rollup-plugin-dts' import nodeResolve from '@rollup/plugin-node-resolve' @@ -17,20 +17,20 @@ const pkg = require('./package.json') const entries = { 'path': 'src/paths.ts', - 'index': 'src/index.ts', + 'index': 'src/public/index.ts', 'cli': 'src/node/cli.ts', - 'node': 'src/node.ts', - 'suite': 'src/suite.ts', - 'browser': 'src/browser.ts', - 'runners': 'src/runners.ts', - 'environments': 'src/environments.ts', + 'node': 'src/public/node.ts', + 'suite': 'src/public/suite.ts', + 'browser': 'src/public/browser.ts', + 'runners': 'src/public/runners.ts', + 'environments': 'src/public/environments.ts', 'spy': 'src/integrations/spy.ts', - 'coverage': 'src/coverage.ts', + 'coverage': 'src/public/coverage.ts', 'utils': 'src/public/utils.ts', 'execute': 'src/public/execute.ts', 'reporters': 'src/public/reporters.ts', // TODO: advanced docs - 'workers': 'src/workers.ts', + 'workers': 'src/public/workers.ts', // for performance reasons we bundle them separately so we don't import everything at once 'worker': 'src/runtime/worker.ts', @@ -41,23 +41,23 @@ const entries = { 'workers/runVmTests': 'src/runtime/runVmTests.ts', - 'snapshot': 'src/snapshot.ts', + 'snapshot': 'src/public/snapshot.ts', } const dtsEntries = { - index: 'src/index.ts', - node: 'src/node.ts', - environments: 'src/environments.ts', - browser: 'src/browser.ts', - runners: 'src/runners.ts', - suite: 'src/suite.ts', - config: 'src/config.ts', - coverage: 'src/coverage.ts', + index: 'src/public/index.ts', + node: 'src/public/node.ts', + environments: 'src/public/environments.ts', + browser: 'src/public/browser.ts', + runners: 'src/public/runners.ts', + suite: 'src/public/suite.ts', + config: 'src/public/config.ts', + coverage: 'src/public/coverage.ts', utils: 'src/public/utils.ts', execute: 'src/public/execute.ts', reporters: 'src/public/reporters.ts', - workers: 'src/workers.ts', - snapshot: 'src/snapshot.ts', + workers: 'src/public/workers.ts', + snapshot: 'src/public/snapshot.ts', } const external = [ @@ -95,7 +95,7 @@ const plugins = [ json(), commonjs(), esbuild({ - target: 'node14', + target: 'node18', }), ] @@ -107,42 +107,14 @@ export default ({ watch }) => output: { dir: 'dist', format: 'esm', - chunkFileNames: (chunkInfo) => { - let id - = chunkInfo.facadeModuleId - || Object.keys(chunkInfo.moduleIds).find( - i => - !i.includes('node_modules') - && (i.includes('src/') || i.includes('src\\')), - ) - if (id) { - id = normalize(id) - const parts = Array.from( - new Set( - relative(process.cwd(), id) - .split(/\//g) - .map(i => i.replace(/\..*$/, '')) - .filter( - i => - !['src', 'index', 'dist', 'node_modules'].some(j => - i.includes(j), - ) && i.match(/^[\w-]+$/), - ), - ), - ) - if (parts.length) { - return `chunks/${parts.slice(-2).join('-')}.[hash].js` - } - } - return 'vendor/[name].[hash].js' - }, + chunkFileNames: 'chunks/[name].[hash].js', }, external, plugins: [...plugins, !watch && licensePlugin()], onwarn, }, { - input: 'src/config.ts', + input: 'src/public/config.ts', output: [ { file: 'dist/config.cjs', @@ -163,6 +135,7 @@ export default ({ watch }) => entryFileNames: chunk => `${normalize(chunk.name).replace('src/', '')}.d.ts`, format: 'esm', + chunkFileNames: 'chunks/[name].[hash].d.ts', }, external, plugins: [dts({ respectExternal: true })], diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index 69ee138e9b3a..2f380a56d00a 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -5,19 +5,14 @@ import { parse, stringify } from 'flatted' import type { WebSocket } from 'ws' import { WebSocketServer } from 'ws' import type { ViteDevServer } from 'vite' +import type { File, TaskResultPack } from '@vitest/runner' import { API_PATH } from '../constants' -import type { Vitest } from '../node' -import type { - Awaitable, - File, - ModuleGraphData, - Reporter, - SerializableSpec, - TaskResultPack, - UserConsoleLog, -} from '../types' +import type { Vitest } from '../node/core' +import type { Awaitable, ModuleGraphData, UserConsoleLog } from '../types/general' +import type { Reporter } from '../node/types/reporter' import { getModuleGraph, isPrimitive, noop, stringifyReplace } from '../utils' import { parseErrorStacktrace } from '../utils/source-map' +import type { SerializedSpec } from '../runtime/types/utils' import type { TransformResultWithSource, WebSocketEvents, @@ -51,10 +46,6 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { function setupClient(ws: WebSocket) { const rpc = createBirpc( { - async onCollected(files) { - ctx.state.collectFiles(files) - await ctx.report('onCollected', files) - }, async onTaskUpdate(packs) { ctx.state.updateTasks(packs) await ctx.report('onTaskUpdate', packs) @@ -83,7 +74,7 @@ export function setup(ctx: Vitest, _server?: ViteDevServer) { await ctx.rerunFiles(files) }, getConfig() { - return ctx.config + return ctx.getCoreWorkspaceProject().getSerializableConfig() }, async getTransformResult(projectName: string, id, browser = false) { const project = ctx.getProjectByName(projectName) @@ -165,7 +156,7 @@ export class WebSocketReporter implements Reporter { }) } - onSpecsCollected(specs?: SerializableSpec[] | undefined): Awaitable { + onSpecsCollected(specs?: SerializedSpec[] | undefined): Awaitable { if (this.clients.size === 0) { return } diff --git a/packages/vitest/src/api/types.ts b/packages/vitest/src/api/types.ts index 749225e99103..60a3a48ef522 100644 --- a/packages/vitest/src/api/types.ts +++ b/packages/vitest/src/api/types.ts @@ -1,24 +1,37 @@ -import type { TransformResult } from 'vite' import type { BirpcReturn } from 'birpc' -import type { - File, - ModuleGraphData, - Reporter, - ResolvedConfig, - TaskResultPack, -} from '../types' +import type { File, TaskResultPack } from '@vitest/runner' +import type { Awaitable, ModuleGraphData, UserConsoleLog } from '../types/general' +import type { SerializedConfig } from '../runtime/config' +import type { SerializedSpec } from '../runtime/types/utils' -export interface TransformResultWithSource extends TransformResult { +interface SourceMap { + file: string + mappings: string + names: string[] + sources: string[] + sourcesContent?: string[] + version: number + toString: () => string + toUrl: () => string +} + +export interface TransformResultWithSource { + code: string + map: SourceMap | { + mappings: '' + } | null + etag?: string + deps?: string[] + dynamicDeps?: string[] source?: string } export interface WebSocketHandlers { - onCollected: (files?: File[]) => Promise onTaskUpdate: (packs: TaskResultPack[]) => void getFiles: () => File[] - getTestFiles: () => Promise<[{ name: string; root: string }, file: string][]> + getTestFiles: () => Promise getPaths: () => string[] - getConfig: () => ResolvedConfig + getConfig: () => SerializedConfig getModuleGraph: ( projectName: string, id: string, @@ -36,16 +49,17 @@ export interface WebSocketHandlers { getUnhandledErrors: () => unknown[] } -export interface WebSocketEvents - extends Pick< - Reporter, - | 'onCollected' - | 'onFinished' - | 'onTaskUpdate' - | 'onUserConsoleLog' - | 'onPathsCollected' - | 'onSpecsCollected' - > { +export interface WebSocketEvents { + onCollected?: (files?: File[]) => Awaitable + onFinished?: ( + files: File[], + errors: unknown[], + coverage?: unknown + ) => Awaitable + onTaskUpdate?: (packs: TaskResultPack[]) => Awaitable + onUserConsoleLog?: (log: UserConsoleLog) => Awaitable + onPathsCollected?: (paths?: string[]) => Awaitable + onSpecsCollected?: (specs?: SerializedSpec[]) => Awaitable onFinishedReportCoverage: () => void } diff --git a/packages/vitest/src/constants.ts b/packages/vitest/src/constants.ts index 3bde7bb53993..ed504323c41f 100644 --- a/packages/vitest/src/constants.ts +++ b/packages/vitest/src/constants.ts @@ -10,8 +10,6 @@ export const extraInlineDeps = [ /^(?!.*node_modules).*\.cjs\.js$/, // Vite client /vite\w*\/dist\/client\/env.mjs/, - // Nuxt - '@nuxt/test-utils', ] export const CONFIG_NAMES = ['vitest.config', 'vite.config'] diff --git a/packages/vitest/src/coverage.ts b/packages/vitest/src/coverage.ts deleted file mode 100644 index 5dccd7b1fd9e..000000000000 --- a/packages/vitest/src/coverage.ts +++ /dev/null @@ -1 +0,0 @@ -export { BaseCoverageProvider } from './utils/coverage' diff --git a/packages/vitest/src/create/browser/creator.ts b/packages/vitest/src/create/browser/creator.ts index 0515cdae2348..83443ab85559 100644 --- a/packages/vitest/src/create/browser/creator.ts +++ b/packages/vitest/src/create/browser/creator.ts @@ -7,7 +7,7 @@ import type { Agent } from '@antfu/install-pkg' import { detectPackageManager, installPackage } from '@antfu/install-pkg' import { findUp } from 'find-up' import { execa } from 'execa' -import type { BrowserBuiltinProvider } from '../../types/browser' +import type { BrowserBuiltinProvider } from '../../node/types/browser' import { configFiles } from '../../constants' import { generateExampleFiles } from './examples' diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts index cd412103235e..f95ad627a036 100644 --- a/packages/vitest/src/defaults.ts +++ b/packages/vitest/src/defaults.ts @@ -4,7 +4,7 @@ import type { CoverageV8Options, ResolvedCoverageOptions, UserConfig, -} from './types' +} from './node/types/config' import { isCI } from './utils/env' export { defaultBrowserPort } from './constants' @@ -106,6 +106,8 @@ const config = { clearMocks: false, restoreMocks: false, mockReset: false, + unstubGlobals: false, + unstubEnvs: false, include: defaultInclude, exclude: defaultExclude, teardownTimeout: 10000, diff --git a/packages/vitest/src/environments.ts b/packages/vitest/src/environments.ts deleted file mode 100644 index 827be772d3c2..000000000000 --- a/packages/vitest/src/environments.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { environments as builtinEnvironments } from './integrations/env/index' -export { populateGlobal } from './integrations/env/utils' diff --git a/packages/vitest/src/index.ts b/packages/vitest/src/index.ts deleted file mode 100644 index 8f898d539282..000000000000 --- a/packages/vitest/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -export { - suite, - test, - describe, - it, - beforeAll, - beforeEach, - afterAll, - afterEach, - onTestFailed, - onTestFinished, -} from '@vitest/runner' -export { bench } from './runtime/benchmark' - -export { runOnce, isFirstRun } from './integrations/run-once' -export * from './integrations/chai' -export * from './integrations/vi' -export * from './integrations/utils' -export { inject } from './integrations/inject' - -export * from './types' -export * from './api/types' diff --git a/packages/vitest/src/integrations/chai/index.ts b/packages/vitest/src/integrations/chai/index.ts index 7c073c570e0c..72ce87d34c5c 100644 --- a/packages/vitest/src/integrations/chai/index.ts +++ b/packages/vitest/src/integrations/chai/index.ts @@ -11,10 +11,9 @@ import { getState, setState, } from '@vitest/expect' -import type { Assertion, ExpectStatic } from '@vitest/expect' -import type { MatcherState } from '../../types/chai' +import type { Assertion, ExpectStatic, MatcherState } from '@vitest/expect' import { getTestName } from '../../utils/tasks' -import { getCurrentEnvironment, getWorkerState } from '../../utils/global' +import { getCurrentEnvironment, getWorkerState } from '../../runtime/utils' import { createExpectPoll } from './poll' export function createExpect(test?: TaskPopulated) { diff --git a/packages/vitest/src/integrations/coverage.ts b/packages/vitest/src/integrations/coverage.ts index 499bf6168802..c3c6ed831d05 100644 --- a/packages/vitest/src/integrations/coverage.ts +++ b/packages/vitest/src/integrations/coverage.ts @@ -1,8 +1,8 @@ +import type { SerializedCoverageConfig } from '../runtime/config' import type { - CoverageOptions, CoverageProvider, CoverageProviderModule, -} from '../types' +} from '../node/types/coverage' interface Loader { executeId: (id: string) => Promise<{ default: CoverageProviderModule }> @@ -14,7 +14,7 @@ export const CoverageProviderMap: Record = { } async function resolveCoverageProviderModule( - options: CoverageOptions | undefined, + options: SerializedCoverageConfig | undefined, loader: Loader, ) { if (!options?.enabled || !options.provider) { @@ -40,7 +40,7 @@ async function resolveCoverageProviderModule( let customProviderModule try { - customProviderModule = await loader.executeId(options.customProviderModule) + customProviderModule = await loader.executeId(options.customProviderModule!) } catch (error) { throw new Error( @@ -59,7 +59,7 @@ async function resolveCoverageProviderModule( } export async function getCoverageProvider( - options: CoverageOptions | undefined, + options: SerializedCoverageConfig | undefined, loader: Loader, ): Promise { const coverageModule = await resolveCoverageProviderModule(options, loader) @@ -72,7 +72,7 @@ export async function getCoverageProvider( } export async function startCoverageInsideWorker( - options: CoverageOptions | undefined, + options: SerializedCoverageConfig | undefined, loader: Loader, ) { const coverageModule = await resolveCoverageProviderModule(options, loader) @@ -85,7 +85,7 @@ export async function startCoverageInsideWorker( } export async function takeCoverageInsideWorker( - options: CoverageOptions | undefined, + options: SerializedCoverageConfig | undefined, loader: Loader, ) { const coverageModule = await resolveCoverageProviderModule(options, loader) @@ -98,7 +98,7 @@ export async function takeCoverageInsideWorker( } export async function stopCoverageInsideWorker( - options: CoverageOptions | undefined, + options: SerializedCoverageConfig | undefined, loader: Loader, ) { const coverageModule = await resolveCoverageProviderModule(options, loader) diff --git a/packages/vitest/src/integrations/css/css-modules.ts b/packages/vitest/src/integrations/css/css-modules.ts index c9a65256a5dc..95a50272989c 100644 --- a/packages/vitest/src/integrations/css/css-modules.ts +++ b/packages/vitest/src/integrations/css/css-modules.ts @@ -1,5 +1,5 @@ import { createHash } from 'node:crypto' -import type { CSSModuleScopeStrategy } from '../../types' +import type { CSSModuleScopeStrategy } from '../../node/types/config' export function generateCssFilenameHash(filepath: string) { return createHash('md5').update(filepath).digest('hex').slice(0, 6) diff --git a/packages/vitest/src/integrations/env/edge-runtime.ts b/packages/vitest/src/integrations/env/edge-runtime.ts index 6a4a87021e5b..5e558222cc12 100644 --- a/packages/vitest/src/integrations/env/edge-runtime.ts +++ b/packages/vitest/src/integrations/env/edge-runtime.ts @@ -1,4 +1,4 @@ -import type { Environment } from '../../types' +import type { Environment } from '../../types/environment' import { populateGlobal } from './utils' import { KEYS } from './jsdom-keys' diff --git a/packages/vitest/src/integrations/env/happy-dom.ts b/packages/vitest/src/integrations/env/happy-dom.ts index 7f3e9a21e5eb..ba7e792c110b 100644 --- a/packages/vitest/src/integrations/env/happy-dom.ts +++ b/packages/vitest/src/integrations/env/happy-dom.ts @@ -1,4 +1,4 @@ -import type { Environment } from '../../types' +import type { Environment } from '../../types/environment' import { populateGlobal } from './utils' async function teardownWindow(win: { diff --git a/packages/vitest/src/integrations/env/index.ts b/packages/vitest/src/integrations/env/index.ts index 53e538578039..e997962b3fca 100644 --- a/packages/vitest/src/integrations/env/index.ts +++ b/packages/vitest/src/integrations/env/index.ts @@ -1,4 +1,3 @@ -import type { VitestEnvironment } from '../../types/config' import node from './node' import jsdom from './jsdom' import happy from './happy-dom' @@ -12,25 +11,3 @@ export const environments = { } export const envs = Object.keys(environments) - -export const envPackageNames: Record< - Exclude, - string -> = { - 'jsdom': 'jsdom', - 'happy-dom': 'happy-dom', - 'edge-runtime': '@edge-runtime/vm', -} - -export function getEnvPackageName(env: VitestEnvironment) { - if (env === 'node') { - return null - } - if (env in envPackageNames) { - return (envPackageNames as any)[env] - } - if (env[0] === '.' || env[0] === '/') { - return null - } - return `vitest-environment-${env}` -} diff --git a/packages/vitest/src/integrations/env/jsdom.ts b/packages/vitest/src/integrations/env/jsdom.ts index 9f554890633a..c772d270813b 100644 --- a/packages/vitest/src/integrations/env/jsdom.ts +++ b/packages/vitest/src/integrations/env/jsdom.ts @@ -1,4 +1,4 @@ -import type { Environment } from '../../types' +import type { Environment } from '../../types/environment' import { populateGlobal } from './utils' function catchWindowErrors(window: Window) { diff --git a/packages/vitest/src/integrations/env/loader.ts b/packages/vitest/src/integrations/env/loader.ts index 0273abe62660..71df3187346b 100644 --- a/packages/vitest/src/integrations/env/loader.ts +++ b/packages/vitest/src/integrations/env/loader.ts @@ -2,8 +2,9 @@ import { readFileSync } from 'node:fs' import { normalize, resolve } from 'pathe' import { ViteNodeRunner } from 'vite-node/client' import type { ViteNodeRunnerOptions } from 'vite-node' -import type { BuiltinEnvironment, VitestEnvironment } from '../../types/config' -import type { ContextRPC, Environment, WorkerRPC } from '../../types' +import type { BuiltinEnvironment, VitestEnvironment } from '../../node/types/config' +import type { ContextRPC, WorkerRPC } from '../../types/worker' +import type { Environment } from '../../types/environment' import { environments } from './index' function isBuiltinEnvironment( diff --git a/packages/vitest/src/integrations/env/node.ts b/packages/vitest/src/integrations/env/node.ts index 843580e10cda..cd4957042baa 100644 --- a/packages/vitest/src/integrations/env/node.ts +++ b/packages/vitest/src/integrations/env/node.ts @@ -1,5 +1,5 @@ import { Console } from 'node:console' -import type { Environment } from '../../types' +import type { Environment } from '../../types/environment' // some globals we do not want, either because deprecated or we set it ourselves const denyList = new Set([ diff --git a/packages/vitest/src/integrations/globals.ts b/packages/vitest/src/integrations/globals.ts index a017d3e7ac8a..e31212eba223 100644 --- a/packages/vitest/src/integrations/globals.ts +++ b/packages/vitest/src/integrations/globals.ts @@ -1,5 +1,5 @@ import { globalApis } from '../constants' -import * as index from '../index' +import * as index from '../public/index' export function registerApiGlobally() { globalApis.forEach((api) => { diff --git a/packages/vitest/src/integrations/inject.ts b/packages/vitest/src/integrations/inject.ts index 1abdf0633e59..076edd562355 100644 --- a/packages/vitest/src/integrations/inject.ts +++ b/packages/vitest/src/integrations/inject.ts @@ -1,5 +1,5 @@ import type { ProvidedContext } from '../types/general' -import { getWorkerState } from '../utils/global' +import { getWorkerState } from '../runtime/utils' /** * Gives access to injected context provided from the main thread. diff --git a/packages/vitest/src/integrations/run-once.ts b/packages/vitest/src/integrations/run-once.ts index 6b4f1e322d71..56b602989be3 100644 --- a/packages/vitest/src/integrations/run-once.ts +++ b/packages/vitest/src/integrations/run-once.ts @@ -1,4 +1,4 @@ -import { getWorkerState } from '../utils/global' +import { getWorkerState } from '../runtime/utils' const filesCount = new Map() const cache = new Map() diff --git a/packages/vitest/src/integrations/snapshot/environments/resolveSnapshotEnvironment.ts b/packages/vitest/src/integrations/snapshot/environments/resolveSnapshotEnvironment.ts index 80251008a1e1..9951bda91475 100644 --- a/packages/vitest/src/integrations/snapshot/environments/resolveSnapshotEnvironment.ts +++ b/packages/vitest/src/integrations/snapshot/environments/resolveSnapshotEnvironment.ts @@ -1,9 +1,9 @@ import type { SnapshotEnvironment } from '@vitest/snapshot/environment' import type { VitestExecutor } from '../../../runtime/execute' -import type { ResolvedConfig } from '../../../types' +import type { SerializedConfig } from '../../../runtime/config' export async function resolveSnapshotEnvironment( - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ): Promise { if (!config.snapshotEnvironment) { diff --git a/packages/vitest/src/integrations/vi.ts b/packages/vitest/src/integrations/vi.ts index 3c6296b49b9a..7c3133188bdc 100644 --- a/packages/vitest/src/integrations/vi.ts +++ b/packages/vitest/src/integrations/vi.ts @@ -2,9 +2,9 @@ import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' import { assertTypes, createSimpleStackTrace } from '@vitest/utils' import { parseSingleStack } from '../utils/source-map' import type { VitestMocker } from '../runtime/mocker' -import type { ResolvedConfig, RuntimeConfig } from '../types' +import type { RuntimeOptions, SerializedConfig } from '../runtime/config' import type { MockFactoryWithHelper } from '../types/mocker' -import { getWorkerState } from '../utils/global' +import { getWorkerState } from '../runtime/utils' import { resetModules, waitForImportsToResolve } from '../utils/modules' import { isChildProcess } from '../utils/base' import { FakeTimers } from './mock/timers' @@ -97,8 +97,8 @@ export interface VitestUtils { /** * Creates a spy on a method or getter/setter of an object similar to [`vi.fn()`](https://vitest.dev/api/vi#vi-fn). It returns a [mock function](https://vitest.dev/api/mock). - * * @example + * ```ts * const cart = { * getApples: () => 42 * } @@ -108,6 +108,7 @@ export interface VitestUtils { * expect(cart.getApples()).toBe(10) * expect(spy).toHaveBeenCalled() * expect(spy).toHaveReturnedWith(10) + * ``` */ spyOn: typeof spyOn @@ -115,8 +116,8 @@ export interface VitestUtils { * Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](https://vitest.dev/api/mock). * * If no function is given, mock will return `undefined`, when invoked. - * * @example + * ```ts * const getApples = vi.fn(() => 0) * * getApples() @@ -128,6 +129,7 @@ export interface VitestUtils { * * expect(getApples()).toBe(5) * expect(getApples).toHaveNthReturnedWith(2, 5) + * ``` */ fn: typeof fn @@ -135,8 +137,8 @@ export interface VitestUtils { * Wait for the callback to execute successfully. If the callback throws an error or returns a rejected promise it will continue to wait until it succeeds or times out. * * This is very useful when you need to wait for some asynchronous action to complete, for example, when you start a server and need to wait for it to start. - * * @example + * ```ts * const server = createServer() * * await vi.waitFor( @@ -150,6 +152,7 @@ export interface VitestUtils { * interval: 20, // default is 50 * } * ) + * ``` */ waitFor: typeof waitFor @@ -157,8 +160,8 @@ export interface VitestUtils { * This is similar to [`vi.waitFor`](https://vitest.dev/api/vi#vi-waitfor), but if the callback throws any errors, execution is immediately interrupted and an error message is received. * * If the callback returns a falsy value, the next check will continue until a truthy value is returned. This is useful when you need to wait for something to exist before taking the next step. - * * @example + * ```ts * const element = await vi.waitUntil( * () => document.querySelector('.element'), * { @@ -169,6 +172,7 @@ export interface VitestUtils { * * // do something with the element * expect(element.querySelector('.element-child')).toBeTruthy() + * ``` */ waitUntil: typeof waitUntil @@ -234,11 +238,13 @@ export interface VitestUtils { * Imports module, bypassing all checks if it should be mocked. * Can be useful if you want to mock module partially. * @example + * ```ts * vi.mock('./example.js', async () => { * const axios = await vi.importActual('./example.js') * * return { ...axios, get: vi.fn() } * }) + * ``` * @param path Path to the module. Can be aliased, if your config supports it */ importActual: (path: string) => Promise @@ -248,9 +254,11 @@ export interface VitestUtils { * * Mocking algorithm is described in [documentation](https://vitest.dev/guide/mocking#modules). * @example + * ```ts * const example = await vi.importMock('./example.js') * example.calc.mockReturnValue(10) * expect(example.calc()).toBe(10) + * ``` * @param path Path to the module. Can be aliased, if your config supports it * @returns Fully mocked module */ @@ -264,6 +272,7 @@ export interface VitestUtils { * When `partial` is `true` it will expect a `Partial` as a return value. By default, this will only make TypeScript believe that * the first level values are mocked. You can pass down `{ deep: true }` as a second argument to tell TypeScript that the whole object is mocked, if it actually is. * @example + * ```ts * import example from './example.js' * vi.mock('./example.js') * @@ -271,6 +280,7 @@ export interface VitestUtils { * vi.mocked(example.calc).mockReturnValue(10) * expect(example.calc(1, '+', 1)).toBe(10) * }) + * ``` * @param item Anything that can be mocked * @param deep If the object is deeply mocked * @param options If the object is partially or deeply mocked @@ -363,7 +373,7 @@ export interface VitestUtils { /** * Updates runtime config. You can only change values that are used when executing tests. */ - setConfig: (config: RuntimeConfig) => void + setConfig: (config: RuntimeOptions) => void /** * If config was changed with `vi.setConfig`, this will reset it to the original state. @@ -373,7 +383,7 @@ export interface VitestUtils { function createVitest(): VitestUtils { let _mockedDate: Date | null = null - let _config: null | ResolvedConfig = null + let _config: null | SerializedConfig = null function _mocker(): VitestMocker { // @ts-expect-error injected by vite-nide @@ -702,7 +712,7 @@ function createVitest(): VitestUtils { return waitForImportsToResolve() }, - setConfig(config: RuntimeConfig) { + setConfig(config: RuntimeOptions) { if (!_config) { _config = { ...workerState.config } } diff --git a/packages/vitest/src/node.ts b/packages/vitest/src/node.ts deleted file mode 100644 index 4b4ba696627c..000000000000 --- a/packages/vitest/src/node.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './node/index' diff --git a/packages/vitest/src/node/cache/results.ts b/packages/vitest/src/node/cache/results.ts index 20fb68dde2c1..6bdafb64526a 100644 --- a/packages/vitest/src/node/cache/results.ts +++ b/packages/vitest/src/node/cache/results.ts @@ -1,6 +1,7 @@ import fs from 'node:fs' import { dirname, relative, resolve } from 'pathe' -import type { File, ResolvedConfig } from '../../types' +import type { File } from '@vitest/runner' +import type { ResolvedConfig } from '../types/config' export interface SuiteResultCache { failed: boolean diff --git a/packages/vitest/src/node/cli/cac.ts b/packages/vitest/src/node/cli/cac.ts index 9a56c772fa0c..e2fcc55c2030 100644 --- a/packages/vitest/src/node/cli/cac.ts +++ b/packages/vitest/src/node/cli/cac.ts @@ -3,7 +3,7 @@ import cac, { type CAC, type Command } from 'cac' import c from 'tinyrainbow' import { version } from '../../../package.json' with { type: 'json' } import { toArray } from '../../utils/base' -import type { VitestRunMode } from '../../types' +import type { VitestRunMode } from '../types/config' import type { CliOptions } from './cli-api' import type { CLIOption, CLIOptions as CLIOptionsConfig } from './cli-config' import { benchCliOptionsConfig, cliOptionsConfig, collectCliOptionsConfig } from './cli-config' diff --git a/packages/vitest/src/node/cli/cli-api.ts b/packages/vitest/src/node/cli/cli-api.ts index 197ae804f25f..c9e3576fabe2 100644 --- a/packages/vitest/src/node/cli/cli-api.ts +++ b/packages/vitest/src/node/cli/cli-api.ts @@ -5,13 +5,13 @@ import { dirname, resolve } from 'pathe' import type { UserConfig as ViteUserConfig } from 'vite' import type { File, Suite, Task } from '@vitest/runner' import { CoverageProviderMap } from '../../integrations/coverage' -import { getEnvPackageName } from '../../integrations/env' -import type { UserConfig, Vitest, VitestRunMode } from '../../types' +import type { environments } from '../../integrations/env' import { createVitest } from '../create' import { registerConsoleShortcuts } from '../stdin' -import type { VitestOptions } from '../core' +import type { Vitest, VitestOptions } from '../core' import { FilesNotFoundError, GitNotFoundError } from '../errors' import { getNames, getTests } from '../../utils' +import type { UserConfig, VitestEnvironment, VitestRunMode } from '../types/config' export interface CliOptions extends UserConfig { /** @@ -236,3 +236,25 @@ export function formatCollectedAsString(files: File[]) { }) }).flat() } + +const envPackageNames: Record< + Exclude, + string +> = { + 'jsdom': 'jsdom', + 'happy-dom': 'happy-dom', + 'edge-runtime': '@edge-runtime/vm', +} + +function getEnvPackageName(env: VitestEnvironment) { + if (env === 'node') { + return null + } + if (env in envPackageNames) { + return (envPackageNames as any)[env] + } + if (env[0] === '.' || env[0] === '/') { + return null + } + return `vitest-environment-${env}` +} diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 055a05387a15..ade1b3a385b7 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -1,11 +1,11 @@ import { defaultBrowserPort, defaultPort } from '../../constants' -import type { ApiConfig } from '../../types/config' +import type { ApiConfig } from '../types/config' import type { ForksOptions, ThreadsOptions, VmOptions, WorkerContextOptions, -} from '../../types/pool-options' +} from '../types/pool-options' import type { CliOptions } from './cli-api' type NestedOption>> = V extends @@ -167,7 +167,7 @@ export const cliOptionsConfig: VitestCLIOptions = { outputFile: { argument: '', description: - 'Write test results to a file when supporter reporter is also specified, use cac\'s dot notation for individual outputs of multiple reporters (example: --outputFile.tap=./tap.txt)', + 'Write test results to a file when supporter reporter is also specified, use cac\'s dot notation for individual outputs of multiple reporters (example: `--outputFile.tap=./tap.txt`)', subcommands: null, }, coverage: { @@ -527,7 +527,7 @@ export const cliOptionsConfig: VitestCLIOptions = { }, seed: { description: - 'Set the randomization seed. This option will have no effect if --sequence.shuffle is falsy. Visit ["Random Seed" page](https://en.wikipedia.org/wiki/Random_seed) for more information', + 'Set the randomization seed. This option will have no effect if `--sequence.shuffle` is falsy. Visit ["Random Seed" page](https://en.wikipedia.org/wiki/Random_seed) for more information', argument: '', }, hooks: { diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config/resolveConfig.ts similarity index 97% rename from packages/vitest/src/node/config.ts rename to packages/vitest/src/node/config/resolveConfig.ts index a3a0cd1e0257..c9745317388d 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config/resolveConfig.ts @@ -7,23 +7,23 @@ import type { ResolvedConfig, UserConfig, VitestRunMode, -} from '../types' +} from '../types/config' import { defaultBrowserPort, defaultInspectPort, defaultPort, extraInlineDeps, -} from '../constants' -import { benchmarkConfigDefaults, configDefaults } from '../defaults' -import { isCI, stdProvider, toArray } from '../utils' +} from '../../constants' +import { benchmarkConfigDefaults, configDefaults } from '../../defaults' +import { isCI, stdProvider, toArray } from '../../utils' import type { BuiltinPool, ForksOptions, PoolOptions, ThreadsOptions } from '../types/pool-options' -import { getWorkersCountByPercentage } from '../utils/workers' -import { VitestCache } from './cache' -import { BaseSequencer } from './sequencers/BaseSequencer' -import { RandomSequencer } from './sequencers/RandomSequencer' -import type { BenchmarkBuiltinReporters } from './reporters' -import { builtinPools } from './pool' -import type { Logger } from './logger' +import { getWorkersCountByPercentage } from '../../utils/workers' +import { VitestCache } from '../cache' +import { BaseSequencer } from '../sequencers/BaseSequencer' +import { RandomSequencer } from '../sequencers/RandomSequencer' +import type { BenchmarkBuiltinReporters } from '../reporters' +import { builtinPools } from '../pool' +import type { Logger } from '../logger' function resolvePath(path: string, root: string) { return normalize( diff --git a/packages/vitest/src/node/config/serializeConfig.ts b/packages/vitest/src/node/config/serializeConfig.ts new file mode 100644 index 000000000000..15d1a06103ea --- /dev/null +++ b/packages/vitest/src/node/config/serializeConfig.ts @@ -0,0 +1,161 @@ +import type { ResolvedConfig as ViteConfig } from 'vite' +import type { ResolvedConfig, SerializedConfig } from '../types/config' + +export function serializeConfig( + config: ResolvedConfig, + coreConfig: ResolvedConfig, + viteConfig: ViteConfig | undefined, +): SerializedConfig { + const optimizer = config.deps?.optimizer + const poolOptions = config.poolOptions + + // Resolve from server.config to avoid comparing against default value + const isolate = viteConfig?.test?.isolate + + return { + // TODO: remove functions from environmentOptions + environmentOptions: config.environmentOptions, + mode: config.mode, + isolate: config.isolate, + base: config.base, + logHeapUsage: config.logHeapUsage, + runner: config.runner, + bail: config.bail, + defines: config.defines, + chaiConfig: config.chaiConfig, + setupFiles: config.setupFiles, + allowOnly: config.allowOnly, + testTimeout: config.testTimeout, + testNamePattern: config.testNamePattern, + hookTimeout: config.hookTimeout, + clearMocks: config.clearMocks, + mockReset: config.mockReset, + restoreMocks: config.restoreMocks, + unstubEnvs: config.unstubEnvs, + unstubGlobals: config.unstubGlobals, + maxConcurrency: config.maxConcurrency, + pool: config.pool, + expect: config.expect, + snapshotSerializers: config.snapshotSerializers, + diff: config.diff, + retry: config.retry, + disableConsoleIntercept: config.disableConsoleIntercept, + root: config.root, + name: config.name, + globals: config.globals, + snapshotEnvironment: config.snapshotEnvironment, + passWithNoTests: config.passWithNoTests, + coverage: ((coverage) => { + const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === 'html') as [ + 'html', + { subdir?: string }, + ] | undefined + const subdir = htmlReporter && htmlReporter[1]?.subdir + return { + reportsDirectory: coverage.reportsDirectory, + provider: coverage.provider, + enabled: coverage.enabled, + htmlReporter: htmlReporter + ? { subdir } + : undefined, + customProviderModule: 'customProviderModule' in coverage + ? coverage.customProviderModule + : undefined, + } + })(config.coverage), + fakeTimers: config.fakeTimers, + poolOptions: { + forks: { + singleFork: + poolOptions?.forks?.singleFork + ?? coreConfig.poolOptions?.forks?.singleFork + ?? false, + isolate: + poolOptions?.forks?.isolate + ?? isolate + ?? coreConfig.poolOptions?.forks?.isolate + ?? true, + }, + threads: { + singleThread: + poolOptions?.threads?.singleThread + ?? coreConfig.poolOptions?.threads?.singleThread + ?? false, + isolate: + poolOptions?.threads?.isolate + ?? isolate + ?? coreConfig.poolOptions?.threads?.isolate + ?? true, + }, + vmThreads: { + singleThread: + poolOptions?.vmThreads?.singleThread + ?? coreConfig.poolOptions?.vmThreads?.singleThread + ?? false, + }, + vmForks: { + singleFork: + poolOptions?.vmForks?.singleFork + ?? coreConfig.poolOptions?.vmForks?.singleFork + ?? false, + }, + }, + deps: { + web: config.deps.web || {}, + optimizer: { + web: { + enabled: optimizer?.web?.enabled ?? true, + }, + ssr: { + enabled: optimizer?.ssr?.enabled ?? true, + }, + }, + interopDefault: config.deps.interopDefault, + moduleDirectories: config.deps.moduleDirectories, + }, + snapshotOptions: { + // TODO: store it differently, not on the config + snapshotEnvironment: undefined!, + updateSnapshot: coreConfig.snapshotOptions.updateSnapshot, + snapshotFormat: { + ...coreConfig.snapshotOptions.snapshotFormat, + compareKeys: undefined, + }, + expand: + config.snapshotOptions.expand + ?? coreConfig.snapshotOptions.expand, + }, + sequence: { + shuffle: coreConfig.sequence.shuffle, + concurrent: coreConfig.sequence.concurrent, + seed: coreConfig.sequence.seed, + hooks: coreConfig.sequence.hooks, + setupFiles: coreConfig.sequence.setupFiles, + }, + inspect: coreConfig.inspect, + inspectBrk: coreConfig.inspectBrk, + inspector: coreConfig.inspector, + watch: config.watch, + includeTaskLocation: + config.includeTaskLocation + ?? coreConfig.includeTaskLocation, + env: { + ...viteConfig?.env, + ...config.env, + }, + browser: ((browser) => { + return { + name: browser.name, + headless: browser.headless, + isolate: browser.isolate, + fileParallelism: browser.fileParallelism, + ui: browser.ui, + viewport: browser.viewport, + screenshotFailures: browser.screenshotFailures, + } + })(config.browser), + standalone: config.standalone, + printConsoleTrace: + config.printConsoleTrace ?? coreConfig.printConsoleTrace, + } +} diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 8d3b88e2dd6e..4a191a9b6ab1 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -12,23 +12,28 @@ import type { CancelReason, File, TaskResultPack } from '@vitest/runner' import { ViteNodeServer } from 'vite-node/server' import type { defineWorkspace } from 'vitest/config' import { version } from '../../package.json' with { type: 'json' } -import type { ArgumentsType, CoverageProvider, OnServerRestartHandler, ProvidedContext, Reporter, ResolvedConfig, SerializableSpec, UserConfig, UserConsoleLog, UserWorkspaceConfig, VitestRunMode } from '../types' import { getTasks, hasFailed, noop, slash, toArray, wildcardPatternToRegExp } from '../utils' import { getCoverageProvider } from '../integrations/coverage' import { CONFIG_NAMES, configFiles, workspacesFiles as workspaceFiles } from '../constants' import { rootDir } from '../paths' import { WebSocketReporter } from '../api/setup' +import type { SerializedCoverageConfig } from '../runtime/config' +import type { SerializedSpec } from '../runtime/types/utils' +import type { ArgumentsType, OnServerRestartHandler, ProvidedContext, UserConsoleLog } from '../types/general' import { createPool } from './pool' import type { ProcessPool, WorkspaceSpec } from './pool' import { createBenchmarkReporters, createReporters } from './reporters/utils' import { StateManager } from './state' -import { resolveConfig } from './config' +import { resolveConfig } from './config/resolveConfig' import { Logger } from './logger' import { VitestCache } from './cache' import { WorkspaceProject, initializeProject } from './workspace' import { VitestPackageInstaller } from './packageInstaller' import { BlobReporter, readBlobs } from './reporters/blob' import { FilesNotFoundError, GitNotFoundError } from './errors' +import type { ResolvedConfig, UserConfig, UserWorkspaceConfig, VitestRunMode } from './types/config' +import type { Reporter } from './types/reporter' +import type { CoverageProvider } from './types/coverage' const WATCHER_DEBOUNCE = 100 @@ -396,7 +401,10 @@ export class Vitest { if (this.coverageProvider !== undefined) { return } - this.coverageProvider = await getCoverageProvider(this.config.coverage, this.runner) + this.coverageProvider = await getCoverageProvider( + this.config.coverage as unknown as SerializedCoverageConfig, + this.runner, + ) if (this.coverageProvider) { await this.coverageProvider.initialize(this) this.config.coverage = this.coverageProvider.resolveOptions() @@ -432,7 +440,7 @@ export class Vitest { files.forEach((file) => { file.logs?.forEach(log => this.state.updateUserLog(log)) }) - this.state.collectFiles(files) + this.state.collectFiles(project, files) } await this.report('onCollected', files).catch(noop) @@ -642,7 +650,7 @@ export class Vitest { if (!projects.has(coreProject)) { projects.add(coreProject) } - for await (const project of projects) { + for (const project of projects) { await project.initializeGlobalSetup() } } @@ -667,7 +675,7 @@ export class Vitest { await this.report('onPathsCollected', filepaths) await this.report('onSpecsCollected', specs.map( ([project, file]) => - [{ name: project.config.name, root: project.config.root }, file] as SerializableSpec, + [{ name: project.config.name, root: project.config.root }, file] as SerializedSpec, )) // previous run diff --git a/packages/vitest/src/node/create.ts b/packages/vitest/src/node/create.ts index 830c91a13b80..2c7dc0a2545a 100644 --- a/packages/vitest/src/node/create.ts +++ b/packages/vitest/src/node/create.ts @@ -5,12 +5,12 @@ import type { UserConfig as ViteUserConfig, } from 'vite' import { findUp } from 'find-up' -import type { UserConfig, VitestRunMode } from '../types' import { configFiles } from '../constants' import type { VitestOptions } from './core' import { Vitest } from './core' import { VitestPlugin } from './plugins' import { createViteServer } from './vite' +import type { UserConfig, VitestRunMode } from './types/config' export async function createVitest( mode: VitestRunMode, diff --git a/packages/vitest/src/node/error.ts b/packages/vitest/src/node/error.ts index cfbbb3750d7e..6597dc902c22 100644 --- a/packages/vitest/src/node/error.ts +++ b/packages/vitest/src/node/error.ts @@ -4,9 +4,9 @@ import { Writable } from 'node:stream' import { normalize, relative } from 'pathe' import c from 'tinyrainbow' import cliTruncate from 'cli-truncate' +import type { ErrorWithDiff, ParsedStack } from '@vitest/utils' import { inspect } from '@vitest/utils' import stripAnsi from 'strip-ansi' -import type { ErrorWithDiff, ParsedStack } from '../types' import { lineSplitRE, positionToOffset, @@ -306,7 +306,7 @@ function printModuleWarningForSourceCode(logger: Logger, path: string) { ) } -export function displayDiff(diff: string | null, console: Console) { +export function displayDiff(diff: string | undefined, console: Console) { if (diff) { console.error(`\n${diff}\n`) } diff --git a/packages/vitest/src/node/globalSetup.ts b/packages/vitest/src/node/globalSetup.ts index 310c8949770a..154881e5b4f9 100644 --- a/packages/vitest/src/node/globalSetup.ts +++ b/packages/vitest/src/node/globalSetup.ts @@ -1,7 +1,7 @@ import { toArray } from '@vitest/utils' import type { ViteNodeRunner } from 'vite-node/client' import type { ProvidedContext } from '../types/general' -import type { ResolvedConfig } from '../types/config' +import type { ResolvedConfig } from './types/config' export interface GlobalSetupContext { config: ResolvedConfig diff --git a/packages/vitest/src/node/index.ts b/packages/vitest/src/node/index.ts deleted file mode 100644 index 4c903849511f..000000000000 --- a/packages/vitest/src/node/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -export type { Vitest } from './core' -export type { WorkspaceProject } from './workspace' -export { createVitest } from './create' -export { VitestPlugin } from './plugins' -export { startVitest } from './cli/cli-api' -export { parseCLI } from './cli/cac' -export { registerConsoleShortcuts } from './stdin' -export type { GlobalSetupContext } from './globalSetup' -export type { WorkspaceSpec, ProcessPool } from './pool' -export { createMethodsRPC } from './pools/rpc' -export { getFilePoolName } from './pool' -export { VitestPackageInstaller } from './packageInstaller' -export { createDebugger } from '../utils/debugger' -export { resolveFsAllow } from './plugins/utils' -export { resolveApiServerConfig, resolveConfig } from './config' - -export { GitNotFoundError, FilesNotFoundError as TestsNotFoundError } from './errors' - -export { distDir, rootDir } from '../paths' - -export type { - TestSequencer, - TestSequencerConstructor, -} from './sequencers/types' -export { BaseSequencer } from './sequencers/BaseSequencer' - -export type { - BrowserProviderInitializationOptions, - BrowserProvider, - CDPSession, - BrowserProviderModule, - ResolvedBrowserOptions, - BrowserProviderOptions, - BrowserBuiltinProvider, - BrowserScript, - BrowserCommand, - BrowserCommandContext, - BrowserServer, - BrowserServerState, - BrowserServerStateContext, - BrowserOrchestrator, -} from '../types/browser' -export type { JsonOptions } from './reporters/json' -export type { JUnitOptions } from './reporters/junit' -export type { HTMLOptions } from './reporters/html' - -export { isFileServingAllowed, createServer, parseAst, parseAstAsync } from 'vite' -export type * as Vite from 'vite' diff --git a/packages/vitest/src/node/logger.ts b/packages/vitest/src/node/logger.ts index b963b744d50b..475a74619d20 100644 --- a/packages/vitest/src/node/logger.ts +++ b/packages/vitest/src/node/logger.ts @@ -3,7 +3,8 @@ import type { Writable } from 'node:stream' import { createLogUpdate } from 'log-update' import c from 'tinyrainbow' import { parseErrorStacktrace } from '@vitest/utils/source-map' -import type { ErrorWithDiff, Task } from '../types' +import type { Task } from '@vitest/runner' +import type { ErrorWithDiff } from '@vitest/utils' import type { TypeCheckError } from '../typecheck/typechecker' import { toArray } from '../utils' import { highlightCode } from '../utils/colors' diff --git a/packages/vitest/src/node/plugins/cssEnabler.ts b/packages/vitest/src/node/plugins/cssEnabler.ts index b9f7e4bcbc2a..c4d577bc1106 100644 --- a/packages/vitest/src/node/plugins/cssEnabler.ts +++ b/packages/vitest/src/node/plugins/cssEnabler.ts @@ -1,7 +1,7 @@ import { relative } from 'pathe' import type { Plugin as VitePlugin } from 'vite' import { generateCssFilenameHash } from '../../integrations/css/css-modules' -import type { CSSModuleScopeStrategy, ResolvedConfig } from '../../types' +import type { CSSModuleScopeStrategy, ResolvedConfig } from '../types/config' import { toArray } from '../../utils' const cssLangs = '\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)' diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index dcf6a28987ae..e30d1c64cda4 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -1,14 +1,14 @@ import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite' import { relative } from 'pathe' import { configDefaults, coverageConfigDefaults } from '../../defaults' -import type { ResolvedConfig, UserConfig } from '../../types' +import type { ResolvedConfig, UserConfig } from '../types/config' import { deepMerge, notNullish, removeUndefinedValues, toArray, } from '../../utils' -import { resolveApiServerConfig } from '../config' +import { resolveApiServerConfig } from '../config/resolveConfig' import { Vitest } from '../core' import { generateScopedClassName } from '../../integrations/css/css-modules' import { defaultPort } from '../../constants' diff --git a/packages/vitest/src/node/plugins/utils.ts b/packages/vitest/src/node/plugins/utils.ts index 84094af2754c..63edb936c915 100644 --- a/packages/vitest/src/node/plugins/utils.ts +++ b/packages/vitest/src/node/plugins/utils.ts @@ -5,7 +5,7 @@ import type { UserConfig as ViteConfig, } from 'vite' import { dirname } from 'pathe' -import type { DepsOptimizationOptions, InlineConfig } from '../../types' +import type { DepsOptimizationOptions, InlineConfig } from '../types/config' import { VitestCache } from '../cache' import { rootDir } from '../../paths' diff --git a/packages/vitest/src/node/plugins/workspace.ts b/packages/vitest/src/node/plugins/workspace.ts index ff1c79716d4e..768f4ad1445f 100644 --- a/packages/vitest/src/node/plugins/workspace.ts +++ b/packages/vitest/src/node/plugins/workspace.ts @@ -5,7 +5,7 @@ import { configDefaults } from '../../defaults' import { generateScopedClassName } from '../../integrations/css/css-modules' import { deepMerge } from '../../utils/base' import type { WorkspaceProject } from '../workspace' -import type { ResolvedConfig, UserWorkspaceConfig } from '../../types' +import type { ResolvedConfig, UserWorkspaceConfig } from '../types/config' import { CoverageTransform } from './coverageTransform' import { CSSEnablerPlugin } from './cssEnabler' import { SsrReplacerPlugin } from './ssrReplacer' diff --git a/packages/vitest/src/node/pool.ts b/packages/vitest/src/node/pool.ts index 5dd244fea431..a8d7b0b2d0d0 100644 --- a/packages/vitest/src/node/pool.ts +++ b/packages/vitest/src/node/pool.ts @@ -1,7 +1,7 @@ import mm from 'micromatch' import type { Awaitable } from '@vitest/utils' -import type { BuiltinPool, Pool } from '../types/pool-options' import { isWindows } from '../utils/env' +import type { BuiltinPool, Pool } from './types/pool-options' import type { Vitest } from './core' import { createForksPool } from './pools/forks' import { createThreadsPool } from './pools/threads' diff --git a/packages/vitest/src/node/pools/forks.ts b/packages/vitest/src/node/pools/forks.ts index 5d54d911bef7..b7185520b886 100644 --- a/packages/vitest/src/node/pools/forks.ts +++ b/packages/vitest/src/node/pools/forks.ts @@ -4,19 +4,15 @@ import EventEmitter from 'node:events' import { Tinypool } from 'tinypool' import type { TinypoolChannel, Options as TinypoolOptions } from 'tinypool' import { createBirpc } from 'birpc' -import type { - ContextRPC, - ContextTestEnvironment, - ResolvedConfig, - RunnerRPC, - RuntimeRPC, - Vitest, -} from '../../types' import type { PoolProcessOptions, ProcessPool, RunWithFiles } from '../pool' import type { WorkspaceProject } from '../workspace' import { envsOrder, groupFilesByEnv } from '../../utils/test-helpers' import { wrapSerializableConfig } from '../../utils/config-helpers' import { groupBy, resolve } from '../../utils' +import type { SerializedConfig } from '../types/config' +import type { RunnerRPC, RuntimeRPC } from '../../types/rpc' +import type { Vitest } from '../core' +import type { ContextRPC, ContextTestEnvironment } from '../../types/worker' import { createMethodsRPC } from './rpc' function createChildProcessChannel(project: WorkspaceProject) { @@ -103,7 +99,7 @@ export function createForksPool( async function runFiles( project: WorkspaceProject, - config: ResolvedConfig, + config: SerializedConfig, files: string[], environment: ContextTestEnvironment, invalidates: string[] = [], @@ -141,7 +137,7 @@ export function createForksPool( && error instanceof Error && /The task has been cancelled/.test(error.message) ) { - ctx.state.cancelFiles(files, ctx.config.root, project.config.name) + ctx.state.cancelFiles(files, project) } else { throw error @@ -156,8 +152,8 @@ export function createForksPool( // Cancel pending tasks from pool when possible ctx.onCancel(() => pool.cancelPendingTasks()) - const configs = new Map() - const getConfig = (project: WorkspaceProject): ResolvedConfig => { + const configs = new Map() + const getConfig = (project: WorkspaceProject): SerializedConfig => { if (configs.has(project)) { return configs.get(project)! } diff --git a/packages/vitest/src/node/pools/rpc.ts b/packages/vitest/src/node/pools/rpc.ts index 3ce3324bb27e..36a2b369921d 100644 --- a/packages/vitest/src/node/pools/rpc.ts +++ b/packages/vitest/src/node/pools/rpc.ts @@ -2,8 +2,8 @@ import { createHash } from 'node:crypto' import { mkdir, writeFile } from 'node:fs/promises' import type { RawSourceMap } from 'vite-node' import { join } from 'pathe' -import type { RuntimeRPC } from '../../types' import type { WorkspaceProject } from '../workspace' +import type { RuntimeRPC } from '../../types/rpc' const created = new Set() const promises = new Map>() @@ -76,7 +76,7 @@ export function createMethodsRPC(project: WorkspaceProject, options: MethodsOpti return ctx.report('onPathsCollected', paths) }, onCollected(files) { - ctx.state.collectFiles(files) + ctx.state.collectFiles(project, files) return ctx.report('onCollected', files) }, onAfterSuiteRun(meta) { diff --git a/packages/vitest/src/node/pools/threads.ts b/packages/vitest/src/node/pools/threads.ts index 0fcf5c02ab97..9613d47d198f 100644 --- a/packages/vitest/src/node/pools/threads.ts +++ b/packages/vitest/src/node/pools/threads.ts @@ -4,18 +4,15 @@ import { createBirpc } from 'birpc' import type { Options as TinypoolOptions } from 'tinypool' import Tinypool from 'tinypool' import { resolve } from 'pathe' -import type { - ContextTestEnvironment, - ResolvedConfig, - RunnerRPC, - RuntimeRPC, - Vitest, - WorkerContext, -} from '../../types' import type { PoolProcessOptions, ProcessPool, RunWithFiles } from '../pool' import { envsOrder, groupFilesByEnv } from '../../utils/test-helpers' import { AggregateError, groupBy } from '../../utils/base' import type { WorkspaceProject } from '../workspace' +import type { SerializedConfig } from '../types/config' +import type { RunnerRPC, RuntimeRPC } from '../../types/rpc' +import type { ContextTestEnvironment } from '../../types/worker' +import type { Vitest } from '../core' +import type { WorkerContext } from '../types/worker' import { createMethodsRPC } from './rpc' function createWorkerChannel(project: WorkspaceProject) { @@ -97,7 +94,7 @@ export function createThreadsPool( async function runFiles( project: WorkspaceProject, - config: ResolvedConfig, + config: SerializedConfig, files: string[], environment: ContextTestEnvironment, invalidates: string[] = [], @@ -138,7 +135,7 @@ export function createThreadsPool( && error instanceof Error && /The task has been cancelled/.test(error.message) ) { - ctx.state.cancelFiles(files, ctx.config.root, project.config.name) + ctx.state.cancelFiles(files, project) } else { throw error @@ -154,8 +151,8 @@ export function createThreadsPool( // Cancel pending tasks from pool when possible ctx.onCancel(() => pool.cancelPendingTasks()) - const configs = new Map() - const getConfig = (project: WorkspaceProject): ResolvedConfig => { + const configs = new Map() + const getConfig = (project: WorkspaceProject): SerializedConfig => { if (configs.has(project)) { return configs.get(project)! } diff --git a/packages/vitest/src/node/pools/typecheck.ts b/packages/vitest/src/node/pools/typecheck.ts index a88c29ae5912..b0ce984e0f49 100644 --- a/packages/vitest/src/node/pools/typecheck.ts +++ b/packages/vitest/src/node/pools/typecheck.ts @@ -61,7 +61,7 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool { checker.setFiles(files) checker.onParseStart(async () => { - ctx.state.collectFiles(checker.getTestFiles()) + ctx.state.collectFiles(project, checker.getTestFiles()) await ctx.report('onCollected') }) @@ -80,7 +80,7 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool { } await checker.collectTests() - ctx.state.collectFiles(checker.getTestFiles()) + ctx.state.collectFiles(project, checker.getTestFiles()) await ctx.report('onTaskUpdate', checker.getTestPacks()) await ctx.report('onCollected') @@ -107,7 +107,7 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool { const checker = await createWorkspaceTypechecker(project, files) checker.setFiles(files) await checker.collectTests() - ctx.state.collectFiles(checker.getTestFiles()) + ctx.state.collectFiles(project, checker.getTestFiles()) await ctx.report('onCollected') } } @@ -135,7 +135,7 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool { }) const triggered = await _p if (project.typechecker && !triggered) { - ctx.state.collectFiles(project.typechecker.getTestFiles()) + ctx.state.collectFiles(project, project.typechecker.getTestFiles()) await ctx.report('onCollected') await onParseEnd(project, project.typechecker.getResult()) continue diff --git a/packages/vitest/src/node/pools/vmForks.ts b/packages/vitest/src/node/pools/vmForks.ts index c34bdb990bab..249da53e503c 100644 --- a/packages/vitest/src/node/pools/vmForks.ts +++ b/packages/vitest/src/node/pools/vmForks.ts @@ -6,20 +6,16 @@ import { resolve } from 'pathe' import type { TinypoolChannel, Options as TinypoolOptions } from 'tinypool' import Tinypool from 'tinypool' import { rootDir } from '../../paths' -import type { - ContextRPC, - ContextTestEnvironment, - ResolvedConfig, - RunnerRPC, - RuntimeRPC, - Vitest, -} from '../../types' import type { PoolProcessOptions, ProcessPool, RunWithFiles } from '../pool' import { groupFilesByEnv } from '../../utils/test-helpers' import { AggregateError } from '../../utils/base' import type { WorkspaceProject } from '../workspace' import { getWorkerMemoryLimit, stringToBytes } from '../../utils/memory-limit' import { wrapSerializableConfig } from '../../utils/config-helpers' +import type { ResolvedConfig, SerializedConfig } from '../types/config' +import type { RunnerRPC, RuntimeRPC } from '../../types/rpc' +import type { Vitest } from '../core' +import type { ContextRPC, ContextTestEnvironment } from '../../types/worker' import { createMethodsRPC } from './rpc' const suppressWarningsPath = resolve(rootDir, './suppress-warnings.cjs') @@ -113,7 +109,7 @@ export function createVmForksPool( async function runFiles( project: WorkspaceProject, - config: ResolvedConfig, + config: SerializedConfig, files: string[], environment: ContextTestEnvironment, invalidates: string[] = [], @@ -151,7 +147,7 @@ export function createVmForksPool( && error instanceof Error && /The task has been cancelled/.test(error.message) ) { - ctx.state.cancelFiles(files, ctx.config.root, project.config.name) + ctx.state.cancelFiles(files, project) } else { throw error @@ -166,8 +162,8 @@ export function createVmForksPool( // Cancel pending tasks from pool when possible ctx.onCancel(() => pool.cancelPendingTasks()) - const configs = new Map() - const getConfig = (project: WorkspaceProject): ResolvedConfig => { + const configs = new Map() + const getConfig = (project: WorkspaceProject): SerializedConfig => { if (configs.has(project)) { return configs.get(project)! } diff --git a/packages/vitest/src/node/pools/vmThreads.ts b/packages/vitest/src/node/pools/vmThreads.ts index 09654cf2f574..700eab6c0a60 100644 --- a/packages/vitest/src/node/pools/vmThreads.ts +++ b/packages/vitest/src/node/pools/vmThreads.ts @@ -5,19 +5,16 @@ import { resolve } from 'pathe' import type { Options as TinypoolOptions } from 'tinypool' import Tinypool from 'tinypool' import { rootDir } from '../../paths' -import type { - ContextTestEnvironment, - ResolvedConfig, - RunnerRPC, - RuntimeRPC, - Vitest, - WorkerContext, -} from '../../types' import type { PoolProcessOptions, ProcessPool, RunWithFiles } from '../pool' import { groupFilesByEnv } from '../../utils/test-helpers' import { AggregateError } from '../../utils/base' import type { WorkspaceProject } from '../workspace' import { getWorkerMemoryLimit, stringToBytes } from '../../utils/memory-limit' +import type { ResolvedConfig, SerializedConfig } from '../types/config' +import type { RunnerRPC, RuntimeRPC } from '../../types/rpc' +import type { ContextTestEnvironment } from '../../types/worker' +import type { Vitest } from '../core' +import type { WorkerContext } from '../types/worker' import { createMethodsRPC } from './rpc' const suppressWarningsPath = resolve(rootDir, './suppress-warnings.cjs') @@ -103,7 +100,7 @@ export function createVmThreadsPool( async function runFiles( project: WorkspaceProject, - config: ResolvedConfig, + config: SerializedConfig, files: string[], environment: ContextTestEnvironment, invalidates: string[] = [], @@ -144,7 +141,7 @@ export function createVmThreadsPool( && error instanceof Error && /The task has been cancelled/.test(error.message) ) { - ctx.state.cancelFiles(files, ctx.config.root, project.config.name) + ctx.state.cancelFiles(files, project) } else { throw error @@ -160,8 +157,8 @@ export function createVmThreadsPool( // Cancel pending tasks from pool when possible ctx.onCancel(() => pool.cancelPendingTasks()) - const configs = new Map() - const getConfig = (project: WorkspaceProject): ResolvedConfig => { + const configs = new Map() + const getConfig = (project: WorkspaceProject): SerializedConfig => { if (configs.has(project)) { return configs.get(project)! } diff --git a/packages/vitest/src/node/reported-workspace-project.ts b/packages/vitest/src/node/reported-workspace-project.ts new file mode 100644 index 000000000000..ffc4c368ceaa --- /dev/null +++ b/packages/vitest/src/node/reported-workspace-project.ts @@ -0,0 +1,77 @@ +import type { ProvidedContext } from '../types/general' +import type { ResolvedConfig, ResolvedProjectConfig, SerializedConfig } from './types/config' +import type { WorkspaceProject } from './workspace' +import type { Vitest } from './core' + +export class TestProject { + /** + * The global vitest instance. + * @experimental The public Vitest API is experimental and does not follow semver. + */ + public readonly vitest: Vitest + /** + * The workspace project this test project is associated with. + * @experimental The public Vitest API is experimental and does not follow semver. + */ + public readonly workspaceProject: WorkspaceProject + + /** + * Resolved project configuration. + */ + public readonly config: ResolvedProjectConfig + /** + * Resolved global configuration. If there are no workspace projects, this will be the same as `config`. + */ + public readonly globalConfig: ResolvedConfig + + /** + * The name of the project or an empty string if not set. + */ + public readonly name: string + + constructor(workspaceProject: WorkspaceProject) { + this.workspaceProject = workspaceProject + this.vitest = workspaceProject.ctx + this.globalConfig = workspaceProject.ctx.config + this.config = workspaceProject.config + this.name = workspaceProject.getName() + } + + /** + * Serialized project configuration. This is the config that tests receive. + */ + public get serializedConfig() { + return this.workspaceProject.getSerializableConfig() + } + + /** + * Custom context provided to the project. + */ + public context(): ProvidedContext { + return this.workspaceProject.getProvidedContext() + } + + /** + * Provide a custom serializable context to the project. This context will be available for tests once they run. + */ + public provide( + key: T, + value: ProvidedContext[T], + ): void { + this.workspaceProject.provide(key, value) + } + + public toJSON(): SerializedTestProject { + return { + name: this.name, + serializedConfig: this.serializedConfig, + context: this.context(), + } + } +} + +interface SerializedTestProject { + name: string + serializedConfig: SerializedConfig + context: ProvidedContext +} diff --git a/packages/vitest/src/node/reporters/base.ts b/packages/vitest/src/node/reporters/base.ts index fe8a099cb47a..702e0bc17f82 100644 --- a/packages/vitest/src/node/reporters/base.ts +++ b/packages/vitest/src/node/reporters/base.ts @@ -2,14 +2,7 @@ import { performance } from 'node:perf_hooks' import c from 'tinyrainbow' import { parseStacktrace } from '@vitest/utils/source-map' import { relative } from 'pathe' -import type { - ErrorWithDiff, - File, - Reporter, - Task, - TaskResultPack, - UserConsoleLog, -} from '../../types' +import type { File, Task, TaskResultPack } from '@vitest/runner' import { getFullName, getSuites, @@ -23,9 +16,10 @@ import { relativePath, toArray, } from '../../utils' -import type { Vitest } from '../../node' +import type { Vitest } from '../core' import { F_POINTER, F_RIGHT } from '../../utils/figures' -import { UNKNOWN_TEST_ID } from '../../runtime/console' +import type { Reporter } from '../types/reporter' +import type { ErrorWithDiff, UserConsoleLog } from '../../types/general' import { countTestErrors, divider, @@ -303,7 +297,7 @@ export abstract class BaseReporter implements Reporter { ` | ${ task ? getFullName(task, c.dim(' > ')) - : log.taskId !== UNKNOWN_TEST_ID + : log.taskId !== '__vitest__unknown_test__' ? log.taskId : 'unknown test' }`, diff --git a/packages/vitest/src/node/reporters/basic.ts b/packages/vitest/src/node/reporters/basic.ts index 9f4438102bf8..f93b2325798c 100644 --- a/packages/vitest/src/node/reporters/basic.ts +++ b/packages/vitest/src/node/reporters/basic.ts @@ -1,4 +1,4 @@ -import type { File } from '../../types/tasks' +import type { File } from '@vitest/runner' import { BaseReporter } from './base' export class BasicReporter extends BaseReporter { diff --git a/packages/vitest/src/node/reporters/benchmark/table/index.ts b/packages/vitest/src/node/reporters/benchmark/table/index.ts index 1174a37e5259..99dae30d86a2 100644 --- a/packages/vitest/src/node/reporters/benchmark/table/index.ts +++ b/packages/vitest/src/node/reporters/benchmark/table/index.ts @@ -1,12 +1,12 @@ import fs from 'node:fs' import c from 'tinyrainbow' import * as pathe from 'pathe' -import type { TaskResultPack } from '@vitest/runner' +import type { File, TaskResultPack } from '@vitest/runner' import type { UserConsoleLog } from '../../../../types/general' import { BaseReporter } from '../../base' -import type { BenchmarkResult, File } from '../../../../types' import { getFullName, getTasks } from '../../../../utils' import { getStateSymbol } from '../../renderers/utils' +import type { BenchmarkResult } from '../../../../runtime/types/benchmark' import { type TableRendererOptions, createTableRenderer, diff --git a/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts b/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts index 51458fb4a174..1eb9e1bca8f6 100644 --- a/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts +++ b/packages/vitest/src/node/reporters/benchmark/table/tableRender.ts @@ -1,11 +1,12 @@ import c from 'tinyrainbow' import cliTruncate from 'cli-truncate' import stripAnsi from 'strip-ansi' -import type { BenchmarkResult, Task } from '../../../../types' +import type { Task } from '@vitest/runner' import { getTests, notNullish } from '../../../../utils' import { F_RIGHT } from '../../../../utils/figures' import type { Logger } from '../../../logger' import { getCols, getStateSymbol } from '../../renderers/utils' +import type { BenchmarkResult } from '../../../../runtime/types/benchmark' import type { FlatBenchmarkReport } from '.' export interface TableRendererOptions { diff --git a/packages/vitest/src/node/reporters/blob.ts b/packages/vitest/src/node/reporters/blob.ts index 6eb32af179c0..4f780e93fa6f 100644 --- a/packages/vitest/src/node/reporters/blob.ts +++ b/packages/vitest/src/node/reporters/blob.ts @@ -3,9 +3,11 @@ import { existsSync } from 'node:fs' import { parse, stringify } from 'flatted' import { dirname, resolve } from 'pathe' import { cleanUrl } from 'vite-node/utils' -import type { File, Reporter, Vitest } from '../../types' +import type { File } from '@vitest/runner' import { getOutputFile } from '../../utils/config-helpers' import type { WorkspaceProject } from '../workspace' +import type { Reporter } from '../types/reporter' +import type { Vitest } from '../core' export interface BlobOptions { outputFile?: string diff --git a/packages/vitest/src/node/reporters/github-actions.ts b/packages/vitest/src/node/reporters/github-actions.ts index 3fbe2a188ba3..606f593ebcef 100644 --- a/packages/vitest/src/node/reporters/github-actions.ts +++ b/packages/vitest/src/node/reporters/github-actions.ts @@ -1,9 +1,11 @@ import { getTasks } from '@vitest/runner/utils' import stripAnsi from 'strip-ansi' -import type { File, Reporter, Vitest } from '../../types' +import type { File } from '@vitest/runner' import { getFullName } from '../../utils' import { capturePrintError } from '../error' import type { WorkspaceProject } from '../workspace' +import type { Reporter } from '../types/reporter' +import type { Vitest } from '../core' export class GithubActionsReporter implements Reporter { ctx: Vitest = undefined! diff --git a/packages/vitest/src/node/reporters/hanging-process.ts b/packages/vitest/src/node/reporters/hanging-process.ts index 8e9b83a57f2c..d5d9ab12f7ac 100644 --- a/packages/vitest/src/node/reporters/hanging-process.ts +++ b/packages/vitest/src/node/reporters/hanging-process.ts @@ -1,5 +1,5 @@ import { createRequire } from 'node:module' -import type { Reporter } from '../../types' +import type { Reporter } from '../types/reporter' export class HangingProcessReporter implements Reporter { whyRunning: (() => void) | undefined diff --git a/packages/vitest/src/node/reporters/index.ts b/packages/vitest/src/node/reporters/index.ts index 3a967cb4c8ef..fe1bb34390e7 100644 --- a/packages/vitest/src/node/reporters/index.ts +++ b/packages/vitest/src/node/reporters/index.ts @@ -1,4 +1,4 @@ -import type { Reporter } from '../../types' +import type { Reporter } from '../types/reporter' import { BasicReporter } from './basic' import { DefaultReporter } from './default' import { DotReporter } from './dot' @@ -28,6 +28,21 @@ export { } export type { BaseReporter, Reporter } +export { TestCase, TestFile, TestSuite } from './reported-tasks' +export type { TestProject } from '../reported-workspace-project' +export type { + TestCollection, + + TaskOptions, + TestDiagnostic, + FileDiagnostic, + + TestResult, + TestResultFailed, + TestResultPassed, + TestResultSkipped, +} from './reported-tasks' + export type { JsonAssertionResult, JsonTestResult, diff --git a/packages/vitest/src/node/reporters/json.ts b/packages/vitest/src/node/reporters/json.ts index ac1a2c984ba3..cdad5ed22bd1 100644 --- a/packages/vitest/src/node/reporters/json.ts +++ b/packages/vitest/src/node/reporters/json.ts @@ -1,16 +1,11 @@ import { existsSync, promises as fs } from 'node:fs' import { dirname, resolve } from 'pathe' -import type { Vitest } from '../../node' -import type { - File, - Reporter, - SnapshotSummary, - Suite, - TaskMeta, - TaskState, -} from '../../types' +import type { File, Suite, TaskMeta, TaskState } from '@vitest/runner' +import type { SnapshotSummary } from '@vitest/snapshot' import { getSuites, getTests } from '../../utils' import { getOutputFile } from '../../utils/config-helpers' +import type { Reporter } from '../types/reporter' +import type { Vitest } from '../core' // for compatibility reasons, the reporter produces a JSON similar to the one produced by the Jest JSON reporter // the following types are extracted from the Jest repository (and simplified) diff --git a/packages/vitest/src/node/reporters/junit.ts b/packages/vitest/src/node/reporters/junit.ts index 5b5c4a2dcf1e..942ecbacc739 100644 --- a/packages/vitest/src/node/reporters/junit.ts +++ b/packages/vitest/src/node/reporters/junit.ts @@ -5,8 +5,8 @@ import { dirname, relative, resolve } from 'pathe' import type { Task } from '@vitest/runner' import { getSuites } from '@vitest/runner/utils' import stripAnsi from 'strip-ansi' -import type { Vitest } from '../../node' -import type { Reporter } from '../../types/reporter' +import type { Vitest } from '../core' +import type { Reporter } from '../types/reporter' import { getOutputFile } from '../../utils/config-helpers' import { capturePrintError } from '../error' import { IndentedLogger } from './renderers/indented-logger' diff --git a/packages/vitest/src/node/reporters/renderers/dotRenderer.ts b/packages/vitest/src/node/reporters/renderers/dotRenderer.ts index 2c8f6ca4da98..2de99b01a081 100644 --- a/packages/vitest/src/node/reporters/renderers/dotRenderer.ts +++ b/packages/vitest/src/node/reporters/renderers/dotRenderer.ts @@ -1,5 +1,5 @@ import c from 'tinyrainbow' -import type { Task } from '../../../types' +import type { Task } from '@vitest/runner' import { getTests } from '../../../utils' import type { Logger } from '../../logger' diff --git a/packages/vitest/src/node/reporters/renderers/listRenderer.ts b/packages/vitest/src/node/reporters/renderers/listRenderer.ts index a13841071936..6eedf6c55836 100644 --- a/packages/vitest/src/node/reporters/renderers/listRenderer.ts +++ b/packages/vitest/src/node/reporters/renderers/listRenderer.ts @@ -1,16 +1,12 @@ import c from 'tinyrainbow' import cliTruncate from 'cli-truncate' import stripAnsi from 'strip-ansi' -import type { - Benchmark, - BenchmarkResult, - SuiteHooks, - Task, - VitestRunMode, -} from '../../../types' +import type { SuiteHooks, Task } from '@vitest/runner' import { getTests, notNullish } from '../../../utils' import { F_RIGHT } from '../../../utils/figures' import type { Logger } from '../../logger' +import type { VitestRunMode } from '../../types/config' +import type { Benchmark, BenchmarkResult } from '../../../runtime/types/benchmark' import { formatProjectName, getCols, diff --git a/packages/vitest/src/node/reporters/renderers/utils.ts b/packages/vitest/src/node/reporters/renderers/utils.ts index eb770bfff4da..9c8212944a70 100644 --- a/packages/vitest/src/node/reporters/renderers/utils.ts +++ b/packages/vitest/src/node/reporters/renderers/utils.ts @@ -1,7 +1,8 @@ import { basename, dirname, isAbsolute, relative } from 'pathe' import c from 'tinyrainbow' import stripAnsi from 'strip-ansi' -import type { SnapshotSummary, Task } from '../../../types' +import type { SuiteHooks, Task } from '@vitest/runner' +import type { SnapshotSummary } from '@vitest/snapshot' import { slash } from '../../../utils/base' import { F_CHECK, @@ -12,7 +13,6 @@ import { F_LONG_DASH, F_POINTER, } from '../../../utils/figures' -import type { SuiteHooks } from './../../../types/tasks' export const spinnerMap = new WeakMap string>() export const hookSpinnerMap = new WeakMap string>>() diff --git a/packages/vitest/src/node/reporters/reported-tasks.ts b/packages/vitest/src/node/reporters/reported-tasks.ts new file mode 100644 index 000000000000..ae69f876b729 --- /dev/null +++ b/packages/vitest/src/node/reporters/reported-tasks.ts @@ -0,0 +1,500 @@ +import type { + Custom as RunnerCustomCase, + Task as RunnerTask, + Test as RunnerTestCase, + File as RunnerTestFile, + Suite as RunnerTestSuite, + TaskMeta, +} from '@vitest/runner' +import type { TestError } from '@vitest/utils' +import { getTestName } from '../../utils/tasks' +import type { WorkspaceProject } from '../workspace' +import { TestProject } from '../reported-workspace-project' + +class ReportedTaskImplementation { + /** + * Task instance. + * @experimental Public runner task API is experimental and does not follow semver. + */ + public readonly task: RunnerTask + + /** + * The project assosiacted with the test or suite. + */ + public readonly project: TestProject + + /** + * Unique identifier. + * This ID is deterministic and will be the same for the same test across multiple runs. + * The ID is based on the project name, file path and test position. + */ + public readonly id: string + + /** + * Location in the file where the test or suite is defined. + */ + public readonly location: { line: number; column: number } | undefined + + protected constructor( + task: RunnerTask, + project: WorkspaceProject, + ) { + this.task = task + this.project = project.testProject || (project.testProject = new TestProject(project)) + this.id = task.id + this.location = task.location + } + + /** + * Creates a new reported task instance and stores it in the project's state for future use. + */ + static register(task: RunnerTask, project: WorkspaceProject) { + const state = new this(task, project) as TestCase | TestSuite | TestFile + storeTask(project, task, state) + return state + } +} + +export class TestCase extends ReportedTaskImplementation { + #fullName: string | undefined + + declare public readonly task: RunnerTestCase | RunnerCustomCase + public readonly type = 'test' + + /** + * Direct reference to the test file where the test or suite is defined. + */ + public readonly file: TestFile + + /** + * Name of the test. + */ + public readonly name: string + + /** + * Options that the test was initiated with. + */ + public readonly options: TaskOptions + + /** + * Parent suite. If the test was called directly inside the file, the parent will be the file. + */ + public readonly parent: TestSuite | TestFile + + protected constructor(task: RunnerTestCase | RunnerCustomCase, project: WorkspaceProject) { + super(task, project) + + this.name = task.name + this.file = getReportedTask(project, task.file) as TestFile + const suite = this.task.suite + if (suite) { + this.parent = getReportedTask(project, suite) as TestSuite + } + else { + this.parent = this.file + } + this.options = buildOptions(task) + } + + /** + * Full name of the test including all parent suites separated with `>`. + */ + public get fullName(): string { + if (this.#fullName === undefined) { + this.#fullName = getTestName(this.task, ' > ') + } + return this.#fullName + } + + /** + * Test results. Will be `undefined` if test is not finished yet or was just collected. + */ + public result(): TestResult | undefined { + const result = this.task.result + if (!result || result.state === 'run') { + return undefined + } + const state = result.state === 'fail' + ? 'failed' + : result.state === 'pass' + ? 'passed' + : 'skipped' + return { + state, + errors: result.errors as TestError[] | undefined, + } as TestResult + } + + /** + * Checks if the test did not fail the suite. + * If the test is not finished yet or was skipped, it will return `true`. + */ + public ok(): boolean { + const result = this.result() + return !result || result.state !== 'failed' + } + + /** + * Custom metadata that was attached to the test during its execution. + */ + public meta(): TaskMeta { + return this.task.meta + } + + /** + * Useful information about the test like duration, memory usage, etc. + * Diagnostic is only available after the test has finished. + */ + public diagnostic(): TestDiagnostic | undefined { + const result = this.task.result + // startTime should always be available if the test has properly finished + if (!result || result.state === 'run' || !result.startTime) { + return undefined + } + return { + heap: result.heap, + duration: result.duration!, + startTime: result.startTime, + retryCount: result.retryCount ?? 0, + repeatCount: result.repeatCount ?? 0, + flaky: !!result.retryCount && result.state === 'pass' && result.retryCount > 0, + } + } +} + +class TestCollection { + #task: RunnerTestSuite | RunnerTestFile + #project: WorkspaceProject + + constructor(task: RunnerTestSuite | RunnerTestFile, project: WorkspaceProject) { + this.#task = task + this.#project = project + } + + /** + * Returns the test or suite at a specific index in the array. + */ + at(index: number): TestCase | TestSuite | undefined { + if (index < 0) { + index = this.size + index + } + return getReportedTask(this.#project, this.#task.tasks[index]) as TestCase | TestSuite | undefined + } + + /** + * The number of tests and suites in the collection. + */ + get size(): number { + return this.#task.tasks.length + } + + /** + * Returns the collection in array form for easier manipulation. + */ + array(): (TestCase | TestSuite)[] { + return Array.from(this) + } + + /** + * Filters all tests that are part of this collection and its children. + */ + *allTests(state?: TestResult['state'] | 'running'): IterableIterator { + for (const child of this) { + if (child.type === 'suite') { + yield * child.children.allTests(state) + } + else if (state) { + const testState = getTestState(child) + if (state === testState) { + yield child + } + } + else { + yield child + } + } + } + + /** + * Filters only the tests that are part of this collection. + */ + *tests(state?: TestResult['state'] | 'running'): IterableIterator { + for (const child of this) { + if (child.type !== 'test') { + continue + } + + if (state) { + const testState = getTestState(child) + if (state === testState) { + yield child + } + } + else { + yield child + } + } + } + + /** + * Filters only the suites that are part of this collection. + */ + *suites(): IterableIterator { + for (const child of this) { + if (child.type === 'suite') { + yield child + } + } + } + + /** + * Filters all suites that are part of this collection and its children. + */ + *allSuites(): IterableIterator { + for (const child of this) { + if (child.type === 'suite') { + yield child + yield * child.children.allSuites() + } + } + } + + *[Symbol.iterator](): IterableIterator { + for (const task of this.#task.tasks) { + yield getReportedTask(this.#project, task) as TestSuite | TestCase + } + } +} + +export type { TestCollection } + +abstract class SuiteImplementation extends ReportedTaskImplementation { + declare public readonly task: RunnerTestSuite | RunnerTestFile + + /** + * Collection of suites and tests that are part of this suite. + */ + public readonly children: TestCollection + + protected constructor(task: RunnerTestSuite | RunnerTestFile, project: WorkspaceProject) { + super(task, project) + this.children = new TestCollection(task, project) + } +} + +export class TestSuite extends SuiteImplementation { + #fullName: string | undefined + + declare public readonly task: RunnerTestSuite + public readonly type = 'suite' + + /** + * Name of the test or the suite. + */ + public readonly name: string + + /** + * Direct reference to the test file where the test or suite is defined. + */ + public readonly file: TestFile + + /** + * Parent suite. If suite was called directly inside the file, the parent will be the file. + */ + public readonly parent: TestSuite | TestFile + + /** + * Options that suite was initiated with. + */ + public readonly options: TaskOptions + + protected constructor(task: RunnerTestSuite, project: WorkspaceProject) { + super(task, project) + + this.name = task.name + this.file = getReportedTask(project, task.file) as TestFile + const suite = this.task.suite + if (suite) { + this.parent = getReportedTask(project, suite) as TestSuite + } + else { + this.parent = this.file + } + this.options = buildOptions(task) + } + + /** + * Full name of the suite including all parent suites separated with `>`. + */ + public get fullName(): string { + if (this.#fullName === undefined) { + this.#fullName = getTestName(this.task, ' > ') + } + return this.#fullName + } +} + +export class TestFile extends SuiteImplementation { + declare public readonly task: RunnerTestFile + declare public readonly location: undefined + public readonly type = 'file' + + /** + * This is usually an absolute UNIX file path. + * It can be a virtual id if the file is not on the disk. + * This value corresponds to Vite's `ModuleGraph` id. + */ + public readonly moduleId: string + + protected constructor(task: RunnerTestFile, project: WorkspaceProject) { + super(task, project) + this.moduleId = task.filepath + } + + /** + * Useful information about the file like duration, memory usage, etc. + * If the file was not executed yet, all diagnostic values will return `0`. + */ + public diagnostic(): FileDiagnostic { + const setupDuration = this.task.setupDuration || 0 + const collectDuration = this.task.collectDuration || 0 + const prepareDuration = this.task.prepareDuration || 0 + const environmentSetupDuration = this.task.environmentLoad || 0 + const duration = this.task.result?.duration || 0 + return { + environmentSetupDuration, + prepareDuration, + collectDuration, + setupDuration, + duration, + } + } +} + +export interface TaskOptions { + each: boolean | undefined + concurrent: boolean | undefined + shuffle: boolean | undefined + retry: number | undefined + repeats: number | undefined + mode: 'run' | 'only' | 'skip' | 'todo' +} + +function buildOptions(task: RunnerTestCase | RunnerCustomCase | RunnerTestFile | RunnerTestSuite): TaskOptions { + return { + each: task.each, + concurrent: task.concurrent, + shuffle: task.shuffle, + retry: task.retry, + repeats: task.repeats, + mode: task.mode, + } +} + +export type TestResult = TestResultPassed | TestResultFailed | TestResultSkipped + +export interface TestResultPassed { + /** + * The test passed successfully. + */ + state: 'passed' + /** + * Errors that were thrown during the test execution. + * + * **Note**: If test was retried successfully, errors will still be reported. + */ + errors: TestError[] | undefined +} + +export interface TestResultFailed { + /** + * The test failed to execute. + */ + state: 'failed' + /** + * Errors that were thrown during the test execution. + */ + errors: TestError[] +} + +export interface TestResultSkipped { + /** + * The test was skipped with `only`, `skip` or `todo` flag. + * You can see which one was used in the `mode` option. + */ + state: 'skipped' + /** + * Skipped tests have no errors. + */ + errors: undefined +} + +export interface TestDiagnostic { + /** + * The amount of memory used by the test in bytes. + * This value is only available if the test was executed with `logHeapUsage` flag. + */ + heap: number | undefined + /** + * The time it takes to execute the test in ms. + */ + duration: number + /** + * The time in ms when the test started. + */ + startTime: number + /** + * The amount of times the test was retried. + */ + retryCount: number + /** + * The amount of times the test was repeated as configured by `repeats` option. + * This value can be lower if the test failed during the repeat and no `retry` is configured. + */ + repeatCount: number + /** + * If test passed on a second retry. + */ + flaky: boolean +} + +export interface FileDiagnostic { + /** + * The time it takes to import and initiate an environment. + */ + environmentSetupDuration: number + /** + * The time it takes Vitest to setup test harness (runner, mocks, etc.). + */ + prepareDuration: number + /** + * The time it takes to import the test file. + * This includes importing everything in the file and executing suite callbacks. + */ + collectDuration: number + /** + * The time it takes to import the setup file. + */ + setupDuration: number + /** + * Accumulated duration of all tests and hooks in the file. + */ + duration: number +} + +function getTestState(test: TestCase): TestResult['state'] | 'running' { + const result = test.result() + return result ? result.state : 'running' +} + +function storeTask(project: WorkspaceProject, runnerTask: RunnerTask, reportedTask: TestCase | TestSuite | TestFile): void { + project.ctx.state.reportedTasksMap.set(runnerTask, reportedTask) +} + +function getReportedTask(project: WorkspaceProject, runnerTask: RunnerTask): TestCase | TestSuite | TestFile { + const reportedTask = project.ctx.state.getReportedEntity(runnerTask) + if (!reportedTask) { + throw new Error(`Task instance was not found for ${runnerTask.type} "${runnerTask.name}"`) + } + return reportedTask +} diff --git a/packages/vitest/src/node/reporters/tap-flat.ts b/packages/vitest/src/node/reporters/tap-flat.ts index da93d9cf2abe..a5905d5e42ca 100644 --- a/packages/vitest/src/node/reporters/tap-flat.ts +++ b/packages/vitest/src/node/reporters/tap-flat.ts @@ -1,5 +1,5 @@ import type { Task } from '@vitest/runner' -import type { Vitest } from '../../node' +import type { Vitest } from '../core' import { TapReporter } from './tap' function flattenTasks(task: Task, baseName = ''): Task[] { diff --git a/packages/vitest/src/node/reporters/tap.ts b/packages/vitest/src/node/reporters/tap.ts index e9ab48e4fa3e..65953b31a224 100644 --- a/packages/vitest/src/node/reporters/tap.ts +++ b/packages/vitest/src/node/reporters/tap.ts @@ -1,7 +1,7 @@ import type { Task } from '@vitest/runner' import type { ErrorWithDiff, ParsedStack } from '@vitest/utils' -import type { Vitest } from '../../node' -import type { Reporter } from '../../types/reporter' +import type { Vitest } from '../core' +import type { Reporter } from '../types/reporter' import { parseErrorStacktrace } from '../../utils/source-map' import { IndentedLogger } from './renderers/indented-logger' diff --git a/packages/vitest/src/node/reporters/utils.ts b/packages/vitest/src/node/reporters/utils.ts index 7cc88b60f074..e3306fa0e36a 100644 --- a/packages/vitest/src/node/reporters/utils.ts +++ b/packages/vitest/src/node/reporters/utils.ts @@ -1,7 +1,9 @@ import type { ViteNodeRunner } from 'vite-node/client' -import type { Reporter, ResolvedConfig, Vitest } from '../../types' -import { BenchmarkReportsMap, ReportersMap } from './index' +import type { Reporter } from '../types/reporter' +import type { ResolvedConfig } from '../types/config' +import type { Vitest } from '../core' import type { BenchmarkBuiltinReporters, BuiltinReporters } from './index' +import { BenchmarkReportsMap, ReportersMap } from './index' async function loadCustomReporterModule( path: string, diff --git a/packages/vitest/src/node/reporters/verbose.ts b/packages/vitest/src/node/reporters/verbose.ts index 33b417511141..9f97221c4241 100644 --- a/packages/vitest/src/node/reporters/verbose.ts +++ b/packages/vitest/src/node/reporters/verbose.ts @@ -1,5 +1,5 @@ import c from 'tinyrainbow' -import type { TaskResultPack } from '../../types' +import type { TaskResultPack } from '@vitest/runner' import { getFullName } from '../../utils' import { F_RIGHT } from '../../utils/figures' import { DefaultReporter } from './default' diff --git a/packages/vitest/src/node/sequencers/types.ts b/packages/vitest/src/node/sequencers/types.ts index fd5237f350b5..5e10b2c00a24 100644 --- a/packages/vitest/src/node/sequencers/types.ts +++ b/packages/vitest/src/node/sequencers/types.ts @@ -1,4 +1,4 @@ -import type { Awaitable } from '../../types' +import type { Awaitable } from '../../types/general' import type { Vitest } from '../core' import type { WorkspaceSpec } from '../pool' diff --git a/packages/vitest/src/node/state.ts b/packages/vitest/src/node/state.ts index 919af2bc6f0e..dc7b79fafe91 100644 --- a/packages/vitest/src/node/state.ts +++ b/packages/vitest/src/node/state.ts @@ -1,10 +1,9 @@ import type { File, Task, TaskResultPack } from '@vitest/runner' - -// can't import actual functions from utils, because it's incompatible with @vitest/browsers import { createFileTask } from '@vitest/runner/utils' import type { AggregateError as AggregateErrorPonyfill } from '../utils/base' import type { UserConsoleLog } from '../types/general' import type { WorkspaceProject } from './workspace' +import { TestCase, TestFile, TestSuite } from './reporters/reported-tasks' export function isAggregateError(err: unknown): err is AggregateErrorPonyfill { if (typeof AggregateError !== 'undefined' && err instanceof AggregateError) { @@ -14,7 +13,6 @@ export function isAggregateError(err: unknown): err is AggregateErrorPonyfill { return err instanceof Error && 'errors' in err } -// Note this file is shared for both node and browser, be aware to avoid node specific logic export class StateManager { filesMap = new Map() pathsSet: Set = new Set() @@ -22,6 +20,7 @@ export class StateManager { taskFileMap = new WeakMap() errorsSet = new Set() processTimeoutCauses = new Set() + reportedTasksMap = new WeakMap() catchError(err: unknown, type: string): void { if (isAggregateError(err)) { @@ -98,7 +97,7 @@ export class StateManager { }) } - collectFiles(files: File[] = []) { + collectFiles(project: WorkspaceProject, files: File[] = []) { files.forEach((file) => { const existing = this.filesMap.get(file.filepath) || [] const otherProject = existing.filter( @@ -114,16 +113,14 @@ export class StateManager { } otherProject.push(file) this.filesMap.set(file.filepath, otherProject) - this.updateId(file) + this.updateId(file, project) }) } - // this file is reused by ws-client, and should not rely on heavy dependencies like workspace clearFiles( - _project: { config: { name: string | undefined; root: string } }, + project: WorkspaceProject, paths: string[] = [], ) { - const project = _project as WorkspaceProject paths.forEach((path) => { const files = this.filesMap.get(path) const fileTask = createFileTask( @@ -132,6 +129,7 @@ export class StateManager { project.config.name, ) fileTask.local = true + TestFile.register(fileTask, project) this.idMap.set(fileTask.id, fileTask) if (!files) { this.filesMap.set(path, [fileTask]) @@ -150,18 +148,33 @@ export class StateManager { }) } - updateId(task: Task) { + updateId(task: Task, project: WorkspaceProject) { if (this.idMap.get(task.id) === task) { return } + + if (task.type === 'suite' && 'filepath' in task) { + TestFile.register(task, project) + } + else if (task.type === 'suite') { + TestSuite.register(task, project) + } + else { + TestCase.register(task, project) + } + this.idMap.set(task.id, task) if (task.type === 'suite') { task.tasks.forEach((task) => { - this.updateId(task) + this.updateId(task, project) }) } } + getReportedEntity(task: Task) { + return this.reportedTasksMap.get(task) + } + updateTasks(packs: TaskResultPack[]) { for (const [id, result, meta] of packs) { const task = this.idMap.get(id) @@ -192,9 +205,12 @@ export class StateManager { ).length } - cancelFiles(files: string[], root: string, projectName: string) { + cancelFiles(files: string[], project: WorkspaceProject) { this.collectFiles( - files.map(filepath => createFileTask(filepath, root, projectName)), + project, + files.map(filepath => + createFileTask(filepath, project.config.root, project.config.name), + ), ) } } diff --git a/packages/vitest/src/types/benchmark.ts b/packages/vitest/src/node/types/benchmark.ts similarity index 57% rename from packages/vitest/src/types/benchmark.ts rename to packages/vitest/src/node/types/benchmark.ts index 580c1ccfd4ff..e2ee6c53a884 100644 --- a/packages/vitest/src/types/benchmark.ts +++ b/packages/vitest/src/node/types/benchmark.ts @@ -1,14 +1,6 @@ -import type { Custom } from '@vitest/runner' -import type { ChainableFunction } from '@vitest/runner/utils' import type { Arrayable } from '@vitest/utils' -import type { - Bench as BenchFactory, - Options as BenchOptions, - Task as BenchTask, - TaskResult as BenchTaskResult, - TaskResult as TinybenchResult, -} from 'tinybench' -import type { BenchmarkBuiltinReporters } from '../node/reporters' + +import type { BenchmarkBuiltinReporters } from '../reporters' import type { Reporter } from './reporter' export interface BenchmarkUserOptions { @@ -59,27 +51,3 @@ export interface BenchmarkUserOptions { */ outputJson?: string } - -export interface Benchmark extends Custom { - meta: { - benchmark: true - result?: BenchTaskResult - } -} - -export interface BenchmarkResult extends TinybenchResult { - name: string - rank: number -} - -export type BenchFunction = (this: BenchFactory) => Promise | void -type ChainableBenchmarkAPI = ChainableFunction< - 'skip' | 'only' | 'todo', - (name: string | Function, fn?: BenchFunction, options?: BenchOptions) => void -> -export type BenchmarkAPI = ChainableBenchmarkAPI & { - skipIf: (condition: any) => ChainableBenchmarkAPI - runIf: (condition: any) => ChainableBenchmarkAPI -} - -export { BenchTaskResult, BenchOptions, BenchFactory, BenchTask } diff --git a/packages/vitest/src/types/browser.ts b/packages/vitest/src/node/types/browser.ts similarity index 98% rename from packages/vitest/src/types/browser.ts rename to packages/vitest/src/node/types/browser.ts index 4f8ed9cb85ba..2c88a74d56a6 100644 --- a/packages/vitest/src/types/browser.ts +++ b/packages/vitest/src/node/types/browser.ts @@ -2,7 +2,7 @@ import type { Awaitable, ErrorWithDiff, ParsedStack } from '@vitest/utils' import type { ViteDevServer } from 'vite' import type { CancelReason } from '@vitest/runner' import type { StackTraceParserOptions } from '@vitest/utils/source-map' -import type { WorkspaceProject } from '../node/workspace' +import type { WorkspaceProject } from '../workspace' import type { ApiConfig } from './config' export interface BrowserProviderInitializationOptions { @@ -240,4 +240,5 @@ export interface ResolvedBrowserOptions extends BrowserConfigOptions { width: number height: number } + screenshotFailures: boolean } diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/node/types/config.ts similarity index 95% rename from packages/vitest/src/types/config.ts rename to packages/vitest/src/node/types/config.ts index bfb0b849614c..bf866ec4fa8a 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/node/types/config.ts @@ -3,24 +3,29 @@ import type { PrettyFormatOptions } from '@vitest/pretty-format' import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' import type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner' import type { ViteNodeServerOptions } from 'vite-node' +import type { SnapshotStateOptions } from '@vitest/snapshot' import type { BuiltinReporterOptions, BuiltinReporters, -} from '../node/reporters' -import type { TestSequencerConstructor } from '../node/sequencers/types' -import type { ChaiConfig } from '../integrations/chai/config' +} from '../reporters' +import type { TestSequencerConstructor } from '../sequencers/types' +import type { ChaiConfig } from '../../integrations/chai/config' +import type { Arrayable, ErrorWithDiff, ParsedStack } from '../../types/general' +import type { JSDOMOptions } from '../../types/jsdom-options' +import type { HappyDOMOptions } from '../../types/happy-dom-options' +import type { EnvironmentOptions } from '../../types/environment' import type { CoverageOptions, ResolvedCoverageOptions } from './coverage' -import type { JSDOMOptions } from './jsdom-options' -import type { HappyDOMOptions } from './happy-dom-options' +import type { Pool, PoolOptions, ResolvedPoolOptions } from './pool-options' +import type { BrowserConfigOptions, ResolvedBrowserOptions } from './browser' import type { Reporter } from './reporter' -import type { SnapshotStateOptions } from './snapshot' -import type { Arrayable, ParsedStack } from './general' import type { BenchmarkUserOptions } from './benchmark' -import type { BrowserConfigOptions, ResolvedBrowserOptions } from './browser' -import type { Pool, PoolOptions, ResolvedPoolOptions } from './pool-options' +export type { CoverageOptions, ResolvedCoverageOptions } +export type { BenchmarkUserOptions } +export type { CoverageV8Options, CoverageIstanbulOptions } from './coverage' export type { BrowserScript, BrowserConfigOptions } from './browser' export type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner' +export type { SerializedConfig, RuntimeConfig } from '../../runtime/config' export type BuiltinEnvironment = | 'node' @@ -39,16 +44,7 @@ export type ApiConfig = Pick< 'port' | 'strictPort' | 'host' | 'middlewareMode' > -export type { JSDOMOptions, HappyDOMOptions } - -export interface EnvironmentOptions { - /** - * jsdom options. - */ - jsdom?: JSDOMOptions - happyDOM?: HappyDOMOptions - [x: string]: unknown -} +export type { JSDOMOptions, HappyDOMOptions, EnvironmentOptions } export type VitestRunMode = 'test' | 'benchmark' @@ -624,7 +620,7 @@ export interface InlineConfig { * * Return `false` to omit the frame. */ - onStackTrace?: (error: Error, frame: ParsedStack) => boolean | void + onStackTrace?: (error: ErrorWithDiff, frame: ParsedStack) => boolean | void /** * Indicates if CSS files should be processed. @@ -955,11 +951,18 @@ export interface ResolvedConfig | 'pool' | 'cliExclude' | 'diff' + | 'setupFiles' + | 'snapshotEnvironment' + | 'bail' > { mode: VitestRunMode base?: string diff?: string + bail?: number + + setupFiles: string[] + snapshotEnvironment?: string config?: string filters?: string[] @@ -1016,9 +1019,7 @@ export interface ResolvedConfig minWorkers: number } -export type ProjectConfig = Omit< - UserConfig, - | 'sequencer' +type NonProjectOptions = | 'shard' | 'watch' | 'run' @@ -1026,7 +1027,6 @@ export type ProjectConfig = Omit< | 'update' | 'reporters' | 'outputFile' - | 'poolOptions' | 'teardownTimeout' | 'silent' | 'forceRerunTriggers' @@ -1044,11 +1044,17 @@ export type ProjectConfig = Omit< | 'slowTestThreshold' | 'inspect' | 'inspectBrk' - | 'deps' | 'coverage' | 'maxWorkers' | 'minWorkers' | 'fileParallelism' + +export type ProjectConfig = Omit< + UserConfig, + NonProjectOptions + | 'sequencer' + | 'deps' + | 'poolOptions' > & { sequencer?: Omit deps?: Omit @@ -1062,23 +1068,9 @@ export type ProjectConfig = Omit< } } -export type RuntimeConfig = Pick< - UserConfig, - | 'allowOnly' - | 'testTimeout' - | 'hookTimeout' - | 'clearMocks' - | 'mockReset' - | 'restoreMocks' - | 'fakeTimers' - | 'maxConcurrency' - | 'expect' - | 'printConsoleTrace' -> & { - sequence?: { - concurrent?: boolean - hooks?: SequenceHooks - } -} +export type ResolvedProjectConfig = Omit< + ResolvedConfig, + NonProjectOptions +> -export type { UserWorkspaceConfig } from '../config' +export type { UserWorkspaceConfig } from '../../public/config' diff --git a/packages/vitest/src/types/coverage.ts b/packages/vitest/src/node/types/coverage.ts similarity index 95% rename from packages/vitest/src/types/coverage.ts rename to packages/vitest/src/node/types/coverage.ts index 9bc381515b36..d61e0715e2ec 100644 --- a/packages/vitest/src/types/coverage.ts +++ b/packages/vitest/src/node/types/coverage.ts @@ -1,8 +1,7 @@ import type { TransformResult as ViteTransformResult } from 'vite' import type { ReportOptions } from 'istanbul-reports' -import type { Vitest } from '../node' -import type { Arrayable } from './general' -import type { AfterSuiteRunMeta } from './worker' +import type { AfterSuiteRunMeta, Arrayable } from '../../types/general' +import type { Vitest } from '../core' type TransformResult = | string @@ -87,9 +86,9 @@ type CoverageReporterWithOptions< : [ReporterName, Partial] : [ReporterName, Record] -type Provider = 'v8' | 'istanbul' | 'custom' | undefined +export type CoverageProviderName = 'v8' | 'istanbul' | 'custom' | undefined -export type CoverageOptions = +export type CoverageOptions = T extends 'istanbul' ? { provider: T } & CoverageIstanbulOptions : T extends 'v8' ? { @@ -116,7 +115,7 @@ type FieldsWithDefaultValues = | 'allowExternal' | 'processingConcurrency' -export type ResolvedCoverageOptions = +export type ResolvedCoverageOptions = CoverageOptions & Required, FieldsWithDefaultValues>> & { // Resolved fields which may have different typings as public configuration API has reporter: CoverageReporterWithOptions[] diff --git a/packages/vitest/src/types/pool-options.ts b/packages/vitest/src/node/types/pool-options.ts similarity index 100% rename from packages/vitest/src/types/pool-options.ts rename to packages/vitest/src/node/types/pool-options.ts diff --git a/packages/vitest/src/types/reporter.ts b/packages/vitest/src/node/types/reporter.ts similarity index 66% rename from packages/vitest/src/types/reporter.ts rename to packages/vitest/src/node/types/reporter.ts index 968eb85da159..975a86eafe1d 100644 --- a/packages/vitest/src/types/reporter.ts +++ b/packages/vitest/src/node/types/reporter.ts @@ -1,11 +1,12 @@ -import type { Vitest } from '../node' -import type { Awaitable, UserConsoleLog } from './general' -import type { File, TaskResultPack } from './tasks' +import type { File, TaskResultPack } from '@vitest/runner' +import type { Vitest } from '../core' +import type { SerializedSpec } from '../../runtime/types/utils' +import type { Awaitable, UserConsoleLog } from '../../types/general' export interface Reporter { onInit?: (ctx: Vitest) => void onPathsCollected?: (paths?: string[]) => Awaitable - onSpecsCollected?: (specs?: SerializableSpec[]) => Awaitable + onSpecsCollected?: (specs?: SerializedSpec[]) => Awaitable onCollected?: (files?: File[]) => Awaitable onFinished?: ( files: File[], @@ -13,20 +14,10 @@ export interface Reporter { coverage?: unknown ) => Awaitable onTaskUpdate?: (packs: TaskResultPack[]) => Awaitable - onTestRemoved?: (trigger?: string) => Awaitable onWatcherStart?: (files?: File[], errors?: unknown[]) => Awaitable onWatcherRerun?: (files: string[], trigger?: string) => Awaitable - onServerRestart?: (reason?: string) => Awaitable - onUserConsoleLog?: (log: UserConsoleLog) => Awaitable - onProcessTimeout?: () => Awaitable } - -export type { Vitest } -export type SerializableSpec = [ - project: { name: string | undefined; root: string }, - file: string, -] diff --git a/packages/vitest/src/types/vite.ts b/packages/vitest/src/node/types/vite.ts similarity index 100% rename from packages/vitest/src/types/vite.ts rename to packages/vitest/src/node/types/vite.ts diff --git a/packages/vitest/src/node/types/worker.ts b/packages/vitest/src/node/types/worker.ts new file mode 100644 index 000000000000..e94d071caf81 --- /dev/null +++ b/packages/vitest/src/node/types/worker.ts @@ -0,0 +1,6 @@ +import type { MessagePort } from 'node:worker_threads' +import type { ContextRPC } from '../../types/worker' + +export interface WorkerContext extends ContextRPC { + port: MessagePort +} diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index cda8f54a7d5d..40a6a21b5ed8 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -1,6 +1,6 @@ import { promises as fs } from 'node:fs' -import { rm } from 'node:fs/promises' import { tmpdir } from 'node:os' +import { rm } from 'node:fs/promises' import fg from 'fast-glob' import mm from 'micromatch' import { @@ -18,24 +18,27 @@ import type { } from 'vite' import { ViteNodeRunner } from 'vite-node/client' import { ViteNodeServer } from 'vite-node/server' +import type { Typechecker } from '../typecheck/typechecker' +import { deepMerge, nanoid } from '../utils/base' +import { setup } from '../api/setup' +import type { ProvidedContext } from '../types/general' import type { - ProvidedContext, ResolvedConfig, + SerializedConfig, UserConfig, UserWorkspaceConfig, - Vitest, -} from '../types' -import type { Typechecker } from '../typecheck/typechecker' -import { deepMerge, nanoid } from '../utils/base' -import { setup } from '../api/setup' -import type { BrowserServer } from '../types/browser' -import { isBrowserEnabled, resolveConfig } from './config' +} from './types/config' +import type { BrowserServer } from './types/browser' +import { isBrowserEnabled, resolveConfig } from './config/resolveConfig' import { WorkspaceVitestPlugin } from './plugins/workspace' import { createViteServer } from './vite' import type { GlobalSetupFile } from './globalSetup' import { loadGlobalSetupFiles } from './globalSetup' import { MocksPlugins } from './plugins/mocks' import { CoverageTransform } from './plugins/coverageTransform' +import { serializeConfig } from './config/serializeConfig' +import type { Vitest } from './core' +import { TestProject } from './reported-workspace-project' interface InitializeProjectOptions extends UserWorkspaceConfig { workspaceConfigPath: string @@ -95,6 +98,8 @@ export class WorkspaceProject { testFilesList: string[] | null = null + public testProject!: TestProject + public readonly id = nanoid() public readonly tmpDir = join(tmpdir(), this.id) @@ -205,12 +210,6 @@ export class WorkspaceProject { return mod?.ssrTransformResult?.map || mod?.transformResult?.map } - getBrowserSourceMapModuleById( - id: string, - ): TransformResult['map'] | undefined { - return this.browser?.vite.moduleGraph.getModuleById(id)?.transformResult?.map - } - get reporters() { return this.ctx.reporters } @@ -365,6 +364,7 @@ export class WorkspaceProject { project.server = ctx.server project.runner = ctx.runner project.config = ctx.config + project.testProject = new TestProject(project) return project } @@ -384,6 +384,7 @@ export class WorkspaceProject { server.config, this.ctx.logger, ) + this.testProject = new TestProject(this) this.server = server @@ -403,115 +404,24 @@ export class WorkspaceProject { await this.initBrowserServer(this.server.config.configFile) } - isBrowserEnabled() { + isBrowserEnabled(): boolean { return isBrowserEnabled(this.config) } - getSerializableConfig(method: 'run' | 'collect' = 'run') { - const optimizer = this.config.deps?.optimizer - const poolOptions = this.config.poolOptions - - // Resolve from server.config to avoid comparing against default value - const isolate = this.server?.config?.test?.isolate - - const config = deepMerge( - { - ...this.config, - - poolOptions: { - forks: { - singleFork: - poolOptions?.forks?.singleFork - ?? this.ctx.config.poolOptions?.forks?.singleFork - ?? false, - isolate: - poolOptions?.forks?.isolate - ?? isolate - ?? this.ctx.config.poolOptions?.forks?.isolate - ?? true, - }, - threads: { - singleThread: - poolOptions?.threads?.singleThread - ?? this.ctx.config.poolOptions?.threads?.singleThread - ?? false, - isolate: - poolOptions?.threads?.isolate - ?? isolate - ?? this.ctx.config.poolOptions?.threads?.isolate - ?? true, - }, - vmThreads: { - singleThread: - poolOptions?.vmThreads?.singleThread - ?? this.ctx.config.poolOptions?.vmThreads?.singleThread - ?? false, - }, - }, - - reporters: [], - deps: { - ...this.config.deps, - optimizer: { - web: { - enabled: optimizer?.web?.enabled ?? true, - }, - ssr: { - enabled: optimizer?.ssr?.enabled ?? true, - }, - }, - }, - snapshotOptions: { - ...this.ctx.config.snapshotOptions, - expand: - this.config.snapshotOptions.expand - ?? this.ctx.config.snapshotOptions.expand, - resolveSnapshotPath: undefined, - }, - onConsoleLog: undefined!, - onStackTrace: undefined!, - sequence: { - ...this.ctx.config.sequence, - sequencer: undefined!, - }, - benchmark: { - ...this.config.benchmark, - reporters: [], - }, - inspect: this.ctx.config.inspect, - inspectBrk: this.ctx.config.inspectBrk, - inspector: this.ctx.config.inspector, - alias: [], - includeTaskLocation: - this.config.includeTaskLocation - ?? this.ctx.config.includeTaskLocation, - env: { - ...this.server?.config.env, - ...this.config.env, - }, - browser: { - ...this.config.browser, - orchestratorScripts: [], - testerScripts: [], - commands: {}, - }, - printConsoleTrace: - this.config.printConsoleTrace ?? this.ctx.config.printConsoleTrace, - }, - this.ctx.configOverride || ({} as any), - ) as ResolvedConfig - - // disable heavy features when collecting because they are not needed - if (method === 'collect') { - config.coverage.enabled = false - if (config.browser.provider && config.browser.provider !== 'preview') { - config.browser.headless = true - } - config.snapshotSerializers = [] - config.diff = undefined + getSerializableConfig(): SerializedConfig { + // TODO: serialize the config _once_ or when needed + const config = serializeConfig( + this.config, + this.ctx.config, + this.server.config, + ) + if (!this.ctx.configOverride) { + return config } - - return config + return deepMerge( + config, + this.ctx.configOverride, + ) } close() { @@ -530,7 +440,7 @@ export class WorkspaceProject { private async clearTmpDir() { try { - await rm(this.tmpDir, { force: true, recursive: true }) + await rm(this.tmpDir, { recursive: true }) } catch {} } diff --git a/packages/vitest/src/browser.ts b/packages/vitest/src/public/browser.ts similarity index 69% rename from packages/vitest/src/browser.ts rename to packages/vitest/src/public/browser.ts index 2aedb49fb4f2..005fdf3e9cf0 100644 --- a/packages/vitest/src/browser.ts +++ b/packages/vitest/src/public/browser.ts @@ -3,11 +3,11 @@ export { setupCommonEnv, loadDiffConfig, loadSnapshotSerializers, -} from './runtime/setup-common' +} from '../runtime/setup-common' export { takeCoverageInsideWorker, stopCoverageInsideWorker, getCoverageProvider, startCoverageInsideWorker, -} from './integrations/coverage' -export * as SpyModule from './integrations/spy' +} from '../integrations/coverage' +export * as SpyModule from '../integrations/spy' diff --git a/packages/vitest/src/config.ts b/packages/vitest/src/public/config.ts similarity index 61% rename from packages/vitest/src/config.ts rename to packages/vitest/src/public/config.ts index 6b80fd38df45..ee605beb662d 100644 --- a/packages/vitest/src/config.ts +++ b/packages/vitest/src/public/config.ts @@ -1,5 +1,7 @@ +import '../node/types/vite' + import type { ConfigEnv, UserConfig as ViteUserConfig } from 'vite' -import type { ProjectConfig } from './types' +import type { ProjectConfig } from '../node/types/config' export interface UserWorkspaceConfig extends ViteUserConfig { test?: ProjectConfig @@ -12,9 +14,9 @@ export { defaultInclude, defaultExclude, coverageConfigDefaults, -} from './defaults' +} from '../defaults' export { mergeConfig } from 'vite' -export { extraInlineDeps } from './constants' +export { extraInlineDeps } from '../constants' export type { Plugin } from 'vite' export type { ConfigEnv, ViteUserConfig as UserConfig } @@ -48,12 +50,22 @@ export function defineConfig(config: UserConfigExport): UserConfigExport { return config } -export function defineProject(config: T): T { +export function defineProject(config: UserWorkspaceConfig): UserWorkspaceConfig +export function defineProject(config: Promise): Promise +export function defineProject(config: UserProjectConfigFn): UserProjectConfigFn +export function defineProject(config: UserProjectConfigExport): UserProjectConfigExport +export function defineProject(config: UserProjectConfigExport): UserProjectConfigExport { return config } -type Workspace = string | (UserProjectConfigExport & { extends?: string }) +type WorkspaceProjectConfiguration = string | (UserProjectConfigExport & { + /** + * Relative path to the extendable config. All other options will be merged with this config. + * @example '../vite.config.ts' + */ + extends?: string +}) -export function defineWorkspace(config: Workspace[]): Workspace[] { +export function defineWorkspace(config: WorkspaceProjectConfiguration[]): WorkspaceProjectConfiguration[] { return config } diff --git a/packages/vitest/src/public/coverage.ts b/packages/vitest/src/public/coverage.ts new file mode 100644 index 000000000000..635589745416 --- /dev/null +++ b/packages/vitest/src/public/coverage.ts @@ -0,0 +1 @@ +export { BaseCoverageProvider } from '../utils/coverage' diff --git a/packages/vitest/src/public/environments.ts b/packages/vitest/src/public/environments.ts new file mode 100644 index 000000000000..52d9a0e0c4f3 --- /dev/null +++ b/packages/vitest/src/public/environments.ts @@ -0,0 +1,7 @@ +export { environments as builtinEnvironments } from '../integrations/env/index' +export { populateGlobal } from '../integrations/env/utils' +export type { + EnvironmentReturn, + VmEnvironmentReturn, + Environment, +} from '../types/environment' diff --git a/packages/vitest/src/public/index.ts b/packages/vitest/src/public/index.ts new file mode 100644 index 000000000000..3b0293034179 --- /dev/null +++ b/packages/vitest/src/public/index.ts @@ -0,0 +1,354 @@ +// TODO: deprecate in favor of `` +import '../node/types/vite' +import '../types/global' + +import type { + Custom as Custom_, + File as File_, + Suite as Suite_, + Task as Task_, + Test as Test_, +} from '@vitest/runner' +import type { + CollectLineNumbers as CollectLineNumbers_, + CollectLines as CollectLines_, + Context as Context_, + RawErrsMap as RawErrsMap_, + RootAndTarget as RootAndTarget_, + TscErrorInfo as TscErrorInfo_, +} from '../typecheck/types' + +import type { + ArgumentsType as ArgumentsType_, + Arrayable as Arrayable_, + Awaitable as Awaitable_, + Constructable as Constructable_, + MutableArray as MutableArray_, + Nullable as Nullable_, + OnServerRestartHandler as OnServerRestartHandler_, +} from '../types/general' + +import type { + EnvironmentReturn as EnvironmentReturn_, + Environment as Environment_, + ResolvedTestEnvironment as ResolvedTestEnvironment_, + VmEnvironmentReturn as VmEnvironmentReturn_, +} from '../types/environment' + +import type { + BaseCoverageOptions as BaseCoverageOptions_, + CoverageIstanbulOptions as CoverageIstanbulOptions_, + CoverageOptions as CoverageOptions_, + CoverageProviderModule as CoverageProviderModule_, + CoverageProviderName, + CoverageProvider as CoverageProvider_, + CoverageReporter as CoverageReporter_, + CoverageV8Options as CoverageV8Options_, + CustomProviderOptions as CustomProviderOptions_, + ReportContext as ReportContext_, + ResolvedCoverageOptions as ResolvedCoverageOptions_, +} from '../node/types/coverage' + +import type { + /** @deprecated import from `vitest/node` instead */ + Reporter as Reporter_, +} from '../node/types/reporter' +import type { + /** @deprecated import from `vitest/node` instead */ + Vitest as Vitest_, +} from '../node/core' +import type { + ApiConfig as ApiConfig_, + BrowserConfigOptions as BrowserConfigOptions_, + BrowserScript as BrowserScript_, + BuiltinEnvironment as BuiltinEnvironment_, + CSSModuleScopeStrategy as CSSModuleScopeStrategy_, + DepsOptimizationOptions as DepsOptimizationOptions_, + EnvironmentOptions as EnvironmentOptions_, + HappyDOMOptions as HappyDOMOptions_, + InlineConfig as InlineConfig_, + JSDOMOptions as JSDOMOptions_, + PoolOptions as PoolOptions_, + Pool as Pool_, + ProjectConfig as ProjectConfig_, + ResolvedConfig as ResolvedConfig_, + SequenceHooks as SequenceHooks_, + SequenceSetupFiles as SequenceSetupFiles_, + TransformModePatterns as TransformModePatterns_, + TypecheckConfig as TypecheckConfig_, + UserConfig as UserConfig_, + UserWorkspaceConfig as UserWorkspaceConfig_, + VitestEnvironment as VitestEnvironment_, + VitestRunMode as VitestRunMode_, +} from '../node/types/config' +import type { + BenchmarkUserOptions as BenchmarkUserOptions_, +} from '../node/types/benchmark' + +import type { SerializedSpec } from '../runtime/types/utils' + +export { + suite, + test, + describe, + it, + beforeAll, + beforeEach, + afterAll, + afterEach, + onTestFailed, + onTestFinished, +} from '@vitest/runner' +export { bench } from '../runtime/benchmark' +export { expectTypeOf } from '../typecheck/expectTypeOf' +export { assertType } from '../typecheck/assertType' + +export { runOnce, isFirstRun } from '../integrations/run-once' +export { createExpect, assert, should, chai, expect } from '../integrations/chai' +export { vi, vitest } from '../integrations/vi' +export { getRunningMode, isWatchMode } from '../integrations/utils' +export { inject } from '../integrations/inject' + +export type { VitestUtils } from '../integrations/vi' + +export type { ExpectTypeOf } from '../typecheck/expectTypeOf' +export type { AssertType } from '../typecheck/assertType' + +/** @deprecated import `TypeCheckRawErrorsMap` from `vitest/node` instead */ +export type RawErrsMap = RawErrsMap_ +/** @deprecated import `TypeCheckErrorInfo` from `vitest/node` instead */ +export type TscErrorInfo = TscErrorInfo_ +/** @deprecated import `TypeCheckCollectLineNumbers` from `vitest/node` instead */ +export type CollectLineNumbers = CollectLineNumbers_ +/** @deprecated import `TypeCheckCollectLines` from `vitest/node` instead */ +export type CollectLines = CollectLines_ +/** @deprecated import `TypeCheckRootAndTarget` from `vitest/node` instead */ +export type RootAndTarget = RootAndTarget_ +/** @deprecated import `TypeCheckContext` from `vitest/node` instead */ +export type Context = Context_ + +/** @deprecated use `RunnerTestSuite` instead */ +export type Suite = Suite_ +/** @deprecated use `RunnerTestFile` instead */ +export type File = File_ +/** @deprecated use `RunnerTestCase` instead */ +export type Test = Test_ +/** @deprecated use `RunnerCustomCase` instead */ +export type Custom = Custom_ +/** @deprecated use `RunnerTask` instead */ +export type Task = Task_ + +export type { + RunMode, + TaskState, + TaskBase, + TaskResult, + TaskResultPack, + Suite as RunnerTestSuite, + File as RunnerTestFile, + Test as RunnerTestCase, + Task as RunnerTask, + Custom as RunnerCustomCase, + DoneCallback, + TestFunction, + TestOptions, + TestAPI, + SuiteAPI, + HookListener, + HookCleanupCallback, + SuiteHooks, + SuiteCollector, + SuiteFactory, + RuntimeContext, + TestContext, + TaskContext, + ExtendedContext, + TaskCustomOptions, + OnTestFailedHandler, + TaskMeta, +} from '@vitest/runner' +export type { + RuntimeRPC, + RunnerRPC, +} from '../types/rpc' +export type { + SnapshotData, + SnapshotUpdateState, + SnapshotStateOptions, + SnapshotMatchOptions, + SnapshotResult, + UncheckedSnapshot, + SnapshotSummary, + SnapshotSerializer, +} from '@vitest/snapshot' + +export type { + ResolveIdFunction, + WorkerRPC, + WorkerGlobalState, + ContextTestEnvironment, + ContextRPC, +} from '../types/worker' +export type { + /** @deprecated import from `vitest/node` instead */ + WorkerContext, +} from '../node/types/worker' + +/** @deprecated do not use, internal helper */ +export type Awaitable = Awaitable_ +/** @deprecated do not use, internal helper */ +export type Nullable = Nullable_ +/** @deprecated do not use, internal helper */ +export type Arrayable = Arrayable_ +/** @deprecated do not use, internal helper */ +export type ArgumentsType = ArgumentsType_ +/** @deprecated do not use, internal helper */ +export type MutableArray = MutableArray_ +/** @deprecated do not use, internal helper */ +export type Constructable = Constructable_ +/** @deprecated import from `vitest/node` instead */ +export type OnServerRestartHandler = OnServerRestartHandler_ + +export type { + ErrorWithDiff, + ParsedStack, + ModuleCache, + UserConsoleLog, + ModuleGraphData, + ProvidedContext, + AfterSuiteRunMeta, +} from '../types/general' + +export type { TestError, SerializedError } from '@vitest/utils' + +/** @deprecated import from `vitest/environments` instead */ +export type EnvironmentReturn = EnvironmentReturn_ +/** @deprecated import from `vitest/environments` instead */ +export type VmEnvironmentReturn = VmEnvironmentReturn_ +/** @deprecated import from `vitest/environments` instead */ +export type Environment = Environment_ +/** @deprecated do not use it */ +export type ResolvedTestEnvironment = ResolvedTestEnvironment_ + +/** @deprecated import from `vitest/node` instead */ +export type CoverageProvider = CoverageProvider_ +/** @deprecated import from `vitest/node` instead */ +export type ReportContext = ReportContext_ +/** @deprecated import from `vitest/node` instead */ +export type CoverageProviderModule = CoverageProviderModule_ +/** @deprecated import from `vitest/node` instead */ +export type CoverageReporter = CoverageReporter_ +/** @deprecated import from `vitest/node` instead */ +export type CoverageOptions = CoverageOptions_ +/** @deprecated import from `vitest/node` instead */ +export type ResolvedCoverageOptions = ResolvedCoverageOptions_ +/** @deprecated import from `vitest/node` instead */ +export type BaseCoverageOptions = BaseCoverageOptions_ +/** @deprecated import from `vitest/node` instead */ +export type CoverageIstanbulOptions = CoverageIstanbulOptions_ +/** @deprecated import from `vitest/node` instead */ +export type CoverageV8Options = CoverageV8Options_ +/** @deprecated import from `vitest/node` instead */ +export type CustomProviderOptions = CustomProviderOptions_ + +export type { CancelReason } from '@vitest/runner' +export type { DiffOptions } from '@vitest/utils/diff' +export type { + MockedFunction, + MockedObject, + MockInstance, + Mock, + MockContext, + Mocked, + MockedClass, +} from '../integrations/spy' +export type { BrowserUI } from '../types/ui' + +/** @deprecated import from `vitest/node` instead */ +export type Reporter = Reporter_ +/** @deprecated import from `vitest/node` instead */ +export type Vitest = Vitest_ + +export type { + ExpectStatic, + AsymmetricMatchersContaining, + JestAssertion, + Assertion, + ExpectPollOptions, +} from '@vitest/expect' + +export type { + SerializedConfig, + RuntimeConfig, + SerializedCoverageConfig, +} from '../runtime/config' + +/** @deprecated import from `vitest/node` instead */ +export type BrowserScript = BrowserScript_ +/** @deprecated import from `vitest/node` instead */ +export type BrowserConfigOptions = BrowserConfigOptions_ +/** @deprecated import from `vitest/node` instead */ +export type SequenceHooks = SequenceHooks_ +/** @deprecated import from `vitest/node` instead */ +export type SequenceSetupFiles = SequenceSetupFiles_ +/** @deprecated import from `vitest/node` instead */ +export type BuiltinEnvironment = BuiltinEnvironment_ +/** @deprecated import from `vitest/node` instead */ +export type VitestEnvironment = VitestEnvironment_ +/** @deprecated import from `vitest/node` instead */ +export type Pool = Pool_ +/** @deprecated import from `vitest/node` instead */ +export type PoolOptions = PoolOptions_ +/** @deprecated import from `vitest/node` instead */ +export type CSSModuleScopeStrategy = CSSModuleScopeStrategy_ +/** @deprecated import from `vitest/node` instead */ +export type ApiConfig = ApiConfig_ +/** @deprecated import from `vitest/node` instead */ +export type JSDOMOptions = JSDOMOptions_ +/** @deprecated import from `vitest/node` instead */ +export type HappyDOMOptions = HappyDOMOptions_ +/** @deprecated import from `vitest/node` instead */ +export type EnvironmentOptions = EnvironmentOptions_ +/** @deprecated import from `vitest/node` instead */ +export type VitestRunMode = VitestRunMode_ +/** @deprecated import from `vitest/node` instead */ +export type DepsOptimizationOptions = DepsOptimizationOptions_ +/** @deprecated import from `vitest/node` instead */ +export type TransformModePatterns = TransformModePatterns_ +/** @deprecated import from `vitest/node` instead */ +export type InlineConfig = InlineConfig_ +/** @deprecated import from `vitest/node` instead */ +export type TypecheckConfig = TypecheckConfig_ +/** @deprecated import from `vitest/node` instead */ +export type UserConfig = UserConfig_ +/** @deprecated import from `vitest/node` instead */ +export type ResolvedConfig = ResolvedConfig_ +/** @deprecated import from `vitest/node` instead */ +export type ProjectConfig = ProjectConfig_ +/** @deprecated import from `vitest/node` instead */ +export type UserWorkspaceConfig = UserWorkspaceConfig_ + +export type { + Benchmark, + BenchmarkResult, + BenchFunction, + BenchmarkAPI, + BenchTaskResult, + BenchOptions, + BenchFactory, + BenchTask, +} from '../runtime/types/benchmark' + +/** @deprecated use `SerializedSpec` instead */ +export type SerializableSpec = SerializedSpec +export type { SerializedSpec } + +/** @deprecated import from `vitest/node` instead */ +export type BenchmarkUserOptions = BenchmarkUserOptions_ + +export type { + TransformResultWithSource, + WebSocketHandlers, + WebSocketEvents, + WebSocketRPC, +} from '../api/types' diff --git a/packages/vitest/src/public/node.ts b/packages/vitest/src/public/node.ts new file mode 100644 index 000000000000..d0d1bcb5d613 --- /dev/null +++ b/packages/vitest/src/public/node.ts @@ -0,0 +1,116 @@ +export type { Vitest } from '../node/core' +export type { WorkspaceProject } from '../node/workspace' +export { createVitest } from '../node/create' +export { VitestPlugin } from '../node/plugins' +export { startVitest } from '../node/cli/cli-api' +export { parseCLI } from '../node/cli/cac' +export { registerConsoleShortcuts } from '../node/stdin' +export type { GlobalSetupContext } from '../node/globalSetup' +export type { WorkspaceSpec, ProcessPool } from '../node/pool' +export { createMethodsRPC } from '../node/pools/rpc' +export { getFilePoolName } from '../node/pool' +export { VitestPackageInstaller } from '../node/packageInstaller' +export { createDebugger } from '../utils/debugger' +export { resolveFsAllow } from '../node/plugins/utils' +export { resolveApiServerConfig, resolveConfig } from '../node/config/resolveConfig' + +export { GitNotFoundError, FilesNotFoundError as TestsNotFoundError } from '../node/errors' + +export { distDir, rootDir } from '../paths' + +export type { + TestSequencer, + TestSequencerConstructor, +} from '../node/sequencers/types' +export { BaseSequencer } from '../node/sequencers/BaseSequencer' + +export type { + BrowserProviderInitializationOptions, + BrowserProvider, + CDPSession, + BrowserProviderModule, + ResolvedBrowserOptions, + BrowserProviderOptions, + BrowserBuiltinProvider, + BrowserScript, + BrowserCommand, + BrowserCommandContext, + BrowserServer, + BrowserServerState, + BrowserServerStateContext, + BrowserOrchestrator, + BrowserConfigOptions, +} from '../node/types/browser' +export type { JsonOptions } from '../node/reporters/json' +export type { JUnitOptions } from '../node/reporters/junit' +export type { HTMLOptions } from '../node/reporters/html' + +export { isFileServingAllowed, createServer, parseAst, parseAstAsync } from 'vite' +export type * as Vite from 'vite' + +export { TestCase, TestFile, TestSuite } from '../node/reporters/reported-tasks' +export { TestProject } from '../node/reported-workspace-project' +export type { + TestCollection, + + TaskOptions, + TestDiagnostic, + FileDiagnostic, + TestResult, + TestResultPassed, + TestResultFailed, + TestResultSkipped, +} from '../node/reporters/reported-tasks' + +export type { + SequenceHooks, + SequenceSetupFiles, + BuiltinEnvironment, + VitestEnvironment, + Pool, + PoolOptions, + CSSModuleScopeStrategy, + ApiConfig, + JSDOMOptions, + HappyDOMOptions, + EnvironmentOptions, + VitestRunMode, + DepsOptimizationOptions, + TransformModePatterns, + InlineConfig, + TypecheckConfig, + UserConfig, + ResolvedConfig, + ProjectConfig, + ResolvedProjectConfig, + UserWorkspaceConfig, + RuntimeConfig, +} from '../node/types/config' + +export type { BenchmarkUserOptions } from '../node/types/benchmark' + +export type { + RawErrsMap as TypeCheckRawErrorsMap, + TscErrorInfo as TypeCheckErrorInfo, + CollectLineNumbers as TypeCheckCollectLineNumbers, + CollectLines as TypeCheckCollectLines, + RootAndTarget as TypeCheckRootAndTarget, + Context as TypeCheckContext, +} from '../typecheck/types' + +export type { OnServerRestartHandler } from '../types/general' + +export type { + CoverageProvider, + ReportContext, + CoverageProviderModule, + CoverageReporter, + CoverageOptions, + ResolvedCoverageOptions, + BaseCoverageOptions, + CoverageIstanbulOptions, + CoverageV8Options, + CustomProviderOptions, +} from '../node/types/coverage' + +export type { WorkerContext } from '../node/types/worker' diff --git a/packages/vitest/src/public/runners.ts b/packages/vitest/src/public/runners.ts new file mode 100644 index 000000000000..9dbec1038021 --- /dev/null +++ b/packages/vitest/src/public/runners.ts @@ -0,0 +1,2 @@ +export { VitestTestRunner } from '../runtime/runners/test' +export { NodeBenchmarkRunner } from '../runtime/runners/benchmark' diff --git a/packages/vitest/src/snapshot.ts b/packages/vitest/src/public/snapshot.ts similarity index 70% rename from packages/vitest/src/snapshot.ts rename to packages/vitest/src/public/snapshot.ts index 11c007acb32d..3b34eb45a8a8 100644 --- a/packages/vitest/src/snapshot.ts +++ b/packages/vitest/src/public/snapshot.ts @@ -1,2 +1,2 @@ export type { SnapshotEnvironment } from '@vitest/snapshot/environment' -export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './integrations/snapshot/environments/node' +export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from '../integrations/snapshot/environments/node' diff --git a/packages/vitest/src/suite.ts b/packages/vitest/src/public/suite.ts similarity index 73% rename from packages/vitest/src/suite.ts rename to packages/vitest/src/public/suite.ts index 141fa6e25e5c..d636dff75ad3 100644 --- a/packages/vitest/src/suite.ts +++ b/packages/vitest/src/public/suite.ts @@ -8,4 +8,4 @@ export { setHooks, } from '@vitest/runner' export { createChainable } from '@vitest/runner/utils' -export { getBenchFn, getBenchOptions } from './runtime/benchmark' +export { getBenchFn, getBenchOptions } from '../runtime/benchmark' diff --git a/packages/vitest/src/public/workers.ts b/packages/vitest/src/public/workers.ts new file mode 100644 index 000000000000..ddbd6fbc420d --- /dev/null +++ b/packages/vitest/src/public/workers.ts @@ -0,0 +1,10 @@ +export { + createForksRpcOptions, + createThreadsRpcOptions, + unwrapSerializableConfig, +} from '../runtime/workers/utils' +export { provideWorkerState } from '../runtime/utils' +export { run as runVitestWorker, collect as collectVitestWorkerTests } from '../runtime/worker' +export { runVmTests } from '../runtime/workers/vm' +export { runBaseTests } from '../runtime/workers/base' +export type { WorkerRpcOptions, VitestWorker } from '../runtime/workers/types' diff --git a/packages/vitest/src/runners.ts b/packages/vitest/src/runners.ts deleted file mode 100644 index ef5804e48c33..000000000000 --- a/packages/vitest/src/runners.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { VitestTestRunner } from './runtime/runners/test' -export { NodeBenchmarkRunner } from './runtime/runners/benchmark' diff --git a/packages/vitest/src/runtime/benchmark.ts b/packages/vitest/src/runtime/benchmark.ts index a2bb2ae00cbc..b9bc0f1c22ce 100644 --- a/packages/vitest/src/runtime/benchmark.ts +++ b/packages/vitest/src/runtime/benchmark.ts @@ -2,8 +2,8 @@ import type { Custom } from '@vitest/runner' import { getCurrentSuite } from '@vitest/runner' import { createChainable } from '@vitest/runner/utils' import { noop } from '@vitest/utils' -import type { BenchFunction, BenchOptions, BenchmarkAPI } from '../types' import { isRunningInBenchmark } from '../utils' +import type { BenchFunction, BenchOptions, BenchmarkAPI } from './types/benchmark' const benchFns = new WeakMap() const benchOptsMap = new WeakMap() diff --git a/packages/vitest/src/runtime/config.ts b/packages/vitest/src/runtime/config.ts new file mode 100644 index 000000000000..912b4bb271d8 --- /dev/null +++ b/packages/vitest/src/runtime/config.ts @@ -0,0 +1,160 @@ +import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' +import type { PrettyFormatOptions } from '@vitest/pretty-format' +import type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner' +import type { SnapshotUpdateState } from '@vitest/snapshot' +import type { SnapshotEnvironment } from '@vitest/snapshot/environment' + +/** + * Config that tests have access to. + */ +export interface SerializedConfig { + name: string | undefined + globals: boolean + base: string | undefined + snapshotEnvironment?: string + disableConsoleIntercept: boolean | undefined + runner: string | undefined + isolate: boolean + mode: 'test' | 'benchmark' + bail: number | undefined + environmentOptions?: Record + root: string + setupFiles: string[] + passWithNoTests: boolean + testNamePattern: RegExp | undefined + allowOnly: boolean + testTimeout: number + hookTimeout: number + clearMocks: boolean + mockReset: boolean + restoreMocks: boolean + unstubGlobals: boolean + unstubEnvs: boolean + // TODO: make optional + fakeTimers: FakeTimerInstallOpts + maxConcurrency: number + defines: Record + expect: { + requireAssertions?: boolean + poll?: { + timeout?: number + interval?: number + } + } + printConsoleTrace: boolean | undefined + sequence: { + shuffle?: boolean + concurrent?: boolean + seed: number + hooks: SequenceHooks + setupFiles: SequenceSetupFiles + } + poolOptions: { + forks: { + singleFork: boolean + isolate: boolean + } + threads: { + singleThread: boolean + isolate: boolean + } + vmThreads: { + singleThread: boolean + } + vmForks: { + singleFork: boolean + } + } + deps: { + web: { + transformAssets?: boolean + transformCss?: boolean + transformGlobPattern?: RegExp | RegExp[] + } + optimizer: { + web: { + enabled: boolean + } + ssr: { + enabled: boolean + } + } + interopDefault: boolean | undefined + moduleDirectories: string[] | undefined + } + snapshotOptions: { + updateSnapshot: SnapshotUpdateState + expand: boolean | undefined + snapshotFormat: PrettyFormatOptions | undefined + /** + * only exists for tests, not available in the main process + */ + snapshotEnvironment: SnapshotEnvironment + } + pool: string + snapshotSerializers: string[] + chaiConfig: { + includeStack?: boolean + showDiff?: boolean + truncateThreshold?: number + } | undefined + diff: string | undefined + retry: number + includeTaskLocation: boolean | undefined + inspect: boolean | string | undefined + inspectBrk: boolean | string | undefined + inspector: { + enabled?: boolean + port?: number + host?: string + waitForDebugger?: boolean + } + watch: boolean + env: Record + browser: { + name: string + headless: boolean + isolate: boolean + fileParallelism: boolean + ui: boolean + viewport: { + width: number + height: number + } + screenshotFailures: boolean + } + standalone: boolean + logHeapUsage: boolean | undefined + coverage: SerializedCoverageConfig +} + +export interface SerializedCoverageConfig { + provider: 'istanbul' | 'v8' | 'custom' | undefined + reportsDirectory: string + htmlReporter: { + subdir: string | undefined + } | undefined + enabled: boolean + customProviderModule: string | undefined +} + +export type RuntimeConfig = Pick< + SerializedConfig, + | 'allowOnly' + | 'testTimeout' + | 'hookTimeout' + | 'clearMocks' + | 'mockReset' + | 'restoreMocks' + | 'fakeTimers' + | 'maxConcurrency' + | 'expect' + | 'printConsoleTrace' +> & { + sequence?: { + concurrent?: boolean + hooks?: SequenceHooks + } +} + +export type RuntimeOptions = Partial diff --git a/packages/vitest/src/runtime/console.ts b/packages/vitest/src/runtime/console.ts index 376298ec5881..82be8c24fd71 100644 --- a/packages/vitest/src/runtime/console.ts +++ b/packages/vitest/src/runtime/console.ts @@ -5,7 +5,7 @@ import { getSafeTimers } from '@vitest/utils' import c from 'tinyrainbow' import { RealDate } from '../integrations/mock/date' import { getWorkerState } from '../utils' -import type { WorkerGlobalState } from '../types' +import type { WorkerGlobalState } from '../types/worker' export const UNKNOWN_TEST_ID = '__vitest__unknown_test__' diff --git a/packages/vitest/src/runtime/execute.ts b/packages/vitest/src/runtime/execute.ts index 1f2d73f2b4d2..441e659c42a3 100644 --- a/packages/vitest/src/runtime/execute.ts +++ b/packages/vitest/src/runtime/execute.ts @@ -14,7 +14,7 @@ import { normalize, relative } from 'pathe' import { processError } from '@vitest/utils/error' import { distDir } from '../paths' import type { MockMap } from '../types/mocker' -import type { WorkerGlobalState } from '../types' +import type { WorkerGlobalState } from '../types/worker' import { VitestMocker } from './mocker' import type { ExternalModulesExecutor } from './external-executor' diff --git a/packages/vitest/src/runtime/inspector.ts b/packages/vitest/src/runtime/inspector.ts index 0e18b60259aa..4beae34b10be 100644 --- a/packages/vitest/src/runtime/inspector.ts +++ b/packages/vitest/src/runtime/inspector.ts @@ -1,6 +1,7 @@ import { createRequire } from 'node:module' import { pathToFileURL } from 'node:url' -import type { ContextRPC, ResolvedConfig } from '../types' +import type { ContextRPC } from '../types/worker' +import type { SerializedConfig } from './config' const __require = createRequire(import.meta.url) let inspector: typeof import('node:inspector') @@ -54,7 +55,7 @@ export function setupInspect(ctx: ContextRPC) { } } -export function closeInspector(config: ResolvedConfig) { +export function closeInspector(config: SerializedConfig) { const keepOpen = shouldKeepOpen(config) if (inspector && !keepOpen) { @@ -63,7 +64,7 @@ export function closeInspector(config: ResolvedConfig) { } } -function shouldKeepOpen(config: ResolvedConfig) { +function shouldKeepOpen(config: SerializedConfig) { // In watch mode the inspector can persist re-runs if isolation is disabled and a single worker is used const isIsolatedSingleThread = config.pool === 'threads' diff --git a/packages/vitest/src/runtime/mocker.ts b/packages/vitest/src/runtime/mocker.ts index 75dd253f9f23..dd87c9b1ef96 100644 --- a/packages/vitest/src/runtime/mocker.ts +++ b/packages/vitest/src/runtime/mocker.ts @@ -188,7 +188,7 @@ export class VitestMocker { return { id, fsPath, - external, + external: external ? this.normalizePath(external) : external, } } @@ -315,14 +315,28 @@ export class VitestMocker { const files = readdirSync(mockFolder) const baseOriginal = basename(path) - for (const file of files) { - const baseFile = basename(file, extname(file)) - if (baseFile === baseOriginal) { - return resolve(mockFolder, file) + function findFile(files: string[], baseOriginal: string): string | null { + for (const file of files) { + const baseFile = basename(file, extname(file)) + if (baseFile === baseOriginal) { + const path = resolve(mockFolder, file) + // if the same name, return the file + if (fs.statSync(path).isFile()) { + return path + } + else { + // find folder/index.{js,ts} + const indexFile = findFile(readdirSync(path), 'index') + if (indexFile) { + return indexFile + } + } + } } + return null } - return null + return findFile(files, baseOriginal) } const dir = dirname(path) @@ -517,7 +531,7 @@ export class VitestMocker { const mocks = this.mockMap.get(suitefile) || {} const resolves = this.resolveCache.get(suitefile) || {} - mocks[id] = factory || this.resolveMockPath(path, external) + mocks[id] = factory || this.resolveMockPath(id, external) resolves[id] = originalId this.mockMap.set(suitefile, mocks) @@ -546,7 +560,7 @@ export class VitestMocker { let mock = this.getDependencyMock(normalizedId) if (mock === undefined) { - mock = this.resolveMockPath(fsPath, external) + mock = this.resolveMockPath(normalizedId, external) } if (mock === null) { diff --git a/packages/vitest/src/runtime/rpc.ts b/packages/vitest/src/runtime/rpc.ts index ae05442070a7..b1eb8f26d3e1 100644 --- a/packages/vitest/src/runtime/rpc.ts +++ b/packages/vitest/src/runtime/rpc.ts @@ -2,9 +2,9 @@ import { getSafeTimers } from '@vitest/utils' import type { CancelReason } from '@vitest/runner' import { createBirpc } from 'birpc' import type { BirpcOptions, BirpcReturn } from 'birpc' -import { getWorkerState } from '../utils/global' import type { RunnerRPC, RuntimeRPC } from '../types/rpc' -import type { WorkerRPC } from '../types' +import type { WorkerRPC } from '../types/worker' +import { getWorkerState } from './utils' const { get } = Reflect diff --git a/packages/vitest/src/runtime/runBaseTests.ts b/packages/vitest/src/runtime/runBaseTests.ts index 4bcc9c04c912..17e04c0f6a06 100644 --- a/packages/vitest/src/runtime/runBaseTests.ts +++ b/packages/vitest/src/runtime/runBaseTests.ts @@ -1,6 +1,5 @@ import { performance } from 'node:perf_hooks' import { collectTests, startTests } from '@vitest/runner' -import type { ResolvedConfig, ResolvedTestEnvironment } from '../types' import { getWorkerState, resetModules } from '../utils' import { vi } from '../integrations/vi' import { @@ -8,6 +7,8 @@ import { stopCoverageInsideWorker, } from '../integrations/coverage' import { setupChaiConfig } from '../integrations/chai/config' +import type { ResolvedTestEnvironment } from '../types/environment' +import type { SerializedConfig } from './config' import { setupGlobalEnv, withEnv } from './setup-node' import type { VitestExecutor } from './execute' import { resolveTestRunner } from './runners' @@ -17,7 +18,7 @@ import { closeInspector } from './inspector' export async function run( method: 'run' | 'collect', files: string[], - config: ResolvedConfig, + config: SerializedConfig, environment: ResolvedTestEnvironment, executor: VitestExecutor, ): Promise { @@ -37,8 +38,7 @@ export async function run( runner.onCancel?.(reason) }) - workerState.durations.prepare - = performance.now() - workerState.durations.prepare + workerState.durations.prepare = performance.now() - workerState.durations.prepare workerState.durations.environment = performance.now() await withEnv( diff --git a/packages/vitest/src/runtime/runVmTests.ts b/packages/vitest/src/runtime/runVmTests.ts index 621022a316cc..cee571fbf33d 100644 --- a/packages/vitest/src/runtime/runVmTests.ts +++ b/packages/vitest/src/runtime/runVmTests.ts @@ -10,19 +10,19 @@ import { startCoverageInsideWorker, stopCoverageInsideWorker, } from '../integrations/coverage' -import type { ResolvedConfig } from '../types' -import { getWorkerState } from '../utils/global' -import * as VitestIndex from '../index' +import * as VitestIndex from '../public/index' import { resolveSnapshotEnvironment } from '../integrations/snapshot/environments/resolveSnapshotEnvironment' +import { getWorkerState } from './utils' import type { VitestExecutor } from './execute' import { resolveTestRunner } from './runners' import { setupCommonEnv } from './setup-common' import { closeInspector } from './inspector' +import type { SerializedConfig } from './config' export async function run( method: 'run' | 'collect', files: string[], - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ): Promise { const workerState = getWorkerState() diff --git a/packages/vitest/src/runtime/runners/benchmark.ts b/packages/vitest/src/runtime/runners/benchmark.ts index 425ea56e8692..cc6edb95c824 100644 --- a/packages/vitest/src/runtime/runners/benchmark.ts +++ b/packages/vitest/src/runtime/runners/benchmark.ts @@ -12,8 +12,8 @@ import type { BenchTask, Benchmark, BenchmarkResult, -} from '../../types/benchmark' -import type { ResolvedConfig } from '../../types/config' +} from '../types/benchmark' +import type { SerializedConfig } from '../config' import type { VitestExecutor } from '../execute' function createBenchmarkResult(name: string): BenchmarkResult { @@ -150,7 +150,7 @@ async function runBenchmarkSuite(suite: Suite, runner: NodeBenchmarkRunner) { export class NodeBenchmarkRunner implements VitestRunner { private __vitest_executor!: VitestExecutor - constructor(public config: ResolvedConfig) {} + constructor(public config: SerializedConfig) {} async importTinybench() { return await import('tinybench') diff --git a/packages/vitest/src/runtime/runners/index.ts b/packages/vitest/src/runtime/runners/index.ts index cdddffa7eb74..803721a743d8 100644 --- a/packages/vitest/src/runtime/runners/index.ts +++ b/packages/vitest/src/runtime/runners/index.ts @@ -1,17 +1,17 @@ import type { VitestRunner, VitestRunnerConstructor } from '@vitest/runner' import { resolve } from 'pathe' -import type { ResolvedConfig } from '../../types/config' import type { VitestExecutor } from '../execute' import { distDir } from '../../paths' -import { getWorkerState } from '../../utils/global' +import { getWorkerState } from '../utils' import { rpc } from '../rpc' import { takeCoverageInsideWorker } from '../../integrations/coverage' import { loadDiffConfig, loadSnapshotSerializers } from '../setup-common' +import type { SerializedConfig } from '../config' const runnersFile = resolve(distDir, 'runners.js') async function getTestRunnerConstructor( - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ): Promise { if (!config.runner) { @@ -33,7 +33,7 @@ async function getTestRunnerConstructor( } export async function resolveTestRunner( - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ): Promise { const TestRunner = await getTestRunnerConstructor(config, executor) diff --git a/packages/vitest/src/runtime/runners/test.ts b/packages/vitest/src/runtime/runners/test.ts index c286ad1f4fbe..40d739dea011 100644 --- a/packages/vitest/src/runtime/runners/test.ts +++ b/packages/vitest/src/runtime/runners/test.ts @@ -16,7 +16,7 @@ import { getSnapshotClient } from '../../integrations/snapshot/chai' import { vi } from '../../integrations/vi' import { getNames, getTestName, getTests, getWorkerState } from '../../utils' import { createExpect } from '../../integrations/chai/index' -import type { ResolvedConfig } from '../../types/config' +import type { SerializedConfig } from '../config' import type { VitestExecutor } from '../execute' import { rpc } from '../rpc' @@ -30,7 +30,7 @@ export class VitestTestRunner implements VitestRunner { public pool = this.workerState.ctx.pool - constructor(public config: ResolvedConfig) {} + constructor(public config: SerializedConfig) {} importFile(filepath: string, source: VitestRunnerImportSource): unknown { if (source === 'setup') { @@ -191,7 +191,7 @@ export class VitestTestRunner implements VitestRunner { } } -function clearModuleMocks(config: ResolvedConfig) { +function clearModuleMocks(config: SerializedConfig) { const { clearMocks, mockReset, restoreMocks, unstubEnvs, unstubGlobals } = config diff --git a/packages/vitest/src/runtime/setup-common.ts b/packages/vitest/src/runtime/setup-common.ts index 32df032448ba..9cfddb9da2a9 100644 --- a/packages/vitest/src/runtime/setup-common.ts +++ b/packages/vitest/src/runtime/setup-common.ts @@ -1,13 +1,13 @@ import { setSafeTimers } from '@vitest/utils' import { addSerializer } from '@vitest/snapshot' import type { SnapshotSerializer } from '@vitest/snapshot' +import type { DiffOptions } from '@vitest/expect' import { resetRunOnceCounter } from '../integrations/run-once' -import type { ResolvedConfig } from '../types' -import type { DiffOptions } from '../types/matcher-utils' import type { VitestExecutor } from './execute' +import type { SerializedConfig } from './config' let globalSetup = false -export async function setupCommonEnv(config: ResolvedConfig) { +export async function setupCommonEnv(config: SerializedConfig) { resetRunOnceCounter() setupDefines(config.defines) setupEnv(config.env) @@ -44,7 +44,7 @@ function setupEnv(env: Record) { } export async function loadDiffConfig( - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ) { if (typeof config.diff !== 'string') { @@ -68,7 +68,7 @@ export async function loadDiffConfig( } export async function loadSnapshotSerializers( - config: ResolvedConfig, + config: SerializedConfig, executor: VitestExecutor, ) { const files = config.snapshotSerializers diff --git a/packages/vitest/src/runtime/setup-node.ts b/packages/vitest/src/runtime/setup-node.ts index 100a7d302072..b4bd65acaeee 100644 --- a/packages/vitest/src/runtime/setup-node.ts +++ b/packages/vitest/src/runtime/setup-node.ts @@ -3,22 +3,19 @@ import util from 'node:util' import timers from 'node:timers' import { installSourcemapsSupport } from 'vite-node/source-map' import { KNOWN_ASSET_TYPES } from 'vite-node/constants' -import type { - EnvironmentOptions, - ResolvedConfig, - ResolvedTestEnvironment, -} from '../types' import { getSafeTimers, getWorkerState } from '../utils' -import * as VitestIndex from '../index' +import * as VitestIndex from '../public/index' import { expect } from '../integrations/chai' import { resolveSnapshotEnvironment } from '../integrations/snapshot/environments/resolveSnapshotEnvironment' +import type { ResolvedTestEnvironment } from '../types/environment' import { setupCommonEnv } from './setup-common' import type { VitestExecutor } from './execute' +import type { SerializedConfig } from './config' // this should only be used in Node let globalSetup = false export async function setupGlobalEnv( - config: ResolvedConfig, + config: SerializedConfig, { environment }: ResolvedTestEnvironment, executor: VitestExecutor, ) { @@ -90,7 +87,7 @@ export async function setupConsoleLogSpy() { export async function withEnv( { environment }: ResolvedTestEnvironment, - options: EnvironmentOptions, + options: Record, fn: () => Promise, ) { // @ts-expect-error untyped global diff --git a/packages/vitest/src/runtime/types/benchmark.ts b/packages/vitest/src/runtime/types/benchmark.ts new file mode 100644 index 000000000000..fb83535b3f56 --- /dev/null +++ b/packages/vitest/src/runtime/types/benchmark.ts @@ -0,0 +1,33 @@ +import type { Custom } from '@vitest/runner' +import type { ChainableFunction } from '@vitest/runner/utils' +import type { + Bench as BenchFactory, + Options as BenchOptions, + Task as BenchTask, + TaskResult as BenchTaskResult, + TaskResult as TinybenchResult, +} from 'tinybench' + +export interface Benchmark extends Custom { + meta: { + benchmark: true + result?: BenchTaskResult + } +} + +export interface BenchmarkResult extends TinybenchResult { + name: string + rank: number +} + +export type BenchFunction = (this: BenchFactory) => Promise | void +type ChainableBenchmarkAPI = ChainableFunction< + 'skip' | 'only' | 'todo', + (name: string | Function, fn?: BenchFunction, options?: BenchOptions) => void +> +export type BenchmarkAPI = ChainableBenchmarkAPI & { + skipIf: (condition: any) => ChainableBenchmarkAPI + runIf: (condition: any) => ChainableBenchmarkAPI +} + +export { BenchTaskResult, BenchOptions, BenchFactory, BenchTask } diff --git a/packages/vitest/src/runtime/types/utils.ts b/packages/vitest/src/runtime/types/utils.ts new file mode 100644 index 000000000000..e65c04ce3382 --- /dev/null +++ b/packages/vitest/src/runtime/types/utils.ts @@ -0,0 +1,4 @@ +export type SerializedSpec = [ + project: { name: string | undefined; root: string }, + file: string, +] diff --git a/packages/vitest/src/utils/global.ts b/packages/vitest/src/runtime/utils.ts similarity index 94% rename from packages/vitest/src/utils/global.ts rename to packages/vitest/src/runtime/utils.ts index 5692a9cf6115..fd94dd4cbb05 100644 --- a/packages/vitest/src/utils/global.ts +++ b/packages/vitest/src/runtime/utils.ts @@ -1,4 +1,4 @@ -import type { WorkerGlobalState } from '../types' +import type { WorkerGlobalState } from '../types/worker' export function getWorkerState(): WorkerGlobalState { // @ts-expect-error untyped global diff --git a/packages/vitest/src/runtime/vm/vite-executor.ts b/packages/vitest/src/runtime/vm/vite-executor.ts index 9f2b40b370ac..7c6bb5e98802 100644 --- a/packages/vitest/src/runtime/vm/vite-executor.ts +++ b/packages/vitest/src/runtime/vm/vite-executor.ts @@ -4,7 +4,7 @@ import { normalize } from 'pathe' import { CSS_LANGS_RE, KNOWN_ASSET_RE } from 'vite-node/constants' import { toArray } from 'vite-node/utils' import type { RuntimeRPC } from '../../types/rpc' -import type { WorkerGlobalState } from '../../types' +import type { WorkerGlobalState } from '../../types/worker' import type { EsmExecutor } from './esm-executor' import { SyntheticModule } from './utils' diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index f55a5b8ad6c4..e8bc761acc11 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -1,9 +1,9 @@ import { pathToFileURL } from 'node:url' import { workerId as poolId } from 'tinypool' import { ModuleCacheMap } from 'vite-node/client' -import type { ContextRPC } from '../types/rpc' import { loadEnvironment } from '../integrations/env/loader' import { isChildProcess, setProcessTitle } from '../utils/base' +import type { ContextRPC } from '../types/worker' import { setupInspect } from './inspector' import { createRuntimeRpc, rpcDone } from './rpc' import type { VitestWorker } from './workers/types' diff --git a/packages/vitest/src/runtime/workers/base.ts b/packages/vitest/src/runtime/workers/base.ts index 740f170eff23..6d3c3a14a1d7 100644 --- a/packages/vitest/src/runtime/workers/base.ts +++ b/packages/vitest/src/runtime/workers/base.ts @@ -1,6 +1,6 @@ import { ModuleCacheMap } from 'vite-node/client' import type { WorkerGlobalState } from '../../types/worker' -import { provideWorkerState } from '../../utils/global' +import { provideWorkerState } from '../utils' import type { ContextExecutorOptions, VitestExecutor } from '../execute' import { getDefaultRequestStubs, startVitestExecutor } from '../execute' import type { MockMap } from '../../types/mocker' diff --git a/packages/vitest/src/runtime/workers/threads.ts b/packages/vitest/src/runtime/workers/threads.ts index 77fb7eb96dd5..34ac89691523 100644 --- a/packages/vitest/src/runtime/workers/threads.ts +++ b/packages/vitest/src/runtime/workers/threads.ts @@ -1,5 +1,5 @@ -import type { ContextRPC } from '../../types/rpc' -import type { WorkerContext, WorkerGlobalState } from '../../types/worker' +import type { WorkerContext } from '../../node/types/worker' +import type { ContextRPC, WorkerGlobalState } from '../../types/worker' import { runBaseTests } from './base' import type { VitestWorker } from './types' import { createThreadsRpcOptions } from './utils' diff --git a/packages/vitest/src/runtime/workers/types.ts b/packages/vitest/src/runtime/workers/types.ts index 0cbdc515d70d..989a3e4687c9 100644 --- a/packages/vitest/src/runtime/workers/types.ts +++ b/packages/vitest/src/runtime/workers/types.ts @@ -1,7 +1,7 @@ import type { BirpcOptions } from 'birpc' import type { Awaitable } from '@vitest/utils' -import type { ContextRPC, RuntimeRPC } from '../../types/rpc' -import type { WorkerGlobalState } from '../../types/worker' +import type { RuntimeRPC } from '../../types/rpc' +import type { ContextRPC, WorkerGlobalState } from '../../types/worker' export type WorkerRpcOptions = Pick< BirpcOptions, diff --git a/packages/vitest/src/runtime/workers/utils.ts b/packages/vitest/src/runtime/workers/utils.ts index 9712189d1810..82b518c2b746 100644 --- a/packages/vitest/src/runtime/workers/utils.ts +++ b/packages/vitest/src/runtime/workers/utils.ts @@ -1,7 +1,7 @@ import type { TinypoolWorkerMessage } from 'tinypool' import { parseRegexp } from '@vitest/utils' -import type { WorkerContext } from '../../types/worker' -import type { ResolvedConfig } from '../../types/config' +import type { ResolvedConfig, SerializedConfig } from '../../node/types/config' +import type { WorkerContext } from '../../node/types/worker' import type { WorkerRpcOptions } from './types' const REGEXP_WRAP_PREFIX = '$$vitest:' @@ -48,7 +48,7 @@ export function createForksRpcOptions( /** * Reverts the wrapping done by `utils/config-helpers.ts`'s `wrapSerializableConfig` */ -export function unwrapSerializableConfig(config: ResolvedConfig) { +export function unwrapSerializableConfig(config: SerializedConfig) { if (config.testNamePattern && typeof config.testNamePattern === 'string') { const testNamePattern = config.testNamePattern as string diff --git a/packages/vitest/src/runtime/workers/vmThreads.ts b/packages/vitest/src/runtime/workers/vmThreads.ts index 3197cd34ba1a..399717d6f57e 100644 --- a/packages/vitest/src/runtime/workers/vmThreads.ts +++ b/packages/vitest/src/runtime/workers/vmThreads.ts @@ -1,5 +1,5 @@ -import type { ContextRPC } from '../../types/rpc' -import type { WorkerContext, WorkerGlobalState } from '../../types/worker' +import type { WorkerContext } from '../../node/types/worker' +import type { ContextRPC, WorkerGlobalState } from '../../types/worker' import type { VitestWorker, WorkerRpcOptions } from './types' import { createThreadsRpcOptions } from './utils' import { runVmTests } from './vm' diff --git a/packages/vitest/src/typecheck/collect.ts b/packages/vitest/src/typecheck/collect.ts index eb4afacaae32..7c7aca0a48aa 100644 --- a/packages/vitest/src/typecheck/collect.ts +++ b/packages/vitest/src/typecheck/collect.ts @@ -9,7 +9,7 @@ import { interpretTaskModes, someTasksAreOnly, } from '@vitest/runner/utils' -import type { File, Suite, Test } from '../types' +import type { File, Suite, Test } from '@vitest/runner' import type { WorkspaceProject } from '../node/workspace' interface ParsedFile extends File { diff --git a/packages/vitest/src/typecheck/parse.ts b/packages/vitest/src/typecheck/parse.ts index 0cd6fdbcfe12..0a014746618c 100644 --- a/packages/vitest/src/typecheck/parse.ts +++ b/packages/vitest/src/typecheck/parse.ts @@ -3,7 +3,7 @@ import os from 'node:os' import { writeFile } from 'node:fs/promises' import { basename, dirname, join, resolve } from 'pathe' import { getTsconfig as getTsconfigContent } from 'get-tsconfig' -import type { TypecheckConfig } from '../types' +import type { TypecheckConfig } from '../node/types/config' import type { RawErrsMap, TscErrorInfo } from './types' const __dirname = url.fileURLToPath(new URL('.', import.meta.url)) diff --git a/packages/vitest/src/typecheck/typechecker.ts b/packages/vitest/src/typecheck/typechecker.ts index b4bc264d38be..b50507aaee2d 100644 --- a/packages/vitest/src/typecheck/typechecker.ts +++ b/packages/vitest/src/typecheck/typechecker.ts @@ -5,22 +5,17 @@ import { execa } from 'execa' import { basename, extname, resolve } from 'pathe' import { TraceMap, generatedPositionFor } from '@vitest/utils/source-map' import type { RawSourceMap } from '@ampproject/remapping' +import type { ParsedStack } from '@vitest/utils' +import type { File, Task, TaskResultPack, TaskState } from '@vitest/runner' import { getTasks } from '../utils' -import type { - Awaitable, - File, - ParsedStack, - Task, - TaskResultPack, - TaskState, - TscErrorInfo, - Vitest, -} from '../types' import type { WorkspaceProject } from '../node/workspace' +import type { Awaitable } from '../types/general' +import type { Vitest } from '../node/core' import { getRawErrsMapFromTsCompile, getTsconfig } from './parse' import { createIndexMap } from './utils' import type { FileInformation } from './collect' import { collectTests } from './collect' +import type { TscErrorInfo } from './types' export class TypeCheckError extends Error { name = 'TypeCheckError' diff --git a/packages/vitest/src/types/chai.ts b/packages/vitest/src/types/chai.ts deleted file mode 100644 index a922590e82b9..000000000000 --- a/packages/vitest/src/types/chai.ts +++ /dev/null @@ -1 +0,0 @@ -export { MatcherState } from '@vitest/expect' diff --git a/packages/vitest/src/types/environment.ts b/packages/vitest/src/types/environment.ts new file mode 100644 index 000000000000..fb047822d149 --- /dev/null +++ b/packages/vitest/src/types/environment.ts @@ -0,0 +1,36 @@ +import type { Awaitable } from './general' +import type { HappyDOMOptions } from './happy-dom-options' +import type { JSDOMOptions } from './jsdom-options' + +export interface EnvironmentReturn { + teardown: (global: any) => Awaitable +} + +export interface VmEnvironmentReturn { + getVmContext: () => { [key: string]: any } + teardown: () => Awaitable +} + +export interface Environment { + name: string + transformMode: 'web' | 'ssr' + setupVM?: (options: Record) => Awaitable + setup: ( + global: any, + options: Record + ) => Awaitable +} + +export interface EnvironmentOptions { + /** + * jsdom options. + */ + jsdom?: JSDOMOptions + happyDOM?: HappyDOMOptions + [x: string]: unknown +} + +export interface ResolvedTestEnvironment { + environment: Environment + options: Record | null +} diff --git a/packages/vitest/src/types/general.ts b/packages/vitest/src/types/general.ts index 79cab51e59b4..22f86a00fe04 100644 --- a/packages/vitest/src/types/general.ts +++ b/packages/vitest/src/types/general.ts @@ -13,29 +13,19 @@ export interface Constructable { new (...args: any[]): any } +export type TransformMode = 'web' | 'ssr' + +/** @deprecated not used */ export interface ModuleCache { promise?: Promise exports?: any code?: string } -export interface EnvironmentReturn { - teardown: (global: any) => Awaitable -} - -export interface VmEnvironmentReturn { - getVmContext: () => { [key: string]: any } - teardown: () => Awaitable -} - -export interface Environment { - name: string - transformMode: 'web' | 'ssr' - setupVM?: (options: Record) => Awaitable - setup: ( - global: any, - options: Record - ) => Awaitable +export interface AfterSuiteRunMeta { + coverage?: unknown + transformMode: TransformMode + projectName?: string } export interface UserConsoleLog { diff --git a/packages/vitest/src/types/global.ts b/packages/vitest/src/types/global.ts index 23158dada2b8..fda010d402d2 100644 --- a/packages/vitest/src/types/global.ts +++ b/packages/vitest/src/types/global.ts @@ -1,9 +1,9 @@ import type { Plugin as PrettyFormatPlugin } from '@vitest/pretty-format' import type { SnapshotState } from '@vitest/snapshot' import type { ExpectStatic, PromisifyAssertion, Tester } from '@vitest/expect' +import type { VitestEnvironment } from '../node/types/config' +import type { BenchmarkResult } from '../runtime/types/benchmark' import type { UserConsoleLog } from './general' -import type { VitestEnvironment } from './config' -import type { BenchmarkResult } from './benchmark' declare global { // eslint-disable-next-line ts/no-namespace diff --git a/packages/vitest/src/types/index.ts b/packages/vitest/src/types/index.ts deleted file mode 100644 index eb9fe39b22e6..000000000000 --- a/packages/vitest/src/types/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import './vite' -import './global' - -export { expectTypeOf, type ExpectTypeOf } from '../typecheck/expectTypeOf' -export { assertType, type AssertType } from '../typecheck/assertType' -export type * from '../typecheck/types' -export type * from './config' -export type * from './tasks' -export type * from './rpc' -export type * from './reporter' -export type * from './snapshot' -export type * from './worker' -export type * from './general' -export type * from './coverage' -export type * from './benchmark' -export type { CancelReason } from '@vitest/runner' -export type { DiffOptions } from '@vitest/utils/diff' -export type { - MockedFunction, - MockedObject, - MockInstance, - Mock, - MockContext, - Mocked, - MockedClass, -} from '../integrations/spy' -export type { BrowserUI } from './ui' - -export type { - ExpectStatic, - AsymmetricMatchersContaining, - JestAssertion, - Assertion, - ExpectPollOptions, -} from '@vitest/expect' diff --git a/packages/vitest/src/types/jsdom-options.ts b/packages/vitest/src/types/jsdom-options.ts index 039965a97e76..6248812aa463 100644 --- a/packages/vitest/src/types/jsdom-options.ts +++ b/packages/vitest/src/types/jsdom-options.ts @@ -4,7 +4,7 @@ export interface JSDOMOptions { * * @default '' */ - html?: string | Buffer | ArrayBufferLike + html?: string | ArrayBufferLike /** * referrer just affects the value read from document.referrer. * It defaults to no referrer (which reflects as the empty string). @@ -75,5 +75,5 @@ export interface JSDOMOptions { * @default false */ cookieJar?: boolean - resources?: 'usable' | any + resources?: 'usable' } diff --git a/packages/vitest/src/types/loader.ts b/packages/vitest/src/types/loader.ts deleted file mode 100644 index 325cc8f6fe04..000000000000 --- a/packages/vitest/src/types/loader.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { Awaitable } from './general' - -interface ModuleContext extends Record { - conditions: string[] - parentURL?: string -} - -export enum ModuleFormat { - Builtin = 'builtin', - Commonjs = 'commonjs', - Json = 'json', - Module = 'module', - Wasm = 'wasm', -} - -export interface ResolveResult { - url: string - shortCircuit?: boolean - format?: ModuleFormat -} - -export interface Resolver { - ( - url: string, - context: ModuleContext, - next: Resolver - ): Awaitable -} - -interface LoaderContext extends Record { - format: ModuleFormat - importAssertions: Record -} - -interface LoaderResult { - format: ModuleFormat - shortCircuit?: boolean - source: string | ArrayBuffer | SharedArrayBuffer | Uint8Array -} - -export interface Loader { - (url: string, context: LoaderContext, next: Loader): Awaitable -} diff --git a/packages/vitest/src/types/matcher-utils.ts b/packages/vitest/src/types/matcher-utils.ts deleted file mode 100644 index 2d52466af2f3..000000000000 --- a/packages/vitest/src/types/matcher-utils.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { Formatter } from 'tinyrainbow' - -export interface MatcherHintOptions { - comment?: string - expectedColor?: Formatter - isDirectExpectCall?: boolean - isNot?: boolean - promise?: string - receivedColor?: Formatter - secondArgument?: string - secondArgumentColor?: Formatter -} - -export interface DiffOptions { - aAnnotation?: string - aColor?: Formatter - aIndicator?: string - bAnnotation?: string - bColor?: Formatter - bIndicator?: string - changeColor?: Formatter - changeLineTrailingSpaceColor?: Formatter - commonColor?: Formatter - commonIndicator?: string - commonLineTrailingSpaceColor?: Formatter - contextLines?: number - emptyFirstOrLastLinePlaceholder?: string - expand?: boolean - includeChangeCounts?: boolean - omitAnnotationLines?: boolean - patchColor?: Formatter - // pretty-format type - compareKeys?: any - truncateThreshold?: number - truncateAnnotation?: string - truncateAnnotationColor?: Formatter -} diff --git a/packages/vitest/src/types/rpc.ts b/packages/vitest/src/types/rpc.ts index dc0e2a7e995f..7f5cc4bc8380 100644 --- a/packages/vitest/src/types/rpc.ts +++ b/packages/vitest/src/types/rpc.ts @@ -1,31 +1,21 @@ import type { FetchResult, RawSourceMap, ViteNodeResolveId } from 'vite-node' -import type { CancelReason } from '@vitest/runner' -import type { - EnvironmentOptions, - Pool, - ResolvedConfig, - VitestEnvironment, -} from './config' -import type { Environment, UserConsoleLog } from './general' -import type { SnapshotResult } from './snapshot' -import type { File, TaskResultPack } from './tasks' -import type { AfterSuiteRunMeta } from './worker' - -type TransformMode = 'web' | 'ssr' +import type { CancelReason, File, TaskResultPack } from '@vitest/runner' +import type { SnapshotResult } from '@vitest/snapshot' +import type { AfterSuiteRunMeta, TransformMode, UserConsoleLog } from './general' export interface RuntimeRPC { fetch: ( id: string, - environment: TransformMode + transformMode: TransformMode ) => Promise<{ externalize?: string id?: string }> - transform: (id: string, environment: TransformMode) => Promise + transform: (id: string, transformMode: TransformMode) => Promise resolveId: ( id: string, importer: string | undefined, - environment: TransformMode + transformMode: TransformMode ) => Promise getSourceMap: ( id: string, @@ -49,26 +39,3 @@ export interface RuntimeRPC { export interface RunnerRPC { onCancel: (reason: CancelReason) => void } - -export interface ContextTestEnvironment { - name: VitestEnvironment - transformMode?: TransformMode - options: EnvironmentOptions | null -} - -export interface ResolvedTestEnvironment { - environment: Environment - options: EnvironmentOptions | null -} - -export interface ContextRPC { - pool: Pool - worker: string - workerId: number - config: ResolvedConfig - projectName: string - files: string[] - environment: ContextTestEnvironment - providedContext: Record - invalidates?: string[] -} diff --git a/packages/vitest/src/types/snapshot.ts b/packages/vitest/src/types/snapshot.ts deleted file mode 100644 index 6d3e27ef5216..000000000000 --- a/packages/vitest/src/types/snapshot.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type { - SnapshotData, - SnapshotUpdateState, - SnapshotStateOptions, - SnapshotMatchOptions, - SnapshotResult, - UncheckedSnapshot, - SnapshotSummary, - SnapshotSerializer, -} from '@vitest/snapshot' diff --git a/packages/vitest/src/types/tasks.ts b/packages/vitest/src/types/tasks.ts deleted file mode 100644 index 50f54043fb7b..000000000000 --- a/packages/vitest/src/types/tasks.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type { - RunMode, - TaskState, - TaskBase, - TaskResult, - TaskResultPack, - Suite, - File, - Test, - Task, - DoneCallback, - TestFunction, - TestOptions, - TestAPI, - SuiteAPI, - HookListener, - HookCleanupCallback, - SuiteHooks, - SuiteCollector, - SuiteFactory, - RuntimeContext, - TestContext, - TaskContext, - ExtendedContext, - Custom, - TaskCustomOptions, - OnTestFailedHandler, - TaskMeta, -} from '@vitest/runner' diff --git a/packages/vitest/src/types/worker.ts b/packages/vitest/src/types/worker.ts index f23dbbc7a794..78561f48c935 100644 --- a/packages/vitest/src/types/worker.ts +++ b/packages/vitest/src/types/worker.ts @@ -1,32 +1,41 @@ -import type { MessagePort } from 'node:worker_threads' -import type { CancelReason, Task } from '@vitest/runner' import type { ModuleCacheMap, ViteNodeResolveId } from 'vite-node' import type { BirpcReturn } from 'birpc' +import type { CancelReason, Task } from '@vitest/runner' +import type { SerializedConfig } from '../runtime/config' +import type { RunnerRPC, RuntimeRPC } from './rpc' import type { MockMap } from './mocker' -import type { ResolvedConfig } from './config' -import type { ContextRPC, RunnerRPC, RuntimeRPC } from './rpc' -import type { Environment } from './general' - -export interface WorkerContext extends ContextRPC { - port: MessagePort -} +import type { TransformMode } from './general' +import type { Environment } from './environment' +/** @deprecated unused */ export type ResolveIdFunction = ( id: string, importer?: string ) => Promise -export interface AfterSuiteRunMeta { - coverage?: unknown - transformMode: Environment['transformMode'] - projectName?: string +export type WorkerRPC = BirpcReturn + +export interface ContextTestEnvironment { + name: string + transformMode?: TransformMode + options: Record | null } -export type WorkerRPC = BirpcReturn +export interface ContextRPC { + pool: string + worker: string + workerId: number + config: SerializedConfig + projectName: string + files: string[] + environment: ContextTestEnvironment + providedContext: Record + invalidates?: string[] +} export interface WorkerGlobalState { ctx: ContextRPC - config: ResolvedConfig + config: SerializedConfig rpc: WorkerRPC current?: Task filepath?: string diff --git a/packages/vitest/src/utils/config-helpers.ts b/packages/vitest/src/utils/config-helpers.ts index d47d210c4b1b..8ab9a5065822 100644 --- a/packages/vitest/src/utils/config-helpers.ts +++ b/packages/vitest/src/utils/config-helpers.ts @@ -1,4 +1,4 @@ -import type { ResolvedConfig } from '../types/config' +import type { SerializedConfig } from '../node/types/config' import type { BenchmarkBuiltinReporters, BuiltinReporters, @@ -26,9 +26,9 @@ export function getOutputFile( } /** - * Prepares `ResolvedConfig` for serialization, e.g. `node:v8.serialize` + * Prepares `SerializedConfig` for serialization, e.g. `node:v8.serialize` */ -export function wrapSerializableConfig(config: ResolvedConfig) { +export function wrapSerializableConfig(config: SerializedConfig) { let testNamePattern = config.testNamePattern let defines = config.defines @@ -47,5 +47,5 @@ export function wrapSerializableConfig(config: ResolvedConfig) { ...config, testNamePattern, defines, - } as ResolvedConfig + } as SerializedConfig } diff --git a/packages/vitest/src/utils/coverage.ts b/packages/vitest/src/utils/coverage.ts index b8ac873f2d77..c2556e467312 100644 --- a/packages/vitest/src/utils/coverage.ts +++ b/packages/vitest/src/utils/coverage.ts @@ -1,7 +1,7 @@ import { relative } from 'pathe' import mm from 'micromatch' import type { CoverageMap } from 'istanbul-lib-coverage' -import type { BaseCoverageOptions, ResolvedCoverageOptions } from '../types' +import type { BaseCoverageOptions, ResolvedCoverageOptions } from '../node/types/coverage' type Threshold = 'lines' | 'functions' | 'statements' | 'branches' diff --git a/packages/vitest/src/utils/graph.ts b/packages/vitest/src/utils/graph.ts index ee53d83b5baa..025b6bc47fc8 100644 --- a/packages/vitest/src/utils/graph.ts +++ b/packages/vitest/src/utils/graph.ts @@ -1,5 +1,6 @@ import type { ModuleNode } from 'vite' -import type { ModuleGraphData, Vitest } from '../types' +import type { Vitest } from '../node/core' +import type { ModuleGraphData } from '../types/general' export async function getModuleGraph( ctx: Vitest, diff --git a/packages/vitest/src/utils/index.ts b/packages/vitest/src/utils/index.ts index bb46c6bdce5c..2a4a96d29416 100644 --- a/packages/vitest/src/utils/index.ts +++ b/packages/vitest/src/utils/index.ts @@ -4,7 +4,7 @@ import { getWorkerState } from '../utils' export * from './graph' export * from './tasks' export * from './base' -export * from './global' +export * from '../runtime/utils' export * from './timers' export * from './env' export * from './modules' diff --git a/packages/vitest/src/utils/memory-limit.ts b/packages/vitest/src/utils/memory-limit.ts index 2c3fc6bb1095..cdd036aa1207 100644 --- a/packages/vitest/src/utils/memory-limit.ts +++ b/packages/vitest/src/utils/memory-limit.ts @@ -6,7 +6,7 @@ */ import * as nodeos from 'node:os' -import type { ResolvedConfig } from '../types' +import type { ResolvedConfig } from '../node/types/config' function getDefaultThreadsCount(config: ResolvedConfig) { const numCpus diff --git a/packages/vitest/src/utils/modules.ts b/packages/vitest/src/utils/modules.ts index bad2ce1ab005..fc8e39017325 100644 --- a/packages/vitest/src/utils/modules.ts +++ b/packages/vitest/src/utils/modules.ts @@ -1,6 +1,6 @@ import type { ModuleCacheMap } from 'vite-node/client' -import { getWorkerState } from './global' +import { getWorkerState } from '../runtime/utils' import { getSafeTimers } from './timers' export function resetModules(modules: ModuleCacheMap, resetMocks = false) { diff --git a/packages/vitest/src/utils/test-helpers.ts b/packages/vitest/src/utils/test-helpers.ts index 1b37c5155887..dcfaef619e93 100644 --- a/packages/vitest/src/utils/test-helpers.ts +++ b/packages/vitest/src/utils/test-helpers.ts @@ -1,12 +1,8 @@ import { promises as fs } from 'node:fs' import mm from 'micromatch' -import type { - ContextTestEnvironment, - EnvironmentOptions, - TransformModePatterns, - VitestEnvironment, -} from '../types' import type { WorkspaceProject } from '../node/workspace' +import type { EnvironmentOptions, TransformModePatterns, VitestEnvironment } from '../node/types/config' +import type { ContextTestEnvironment } from '../types/worker' import { groupBy } from './base' export const envsOrder = ['node', 'jsdom', 'happy-dom', 'edge-runtime'] diff --git a/packages/vitest/src/workers.ts b/packages/vitest/src/workers.ts deleted file mode 100644 index 5601196ce6f4..000000000000 --- a/packages/vitest/src/workers.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { - createForksRpcOptions, - createThreadsRpcOptions, - unwrapSerializableConfig, -} from './runtime/workers/utils' -export { provideWorkerState } from './utils/global' -export { run as runVitestWorker, collect as collectVitestWorkerTests } from './runtime/worker' -export { runVmTests } from './runtime/workers/vm' -export { runBaseTests } from './runtime/workers/base' -export type { WorkerRpcOptions, VitestWorker } from './runtime/workers/types' diff --git a/packages/web-worker/package.json b/packages/web-worker/package.json index 27660dd00f2e..d9553db8ec97 100644 --- a/packages/web-worker/package.json +++ b/packages/web-worker/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/web-worker", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "Web Worker support for testing in Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/web-worker/src/shared-worker.ts b/packages/web-worker/src/shared-worker.ts index d7954a1c9fbf..8da51396051f 100644 --- a/packages/web-worker/src/shared-worker.ts +++ b/packages/web-worker/src/shared-worker.ts @@ -2,20 +2,10 @@ import { MessageChannel, type MessagePort as NodeMessagePort, } from 'node:worker_threads' -import type { InlineWorkerContext, Procedure } from './types' +import type { Procedure } from './types' import { InlineWorkerRunner } from './runner' import { debug, getFileIdFromUrl, getRunnerOptions } from './utils' -interface SharedInlineWorkerContext - extends Omit< - InlineWorkerContext, - 'onmessage' | 'postMessage' | 'self' | 'global' - > { - onconnect: Procedure | null - self: SharedInlineWorkerContext - global: SharedInlineWorkerContext -} - function convertNodePortToWebPort(port: NodeMessagePort): MessagePort { if (!('addEventListener' in port)) { Object.defineProperty(port, 'addEventListener', { @@ -79,33 +69,55 @@ export function createSharedWorkerConstructor(): typeof SharedWorker { super() const name = typeof options === 'string' ? options : options?.name - - // should be equal to SharedWorkerGlobalScope - const context: SharedInlineWorkerContext = { - onconnect: null, - name, + let selfProxy: typeof globalThis + + const context = { + onmessage: null, + onmessageerror: null, + onerror: null, + onlanguagechange: null, + onoffline: null, + ononline: null, + onrejectionhandled: null, + onrtctransform: null, + onunhandledrejection: null, + origin: typeof location !== 'undefined' ? location.origin : 'http://localhost:3000', + importScripts: () => { + throw new Error( + '[vitest] `importScripts` is not supported in Vite workers. Please, consider using `import` instead.', + ) + }, + crossOriginIsolated: false, + onconnect: null as ((e: MessageEvent) => void) | null, + name: name || '', close: () => this.port.close(), dispatchEvent: (event: Event) => { return this._vw_workerTarget.dispatchEvent(event) }, - addEventListener: (...args) => { - return this._vw_workerTarget.addEventListener(...args) + addEventListener: (...args: any[]) => { + return this._vw_workerTarget.addEventListener(...args as [any, any]) }, removeEventListener: this._vw_workerTarget.removeEventListener, get self() { - return context - }, - get global() { - return context + return selfProxy }, } + selfProxy = new Proxy(context, { + get(target, prop, receiver) { + if (Reflect.has(target, prop)) { + return Reflect.get(target, prop, receiver) + } + return Reflect.get(globalThis, prop, receiver) + }, + }) as any + const channel = new MessageChannel() this.port = convertNodePortToWebPort(channel.port1) this._vw_workerPort = convertNodePortToWebPort(channel.port2) this._vw_workerTarget.addEventListener('connect', (e) => { - context.onconnect?.(e) + context.onconnect?.(e as MessageEvent) }) const runner = new InlineWorkerRunner(runnerOptions, context) diff --git a/packages/web-worker/src/types.ts b/packages/web-worker/src/types.ts index 0bd3bfa7ddc0..df16ab9a6322 100644 --- a/packages/web-worker/src/types.ts +++ b/packages/web-worker/src/types.ts @@ -4,19 +4,3 @@ export type CloneOption = 'native' | 'ponyfill' | 'none' export interface DefineWorkerOptions { clone: CloneOption } - -export interface InlineWorkerContext { - onmessage: Procedure | null - name?: string - close: () => void - dispatchEvent: (e: Event) => void - addEventListener: (e: string, fn: Procedure) => void - removeEventListener: (e: string, fn: Procedure) => void - postMessage: ( - data: any, - transfer?: Transferable[] | StructuredSerializeOptions - ) => void - self: InlineWorkerContext - global: InlineWorkerContext - importScripts?: any -} diff --git a/packages/web-worker/src/worker.ts b/packages/web-worker/src/worker.ts index 1013214355d8..0d13bfa57de1 100644 --- a/packages/web-worker/src/worker.ts +++ b/packages/web-worker/src/worker.ts @@ -1,7 +1,6 @@ import type { CloneOption, DefineWorkerOptions, - InlineWorkerContext, Procedure, } from './types' import { InlineWorkerRunner } from './runner' @@ -45,22 +44,39 @@ export function createWorkerConstructor( constructor(url: URL | string, options?: WorkerOptions) { super() - // should be equal to DedicatedWorkerGlobalScope - const context: InlineWorkerContext = { - onmessage: null, - name: options?.name, + let selfProxy: typeof globalThis + + // should be in sync with DedicatedWorkerGlobalScope, but without globalThis + const context = { + onmessage: null as null | ((e: MessageEvent) => void), + onmessageerror: null, + onerror: null, + onlanguagechange: null, + onoffline: null, + ononline: null, + onrejectionhandled: null, + onrtctransform: null, + onunhandledrejection: null, + origin: typeof location !== 'undefined' ? location.origin : 'http://localhost:3000', + importScripts: () => { + throw new Error( + '[vitest] `importScripts` is not supported in Vite workers. Please, consider using `import` instead.', + ) + }, + crossOriginIsolated: false, + name: options?.name || '', close: () => this.terminate(), dispatchEvent: (event: Event) => { return this._vw_workerTarget.dispatchEvent(event) }, - addEventListener: (...args) => { + addEventListener: (...args: any[]) => { if (args[1]) { this._vw_insideListeners.set(args[0], args[1]) } - return this._vw_workerTarget.addEventListener(...args) + return this._vw_workerTarget.addEventListener(...args as [any, any]) }, removeEventListener: this._vw_workerTarget.removeEventListener, - postMessage: (...args) => { + postMessage: (...args: any[]) => { if (!args.length) { throw new SyntaxError( '"postMessage" requires at least one argument.', @@ -76,15 +92,21 @@ export function createWorkerConstructor( this.dispatchEvent(event) }, get self() { - return context - }, - get global() { - return context + return selfProxy }, } + selfProxy = new Proxy(context, { + get(target, prop, receiver) { + if (Reflect.has(target, prop)) { + return Reflect.get(target, prop, receiver) + } + return globalThis[prop as 'crypto'] + }, + }) as any + this._vw_workerTarget.addEventListener('message', (e) => { - context.onmessage?.(e) + context.onmessage?.(e as MessageEvent) }) this.addEventListener('message', (e) => { diff --git a/packages/web-worker/tsconfig.json b/packages/web-worker/tsconfig.json index efb0628e6fcf..2099cdc01337 100644 --- a/packages/web-worker/tsconfig.json +++ b/packages/web-worker/tsconfig.json @@ -1,4 +1,7 @@ { "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["ESNext", "WebWorker"] + }, "exclude": ["./dist"] } diff --git a/packages/ws-client/package.json b/packages/ws-client/package.json index 607421253026..b4904f6e7d43 100644 --- a/packages/ws-client/package.json +++ b/packages/ws-client/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/ws-client", "type": "module", - "version": "2.0.4", + "version": "2.0.5", "description": "WebSocket client wrapper for communicating with Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/ws-client/src/index.ts b/packages/ws-client/src/index.ts index 8301c19b719c..ecd65739426e 100644 --- a/packages/ws-client/src/index.ts +++ b/packages/ws-client/src/index.ts @@ -4,7 +4,7 @@ import { parse, stringify } from 'flatted' // eslint-disable-next-line no-restricted-imports import type { WebSocketEvents, WebSocketHandlers } from 'vitest' -import { StateManager } from '../../vitest/src/node/state' +import { StateManager } from './state' export * from '../../vitest/src/utils/tasks' diff --git a/packages/ws-client/src/state.ts b/packages/ws-client/src/state.ts new file mode 100644 index 000000000000..e00b92333d45 --- /dev/null +++ b/packages/ws-client/src/state.ts @@ -0,0 +1,134 @@ +import type { File, Task, TaskResultPack } from '@vitest/runner' +// eslint-disable-next-line no-restricted-imports +import type { UserConsoleLog } from 'vitest' + +// can't import actual functions from utils, because it's incompatible with @vitest/browsers +import { createFileTask } from '@vitest/runner/utils' + +// Note this file is shared for both node and browser, be aware to avoid node specific logic +export class StateManager { + filesMap = new Map() + pathsSet: Set = new Set() + idMap = new Map() + + getPaths() { + return Array.from(this.pathsSet) + } + + /** + * Return files that were running or collected. + */ + getFiles(keys?: string[]): File[] { + if (keys) { + return keys + .map(key => this.filesMap.get(key)!) + .flat() + .filter(file => file && !file.local) + } + return Array.from(this.filesMap.values()).flat().filter(file => !file.local) + } + + getFilepaths(): string[] { + return Array.from(this.filesMap.keys()) + } + + getFailedFilepaths() { + return this.getFiles() + .filter(i => i.result?.state === 'fail') + .map(i => i.filepath) + } + + collectPaths(paths: string[] = []) { + paths.forEach((path) => { + this.pathsSet.add(path) + }) + } + + collectFiles(files: File[] = []) { + files.forEach((file) => { + const existing = this.filesMap.get(file.filepath) || [] + const otherProject = existing.filter( + i => i.projectName !== file.projectName, + ) + const currentFile = existing.find( + i => i.projectName === file.projectName, + ) + // keep logs for the previous file because it should always be initiated before the collections phase + // which means that all logs are collected during the collection and not inside tests + if (currentFile) { + file.logs = currentFile.logs + } + otherProject.push(file) + this.filesMap.set(file.filepath, otherProject) + this.updateId(file) + }) + } + + // this file is reused by ws-client, and should not rely on heavy dependencies like workspace + clearFiles( + _project: { config: { name: string | undefined; root: string } }, + paths: string[] = [], + ) { + const project = _project + paths.forEach((path) => { + const files = this.filesMap.get(path) + const fileTask = createFileTask( + path, + project.config.root, + project.config.name || '', + ) + fileTask.local = true + this.idMap.set(fileTask.id, fileTask) + if (!files) { + this.filesMap.set(path, [fileTask]) + return + } + const filtered = files.filter( + file => file.projectName !== project.config.name, + ) + // always keep a File task, so we can associate logs with it + if (!filtered.length) { + this.filesMap.set(path, [fileTask]) + } + else { + this.filesMap.set(path, [...filtered, fileTask]) + } + }) + } + + updateId(task: Task) { + if (this.idMap.get(task.id) === task) { + return + } + this.idMap.set(task.id, task) + if (task.type === 'suite') { + task.tasks.forEach((task) => { + this.updateId(task) + }) + } + } + + updateTasks(packs: TaskResultPack[]) { + for (const [id, result, meta] of packs) { + const task = this.idMap.get(id) + if (task) { + task.result = result + task.meta = meta + // skipped with new PendingError + if (result?.state === 'skip') { + task.mode = 'skip' + } + } + } + } + + updateUserLog(log: UserConsoleLog) { + const task = log.taskId && this.idMap.get(log.taskId) + if (task) { + if (!task.logs) { + task.logs = [] + } + task.logs.push(log) + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bbcde7fd05c..5eb8fc01f502 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,8 +5,9 @@ settings: excludeLinksFromLockfile: false overrides: + acorn: 8.11.3 mlly: ^1.7.1 - rollup: ^4.18.1 + rollup: ^4.19.0 vite: ^5.3.3 vitest: workspace:* @@ -35,26 +36,26 @@ importers: .: devDependencies: '@antfu/eslint-config': - specifier: ^2.22.2 - version: 2.22.2(@vue/compiler-sfc@3.4.31)(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.3)(vitest@packages+vitest) + specifier: ^2.23.2 + version: 2.23.2(@vue/compiler-sfc@3.4.33)(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.4)(vitest@packages+vitest) '@antfu/ni': specifier: ^0.22.0 version: 0.22.0 '@playwright/test': - specifier: ^1.45.1 - version: 1.45.1 + specifier: ^1.45.3 + version: 1.45.3 '@rollup/plugin-commonjs': specifier: ^26.0.1 - version: 26.0.1(rollup@4.18.1) + version: 26.0.1(rollup@4.19.0) '@rollup/plugin-json': specifier: ^6.1.0 - version: 6.1.0(rollup@4.18.1) + version: 6.1.0(rollup@4.19.0) '@rollup/plugin-node-resolve': specifier: ^15.2.3 - version: 15.2.3(rollup@4.18.1) + version: 15.2.3(rollup@4.19.0) '@types/node': - specifier: ^20.14.10 - version: 20.14.10 + specifier: ^20.14.11 + version: 20.14.11 '@types/ws': specifier: ^8.5.11 version: 8.5.11 @@ -92,26 +93,26 @@ importers: specifier: ^6.0.1 version: 6.0.1 rollup: - specifier: ^4.18.1 - version: 4.18.1 + specifier: ^4.19.0 + version: 4.19.0 rollup-plugin-dts: specifier: ^6.1.1 - version: 6.1.1(rollup@4.18.1)(typescript@5.5.3) + version: 6.1.1(rollup@4.19.0)(typescript@5.5.4) rollup-plugin-esbuild: specifier: ^6.1.1 - version: 6.1.1(esbuild@0.23.0)(rollup@4.18.1) + version: 6.1.1(esbuild@0.23.0)(rollup@4.19.0) rollup-plugin-license: specifier: ^3.5.2 - version: 3.5.2(rollup@4.18.1) + version: 3.5.2(rollup@4.19.0) tsx: specifier: ^4.16.2 version: 4.16.2 typescript: - specifier: ^5.5.3 - version: 5.5.3 + specifier: ^5.5.4 + version: 5.5.4 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:packages/vitest @@ -123,10 +124,10 @@ importers: dependencies: '@vueuse/core': specifier: ^10.11.0 - version: 10.11.0(vue@3.4.31(typescript@5.5.3)) + version: 10.11.0(vue@3.4.33(typescript@5.5.4)) vue: - specifier: ^3.4.31 - version: 3.4.31(typescript@5.5.3) + specifier: ^3.4.33 + version: 3.4.33(typescript@5.5.4) devDependencies: '@iconify-json/carbon': specifier: ^1.1.36 @@ -135,20 +136,20 @@ importers: specifier: ^1.1.43 version: 1.1.43 '@shikijs/vitepress-twoslash': - specifier: ^1.10.3 - version: 1.10.3(typescript@5.5.3) + specifier: ^1.11.0 + version: 1.11.0(typescript@5.5.4) '@unocss/reset': - specifier: ^0.61.3 - version: 0.61.3 + specifier: ^0.61.5 + version: 0.61.5 '@vite-pwa/assets-generator': specifier: ^0.2.4 version: 0.2.4 '@vite-pwa/vitepress': specifier: ^0.5.0 - version: 0.5.0(@vite-pwa/assets-generator@0.2.4)(vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0)) + version: 0.5.0(@vite-pwa/assets-generator@0.2.4)(vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0)) '@vitejs/plugin-vue': - specifier: latest - version: 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue@3.4.31(typescript@5.5.3)) + specifier: ^5.0.5 + version: 5.0.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue@3.4.33(typescript@5.5.4)) fast-glob: specifier: ^3.3.2 version: 3.3.2 @@ -156,20 +157,20 @@ importers: specifier: ^4.7.1 version: 4.7.1 unocss: - specifier: ^0.61.3 - version: 0.61.3(postcss@8.4.39)(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + specifier: ^0.61.5 + version: 0.61.5(postcss@8.4.39)(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) unplugin-vue-components: - specifier: ^0.27.2 - version: 0.27.2(@babel/parser@7.24.7)(rollup@4.18.1)(vue@3.4.31(typescript@5.5.3)) + specifier: ^0.27.3 + version: 0.27.3(@babel/parser@7.24.8)(rollup@4.19.0)(vue@3.4.33(typescript@5.5.4)) vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vite-plugin-pwa: specifier: ^0.20.0 - version: 0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0) + version: 0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0) vitepress: specifier: ^1.3.1 - version: 1.3.1(@algolia/client-search@4.20.0)(@types/node@20.14.10)(@types/react@18.2.79)(postcss@8.4.39)(react-dom@18.0.0(react@18.2.0))(react@18.2.0)(search-insights@2.9.0)(terser@5.22.0)(typescript@5.5.3) + version: 1.3.1(@algolia/client-search@4.20.0)(@types/node@20.14.11)(@types/react@18.2.79)(postcss@8.4.39)(react-dom@18.0.0(react@18.2.0))(react@18.2.0)(search-insights@2.9.0)(terser@5.22.0)(typescript@5.5.4) workbox-window: specifier: ^7.1.0 version: 7.1.0 @@ -178,10 +179,10 @@ importers: devDependencies: '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -190,7 +191,7 @@ importers: devDependencies: '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) fastify: specifier: ^4.26.2 version: 4.26.2 @@ -202,7 +203,7 @@ importers: version: 4.7.2 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -215,22 +216,22 @@ importers: devDependencies: '@vitest/browser': specifier: latest - version: 2.0.2(playwright@1.45.1)(typescript@5.5.3)(vitest@packages+vitest)(webdriverio@8.32.2(typescript@5.5.3)) + version: 2.0.4(playwright@1.45.3)(typescript@5.5.4)(vitest@packages+vitest)(webdriverio@8.32.2(typescript@5.5.4)) '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) jsdom: specifier: latest - version: 24.1.0 + version: 24.1.1 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest webdriverio: specifier: ^8.32.2 - version: 8.32.2(typescript@5.5.3) + version: 8.32.2(typescript@5.5.4) examples/preact: dependencies: @@ -249,7 +250,7 @@ importers: devDependencies: '@preact/preset-vite': specifier: ^2.8.2 - version: 2.8.2(@babel/core@7.24.5)(preact@10.21.0)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 2.8.2(@babel/core@7.24.5)(preact@10.21.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.4.2(@types/jest@29.0.0)(vitest@packages+vitest) @@ -258,13 +259,13 @@ importers: version: 3.2.3(preact@10.21.0) '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) typescript: specifier: ^5.4.5 version: 5.4.5 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -283,19 +284,19 @@ importers: version: 13.4.0(react-dom@18.0.0(react@18.2.0))(react@18.2.0) '@testing-library/user-event': specifier: ^14.5.2 - version: 14.5.2(@testing-library/dom@10.3.1) + version: 14.5.2(@testing-library/dom@10.4.0) '@types/react': specifier: ^18.2.79 version: 18.2.79 '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) jsdom: specifier: ^24.0.0 version: 24.0.0 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -314,13 +315,13 @@ importers: version: 5.16.5 jsdom: specifier: latest - version: 24.1.0 + version: 24.1.1 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vite-plugin-solid: specifier: ^2.7.2 - version: 2.7.2(solid-js@1.8.3)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 2.7.2(solid-js@1.8.3)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -329,16 +330,16 @@ importers: devDependencies: '@sveltejs/adapter-auto': specifier: ^2.1.0 - version: 2.1.0(@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))) + version: 2.1.0(@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))) '@sveltejs/kit': specifier: ^1.20.2 - version: 1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) svelte: specifier: ^3.59.1 version: 3.59.1 svelte-check: specifier: ^3.4.3 - version: 3.4.3(@babel/core@7.24.7)(postcss@8.4.39)(svelte@3.59.1) + version: 3.4.3(@babel/core@7.24.9)(postcss@8.4.39)(svelte@3.59.1) tslib: specifier: ^2.5.3 version: 2.5.3 @@ -347,7 +348,7 @@ importers: version: 5.2.2 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -359,7 +360,7 @@ importers: version: 20.11.5 '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) typescript: specifier: ^5.2.2 version: 5.2.2 @@ -380,16 +381,16 @@ importers: version: 13.4.0(react-dom@18.0.0(react@18.2.0))(react@18.2.0) '@testing-library/user-event': specifier: ^14.5.2 - version: 14.5.2(@testing-library/dom@10.3.1) + version: 14.5.2(@testing-library/dom@10.4.0) '@types/react': specifier: ^18.2.79 version: 18.2.79 '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 4.2.1(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@vitest/ui': specifier: latest - version: 2.0.2(vitest@packages+vitest) + version: 2.0.4(vitest@packages+vitest) fastify: specifier: ^4.26.2 version: 4.26.2 @@ -407,7 +408,7 @@ importers: version: 4.7.2 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -415,11 +416,11 @@ importers: packages/browser: dependencies: '@testing-library/dom': - specifier: ^10.3.1 - version: 10.3.1 + specifier: ^10.4.0 + version: 10.4.0 '@testing-library/user-event': specifier: ^14.5.2 - version: 14.5.2(@testing-library/dom@10.3.1) + version: 14.5.2(@testing-library/dom@10.4.0) '@vitest/utils': specifier: workspace:* version: link:../utils @@ -427,8 +428,8 @@ importers: specifier: ^0.30.10 version: 0.30.10 msw: - specifier: ^2.3.1 - version: 2.3.1(typescript@5.5.3) + specifier: ^2.3.2 + version: 2.3.2(typescript@5.5.4) sirv: specifier: ^2.0.4 version: 2.0.4 @@ -437,8 +438,8 @@ importers: version: 8.18.0 devDependencies: '@testing-library/jest-dom': - specifier: ^6.4.6 - version: 6.4.6(@types/jest@29.0.0)(vitest@packages+vitest) + specifier: ^6.4.7 + version: 6.4.7(@types/jest@29.0.0)(vitest@packages+vitest) '@types/ws': specifier: ^8.5.11 version: 8.5.11 @@ -467,11 +468,11 @@ importers: specifier: ^4.0.2 version: 4.0.2 playwright: - specifier: ^1.45.1 - version: 1.45.1 + specifier: ^1.45.3 + version: 1.45.3 playwright-core: - specifier: ^1.45.1 - version: 1.45.1 + specifier: ^1.45.3 + version: 1.45.3 safaridriver: specifier: ^0.1.2 version: 0.1.2 @@ -480,7 +481,7 @@ importers: version: link:../vitest webdriverio: specifier: ^8.39.1 - version: 8.39.1(typescript@5.5.3) + version: 8.39.1(typescript@5.5.4) packages/coverage-istanbul: dependencies: @@ -720,7 +721,7 @@ importers: version: 1.1.43 '@testing-library/vue': specifier: ^8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.4.31)(vue@3.4.31(typescript@5.5.3)) + version: 8.1.0(@vue/compiler-sfc@3.4.33)(vue@3.4.33(typescript@5.5.4)) '@types/codemirror': specifier: ^5.60.15 version: 5.60.15 @@ -734,11 +735,11 @@ importers: specifier: ^8.5.11 version: 8.5.11 '@unocss/reset': - specifier: ^0.61.3 - version: 0.61.3 + specifier: ^0.61.5 + version: 0.61.5 '@vitejs/plugin-vue': specifier: ^5.0.5 - version: 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue@3.4.31(typescript@5.5.3)) + version: 5.0.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue@3.4.33(typescript@5.5.4)) '@vitest/runner': specifier: workspace:* version: link:../runner @@ -750,7 +751,7 @@ importers: version: 2.4.6 '@vueuse/core': specifier: ^10.11.0 - version: 10.11.0(vue@3.4.31(typescript@5.5.3)) + version: 10.11.0(vue@3.4.33(typescript@5.5.4)) ansi-to-html: specifier: ^0.7.2 version: 0.7.2 @@ -758,8 +759,8 @@ importers: specifier: 0.2.17 version: 0.2.17 codemirror: - specifier: ^5.65.16 - version: 5.65.16 + specifier: ^5.65.17 + version: 5.65.17 codemirror-theme-vars: specifier: ^0.1.2 version: 0.1.2 @@ -768,34 +769,34 @@ importers: version: 3.0.10 floating-vue: specifier: ^5.2.2 - version: 5.2.2(vue@3.4.31(typescript@5.5.3)) + version: 5.2.2(vue@3.4.33(typescript@5.5.4)) splitpanes: specifier: ^3.1.5 version: 3.1.5 unocss: - specifier: ^0.61.3 - version: 0.61.3(postcss@8.4.39)(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + specifier: ^0.61.5 + version: 0.61.5(postcss@8.4.39)(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) unplugin-auto-import: specifier: ^0.18.0 - version: 0.18.0(@vueuse/core@10.11.0(vue@3.4.31(typescript@5.5.3)))(rollup@4.18.1) + version: 0.18.0(@vueuse/core@10.11.0(vue@3.4.33(typescript@5.5.4)))(rollup@4.19.0) unplugin-vue-components: - specifier: ^0.27.2 - version: 0.27.2(@babel/parser@7.24.7)(rollup@4.18.1)(vue@3.4.31(typescript@5.5.3)) + specifier: ^0.27.3 + version: 0.27.3(@babel/parser@7.24.8)(rollup@4.19.0)(vue@3.4.33(typescript@5.5.4)) vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vite-plugin-pages: specifier: ^0.32.3 - version: 0.32.3(@vue/compiler-sfc@3.4.31)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue-router@4.4.0(vue@3.4.31(typescript@5.5.3))) + version: 0.32.3(@vue/compiler-sfc@3.4.33)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue-router@4.4.0(vue@3.4.33(typescript@5.5.4))) vue: - specifier: ^3.4.31 - version: 3.4.31(typescript@5.5.3) + specifier: ^3.4.33 + version: 3.4.33(typescript@5.5.4) vue-router: specifier: ^4.4.0 - version: 4.4.0(vue@3.4.31(typescript@5.5.3)) + version: 4.4.0(vue@3.4.33(typescript@5.5.4)) vue-virtual-scroller: specifier: 2.0.0-beta.8 - version: 2.0.0-beta.8(vue@3.4.31(typescript@5.5.3)) + version: 2.0.0-beta.8(vue@3.4.33(typescript@5.5.4)) packages/utils: dependencies: @@ -841,7 +842,7 @@ importers: version: 1.2.0 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) devDependencies: '@jridgewell/trace-mapping': specifier: ^0.3.25 @@ -908,7 +909,7 @@ importers: version: 1.2.0 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vite-node: specifier: workspace:* version: link:../vite-node @@ -944,8 +945,8 @@ importers: specifier: ^4.0.9 version: 4.0.9 '@types/node': - specifier: ^20.14.10 - version: 20.14.10 + specifier: ^20.14.11 + version: 20.14.11 '@types/prompts': specifier: ^2.4.9 version: 2.4.9 @@ -980,14 +981,14 @@ importers: specifier: ^3.3.1 version: 3.3.1 get-tsconfig: - specifier: ^4.7.5 - version: 4.7.5 + specifier: ^4.7.6 + version: 4.7.6 happy-dom: specifier: ^14.12.3 version: 14.12.3 jsdom: - specifier: ^24.1.0 - version: 24.1.0 + specifier: ^24.1.1 + version: 24.1.1 local-pkg: specifier: ^0.5.0 version: 0.5.0 @@ -1058,7 +1059,7 @@ importers: devDependencies: '@vitejs/plugin-basic-ssl': specifier: ^1.0.2 - version: 1.0.2(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 1.0.2(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@vitest/browser': specifier: workspace:* version: link:../../packages/browser @@ -1082,7 +1083,7 @@ importers: version: link:../../packages/vitest webdriverio: specifier: ^8.32.2 - version: 8.32.2(typescript@5.5.3) + version: 8.32.2(typescript@5.5.4) test/cli: devDependencies: @@ -1094,7 +1095,7 @@ importers: version: 8.5.9 '@vitejs/plugin-basic-ssl': specifier: ^1.0.2 - version: 1.0.2(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + version: 1.0.2(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@vitest/runner': specifier: workspace:^ version: link:../../packages/runner @@ -1109,10 +1110,10 @@ importers: version: 8.0.1 unplugin-swc: specifier: ^1.4.4 - version: 1.4.4(@swc/core@1.4.1)(rollup@4.18.1) + version: 1.4.4(@swc/core@1.4.1)(rollup@4.19.0) vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -1127,7 +1128,7 @@ importers: version: 8.0.1 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -1163,7 +1164,7 @@ importers: version: link:../../packages/web-worker '@vueuse/integrations': specifier: ^10.9.0 - version: 10.9.0(axios@0.26.1(debug@4.3.4))(focus-trap@7.5.4)(vue@3.4.26(typescript@5.5.3)) + version: 10.9.0(axios@0.26.1(debug@4.3.4))(focus-trap@7.5.4)(vue@3.4.26(typescript@5.5.4)) axios: specifier: ^0.26.1 version: 0.26.1(debug@4.3.4) @@ -1173,6 +1174,9 @@ importers: immutable: specifier: 5.0.0-beta.5 version: 5.0.0-beta.5 + memfs: + specifier: ^4.8.2 + version: 4.8.2 strip-ansi: specifier: ^7.1.0 version: 7.1.0 @@ -1199,7 +1203,7 @@ importers: version: file:test/core/vitest-environment-custom vue: specifier: ^3.4.26 - version: 3.4.26(typescript@5.5.3) + version: 3.4.26(typescript@5.5.4) zustand: specifier: ^4.1.1 version: 4.1.1(react@18.2.0) @@ -1217,7 +1221,7 @@ importers: version: 3.0.3 '@vitejs/plugin-vue': specifier: latest - version: 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue@3.4.31(typescript@5.5.3)) + version: 5.0.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue@3.4.33(typescript@5.5.4)) '@vitest/browser': specifier: workspace:* version: link:../../packages/browser @@ -1247,19 +1251,19 @@ importers: version: 0.3.3 unplugin-swc: specifier: ^1.4.4 - version: 1.4.4(@swc/core@1.4.1)(rollup@4.18.1) + version: 1.4.4(@swc/core@1.4.1)(rollup@4.19.0) vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest vue: specifier: latest - version: 3.4.31(typescript@5.5.3) + version: 3.4.33(typescript@5.5.4) webdriverio: specifier: latest - version: 8.39.1(typescript@5.5.3) + version: 8.39.1(typescript@5.5.4) test/global-setup: devDependencies: @@ -1310,7 +1314,7 @@ importers: version: 7.0.1 vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vite-node: specifier: workspace:* version: link:../../packages/vite-node @@ -1371,13 +1375,13 @@ importers: version: link:../../packages/browser vite: specifier: ^5.3.3 - version: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + version: 5.3.3(@types/node@20.14.11)(terser@5.22.0) vitest: specifier: workspace:* version: link:../../packages/vitest webdriverio: specifier: latest - version: 8.39.1(typescript@5.5.3) + version: 8.39.1(typescript@5.5.4) test/workspaces: devDependencies: @@ -1392,7 +1396,7 @@ importers: version: 3.2.0 jsdom: specifier: latest - version: 24.1.0 + version: 24.1.1 vitest: specifier: workspace:* version: link:../../packages/vitest @@ -1491,8 +1495,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@antfu/eslint-config@2.22.2': - resolution: {integrity: sha512-LKC61Rm1VC0CduV4XAZzzEQ1nmTd+H4Y1rVvNg47MgcaCVGftUpY50MD2us3QCC+ktt3AAQYT9Kmbr/nsFW73g==} + '@antfu/eslint-config@2.23.2': + resolution: {integrity: sha512-O1HYH2EVTm/+NPk30pG5nExHPe7B7Uozv2K6Xq+5u4WMjL7DN/zRO+Dj/4Ea6VqyWDUXVEKoIjATGsngpHjsoA==} hasBin: true peerDependencies: '@eslint-react/eslint-plugin': ^1.5.8 @@ -1571,6 +1575,10 @@ packages: resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.24.9': + resolution: {integrity: sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==} + engines: {node: '>=6.9.0'} + '@babel/core@7.23.3': resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} engines: {node: '>=6.9.0'} @@ -1587,6 +1595,14 @@ packages: resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} engines: {node: '>=6.9.0'} + '@babel/core@7.24.9': + resolution: {integrity: sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.10': + resolution: {integrity: sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.24.5': resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==} engines: {node: '>=6.9.0'} @@ -1615,6 +1631,10 @@ packages: resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.24.8': + resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==} + engines: {node: '>=6.9.0'} + '@babel/helper-create-class-features-plugin@7.24.7': resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==} engines: {node: '>=6.9.0'} @@ -1677,6 +1697,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.24.9': + resolution: {integrity: sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-optimise-call-expression@7.24.7': resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} @@ -1725,6 +1751,10 @@ packages: resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.24.8': + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.22.20': resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} @@ -1741,6 +1771,10 @@ packages: resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.24.8': + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.22.20': resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} engines: {node: '>=6.9.0'} @@ -1753,6 +1787,10 @@ packages: resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.24.8': + resolution: {integrity: sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==} + engines: {node: '>=6.9.0'} + '@babel/highlight@7.24.7': resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} @@ -1772,6 +1810,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.24.8': + resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15': resolution: {integrity: sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==} engines: {node: '>=6.9.0'} @@ -2268,6 +2311,10 @@ packages: resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.24.8': + resolution: {integrity: sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.23.6': resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} @@ -2284,6 +2331,10 @@ packages: resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.24.9': + resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -2769,10 +2820,6 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-community/regexpp@4.11.0': resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -2955,8 +3002,8 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.45.1': - resolution: {integrity: sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==} + '@playwright/test@1.45.3': + resolution: {integrity: sha512-UKF4XsBfy+u3MFWEH44hva1Q8Da28G6RFtR2+5saw+jgAFQV5yYnB1fu68Mz7fO+5GJF3wgwAIs0UelU8TxFrA==} engines: {node: '>=18'} hasBin: true @@ -3016,7 +3063,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0 '@types/babel__core': ^7.1.9 - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: '@types/babel__core': optional: true @@ -3025,7 +3072,7 @@ packages: resolution: {integrity: sha512-UnsKoZK6/aGIH6AdkptXhNvhaqftcjq3zZdT+LY5Ftms6JR06nADcDsYp5hTU9E2lbJUEOhdlY5J4DNTneM+jQ==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true @@ -3034,7 +3081,7 @@ packages: resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true @@ -3043,7 +3090,7 @@ packages: resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true @@ -3051,13 +3098,13 @@ packages: '@rollup/plugin-replace@2.4.2': resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 '@rollup/plugin-terser@0.4.4': resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true @@ -3066,7 +3113,7 @@ packages: resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} @@ -3076,7 +3123,7 @@ packages: resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true @@ -3085,88 +3132,88 @@ packages: resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 peerDependenciesMeta: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.18.1': - resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} + '@rollup/rollup-android-arm-eabi@4.19.0': + resolution: {integrity: sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.18.1': - resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} + '@rollup/rollup-android-arm64@4.19.0': + resolution: {integrity: sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.18.1': - resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} + '@rollup/rollup-darwin-arm64@4.19.0': + resolution: {integrity: sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.18.1': - resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} + '@rollup/rollup-darwin-x64@4.19.0': + resolution: {integrity: sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.18.1': - resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} + '@rollup/rollup-linux-arm-gnueabihf@4.19.0': + resolution: {integrity: sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.18.1': - resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} + '@rollup/rollup-linux-arm-musleabihf@4.19.0': + resolution: {integrity: sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.18.1': - resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} + '@rollup/rollup-linux-arm64-gnu@4.19.0': + resolution: {integrity: sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.18.1': - resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} + '@rollup/rollup-linux-arm64-musl@4.19.0': + resolution: {integrity: sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': - resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.19.0': + resolution: {integrity: sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.18.1': - resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} + '@rollup/rollup-linux-riscv64-gnu@4.19.0': + resolution: {integrity: sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.18.1': - resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + '@rollup/rollup-linux-s390x-gnu@4.19.0': + resolution: {integrity: sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.18.1': - resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} + '@rollup/rollup-linux-x64-gnu@4.19.0': + resolution: {integrity: sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.18.1': - resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} + '@rollup/rollup-linux-x64-musl@4.19.0': + resolution: {integrity: sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.18.1': - resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} + '@rollup/rollup-win32-arm64-msvc@4.19.0': + resolution: {integrity: sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.18.1': - resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} + '@rollup/rollup-win32-ia32-msvc@4.19.0': + resolution: {integrity: sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.18.1': - resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} + '@rollup/rollup-win32-x64-msvc@4.19.0': + resolution: {integrity: sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag==} cpu: [x64] os: [win32] @@ -3176,14 +3223,17 @@ packages: '@shikijs/core@1.10.3': resolution: {integrity: sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==} + '@shikijs/core@1.11.0': + resolution: {integrity: sha512-VbEhDAhT/2ozO0TPr5/ZQBO/NWLqtk4ZiBf6NplYpF38mKjNfMMied5fNEfIfYfN+cdKvhDB4VMcKvG/g9c3zg==} + '@shikijs/transformers@1.10.3': resolution: {integrity: sha512-MNjsyye2WHVdxfZUSr5frS97sLGe6G1T+1P41QjyBFJehZphMcr4aBlRLmq6OSPBslYe9byQPVvt/LJCOfxw8Q==} - '@shikijs/twoslash@1.10.3': - resolution: {integrity: sha512-9HlQgvy51jnO46Tcr87A7v6gxlzdKzcpYk15/CQfO48svAslOf+6QYXf0Gao3HWPywOwVj2alMAe0zQhT59y9w==} + '@shikijs/twoslash@1.11.0': + resolution: {integrity: sha512-fyqUlij+Qm1MigL2JvXmeIJYSzvfrvO+SRULJco1y9XjIOe7SawvgUQf2BXhjZJPmrTKVqi4mbqECpj1KYtmKA==} - '@shikijs/vitepress-twoslash@1.10.3': - resolution: {integrity: sha512-rTfayHA8J4B0z9J9XspwQRg40m0xYLzBgNRhjBWGVGgfymh3OdM0CpEsqwGEFxGgRmDRYCEpf3jqdBejWMekgQ==} + '@shikijs/vitepress-twoslash@1.11.0': + resolution: {integrity: sha512-ntZKY0Io1P05eiZ75zwIl1IG/5DXqQjKchuSIhkX8cGjdKbGW4cp8EabTmVlW0cevJy5OJBDyGTHhW79GXLH2g==} '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3349,12 +3399,8 @@ packages: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} - '@testing-library/dom@10.2.0': - resolution: {integrity: sha512-CytIvb6tVOADRngTHGWNxH8LPgO/3hi/BdCEHOf7Qd2GvZVClhVP0Wo/QHzWhpki49Bk0b4VT6xpt3fx8HTSIw==} - engines: {node: '>=18'} - - '@testing-library/dom@10.3.1': - resolution: {integrity: sha512-q/WL+vlXMpC0uXDyfsMtc1rmotzLV8Y0gq6q1gfrrDjQeHoeLrqHbxdPvPNAh1i+xuJl7+BezywcXArz7vLqKQ==} + '@testing-library/dom@10.4.0': + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} '@testing-library/dom@8.19.0': @@ -3394,8 +3440,8 @@ packages: vitest: optional: true - '@testing-library/jest-dom@6.4.6': - resolution: {integrity: sha512-8qpnGVincVDLEcQXWaHOf6zmlbwTKc6Us6PPu4CRnPXCzo2OGBS5cwgMMOWdxDpEz1mkbvXHpEy99M5Yvt682w==} + '@testing-library/jest-dom@6.4.7': + resolution: {integrity: sha512-GaKJ0nijoNf30dWSOOzQEBkWBRk4rG3C/efw8zKrimNuZpnS/6/AEwo0WvZHgJxG84cNCgxt+mtbe1fsvfLp2A==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} peerDependencies: '@jest/globals': '>= 28' @@ -3588,6 +3634,9 @@ packages: '@types/node@20.14.10': resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==} + '@types/node@20.14.11': + resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + '@types/normalize-package-data@2.4.1': resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -3786,89 +3835,89 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@unocss/astro@0.61.3': - resolution: {integrity: sha512-VTgO+nm7PW7/VJt1kf1/4qTqMp4X4CdNG1XjYRGmCTONW+yHhFUEC1NAXt7t2wKEvCYSf5ObmjYowr2qM+GafQ==} + '@unocss/astro@0.61.5': + resolution: {integrity: sha512-keyh6/EsPMBEiLguaOsh47UcMkWCGT0rW3KV5aYRUfYXlgccSzDd4SLmTNsdlGXIso2XCl/14BJQuwjP0UEU0Q==} peerDependencies: vite: ^5.3.3 peerDependenciesMeta: vite: optional: true - '@unocss/cli@0.61.3': - resolution: {integrity: sha512-yj4whI4PwwK9cZXVrtl10AkZlyl9+569xYX+g89cBxqG2wpnbfBvug/hsvw3DyPG6i2MxKAv3Z78uruKnzCIjw==} + '@unocss/cli@0.61.5': + resolution: {integrity: sha512-Y5mKSoQGEYRmjUi5Tia3EesQbLgQTTPGmeE7LFrbeyP1c7PDiW3wSR5fRNZ7PBrr6/C5oo2sId3MhWJQl3tFSA==} engines: {node: '>=14'} hasBin: true - '@unocss/config@0.61.3': - resolution: {integrity: sha512-ZSSj5ST8XhiKoi2hLtVcyS8YJxn+Ug/WfasQ2wwOArcYfVFzZUoOQKbLo85hFuI7NV5Fh/aQREoVaJQI111jDA==} + '@unocss/config@0.61.5': + resolution: {integrity: sha512-VIIln/1aD9cqU95+3IVZG9U1yO7Ys6RqyqtgD5pIJ77rg57v/2sey+S2ScFx3KB24Bal3FxAgHA5CdjFpQZldA==} engines: {node: '>=14'} - '@unocss/core@0.61.3': - resolution: {integrity: sha512-9vixY1i5E0DQFtHJz/pHyFlFsiXJgL1bKHuocbl+GUi09lY/gE9TRm2qr2JOJx/BF720tMv9VxYI8Zq3EyPOXA==} + '@unocss/core@0.61.5': + resolution: {integrity: sha512-hB8zr2rnrCzz9x8ho2SAXQiYTEjwAPMiBzpaEe2C0+CFWeL1179h9508YVyZHHAzMyZILIG9YrVAWrrMdt2/Xg==} - '@unocss/extractor-arbitrary-variants@0.61.3': - resolution: {integrity: sha512-8yFAavi4PXTZTyJqsSQJuZNdaERMyLP4Gs4IzBDt8zjmUrXmYfgV+bKif2eE52QKvtb5/Jsij3fgfMsJouln7A==} + '@unocss/extractor-arbitrary-variants@0.61.5': + resolution: {integrity: sha512-UB1EweAaJrUxv+h3n5FqoizKHrnUgUzkdmOdJTfV6xvow90ITqbUoza+L6iVMNfcrcXTx8QpDnWh6rhLRyKY+g==} - '@unocss/inspector@0.61.3': - resolution: {integrity: sha512-F2WfVYdzM+CnocVSptBh945G85+RcxGd0KDm6q+Ctjs5NrHtT0TzX83USMLSjfFzTz/j+Q/kR1WOJWjKynVTXQ==} + '@unocss/inspector@0.61.5': + resolution: {integrity: sha512-DIT+hgTphHXZTJEe4ZWUoYoQUNszmVJr06+gGhBkKwpdetQa6B2N+zGLkAxgAvo/BUmk29tOORIBu7AyoloRUA==} - '@unocss/postcss@0.61.3': - resolution: {integrity: sha512-i76kuYbrvqkVhdfD37mnVqiBJiq9azGzbKZHFIjFWApOxFLak1OTHX5TIwxPspFm8u7U7kmU03JCnqyxWIE0wQ==} + '@unocss/postcss@0.61.5': + resolution: {integrity: sha512-FbN9G3v5X6TEzBRytnFvqOr1oeeUv1ZzprBIyXnQFg17D8rx7uRS9kAfUMoSiqAqnFxkJObv43fH+W3E41+JYQ==} engines: {node: '>=14'} peerDependencies: postcss: ^8.4.21 - '@unocss/preset-attributify@0.61.3': - resolution: {integrity: sha512-TSgje5WDfoicTOoh/Od6qlizkZd68vXTdtT7jYEvjCm2mV7EgDJpX+sj2eVv0rPuaARtIqs1b4yG7w3HA6BBnQ==} + '@unocss/preset-attributify@0.61.5': + resolution: {integrity: sha512-D2KDHPj8Qvp0hafA4JT5GXebO49gHsuKT6QvzwBpP9wzwAefAkd6PIY8cSKqSD6sjjVSfOpCfbZIzbwLEbXV5w==} - '@unocss/preset-icons@0.61.3': - resolution: {integrity: sha512-XNti2mgfbRCClzKxy7eMPukgk/mepyGGJNqtONnZmOkzkyhx6KQ2/luhMYnz5xONMG/aseoXMc4Zc1VzOqePRA==} + '@unocss/preset-icons@0.61.5': + resolution: {integrity: sha512-Fx1WZz6A7wtUDU+mt6KdjWOu9fEGG2XgzE8t8YFfUu22KjXyyef7Lto90uUNs9z+vYLevXqeDfthOZQFwNSfIg==} - '@unocss/preset-mini@0.61.3': - resolution: {integrity: sha512-QY9P7jcLePkmCGQSqX+ha4Rh2YhY9b9P8gtLFnjzqcdmSxvDFkT7Kf5Un/u/jwV+zCz/5t4F88vWLzBM6js6yQ==} + '@unocss/preset-mini@0.61.5': + resolution: {integrity: sha512-gVm7Z9X0krx8CK/+pKAqcVmpqzRk1+SH7bfgRxKtKhyFSxJlwpjNp1rKm3gCT0F1Tlp3d8aufYRksaXGZhs8Ow==} - '@unocss/preset-tagify@0.61.3': - resolution: {integrity: sha512-ir+gZJ20hZKapsrxWRTjFjyVJmmUcnkvhk1AiMgoG62MP6GzBQgbkAiy2TzJIEU0zQb8pYhtZ5KePtno+1vcaQ==} + '@unocss/preset-tagify@0.61.5': + resolution: {integrity: sha512-kxO20pV7Bwg7U3hPpxShFSn6CXH+EMaTFC+WXsh2wTOEs43Tta7L6kCSUPzrZ9pX/Pq4oInRQY9gqiZqlGETmQ==} - '@unocss/preset-typography@0.61.3': - resolution: {integrity: sha512-0b1JSk5/oi4DT86dO2sdscZlih4fVo//U6bh1cROAfLlYJsHlAEZau8IxLADcgBAYwCGtY94npfp6y60R37T/A==} + '@unocss/preset-typography@0.61.5': + resolution: {integrity: sha512-CQIleFkmfk/dAOlY7nPA1SOYHzXA6ia7+BCqGrTKxQVFOyBL7iHeNl0yV7lFtKFQn8zyFNEiBVW+fYi0QrouYw==} - '@unocss/preset-uno@0.61.3': - resolution: {integrity: sha512-ULP0hLBTNJuB0iQqaYaJZYbC4jwQYy0C6H7un3o4R+KsqIuyDanme2VsY51U5mN/pp7K6QJK6qE8EHVvtjCLHQ==} + '@unocss/preset-uno@0.61.5': + resolution: {integrity: sha512-CflB0l9CeZx+b/Q8mA4Ow4d63Caf+vFJ+1EGA06jG9qYjPLy76Rkci//0m9cEtO+vPnYtgLc7HZAZv0X6wh4Tg==} - '@unocss/preset-web-fonts@0.61.3': - resolution: {integrity: sha512-uBQKjIY+vUWCEqcgjEzdxok8svOmNNHDk1r+qh/Y5VLPWvPdA+Bb5iIwrxib3zzQvkT+au/utCeTGKGgIVhcXA==} + '@unocss/preset-web-fonts@0.61.5': + resolution: {integrity: sha512-hVIMPGayxg7xvlvfQnJxB0N3KTvmrglbH3v5BCYNjbh37+5hv+x22K6iWewY3BkGtaWqOtLO3H1n5a1rxPMyaw==} - '@unocss/preset-wind@0.61.3': - resolution: {integrity: sha512-THdTNAYEtvLz/jhHNgkpLFxC+LNn4W2VqDmpmK/fVMgSlhOYJ8IoQlt8nwgBRbNkEksvgItq8gL/t5+2sHGHhA==} + '@unocss/preset-wind@0.61.5': + resolution: {integrity: sha512-n4uepxv3gVoVQb0tv7iV8M4W0CgwLw0QaMX+3ECYzFLMynjCkZmFDtdQAX720yTvLZxwCxEZfQCgydOSt0qjZA==} - '@unocss/reset@0.61.3': - resolution: {integrity: sha512-WegQ6Plmr/H0D9wuKCVjhUMzi/xAn55A0mJgUnKl1pJHTZetRdK29u0bnpVQzynmlh/Lh4YtD+X4r8DVkASgPw==} + '@unocss/reset@0.61.5': + resolution: {integrity: sha512-5FKNsHnke9J1Z0T4prOZn9hkWh86c6Px+Oh3xf8mDd6dDw8CjzYMRxZEKti0gt13NcsO29G1vLGM7UjG1sCamg==} - '@unocss/rule-utils@0.61.3': - resolution: {integrity: sha512-XwzXE6YUAEc1+4TvJruZfntIM7eo+HdQDMlMI289w9YLLAXw973fp00E9U1dR16JRt1BWzlCnnY1RHAqSiXCVw==} + '@unocss/rule-utils@0.61.5': + resolution: {integrity: sha512-sCHnpCQoj3/ZmCjYo+oW3+4r5Z8kFI2snEL+miU2Uk0SqCgY1k0cUIYivj5L9ghp29p8VjEusX9M01QEZOYK7g==} engines: {node: '>=14'} - '@unocss/scope@0.61.3': - resolution: {integrity: sha512-yElJs2uUiBHyTHKLqWZRK5zvY+7XIqoFXc1Fkv+fxiGy1+4u+zLGoGA66bUWwbjDFLiFgEqwUBJ2+SzDC4Q0Ig==} + '@unocss/scope@0.61.5': + resolution: {integrity: sha512-GSmnSYWQ4oiSmJdyT5bmf0McXXhFJcVY7jgweAK2WltQgrxs1C3FWl9XIJtkWvaP3DIJjf4mKJf+zc6TjYxxEw==} - '@unocss/transformer-attributify-jsx-babel@0.61.3': - resolution: {integrity: sha512-Ubr2/XhB61C2EqrH0TnbJ9bGREvrORyotdRxpCCAzkBWh3i+J+kPrdGCFUgB+wHFcUPUuOKou+8o0rhWVY7mjw==} + '@unocss/transformer-attributify-jsx-babel@0.61.5': + resolution: {integrity: sha512-wBwjBCh6N95Bv3fJg8iokbDO9P5F+ee4n4gCecoePi6qSW22cBowj/UakP++L92GWX8FNZcphKOqMxx61q9gOg==} - '@unocss/transformer-attributify-jsx@0.61.3': - resolution: {integrity: sha512-KK4pi7xsxjRKk/RSFxkdl1JODsefD1YMaqgs6HM2KCdXctqUXd6RYQez7IfQwxnAeZupgatwoFe2CZd0Bbhq2g==} + '@unocss/transformer-attributify-jsx@0.61.5': + resolution: {integrity: sha512-w9vSBfgRdfofFnqzBvxrMi/FmP+ZtXz9W07wnoS6Yea7uhADilgx1h7wNfJECmK8kM8gWhjl5e6svZNAUQbI7A==} - '@unocss/transformer-compile-class@0.61.3': - resolution: {integrity: sha512-qHxJtRo+yjC0d+IIoNrOxnO8j5bdw7R4XDpR8+MKpGZgVQRmEGwl7Ej0PUGTudVknYGUdPmDTZGr693bzhwzQg==} + '@unocss/transformer-compile-class@0.61.5': + resolution: {integrity: sha512-5WLi5MgRt8DJiANoWUK49noCgdyU/IKneGs3RJYDRNONEh2HdsL6ktACSRe9Y185ICGaD9MOk3cHBZALj07gew==} - '@unocss/transformer-directives@0.61.3': - resolution: {integrity: sha512-FNJCOlXwi62tVXr4B8lDkHGxOIhNJw2qQpM5jeohLT7xpGPOmVvscWaWI0h6fjSREFwnnbRNif4YPLe/rB6PsA==} + '@unocss/transformer-directives@0.61.5': + resolution: {integrity: sha512-vQvgLicgFJt/rUTh3nd8yZz5l0AMoE9qmtZqpgb9iDMOTHUZrlWpI3hsVsU6AB9kvL/NoyMI16hVkP8x6y7b9g==} - '@unocss/transformer-variant-group@0.61.3': - resolution: {integrity: sha512-F7v05kfVDhIJ4lu3fjgkwV2GWoeJX4aszER8iqhwWz+0jVUaJRYAxzsVqE299uJ0ut07d+Di+JB7M4ZBRoH3qw==} + '@unocss/transformer-variant-group@0.61.5': + resolution: {integrity: sha512-7Is7PChplNYTkLTiQm5fL5zFKf+LV6d9TpzNuwXNK2oa1pQARMXNmnHjFPpzaDgxpTjn9sqQON72gziuXcpOsg==} - '@unocss/vite@0.61.3': - resolution: {integrity: sha512-Z2kq/hSv1RC3PYAaoXOGB0PEWXCVsgYtdnuFXR/8Tp0Yj2Wdeq906/s411/sqMUvXIaIhm2O9WaDfe0ISoV0sg==} + '@unocss/vite@0.61.5': + resolution: {integrity: sha512-+U5Ey5Z2csjLy7zcaDCtUqs08+ugRK87UWGm65W8yMAGW7me72f36QR8IHJUTqlVVEdhbJVIAy+yNFjGHYffjA==} peerDependencies: vite: ^5.3.3 @@ -3905,8 +3954,8 @@ packages: vite: ^5.3.3 vue: ^3.2.25 - '@vitest/browser@2.0.2': - resolution: {integrity: sha512-0U0LY7Yq5INXwS1+CDlKEntgtWGYu5pdVmuzD9alXEBDeNnjMD0fKL4dO7V7uIWnzMgzVjKxE205y4IoRBPn/A==} + '@vitest/browser@2.0.4': + resolution: {integrity: sha512-QsIkbqPqHsXvgxjCjjgKjuWKmrC0VJgpaDkuEmOy5gTnErhhifWIfp3HpH92K7cscfaIao+RlKv5f8nUMgjfmA==} peerDependencies: playwright: '*' safaridriver: '*' @@ -3920,8 +3969,8 @@ packages: webdriverio: optional: true - '@vitest/pretty-format@2.0.2': - resolution: {integrity: sha512-SBCyOXfGVvddRd9r2PwoVR0fonQjh9BMIcBMlSzbcNwFfGr6ZhOhvBzurjvi2F4ryut2HcqiFhNeDVGwru8tLg==} + '@vitest/pretty-format@2.0.4': + resolution: {integrity: sha512-RYZl31STbNGqf4l2eQM1nvKPXE0NhC6Eq0suTTePc4mtMQ1Fn8qZmjV4emZdEdG2NOWGKSCrHZjmTqDCDoeFBw==} '@vitest/test-dep1@file:test/core/deps/dep1': resolution: {directory: test/core/deps/dep1, type: directory} @@ -3932,13 +3981,13 @@ packages: '@vitest/test-deps-url@file:test/optimize-deps/dep-url': resolution: {directory: test/optimize-deps/dep-url, type: directory} - '@vitest/ui@2.0.2': - resolution: {integrity: sha512-VwxFTOC2GcNPexQlR9PFb8drWCLA+nLWTWlAS4oba1xbTJYJ8H5vY8OUFOTMb7YQXF0Vsc5IfmLpYkb2dcVgOA==} + '@vitest/ui@2.0.4': + resolution: {integrity: sha512-9SNE9ve3kgDkVTxJsY7BjqSwyqDVRJbq/AHVHZs+V0vmr/0cCX6yGT6nOahSXEsXFtKAsvRtBXKlTgr+5njzZQ==} peerDependencies: vitest: workspace:* - '@vitest/utils@2.0.2': - resolution: {integrity: sha512-pxCY1v7kmOCWYWjzc0zfjGTA3Wmn8PKnlPvSrsA643P1NHl1fOyXj2Q9SaNlrlFE+ivCsxM80Ov3AR82RmHCWQ==} + '@vitest/utils@2.0.4': + resolution: {integrity: sha512-Zc75QuuoJhOBnlo99ZVUkJIuq4Oj0zAkrQ2VzCqNCx6wAwViHEh5Fnp4fiJTE9rA+sAoXRf00Z9xGgfEzV6fzQ==} '@volar/language-core@1.10.4': resolution: {integrity: sha512-Na69qA6uwVIdA0rHuOc2W3pHtVQQO8hCNim7FOaKNpRJh0oAFnu5r9i7Oopo5C4cnELZkPNjTrbmpcCTiW+CMQ==} @@ -3961,23 +4010,29 @@ packages: '@vue/compiler-core@3.4.31': resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==} + '@vue/compiler-core@3.4.33': + resolution: {integrity: sha512-MoIREbkdPQlnGfSKDMgzTqzqx5nmEjIc0ydLVYlTACGBsfvOJ4tHSbZXKVF536n6fB+0eZaGEOqsGThPpdvF5A==} + '@vue/compiler-dom@3.4.26': resolution: {integrity: sha512-4CWbR5vR9fMg23YqFOhr6t6WB1Fjt62d6xdFPyj8pxrYub7d+OgZaObMsoxaF9yBUHPMiPFK303v61PwAuGvZA==} '@vue/compiler-dom@3.4.31': resolution: {integrity: sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==} + '@vue/compiler-dom@3.4.33': + resolution: {integrity: sha512-GzB8fxEHKw0gGet5BKlpfXEqoBnzSVWwMnT+dc25wE7pFEfrU/QsvjZMP9rD4iVXHBBoemTct8mN0GJEI6ZX5A==} + '@vue/compiler-sfc@3.4.26': resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==} - '@vue/compiler-sfc@3.4.31': - resolution: {integrity: sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==} + '@vue/compiler-sfc@3.4.33': + resolution: {integrity: sha512-7rk7Vbkn21xMwIUpHQR4hCVejwE6nvhBOiDgoBcR03qvGqRKA7dCBSsHZhwhYUsmjlbJ7OtD5UFIyhP6BY+c8A==} '@vue/compiler-ssr@3.4.26': resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==} - '@vue/compiler-ssr@3.4.31': - resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==} + '@vue/compiler-ssr@3.4.33': + resolution: {integrity: sha512-0WveC9Ai+eT/1b6LCV5IfsufBZ0HP7pSSTdDjcuW302tTEgoBw8rHVHKPbGUtzGReUFCRXbv6zQDDgucnV2WzQ==} '@vue/devtools-api@6.5.1': resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} @@ -4010,30 +4065,30 @@ packages: '@vue/reactivity@3.4.26': resolution: {integrity: sha512-E/ynEAu/pw0yotJeLdvZEsp5Olmxt+9/WqzvKff0gE67tw73gmbx6tRkiagE/eH0UCubzSlGRebCbidB1CpqZQ==} - '@vue/reactivity@3.4.31': - resolution: {integrity: sha512-VGkTani8SOoVkZNds1PfJ/T1SlAIOf8E58PGAhIOUDYPC4GAmFA2u/E14TDAFcf3vVDKunc4QqCe/SHr8xC65Q==} + '@vue/reactivity@3.4.33': + resolution: {integrity: sha512-B24QIelahDbyHipBgbUItQblbd4w5HpG3KccL+YkGyo3maXyS253FzcTR3pSz739OTphmzlxP7JxEMWBpewilA==} '@vue/runtime-core@3.4.26': resolution: {integrity: sha512-AFJDLpZvhT4ujUgZSIL9pdNcO23qVFh7zWCsNdGQBw8ecLNxOOnPcK9wTTIYCmBJnuPHpukOwo62a2PPivihqw==} - '@vue/runtime-core@3.4.31': - resolution: {integrity: sha512-LDkztxeUPazxG/p8c5JDDKPfkCDBkkiNLVNf7XZIUnJ+66GVGkP+TIh34+8LtPisZ+HMWl2zqhIw0xN5MwU1cw==} + '@vue/runtime-core@3.4.33': + resolution: {integrity: sha512-6wavthExzT4iAxpe8q37/rDmf44nyOJGISJPxCi9YsQO+8w9v0gLCFLfH5TzD1V1AYrTAdiF4Y1cgUmP68jP6w==} '@vue/runtime-dom@3.4.26': resolution: {integrity: sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw==} - '@vue/runtime-dom@3.4.31': - resolution: {integrity: sha512-2Auws3mB7+lHhTFCg8E9ZWopA6Q6L455EcU7bzcQ4x6Dn4cCPuqj6S2oBZgN2a8vJRS/LSYYxwFFq2Hlx3Fsaw==} + '@vue/runtime-dom@3.4.33': + resolution: {integrity: sha512-iHsMCUSFJ+4z432Bn9kZzHX+zOXa6+iw36DaVRmKYZpPt9jW9riF32SxNwB124i61kp9+AZtheQ/mKoJLerAaQ==} '@vue/server-renderer@3.4.26': resolution: {integrity: sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw==} peerDependencies: vue: 3.4.26 - '@vue/server-renderer@3.4.31': - resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} + '@vue/server-renderer@3.4.33': + resolution: {integrity: sha512-jTH0d6gQcaYideFP/k0WdEu8PpRS9MF8d0b6SfZzNi+ap972pZ0TNIeTaESwdOtdY0XPVj54XEJ6K0wXxir4fw==} peerDependencies: - vue: 3.4.31 + vue: 3.4.33 '@vue/shared@3.4.26': resolution: {integrity: sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ==} @@ -4041,6 +4096,9 @@ packages: '@vue/shared@3.4.31': resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==} + '@vue/shared@3.4.33': + resolution: {integrity: sha512-aoRY0jQk3A/cuvdkodTrM4NMfxco8n55eG4H7ML/CRy7OryHfiqvug4xrCBBMbbN+dvXAetDDwZW9DXWWjBntA==} + '@vue/test-utils@2.4.6': resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} @@ -4214,7 +4272,7 @@ packages: acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn: 8.11.3 acorn-walk@8.3.3: resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} @@ -4225,11 +4283,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.12.0: - resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} - engines: {node: '>=0.4.0'} - hasBin: true - agent-base@7.1.0: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} engines: {node: '>= 14'} @@ -4480,6 +4533,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.23.2: + resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -4553,6 +4611,9 @@ packages: caniuse-lite@1.0.30001600: resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==} + caniuse-lite@1.0.30001643: + resolution: {integrity: sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4680,8 +4741,8 @@ packages: codemirror-theme-vars@0.1.2: resolution: {integrity: sha512-WTau8X2q58b0SOAY9DO+iQVw8JKVEgyQIqArp2D732tcc+pobbMta3bnVMdQdmgwuvNrOFFr6HoxPRoQOgooFA==} - codemirror@5.65.16: - resolution: {integrity: sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==} + codemirror@5.65.17: + resolution: {integrity: sha512-1zOsUx3lzAOu/gnMAZkQ9kpIHcPYOc9y1Fbm2UVk5UBPkdq380nhkelG0qUwm1f7wPvTbndu9ZYlug35EwAZRQ==} color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -5158,6 +5219,9 @@ packages: electron-to-chromium@1.4.715: resolution: {integrity: sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==} + electron-to-chromium@1.4.832: + resolution: {integrity: sha512-cTen3SB0H2SGU7x467NRe1eVcQgcuS6jckKfWJHia2eo0cHIGOqHoAxevIYZD4eRHcWjkvFzo93bi3vJ9W+1lA==} + emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -5271,8 +5335,8 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-config-flat-gitignore@0.1.7: - resolution: {integrity: sha512-K4UcPriNg6IvNozipPVnLRxuhxys9vRkxYoLLdMPgPDngtWEP/xBT946oUYQHUWLoz4jvX5k+AF/MWh3VN5Lrg==} + eslint-config-flat-gitignore@0.1.8: + resolution: {integrity: sha512-OEUbS2wzzYtUfshjOqzFo4Bl4lHykXUdM08TCnYNl7ki+niW4Q1R0j0FDFDr0vjVsI5ZFOz5LvluxOP+Ew+dYw==} eslint-flat-config-utils@0.2.5: resolution: {integrity: sha512-iO+yLZtC/LKgACerkpvsZ6NoRVB2sxT04mOpnNcEM1aTwKy+6TsT46PUvrML4y2uVBS6I67hRCd2JiKAPaL/Uw==} @@ -5313,8 +5377,8 @@ packages: peerDependencies: eslint: ^8.56.0 || ^9.0.0-0 - eslint-plugin-jsdoc@48.7.0: - resolution: {integrity: sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==} + eslint-plugin-jsdoc@48.8.3: + resolution: {integrity: sha512-AtIvwwW9D17MRkM0Z0y3/xZYaa9mdAvJrkY6fU/HNUwGbmMtHVvK4qRM9CDixGVtfNrQitb8c6zQtdh6cTOvLg==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -5377,12 +5441,12 @@ packages: peerDependencies: eslint: '>=8.56.0' - eslint-plugin-unused-imports@4.0.0: - resolution: {integrity: sha512-mzM+y2B7XYpQryVa1usT+Y/BdNAtAZiXzwpSyDCboFoJN/LZRN67TNvQxKtuTK/Aplya3sLNQforiubzPPaIcQ==} + eslint-plugin-unused-imports@4.0.1: + resolution: {integrity: sha512-rax76s05z64uQgG9YXsWFmXrgjkaK79AvfeAWiSxhPP6RVGxeRaj4+2u+wxxu/mDy2pmJoOy1QTOEALMia2xGQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/eslint-plugin': '8' - eslint: '9' + '@typescript-eslint/eslint-plugin': ^8.0.0-0 + eslint: ^9.0.0 peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -5636,6 +5700,10 @@ packages: resolution: {integrity: sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==} engines: {node: '>=14'} + find-up-simple@1.0.0: + resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} + engines: {node: '>=18'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5648,10 +5716,6 @@ packages: resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -5818,8 +5882,8 @@ packages: get-tsconfig@4.7.3: resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==} - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + get-tsconfig@4.7.6: + resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} get-uri@6.0.1: resolution: {integrity: sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q==} @@ -6038,6 +6102,10 @@ packages: resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -6412,8 +6480,8 @@ packages: canvas: optional: true - jsdom@24.1.0: - resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==} + jsdom@24.1.1: + resolution: {integrity: sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==} engines: {node: '>=18'} peerDependencies: canvas: ^2.11.2 @@ -6564,10 +6632,6 @@ packages: resolution: {integrity: sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.clonedeep@4.5.0: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} @@ -6720,6 +6784,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + memfs@4.8.2: + resolution: {integrity: sha512-j4WKth315edViMBGkHW6NTF0QBjsTrcRDmYNcGsPq+ozMEyCCCIlX2d2mJ5wuh6iHvJ3FevUrr48v58YRqVdYg==} + engines: {node: '>= 4.0.0'} + merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} @@ -6965,6 +7033,16 @@ packages: typescript: optional: true + msw@2.3.2: + resolution: {integrity: sha512-vDn6d6a50vxPE+HnaKQfpmZ4SVXlOjF97yD5FJcUT3v2/uZ65qvTYNL25yOmnrfCNWZ4wtAS7EbtXxygMug2Tw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.7.x' + peerDependenciesMeta: + typescript: + optional: true + muggle-string@0.3.1: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} @@ -7064,8 +7142,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nwsapi@2.2.10: - resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==} + nwsapi@2.2.12: + resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==} nwsapi@2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} @@ -7315,8 +7393,8 @@ packages: engines: {node: '>=16'} hasBin: true - playwright-core@1.45.1: - resolution: {integrity: sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==} + playwright-core@1.45.3: + resolution: {integrity: sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA==} engines: {node: '>=18'} hasBin: true @@ -7325,8 +7403,8 @@ packages: engines: {node: '>=16'} hasBin: true - playwright@1.45.1: - resolution: {integrity: sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==} + playwright@1.45.3: + resolution: {integrity: sha512-QhVaS+lpluxCaioejDZ95l4Y4jSFCsBvl2UZkpeXlzxmqS+aABr5c82YmfMHrL6x27nvrvykJAFpkzT2eWdJww==} engines: {node: '>=18'} hasBin: true @@ -7659,7 +7737,7 @@ packages: resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} engines: {node: '>=16'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 typescript: ^4.5 || ^5.0 rollup-plugin-esbuild@6.1.1: @@ -7667,16 +7745,16 @@ packages: engines: {node: '>=14.18.0'} peerDependencies: esbuild: '>=0.18.0' - rollup: ^4.18.1 + rollup: ^4.19.0 rollup-plugin-license@3.5.2: resolution: {integrity: sha512-NNeXBcE6RyQdZdSC8Vxe8Cheax2aUa/K0Ok6JDZwr9isjkSDer4aMg0sovas1Ua76ojLZX1BrNQ6ZFspztKkZQ==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^4.18.1 + rollup: ^4.19.0 - rollup@4.18.1: - resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} + rollup@4.19.0: + resolution: {integrity: sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7775,6 +7853,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -7829,6 +7912,9 @@ packages: shiki@1.10.3: resolution: {integrity: sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==} + shiki@1.11.0: + resolution: {integrity: sha512-NqH/O1zRHvnuk/WfSL6b7+DtI7/kkMMSQGlZhm9DyzSU+SoIHhaw/fBZMr+zp9R8KjdIzkk3JKSC6hORuGDyng==} + side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} @@ -8179,8 +8265,8 @@ packages: resolution: {integrity: sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==} engines: {node: '>=12.20'} - synckit@0.9.0: - resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==} + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} tabbable@6.2.0: @@ -8430,8 +8516,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.5.3: - resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} hasBin: true @@ -8478,10 +8564,6 @@ packages: resolution: {integrity: sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==} engines: {node: '>=4'} - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - unimport@3.7.2: resolution: {integrity: sha512-91mxcZTadgXyj3lFWmrGT8GyoRHWuE5fqPOjg5RVtF6vj+OfM5G6WCzXjuYtSgELE5ggB34RY4oiCSEP8I3AHw==} @@ -8519,11 +8601,11 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - unocss@0.61.3: - resolution: {integrity: sha512-Mpci+yP9CUnDjSwm0EAq9U76cgiNB5UM0ztXfDjjMiSe+jOS6sZ2A+kZ5JY9ZBRx5TX0Wh4kQBoPQQ1ooxHicg==} + unocss@0.61.5: + resolution: {integrity: sha512-BScwlqXW9KHQLKIKtXmwWmMb4Ihoryb7uIgmS+HSqmCN58eqNA73vAo3cZ97xtO+RFdauqgGKP5wD6ShQUvqnQ==} engines: {node: '>=14'} peerDependencies: - '@unocss/webpack': 0.61.3 + '@unocss/webpack': 0.61.5 vite: ^5.3.3 peerDependenciesMeta: '@unocss/webpack': @@ -8552,8 +8634,8 @@ packages: peerDependencies: '@swc/core': ^1.2.108 - unplugin-vue-components@0.27.2: - resolution: {integrity: sha512-YifnsmslMRNt+JRQiCG4ZX1+xUQuubUZm76K7Qtg8dmchZJkHIDxZSyfZb5/jqrLWMTm/TUjGJ3ZDlzO6SFnSQ==} + unplugin-vue-components@0.27.3: + resolution: {integrity: sha512-5wg7lbdg5ZcrAQNzyYK+6gcg/DG8K6rO+f5YeuvqGHs/PhpapBvpA4O/0ex/pFthE5WgRk43iWuRZEMLVsdz4Q==} engines: {node: '>=14'} peerDependencies: '@babel/parser': ^7.15.8 @@ -8565,10 +8647,6 @@ packages: '@nuxt/kit': optional: true - unplugin@1.10.1: - resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==} - engines: {node: '>=14.0.0'} - unplugin@1.11.0: resolution: {integrity: sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==} engines: {node: '>=14.0.0'} @@ -8589,6 +8667,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -8816,8 +8900,8 @@ packages: typescript: optional: true - vue@3.4.31: - resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==} + vue@3.4.33: + resolution: {integrity: sha512-VdMCWQOummbhctl4QFMcW6eNtXHsFyDlX60O/tsSQuCcuDOnJ1qPOhhVla65Niece7xq/P2zyZReIO5mP+LGTQ==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -9239,35 +9323,35 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@antfu/eslint-config@2.22.2(@vue/compiler-sfc@3.4.31)(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.3)(vitest@packages+vitest)': + '@antfu/eslint-config@2.23.2(@vue/compiler-sfc@3.4.33)(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.4)(vitest@packages+vitest)': dependencies: '@antfu/install-pkg': 0.3.3 '@clack/prompts': 0.7.0 - '@stylistic/eslint-plugin': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3) - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) - '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) + '@stylistic/eslint-plugin': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4) + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4) + '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4) eslint: 9.7.0 - eslint-config-flat-gitignore: 0.1.7 + eslint-config-flat-gitignore: 0.1.8 eslint-flat-config-utils: 0.2.5 eslint-merge-processors: 0.1.0(eslint@9.7.0) eslint-plugin-antfu: 2.3.4(eslint@9.7.0) eslint-plugin-command: 0.2.3(eslint@9.7.0) eslint-plugin-eslint-comments: 3.2.0(eslint@9.7.0) - eslint-plugin-import-x: 3.0.1(eslint@9.7.0)(typescript@5.5.3) - eslint-plugin-jsdoc: 48.7.0(eslint@9.7.0) + eslint-plugin-import-x: 3.0.1(eslint@9.7.0)(typescript@5.5.4) + eslint-plugin-jsdoc: 48.8.3(eslint@9.7.0) eslint-plugin-jsonc: 2.16.0(eslint@9.7.0) eslint-plugin-markdown: 5.1.0(eslint@9.7.0) eslint-plugin-n: 17.9.0(eslint@9.7.0) eslint-plugin-no-only-tests: 3.1.0 - eslint-plugin-perfectionist: 2.11.0(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.3)(vue-eslint-parser@9.4.3(eslint@9.7.0)) + eslint-plugin-perfectionist: 2.11.0(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.4)(vue-eslint-parser@9.4.3(eslint@9.7.0)) eslint-plugin-regexp: 2.6.0(eslint@9.7.0) eslint-plugin-toml: 0.11.1(eslint@9.7.0) eslint-plugin-unicorn: 54.0.0(eslint@9.7.0) - eslint-plugin-unused-imports: 4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0) - eslint-plugin-vitest: 0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)(vitest@packages+vitest) + eslint-plugin-unused-imports: 4.0.1(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0) + eslint-plugin-vitest: 0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4)(vitest@packages+vitest) eslint-plugin-vue: 9.27.0(eslint@9.7.0) eslint-plugin-yml: 1.14.0(eslint@9.7.0) - eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.4.31)(eslint@9.7.0) + eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.4.33)(eslint@9.7.0) globals: 15.8.0 jsonc-eslint-parser: 2.4.0 local-pkg: 0.5.0 @@ -9320,6 +9404,8 @@ snapshots: '@babel/compat-data@7.24.7': {} + '@babel/compat-data@7.24.9': {} + '@babel/core@7.23.3': dependencies: '@ampproject/remapping': 2.3.0 @@ -9400,6 +9486,33 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.24.9': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.10 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.9) + '@babel/helpers': 7.24.8 + '@babel/parser': 7.24.8 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.9 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.24.10': + dependencies: + '@babel/types': 7.24.9 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + '@babel/generator@7.24.5': dependencies: '@babel/types': 7.24.7 @@ -9424,7 +9537,7 @@ snapshots: '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.24.9 '@babel/helper-compilation-targets@7.23.6': dependencies: @@ -9442,6 +9555,14 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.24.8': + dependencies: + '@babel/compat-data': 7.24.9 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.2 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.23.3)': dependencies: '@babel/core': 7.23.3 @@ -9457,32 +9578,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7)': + '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 '@babel/helper-member-expression-to-functions': 7.24.7 '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.9) '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.7)': + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.7)': + '@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/core': 7.24.9 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-plugin-utils': 7.24.7 debug: 4.3.5 lodash.debounce: 4.0.8 @@ -9490,10 +9611,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.7)': + '@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/core': 7.24.9 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-plugin-utils': 7.24.7 debug: 4.3.5 lodash.debounce: 4.0.8 @@ -9580,6 +9701,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.9)': + dependencies: + '@babel/core': 7.24.9 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.24.9(@babel/core@7.24.9)': + dependencies: + '@babel/core': 7.24.9 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.24.7': dependencies: '@babel/types': 7.24.7 @@ -9588,9 +9731,9 @@ snapshots: '@babel/helper-plugin-utils@7.24.7': {} - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.7)': + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-wrap-function': 7.22.20 @@ -9604,9 +9747,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7)': + '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-member-expression-to-functions': 7.24.7 '@babel/helper-optimise-call-expression': 7.24.7 @@ -9637,6 +9780,8 @@ snapshots: '@babel/helper-string-parser@7.24.7': {} + '@babel/helper-string-parser@7.24.8': {} + '@babel/helper-validator-identifier@7.22.20': {} '@babel/helper-validator-identifier@7.24.5': {} @@ -9645,11 +9790,13 @@ snapshots: '@babel/helper-validator-option@7.24.7': {} + '@babel/helper-validator-option@7.24.8': {} + '@babel/helper-wrap-function@7.22.20': dependencies: '@babel/helper-function-name': 7.24.7 '@babel/template': 7.24.7 - '@babel/types': 7.24.7 + '@babel/types': 7.24.9 '@babel/helpers@7.24.5': dependencies: @@ -9664,6 +9811,11 @@ snapshots: '@babel/template': 7.24.7 '@babel/types': 7.24.7 + '@babel/helpers@7.24.8': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.9 + '@babel/highlight@7.24.7': dependencies: '@babel/helper-validator-identifier': 7.24.7 @@ -9683,67 +9835,71 @@ snapshots: dependencies: '@babel/types': 7.24.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.24.7)': + '@babel/parser@7.24.8': dependencies: - '@babel/core': 7.24.7 + '@babel/types': 7.24.9 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.24.9)': + dependencies: + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.24.7)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.7) + '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.7)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.5)': @@ -9756,49 +9912,49 @@ snapshots: '@babel/core': 7.23.3 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.7)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.23.3)': @@ -9806,159 +9962,159 @@ snapshots: '@babel/core': 7.23.3 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.7)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-async-generator-functions@7.23.2(@babel/core@7.24.7)': + '@babel/plugin-transform-async-generator-functions@7.23.2(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.9) - '@babel/plugin-transform-async-to-generator@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-async-to-generator@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.7) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.24.7)': + '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.22.15(@babel/core@7.24.7)': + '@babel/plugin-transform-classes@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 '@babel/helper-optimise-call-expression': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.9) '@babel/helper-split-export-declaration': 7.24.7 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/template': 7.24.7 - '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.24.7)': + '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-for-of@7.22.15(@babel/core@7.24.7)': + '@babel/plugin-transform-for-of@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/core': 7.24.9 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-function-name': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-literals@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-literals@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-modules-amd@7.23.0(@babel/core@7.24.7)': + '@babel/plugin-transform-modules-amd@7.23.0(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 transitivePeerDependencies: - supports-color @@ -9972,114 +10128,114 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-simple-access': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.24.7)': + '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.9) - '@babel/plugin-transform-object-rest-spread@7.22.15(@babel/core@7.24.7)': + '@babel/plugin-transform-object-rest-spread@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/compat-data': 7.24.7 - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/compat-data': 7.24.9 + '@babel/core': 7.24.9 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.24.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.24.9) - '@babel/plugin-transform-object-super@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-object-super@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.9) - '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.24.7)': + '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.22.15(@babel/core@7.24.7)': + '@babel/plugin-transform-parameters@7.22.15(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.24.7)': + '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.24.5)': @@ -10106,43 +10262,43 @@ snapshots: '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5) '@babel/types': 7.24.5 - '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.24.7)': + '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-spread@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-spread@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.23.3)': @@ -10155,130 +10311,130 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.9) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.24.7)': + '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.24.7)': + '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.9) '@babel/helper-plugin-utils': 7.24.7 - '@babel/preset-env@7.23.2(@babel/core@7.24.7)': + '@babel/preset-env@7.23.2(@babel/core@7.24.9)': dependencies: - '@babel/compat-data': 7.24.7 - '@babel/core': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 + '@babel/compat-data': 7.24.9 + '@babel/core': 7.24.9 + '@babel/helper-compilation-targets': 7.24.8 '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-validator-option': 7.24.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.7) - '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-async-generator-functions': 7.23.2(@babel/core@7.24.7) - '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-block-scoping': 7.23.0(@babel/core@7.24.7) - '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-class-static-block': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-classes': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-destructuring': 7.23.0(@babel/core@7.24.7) - '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-dynamic-import': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-export-namespace-from': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-for-of': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-json-strings': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-logical-assignment-operators': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-modules-amd': 7.23.0(@babel/core@7.24.7) - '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-modules-systemjs': 7.23.0(@babel/core@7.24.7) - '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-numeric-separator': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-object-rest-spread': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-optional-catch-binding': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.7) - '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.24.7) - '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-private-property-in-object': 7.22.11(@babel/core@7.24.7) - '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-regenerator': 7.22.10(@babel/core@7.24.7) - '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-unicode-escapes': 7.22.10(@babel/core@7.24.7) - '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.24.7) - '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.24.7) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.7) - '@babel/types': 7.24.7 - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.7) - babel-plugin-polyfill-corejs3: 0.8.5(@babel/core@7.24.7) - babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.24.7) + '@babel/helper-validator-option': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.9) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.9) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.9) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.9) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.9) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.9) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.9) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.9) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.9) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.9) + '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-async-generator-functions': 7.23.2(@babel/core@7.24.9) + '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-block-scoping': 7.23.0(@babel/core@7.24.9) + '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-class-static-block': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-classes': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-destructuring': 7.23.0(@babel/core@7.24.9) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-dynamic-import': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-export-namespace-from': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-for-of': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-json-strings': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-logical-assignment-operators': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-modules-amd': 7.23.0(@babel/core@7.24.9) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.9) + '@babel/plugin-transform-modules-systemjs': 7.23.0(@babel/core@7.24.9) + '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-numeric-separator': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-object-rest-spread': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-optional-catch-binding': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.9) + '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.24.9) + '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-private-property-in-object': 7.22.11(@babel/core@7.24.9) + '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-regenerator': 7.22.10(@babel/core@7.24.9) + '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-unicode-escapes': 7.22.10(@babel/core@7.24.9) + '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.24.9) + '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.24.9) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.9) + '@babel/types': 7.24.9 + babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.9) + babel-plugin-polyfill-corejs3: 0.8.5(@babel/core@7.24.9) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.24.9) core-js-compat: 3.37.1 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 - '@babel/types': 7.24.7 + '@babel/types': 7.24.9 esutils: 2.0.3 '@babel/preset-typescript@7.23.2(@babel/core@7.23.3)': @@ -10292,14 +10448,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.24.7(@babel/core@7.24.7)': + '@babel/preset-typescript@7.24.7(@babel/core@7.24.9)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-validator-option': 7.24.7 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.9) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.9) + '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.9) transitivePeerDependencies: - supports-color @@ -10351,6 +10507,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.24.8': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.10 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.8 + '@babel/types': 7.24.9 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + '@babel/types@7.23.6': dependencies: '@babel/helper-string-parser': 7.23.4 @@ -10375,6 +10546,12 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@babel/types@7.24.9': + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + '@bcoe/v8-coverage@0.2.3': {} '@bundled-es-modules/cookie@2.0.0': @@ -10437,7 +10614,7 @@ snapshots: '@types/estree': 1.0.5 '@typescript-eslint/types': 7.14.1 comment-parser: 1.4.1 - esquery: 1.5.0 + esquery: 1.6.0 jsdoc-type-pratt-parser: 4.0.0 '@es-joy/jsdoccomment@0.46.0': @@ -10661,8 +10838,6 @@ snapshots: eslint: 9.7.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} - '@eslint-community/regexpp@4.11.0': {} '@eslint/config-array@0.17.0': @@ -10755,7 +10930,7 @@ snapshots: '@inquirer/figures': 1.0.3 '@inquirer/type': 1.3.3 '@types/mute-stream': 0.0.4 - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -10794,7 +10969,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/yargs': 17.0.12 chalk: 4.1.2 @@ -10881,9 +11056,9 @@ snapshots: '@pkgr/core@0.1.1': {} - '@playwright/test@1.45.1': + '@playwright/test@1.45.3': dependencies: - playwright: 1.45.1 + playwright: 1.45.3 '@polka/url@1.0.0-next.24': {} @@ -10891,12 +11066,12 @@ snapshots: dependencies: preact: 10.21.0 - '@preact/preset-vite@2.8.2(@babel/core@7.24.5)(preact@10.21.0)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@preact/preset-vite@2.8.2(@babel/core@7.24.5)(preact@10.21.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: '@babel/core': 7.24.5 '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.24.5) - '@prefresh/vite': 2.4.1(preact@10.21.0)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@prefresh/vite': 2.4.1(preact@10.21.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.24.5) debug: 4.3.4 @@ -10906,7 +11081,7 @@ snapshots: resolve: 1.22.8 source-map: 0.7.4 stack-trace: 1.0.0-pre2 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - preact - supports-color @@ -10919,7 +11094,7 @@ snapshots: '@prefresh/utils@1.2.0': {} - '@prefresh/vite@2.4.1(preact@10.21.0)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@prefresh/vite@2.4.1(preact@10.21.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: '@babel/core': 7.24.5 '@prefresh/babel-plugin': 0.5.0 @@ -10927,11 +11102,11 @@ snapshots: '@prefresh/utils': 1.2.0 '@rollup/pluginutils': 4.2.1 preact: 10.21.0 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - supports-color - '@puppeteer/browsers@1.4.6(typescript@5.5.3)': + '@puppeteer/browsers@1.4.6(typescript@5.5.4)': dependencies: debug: 4.3.4 extract-zip: 2.0.1 @@ -10941,7 +11116,7 @@ snapshots: unbzip2-stream: 1.4.3 yargs: 17.7.1 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -10959,133 +11134,133 @@ snapshots: '@remix-run/router@1.16.0': {} - '@rollup/plugin-babel@5.3.1(@babel/core@7.24.7)(@types/babel__core@7.20.5)(rollup@4.18.1)': + '@rollup/plugin-babel@5.3.1(@babel/core@7.24.9)(@types/babel__core@7.20.5)(rollup@4.19.0)': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 '@babel/helper-module-imports': 7.24.7 - '@rollup/pluginutils': 3.1.0(rollup@4.18.1) - rollup: 4.18.1 + '@rollup/pluginutils': 3.1.0(rollup@4.19.0) + rollup: 4.19.0 optionalDependencies: '@types/babel__core': 7.20.5 transitivePeerDependencies: - supports-color - '@rollup/plugin-commonjs@26.0.1(rollup@4.18.1)': + '@rollup/plugin-commonjs@26.0.1(rollup@4.19.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) commondir: 1.0.1 estree-walker: 2.0.2 glob: 10.4.1 is-reference: 1.2.1 magic-string: 0.30.10 optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/plugin-json@6.1.0(rollup@4.18.1)': + '@rollup/plugin-json@6.1.0(rollup@4.19.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/plugin-node-resolve@15.2.3(rollup@4.18.1)': + '@rollup/plugin-node-resolve@15.2.3(rollup@4.19.0)': dependencies: - '@rollup/pluginutils': 5.0.5(rollup@4.18.1) + '@rollup/pluginutils': 5.0.5(rollup@4.19.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/plugin-replace@2.4.2(rollup@4.18.1)': + '@rollup/plugin-replace@2.4.2(rollup@4.19.0)': dependencies: - '@rollup/pluginutils': 3.1.0(rollup@4.18.1) + '@rollup/pluginutils': 3.1.0(rollup@4.19.0) magic-string: 0.25.9 - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/plugin-terser@0.4.4(rollup@4.18.1)': + '@rollup/plugin-terser@0.4.4(rollup@4.19.0)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.22.0 optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/pluginutils@3.1.0(rollup@4.18.1)': + '@rollup/pluginutils@3.1.0(rollup@4.19.0)': dependencies: '@types/estree': 0.0.39 estree-walker: 1.0.1 picomatch: 2.3.1 - rollup: 4.18.1 + rollup: 4.19.0 '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.0.5(rollup@4.18.1)': + '@rollup/pluginutils@5.0.5(rollup@4.19.0)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/pluginutils@5.1.0(rollup@4.18.1)': + '@rollup/pluginutils@5.1.0(rollup@4.19.0)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.18.1 + rollup: 4.19.0 - '@rollup/rollup-android-arm-eabi@4.18.1': + '@rollup/rollup-android-arm-eabi@4.19.0': optional: true - '@rollup/rollup-android-arm64@4.18.1': + '@rollup/rollup-android-arm64@4.19.0': optional: true - '@rollup/rollup-darwin-arm64@4.18.1': + '@rollup/rollup-darwin-arm64@4.19.0': optional: true - '@rollup/rollup-darwin-x64@4.18.1': + '@rollup/rollup-darwin-x64@4.19.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + '@rollup/rollup-linux-arm-gnueabihf@4.19.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.18.1': + '@rollup/rollup-linux-arm-musleabihf@4.19.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.18.1': + '@rollup/rollup-linux-arm64-gnu@4.19.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.18.1': + '@rollup/rollup-linux-arm64-musl@4.19.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + '@rollup/rollup-linux-powerpc64le-gnu@4.19.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.18.1': + '@rollup/rollup-linux-riscv64-gnu@4.19.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.18.1': + '@rollup/rollup-linux-s390x-gnu@4.19.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.18.1': + '@rollup/rollup-linux-x64-gnu@4.19.0': optional: true - '@rollup/rollup-linux-x64-musl@4.18.1': + '@rollup/rollup-linux-x64-musl@4.19.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.18.1': + '@rollup/rollup-win32-arm64-msvc@4.19.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.18.1': + '@rollup/rollup-win32-ia32-msvc@4.19.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.18.1': + '@rollup/rollup-win32-x64-msvc@4.19.0': optional: true '@rtsao/scc@1.1.0': {} @@ -11094,29 +11269,33 @@ snapshots: dependencies: '@types/hast': 3.0.4 + '@shikijs/core@1.11.0': + dependencies: + '@types/hast': 3.0.4 + '@shikijs/transformers@1.10.3': dependencies: shiki: 1.10.3 - '@shikijs/twoslash@1.10.3(typescript@5.5.3)': + '@shikijs/twoslash@1.11.0(typescript@5.5.4)': dependencies: - '@shikijs/core': 1.10.3 - twoslash: 0.2.9(typescript@5.5.3) + '@shikijs/core': 1.11.0 + twoslash: 0.2.9(typescript@5.5.4) transitivePeerDependencies: - supports-color - typescript - '@shikijs/vitepress-twoslash@1.10.3(typescript@5.5.3)': + '@shikijs/vitepress-twoslash@1.11.0(typescript@5.5.4)': dependencies: - '@shikijs/twoslash': 1.10.3(typescript@5.5.3) - floating-vue: 5.2.2(vue@3.4.31(typescript@5.5.3)) + '@shikijs/twoslash': 1.11.0(typescript@5.5.4) + floating-vue: 5.2.2(vue@3.4.33(typescript@5.5.4)) mdast-util-from-markdown: 2.0.1 mdast-util-gfm: 3.0.0 mdast-util-to-hast: 13.2.0 - shiki: 1.10.3 - twoslash: 0.2.9(typescript@5.5.3) - twoslash-vue: 0.2.9(typescript@5.5.3) - vue: 3.4.31(typescript@5.5.3) + shiki: 1.11.0 + twoslash: 0.2.9(typescript@5.5.4) + twoslash-vue: 0.2.9(typescript@5.5.4) + vue: 3.4.33(typescript@5.5.4) transitivePeerDependencies: - '@nuxt/kit' - supports-color @@ -11147,7 +11326,7 @@ snapshots: '@stylistic/eslint-plugin-js@2.6.0-beta.0(eslint@9.7.0)': dependencies: '@types/eslint': 8.56.10 - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) eslint: 9.7.0 eslint-visitor-keys: 4.0.0 espree: 10.1.0 @@ -11160,31 +11339,31 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.2 - '@stylistic/eslint-plugin-plus@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3)': + '@stylistic/eslint-plugin-plus@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@types/eslint': 8.56.10 - '@typescript-eslint/utils': 8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.4) eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript - '@stylistic/eslint-plugin-ts@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3)': + '@stylistic/eslint-plugin-ts@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@stylistic/eslint-plugin-js': 2.6.0-beta.0(eslint@9.7.0) '@types/eslint': 8.56.10 - '@typescript-eslint/utils': 8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.4) eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript - '@stylistic/eslint-plugin@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3)': + '@stylistic/eslint-plugin@2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@stylistic/eslint-plugin-js': 2.6.0-beta.0(eslint@9.7.0) '@stylistic/eslint-plugin-jsx': 2.6.0-beta.0(eslint@9.7.0) - '@stylistic/eslint-plugin-plus': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3) - '@stylistic/eslint-plugin-ts': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3) + '@stylistic/eslint-plugin-plus': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4) + '@stylistic/eslint-plugin-ts': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.4) '@types/eslint': 8.56.10 eslint: 9.7.0 transitivePeerDependencies: @@ -11198,14 +11377,14 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.10 - '@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)))': + '@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)))': dependencies: - '@sveltejs/kit': 1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@sveltejs/kit': 1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) import-meta-resolve: 3.0.0 - '@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@sveltejs/kit@1.20.2(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@sveltejs/vite-plugin-svelte': 2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) '@types/cookie': 0.5.1 cookie: 0.5.0 devalue: 4.3.2 @@ -11219,30 +11398,30 @@ snapshots: svelte: 3.59.1 tiny-glob: 0.2.9 undici: 5.22.1 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)))(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)))(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@sveltejs/vite-plugin-svelte': 2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) debug: 4.3.5 svelte: 3.59.1 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)))(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.4.6(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)))(svelte@3.59.1)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) debug: 4.3.5 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.10 svelte: 3.59.1 svelte-hmr: 0.15.3(svelte@3.59.1) - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) - vitefu: 0.2.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) + vitefu: 0.2.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) transitivePeerDependencies: - supports-color @@ -11300,18 +11479,7 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@testing-library/dom@10.2.0': - dependencies: - '@babel/code-frame': 7.24.7 - '@babel/runtime': 7.24.4 - '@types/aria-query': 5.0.3 - aria-query: 5.3.0 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - - '@testing-library/dom@10.3.1': + '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.24.7 '@babel/runtime': 7.24.4 @@ -11381,7 +11549,7 @@ snapshots: '@types/jest': 29.0.0 vitest: link:packages/vitest - '@testing-library/jest-dom@6.4.6(@types/jest@29.0.0)(vitest@packages+vitest)': + '@testing-library/jest-dom@6.4.7(@types/jest@29.0.0)(vitest@packages+vitest)': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.4 @@ -11408,22 +11576,18 @@ snapshots: react: 18.2.0 react-dom: 18.0.0(react@18.2.0) - '@testing-library/user-event@14.5.2(@testing-library/dom@10.2.0)': + '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)': dependencies: - '@testing-library/dom': 10.2.0 + '@testing-library/dom': 10.4.0 - '@testing-library/user-event@14.5.2(@testing-library/dom@10.3.1)': - dependencies: - '@testing-library/dom': 10.3.1 - - '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.4.31)(vue@3.4.31(typescript@5.5.3))': + '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.4.33)(vue@3.4.33(typescript@5.5.4))': dependencies: '@babel/runtime': 7.24.4 '@testing-library/dom': 9.3.4 '@vue/test-utils': 2.4.6 - vue: 3.4.31(typescript@5.5.3) + vue: 3.4.33(typescript@5.5.4) optionalDependencies: - '@vue/compiler-sfc': 3.4.31 + '@vue/compiler-sfc': 3.4.33 '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -11494,17 +11658,17 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.14.10 + '@types/node': 20.14.11 optional: true '@types/fs-extra@8.1.3': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.1 - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/hast@3.0.4': dependencies: @@ -11545,7 +11709,7 @@ snapshots: '@types/jsdom@21.1.7': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 @@ -11553,7 +11717,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 optional: true '@types/linkify-it@5.0.0': {} @@ -11583,7 +11747,7 @@ snapshots: '@types/mute-stream@0.0.4': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/natural-compare@1.4.3': {} @@ -11599,11 +11763,15 @@ snapshots: dependencies: undici-types: 5.26.5 + '@types/node@20.14.11': + dependencies: + undici-types: 5.26.5 + '@types/normalize-package-data@2.4.1': {} '@types/prompts@2.4.9': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 kleur: 3.0.3 '@types/prop-types@15.7.9': {} @@ -11641,7 +11809,7 @@ snapshots: '@types/through@0.0.30': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/tough-cookie@4.0.2': {} @@ -11665,7 +11833,7 @@ snapshots: '@types/ws@8.5.9': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/yargs-parser@21.0.0': {} @@ -11675,37 +11843,37 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 optional: true - '@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4) '@typescript-eslint/scope-manager': 8.0.0-alpha.40 - '@typescript-eslint/type-utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) - '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/type-utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 8.0.0-alpha.40 eslint: 9.7.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@typescript-eslint/scope-manager': 8.0.0-alpha.40 '@typescript-eslint/types': 8.0.0-alpha.40 - '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.4) '@typescript-eslint/visitor-keys': 8.0.0-alpha.40 debug: 4.3.5 eslint: 9.7.0 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -11724,14 +11892,14 @@ snapshots: '@typescript-eslint/types': 8.0.0-alpha.44 '@typescript-eslint/visitor-keys': 8.0.0-alpha.44 - '@typescript-eslint/type-utils@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/type-utils@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4)': dependencies: - '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.3) - '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.4) + '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4) debug: 4.3.5 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - eslint - supports-color @@ -11742,7 +11910,7 @@ snapshots: '@typescript-eslint/types@8.0.0-alpha.44': {} - '@typescript-eslint/typescript-estree@7.14.1(typescript@5.5.3)': + '@typescript-eslint/typescript-estree@7.14.1(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 7.14.1 '@typescript-eslint/visitor-keys': 7.14.1 @@ -11751,13 +11919,13 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.0.0-alpha.40(typescript@5.5.3)': + '@typescript-eslint/typescript-estree@8.0.0-alpha.40(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 8.0.0-alpha.40 '@typescript-eslint/visitor-keys': 8.0.0-alpha.40 @@ -11766,13 +11934,13 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.0.0-alpha.44(typescript@5.5.3)': + '@typescript-eslint/typescript-estree@8.0.0-alpha.44(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 8.0.0-alpha.44 '@typescript-eslint/visitor-keys': 8.0.0-alpha.44 @@ -11781,40 +11949,40 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.5.3) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.14.1(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/utils@7.14.1(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@typescript-eslint/scope-manager': 7.14.1 '@typescript-eslint/types': 7.14.1 - '@typescript-eslint/typescript-estree': 7.14.1(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 7.14.1(typescript@5.5.4) eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/utils@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@typescript-eslint/scope-manager': 8.0.0-alpha.40 '@typescript-eslint/types': 8.0.0-alpha.40 - '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 8.0.0-alpha.40(typescript@5.5.4) eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/utils@8.0.0-alpha.44(eslint@9.7.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@typescript-eslint/scope-manager': 8.0.0-alpha.44 '@typescript-eslint/types': 8.0.0-alpha.44 - '@typescript-eslint/typescript-estree': 8.0.0-alpha.44(typescript@5.5.3) + '@typescript-eslint/typescript-estree': 8.0.0-alpha.44(typescript@5.5.4) eslint: 9.7.0 transitivePeerDependencies: - supports-color @@ -11843,23 +12011,23 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@unocss/astro@0.61.3(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@unocss/astro@0.61.5(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: - '@unocss/core': 0.61.3 - '@unocss/reset': 0.61.3 - '@unocss/vite': 0.61.3(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + '@unocss/core': 0.61.5 + '@unocss/reset': 0.61.5 + '@unocss/vite': 0.61.5(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) optionalDependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - rollup - '@unocss/cli@0.61.3(rollup@4.18.1)': + '@unocss/cli@0.61.5(rollup@4.19.0)': dependencies: '@ampproject/remapping': 2.3.0 - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) - '@unocss/config': 0.61.3 - '@unocss/core': 0.61.3 - '@unocss/preset-uno': 0.61.3 + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) + '@unocss/config': 0.61.5 + '@unocss/core': 0.61.5 + '@unocss/preset-uno': 0.61.5 cac: 6.7.14(patch_hash=slh3cigivjjjktoa42g2agwaem) chokidar: 3.6.0 colorette: 2.0.20 @@ -11871,128 +12039,128 @@ snapshots: transitivePeerDependencies: - rollup - '@unocss/config@0.61.3': + '@unocss/config@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 unconfig: 0.3.13 - '@unocss/core@0.61.3': {} + '@unocss/core@0.61.5': {} - '@unocss/extractor-arbitrary-variants@0.61.3': + '@unocss/extractor-arbitrary-variants@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/inspector@0.61.3': + '@unocss/inspector@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/rule-utils': 0.61.5 gzip-size: 6.0.0 sirv: 2.0.4 - '@unocss/postcss@0.61.3(postcss@8.4.39)': + '@unocss/postcss@0.61.5(postcss@8.4.39)': dependencies: - '@unocss/config': 0.61.3 - '@unocss/core': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/config': 0.61.5 + '@unocss/core': 0.61.5 + '@unocss/rule-utils': 0.61.5 css-tree: 2.3.1 fast-glob: 3.3.2 magic-string: 0.30.10 postcss: 8.4.39 - '@unocss/preset-attributify@0.61.3': + '@unocss/preset-attributify@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/preset-icons@0.61.3': + '@unocss/preset-icons@0.61.5': dependencies: '@iconify/utils': 2.1.25 - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 ofetch: 1.3.4 transitivePeerDependencies: - supports-color - '@unocss/preset-mini@0.61.3': + '@unocss/preset-mini@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/extractor-arbitrary-variants': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/extractor-arbitrary-variants': 0.61.5 + '@unocss/rule-utils': 0.61.5 - '@unocss/preset-tagify@0.61.3': + '@unocss/preset-tagify@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/preset-typography@0.61.3': + '@unocss/preset-typography@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/preset-mini': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/preset-mini': 0.61.5 - '@unocss/preset-uno@0.61.3': + '@unocss/preset-uno@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/preset-mini': 0.61.3 - '@unocss/preset-wind': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/preset-mini': 0.61.5 + '@unocss/preset-wind': 0.61.5 + '@unocss/rule-utils': 0.61.5 - '@unocss/preset-web-fonts@0.61.3': + '@unocss/preset-web-fonts@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 ofetch: 1.3.4 - '@unocss/preset-wind@0.61.3': + '@unocss/preset-wind@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/preset-mini': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/preset-mini': 0.61.5 + '@unocss/rule-utils': 0.61.5 - '@unocss/reset@0.61.3': {} + '@unocss/reset@0.61.5': {} - '@unocss/rule-utils@0.61.3': + '@unocss/rule-utils@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 magic-string: 0.30.10 - '@unocss/scope@0.61.3': {} + '@unocss/scope@0.61.5': {} - '@unocss/transformer-attributify-jsx-babel@0.61.3': + '@unocss/transformer-attributify-jsx-babel@0.61.5': dependencies: - '@babel/core': 7.24.7 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) - '@babel/preset-typescript': 7.24.7(@babel/core@7.24.7) - '@unocss/core': 0.61.3 + '@babel/core': 7.24.9 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.9) + '@babel/preset-typescript': 7.24.7(@babel/core@7.24.9) + '@unocss/core': 0.61.5 transitivePeerDependencies: - supports-color - '@unocss/transformer-attributify-jsx@0.61.3': + '@unocss/transformer-attributify-jsx@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/transformer-compile-class@0.61.3': + '@unocss/transformer-compile-class@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/transformer-directives@0.61.3': + '@unocss/transformer-directives@0.61.5': dependencies: - '@unocss/core': 0.61.3 - '@unocss/rule-utils': 0.61.3 + '@unocss/core': 0.61.5 + '@unocss/rule-utils': 0.61.5 css-tree: 2.3.1 - '@unocss/transformer-variant-group@0.61.3': + '@unocss/transformer-variant-group@0.61.5': dependencies: - '@unocss/core': 0.61.3 + '@unocss/core': 0.61.5 - '@unocss/vite@0.61.3(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@unocss/vite@0.61.5(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: '@ampproject/remapping': 2.3.0 - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) - '@unocss/config': 0.61.3 - '@unocss/core': 0.61.3 - '@unocss/inspector': 0.61.3 - '@unocss/scope': 0.61.3 - '@unocss/transformer-directives': 0.61.3 + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) + '@unocss/config': 0.61.5 + '@unocss/core': 0.61.5 + '@unocss/inspector': 0.61.5 + '@unocss/scope': 0.61.5 + '@unocss/transformer-directives': 0.61.5 chokidar: 3.6.0 fast-glob: 3.3.2 magic-string: 0.30.10 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - rollup @@ -12005,51 +12173,51 @@ snapshots: sharp-ico: 0.1.5 unconfig: 0.3.11 - '@vite-pwa/vitepress@0.5.0(@vite-pwa/assets-generator@0.2.4)(vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0))': + '@vite-pwa/vitepress@0.5.0(@vite-pwa/assets-generator@0.2.4)(vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0))': dependencies: - vite-plugin-pwa: 0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0) + vite-plugin-pwa: 0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0) optionalDependencies: '@vite-pwa/assets-generator': 0.2.4 - '@vitejs/plugin-basic-ssl@1.0.2(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@vitejs/plugin-basic-ssl@1.0.2(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) - '@vitejs/plugin-react@4.2.1(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))': + '@vitejs/plugin-react@4.2.1(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))': dependencies: '@babel/core': 7.24.4 '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.24.4) '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.24.4) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue@3.4.31(typescript@5.5.3))': + '@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue@3.4.33(typescript@5.5.4))': dependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) - vue: 3.4.31(typescript@5.5.3) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) + vue: 3.4.33(typescript@5.5.4) - '@vitest/browser@2.0.2(playwright@1.45.1)(typescript@5.5.3)(vitest@packages+vitest)(webdriverio@8.32.2(typescript@5.5.3))': + '@vitest/browser@2.0.4(playwright@1.45.3)(typescript@5.5.4)(vitest@packages+vitest)(webdriverio@8.32.2(typescript@5.5.4))': dependencies: - '@testing-library/dom': 10.2.0 - '@testing-library/user-event': 14.5.2(@testing-library/dom@10.2.0) - '@vitest/utils': 2.0.2 + '@testing-library/dom': 10.4.0 + '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) + '@vitest/utils': 2.0.4 magic-string: 0.30.10 - msw: 2.3.1(typescript@5.5.3) + msw: 2.3.1(typescript@5.5.4) sirv: 2.0.4 vitest: link:packages/vitest - ws: 8.17.1 + ws: 8.18.0 optionalDependencies: - playwright: 1.45.1 - webdriverio: 8.32.2(typescript@5.5.3) + playwright: 1.45.3 + webdriverio: 8.32.2(typescript@5.5.4) transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - '@vitest/pretty-format@2.0.2': + '@vitest/pretty-format@2.0.4': dependencies: tinyrainbow: 1.2.0 @@ -12061,9 +12229,9 @@ snapshots: '@vitest/test-deps-url@file:test/optimize-deps/dep-url': {} - '@vitest/ui@2.0.2(vitest@packages+vitest)': + '@vitest/ui@2.0.4(vitest@packages+vitest)': dependencies: - '@vitest/utils': 2.0.2 + '@vitest/utils': 2.0.4 fast-glob: 3.3.2 fflate: 0.8.2 flatted: 3.3.1 @@ -12072,9 +12240,9 @@ snapshots: tinyrainbow: 1.2.0 vitest: link:packages/vitest - '@vitest/utils@2.0.2': + '@vitest/utils@2.0.4': dependencies: - '@vitest/pretty-format': 2.0.2 + '@vitest/pretty-format': 2.0.4 estree-walker: 3.0.3 loupe: 3.1.1 tinyrainbow: 1.2.0 @@ -12113,6 +12281,14 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.0 + '@vue/compiler-core@3.4.33': + dependencies: + '@babel/parser': 7.24.7 + '@vue/shared': 3.4.33 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + '@vue/compiler-dom@3.4.26': dependencies: '@vue/compiler-core': 3.4.26 @@ -12123,6 +12299,11 @@ snapshots: '@vue/compiler-core': 3.4.31 '@vue/shared': 3.4.31 + '@vue/compiler-dom@3.4.33': + dependencies: + '@vue/compiler-core': 3.4.33 + '@vue/shared': 3.4.33 + '@vue/compiler-sfc@3.4.26': dependencies: '@babel/parser': 7.24.4 @@ -12135,13 +12316,13 @@ snapshots: postcss: 8.4.38 source-map-js: 1.2.0 - '@vue/compiler-sfc@3.4.31': + '@vue/compiler-sfc@3.4.33': dependencies: '@babel/parser': 7.24.7 - '@vue/compiler-core': 3.4.31 - '@vue/compiler-dom': 3.4.31 - '@vue/compiler-ssr': 3.4.31 - '@vue/shared': 3.4.31 + '@vue/compiler-core': 3.4.33 + '@vue/compiler-dom': 3.4.33 + '@vue/compiler-ssr': 3.4.33 + '@vue/shared': 3.4.33 estree-walker: 2.0.2 magic-string: 0.30.10 postcss: 8.4.39 @@ -12152,10 +12333,10 @@ snapshots: '@vue/compiler-dom': 3.4.26 '@vue/shared': 3.4.26 - '@vue/compiler-ssr@3.4.31': + '@vue/compiler-ssr@3.4.33': dependencies: - '@vue/compiler-dom': 3.4.31 - '@vue/shared': 3.4.31 + '@vue/compiler-dom': 3.4.33 + '@vue/shared': 3.4.33 '@vue/devtools-api@6.5.1': {} @@ -12190,7 +12371,7 @@ snapshots: optionalDependencies: typescript: 5.2.2 - '@vue/language-core@2.0.24(typescript@5.5.3)': + '@vue/language-core@2.0.24(typescript@5.5.4)': dependencies: '@volar/language-core': 2.4.0-alpha.5 '@vue/compiler-dom': 3.4.31 @@ -12201,25 +12382,25 @@ snapshots: path-browserify: 1.0.1 vue-template-compiler: 2.7.15 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 '@vue/reactivity@3.4.26': dependencies: '@vue/shared': 3.4.26 - '@vue/reactivity@3.4.31': + '@vue/reactivity@3.4.33': dependencies: - '@vue/shared': 3.4.31 + '@vue/shared': 3.4.33 '@vue/runtime-core@3.4.26': dependencies: '@vue/reactivity': 3.4.26 '@vue/shared': 3.4.26 - '@vue/runtime-core@3.4.31': + '@vue/runtime-core@3.4.33': dependencies: - '@vue/reactivity': 3.4.31 - '@vue/shared': 3.4.31 + '@vue/reactivity': 3.4.33 + '@vue/shared': 3.4.33 '@vue/runtime-dom@3.4.26': dependencies: @@ -12227,29 +12408,31 @@ snapshots: '@vue/shared': 3.4.26 csstype: 3.1.3 - '@vue/runtime-dom@3.4.31': + '@vue/runtime-dom@3.4.33': dependencies: - '@vue/reactivity': 3.4.31 - '@vue/runtime-core': 3.4.31 - '@vue/shared': 3.4.31 + '@vue/reactivity': 3.4.33 + '@vue/runtime-core': 3.4.33 + '@vue/shared': 3.4.33 csstype: 3.1.3 - '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.5.3))': + '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.5.4))': dependencies: '@vue/compiler-ssr': 3.4.26 '@vue/shared': 3.4.26 - vue: 3.4.26(typescript@5.5.3) + vue: 3.4.26(typescript@5.5.4) - '@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3))': + '@vue/server-renderer@3.4.33(vue@3.4.33(typescript@5.5.4))': dependencies: - '@vue/compiler-ssr': 3.4.31 - '@vue/shared': 3.4.31 - vue: 3.4.31(typescript@5.5.3) + '@vue/compiler-ssr': 3.4.33 + '@vue/shared': 3.4.33 + vue: 3.4.33(typescript@5.5.4) '@vue/shared@3.4.26': {} '@vue/shared@3.4.31': {} + '@vue/shared@3.4.33': {} + '@vue/test-utils@2.4.6': dependencies: js-beautify: 1.15.1 @@ -12262,42 +12445,42 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/core@10.11.0(vue@3.4.31(typescript@5.5.3))': + '@vueuse/core@10.11.0(vue@3.4.33(typescript@5.5.4))': dependencies: '@types/web-bluetooth': 0.0.20 '@vueuse/metadata': 10.11.0 - '@vueuse/shared': 10.11.0(vue@3.4.31(typescript@5.5.3)) - vue-demi: 0.14.8(vue@3.4.31(typescript@5.5.3)) + '@vueuse/shared': 10.11.0(vue@3.4.33(typescript@5.5.4)) + vue-demi: 0.14.8(vue@3.4.33(typescript@5.5.4)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/core@10.9.0(vue@3.4.26(typescript@5.5.3))': + '@vueuse/core@10.9.0(vue@3.4.26(typescript@5.5.4))': dependencies: '@types/web-bluetooth': 0.0.20 '@vueuse/metadata': 10.9.0 - '@vueuse/shared': 10.9.0(vue@3.4.26(typescript@5.5.3)) - vue-demi: 0.14.8(vue@3.4.26(typescript@5.5.3)) + '@vueuse/shared': 10.9.0(vue@3.4.26(typescript@5.5.4)) + vue-demi: 0.14.8(vue@3.4.26(typescript@5.5.4)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/integrations@10.11.0(focus-trap@7.5.4)(vue@3.4.31(typescript@5.5.3))': + '@vueuse/integrations@10.11.0(focus-trap@7.5.4)(vue@3.4.33(typescript@5.5.4))': dependencies: - '@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.5.3)) - '@vueuse/shared': 10.11.0(vue@3.4.31(typescript@5.5.3)) - vue-demi: 0.14.8(vue@3.4.31(typescript@5.5.3)) + '@vueuse/core': 10.11.0(vue@3.4.33(typescript@5.5.4)) + '@vueuse/shared': 10.11.0(vue@3.4.33(typescript@5.5.4)) + vue-demi: 0.14.8(vue@3.4.33(typescript@5.5.4)) optionalDependencies: focus-trap: 7.5.4 transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/integrations@10.9.0(axios@0.26.1(debug@4.3.4))(focus-trap@7.5.4)(vue@3.4.26(typescript@5.5.3))': + '@vueuse/integrations@10.9.0(axios@0.26.1(debug@4.3.4))(focus-trap@7.5.4)(vue@3.4.26(typescript@5.5.4))': dependencies: - '@vueuse/core': 10.9.0(vue@3.4.26(typescript@5.5.3)) - '@vueuse/shared': 10.9.0(vue@3.4.26(typescript@5.5.3)) - vue-demi: 0.14.7(vue@3.4.26(typescript@5.5.3)) + '@vueuse/core': 10.9.0(vue@3.4.26(typescript@5.5.4)) + '@vueuse/shared': 10.9.0(vue@3.4.26(typescript@5.5.4)) + vue-demi: 0.14.7(vue@3.4.26(typescript@5.5.4)) optionalDependencies: axios: 0.26.1(debug@4.3.4) focus-trap: 7.5.4 @@ -12309,16 +12492,16 @@ snapshots: '@vueuse/metadata@10.9.0': {} - '@vueuse/shared@10.11.0(vue@3.4.31(typescript@5.5.3))': + '@vueuse/shared@10.11.0(vue@3.4.33(typescript@5.5.4))': dependencies: - vue-demi: 0.14.8(vue@3.4.31(typescript@5.5.3)) + vue-demi: 0.14.8(vue@3.4.33(typescript@5.5.4)) transitivePeerDependencies: - '@vue/composition-api' - vue - '@vueuse/shared@10.9.0(vue@3.4.26(typescript@5.5.3))': + '@vueuse/shared@10.9.0(vue@3.4.26(typescript@5.5.4))': dependencies: - vue-demi: 0.14.8(vue@3.4.26(typescript@5.5.3)) + vue-demi: 0.14.8(vue@3.4.26(typescript@5.5.4)) transitivePeerDependencies: - '@vue/composition-api' - vue @@ -12367,15 +12550,15 @@ snapshots: '@wdio/repl@8.24.12': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@wdio/types@8.32.2': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@wdio/types@8.39.0': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@wdio/utils@8.32.2': dependencies: @@ -12430,9 +12613,9 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-jsx@5.3.2(acorn@8.12.0): + acorn-jsx@5.3.2(acorn@8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm)): dependencies: - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) acorn-walk@8.3.3: dependencies: @@ -12440,8 +12623,6 @@ snapshots: acorn@8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm): {} - acorn@8.12.0: {} - agent-base@7.1.0: dependencies: debug: 4.3.5 @@ -12640,27 +12821,27 @@ snapshots: html-entities: 2.3.3 validate-html-nesting: 1.2.2 - babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.7): + babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.9): dependencies: - '@babel/compat-data': 7.24.7 - '@babel/core': 7.24.7 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.7) + '@babel/compat-data': 7.24.9 + '@babel/core': 7.24.9 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.9) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.8.5(@babel/core@7.24.7): + babel-plugin-polyfill-corejs3@0.8.5(@babel/core@7.24.9): dependencies: - '@babel/core': 7.24.7 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.9) core-js-compat: 3.37.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.7): + babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.9): dependencies: - '@babel/core': 7.24.7 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.9) transitivePeerDependencies: - supports-color @@ -12743,6 +12924,13 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) + browserslist@4.23.2: + dependencies: + caniuse-lite: 1.0.30001643 + electron-to-chromium: 1.4.832 + node-releases: 2.0.14 + update-browserslist-db: 1.1.0(browserslist@4.23.2) + buffer-crc32@0.2.13: {} buffer-crc32@1.0.0: {} @@ -12822,6 +13010,8 @@ snapshots: caniuse-lite@1.0.30001600: {} + caniuse-lite@1.0.30001643: {} + ccount@2.0.1: {} chai-subset@1.6.0: {} @@ -12946,7 +13136,7 @@ snapshots: codemirror-theme-vars@0.1.2: {} - codemirror@5.65.16: {} + codemirror@5.65.17: {} color-convert@1.9.3: dependencies: @@ -13396,6 +13586,8 @@ snapshots: electron-to-chromium@1.4.715: {} + electron-to-chromium@1.4.832: {} + emoji-regex@10.3.0: {} emoji-regex@8.0.0: {} @@ -13603,9 +13795,9 @@ snapshots: eslint: 9.7.0 semver: 7.6.2 - eslint-config-flat-gitignore@0.1.7: + eslint-config-flat-gitignore@0.1.8: dependencies: - find-up: 7.0.0 + find-up-simple: 1.0.0 parse-gitignore: 2.0.0 eslint-flat-config-utils@0.2.5: @@ -13638,7 +13830,7 @@ snapshots: eslint-plugin-es-x@7.5.0(eslint@9.7.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/regexpp': 4.11.0 eslint: 9.7.0 eslint-compat-utils: 0.1.2(eslint@9.7.0) @@ -13648,15 +13840,15 @@ snapshots: eslint: 9.7.0 ignore: 5.3.1 - eslint-plugin-import-x@3.0.1(eslint@9.7.0)(typescript@5.5.3): + eslint-plugin-import-x@3.0.1(eslint@9.7.0)(typescript@5.5.4): dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.4) debug: 4.3.5 doctrine: 3.0.0 eslint: 9.7.0 eslint-import-resolver-node: 0.3.9 - get-tsconfig: 4.7.5 + get-tsconfig: 4.7.6 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.2 @@ -13666,7 +13858,7 @@ snapshots: - supports-color - typescript - eslint-plugin-jsdoc@48.7.0(eslint@9.7.0): + eslint-plugin-jsdoc@48.8.3(eslint@9.7.0): dependencies: '@es-joy/jsdoccomment': 0.46.0 are-docs-informative: 0.0.2 @@ -13676,9 +13868,9 @@ snapshots: eslint: 9.7.0 esquery: 1.6.0 parse-imports: 2.1.1 - semver: 7.6.2 + semver: 7.6.3 spdx-expression-parse: 4.0.0 - synckit: 0.9.0 + synckit: 0.9.1 transitivePeerDependencies: - supports-color @@ -13706,7 +13898,7 @@ snapshots: enhanced-resolve: 5.17.0 eslint: 9.7.0 eslint-plugin-es-x: 7.5.0(eslint@9.7.0) - get-tsconfig: 4.7.5 + get-tsconfig: 4.7.6 globals: 15.8.0 ignore: 5.3.1 minimatch: 9.0.5 @@ -13714,9 +13906,9 @@ snapshots: eslint-plugin-no-only-tests@3.1.0: {} - eslint-plugin-perfectionist@2.11.0(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.3)(vue-eslint-parser@9.4.3(eslint@9.7.0)): + eslint-plugin-perfectionist@2.11.0(eslint@9.7.0)(svelte@3.59.1)(typescript@5.5.4)(vue-eslint-parser@9.4.3(eslint@9.7.0)): dependencies: - '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.4) eslint: 9.7.0 minimatch: 9.0.5 natural-compare-lite: 1.4.0 @@ -13730,7 +13922,7 @@ snapshots: eslint-plugin-regexp@2.6.0(eslint@9.7.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/regexpp': 4.11.0 comment-parser: 1.4.1 eslint: 9.7.0 jsdoc-type-pratt-parser: 4.0.0 @@ -13757,7 +13949,7 @@ snapshots: clean-regexp: 1.0.0 core-js-compat: 3.37.1 eslint: 9.7.0 - esquery: 1.5.0 + esquery: 1.6.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 jsesc: 3.0.2 @@ -13770,19 +13962,19 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-unused-imports@4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0): + eslint-plugin-unused-imports@4.0.1(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0): dependencies: eslint: 9.7.0 eslint-rule-composer: 0.3.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4) - eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)(vitest@packages+vitest): + eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4)(vitest@packages+vitest): dependencies: - '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.14.1(eslint@9.7.0)(typescript@5.5.4) eslint: 9.7.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.4))(eslint@9.7.0)(typescript@5.5.4) vitest: link:packages/vitest transitivePeerDependencies: - supports-color @@ -13813,9 +14005,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-processor-vue-blocks@0.1.2(@vue/compiler-sfc@3.4.31)(eslint@9.7.0): + eslint-processor-vue-blocks@0.1.2(@vue/compiler-sfc@3.4.33)(eslint@9.7.0): dependencies: - '@vue/compiler-sfc': 3.4.31 + '@vue/compiler-sfc': 3.4.33 eslint: 9.7.0 eslint-rule-composer@0.3.0: {} @@ -13877,14 +14069,14 @@ snapshots: espree@10.1.0: dependencies: - acorn: 8.12.0 - acorn-jsx: 5.3.2(acorn@8.12.0) + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) + acorn-jsx: 5.3.2(acorn@8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm)) eslint-visitor-keys: 4.0.0 espree@9.6.1: dependencies: - acorn: 8.12.0 - acorn-jsx: 5.3.2(acorn@8.12.0) + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) + acorn-jsx: 5.3.2(acorn@8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm)) eslint-visitor-keys: 3.4.3 esprima-extract-comments@1.1.0: @@ -14155,6 +14347,8 @@ snapshots: fast-querystring: 1.1.2 safe-regex2: 2.0.0 + find-up-simple@1.0.0: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -14170,12 +14364,6 @@ snapshots: locate-path: 7.1.1 path-exists: 5.0.0 - find-up@7.0.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - unicorn-magic: 0.1.0 - flat-cache@4.0.1: dependencies: flatted: 3.3.1 @@ -14187,11 +14375,11 @@ snapshots: flatted@3.3.1: {} - floating-vue@5.2.2(vue@3.4.31(typescript@5.5.3)): + floating-vue@5.2.2(vue@3.4.33(typescript@5.5.4)): dependencies: '@floating-ui/dom': 1.1.1 - vue: 3.4.31(typescript@5.5.3) - vue-resize: 2.0.0-alpha.1(vue@3.4.31(typescript@5.5.3)) + vue: 3.4.33(typescript@5.5.4) + vue-resize: 2.0.0-alpha.1(vue@3.4.33(typescript@5.5.4)) focus-trap@7.5.4: dependencies: @@ -14346,7 +14534,7 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - get-tsconfig@4.7.5: + get-tsconfig@4.7.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -14635,6 +14823,13 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.5: + dependencies: + agent-base: 7.1.0 + debug: 4.3.5 + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} human-signals@3.0.1: {} @@ -14949,7 +15144,7 @@ snapshots: jest-util@29.0.1: dependencies: '@jest/types': 29.0.1 - '@types/node': 20.14.10 + '@types/node': 20.14.11 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -15009,7 +15204,7 @@ snapshots: - supports-color - utf-8-validate - jsdom@24.1.0: + jsdom@24.1.1: dependencies: cssstyle: 4.0.1 data-urls: 5.0.0 @@ -15017,9 +15212,9 @@ snapshots: form-data: 4.0.0 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.4 + https-proxy-agent: 7.0.5 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.10 + nwsapi: 2.2.12 parse5: 7.1.2 rrweb-cssom: 0.7.1 saxes: 6.0.0 @@ -15030,7 +15225,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - ws: 8.17.1 + ws: 8.18.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -15067,7 +15262,7 @@ snapshots: jsonc-eslint-parser@2.4.0: dependencies: - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) eslint-visitor-keys: 3.4.3 espree: 9.6.1 semver: 7.6.2 @@ -15182,10 +15377,6 @@ snapshots: dependencies: p-locate: 6.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - lodash.clonedeep@4.5.0: {} lodash.debounce@4.0.8: {} @@ -15412,6 +15603,10 @@ snapshots: media-typer@0.3.0: {} + memfs@4.8.2: + dependencies: + tslib: 2.6.2 + merge-anything@5.1.7: dependencies: is-what: 4.1.8 @@ -15678,7 +15873,7 @@ snapshots: ms@2.1.3: {} - msw@2.3.1(typescript@5.5.3): + msw@2.3.1(typescript@5.5.4): dependencies: '@bundled-es-modules/cookie': 2.0.0 '@bundled-es-modules/statuses': 1.0.1 @@ -15698,7 +15893,29 @@ snapshots: type-fest: 4.20.0 yargs: 17.7.2 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 + + msw@2.3.2(typescript@5.5.4): + dependencies: + '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/statuses': 1.0.1 + '@inquirer/confirm': 3.1.9 + '@mswjs/cookies': 1.1.0 + '@mswjs/interceptors': 0.29.1 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + chalk: 4.1.2 + graphql: 16.8.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.2 + path-to-regexp: 6.2.2 + strict-event-emitter: 0.5.1 + type-fest: 4.20.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.5.4 muggle-string@0.3.1: {} @@ -15778,7 +15995,7 @@ snapshots: dependencies: boolbase: 1.0.0 - nwsapi@2.2.10: {} + nwsapi@2.2.12: {} nwsapi@2.2.7: {} @@ -16038,7 +16255,7 @@ snapshots: playwright-core@1.41.0: {} - playwright-core@1.45.1: {} + playwright-core@1.45.3: {} playwright@1.41.0: dependencies: @@ -16046,9 +16263,9 @@ snapshots: optionalDependencies: fsevents: 2.3.2 - playwright@1.45.1: + playwright@1.45.3: dependencies: - playwright-core: 1.45.1 + playwright-core: 1.45.3 optionalDependencies: fsevents: 2.3.2 @@ -16152,16 +16369,16 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@20.9.0(typescript@5.5.3): + puppeteer-core@20.9.0(typescript@5.5.4): dependencies: - '@puppeteer/browsers': 1.4.6(typescript@5.5.3) + '@puppeteer/browsers': 1.4.6(typescript@5.5.4) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0 debug: 4.3.4 devtools-protocol: 0.0.1147663 ws: 8.13.0 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - bufferutil - encoding @@ -16294,7 +16511,7 @@ snapshots: refa@0.12.1: dependencies: - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/regexpp': 4.11.0 regenerate-unicode-properties@10.1.1: dependencies: @@ -16310,7 +16527,7 @@ snapshots: regexp-ast-analysis@0.7.1: dependencies: - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/regexpp': 4.11.0 refa: 0.12.1 regexp-tree@0.1.27: {} @@ -16401,26 +16618,26 @@ snapshots: globby: 10.0.1 is-plain-object: 3.0.1 - rollup-plugin-dts@6.1.1(rollup@4.18.1)(typescript@5.5.3): + rollup-plugin-dts@6.1.1(rollup@4.19.0)(typescript@5.5.4): dependencies: magic-string: 0.30.10 - rollup: 4.18.1 - typescript: 5.5.3 + rollup: 4.19.0 + typescript: 5.5.4 optionalDependencies: '@babel/code-frame': 7.24.7 - rollup-plugin-esbuild@6.1.1(esbuild@0.23.0)(rollup@4.18.1): + rollup-plugin-esbuild@6.1.1(esbuild@0.23.0)(rollup@4.19.0): dependencies: - '@rollup/pluginutils': 5.0.5(rollup@4.18.1) + '@rollup/pluginutils': 5.0.5(rollup@4.19.0) debug: 4.3.5 es-module-lexer: 1.3.1 esbuild: 0.23.0 - get-tsconfig: 4.7.5 - rollup: 4.18.1 + get-tsconfig: 4.7.6 + rollup: 4.19.0 transitivePeerDependencies: - supports-color - rollup-plugin-license@3.5.2(rollup@4.18.1): + rollup-plugin-license@3.5.2(rollup@4.19.0): dependencies: commenting: 1.1.0 fdir: 6.1.1 @@ -16428,32 +16645,32 @@ snapshots: magic-string: 0.30.10 moment: 2.30.1 package-name-regex: 2.0.6 - rollup: 4.18.1 + rollup: 4.19.0 spdx-expression-validate: 2.0.0 spdx-satisfies: 5.0.1 transitivePeerDependencies: - picomatch - rollup@4.18.1: + rollup@4.19.0: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.1 - '@rollup/rollup-android-arm64': 4.18.1 - '@rollup/rollup-darwin-arm64': 4.18.1 - '@rollup/rollup-darwin-x64': 4.18.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 - '@rollup/rollup-linux-arm-musleabihf': 4.18.1 - '@rollup/rollup-linux-arm64-gnu': 4.18.1 - '@rollup/rollup-linux-arm64-musl': 4.18.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 - '@rollup/rollup-linux-riscv64-gnu': 4.18.1 - '@rollup/rollup-linux-s390x-gnu': 4.18.1 - '@rollup/rollup-linux-x64-gnu': 4.18.1 - '@rollup/rollup-linux-x64-musl': 4.18.1 - '@rollup/rollup-win32-arm64-msvc': 4.18.1 - '@rollup/rollup-win32-ia32-msvc': 4.18.1 - '@rollup/rollup-win32-x64-msvc': 4.18.1 + '@rollup/rollup-android-arm-eabi': 4.19.0 + '@rollup/rollup-android-arm64': 4.19.0 + '@rollup/rollup-darwin-arm64': 4.19.0 + '@rollup/rollup-darwin-x64': 4.19.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.19.0 + '@rollup/rollup-linux-arm-musleabihf': 4.19.0 + '@rollup/rollup-linux-arm64-gnu': 4.19.0 + '@rollup/rollup-linux-arm64-musl': 4.19.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.19.0 + '@rollup/rollup-linux-riscv64-gnu': 4.19.0 + '@rollup/rollup-linux-s390x-gnu': 4.19.0 + '@rollup/rollup-linux-x64-gnu': 4.19.0 + '@rollup/rollup-linux-x64-musl': 4.19.0 + '@rollup/rollup-win32-arm64-msvc': 4.19.0 + '@rollup/rollup-win32-ia32-msvc': 4.19.0 + '@rollup/rollup-win32-x64-msvc': 4.19.0 fsevents: 2.3.3 rrweb-cssom@0.6.0: {} @@ -16518,7 +16735,7 @@ snapshots: scslre@0.3.0: dependencies: - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/regexpp': 4.11.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 @@ -16544,6 +16761,8 @@ snapshots: semver@7.6.2: {} + semver@7.6.3: {} + send@0.18.0: dependencies: debug: 2.6.9 @@ -16628,6 +16847,11 @@ snapshots: '@shikijs/core': 1.10.3 '@types/hast': 3.0.4 + shiki@1.11.0: + dependencies: + '@shikijs/core': 1.11.0 + '@types/hast': 3.0.4 + side-channel@1.0.4: dependencies: call-bind: 1.0.5 @@ -16959,7 +17183,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@3.4.3(@babel/core@7.24.7)(postcss@8.4.39)(svelte@3.59.1): + svelte-check@3.4.3(@babel/core@7.24.9)(postcss@8.4.39)(svelte@3.59.1): dependencies: '@jridgewell/trace-mapping': 0.3.18 chokidar: 3.5.3 @@ -16968,7 +17192,7 @@ snapshots: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.59.1 - svelte-preprocess: 5.0.4(@babel/core@7.24.7)(postcss@8.4.39)(svelte@3.59.1)(typescript@5.4.5) + svelte-preprocess: 5.0.4(@babel/core@7.24.9)(postcss@8.4.39)(svelte@3.59.1)(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - '@babel/core' @@ -16985,7 +17209,7 @@ snapshots: dependencies: svelte: 3.59.1 - svelte-preprocess@5.0.4(@babel/core@7.24.7)(postcss@8.4.39)(svelte@3.59.1)(typescript@5.4.5): + svelte-preprocess@5.0.4(@babel/core@7.24.9)(postcss@8.4.39)(svelte@3.59.1)(typescript@5.4.5): dependencies: '@types/pug': 2.0.6 detect-indent: 6.1.0 @@ -16994,7 +17218,7 @@ snapshots: strip-indent: 3.0.0 svelte: 3.59.1 optionalDependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.24.9 postcss: 8.4.39 typescript: 5.4.5 @@ -17008,7 +17232,7 @@ snapshots: dependencies: tslib: 2.6.2 - synckit@0.9.0: + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 tslib: 2.6.2 @@ -17065,7 +17289,7 @@ snapshots: terser@5.22.0: dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) commander: 2.20.3 source-map-support: 0.5.21 @@ -17154,9 +17378,9 @@ snapshots: trim-lines@3.0.1: {} - ts-api-utils@1.3.0(typescript@5.5.3): + ts-api-utils@1.3.0(typescript@5.5.4): dependencies: - typescript: 5.5.3 + typescript: 5.5.4 tslib@2.5.3: {} @@ -17165,7 +17389,7 @@ snapshots: tsx@4.16.2: dependencies: esbuild: 0.21.5 - get-tsconfig: 4.7.5 + get-tsconfig: 4.7.6 optionalDependencies: fsevents: 2.3.3 @@ -17182,20 +17406,20 @@ snapshots: twoslash-protocol@0.2.9: {} - twoslash-vue@0.2.9(typescript@5.5.3): + twoslash-vue@0.2.9(typescript@5.5.4): dependencies: - '@vue/language-core': 2.0.24(typescript@5.5.3) - twoslash: 0.2.9(typescript@5.5.3) + '@vue/language-core': 2.0.24(typescript@5.5.4) + twoslash: 0.2.9(typescript@5.5.4) twoslash-protocol: 0.2.9 - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - twoslash@0.2.9(typescript@5.5.3): + twoslash@0.2.9(typescript@5.5.4): dependencies: '@typescript/vfs': 1.5.0 twoslash-protocol: 0.2.9 - typescript: 5.5.3 + typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -17259,7 +17483,7 @@ snapshots: typescript@5.4.5: {} - typescript@5.5.3: {} + typescript@5.5.4: {} ufo@1.5.3: {} @@ -17307,12 +17531,10 @@ snapshots: unicode-property-aliases-ecmascript@2.0.0: {} - unicorn-magic@0.1.0: {} - - unimport@3.7.2(rollup@4.18.1): + unimport@3.7.2(rollup@4.19.0): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) - acorn: 8.12.0 + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) escape-string-regexp: 5.0.0 estree-walker: 3.0.3 fast-glob: 3.3.2 @@ -17364,30 +17586,30 @@ snapshots: universalify@2.0.0: {} - unocss@0.61.3(postcss@8.4.39)(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)): - dependencies: - '@unocss/astro': 0.61.3(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) - '@unocss/cli': 0.61.3(rollup@4.18.1) - '@unocss/core': 0.61.3 - '@unocss/extractor-arbitrary-variants': 0.61.3 - '@unocss/postcss': 0.61.3(postcss@8.4.39) - '@unocss/preset-attributify': 0.61.3 - '@unocss/preset-icons': 0.61.3 - '@unocss/preset-mini': 0.61.3 - '@unocss/preset-tagify': 0.61.3 - '@unocss/preset-typography': 0.61.3 - '@unocss/preset-uno': 0.61.3 - '@unocss/preset-web-fonts': 0.61.3 - '@unocss/preset-wind': 0.61.3 - '@unocss/reset': 0.61.3 - '@unocss/transformer-attributify-jsx': 0.61.3 - '@unocss/transformer-attributify-jsx-babel': 0.61.3 - '@unocss/transformer-compile-class': 0.61.3 - '@unocss/transformer-directives': 0.61.3 - '@unocss/transformer-variant-group': 0.61.3 - '@unocss/vite': 0.61.3(rollup@4.18.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + unocss@0.61.5(postcss@8.4.39)(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)): + dependencies: + '@unocss/astro': 0.61.5(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) + '@unocss/cli': 0.61.5(rollup@4.19.0) + '@unocss/core': 0.61.5 + '@unocss/extractor-arbitrary-variants': 0.61.5 + '@unocss/postcss': 0.61.5(postcss@8.4.39) + '@unocss/preset-attributify': 0.61.5 + '@unocss/preset-icons': 0.61.5 + '@unocss/preset-mini': 0.61.5 + '@unocss/preset-tagify': 0.61.5 + '@unocss/preset-typography': 0.61.5 + '@unocss/preset-uno': 0.61.5 + '@unocss/preset-web-fonts': 0.61.5 + '@unocss/preset-wind': 0.61.5 + '@unocss/reset': 0.61.5 + '@unocss/transformer-attributify-jsx': 0.61.5 + '@unocss/transformer-attributify-jsx-babel': 0.61.5 + '@unocss/transformer-compile-class': 0.61.5 + '@unocss/transformer-directives': 0.61.5 + '@unocss/transformer-variant-group': 0.61.5 + '@unocss/vite': 0.61.5(rollup@4.19.0)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) optionalDependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) transitivePeerDependencies: - postcss - rollup @@ -17395,34 +17617,34 @@ snapshots: unpipe@1.0.0: {} - unplugin-auto-import@0.18.0(@vueuse/core@10.11.0(vue@3.4.31(typescript@5.5.3)))(rollup@4.18.1): + unplugin-auto-import@0.18.0(@vueuse/core@10.11.0(vue@3.4.33(typescript@5.5.4)))(rollup@4.19.0): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) fast-glob: 3.3.2 local-pkg: 0.5.0 magic-string: 0.30.10 minimatch: 9.0.5 - unimport: 3.7.2(rollup@4.18.1) + unimport: 3.7.2(rollup@4.19.0) unplugin: 1.11.0 optionalDependencies: - '@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.5.3)) + '@vueuse/core': 10.11.0(vue@3.4.33(typescript@5.5.4)) transitivePeerDependencies: - rollup - unplugin-swc@1.4.4(@swc/core@1.4.1)(rollup@4.18.1): + unplugin-swc@1.4.4(@swc/core@1.4.1)(rollup@4.19.0): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) '@swc/core': 1.4.1 load-tsconfig: 0.2.5 unplugin: 1.7.1 transitivePeerDependencies: - rollup - unplugin-vue-components@0.27.2(@babel/parser@7.24.7)(rollup@4.18.1)(vue@3.4.31(typescript@5.5.3)): + unplugin-vue-components@0.27.3(@babel/parser@7.24.8)(rollup@4.19.0)(vue@3.4.33(typescript@5.5.4)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@rollup/pluginutils': 5.1.0(rollup@4.19.0) chokidar: 3.6.0 debug: 4.3.5 fast-glob: 3.3.2 @@ -17430,31 +17652,24 @@ snapshots: magic-string: 0.30.10 minimatch: 9.0.5 mlly: 1.7.1 - unplugin: 1.10.1 - vue: 3.4.31(typescript@5.5.3) + unplugin: 1.11.0 + vue: 3.4.33(typescript@5.5.4) optionalDependencies: - '@babel/parser': 7.24.7 + '@babel/parser': 7.24.8 transitivePeerDependencies: - rollup - supports-color - unplugin@1.10.1: - dependencies: - acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) - chokidar: 3.6.0 - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.6.1 - unplugin@1.11.0: dependencies: - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.1 unplugin@1.7.1: dependencies: - acorn: 8.12.0 + acorn: 8.11.3(patch_hash=no36qihqjrd3chyjw73dk5xfkm) chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.1 @@ -17480,6 +17695,12 @@ snapshots: escalade: 3.1.2 picocolors: 1.0.1 + update-browserslist-db@1.1.0(browserslist@4.23.2): + dependencies: + browserslist: 4.23.2 + escalade: 3.1.2 + picocolors: 1.0.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -17541,7 +17762,7 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-plugin-pages@0.32.3(@vue/compiler-sfc@3.4.31)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue-router@4.4.0(vue@3.4.31(typescript@5.5.3))): + vite-plugin-pages@0.32.3(@vue/compiler-sfc@3.4.33)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue-router@4.4.0(vue@3.4.33(typescript@5.5.4))): dependencies: '@types/debug': 4.1.12 debug: 4.3.5 @@ -17551,20 +17772,20 @@ snapshots: json5: 2.2.3 local-pkg: 0.5.0 picocolors: 1.0.1 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) yaml: 2.4.5 optionalDependencies: - '@vue/compiler-sfc': 3.4.31 - vue-router: 4.4.0(vue@3.4.31(typescript@5.5.3)) + '@vue/compiler-sfc': 3.4.33 + vue-router: 4.4.0(vue@3.4.33(typescript@5.5.4)) transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0): + vite-plugin-pwa@0.20.0(@vite-pwa/assets-generator@0.2.4)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(workbox-build@7.1.0(@types/babel__core@7.20.5))(workbox-window@7.1.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) workbox-build: 7.1.0(@types/babel__core@7.20.5) workbox-window: 7.1.0 optionalDependencies: @@ -17572,7 +17793,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-solid@2.7.2(solid-js@1.8.3)(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)): + vite-plugin-solid@2.7.2(solid-js@1.8.3)(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)): dependencies: '@babel/core': 7.23.3 '@babel/preset-typescript': 7.23.2(@babel/core@7.23.3) @@ -17581,8 +17802,8 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.8.3 solid-refresh: 0.5.3(solid-js@1.8.3) - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) - vitefu: 0.2.4(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) + vitefu: 0.2.4(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)) transitivePeerDependencies: - supports-color @@ -17590,48 +17811,48 @@ snapshots: dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.1 + rollup: 4.19.0 optionalDependencies: '@types/node': 20.11.5 fsevents: 2.3.3 terser: 5.22.0 - vite@5.3.3(@types/node@20.14.10)(terser@5.22.0): + vite@5.3.3(@types/node@20.14.11)(terser@5.22.0): dependencies: esbuild: 0.21.5 postcss: 8.4.39 - rollup: 4.18.1 + rollup: 4.19.0 optionalDependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 fsevents: 2.3.3 terser: 5.22.0 - vitefu@0.2.4(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)): + vitefu@0.2.4(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)): optionalDependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) - vitefu@0.2.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0)): + vitefu@0.2.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0)): optionalDependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) - vitepress@1.3.1(@algolia/client-search@4.20.0)(@types/node@20.14.10)(@types/react@18.2.79)(postcss@8.4.39)(react-dom@18.0.0(react@18.2.0))(react@18.2.0)(search-insights@2.9.0)(terser@5.22.0)(typescript@5.5.3): + vitepress@1.3.1(@algolia/client-search@4.20.0)(@types/node@20.14.11)(@types/react@18.2.79)(postcss@8.4.39)(react-dom@18.0.0(react@18.2.0))(react@18.2.0)(search-insights@2.9.0)(terser@5.22.0)(typescript@5.5.4): dependencies: '@docsearch/css': 3.6.0 '@docsearch/js': 3.6.0(@algolia/client-search@4.20.0)(@types/react@18.2.79)(react-dom@18.0.0(react@18.2.0))(react@18.2.0)(search-insights@2.9.0) '@shikijs/core': 1.10.3 '@shikijs/transformers': 1.10.3 '@types/markdown-it': 14.1.1 - '@vitejs/plugin-vue': 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.22.0))(vue@3.4.31(typescript@5.5.3)) + '@vitejs/plugin-vue': 5.0.5(vite@5.3.3(@types/node@20.14.11)(terser@5.22.0))(vue@3.4.33(typescript@5.5.4)) '@vue/devtools-api': 7.3.6 '@vue/shared': 3.4.31 - '@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.5.3)) - '@vueuse/integrations': 10.11.0(focus-trap@7.5.4)(vue@3.4.31(typescript@5.5.3)) + '@vueuse/core': 10.11.0(vue@3.4.33(typescript@5.5.4)) + '@vueuse/integrations': 10.11.0(focus-trap@7.5.4)(vue@3.4.33(typescript@5.5.4)) focus-trap: 7.5.4 mark.js: 8.11.1 minisearch: 7.0.0 shiki: 1.10.3 - vite: 5.3.3(@types/node@20.14.10)(terser@5.22.0) - vue: 3.4.31(typescript@5.5.3) + vite: 5.3.3(@types/node@20.14.11)(terser@5.22.0) + vue: 3.4.33(typescript@5.5.4) optionalDependencies: postcss: 8.4.39 transitivePeerDependencies: @@ -17669,17 +17890,17 @@ snapshots: vue-component-type-helpers@2.0.17: {} - vue-demi@0.14.7(vue@3.4.26(typescript@5.5.3)): + vue-demi@0.14.7(vue@3.4.26(typescript@5.5.4)): dependencies: - vue: 3.4.26(typescript@5.5.3) + vue: 3.4.26(typescript@5.5.4) - vue-demi@0.14.8(vue@3.4.26(typescript@5.5.3)): + vue-demi@0.14.8(vue@3.4.26(typescript@5.5.4)): dependencies: - vue: 3.4.26(typescript@5.5.3) + vue: 3.4.26(typescript@5.5.4) - vue-demi@0.14.8(vue@3.4.31(typescript@5.5.3)): + vue-demi@0.14.8(vue@3.4.33(typescript@5.5.4)): dependencies: - vue: 3.4.31(typescript@5.5.3) + vue: 3.4.33(typescript@5.5.4) vue-eslint-parser@9.4.3(eslint@9.7.0): dependencies: @@ -17688,24 +17909,24 @@ snapshots: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 lodash: 4.17.21 semver: 7.6.2 transitivePeerDependencies: - supports-color - vue-observe-visibility@2.0.0-alpha.1(vue@3.4.31(typescript@5.5.3)): + vue-observe-visibility@2.0.0-alpha.1(vue@3.4.33(typescript@5.5.4)): dependencies: - vue: 3.4.31(typescript@5.5.3) + vue: 3.4.33(typescript@5.5.4) - vue-resize@2.0.0-alpha.1(vue@3.4.31(typescript@5.5.3)): + vue-resize@2.0.0-alpha.1(vue@3.4.33(typescript@5.5.4)): dependencies: - vue: 3.4.31(typescript@5.5.3) + vue: 3.4.33(typescript@5.5.4) - vue-router@4.4.0(vue@3.4.31(typescript@5.5.3)): + vue-router@4.4.0(vue@3.4.33(typescript@5.5.4)): dependencies: '@vue/devtools-api': 6.5.1 - vue: 3.4.31(typescript@5.5.3) + vue: 3.4.33(typescript@5.5.4) vue-template-compiler@2.7.15: dependencies: @@ -17719,32 +17940,32 @@ snapshots: semver: 7.5.4 typescript: 5.2.2 - vue-virtual-scroller@2.0.0-beta.8(vue@3.4.31(typescript@5.5.3)): + vue-virtual-scroller@2.0.0-beta.8(vue@3.4.33(typescript@5.5.4)): dependencies: mitt: 2.1.0 - vue: 3.4.31(typescript@5.5.3) - vue-observe-visibility: 2.0.0-alpha.1(vue@3.4.31(typescript@5.5.3)) - vue-resize: 2.0.0-alpha.1(vue@3.4.31(typescript@5.5.3)) + vue: 3.4.33(typescript@5.5.4) + vue-observe-visibility: 2.0.0-alpha.1(vue@3.4.33(typescript@5.5.4)) + vue-resize: 2.0.0-alpha.1(vue@3.4.33(typescript@5.5.4)) - vue@3.4.26(typescript@5.5.3): + vue@3.4.26(typescript@5.5.4): dependencies: '@vue/compiler-dom': 3.4.26 '@vue/compiler-sfc': 3.4.26 '@vue/runtime-dom': 3.4.26 - '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.5.3)) + '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.5.4)) '@vue/shared': 3.4.26 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 - vue@3.4.31(typescript@5.5.3): + vue@3.4.33(typescript@5.5.4): dependencies: - '@vue/compiler-dom': 3.4.31 - '@vue/compiler-sfc': 3.4.31 - '@vue/runtime-dom': 3.4.31 - '@vue/server-renderer': 3.4.31(vue@3.4.31(typescript@5.5.3)) - '@vue/shared': 3.4.31 + '@vue/compiler-dom': 3.4.33 + '@vue/compiler-sfc': 3.4.33 + '@vue/runtime-dom': 3.4.33 + '@vue/server-renderer': 3.4.33(vue@3.4.33(typescript@5.5.4)) + '@vue/shared': 3.4.33 optionalDependencies: - typescript: 5.5.3 + typescript: 5.5.4 w3c-xmlserializer@5.0.0: dependencies: @@ -17770,7 +17991,7 @@ snapshots: webdriver@8.32.2: dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/ws': 8.5.11 '@wdio/config': 8.32.2 '@wdio/logger': 8.28.0 @@ -17788,7 +18009,7 @@ snapshots: webdriver@8.39.0: dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 '@types/ws': 8.5.11 '@wdio/config': 8.39.0 '@wdio/logger': 8.38.0 @@ -17804,7 +18025,7 @@ snapshots: - supports-color - utf-8-validate - webdriverio@8.32.2(typescript@5.5.3): + webdriverio@8.32.2(typescript@5.5.4): dependencies: '@types/node': 20.11.19 '@wdio/config': 8.32.2 @@ -17824,7 +18045,7 @@ snapshots: lodash.clonedeep: 4.5.0 lodash.zip: 4.2.0 minimatch: 9.0.3 - puppeteer-core: 20.9.0(typescript@5.5.3) + puppeteer-core: 20.9.0(typescript@5.5.4) query-selector-shadow-dom: 1.0.1 resq: 1.11.0 rgb2hex: 0.2.5 @@ -17837,7 +18058,7 @@ snapshots: - typescript - utf-8-validate - webdriverio@8.39.1(typescript@5.5.3): + webdriverio@8.39.1(typescript@5.5.4): dependencies: '@types/node': 20.14.10 '@wdio/config': 8.39.0 @@ -17858,7 +18079,7 @@ snapshots: lodash.clonedeep: 4.5.0 lodash.zip: 4.2.0 minimatch: 9.0.5 - puppeteer-core: 20.9.0(typescript@5.5.3) + puppeteer-core: 20.9.0(typescript@5.5.4) query-selector-shadow-dom: 1.0.1 resq: 1.11.0 rgb2hex: 0.2.5 @@ -17953,13 +18174,13 @@ snapshots: workbox-build@7.1.0(@types/babel__core@7.20.5): dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) - '@babel/core': 7.24.7 - '@babel/preset-env': 7.23.2(@babel/core@7.24.7) + '@babel/core': 7.24.9 + '@babel/preset-env': 7.23.2(@babel/core@7.24.9) '@babel/runtime': 7.24.4 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.24.7)(@types/babel__core@7.20.5)(rollup@4.18.1) - '@rollup/plugin-node-resolve': 15.2.3(rollup@4.18.1) - '@rollup/plugin-replace': 2.4.2(rollup@4.18.1) - '@rollup/plugin-terser': 0.4.4(rollup@4.18.1) + '@rollup/plugin-babel': 5.3.1(@babel/core@7.24.9)(@types/babel__core@7.20.5)(rollup@4.19.0) + '@rollup/plugin-node-resolve': 15.2.3(rollup@4.19.0) + '@rollup/plugin-replace': 2.4.2(rollup@4.19.0) + '@rollup/plugin-terser': 0.4.4(rollup@4.19.0) '@surma/rollup-plugin-off-main-thread': 2.2.3 ajv: 8.12.0 common-tags: 1.8.2 @@ -17968,7 +18189,7 @@ snapshots: glob: 7.2.3 lodash: 4.17.21 pretty-bytes: 5.6.0 - rollup: 4.18.1 + rollup: 4.19.0 source-map: 0.8.0-beta.0 stringify-object: 3.3.0 strip-comments: 2.0.1 @@ -18158,4 +18379,4 @@ snapshots: zx@8.1.4: optionalDependencies: '@types/fs-extra': 11.0.4 - '@types/node': 20.14.10 + '@types/node': 20.14.11 diff --git a/test/browser/fixtures/mocking/import-actual-dep.test.ts b/test/browser/fixtures/mocking/import-actual-dep.test.ts new file mode 100644 index 000000000000..04b712c13cd2 --- /dev/null +++ b/test/browser/fixtures/mocking/import-actual-dep.test.ts @@ -0,0 +1,13 @@ +import { a, b } from '@vitest/cjs-lib' +import { expect, test, vi } from 'vitest' + +vi.mock(import('@vitest/cjs-lib'), async (importOriginal) => { + return { + ...await importOriginal(), + } +}) + +test('mocking works correctly', () => { + expect(a).toBe('a') + expect(b).toBe('b') +}) diff --git a/test/browser/specs/mocking.test.ts b/test/browser/specs/mocking.test.ts index 040a7e764066..a42fc91957fd 100644 --- a/test/browser/specs/mocking.test.ts +++ b/test/browser/specs/mocking.test.ts @@ -24,6 +24,7 @@ test.each([true, false])('mocking works correctly - isolated %s', async (isolate expect(result.stdout).toContain('import-actual-query.test.ts') expect(result.stdout).toContain('import-mock.test.ts') expect(result.stdout).toContain('mocked-do-mock-factory.test.ts') + expect(result.stdout).toContain('import-actual-dep.test.ts') expect(result.exitCode).toBe(0) }) diff --git a/test/browser/test/userEvent.test.ts b/test/browser/test/userEvent.test.ts index 77363addd2e3..c69c890812e6 100644 --- a/test/browser/test/userEvent.test.ts +++ b/test/browser/test/userEvent.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, test, vi } from 'vitest' -import { server, userEvent } from '@vitest/browser/context' +import { userEvent as _uE, server } from '@vitest/browser/context' import '../src/button.css' beforeEach(() => { @@ -7,6 +7,8 @@ beforeEach(() => { document.body.replaceChildren() }) +const userEvent = _uE.setup() + describe('userEvent.click', () => { test('correctly clicks a button', async () => { const button = document.createElement('button') @@ -68,6 +70,27 @@ describe('userEvent.click', () => { expect(onClick).toHaveBeenCalled() }) + + test('clicks a button with complex HTML ID', async () => { + const container = document.createElement('div') + // This is similar to unique IDs generated by React's useId() + container.id = ':r3:' + const button = document.createElement('button') + // Use uppercase and special characters + button.id = 'A:Button' + button.textContent = 'Click me' + container.appendChild(button) + document.body.appendChild(container) + + const onClick = vi.fn() + const dblClick = vi.fn() + button.addEventListener('click', onClick) + + await userEvent.click(button) + + expect(onClick).toHaveBeenCalled() + expect(dblClick).not.toHaveBeenCalled() + }) }) describe('userEvent.dblClick', () => { @@ -153,13 +176,14 @@ describe('userEvent.tripleClick', () => { }) describe('userEvent.hover, userEvent.unhover', () => { - test('hover works correctly', async () => { + test('hover, unhover works correctly', async () => { const target = document.createElement('div') target.style.width = '100px' target.style.height = '100px' let mouseEntered = false let pointerEntered = false + target.addEventListener('mouseover', () => { mouseEntered = true }) @@ -186,6 +210,46 @@ describe('userEvent.hover, userEvent.unhover', () => { expect(mouseEntered).toBe(false) }) + test.runIf(server.provider === 'playwright')('hover, unhover correctly pass options', async () => { + interface ModifiersDetected { shift: boolean; control: boolean } + type ModifierKeys = 'Shift' | 'Control' | 'Alt' | 'ControlOrMeta' | 'Meta' + + const hoverOptions = { modifiers: ['Shift'] as ModifierKeys[] } + const unhoverOptions = { modifiers: ['Control'] as ModifierKeys[] } + + const target = document.createElement('div') + target.style.width = '100px' + target.style.height = '100px' + + let modifiersDetected: ModifiersDetected = { + shift: false, + control: false, + } + + target.addEventListener('mouseover', (e) => { + modifiersDetected.shift = e.shiftKey + modifiersDetected.control = e.ctrlKey + }) + + target.addEventListener('mouseout', (e) => { + modifiersDetected.shift = e.shiftKey + modifiersDetected.control = e.ctrlKey + }) + + document.body.appendChild(target) + + await userEvent.hover(target, hoverOptions) + + expect(modifiersDetected.shift).toEqual(hoverOptions.modifiers.includes('Shift')) + expect(modifiersDetected.control).toEqual(hoverOptions.modifiers.includes('Control')) + modifiersDetected = { shift: false, control: false } + + await userEvent.unhover(target, unhoverOptions) + + expect(modifiersDetected.shift).toEqual(unhoverOptions.modifiers.includes('Shift')) + expect(modifiersDetected.control).toEqual(unhoverOptions.modifiers.includes('Control')) + }) + test('hover works with shadow root', async () => { const shadowRoot = createShadowRoot() const target = document.createElement('div') @@ -208,6 +272,7 @@ describe('userEvent.hover, userEvent.unhover', () => { }) shadowRoot.appendChild(target) + expect.poll(() => document.body.contains(target)).toBeTruthy() await userEvent.hover(target) @@ -347,11 +412,11 @@ describe.each(inputLike)('userEvent.type', (getElement) => { test('repeating without manual up works correctly', async () => { const { input, keydown, keyup, value } = createTextInput() - await userEvent.type(input, '{a>3}4') - expect(value()).toBe('aaa4') + const userEvent = _uE.setup() + await userEvent.type(input, '{a>2}4') + expect(value()).toBe('aa4') expect(keydown).toEqual([ - 'a', 'a', 'a', '4', @@ -366,6 +431,7 @@ describe.each(inputLike)('userEvent.type', (getElement) => { test('repeating with manual up works correctly', async () => { const { input, keydown, keyup, value } = createTextInput() + const userEvent = _uE.setup() await userEvent.type(input, '{a>3/}4') expect(value()).toBe('aaa4') @@ -385,6 +451,7 @@ describe.each(inputLike)('userEvent.type', (getElement) => { test('repeating with disabled up works correctly', async () => { const { input, keydown, keyup, value } = createTextInput() + const userEvent = _uE.setup() await userEvent.type(input, '{a>3}4', { skipAutoClose: true, }) @@ -406,6 +473,7 @@ describe.each(inputLike)('userEvent.type', (getElement) => { const shadowRoot = createShadowRoot() const { input, keydown, value } = createTextInput(shadowRoot) + const userEvent = _uE.setup() await userEvent.type(input, 'Hello') expect(value()).toBe('Hello') expect(keydown).toEqual([ @@ -557,6 +625,7 @@ describe('userEvent.keyboard', async () => { ]) }) + // looks like wdio doesn't support releasing Enter on its own test('should not auto release', async () => { const spyKeydown = vi.fn() const spyKeyup = vi.fn() @@ -569,8 +638,7 @@ describe('userEvent.keyboard', async () => { expect(spyKeydown).toHaveBeenCalledOnce() expect(spyKeyup).not.toHaveBeenCalled() await userEvent.keyboard('{/Enter}') - // userEvent doesn't fire any event here, but should we? - expect(spyKeyup).not.toHaveBeenCalled() + expect(spyKeyup).toHaveBeenCalled() }) test('standalone keyboard works correctly with active input', async () => { diff --git a/test/cli/fixtures/reported-tasks/1_first.test.ts b/test/cli/fixtures/reported-tasks/1_first.test.ts new file mode 100644 index 000000000000..1c52b5e3ee50 --- /dev/null +++ b/test/cli/fixtures/reported-tasks/1_first.test.ts @@ -0,0 +1,84 @@ +import { describe, expect, it } from 'vitest' + +it('runs a test', async () => { + await new Promise(r => setTimeout(r, 10)) + expect(1).toBe(1) +}) + +it('fails a test', async () => { + await new Promise(r => setTimeout(r, 10)) + expect(1).toBe(2) +}) + +it('fails multiple times', () => { + expect.soft(1).toBe(2) + expect.soft(3).toBe(3) + expect.soft(2).toBe(3) +}) + +it('skips an option test', { skip: true }) +it.skip('skips a .modifier test') + +it('todos an option test', { todo: true }) +it.todo('todos a .modifier test') + +it('retries a test', { retry: 5 }, () => { + expect(1).toBe(2) +}) + +let counter = 0 +it('retries a test with success', { retry: 5 }, () => { + expect(counter++).toBe(2) +}) + +it('repeats a test', { repeats: 5 }, () => { + expect(1).toBe(2) +}) + +describe('a group', () => { + it('runs a test in a group', () => { + expect(1).toBe(1) + }) + + it('todos an option test in a group', { todo: true }) + + describe('a nested group', () => { + it('runs a test in a nested group', () => { + expect(1).toBe(1) + }) + + it('fails a test in a nested group', () => { + expect(1).toBe(2) + }) + + it.concurrent('runs first concurrent test in a nested group', () => { + expect(1).toBe(1) + }) + + it.concurrent('runs second concurrent test in a nested group', () => { + expect(1).toBe(1) + }) + }) +}) + +describe.shuffle('shuffled group', () => { + it('runs a test in a shuffled group', () => { + expect(1).toBe(1) + }) +}) + +describe.each([1])('each group %s', (groupValue) => { + it.each([2])('each test %s', (itValue) => { + expect(groupValue + itValue).toBe(3) + }) +}) + +it('registers a metadata', (ctx) => { + ctx.task.meta.key = 'value' +}) + +declare module 'vitest' { + interface TaskMeta { + key?: string + } +} diff --git a/test/cli/test/console.test.ts b/test/cli/test/console.test.ts index a1ead6cd8289..257a3bfb33e1 100644 --- a/test/cli/test/console.test.ts +++ b/test/cli/test/console.test.ts @@ -64,21 +64,11 @@ test('can run custom pools with Vitest', async () => { expect(stackStderr).not.toMatch('❯ ') if (process.platform !== 'win32') { const root = resolve(process.cwd(), '../..') - expect(stackStderr.replace(new RegExp(root, 'g'), '').replace(/\d+:\d+/g, 'ln:cl').replace(/\.\w+\.js:/g, '..js:')).toMatchInlineSnapshot(` + const trace = stackStderr.replace(new RegExp(root, 'g'), '').replace(/\d+:\d+/g, 'ln:cl').split('\n').slice(0, 3).join('\n') + expect(trace).toMatchInlineSnapshot(` "stderr | trace.test.ts > logging to stdout Trace: trace with trace - at /test/cli/fixtures/console/trace.test.ts:ln:cl - at file:///packages/runner/dist/index.js:ln:cl - at file:///packages/runner/dist/index.js:ln:cl - at runTest (file:///packages/runner/dist/index.js:ln:cl) - at processTicksAndRejections (node:internal/process/task_queues:ln:cl) - at runSuite (file:///packages/runner/dist/index.js:ln:cl) - at runFiles (file:///packages/runner/dist/index.js:ln:cl) - at startTests (file:///packages/runner/dist/index.js:ln:cl) - at file:///packages/vitest/dist/chunks/runtime-runBaseTests..js:ln:cl - at withEnv (file:///packages/vitest/dist/chunks/runtime-runBaseTests..js:ln:cl) - - " + at /test/cli/fixtures/console/trace.test.ts:ln:cl" `) } }) diff --git a/test/cli/test/reported-tasks.test.ts b/test/cli/test/reported-tasks.test.ts new file mode 100644 index 000000000000..716d9f96b3c9 --- /dev/null +++ b/test/cli/test/reported-tasks.test.ts @@ -0,0 +1,246 @@ +import { beforeAll, expect, it } from 'vitest' +import { resolve } from 'pathe' +import type { File } from 'vitest' +import type { StateManager } from 'vitest/src/node/state.js' +import type { WorkspaceProject } from 'vitest/node' +import { runVitest } from '../../test-utils' +import type { TestCase, TestCollection, TestFile } from '../../../packages/vitest/src/node/reporters/reported-tasks' + +const now = new Date() +// const finishedFiles: File[] = [] +const collectedFiles: File[] = [] +let state: StateManager +let project: WorkspaceProject +let files: File[] +let testFile: TestFile + +beforeAll(async () => { + const { ctx } = await runVitest({ + root: resolve(__dirname, '..', 'fixtures', 'reported-tasks'), + include: ['**/*.test.ts'], + reporters: [ + 'verbose', + { + // onFinished(files) { + // finishedFiles.push(...files || []) + // }, + onCollected(files) { + collectedFiles.push(...files || []) + }, + }, + ], + includeTaskLocation: true, + logHeapUsage: true, + }) + state = ctx!.state + project = ctx!.getCoreWorkspaceProject() + files = state.getFiles() + expect(files).toHaveLength(1) + testFile = state.getReportedEntity(files[0])! as TestFile + expect(testFile).toBeDefined() +}) + +it('correctly reports a file', () => { + // suite properties not available on file + expect(testFile).not.toHaveProperty('parent') + expect(testFile).not.toHaveProperty('options') + expect(testFile).not.toHaveProperty('file') + expect(testFile).not.toHaveProperty('fullName') + expect(testFile).not.toHaveProperty('name') + + expect(testFile.type).toBe('file') + expect(testFile.task).toBe(files[0]) + expect(testFile.id).toBe(files[0].id) + expect(testFile.location).toBeUndefined() + expect(testFile.moduleId).toBe(resolve('./fixtures/reported-tasks/1_first.test.ts')) + expect(testFile.project.workspaceProject).toBe(project) + expect(testFile.children.size).toBe(14) + + const tests = [...testFile.children.tests()] + expect(tests).toHaveLength(11) + const deepTests = [...testFile.children.allTests()] + expect(deepTests).toHaveLength(19) + + const suites = [...testFile.children.suites()] + expect(suites).toHaveLength(3) + const deepSuites = [...testFile.children.allSuites()] + expect(deepSuites).toHaveLength(4) + + const diagnostic = testFile.diagnostic() + expect(diagnostic).toBeDefined() + expect(diagnostic.environmentSetupDuration).toBeGreaterThan(0) + expect(diagnostic.prepareDuration).toBeGreaterThan(0) + expect(diagnostic.collectDuration).toBeGreaterThan(0) + expect(diagnostic.duration).toBeGreaterThan(0) + // doesn't have a setup file + expect(diagnostic.setupDuration).toBe(0) +}) + +it('correctly reports a passed test', () => { + const passedTest = findTest(testFile.children, 'runs a test') + expect(passedTest.type).toBe('test') + expect(passedTest.task).toBe(files[0].tasks[0]) + expect(passedTest.name).toBe('runs a test') + expect(passedTest.fullName).toBe('runs a test') + expect(passedTest.file).toBe(testFile) + expect(passedTest.parent).toBe(testFile) + expect(passedTest.options).toEqual({ + each: undefined, + concurrent: undefined, + shuffle: undefined, + retry: undefined, + repeats: undefined, + mode: 'run', + }) + expect(passedTest.meta()).toEqual({}) + + const result = passedTest.result()! + expect(result).toBeDefined() + expect(result.state).toBe('passed') + expect(result.errors).toBeUndefined() + + const diagnostic = passedTest.diagnostic()! + expect(diagnostic).toBeDefined() + expect(diagnostic.heap).toBeGreaterThan(0) + expect(diagnostic.duration).toBeGreaterThan(0) + expect(date(new Date(diagnostic.startTime))).toBe(date(now)) + expect(diagnostic.flaky).toBe(false) + expect(diagnostic.repeatCount).toBe(0) + expect(diagnostic.repeatCount).toBe(0) +}) + +it('correctly reports failed test', () => { + const passedTest = findTest(testFile.children, 'fails a test') + expect(passedTest.type).toBe('test') + expect(passedTest.task).toBe(files[0].tasks[1]) + expect(passedTest.name).toBe('fails a test') + expect(passedTest.fullName).toBe('fails a test') + expect(passedTest.file).toBe(testFile) + expect(passedTest.parent).toBe(testFile) + expect(passedTest.options).toEqual({ + each: undefined, + concurrent: undefined, + shuffle: undefined, + retry: undefined, + repeats: undefined, + mode: 'run', + }) + expect(passedTest.meta()).toEqual({}) + + const result = passedTest.result()! + expect(result).toBeDefined() + expect(result.state).toBe('failed') + expect(result.errors).toHaveLength(1) + expect(result.errors![0]).toMatchObject({ + diff: expect.any(String), + message: 'expected 1 to be 2 // Object.is equality', + ok: false, + stack: expect.stringContaining('expected 1 to be 2 // Object.is equality'), + stacks: [ + { + column: 13, + file: resolve('./fixtures/reported-tasks/1_first.test.ts'), + line: 10, + method: '', + }, + ], + }) + + const diagnostic = passedTest.diagnostic()! + expect(diagnostic).toBeDefined() + expect(diagnostic.heap).toBeGreaterThan(0) + expect(diagnostic.duration).toBeGreaterThan(0) + expect(date(new Date(diagnostic.startTime))).toBe(date(now)) + expect(diagnostic.flaky).toBe(false) + expect(diagnostic.repeatCount).toBe(0) + expect(diagnostic.repeatCount).toBe(0) +}) + +it('correctly reports multiple failures', () => { + const testCase = findTest(testFile.children, 'fails multiple times') + const result = testCase.result()! + expect(result).toBeDefined() + expect(result.state).toBe('failed') + expect(result.errors).toHaveLength(2) + expect(result.errors![0]).toMatchObject({ + message: 'expected 1 to be 2 // Object.is equality', + }) + expect(result.errors![1]).toMatchObject({ + message: 'expected 2 to be 3 // Object.is equality', + }) +}) + +it('correctly reports test assigned options', () => { + const testOptionSkip = findTest(testFile.children, 'skips an option test') + expect(testOptionSkip.options.mode).toBe('skip') + const testModifierSkip = findTest(testFile.children, 'skips a .modifier test') + expect(testModifierSkip.options.mode).toBe('skip') + + const testOptionTodo = findTest(testFile.children, 'todos an option test') + expect(testOptionTodo.options.mode).toBe('todo') + const testModifierTodo = findTest(testFile.children, 'todos a .modifier test') + expect(testModifierTodo.options.mode).toBe('todo') +}) + +it('correctly reports retried tests', () => { + const testRetry = findTest(testFile.children, 'retries a test') + expect(testRetry.options.retry).toBe(5) + expect(testRetry.options.repeats).toBeUndefined() + expect(testRetry.result()!.state).toBe('failed') +}) + +it('correctly reports flaky tests', () => { + const testFlaky = findTest(testFile.children, 'retries a test with success') + const diagnostic = testFlaky.diagnostic()! + expect(diagnostic.flaky).toBe(true) + expect(diagnostic.retryCount).toBe(2) + expect(diagnostic.repeatCount).toBe(0) + const result = testFlaky.result()! + expect(result.state).toBe('passed') + expect(result.errors).toHaveLength(2) +}) + +it('correctly reports repeated tests', () => { + const testRepeated = findTest(testFile.children, 'repeats a test') + const diagnostic = testRepeated.diagnostic()! + expect(diagnostic.flaky).toBe(false) + expect(diagnostic.retryCount).toBe(0) + expect(diagnostic.repeatCount).toBe(5) + const result = testRepeated.result()! + expect(result.state).toBe('failed') + expect(result.errors).toHaveLength(6) +}) + +it('correctly passed down metadata', () => { + const testMetadata = findTest(testFile.children, 'registers a metadata') + const meta = testMetadata.meta() + expect(meta).toHaveProperty('key', 'value') +}) + +function date(time: Date) { + return `${time.getDate()}/${time.getMonth() + 1}/${time.getFullYear()}` +} + +function deepFind(children: TestCollection, name: string): TestCase | undefined { + for (const task of children) { + if (task.type === 'test') { + if (task.name === name) { + return task + } + } + if (task.type === 'suite') { + const result = deepFind(task.children, name) + if (result) { + return result + } + } + } +} + +function findTest(children: TestCollection, name: string): TestCase { + const testCase = deepFind(children, name) + if (!testCase) { + throw new Error(`Test "${name}" not found`) + } + return testCase +} diff --git a/test/config/test/flags.test.ts b/test/config/test/flags.test.ts index e43b8f5909df..b490142beb6c 100644 --- a/test/config/test/flags.test.ts +++ b/test/config/test/flags.test.ts @@ -19,7 +19,7 @@ it('correctly inherit from the cli', async () => { bail: 100, }) const project = ctx!.projects[0] - const config = project.getSerializableConfig() + const config = project.config expect(config).toMatchObject({ logHeapUsage: true, allowOnly: true, diff --git a/test/core/__mocks__/fs.cjs b/test/core/__mocks__/fs.cjs new file mode 100644 index 000000000000..1d1562604b44 --- /dev/null +++ b/test/core/__mocks__/fs.cjs @@ -0,0 +1,6 @@ +// we can also use `import`, but then +// every export should be explicitly defined + +const { fs } = require('memfs') + +module.exports = fs diff --git a/test/core/__mocks__/fs/promises.cjs b/test/core/__mocks__/fs/promises.cjs new file mode 100644 index 000000000000..9fa31bcf52b0 --- /dev/null +++ b/test/core/__mocks__/fs/promises.cjs @@ -0,0 +1,6 @@ +// we can also use `import`, but then +// every export should be explicitly defined + +const { fs } = require('memfs') + +module.exports = fs.promises diff --git a/test/core/package.json b/test/core/package.json index 2439a810a807..6a04ff535722 100644 --- a/test/core/package.json +++ b/test/core/package.json @@ -23,6 +23,7 @@ "axios": "^0.26.1", "debug": "^4.3.4", "immutable": "5.0.0-beta.5", + "memfs": "^4.8.2", "strip-ansi": "^7.1.0", "sweetalert2": "^11.6.16", "tinyrainbow": "^1.2.0", diff --git a/test/core/src/read-hello-world.ts b/test/core/src/read-hello-world.ts new file mode 100644 index 000000000000..5eeb77427b69 --- /dev/null +++ b/test/core/src/read-hello-world.ts @@ -0,0 +1,6 @@ +// hello-world.js +import { readFileSync } from 'node:fs' + +export function readHelloWorld(path: string) { + return readFileSync(path, 'utf-8') +} diff --git a/test/core/src/web-worker/worker-globals.ts b/test/core/src/web-worker/worker-globals.ts new file mode 100644 index 000000000000..59d6b80d4790 --- /dev/null +++ b/test/core/src/web-worker/worker-globals.ts @@ -0,0 +1,8 @@ +self.onmessage = () => { + self.postMessage({ + crypto: !!self.crypto, + caches: !!self.caches, + location: !!self.location, + origin: self.origin, + }) +} diff --git a/test/core/test/__snapshots__/jest-expect.test.ts.snap b/test/core/test/__snapshots__/jest-expect.test.ts.snap index 3e92bdac56d4..85b30fbf13c6 100644 --- a/test/core/test/__snapshots__/jest-expect.test.ts.snap +++ b/test/core/test/__snapshots__/jest-expect.test.ts.snap @@ -3,7 +3,7 @@ exports[`asymmetric matcher error 1`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringContaining "xx"", "message": "expected 'hello' to deeply equal StringContaining "xx"", } @@ -12,7 +12,7 @@ exports[`asymmetric matcher error 1`] = ` exports[`asymmetric matcher error 2`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringNotContaining "ll"", "message": "expected 'hello' to deeply equal StringNotContaining "ll"", } @@ -200,7 +200,7 @@ exports[`asymmetric matcher error 13`] = ` exports[`asymmetric matcher error 14`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringMatching /xx/", "message": "expected 'hello' to deeply equal StringMatching /xx/", } @@ -222,7 +222,7 @@ exports[`asymmetric matcher error 15`] = ` exports[`asymmetric matcher error 16`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringContaining "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", "message": "expected 'hello' to deeply equal StringContaining{…}", } @@ -231,7 +231,7 @@ exports[`asymmetric matcher error 16`] = ` exports[`asymmetric matcher error 17`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringContaining "xx"", "message": "expected error to match asymmetric matcher", } @@ -253,7 +253,7 @@ stringContainingCustom exports[`asymmetric matcher error 19`] = ` { "actual": "hello", - "diff": null, + "diff": undefined, "expected": "StringContaining "ll"", "message": "expected error not to match asymmetric matcher", } @@ -344,11 +344,8 @@ exports[`toHaveBeenNthCalledWith error 2`] = ` exports[`toMatch/toContain diff 1`] = ` { "actual": "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", - "diff": "- Expected -+ Received - -- world -+ hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", + "diff": "Expected: "world" +Received: "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello"", "expected": "world", "message": "expected 'hellohellohellohellohellohellohellohe…' to contain 'world'", } @@ -357,11 +354,8 @@ exports[`toMatch/toContain diff 1`] = ` exports[`toMatch/toContain diff 2`] = ` { "actual": "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", - "diff": "- Expected -+ Received - -- world -+ hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", + "diff": "Expected: "world" +Received: "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello"", "expected": "world", "message": "expected 'hellohellohellohellohellohellohellohe…' to match 'world'", } diff --git a/test/core/test/cli-test.test.ts b/test/core/test/cli-test.test.ts index 3afce7882b9a..6cb158bf69fa 100644 --- a/test/core/test/cli-test.test.ts +++ b/test/core/test/cli-test.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest' import { resolveConfig as viteResolveConfig } from 'vite' -import { resolveConfig } from '../../../packages/vitest/src/node/config.js' +import { resolveConfig } from '../../../packages/vitest/src/node/config/resolveConfig.js' import { createCLI, parseCLI } from '../../../packages/vitest/src/node/cli/cac.js' const vitestCli = createCLI() diff --git a/test/core/test/diff.test.ts b/test/core/test/diff.test.ts index 1cc368fb95f6..5e027808499b 100644 --- a/test/core/test/diff.test.ts +++ b/test/core/test/diff.test.ts @@ -1,10 +1,23 @@ import { expect, test, vi } from 'vitest' import stripAnsi from 'strip-ansi' import type { DiffOptions } from '@vitest/utils/diff' -import { diff, diffStringsUnified } from '@vitest/utils/diff' +import { diff, diffStringsUnified, printDiffOrStringify } from '@vitest/utils/diff' import { processError } from '@vitest/runner' import { displayDiff } from '../../../packages/vitest/src/node/error' +test('displays string diff', () => { + const stringA = 'Hello AWorld' + const stringB = 'Hello BWorld' + const console = { log: vi.fn(), error: vi.fn() } + displayDiff(printDiffOrStringify(stringA, stringB), console as any) + expect(stripAnsi(console.error.mock.calls[0][0])).toMatchInlineSnapshot(` + " + Expected: "Hello BWorld" + Received: "Hello AWorld" + " + `) +}) + test('displays object diff', () => { const objectA = { a: 1, b: 2 } const objectB = { a: 1, b: 3 } diff --git a/test/core/test/environments/jsdom.spec.ts b/test/core/test/environments/jsdom.spec.ts index c0a32408a880..95f196fa0d0a 100644 --- a/test/core/test/environments/jsdom.spec.ts +++ b/test/core/test/environments/jsdom.spec.ts @@ -71,11 +71,8 @@ test('toContain correctly handles DOM nodes', () => { } catch (err: any) { expect(stripAnsi(processError(err).diff)).toMatchInlineSnapshot(` - "- Expected - + Received - - - flex flex-col flex-row - + flex flex-col" + "Expected: "flex flex-col flex-row" + Received: "flex flex-col"" `) } @@ -85,11 +82,8 @@ test('toContain correctly handles DOM nodes', () => { } catch (err: any) { expect(stripAnsi(processError(err).diff)).toMatchInlineSnapshot(` - "- Expected - + Received - - - flex-col - + flex flex-col" + "Expected: "flex-col" + Received: "flex flex-col"" `) } }) diff --git a/test/core/test/file-path.test.ts b/test/core/test/file-path.test.ts index e0fb611f6160..022835826b5a 100644 --- a/test/core/test/file-path.test.ts +++ b/test/core/test/file-path.test.ts @@ -2,7 +2,11 @@ import { existsSync } from 'node:fs' import { describe, expect, it, vi } from 'vitest' import { isWindows, slash, toFilePath } from '../../../packages/vite-node/src/utils' -vi.mock('fs') +vi.mock('fs', () => { + return { + existsSync: vi.fn(), + } +}) describe('current url', () => { it('__filename is equal to import.meta.url', () => { diff --git a/test/core/test/jest-expect.test.ts b/test/core/test/jest-expect.test.ts index 67ed5dbe2f18..c057bb825c43 100644 --- a/test/core/test/jest-expect.test.ts +++ b/test/core/test/jest-expect.test.ts @@ -1066,11 +1066,8 @@ it('toHaveProperty error diff', () => { expect(getError(() => expect({ name: 'foo' }).toHaveProperty('name', 'bar'))).toMatchInlineSnapshot(` [ "expected { name: 'foo' } to have property "name" with value 'bar'", - "- Expected - + Received - - - bar - + foo", + "Expected: "bar" + Received: "foo"", ] `) @@ -1114,11 +1111,8 @@ it('toHaveProperty error diff', () => { expect(getError(() => expect({ parent: { name: 'foo' } }).toHaveProperty('parent.name', 'bar'))).toMatchInlineSnapshot(` [ "expected { parent: { name: 'foo' } } to have property "parent.name" with value 'bar'", - "- Expected - + Received - - - bar - + foo", + "Expected: "bar" + Received: "foo"", ] `) diff --git a/test/core/test/mock-fs.test.ts b/test/core/test/mock-fs.test.ts new file mode 100644 index 000000000000..4d834133ea93 --- /dev/null +++ b/test/core/test/mock-fs.test.ts @@ -0,0 +1,37 @@ +// hello-world.test.js +import { beforeEach, expect, it, vi } from 'vitest' +import { fs, vol } from 'memfs' +import { readHelloWorld } from '../src/read-hello-world' + +// tell vitest to use fs mock from __mocks__ folder +// this can be done in a setup file if fs should always be mocked +vi.mock('node:fs') +vi.mock('node:fs/promises') + +beforeEach(() => { + // reset the state of in-memory fs + vol.reset() +}) + +it('should return correct text', () => { + const path = '/hello-world.txt' + fs.writeFileSync(path, 'hello world') + + const text = readHelloWorld(path) + expect(text).toBe('hello world') +}) + +it('can return a value multiple times', () => { + // you can use vol.fromJSON to define several files + vol.fromJSON( + { + './dir1/hw.txt': 'hello dir1', + './dir2/hw.txt': 'hello dir2', + }, + // default cwd + '/tmp', + ) + + expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1') + expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2') +}) diff --git a/test/core/test/replace-matcher.test.ts b/test/core/test/replace-matcher.test.ts index 3c77007650b0..42a95d0f8d4d 100644 --- a/test/core/test/replace-matcher.test.ts +++ b/test/core/test/replace-matcher.test.ts @@ -1,4 +1,4 @@ -import { replaceAsymmetricMatcher } from '@vitest/utils/error' +import { replaceAsymmetricMatcher } from '@vitest/utils/diff' import { describe, expect, it } from 'vitest' describe('replace asymmetric matcher', () => { diff --git a/test/core/test/serialize.test.ts b/test/core/test/serialize.test.ts index af2721376d44..387d8de7f631 100644 --- a/test/core/test/serialize.test.ts +++ b/test/core/test/serialize.test.ts @@ -1,15 +1,15 @@ // @vitest-environment jsdom -import { serializeError } from '@vitest/utils/error' +import { serializeValue } from '@vitest/utils/error' import { describe, expect, it } from 'vitest' describe('error serialize', () => { it('works', () => { - expect(serializeError(undefined)).toEqual(undefined) - expect(serializeError(null)).toEqual(null) - expect(serializeError('hi')).toEqual('hi') + expect(serializeValue(undefined)).toEqual(undefined) + expect(serializeValue(null)).toEqual(null) + expect(serializeValue('hi')).toEqual('hi') - expect(serializeError({ + expect(serializeValue({ foo: 'hi', promise: new Promise(() => {}), fn: () => {}, @@ -35,7 +35,7 @@ describe('error serialize', () => { error.whateverArray = [error, error] error.whateverArrayClone = error.whateverArray - expect(serializeError(error)).toMatchSnapshot() + expect(serializeValue(error)).toMatchSnapshot() }) it('Should handle object with getter/setter correctly', () => { @@ -51,7 +51,7 @@ describe('error serialize', () => { }, } - expect(serializeError(user)).toEqual({ + expect(serializeValue(user)).toEqual({ name: 'John', surname: 'Smith', fullName: 'John Smith', @@ -70,7 +70,7 @@ describe('error serialize', () => { Object.defineProperty(user, 'fullName', { enumerable: false, value: 'John Smith' }) - const serialized = serializeError(user) + const serialized = serializeValue(user) expect(serialized).not.toBe(user) expect(serialized).toEqual({ name: 'John', @@ -86,7 +86,7 @@ describe('error serialize', () => { // `MessagePort`, so the serialized error object should have been recreated as plain object. const error = new Error('test') - const serialized = serializeError(error) + const serialized = serializeValue(error) expect(Object.getPrototypeOf(serialized)).toBe(null) expect(serialized).toEqual({ constructor: 'Function', @@ -114,7 +114,7 @@ describe('error serialize', () => { }, }], }) - expect(serializeError(error)).toEqual({ + expect(serializeValue(error)).toEqual({ array: [ { name: ': name cannot be accessed', @@ -131,7 +131,7 @@ describe('error serialize', () => { it('can serialize DOMException', () => { const err = new DOMException('You failed', 'InvalidStateError') - expect(serializeError(err)).toMatchObject({ + expect(serializeValue(err)).toMatchObject({ NETWORK_ERR: 19, name: 'InvalidStateError', message: 'You failed', @@ -160,7 +160,7 @@ describe('error serialize', () => { immutableRecord, }) - expect(serializeError(error)).toMatchObject({ + expect(serializeValue(error)).toMatchObject({ stack: expect.stringContaining('Error: test'), immutableList: ['foo'], immutableRecord: { foo: 'bar' }, @@ -186,7 +186,7 @@ describe('error serialize', () => { }, } - const serialized = serializeError(error) + const serialized = serializeValue(error) expect(serialized).toEqual({ key: 'value', diff --git a/test/core/test/web-worker-jsdom.test.ts b/test/core/test/web-worker-jsdom.test.ts index 5f740eadcd38..94197e66a816 100644 --- a/test/core/test/web-worker-jsdom.test.ts +++ b/test/core/test/web-worker-jsdom.test.ts @@ -3,6 +3,7 @@ import '@vitest/web-worker' import { expect, it } from 'vitest' +import GlobalsWorker from '../src/web-worker/worker-globals?worker' it('worker with invalid url throws an error', async () => { const url = import.meta.url @@ -35,3 +36,25 @@ it('throws an error on invalid path', async () => { } expect(event.error.message).toContain('Failed to load') }) + +it('returns globals on self correctly', async () => { + const worker = new GlobalsWorker() + await new Promise((resolve, reject) => { + worker.onmessage = (e) => { + try { + expect(e.data).toEqual({ + crypto: !!globalThis.crypto, + location: !!globalThis.location, + caches: !!globalThis.caches, + origin: 'http://localhost:3000', + }) + resolve() + } + catch (err) { + reject(err) + } + } + worker.onerror = reject + worker.postMessage(null) + }) +}) diff --git a/test/core/test/web-worker-node.test.ts b/test/core/test/web-worker-node.test.ts index 403bd9a7bbcd..5b4242b2c576 100644 --- a/test/core/test/web-worker-node.test.ts +++ b/test/core/test/web-worker-node.test.ts @@ -10,6 +10,7 @@ import MyObjectWorker from '../src/web-worker/objectWorker?worker' import MyEventListenerWorker from '../src/web-worker/eventListenerWorker?worker' import MySelfWorker from '../src/web-worker/selfWorker?worker' import MySharedWorker from '../src/web-worker/sharedWorker?sharedworker' +import GlobalsWorker from '../src/web-worker/worker-globals?worker' const major = Number(version.split('.')[0].slice(1)) @@ -269,3 +270,25 @@ it('doesn\'t trigger events, if closed', async () => { setTimeout(resolve, 100) }) }) + +it('returns globals on self correctly', async () => { + const worker = new GlobalsWorker() + await new Promise((resolve, reject) => { + worker.onmessage = (e) => { + try { + expect(e.data).toEqual({ + crypto: !!globalThis.crypto, + location: !!globalThis.location, + caches: !!globalThis.caches, + origin: 'http://localhost:3000', + }) + resolve() + } + catch (err) { + reject(err) + } + } + worker.onerror = reject + worker.postMessage(null) + }) +}) diff --git a/test/coverage-test/test/threshold-100.test.ts b/test/coverage-test/test/threshold-100.test.ts index 154ae4c4ac86..8c5a3e261cab 100644 --- a/test/coverage-test/test/threshold-100.test.ts +++ b/test/coverage-test/test/threshold-100.test.ts @@ -1,23 +1,44 @@ -import { assert, expect } from 'vitest' -import { getWorkerState } from 'vitest/src/utils.js' +import { assert, expect, inject } from 'vitest' import { coverageTest, normalizeURL, runVitest, test } from '../utils' +declare module 'vitest' { + export interface ProvidedContext { + coverage: { + provider: string | undefined + thresholds: { + [key: string]: any + } + } + } +} + test('{ threshold: { 100: true }}', async () => { await runVitest({ include: [normalizeURL(import.meta.url)], coverage: { thresholds: { 100: true } }, + reporters: [ + 'verbose', + { + onInit(ctx) { + ctx.getCoreWorkspaceProject().provide('coverage', { + provider: ctx.config.coverage.provider, + thresholds: (ctx.config.coverage as any).thresholds, + }) + }, + }, + ], }, { throwOnError: false }) }) coverageTest('thresholds.100 sets global thresholds to 100', () => { - const state = getWorkerState() + const coverage = inject('coverage') - assert(state.config.coverage.provider === 'v8' || state.config.coverage.provider === 'istanbul') - assert(state.config.coverage.thresholds !== undefined) + assert(coverage.provider === 'v8' || coverage.provider === 'istanbul') + assert(coverage.thresholds !== undefined) - expect(state.config.coverage.thresholds[100]).toBe(true) - expect(state.config.coverage.thresholds.lines).toBe(100) - expect(state.config.coverage.thresholds.branches).toBe(100) - expect(state.config.coverage.thresholds.functions).toBe(100) - expect(state.config.coverage.thresholds.statements).toBe(100) + expect(coverage.thresholds[100]).toBe(true) + expect(coverage.thresholds.lines).toBe(100) + expect(coverage.thresholds.branches).toBe(100) + expect(coverage.thresholds.functions).toBe(100) + expect(coverage.thresholds.statements).toBe(100) }) diff --git a/test/reporters/src/context.ts b/test/reporters/src/context.ts index e6703ebb18a2..5d43ca43bc6b 100644 --- a/test/reporters/src/context.ts +++ b/test/reporters/src/context.ts @@ -1,8 +1,9 @@ import type { ModuleGraph, ViteDevServer } from 'vite' import type { Logger } from '../../../packages/vitest/src/node/logger' -import type { Vitest } from '../../../packages/vitest/src/node' +import type { Vitest } from '../../../packages/vitest/src/node/core' +import type { File } from '../../../packages/vitest/src/public/index' import type { StateManager } from '../../../packages/vitest/src/node/state' -import type { File, ResolvedConfig } from '../../../packages/vitest/src/types' +import type { ResolvedConfig } from '../../../packages/vitest/src/node/types/config' interface Context { vitest: Vitest diff --git a/test/typescript/test-d/test.test-d.ts b/test/typescript/test-d/test.test-d.ts index 11ee3bd9e2b7..4fbc1afff10b 100644 --- a/test/typescript/test-d/test.test-d.ts +++ b/test/typescript/test-d/test.test-d.ts @@ -1,3 +1,6 @@ +/* eslint-disable ts/prefer-ts-expect-error */ +/* eslint-disable ts/ban-ts-comment */ + import { google, type sheets_v4 } from 'googleapis' import { describe, expectTypeOf, test, vi } from 'vitest' @@ -24,7 +27,6 @@ describe('test', () => { }) test('ignored error', () => { - // eslint-disable-next-line ts/prefer-ts-expect-error, ts/ban-ts-comment // @ts-ignore 45 is not a string expectTypeOf(45).toEqualTypeOf() }) diff --git a/test/ui/package.json b/test/ui/package.json index 836151a1fbeb..84839f72df34 100644 --- a/test/ui/package.json +++ b/test/ui/package.json @@ -3,6 +3,7 @@ "type": "module", "private": true, "scripts": { + "test": "GITHUB_ACTIONS=false playwright test", "test-e2e": "GITHUB_ACTIONS=false playwright test", "test-e2e-ui": "GITHUB_ACTIONS=false playwright test --ui", "test-fixtures": "vitest" diff --git a/tsconfig.base.json b/tsconfig.base.json index 7af1ddcf357e..5907b7d02575 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -19,14 +19,14 @@ "@vitest/browser": ["./packages/browser/src/node/index.ts"], "@vitest/browser/client": ["./packages/browser/src/client/client.ts"], "~/*": ["./packages/ui/client/*"], - "vitest": ["./packages/vitest/src/index.ts"], + "vitest": ["./packages/vitest/src/public/index.ts"], "vitest/globals": ["./packages/vitest/globals.d.ts"], - "vitest/node": ["./packages/vitest/src/node/index.ts"], + "vitest/node": ["./packages/vitest/src/public/node.ts"], "vitest/execute": ["./packages/vitest/src/public/execute.ts"], - "vitest/config": ["./packages/vitest/src/config.ts"], - "vitest/coverage": ["./packages/vitest/src/coverage.ts"], - "vitest/browser": ["./packages/vitest/src/browser.ts"], - "vitest/runners": ["./packages/vitest/src/runners.ts"], + "vitest/config": ["./packages/vitest/src/public/config.ts"], + "vitest/coverage": ["./packages/vitest/src/public/coverage.ts"], + "vitest/browser": ["./packages/vitest/src/public/browser.ts"], + "vitest/runners": ["./packages/vitest/src/public/runners.ts"], "vite-node": ["./packages/vite-node/src/index.ts"], "vite-node/client": ["./packages/vite-node/src/client.ts"], "vite-node/server": ["./packages/vite-node/src/server.ts"],