Repository: vitest-dev/vitest
Branch: main
Commit: 0685b6f02757
Files: 2731
Total size: 7.8 MB
Directory structure:
gitextract_qnymewnt/
├── .claude/
│ └── agents/
│ └── vitest-test-writer.md
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── docs.yml
│ │ └── feature_request.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── actions/
│ │ ├── setup-and-cache/
│ │ │ └── action.yml
│ │ └── setup-playwright/
│ │ └── action.yml
│ ├── commit-convention.md
│ ├── copilot-instructions.md
│ ├── renovate.json5
│ └── workflows/
│ ├── ci.yml
│ ├── cr.yml
│ ├── ecosystem-ci-trigger.yml
│ ├── issue-close-require.yml
│ ├── issue-labeled.yml
│ ├── lock-closed-issues.yml
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .tazerc.json
├── .vscode/
│ ├── extensions.json
│ ├── settings.json
│ └── tasks.json
├── AGENTS.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.json
├── LICENSE
├── README.md
├── SECURITY.md
├── docs/
│ ├── .vitepress/
│ │ ├── blog.data.ts
│ │ ├── components/
│ │ │ ├── Advanced.vue
│ │ │ ├── ArrowDown.vue
│ │ │ ├── BlogIndex.vue
│ │ │ ├── Box.vue
│ │ │ ├── CRoot.vue
│ │ │ ├── CourseLink.vue
│ │ │ ├── Deprecated.vue
│ │ │ ├── Experimental.vue
│ │ │ ├── FeaturesList.vue
│ │ │ ├── HomePage.vue
│ │ │ ├── ListItem.vue
│ │ │ └── Version.vue
│ │ ├── config.ts
│ │ ├── contributors.ts
│ │ ├── meta.ts
│ │ ├── scripts/
│ │ │ ├── cli-generator.ts
│ │ │ ├── fetch-avatars.ts
│ │ │ ├── pwa.ts
│ │ │ └── transformHead.ts
│ │ ├── sponsors.ts
│ │ └── theme/
│ │ ├── FeatureGrid.vue
│ │ ├── Hero.vue
│ │ ├── Home.vue
│ │ ├── Intro.vue
│ │ ├── index.ts
│ │ ├── pwa.ts
│ │ └── styles.css
│ ├── api/
│ │ ├── advanced/
│ │ │ ├── artifacts.md
│ │ │ ├── import-example.md
│ │ │ ├── metadata.md
│ │ │ ├── plugin.md
│ │ │ ├── reporters.md
│ │ │ ├── runner.md
│ │ │ ├── test-case.md
│ │ │ ├── test-collection.md
│ │ │ ├── test-module.md
│ │ │ ├── test-project.md
│ │ │ ├── test-specification.md
│ │ │ ├── test-suite.md
│ │ │ └── vitest.md
│ │ ├── assert-type.md
│ │ ├── assert.md
│ │ ├── browser/
│ │ │ ├── assertions.md
│ │ │ ├── commands.md
│ │ │ ├── context.md
│ │ │ ├── interactivity.md
│ │ │ ├── locators.md
│ │ │ ├── react.md
│ │ │ ├── svelte.md
│ │ │ └── vue.md
│ │ ├── describe.md
│ │ ├── expect-typeof.md
│ │ ├── expect.md
│ │ ├── hooks.md
│ │ ├── mock.md
│ │ ├── test.md
│ │ └── vi.md
│ ├── blog/
│ │ ├── vitest-3-2.md
│ │ ├── vitest-3.md
│ │ ├── vitest-4-1.md
│ │ └── vitest-4.md
│ ├── blog.md
│ ├── config/
│ │ ├── alias.md
│ │ ├── allowonly.md
│ │ ├── api.md
│ │ ├── attachmentsdir.md
│ │ ├── bail.md
│ │ ├── benchmark.md
│ │ ├── browser/
│ │ │ ├── api.md
│ │ │ ├── commands.md
│ │ │ ├── connecttimeout.md
│ │ │ ├── detailspanelposition.md
│ │ │ ├── enabled.md
│ │ │ ├── expect.md
│ │ │ ├── headless.md
│ │ │ ├── instances.md
│ │ │ ├── isolate.md
│ │ │ ├── locators.md
│ │ │ ├── orchestratorscripts.md
│ │ │ ├── playwright.md
│ │ │ ├── preview.md
│ │ │ ├── provider.md
│ │ │ ├── screenshotdirectory.md
│ │ │ ├── screenshotfailures.md
│ │ │ ├── testerhtmlpath.md
│ │ │ ├── trace.md
│ │ │ ├── trackunhandlederrors.md
│ │ │ ├── ui.md
│ │ │ ├── viewport.md
│ │ │ └── webdriverio.md
│ │ ├── cache.md
│ │ ├── chaiconfig.md
│ │ ├── clearmocks.md
│ │ ├── coverage.md
│ │ ├── css.md
│ │ ├── dangerouslyignoreunhandlederrors.md
│ │ ├── deps.md
│ │ ├── detectasyncleaks.md
│ │ ├── diff.md
│ │ ├── dir.md
│ │ ├── disableconsoleintercept.md
│ │ ├── env.md
│ │ ├── environment.md
│ │ ├── environmentoptions.md
│ │ ├── exclude.md
│ │ ├── execargv.md
│ │ ├── expandsnapshotdiff.md
│ │ ├── expect.md
│ │ ├── experimental.md
│ │ ├── faketimers.md
│ │ ├── fileparallelism.md
│ │ ├── forcereruntriggers.md
│ │ ├── globals.md
│ │ ├── globalsetup.md
│ │ ├── hideskippedtests.md
│ │ ├── hooktimeout.md
│ │ ├── include-source.md
│ │ ├── include.md
│ │ ├── includetasklocation.md
│ │ ├── index.md
│ │ ├── isolate.md
│ │ ├── logheapusage.md
│ │ ├── maxconcurrency.md
│ │ ├── maxworkers.md
│ │ ├── mockreset.md
│ │ ├── mode.md
│ │ ├── name.md
│ │ ├── onconsolelog.md
│ │ ├── onstacktrace.md
│ │ ├── onunhandlederror.md
│ │ ├── open.md
│ │ ├── outputfile.md
│ │ ├── passwithnotests.md
│ │ ├── pool.md
│ │ ├── printconsoletrace.md
│ │ ├── projects.md
│ │ ├── provide.md
│ │ ├── reporters.md
│ │ ├── resolvesnapshotpath.md
│ │ ├── restoremocks.md
│ │ ├── retry.md
│ │ ├── root.md
│ │ ├── runner.md
│ │ ├── sequence.md
│ │ ├── server.md
│ │ ├── setupfiles.md
│ │ ├── silent.md
│ │ ├── slowtestthreshold.md
│ │ ├── snapshotenvironment.md
│ │ ├── snapshotformat.md
│ │ ├── snapshotserializers.md
│ │ ├── stricttags.md
│ │ ├── tags.md
│ │ ├── teardowntimeout.md
│ │ ├── testnamepattern.md
│ │ ├── testtimeout.md
│ │ ├── typecheck.md
│ │ ├── ui.md
│ │ ├── unstubenvs.md
│ │ ├── unstubglobals.md
│ │ ├── update.md
│ │ ├── vmmemorylimit.md
│ │ ├── watch.md
│ │ └── watchtriggerpatterns.md
│ ├── guide/
│ │ ├── advanced/
│ │ │ ├── index.md
│ │ │ ├── pool.md
│ │ │ ├── reporters.md
│ │ │ └── tests.md
│ │ ├── browser/
│ │ │ ├── component-testing.md
│ │ │ ├── index.md
│ │ │ ├── multiple-setups.md
│ │ │ ├── trace-view.md
│ │ │ ├── visual-regression-testing.md
│ │ │ └── why.md
│ │ ├── cli-generated.md
│ │ ├── cli.md
│ │ ├── common-errors.md
│ │ ├── comparisons.md
│ │ ├── coverage.md
│ │ ├── debugging.md
│ │ ├── environment.md
│ │ ├── examples/
│ │ │ ├── projects-workspace.md
│ │ │ └── promise-done.md
│ │ ├── extending-matchers.md
│ │ ├── features.md
│ │ ├── filtering.md
│ │ ├── ide.md
│ │ ├── improving-performance.md
│ │ ├── in-source.md
│ │ ├── index.md
│ │ ├── lifecycle.md
│ │ ├── migration.md
│ │ ├── mocking/
│ │ │ ├── classes.md
│ │ │ ├── dates.md
│ │ │ ├── file-system.md
│ │ │ ├── functions.md
│ │ │ ├── globals.md
│ │ │ ├── modules.md
│ │ │ ├── requests.md
│ │ │ └── timers.md
│ │ ├── mocking.md
│ │ ├── open-telemetry.md
│ │ ├── parallelism.md
│ │ ├── profiling-test-performance.md
│ │ ├── projects.md
│ │ ├── recipes.md
│ │ ├── reporters.md
│ │ ├── snapshot.md
│ │ ├── test-annotations.md
│ │ ├── test-context.md
│ │ ├── test-tags.md
│ │ ├── testing-types.md
│ │ ├── ui.md
│ │ ├── using-plugins.md
│ │ └── why.md
│ ├── index.md
│ ├── package.json
│ ├── public/
│ │ ├── _headers
│ │ ├── new-reporter.webm
│ │ └── robots.txt
│ ├── pwa-assets.config.ts
│ ├── team.md
│ ├── todo.md
│ ├── tsconfig.json
│ └── vite.config.ts
├── eslint.config.js
├── examples/
│ ├── basic/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── basic.ts
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ └── suite.test.ts.snap
│ │ │ ├── basic.test.ts
│ │ │ └── suite.test.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── fastify/
│ │ ├── mockData.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app.ts
│ │ │ └── index.ts
│ │ └── test/
│ │ └── app.test.ts
│ ├── in-source-test/
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── lit/
│ │ ├── .gitignore
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── my-button.ts
│ │ ├── test/
│ │ │ └── basic.test.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── opentelemetry/
│ │ ├── README.md
│ │ ├── docker-compose.yaml
│ │ ├── jaeger-config.yml
│ │ ├── otel-browser.js
│ │ ├── otel.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── basic.test.ts
│ │ │ ├── basic.ts
│ │ │ └── other.test.ts
│ │ └── vite.config.ts
│ ├── profiling/
│ │ ├── global-setup.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── prime-number.ts
│ │ ├── test/
│ │ │ └── prime-number.test.ts
│ │ └── vitest.config.ts
│ ├── projects/
│ │ ├── package.json
│ │ ├── packages/
│ │ │ ├── client/
│ │ │ │ ├── components/
│ │ │ │ │ └── Link.tsx
│ │ │ │ ├── test/
│ │ │ │ │ └── basic.test.tsx
│ │ │ │ ├── tsconfig.json
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.setup.ts
│ │ │ └── server/
│ │ │ ├── mockData.ts
│ │ │ ├── src/
│ │ │ │ ├── app.ts
│ │ │ │ └── index.ts
│ │ │ └── test/
│ │ │ └── app.test.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ └── typecheck/
│ ├── package.json
│ ├── test/
│ │ ├── normal.test.ts
│ │ └── type.test-d.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── netlify.toml
├── package.json
├── packages/
│ ├── browser/
│ │ ├── README.md
│ │ ├── aria-role.d.ts
│ │ ├── context.d.ts
│ │ ├── context.js
│ │ ├── dummy.js
│ │ ├── jest-dom.d.ts
│ │ ├── matchers.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── scripts/
│ │ │ └── build-client.js
│ │ ├── src/
│ │ │ ├── client/
│ │ │ │ ├── channel.ts
│ │ │ │ ├── client.ts
│ │ │ │ ├── orchestrator.html
│ │ │ │ ├── orchestrator.ts
│ │ │ │ ├── public/
│ │ │ │ │ ├── error-catcher.js
│ │ │ │ │ └── esm-client-injector.js
│ │ │ │ ├── tester/
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── dialog.ts
│ │ │ │ │ ├── expect/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── toBeChecked.ts
│ │ │ │ │ │ ├── toBeEmptyDOMElement.ts
│ │ │ │ │ │ ├── toBeEnabled.ts
│ │ │ │ │ │ ├── toBeInTheDocument.ts
│ │ │ │ │ │ ├── toBeInViewport.ts
│ │ │ │ │ │ ├── toBeInvalid.ts
│ │ │ │ │ │ ├── toBePartiallyChecked.ts
│ │ │ │ │ │ ├── toBeRequired.ts
│ │ │ │ │ │ ├── toBeVisible.ts
│ │ │ │ │ │ ├── toContainElement.ts
│ │ │ │ │ │ ├── toContainHTML.ts
│ │ │ │ │ │ ├── toHaveAccessibleDescription.ts
│ │ │ │ │ │ ├── toHaveAccessibleErrorMessage.ts
│ │ │ │ │ │ ├── toHaveAccessibleName.ts
│ │ │ │ │ │ ├── toHaveAttribute.ts
│ │ │ │ │ │ ├── toHaveClass.ts
│ │ │ │ │ │ ├── toHaveDisplayValue.ts
│ │ │ │ │ │ ├── toHaveFocus.ts
│ │ │ │ │ │ ├── toHaveFormValues.ts
│ │ │ │ │ │ ├── toHaveRole.ts
│ │ │ │ │ │ ├── toHaveSelection.ts
│ │ │ │ │ │ ├── toHaveStyle.ts
│ │ │ │ │ │ ├── toHaveTextContent.ts
│ │ │ │ │ │ ├── toHaveValue.ts
│ │ │ │ │ │ ├── toMatchScreenshot.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── expect-element.ts
│ │ │ │ │ ├── locators/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── logger.ts
│ │ │ │ │ ├── mocker-interceptor.ts
│ │ │ │ │ ├── mocker.ts
│ │ │ │ │ ├── rpc.ts
│ │ │ │ │ ├── runner.ts
│ │ │ │ │ ├── snapshot.ts
│ │ │ │ │ ├── state.ts
│ │ │ │ │ ├── tester-utils.ts
│ │ │ │ │ ├── tester.html
│ │ │ │ │ └── tester.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ ├── ui.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── node/
│ │ │ │ ├── cdp.ts
│ │ │ │ ├── commands/
│ │ │ │ │ ├── fs.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── screenshot.ts
│ │ │ │ │ ├── screenshotMatcher/
│ │ │ │ │ │ ├── codecs/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── png.ts
│ │ │ │ │ │ ├── comparators/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── pixelmatch.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ └── trace.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── middlewares/
│ │ │ │ │ ├── orchestratorMiddleware.ts
│ │ │ │ │ ├── testerMiddleware.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── plugin.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ └── pluginContext.ts
│ │ │ │ ├── project.ts
│ │ │ │ ├── projectParent.ts
│ │ │ │ ├── rpc.ts
│ │ │ │ ├── serverOrchestrator.ts
│ │ │ │ ├── serverTester.ts
│ │ │ │ ├── state.ts
│ │ │ │ └── utils.ts
│ │ │ ├── shared/
│ │ │ │ └── screenshotMatcher/
│ │ │ │ └── types.ts
│ │ │ └── types.ts
│ │ ├── tsconfig.json
│ │ └── utils.d.ts
│ ├── browser-playwright/
│ │ ├── README.md
│ │ ├── context.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── commands/
│ │ │ │ ├── clear.ts
│ │ │ │ ├── click.ts
│ │ │ │ ├── dragAndDrop.ts
│ │ │ │ ├── fill.ts
│ │ │ │ ├── hover.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── screenshot.ts
│ │ │ │ ├── select.ts
│ │ │ │ ├── tab.ts
│ │ │ │ ├── trace.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── upload.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── wheel.ts
│ │ │ ├── constants.ts
│ │ │ ├── index.ts
│ │ │ ├── locators.ts
│ │ │ └── playwright.ts
│ │ └── tsconfig.json
│ ├── browser-preview/
│ │ ├── README.md
│ │ ├── context.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── constants.ts
│ │ │ ├── index.ts
│ │ │ ├── locators.ts
│ │ │ └── preview.ts
│ │ └── tsconfig.json
│ ├── browser-webdriverio/
│ │ ├── README.md
│ │ ├── context.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── commands/
│ │ │ │ ├── clear.ts
│ │ │ │ ├── click.ts
│ │ │ │ ├── dragAndDrop.ts
│ │ │ │ ├── fill.ts
│ │ │ │ ├── hover.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── screenshot.ts
│ │ │ │ ├── select.ts
│ │ │ │ ├── tab.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── upload.ts
│ │ │ │ ├── utils.ts
│ │ │ │ ├── viewport.ts
│ │ │ │ └── wheel.ts
│ │ │ ├── constants.ts
│ │ │ ├── index.ts
│ │ │ ├── locators.ts
│ │ │ └── webdriverio.ts
│ │ └── tsconfig.json
│ ├── coverage-istanbul/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── constants.ts
│ │ │ ├── index.ts
│ │ │ └── provider.ts
│ │ └── tsconfig.json
│ ├── coverage-v8/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── browser.ts
│ │ │ ├── index.ts
│ │ │ ├── load-provider.ts
│ │ │ └── provider.ts
│ │ └── tsconfig.json
│ ├── expect/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── chai-style-assertions.ts
│ │ │ ├── constants.ts
│ │ │ ├── custom-matchers.ts
│ │ │ ├── index.ts
│ │ │ ├── jest-asymmetric-matchers.ts
│ │ │ ├── jest-expect.ts
│ │ │ ├── jest-extend.ts
│ │ │ ├── jest-matcher-utils.ts
│ │ │ ├── jest-utils.ts
│ │ │ ├── state.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ └── tsconfig.json
│ ├── mocker/
│ │ ├── EXPORTS.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── automocker.ts
│ │ │ ├── browser/
│ │ │ │ ├── auto-register.ts
│ │ │ │ ├── hints.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── interceptor-msw.ts
│ │ │ │ ├── interceptor-native.ts
│ │ │ │ ├── interceptor.ts
│ │ │ │ ├── mocker.ts
│ │ │ │ ├── register.ts
│ │ │ │ └── utils.ts
│ │ │ ├── index.ts
│ │ │ ├── node/
│ │ │ │ ├── automock.ts
│ │ │ │ ├── automockPlugin.ts
│ │ │ │ ├── dynamicImportPlugin.ts
│ │ │ │ ├── esmWalker.ts
│ │ │ │ ├── hoistMocks.ts
│ │ │ │ ├── hoistMocksPlugin.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── interceptorPlugin.ts
│ │ │ │ ├── mockerPlugin.ts
│ │ │ │ ├── parsers.ts
│ │ │ │ ├── redirect.ts
│ │ │ │ ├── resolver.ts
│ │ │ │ └── transforms.ts
│ │ │ ├── registry.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ └── tsconfig.json
│ ├── pretty-format/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── collections.ts
│ │ │ ├── index.ts
│ │ │ ├── plugins/
│ │ │ │ ├── AsymmetricMatcher.ts
│ │ │ │ ├── DOMCollection.ts
│ │ │ │ ├── DOMElement.ts
│ │ │ │ ├── Immutable.ts
│ │ │ │ ├── ReactElement.ts
│ │ │ │ ├── ReactTestComponent.ts
│ │ │ │ └── lib/
│ │ │ │ ├── escapeHTML.ts
│ │ │ │ └── markup.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── runner/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── artifact.ts
│ │ │ ├── collect.ts
│ │ │ ├── context.ts
│ │ │ ├── errors.ts
│ │ │ ├── fixture.ts
│ │ │ ├── hooks.ts
│ │ │ ├── index.ts
│ │ │ ├── map.ts
│ │ │ ├── run.ts
│ │ │ ├── setup.ts
│ │ │ ├── suite.ts
│ │ │ ├── test-state.ts
│ │ │ ├── types/
│ │ │ │ ├── runner.ts
│ │ │ │ └── tasks.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ ├── chain.ts
│ │ │ ├── collect.ts
│ │ │ ├── index.ts
│ │ │ ├── limit-concurrency.ts
│ │ │ ├── suite.ts
│ │ │ ├── tags.ts
│ │ │ └── tasks.ts
│ │ ├── tsconfig.json
│ │ ├── types.d.ts
│ │ └── utils.d.ts
│ ├── snapshot/
│ │ ├── README.md
│ │ ├── environment.d.ts
│ │ ├── manager.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── client.ts
│ │ │ ├── env/
│ │ │ │ └── node.ts
│ │ │ ├── environment.ts
│ │ │ ├── index.ts
│ │ │ ├── manager.ts
│ │ │ ├── port/
│ │ │ │ ├── inlineSnapshot.ts
│ │ │ │ ├── mockSerializer.ts
│ │ │ │ ├── plugins.ts
│ │ │ │ ├── rawSnapshot.ts
│ │ │ │ ├── state.ts
│ │ │ │ └── utils.ts
│ │ │ └── types/
│ │ │ ├── environment.ts
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── spy/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── ui/
│ │ ├── CONTRIBUTING.md
│ │ ├── README.md
│ │ ├── browser.dev.js
│ │ ├── client/
│ │ │ ├── App.vue
│ │ │ ├── components/
│ │ │ │ ├── AnnotationAttachmentImage.vue
│ │ │ │ ├── Badge.vue
│ │ │ │ ├── BrowserIframe.vue
│ │ │ │ ├── ClosedDetailsHeader.vue
│ │ │ │ ├── CodeMirrorContainer.vue
│ │ │ │ ├── ConnectionOverlay.vue
│ │ │ │ ├── Coverage.vue
│ │ │ │ ├── Dashboard.vue
│ │ │ │ ├── DetailsHeaderButtons.vue
│ │ │ │ ├── FailureScreenshot.vue
│ │ │ │ ├── FileDetails.vue
│ │ │ │ ├── FilterStatus.vue
│ │ │ │ ├── IconAction.vue
│ │ │ │ ├── IconButton.vue
│ │ │ │ ├── Modal.vue
│ │ │ │ ├── ModuleGraphImportBreakdown.vue
│ │ │ │ ├── ModuleTransformResultView.vue
│ │ │ │ ├── Navigation.vue
│ │ │ │ ├── ProgressBar.vue
│ │ │ │ ├── ResultsPanel.vue
│ │ │ │ ├── StatusIcon.vue
│ │ │ │ ├── artifacts/
│ │ │ │ │ ├── ArtifactTemplate.vue
│ │ │ │ │ ├── Artifacts.vue
│ │ │ │ │ └── visual-regression/
│ │ │ │ │ ├── SmallTabs.spec.ts
│ │ │ │ │ ├── SmallTabs.vue
│ │ │ │ │ ├── SmallTabsPane.vue
│ │ │ │ │ ├── VisualRegression.spec.ts
│ │ │ │ │ ├── VisualRegression.vue
│ │ │ │ │ ├── VisualRegressionImage.vue
│ │ │ │ │ ├── VisualRegressionImageContainer.vue
│ │ │ │ │ ├── VisualRegressionSlider.spec.ts
│ │ │ │ │ └── VisualRegressionSlider.vue
│ │ │ │ ├── dashboard/
│ │ │ │ │ ├── DashboardEntry.spec.ts
│ │ │ │ │ ├── DashboardEntry.vue
│ │ │ │ │ ├── ErrorEntry.vue
│ │ │ │ │ ├── TestFilesEntry.vue
│ │ │ │ │ ├── TestsEntry.vue
│ │ │ │ │ └── TestsFilesContainer.vue
│ │ │ │ ├── explorer/
│ │ │ │ │ ├── Explorer.vue
│ │ │ │ │ └── ExplorerItem.vue
│ │ │ │ └── views/
│ │ │ │ ├── ScreenshotError.vue
│ │ │ │ ├── ViewConsoleOutput.vue
│ │ │ │ ├── ViewConsoleOutputEntry.spec.ts
│ │ │ │ ├── ViewConsoleOutputEntry.vue
│ │ │ │ ├── ViewEditor.vue
│ │ │ │ ├── ViewModuleGraph.vue
│ │ │ │ ├── ViewReport.spec.ts
│ │ │ │ ├── ViewReport.vue
│ │ │ │ ├── ViewReportError.vue
│ │ │ │ └── ViewTestReport.vue
│ │ │ ├── composables/
│ │ │ │ ├── api.ts
│ │ │ │ ├── attachments.ts
│ │ │ │ ├── browser.ts
│ │ │ │ ├── client/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── state.ts
│ │ │ │ │ └── static.ts
│ │ │ │ ├── codemirror.ts
│ │ │ │ ├── dark.ts
│ │ │ │ ├── error.ts
│ │ │ │ ├── explorer/
│ │ │ │ │ ├── collapse.ts
│ │ │ │ │ ├── collector.ts
│ │ │ │ │ ├── expand.ts
│ │ │ │ │ ├── filter.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── search.ts
│ │ │ │ │ ├── state.ts
│ │ │ │ │ ├── tree.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── location.ts
│ │ │ │ ├── module-graph.ts
│ │ │ │ ├── navigation.ts
│ │ │ │ ├── params.ts
│ │ │ │ └── small-tabs.ts
│ │ │ ├── constants.ts
│ │ │ ├── global-setup.ts
│ │ │ ├── main.ts
│ │ │ ├── pages/
│ │ │ │ └── index.vue
│ │ │ ├── shim.d.ts
│ │ │ ├── styles/
│ │ │ │ └── main.css
│ │ │ ├── test.ts
│ │ │ └── utils/
│ │ │ ├── escape.ts
│ │ │ └── task.ts
│ │ ├── explorer.md
│ │ ├── index.html
│ │ ├── node/
│ │ │ ├── index.ts
│ │ │ ├── reporter.ts
│ │ │ └── tsconfig.json
│ │ ├── package.json
│ │ ├── reporter.d.ts
│ │ ├── rollup.config.js
│ │ ├── shim.d.ts
│ │ ├── tsconfig.json
│ │ ├── types.ts
│ │ ├── vite.config.ts
│ │ └── vitest.config.ts
│ ├── utils/
│ │ ├── README.md
│ │ ├── diff.d.ts
│ │ ├── error.d.ts
│ │ ├── helpers.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── source-map.ts
│ │ ├── src/
│ │ │ ├── constants.ts
│ │ │ ├── diff/
│ │ │ │ ├── cleanupSemantic.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── diffLines.ts
│ │ │ │ ├── diffStrings.ts
│ │ │ │ ├── getAlignedDiffs.ts
│ │ │ │ ├── getType.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── joinAlignedDiffs.ts
│ │ │ │ ├── normalizeDiffOptions.ts
│ │ │ │ ├── printDiffs.ts
│ │ │ │ └── types.ts
│ │ │ ├── display.ts
│ │ │ ├── error.ts
│ │ │ ├── helpers.ts
│ │ │ ├── index.ts
│ │ │ ├── nanoid.ts
│ │ │ ├── offset.ts
│ │ │ ├── random.ts
│ │ │ ├── resolver.ts
│ │ │ ├── serialize.ts
│ │ │ ├── source-map/
│ │ │ │ └── node.ts
│ │ │ ├── source-map.ts
│ │ │ ├── timers.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── vitest/
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── browser/
│ │ │ ├── context.d.ts
│ │ │ └── context.js
│ │ ├── config.d.ts
│ │ ├── coverage.d.ts
│ │ ├── environments.d.ts
│ │ ├── globals.d.ts
│ │ ├── import-meta.d.ts
│ │ ├── importMeta.d.ts
│ │ ├── index.cjs
│ │ ├── index.d.cts
│ │ ├── jsdom.d.ts
│ │ ├── mocker.d.ts
│ │ ├── node.d.ts
│ │ ├── optional-types.d.ts
│ │ ├── package.json
│ │ ├── reporters.d.ts
│ │ ├── rollup.config.js
│ │ ├── runners.d.ts
│ │ ├── snapshot.d.ts
│ │ ├── src/
│ │ │ ├── api/
│ │ │ │ ├── check.ts
│ │ │ │ ├── setup.ts
│ │ │ │ └── types.ts
│ │ │ ├── constants.ts
│ │ │ ├── create/
│ │ │ │ └── browser/
│ │ │ │ ├── creator.ts
│ │ │ │ └── examples.ts
│ │ │ ├── defaults.ts
│ │ │ ├── integrations/
│ │ │ │ ├── chai/
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── poll.ts
│ │ │ │ │ └── setup.ts
│ │ │ │ ├── coverage.ts
│ │ │ │ ├── css/
│ │ │ │ │ └── css-modules.ts
│ │ │ │ ├── env/
│ │ │ │ │ ├── edge-runtime.ts
│ │ │ │ │ ├── happy-dom.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── jsdom-keys.ts
│ │ │ │ │ ├── jsdom.ts
│ │ │ │ │ ├── loader.ts
│ │ │ │ │ ├── node.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── globals.ts
│ │ │ │ ├── inject.ts
│ │ │ │ ├── mock/
│ │ │ │ │ ├── date.ts
│ │ │ │ │ └── timers.ts
│ │ │ │ ├── snapshot/
│ │ │ │ │ ├── chai.ts
│ │ │ │ │ └── environments/
│ │ │ │ │ ├── node.ts
│ │ │ │ │ └── resolveSnapshotEnvironment.ts
│ │ │ │ ├── spy.ts
│ │ │ │ ├── vi.ts
│ │ │ │ └── wait.ts
│ │ │ ├── node/
│ │ │ │ ├── ast-collect.ts
│ │ │ │ ├── browser/
│ │ │ │ │ └── sessions.ts
│ │ │ │ ├── cache/
│ │ │ │ │ ├── files.ts
│ │ │ │ │ ├── fsModuleCache.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── results.ts
│ │ │ │ ├── cli/
│ │ │ │ │ ├── cac.ts
│ │ │ │ │ ├── cli-api.ts
│ │ │ │ │ ├── cli-config.ts
│ │ │ │ │ ├── completions.ts
│ │ │ │ │ └── filter.ts
│ │ │ │ ├── cli.ts
│ │ │ │ ├── config/
│ │ │ │ │ ├── resolveConfig.ts
│ │ │ │ │ └── serializeConfig.ts
│ │ │ │ ├── core.ts
│ │ │ │ ├── coverage.ts
│ │ │ │ ├── create.ts
│ │ │ │ ├── environments/
│ │ │ │ │ ├── fetchModule.ts
│ │ │ │ │ ├── normalizeUrl.ts
│ │ │ │ │ └── serverRunner.ts
│ │ │ │ ├── errors.ts
│ │ │ │ ├── git.ts
│ │ │ │ ├── globalSetup.ts
│ │ │ │ ├── hash.ts
│ │ │ │ ├── logger.ts
│ │ │ │ ├── module-diagnostic.ts
│ │ │ │ ├── packageInstaller.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ ├── coverageTransform.ts
│ │ │ │ │ ├── cssEnabler.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── metaEnvReplacer.ts
│ │ │ │ │ ├── mocks.ts
│ │ │ │ │ ├── normalizeURL.ts
│ │ │ │ │ ├── optimizer.ts
│ │ │ │ │ ├── publicConfig.ts
│ │ │ │ │ ├── runnerTransform.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ ├── vitestResolver.ts
│ │ │ │ │ └── workspace.ts
│ │ │ │ ├── pool.ts
│ │ │ │ ├── pools/
│ │ │ │ │ ├── browser.ts
│ │ │ │ │ ├── pool.ts
│ │ │ │ │ ├── poolRunner.ts
│ │ │ │ │ ├── rpc.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── workers/
│ │ │ │ │ ├── forksWorker.ts
│ │ │ │ │ ├── threadsWorker.ts
│ │ │ │ │ ├── typecheckWorker.ts
│ │ │ │ │ ├── vmForksWorker.ts
│ │ │ │ │ └── vmThreadsWorker.ts
│ │ │ │ ├── printError.ts
│ │ │ │ ├── project.ts
│ │ │ │ ├── projects/
│ │ │ │ │ └── resolveProjects.ts
│ │ │ │ ├── reporters/
│ │ │ │ │ ├── agent.ts
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── benchmark/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── json-formatter.ts
│ │ │ │ │ │ ├── reporter.ts
│ │ │ │ │ │ ├── tableRender.ts
│ │ │ │ │ │ └── verbose.ts
│ │ │ │ │ ├── blob.ts
│ │ │ │ │ ├── default.ts
│ │ │ │ │ ├── dot.ts
│ │ │ │ │ ├── github-actions.ts
│ │ │ │ │ ├── hanging-process.ts
│ │ │ │ │ ├── html.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── json.ts
│ │ │ │ │ ├── junit.ts
│ │ │ │ │ ├── renderers/
│ │ │ │ │ │ ├── figures.ts
│ │ │ │ │ │ ├── indented-logger.ts
│ │ │ │ │ │ ├── utils.ts
│ │ │ │ │ │ └── windowedRenderer.ts
│ │ │ │ │ ├── reported-tasks.ts
│ │ │ │ │ ├── summary.ts
│ │ │ │ │ ├── tap-flat.ts
│ │ │ │ │ ├── tap.ts
│ │ │ │ │ ├── tree.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ └── verbose.ts
│ │ │ │ ├── resolver.ts
│ │ │ │ ├── sequencers/
│ │ │ │ │ ├── BaseSequencer.ts
│ │ │ │ │ ├── RandomSequencer.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── specifications.ts
│ │ │ │ ├── state.ts
│ │ │ │ ├── stdin.ts
│ │ │ │ ├── tags.ts
│ │ │ │ ├── test-run.ts
│ │ │ │ ├── test-specification.ts
│ │ │ │ ├── types/
│ │ │ │ │ ├── benchmark.ts
│ │ │ │ │ ├── browser.ts
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── coverage.ts
│ │ │ │ │ ├── plugin.ts
│ │ │ │ │ ├── reporter.ts
│ │ │ │ │ ├── tests.ts
│ │ │ │ │ ├── vite.ts
│ │ │ │ │ └── worker.ts
│ │ │ │ ├── vite.ts
│ │ │ │ ├── viteLogger.ts
│ │ │ │ ├── watch-filter.ts
│ │ │ │ └── watcher.ts
│ │ │ ├── paths.ts
│ │ │ ├── public/
│ │ │ │ ├── browser.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── coverage.ts
│ │ │ │ ├── environments.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── node.ts
│ │ │ │ ├── reporters.ts
│ │ │ │ ├── runners.ts
│ │ │ │ ├── runtime.ts
│ │ │ │ ├── snapshot.ts
│ │ │ │ ├── suite.ts
│ │ │ │ └── worker.ts
│ │ │ ├── runtime/
│ │ │ │ ├── benchmark.ts
│ │ │ │ ├── cleanup.ts
│ │ │ │ ├── config.ts
│ │ │ │ ├── console.ts
│ │ │ │ ├── detect-async-leaks.ts
│ │ │ │ ├── external-executor.ts
│ │ │ │ ├── inspector.ts
│ │ │ │ ├── listeners.ts
│ │ │ │ ├── moduleRunner/
│ │ │ │ │ ├── bareModuleMocker.ts
│ │ │ │ │ ├── cachedResolver.ts
│ │ │ │ │ ├── errorCatcher.ts
│ │ │ │ │ ├── evaluatedModules.ts
│ │ │ │ │ ├── moduleDebug.ts
│ │ │ │ │ ├── moduleEvaluator.ts
│ │ │ │ │ ├── moduleMocker.ts
│ │ │ │ │ ├── moduleRunner.ts
│ │ │ │ │ ├── moduleTransport.ts
│ │ │ │ │ ├── nativeModuleMocker.ts
│ │ │ │ │ ├── startVitestModuleRunner.ts
│ │ │ │ │ ├── testModuleRunner.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── nodejsWorkerLoader.ts
│ │ │ │ ├── rpc.ts
│ │ │ │ ├── runBaseTests.ts
│ │ │ │ ├── runVmTests.ts
│ │ │ │ ├── runners/
│ │ │ │ │ ├── benchmark.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── test.ts
│ │ │ │ ├── setup-common.ts
│ │ │ │ ├── setup-node.ts
│ │ │ │ ├── types/
│ │ │ │ │ ├── benchmark.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── utils.ts
│ │ │ │ ├── vm/
│ │ │ │ │ ├── commonjs-executor.ts
│ │ │ │ │ ├── esm-executor.ts
│ │ │ │ │ ├── file-map.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ └── vite-executor.ts
│ │ │ │ ├── worker.ts
│ │ │ │ └── workers/
│ │ │ │ ├── base.ts
│ │ │ │ ├── forks.ts
│ │ │ │ ├── init-forks.ts
│ │ │ │ ├── init-threads.ts
│ │ │ │ ├── init.ts
│ │ │ │ ├── native.ts
│ │ │ │ ├── threads.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── vm.ts
│ │ │ │ ├── vmForks.ts
│ │ │ │ └── vmThreads.ts
│ │ │ ├── shims.dev.d.ts
│ │ │ ├── typecheck/
│ │ │ │ ├── assertType.ts
│ │ │ │ ├── collect.ts
│ │ │ │ ├── expectTypeOf.ts
│ │ │ │ ├── parse.ts
│ │ │ │ ├── typechecker.ts
│ │ │ │ └── types.ts
│ │ │ ├── types/
│ │ │ │ ├── browser.ts
│ │ │ │ ├── environment.ts
│ │ │ │ ├── general.ts
│ │ │ │ ├── global.ts
│ │ │ │ ├── happy-dom-options.ts
│ │ │ │ ├── jsdom-options.ts
│ │ │ │ ├── mocker.ts
│ │ │ │ ├── module-locations.ts
│ │ │ │ ├── rpc.ts
│ │ │ │ ├── ui.ts
│ │ │ │ └── worker.ts
│ │ │ └── utils/
│ │ │ ├── base.ts
│ │ │ ├── colors.ts
│ │ │ ├── config-helpers.ts
│ │ │ ├── coverage.ts
│ │ │ ├── debugger.ts
│ │ │ ├── env.ts
│ │ │ ├── environments.ts
│ │ │ ├── graph.ts
│ │ │ ├── memory-limit.ts
│ │ │ ├── modules.ts
│ │ │ ├── nativeModuleRunner.ts
│ │ │ ├── serialization.ts
│ │ │ ├── source-map.ts
│ │ │ ├── tasks.ts
│ │ │ ├── test-helpers.ts
│ │ │ ├── timers.ts
│ │ │ ├── traces.ts
│ │ │ └── workers.ts
│ │ ├── suite.d.ts
│ │ ├── suppress-warnings.cjs
│ │ ├── tsconfig.json
│ │ ├── vitest.mjs
│ │ └── worker.d.ts
│ ├── web-worker/
│ │ ├── README.md
│ │ ├── index.d.ts
│ │ ├── package.json
│ │ ├── pure.d.ts
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── pure.ts
│ │ │ ├── runner.ts
│ │ │ ├── shared-worker.ts
│ │ │ ├── types.ts
│ │ │ ├── utils.ts
│ │ │ └── worker.ts
│ │ └── tsconfig.json
│ └── ws-client/
│ ├── package.json
│ ├── rollup.config.js
│ ├── src/
│ │ ├── index.ts
│ │ └── state.ts
│ └── tsconfig.json
├── patches/
│ ├── @sinonjs__fake-timers@15.0.0.patch
│ ├── acorn@8.11.3.patch
│ ├── cac@6.7.14.patch
│ ├── istanbul-lib-instrument.patch
│ └── istanbul-lib-source-maps.patch
├── pnpm-workspace.yaml
├── scripts/
│ ├── build-utils.js
│ ├── explain-types.ts
│ ├── publish-ci.ts
│ ├── release.ts
│ └── update-contributors.ts
├── shims.d.ts
├── test/
│ ├── README.md
│ ├── browser/
│ │ ├── README.md
│ │ ├── bundled-lib/
│ │ │ ├── package.json
│ │ │ └── src/
│ │ │ ├── a.js
│ │ │ ├── b.js
│ │ │ ├── index.d.ts
│ │ │ └── index.js
│ │ ├── cjs-lib/
│ │ │ ├── index.js
│ │ │ ├── lib.d.ts
│ │ │ ├── lib.mjs
│ │ │ └── package.json
│ │ ├── custom-diff-config.ts
│ │ ├── custom-snapshot-env.ts
│ │ ├── custom-tester.html
│ │ ├── deps/
│ │ │ └── test-dep-error/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── docker-compose.yaml
│ │ ├── fixtures/
│ │ │ ├── assertion-helper/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── benchmark/
│ │ │ │ ├── basic.bench.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── broken-iframe/
│ │ │ │ ├── submit-form.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── browser-crash/
│ │ │ │ ├── browser-crash.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── error-in-dep/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── expect-dom/
│ │ │ │ ├── setup.ts
│ │ │ │ ├── toBeChecked.test.ts
│ │ │ │ ├── toBeDisabled.test.ts
│ │ │ │ ├── toBeEmptyDOMElement.test.ts
│ │ │ │ ├── toBeInTheDocument.test.ts
│ │ │ │ ├── toBeInViewport.test.ts
│ │ │ │ ├── toBeInvalid.test.ts
│ │ │ │ ├── toBePartiallyChecked.test.ts
│ │ │ │ ├── toBeRequired.test.ts
│ │ │ │ ├── toBeVisible.test.ts
│ │ │ │ ├── toContainElement.test.ts
│ │ │ │ ├── toContainHTML.test.ts
│ │ │ │ ├── toHaveAccessibleDescription.test.ts
│ │ │ │ ├── toHaveAccessibleErrorMessage.test.ts
│ │ │ │ ├── toHaveAttribute.test.ts
│ │ │ │ ├── toHaveClass.test.ts
│ │ │ │ ├── toHaveDisplayValue.test.ts
│ │ │ │ ├── toHaveFocus.test.ts
│ │ │ │ ├── toHaveFormValues.test.ts
│ │ │ │ ├── toHaveLength.test.ts
│ │ │ │ ├── toHaveRole.test.ts
│ │ │ │ ├── toHaveSelection.test.ts
│ │ │ │ ├── toHaveStyle.test.ts
│ │ │ │ ├── toHaveTextContent.test.ts
│ │ │ │ ├── toHaveValue.test.ts
│ │ │ │ ├── toMatchScreenshot.test.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── vitest.config.js
│ │ │ ├── failing/
│ │ │ │ ├── failing.snaphot.test.ts
│ │ │ │ ├── failing.test.ts
│ │ │ │ ├── src/
│ │ │ │ │ └── error.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── insecure-context/
│ │ │ │ ├── src/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── dynamic-import.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── inspect/
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.config.with-workspace.ts
│ │ │ ├── isolate-and-setup-file/
│ │ │ │ ├── a.test.ts
│ │ │ │ ├── b.test.ts
│ │ │ │ ├── browser-setup.ts
│ │ │ │ ├── counter.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── locators/
│ │ │ │ ├── blog.test.tsx
│ │ │ │ ├── query.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── locators-custom/
│ │ │ │ ├── basic.test.tsx
│ │ │ │ └── vitest.config.ts
│ │ │ ├── mocking/
│ │ │ │ ├── automocked.test.ts
│ │ │ │ ├── autospying.test.ts
│ │ │ │ ├── import-actual-dep.test.ts
│ │ │ │ ├── import-actual-in-mock.test.ts
│ │ │ │ ├── import-actual-query.test.ts
│ │ │ │ ├── import-mock.test.ts
│ │ │ │ ├── mocked-__mocks__.test.ts
│ │ │ │ ├── mocked-do-mock-factory.test.ts
│ │ │ │ ├── mocked-factory-hoisted.test.ts
│ │ │ │ ├── mocked-factory.test.ts
│ │ │ │ ├── mocked-nested.test.ts
│ │ │ │ ├── mocking-dep.test.ts
│ │ │ │ ├── not-mocked-nested.test.ts
│ │ │ │ ├── not-mocked.test.ts
│ │ │ │ ├── service-worker.js
│ │ │ │ ├── service-worker.test.ts
│ │ │ │ ├── src/
│ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ └── mocks_calculator.ts
│ │ │ │ │ ├── actions.ts
│ │ │ │ │ ├── calculator.ts
│ │ │ │ │ ├── example.ts
│ │ │ │ │ ├── mocks_calculator.ts
│ │ │ │ │ ├── mocks_factory.ts
│ │ │ │ │ ├── mocks_factory_many.ts
│ │ │ │ │ ├── mocks_factory_many_dep1.ts
│ │ │ │ │ ├── mocks_factory_many_dep2.ts
│ │ │ │ │ ├── nested_child.ts
│ │ │ │ │ └── nested_parent.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── mocking-out-of-root/
│ │ │ │ ├── project1/
│ │ │ │ │ ├── basic.test.js
│ │ │ │ │ ├── imported-test.js
│ │ │ │ │ ├── lib.js
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── project2/
│ │ │ │ │ └── index.js
│ │ │ │ └── project3/
│ │ │ │ ├── imported-test.js
│ │ │ │ └── lib.js
│ │ │ ├── mocking-watch/
│ │ │ │ ├── 1_mocked-on-watch-change.test.ts
│ │ │ │ ├── 2_not-mocked-import.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── multiple-different-configs/
│ │ │ │ ├── basic.test.js
│ │ │ │ ├── customTester.html
│ │ │ │ └── vitest.config.js
│ │ │ ├── playwright-connect/
│ │ │ │ ├── basic.test.js
│ │ │ │ └── vitest.config.js
│ │ │ ├── print-logs/
│ │ │ │ ├── test/
│ │ │ │ │ ├── dialog.test.ts
│ │ │ │ │ └── logs.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── project-name-encoding/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── server-url/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── setup-file/
│ │ │ │ ├── browser-setup.ts
│ │ │ │ ├── module-equality.test.ts
│ │ │ │ ├── source.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── timeout/
│ │ │ │ ├── timeout.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── timeout-hooks/
│ │ │ │ ├── hooks-timeout.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── trace-mark/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── trace-view/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── failing.special.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── unhandled/
│ │ │ │ ├── throw-unhandled-error.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── unhandled-non-error/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── update-snapshot/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── basic.test.ts.snap
│ │ │ │ │ └── custom/
│ │ │ │ │ └── my_snapshot
│ │ │ │ ├── basic-fixture.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── user-event/
│ │ │ │ ├── cleanup-retry.test.ts
│ │ │ │ ├── cleanup1.test.ts
│ │ │ │ ├── cleanup2.test.ts
│ │ │ │ ├── clipboard.test.ts
│ │ │ │ ├── keyboard.test.ts
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── wheel.test.ts
│ │ │ ├── viewport/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ └── worker/
│ │ │ ├── src/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── worker-dynamic-dep.ts
│ │ │ │ └── worker.ts
│ │ │ └── vitest.config.ts
│ │ ├── injected.ts
│ │ ├── package.json
│ │ ├── settings.ts
│ │ ├── setup.unit.ts
│ │ ├── specs/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── expect-element-no-awaited.test.ts.snap
│ │ │ │ └── update-snapshot.test.ts.snap
│ │ │ ├── assertion-helper.test.ts
│ │ │ ├── bail-out.test.ts
│ │ │ ├── benchmark.test.ts
│ │ │ ├── errors.test.ts
│ │ │ ├── expect-dom.test.ts
│ │ │ ├── expect-element-no-awaited.test.ts
│ │ │ ├── filter.test.ts
│ │ │ ├── fix-4686.test.ts
│ │ │ ├── insecure-context.test.ts
│ │ │ ├── inspect.test.ts
│ │ │ ├── locators.test.ts
│ │ │ ├── mocking.test.ts
│ │ │ ├── multiple-different-configs.test.ts
│ │ │ ├── playwright-connect.test.ts
│ │ │ ├── playwright-trace-mark.test.ts
│ │ │ ├── playwright-trace.test.ts
│ │ │ ├── project-name-encoding.test.ts
│ │ │ ├── runner.test.ts
│ │ │ ├── server-url.test.ts
│ │ │ ├── setup-file.test.ts
│ │ │ ├── to-match-screenshot.test.ts
│ │ │ ├── update-snapshot.test.ts
│ │ │ ├── utils.ts
│ │ │ ├── viewport.test.ts
│ │ │ └── worker.test.ts
│ │ ├── src/
│ │ │ ├── __mocks__/
│ │ │ │ └── _calculator.ts
│ │ │ ├── actions.ts
│ │ │ ├── blog-app/
│ │ │ │ └── blog.tsx
│ │ │ ├── button.css
│ │ │ ├── calculator.ts
│ │ │ ├── createNode.ts
│ │ │ ├── dynamic.ts
│ │ │ └── env.ts
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── custom/
│ │ │ │ │ └── my_snapshot
│ │ │ │ ├── snapshot.test.ts.snap
│ │ │ │ └── utils.test.ts.snap
│ │ │ ├── another.test.ts
│ │ │ ├── basic.test.ts
│ │ │ ├── cdp.test-d.ts
│ │ │ ├── cdp.test.ts
│ │ │ ├── cjs-lib.test.ts
│ │ │ ├── commands.test.ts
│ │ │ ├── dom.test.ts
│ │ │ ├── dynamic-module.test.ts
│ │ │ ├── env.test.ts
│ │ │ ├── expect-element.test.ts
│ │ │ ├── findElement.test.ts
│ │ │ ├── iframe.test.ts
│ │ │ ├── injected.test.ts
│ │ │ ├── mocking.test.ts
│ │ │ ├── polyfill-lib.test.ts
│ │ │ ├── server-headers.test.ts
│ │ │ ├── snapshot.test.ts
│ │ │ ├── tags.test.ts
│ │ │ ├── timers.test.ts
│ │ │ ├── userEvent.test.ts
│ │ │ ├── utils.test.ts
│ │ │ └── viewport.test.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config-basepath.mts
│ │ ├── vitest.config.mts
│ │ └── vitest.config.unit.mts
│ ├── cli/
│ │ ├── .gitignore
│ │ ├── custom.ts
│ │ ├── deps/
│ │ │ ├── dep-invalid/
│ │ │ │ └── package.json
│ │ │ ├── dep-simple/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── dep-url/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── error/
│ │ │ │ ├── index.js
│ │ │ │ ├── package.json
│ │ │ │ ├── transpiled-inline.js
│ │ │ │ ├── transpiled-inline.ts
│ │ │ │ ├── transpiled.js
│ │ │ │ ├── transpiled.ts
│ │ │ │ └── ts.ts
│ │ │ ├── linked/
│ │ │ │ ├── index.ts
│ │ │ │ └── package.json
│ │ │ └── pkg-reporter/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── dts/
│ │ │ ├── _shared/
│ │ │ │ ├── happy-dom-patch.ts
│ │ │ │ └── tsconfig.patch.json
│ │ │ ├── browser-playwright/
│ │ │ │ ├── package.json
│ │ │ │ ├── src/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── vite.config.ts
│ │ │ ├── config/
│ │ │ │ ├── package.json
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── vite.config.ts
│ │ │ ├── exact-optional-property/
│ │ │ │ ├── package.json
│ │ │ │ ├── src/
│ │ │ │ │ ├── reporter.ts
│ │ │ │ │ └── runner.ts
│ │ │ │ └── tsconfig.json
│ │ │ └── fixture-extend/
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ └── repro.ts
│ │ │ ├── tsconfig.check.json
│ │ │ └── tsconfig.json
│ │ ├── fixtures/
│ │ │ ├── assertion-helper/
│ │ │ │ └── basic.test.ts
│ │ │ ├── bail-race/
│ │ │ │ ├── a.test.ts
│ │ │ │ └── b.test.ts
│ │ │ ├── basic/
│ │ │ │ └── basic.test.ts
│ │ │ ├── benchmarking/
│ │ │ │ ├── basic/
│ │ │ │ │ ├── base.bench.ts
│ │ │ │ │ ├── mode.bench.ts
│ │ │ │ │ ├── only.bench.ts
│ │ │ │ │ ├── should-not-run.test-d.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── compare/
│ │ │ │ │ ├── basic.bench.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── reporter/
│ │ │ │ │ ├── multiple.bench.ts
│ │ │ │ │ ├── summary.bench.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ └── sequential/
│ │ │ │ ├── f1.bench.ts
│ │ │ │ ├── f2.bench.ts
│ │ │ │ ├── helper.ts
│ │ │ │ ├── setup.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── browser-init/
│ │ │ │ ├── package.json
│ │ │ │ └── vitest.config.ts
│ │ │ ├── browser-multiple/
│ │ │ │ ├── basic.test.js
│ │ │ │ ├── package.json
│ │ │ │ └── vitest.config.ts
│ │ │ ├── caching/
│ │ │ │ ├── dynamic-cache-key/
│ │ │ │ │ ├── replaced.test.js
│ │ │ │ │ ├── vitest.config.bails.js
│ │ │ │ │ ├── vitest.config.fails.js
│ │ │ │ │ └── vitest.config.passes.js
│ │ │ │ └── import-meta-glob/
│ │ │ │ ├── glob.test.js
│ │ │ │ └── vitest.config.js
│ │ │ ├── cancel-run/
│ │ │ │ ├── blocked-test-cases.test.ts
│ │ │ │ └── blocked-thread.test.ts
│ │ │ ├── config/
│ │ │ │ ├── bail/
│ │ │ │ │ ├── test/
│ │ │ │ │ │ ├── first.test.ts
│ │ │ │ │ │ └── second.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── browser-custom-html/
│ │ │ │ │ ├── browser-basic.test.ts
│ │ │ │ │ ├── browser-custom.test.ts
│ │ │ │ │ ├── custom-html.html
│ │ │ │ │ ├── vitest.config.correct.ts
│ │ │ │ │ ├── vitest.config.custom-transformIndexHtml.ts
│ │ │ │ │ ├── vitest.config.default-transformIndexHtml.ts
│ │ │ │ │ ├── vitest.config.error-hook.ts
│ │ │ │ │ └── vitest.config.non-existing.ts
│ │ │ │ ├── browser-define/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ └── watch-trigger-pattern/
│ │ │ │ ├── folder/
│ │ │ │ │ └── fs/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── text.txt
│ │ │ │ └── vitest.config.ts
│ │ │ ├── config-loader/
│ │ │ │ ├── browser/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── node/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── console/
│ │ │ │ ├── trace.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── create-vitest/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── custom-file-env/
│ │ │ │ └── custom-file-env.test.ts
│ │ │ ├── custom-pool/
│ │ │ │ ├── pool/
│ │ │ │ │ └── custom-pool.ts
│ │ │ │ ├── tests/
│ │ │ │ │ ├── custom-not-run.spec.ts
│ │ │ │ │ └── custom-run.threads.spec.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── custom-runner/
│ │ │ │ ├── custom-runner.test.ts
│ │ │ │ ├── test-runner.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── dotted-files/
│ │ │ │ └── .cache/
│ │ │ │ └── projects/
│ │ │ │ └── test/
│ │ │ │ └── should-run.test.ts
│ │ │ ├── expect-soft/
│ │ │ │ ├── expects/
│ │ │ │ │ └── soft.test.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── fails/
│ │ │ │ ├── .dot-folder/
│ │ │ │ │ └── dot-test.test.ts
│ │ │ │ ├── async-assertion.test.ts
│ │ │ │ ├── each-timeout.test.ts
│ │ │ │ ├── empty.test.ts
│ │ │ │ ├── expect-soft.test.ts
│ │ │ │ ├── expect-unreachable.test.ts
│ │ │ │ ├── expect.test.ts
│ │ │ │ ├── exports-error.test.js
│ │ │ │ ├── hook-timeout.test.ts
│ │ │ │ ├── hooks-called.test.ts
│ │ │ │ ├── hooks-fail-afterAll.test.ts
│ │ │ │ ├── hooks-fail-afterEach.test.ts
│ │ │ │ ├── hooks-fail-beforeAll.test.ts
│ │ │ │ ├── hooks-fail-beforeEach.test.ts
│ │ │ │ ├── hooks-timeout-before-hook-cleanup-callback.test.ts
│ │ │ │ ├── mock-import-proxy-module.test.ts
│ │ │ │ ├── nested-suite.test.ts
│ │ │ │ ├── no-assertions.test.ts
│ │ │ │ ├── node-browser-context.test.ts
│ │ │ │ ├── poll-no-awaited.test.ts
│ │ │ │ ├── primitive-error.test.ts
│ │ │ │ ├── proxy-module.ts
│ │ │ │ ├── skip-conditional.test.ts
│ │ │ │ ├── snapshot-with-not.test.ts
│ │ │ │ ├── stall.test.ts
│ │ │ │ ├── test-extend/
│ │ │ │ │ ├── circular-dependency.test.ts
│ │ │ │ │ ├── fixture-error.test.ts
│ │ │ │ │ ├── fixture-rest-params.test.ts
│ │ │ │ │ ├── fixture-rest-props.test.ts
│ │ │ │ │ ├── fixture-without-destructuring.test.ts
│ │ │ │ │ ├── test-rest-params.test.ts
│ │ │ │ │ ├── test-rest-props.test.ts
│ │ │ │ │ └── test-without-destructuring.test.ts
│ │ │ │ ├── test-timeout.test.ts
│ │ │ │ ├── unhandled-suite.test.ts
│ │ │ │ ├── unhandled.test.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── file-tags/
│ │ │ │ ├── error-file-one-line-comment.test.ts
│ │ │ │ ├── error-file-tags.test.ts
│ │ │ │ ├── valid-file-one-line-comment.test.ts
│ │ │ │ └── valid-file-tags.test.ts
│ │ │ ├── forks-channel/
│ │ │ │ ├── process-send.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── git-changed/
│ │ │ │ ├── related/
│ │ │ │ │ ├── deep-related-exports.test.ts
│ │ │ │ │ ├── deep-related-imports.test.ts
│ │ │ │ │ ├── not-related.test.ts
│ │ │ │ │ ├── related.test.ts
│ │ │ │ │ ├── src/
│ │ │ │ │ │ ├── sourceA.ts
│ │ │ │ │ │ ├── sourceB.ts
│ │ │ │ │ │ ├── sourceC.ts
│ │ │ │ │ │ └── sourceD.ts
│ │ │ │ │ └── vitest.config.js
│ │ │ │ └── workspace/
│ │ │ │ ├── package.json
│ │ │ │ ├── packages/
│ │ │ │ │ ├── packageA/
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── index.test.js
│ │ │ │ │ │ └── vitest.config.mjs
│ │ │ │ │ └── packageB/
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.test.js
│ │ │ │ │ └── vitest.config.mjs
│ │ │ │ └── vitest.config.mjs
│ │ │ ├── global-setup/
│ │ │ │ ├── globalSetup/
│ │ │ │ │ ├── another-vite-instance.ts
│ │ │ │ │ ├── default-export.js
│ │ │ │ │ ├── named-exports.js
│ │ │ │ │ ├── server.ts
│ │ │ │ │ ├── ts-with-imports.ts
│ │ │ │ │ └── update-env.ts
│ │ │ │ ├── index.html
│ │ │ │ ├── setupFiles/
│ │ │ │ │ ├── add-something-to-global.ts
│ │ │ │ │ └── without-relative-path-prefix.ts
│ │ │ │ └── test/
│ │ │ │ ├── global-setup.test.ts
│ │ │ │ └── setup-files.test.ts
│ │ │ ├── global-setup-fail/
│ │ │ │ ├── example.test.ts
│ │ │ │ ├── globalSetup/
│ │ │ │ │ └── error.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── inspect/
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.config.ts.timestamp-1713887058308-b154731a64b17.mjs
│ │ │ ├── invalid-package/
│ │ │ │ ├── mock-bad-dep.test.ts
│ │ │ │ ├── mock-wrapper-and-bad-dep.test.ts
│ │ │ │ ├── mock-wrapper.test.ts
│ │ │ │ └── wrapper.ts
│ │ │ ├── list/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── custom.config.ts
│ │ │ │ ├── describe-error.test.ts
│ │ │ │ ├── fail.config.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── top-level-error.test.ts
│ │ │ │ ├── type.test-d.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── location-filters/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── math-with-dashes-in-name.test.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── no-task-location.config.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── mocker/
│ │ │ │ ├── automock/
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── test.js
│ │ │ │ ├── autospy/
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── test.js
│ │ │ │ ├── manual-mock/
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── test.js
│ │ │ │ └── redirect/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── test.js
│ │ │ │ ├── index.html
│ │ │ │ ├── index.js
│ │ │ │ └── test.js
│ │ │ ├── network-imports/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── public/
│ │ │ │ └── slash@3.0.0.js
│ │ │ ├── no-module-runner/
│ │ │ │ ├── jsSetup.js
│ │ │ │ ├── package.json
│ │ │ │ ├── src/
│ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ └── redirect.ts
│ │ │ │ │ ├── basic.ts
│ │ │ │ │ ├── dependency.ts
│ │ │ │ │ ├── from-async.ts
│ │ │ │ │ ├── in-source/
│ │ │ │ │ │ ├── add.ts
│ │ │ │ │ │ ├── fibonacci.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── minus.ts
│ │ │ │ │ ├── mock-async.ts
│ │ │ │ │ ├── mock-js.d.ts
│ │ │ │ │ ├── mock-js.js
│ │ │ │ │ ├── mock-sync.ts
│ │ │ │ │ ├── no-mock.ts
│ │ │ │ │ ├── redirect.ts
│ │ │ │ │ └── setups.ts
│ │ │ │ ├── test/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── suite.test.ts.snap
│ │ │ │ │ ├── automock.test.ts
│ │ │ │ │ ├── autospy.test.ts
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ ├── manual-mock.test.ts
│ │ │ │ │ ├── mock-async-factory.test.ts
│ │ │ │ │ ├── redirect-mock.test.ts
│ │ │ │ │ └── suite.test.ts
│ │ │ │ ├── tsSetup.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── vitest.config.ts
│ │ │ ├── no-unexpected-logging/
│ │ │ │ ├── fixture-1.test.ts
│ │ │ │ ├── fixture-10.test.ts
│ │ │ │ ├── fixture-11.test.ts
│ │ │ │ ├── fixture-12.test.ts
│ │ │ │ ├── fixture-2.test.ts
│ │ │ │ ├── fixture-3.test.ts
│ │ │ │ ├── fixture-4.test.ts
│ │ │ │ ├── fixture-5.test.ts
│ │ │ │ ├── fixture-6.test.ts
│ │ │ │ ├── fixture-7.test.ts
│ │ │ │ ├── fixture-8.test.ts
│ │ │ │ └── fixture-9.test.ts
│ │ │ ├── optimize-deps/
│ │ │ │ ├── ssr.test.ts
│ │ │ │ └── web.test.ts
│ │ │ ├── otel-tests/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── otel.browser.sdk.js
│ │ │ │ ├── otel.sdk.js
│ │ │ │ └── vitest.config.ts
│ │ │ ├── path-filter/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── plugin/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── project/
│ │ │ │ ├── packages/
│ │ │ │ │ ├── project_1/
│ │ │ │ │ │ └── base.test.ts
│ │ │ │ │ ├── project_2/
│ │ │ │ │ │ └── base.test.ts
│ │ │ │ │ └── space_1/
│ │ │ │ │ └── base.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── public-api/
│ │ │ │ ├── custom.spec.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── reported-tasks/
│ │ │ │ └── 1_first.test.ts
│ │ │ ├── reporters/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── all-passing-or-skipped.test.ts
│ │ │ │ ├── all-skipped.test.ts
│ │ │ │ ├── basic/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.override.js
│ │ │ │ ├── better-testsuite-name/
│ │ │ │ │ ├── space-1/
│ │ │ │ │ │ └── test/
│ │ │ │ │ │ └── base.test.ts
│ │ │ │ │ ├── space-2/
│ │ │ │ │ │ └── test/
│ │ │ │ │ │ └── base.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── code-frame-line-limit.test.ts
│ │ │ │ ├── console-interleave.test.ts
│ │ │ │ ├── console-simple.test.ts
│ │ │ │ ├── console-some-failing.test.ts
│ │ │ │ ├── console.test.ts
│ │ │ │ ├── custom-diff-config.test.ts
│ │ │ │ ├── custom-diff-config.ts
│ │ │ │ ├── custom-error/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── default/
│ │ │ │ │ ├── a.test.ts
│ │ │ │ │ ├── b1.test.ts
│ │ │ │ │ ├── b2.test.ts
│ │ │ │ │ ├── print-index.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── duration/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── error-props/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── error-to-json.test.ts
│ │ │ │ ├── error.test.ts
│ │ │ │ ├── function-as-name.bench.ts
│ │ │ │ ├── function-as-name.test.ts
│ │ │ │ ├── github-actions/
│ │ │ │ │ └── flaky/
│ │ │ │ │ ├── math.spec.ts
│ │ │ │ │ └── network.spec.ts
│ │ │ │ ├── implementations/
│ │ │ │ │ ├── custom-reporter.js
│ │ │ │ │ └── custom-reporter.ts
│ │ │ │ ├── import-durations-25ms-throws.ts
│ │ │ │ ├── import-durations-25ms.ts
│ │ │ │ ├── import-durations-50ms.ts
│ │ │ │ ├── import-durations-throws.test.ts
│ │ │ │ ├── import-durations.test.ts
│ │ │ │ ├── indicator-position.test.js
│ │ │ │ ├── invalid-diff-config.ts
│ │ │ │ ├── json-fail-import.test.ts
│ │ │ │ ├── json-fail.test.ts
│ │ │ │ ├── junit-cli-options/
│ │ │ │ │ ├── sample.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── long-loading-task.test.ts
│ │ │ │ ├── many-errors/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── merge-errors/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── merge-reports/
│ │ │ │ │ ├── first.test.ts
│ │ │ │ │ ├── second.test.ts
│ │ │ │ │ └── vitest.config.js
│ │ │ │ ├── merge-reports-module-graph/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ ├── second.test.ts
│ │ │ │ │ ├── sub/
│ │ │ │ │ │ ├── format.ts
│ │ │ │ │ │ └── subject.ts
│ │ │ │ │ ├── util.ts
│ │ │ │ │ └── vitest.config.js
│ │ │ │ ├── metadata/
│ │ │ │ │ ├── metadata.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── ok.test.ts
│ │ │ │ ├── pass-and-skip-test-suites.test.ts
│ │ │ │ ├── project-name/
│ │ │ │ │ ├── example.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── repeats.test.ts
│ │ │ │ ├── reporter-error/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── retry.test.ts
│ │ │ │ ├── some-failing.test.ts
│ │ │ │ ├── suite-hook-failure/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── test-for-title.test.ts
│ │ │ │ ├── verbose/
│ │ │ │ │ ├── example-1.test.ts
│ │ │ │ │ └── example-2.test.ts
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── with-syntax-error.test.js
│ │ │ ├── restricted-fs/
│ │ │ │ ├── src/
│ │ │ │ │ └── math.js
│ │ │ │ ├── tests/
│ │ │ │ │ └── basic.spec.js
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.setup.js
│ │ │ ├── retry-config/
│ │ │ │ └── vitest.config.ts
│ │ │ ├── rollup-error/
│ │ │ │ ├── not-found-export.test.ts
│ │ │ │ ├── not-found-package.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── setup-files/
│ │ │ │ ├── console-setup.ts
│ │ │ │ ├── empty-setup.ts
│ │ │ │ └── empty.test.ts
│ │ │ ├── skip-note/
│ │ │ │ └── basic.test.ts
│ │ │ ├── ssr-runner/
│ │ │ │ ├── basic.test.ts
│ │ │ │ ├── test-runner.js
│ │ │ │ └── vitest.config.ts
│ │ │ ├── ssr-runner-project/
│ │ │ │ ├── project/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ ├── test-runner.js
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── stacktraces/
│ │ │ │ ├── add-in-imba.test.imba
│ │ │ │ ├── add-in-js.test.js
│ │ │ │ ├── add.test.ts
│ │ │ │ ├── error-in-deps.test.js
│ │ │ │ ├── error-in-package.test.js
│ │ │ │ ├── error-with-stack.test.js
│ │ │ │ ├── foo.js
│ │ │ │ ├── frame.spec.imba
│ │ │ │ ├── mocked-global.test.js
│ │ │ │ ├── mocked-imported.test.js
│ │ │ │ ├── mocked-imported.test.ts
│ │ │ │ ├── require-assertions.test.js
│ │ │ │ ├── reset-modules.test.ts
│ │ │ │ ├── setup.js
│ │ │ │ ├── utils.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── stacktraces-custom-helper/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── helper.ts
│ │ │ ├── standalone/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── test-tags/
│ │ │ │ └── basic.test.ts
│ │ │ ├── tty/
│ │ │ │ ├── example.test.ts
│ │ │ │ ├── example.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── math.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── vitest.config.js
│ │ │ ├── vm-threads/
│ │ │ │ ├── import-external-css-assets.test.js
│ │ │ │ ├── module.test.js
│ │ │ │ ├── not-found.test.ts
│ │ │ │ ├── require-cjs.test.js
│ │ │ │ ├── src/
│ │ │ │ │ └── external/
│ │ │ │ │ ├── assets/
│ │ │ │ │ │ └── file2.txt
│ │ │ │ │ ├── css/
│ │ │ │ │ │ ├── empty.css
│ │ │ │ │ │ ├── processed.css
│ │ │ │ │ │ └── processed.module.css
│ │ │ │ │ ├── default-cjs.cjs
│ │ │ │ │ ├── export-default-cjs.js
│ │ │ │ │ ├── export-nested-default-cjs.js
│ │ │ │ │ ├── nested-default-cjs.cjs
│ │ │ │ │ ├── not-found.js
│ │ │ │ │ ├── package-null/
│ │ │ │ │ │ └── package-null.js
│ │ │ │ │ ├── package.json
│ │ │ │ │ └── primitive-cjs.cjs
│ │ │ │ └── vitest.config.ts
│ │ │ ├── watch/
│ │ │ │ ├── 42.txt
│ │ │ │ ├── example.test.ts
│ │ │ │ ├── example.ts
│ │ │ │ ├── force-watch/
│ │ │ │ │ └── trigger.js
│ │ │ │ ├── global-setup.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── math.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── windows-drive-case/
│ │ │ │ └── basic.test.ts
│ │ │ └── workspace/
│ │ │ ├── api/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vite.custom.config.js
│ │ │ ├── config-empty/
│ │ │ │ └── vitest.config.js
│ │ │ ├── config-extends/
│ │ │ │ ├── repro.test.js
│ │ │ │ └── vitest.config.ts
│ │ │ ├── config-import-analysis/
│ │ │ │ ├── dep.ts
│ │ │ │ ├── packages/
│ │ │ │ │ └── a/
│ │ │ │ │ ├── package.json
│ │ │ │ │ └── test.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── invalid-duplicate-configs/
│ │ │ │ ├── vitest.config.one.js
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.config.two.js
│ │ │ ├── invalid-duplicate-inline/
│ │ │ │ └── vitest.config.ts
│ │ │ ├── invalid-non-existing-config/
│ │ │ │ └── vitest.config.ts
│ │ │ ├── negated/
│ │ │ │ ├── packages/
│ │ │ │ │ ├── a/
│ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ └── test.test.ts
│ │ │ │ │ ├── b/
│ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ └── test.test.ts
│ │ │ │ │ └── c/
│ │ │ │ │ ├── package.json
│ │ │ │ │ └── test.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── project-1/
│ │ │ │ └── calculator-1.test.ts
│ │ │ ├── project-2/
│ │ │ │ └── calculator-2.test.ts
│ │ │ ├── several-configs/
│ │ │ │ ├── test/
│ │ │ │ │ ├── 1_test.test.ts
│ │ │ │ │ ├── 2_test.test.ts
│ │ │ │ │ ├── vitest.config.one.ts
│ │ │ │ │ └── vitest.config.two.ts
│ │ │ │ └── vitest.config.ts
│ │ │ └── several-folders/
│ │ │ ├── apps/
│ │ │ │ └── b/
│ │ │ │ ├── package.json
│ │ │ │ └── test.test.ts
│ │ │ ├── projects/
│ │ │ │ └── a/
│ │ │ │ ├── package.json
│ │ │ │ └── test.test.ts
│ │ │ └── vitest.config.ts
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── benchmarking.test.ts.snap
│ │ │ │ ├── fails.test.ts.snap
│ │ │ │ ├── list.test.ts.snap
│ │ │ │ ├── no-module-runner.test.ts.snap
│ │ │ │ └── stacktraces.test.ts.snap
│ │ │ ├── annotations.test.ts
│ │ │ ├── around-each.test.ts
│ │ │ ├── artifacts.test.ts
│ │ │ ├── assertion-helper.test.ts
│ │ │ ├── bail-race.test.ts
│ │ │ ├── benchmarking.test.ts
│ │ │ ├── browser-multiple.test.ts
│ │ │ ├── caching.test.ts
│ │ │ ├── cancel-run.test.ts
│ │ │ ├── concurrent.test.ts
│ │ │ ├── config/
│ │ │ │ ├── bail.test.ts
│ │ │ │ ├── browser-configs.test.ts
│ │ │ │ ├── passWithNoTests.test.ts
│ │ │ │ ├── sequence-shuffle.test.ts
│ │ │ │ └── watchTriggerPattern.test.ts
│ │ │ ├── config-loader.test.ts
│ │ │ ├── configureVitest.test.ts
│ │ │ ├── console.test.ts
│ │ │ ├── create-vitest.test.ts
│ │ │ ├── custom-pool.test.ts
│ │ │ ├── custom-runner.test.ts
│ │ │ ├── detect-async-leaks.test.ts
│ │ │ ├── dotted-files.test.ts
│ │ │ ├── expect-soft.test.ts
│ │ │ ├── expect-task.test.ts
│ │ │ ├── fails.test.ts
│ │ │ ├── fixtures/
│ │ │ │ └── reporters/
│ │ │ │ └── html/
│ │ │ │ ├── all-passing-or-skipped/
│ │ │ │ │ ├── assets/
│ │ │ │ │ │ ├── index-BUCFJtth.js
│ │ │ │ │ │ └── index-DlhE0rqZ.css
│ │ │ │ │ └── index.html
│ │ │ │ └── fail/
│ │ │ │ ├── assets/
│ │ │ │ │ ├── index-BUCFJtth.js
│ │ │ │ │ └── index-DlhE0rqZ.css
│ │ │ │ └── index.html
│ │ │ ├── fs-cached-check.test.ts
│ │ │ ├── get-state.test.ts
│ │ │ ├── git-changed.test.ts
│ │ │ ├── global-setup.test.ts
│ │ │ ├── group-order.test.ts
│ │ │ ├── init.test.ts
│ │ │ ├── inspect.test.ts
│ │ │ ├── list-changed.test.ts
│ │ │ ├── list.test.ts
│ │ │ ├── location-filters.test.ts
│ │ │ ├── mocking.test.ts
│ │ │ ├── network-imports.test.ts
│ │ │ ├── no-module-runner.test.ts
│ │ │ ├── no-unexpected-logging.test.ts
│ │ │ ├── node-builtins.test.ts
│ │ │ ├── open-telemetry.test.ts
│ │ │ ├── optimize-deps.test.ts
│ │ │ ├── oxc.test.ts
│ │ │ ├── path-filter.test.ts
│ │ │ ├── plugin.test.ts
│ │ │ ├── print-error.test.ts
│ │ │ ├── projects.test.ts
│ │ │ ├── public-api.test.ts
│ │ │ ├── public-mocker.test.ts
│ │ │ ├── reported-tasks.test.ts
│ │ │ ├── reporters/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── default.test.ts.snap
│ │ │ │ │ ├── html.test.ts.snap
│ │ │ │ │ ├── json.test.ts.snap
│ │ │ │ │ ├── junit.test.ts.snap
│ │ │ │ │ ├── reporters.spec.ts.snap
│ │ │ │ │ └── reporters.test.ts.snap
│ │ │ │ ├── agent.test.ts
│ │ │ │ ├── code-frame-line-limit.test.ts
│ │ │ │ ├── configuration-options.test-d.ts
│ │ │ │ ├── console.test.ts
│ │ │ │ ├── custom-diff-config.test.ts
│ │ │ │ ├── custom-reporter.test.ts
│ │ │ │ ├── default.test.ts
│ │ │ │ ├── dot.test.ts
│ │ │ │ ├── error-to-json.test.ts
│ │ │ │ ├── function-as-name.test.ts
│ │ │ │ ├── github-actions.test.ts
│ │ │ │ ├── html.test.ts
│ │ │ │ ├── import-durations.test.ts
│ │ │ │ ├── indicator-position.test.ts
│ │ │ │ ├── json.test.ts
│ │ │ │ ├── junit.test.ts
│ │ │ │ ├── logger.test.ts
│ │ │ │ ├── merge-reports.test.ts
│ │ │ │ ├── reporter-error.test.ts
│ │ │ │ ├── reporters.test.ts
│ │ │ │ ├── silent.test.ts
│ │ │ │ ├── tap.test.ts
│ │ │ │ ├── test-run.test.ts
│ │ │ │ ├── tree.test.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── verbose.test.ts
│ │ │ ├── restricted-fs.test.ts
│ │ │ ├── retry-clear-mocks.test.ts
│ │ │ ├── rollup-error.test.ts
│ │ │ ├── run-custom-env.test.ts
│ │ │ ├── scoped-fixtures.test.ts
│ │ │ ├── server-url.test.ts
│ │ │ ├── setup-files.test.ts
│ │ │ ├── shared-env.test.ts
│ │ │ ├── signal.test.ts
│ │ │ ├── skip-note.test.ts
│ │ │ ├── ssr-runner.test.ts
│ │ │ ├── stacktraces.test.ts
│ │ │ ├── standalone.test.ts
│ │ │ ├── static-collect.test.ts
│ │ │ ├── test-meta.test.ts
│ │ │ ├── test-specifications.test.ts
│ │ │ ├── test-tags.test.ts
│ │ │ ├── tty.test.ts
│ │ │ ├── unhandled-ignore.test.ts
│ │ │ ├── unhandled-rejections.test.ts
│ │ │ ├── vm-threads.test.ts
│ │ │ ├── watch/
│ │ │ │ ├── change-project.test.ts
│ │ │ │ ├── config-watching.test.ts
│ │ │ │ ├── file-watching.test.ts
│ │ │ │ ├── global-setup-rerun.test.ts
│ │ │ │ ├── related.test.ts
│ │ │ │ ├── reporter-failed.test.ts
│ │ │ │ ├── stdin.test.ts
│ │ │ │ ├── stdout.test.ts
│ │ │ │ └── workspaces.test.ts
│ │ │ ├── windows-drive-case.test.ts
│ │ │ └── workers-option.test.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── config/
│ │ ├── deps/
│ │ │ ├── optimizer/
│ │ │ │ ├── external/
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── package.json
│ │ │ │ └── optimized/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── test-dep-conditions/
│ │ │ │ ├── false.js
│ │ │ │ ├── indirect.js
│ │ │ │ ├── inline.js
│ │ │ │ ├── package.json
│ │ │ │ └── true.js
│ │ │ ├── test-dep-conditions-indirect/
│ │ │ │ ├── false.js
│ │ │ │ ├── package.json
│ │ │ │ └── true.js
│ │ │ ├── test-dep-config/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── test-dep-virtual/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ └── vite-ssr-resolve/
│ │ │ ├── inline-dep/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── other-dep/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ └── ssr-no-external-dep/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── fixtures/
│ │ │ ├── allowed-exec-args-fixtures/
│ │ │ │ ├── allowed-exec-argv.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── browser-no-config/
│ │ │ │ └── vitest.config.ts
│ │ │ ├── browser-persistent-context/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── cache/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── second.test.ts
│ │ │ ├── chai-config/
│ │ │ │ ├── test-each-title.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── conditions/
│ │ │ │ ├── basic.test.js
│ │ │ │ └── vite.config.ts
│ │ │ ├── conditions-pkg/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── conditions-projects/
│ │ │ │ ├── project-a/
│ │ │ │ │ ├── basic.test.js
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── project-b/
│ │ │ │ │ ├── basic.test.js
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── conditions-subpackage/
│ │ │ │ ├── custom.js
│ │ │ │ ├── default.js
│ │ │ │ ├── development.js
│ │ │ │ ├── package.json
│ │ │ │ └── production.js
│ │ │ ├── conditions-test/
│ │ │ │ ├── conditions.test.js
│ │ │ │ └── vitest.config.ts
│ │ │ ├── console/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── console-batch/
│ │ │ │ └── basic.test.ts
│ │ │ ├── console-color/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── coverage-test/
│ │ │ │ └── example.ts
│ │ │ ├── css/
│ │ │ │ ├── App.css
│ │ │ │ ├── App.module.css
│ │ │ │ ├── test/
│ │ │ │ │ ├── default-css.spec.ts
│ │ │ │ │ ├── non-scope-module.spec.ts
│ │ │ │ │ ├── process-css.spec.ts
│ │ │ │ │ ├── process-inline.spec.ts
│ │ │ │ │ ├── process-module.spec.ts
│ │ │ │ │ └── scope-module.spec.ts
│ │ │ │ └── utils.ts
│ │ │ ├── diff/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vite.config.ts
│ │ │ ├── exclude/
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── math.ts
│ │ │ │ ├── string.test.ts
│ │ │ │ ├── string.ts
│ │ │ │ └── vitest.exclude.config.ts
│ │ │ ├── exec-args-fixtures/
│ │ │ │ ├── forks.test.ts
│ │ │ │ ├── threads.test.ts
│ │ │ │ └── vmThreads.test.ts
│ │ │ ├── external/
│ │ │ │ └── dynamic/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── filters/
│ │ │ │ └── test/
│ │ │ │ ├── config.test.ts
│ │ │ │ ├── dont-run-this.test.ts
│ │ │ │ └── example.test.ts
│ │ │ ├── filters-slash/
│ │ │ │ ├── test/
│ │ │ │ │ ├── basic/
│ │ │ │ │ │ └── a.test.ts
│ │ │ │ │ ├── basic-foo/
│ │ │ │ │ │ └── a.test.ts
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── foo-basic/
│ │ │ │ │ └── a.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── fixture-no-async/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── hook-timeout/
│ │ │ │ └── basic.test.ts
│ │ │ ├── inline-setup-file/
│ │ │ │ ├── file-setup.js
│ │ │ │ ├── test.test.js
│ │ │ │ └── vitest.config.js
│ │ │ ├── mixed-environments/
│ │ │ │ ├── project/
│ │ │ │ │ └── test/
│ │ │ │ │ ├── happy-dom.test.ts
│ │ │ │ │ ├── jsdom.test.ts
│ │ │ │ │ ├── node.test.ts
│ │ │ │ │ └── workspace-project.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── mode/
│ │ │ │ ├── example.benchmark.ts
│ │ │ │ ├── example.test.ts
│ │ │ │ ├── vitest.benchmark.config.ts
│ │ │ │ └── vitest.test.config.ts
│ │ │ ├── no-browser-workspace/
│ │ │ │ └── vitest.config.ts
│ │ │ ├── no-exec-args-fixtures/
│ │ │ │ ├── no-exec-argv.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── optimizer/
│ │ │ │ └── external/
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── pool/
│ │ │ │ ├── a.test.ts
│ │ │ │ ├── b.test.ts
│ │ │ │ ├── c.test.ts
│ │ │ │ ├── print-config.test.ts
│ │ │ │ ├── print-testfiles.test.ts
│ │ │ │ └── write-to-stdout-and-stderr.test.ts
│ │ │ ├── public-config/
│ │ │ │ ├── vitest.config.ts
│ │ │ │ └── vitest.custom.config.ts
│ │ │ ├── retry/
│ │ │ │ ├── retry.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── run-mode/
│ │ │ │ ├── example.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── sequence-concurrent/
│ │ │ │ ├── sequence-concurrent-false-concurrent.test.ts
│ │ │ │ ├── sequence-concurrent-false-sequential.test.ts
│ │ │ │ ├── sequence-concurrent-true-concurrent.test.ts
│ │ │ │ └── sequence-concurrent-true-sequential.test.ts
│ │ │ ├── shard/
│ │ │ │ ├── test/
│ │ │ │ │ ├── 1.test.js
│ │ │ │ │ ├── 2.test.js
│ │ │ │ │ └── 3.test.js
│ │ │ │ └── vitest.config.js
│ │ │ ├── shard-4-files/
│ │ │ │ ├── test/
│ │ │ │ │ ├── 1.test.js
│ │ │ │ │ ├── 2.test.js
│ │ │ │ │ ├── 3.test.js
│ │ │ │ │ └── 4.test.js
│ │ │ │ └── vitest.config.js
│ │ │ ├── snapshot-path-context/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── project1/
│ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ └── project2/
│ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ ├── basic.test.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── test/
│ │ │ │ ├── example.test.ts
│ │ │ │ ├── fake-timers.test.ts
│ │ │ │ └── vitest.config.js
│ │ │ ├── vitest.config.js
│ │ │ ├── workers-option/
│ │ │ │ ├── example.test.ts
│ │ │ │ └── vitest.config.js
│ │ │ └── workspace-flags/
│ │ │ ├── projects/
│ │ │ │ ├── cli-config.test.ts
│ │ │ │ └── vitest.config.js
│ │ │ └── vitest.config.js
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── diff.test.ts.snap
│ │ │ │ └── hook-timeout.test.ts.snap
│ │ │ ├── browser-persistent-context.test.ts
│ │ │ ├── cache.test.ts
│ │ │ ├── chai-config.test.ts
│ │ │ ├── cli-config.test.ts
│ │ │ ├── conditions-cli.test.ts
│ │ │ ├── config-types.test-d.ts
│ │ │ ├── console-color.test.ts
│ │ │ ├── console.test.ts
│ │ │ ├── css-configs.test.ts
│ │ │ ├── diff.test.ts
│ │ │ ├── exclude.test.ts
│ │ │ ├── exec-args.test.ts
│ │ │ ├── external.test.ts
│ │ │ ├── failures.test.ts
│ │ │ ├── fixture-no-async.test.ts
│ │ │ ├── hook-timeout.test.ts
│ │ │ ├── inline-setup-file.test.ts
│ │ │ ├── mixed-environments.test.ts
│ │ │ ├── mode.test.ts
│ │ │ ├── optimizer.test.ts
│ │ │ ├── override.test.ts
│ │ │ ├── pass-empty-files.test.ts
│ │ │ ├── pool.test.ts
│ │ │ ├── public.test.ts
│ │ │ ├── retry.test.ts
│ │ │ ├── sequence-concurrent.test.ts
│ │ │ ├── shard.test.ts
│ │ │ ├── snapshot.test.ts
│ │ │ ├── testname-pattern.test.ts
│ │ │ └── vite-ssr-resolve.test.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── core/
│ │ ├── __mocks__/
│ │ │ ├── @vitest/
│ │ │ │ └── test-fn.ts
│ │ │ ├── @vueuse/
│ │ │ │ └── integrations/
│ │ │ │ └── useJwt.ts
│ │ │ ├── axios/
│ │ │ │ └── index.ts
│ │ │ ├── custom-lib.ts
│ │ │ ├── extension.js.ts
│ │ │ ├── fs/
│ │ │ │ └── promises.cjs
│ │ │ ├── fs.cjs
│ │ │ ├── timers.ts
│ │ │ ├── virtual-module.ts
│ │ │ └── vscode-mocks.ts
│ │ ├── deps/
│ │ │ ├── dep-cjs/
│ │ │ │ ├── esm-comment.js
│ │ │ │ ├── esm-string.js
│ │ │ │ └── package.json
│ │ │ ├── dep-esm-non-existing/
│ │ │ │ ├── index.mjs
│ │ │ │ ├── index.mts
│ │ │ │ └── package.json
│ │ │ ├── dep-fn/
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── dep-nested-cjs/
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── dep1/
│ │ │ │ ├── esm/
│ │ │ │ │ └── index.js
│ │ │ │ └── package.json
│ │ │ └── dep2/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── projects/
│ │ │ ├── custom-lib/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── inline-lib/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── vite-environment-external/
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ └── vite-external/
│ │ │ ├── index.d.ts
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── src/
│ │ │ ├── __mocks__/
│ │ │ │ └── submodule.ts
│ │ │ ├── aliased-mod.ts
│ │ │ ├── circularA.ts
│ │ │ ├── circularB.ts
│ │ │ ├── cjs/
│ │ │ │ ├── array-cjs.js
│ │ │ │ ├── bare-cjs.js
│ │ │ │ ├── class-cjs.js
│ │ │ │ ├── default-function.d.ts
│ │ │ │ ├── default-function.js
│ │ │ │ ├── module-cjs.ts
│ │ │ │ ├── nested-default-cjs.js
│ │ │ │ ├── primitive-cjs.js
│ │ │ │ ├── promise-export.js
│ │ │ │ └── prototype-cjs.js
│ │ │ ├── class-inheritence/
│ │ │ │ ├── bar.ts
│ │ │ │ └── foo.ts
│ │ │ ├── custom/
│ │ │ │ └── gardener.ts
│ │ │ ├── dynamic-import.ts
│ │ │ ├── env.ts
│ │ │ ├── esm/
│ │ │ │ ├── esm.js
│ │ │ │ ├── internal-esm.mjs
│ │ │ │ └── package.json
│ │ │ ├── exec.ts
│ │ │ ├── external/
│ │ │ │ ├── default-cjs.js
│ │ │ │ ├── nested-default-cjs.js
│ │ │ │ ├── package.json
│ │ │ │ ├── pkg-browser/
│ │ │ │ │ ├── index.d.ts
│ │ │ │ │ ├── package.json
│ │ │ │ │ ├── ssr.js
│ │ │ │ │ └── web.js
│ │ │ │ └── pkg-node/
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── package.json
│ │ │ │ ├── ssr.js
│ │ │ │ └── web.js
│ │ │ ├── file-css.css
│ │ │ ├── file-less.less
│ │ │ ├── file-sass.sass
│ │ │ ├── file-scss.scss
│ │ │ ├── file-txt.txt
│ │ │ ├── global-mock.ts
│ │ │ ├── in-source/
│ │ │ │ ├── add.ts
│ │ │ │ ├── fibonacci.ts
│ │ │ │ └── index.ts
│ │ │ ├── mockedA.ts
│ │ │ ├── mockedB.ts
│ │ │ ├── mockedC.ts
│ │ │ ├── mockedD.ts
│ │ │ ├── mockedE.ts
│ │ │ ├── mocks/
│ │ │ │ ├── A.ts
│ │ │ │ ├── B.ts
│ │ │ │ ├── autospying-namespace/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── namespaceTarget.ts
│ │ │ │ ├── cyclic-deps/
│ │ │ │ │ ├── module-1.mjs
│ │ │ │ │ ├── module-2.mjs
│ │ │ │ │ ├── module-3.mjs
│ │ │ │ │ └── module-4.mjs
│ │ │ │ ├── default.ts
│ │ │ │ ├── dynamic-module.d.ts
│ │ │ │ ├── dynamic-module.js
│ │ │ │ ├── example.ts
│ │ │ │ ├── export-default-circle-b.ts
│ │ │ │ ├── export-default-circle-index.ts
│ │ │ │ ├── external/
│ │ │ │ │ ├── cjs-pseudoesm.cjs
│ │ │ │ │ ├── default-cjs.cjs
│ │ │ │ │ ├── default-function.cjs
│ │ │ │ │ └── external.mjs
│ │ │ │ ├── has space in path.ts
│ │ │ │ ├── integration.ts
│ │ │ │ ├── log.ts
│ │ │ │ ├── main.js
│ │ │ │ ├── moduleA.ts
│ │ │ │ ├── moduleB.ts
│ │ │ │ ├── moduleWithSymbol.ts
│ │ │ │ ├── retry-dynamic-import.ts
│ │ │ │ ├── set-foo.ts
│ │ │ │ ├── squared.js
│ │ │ │ └── test-fn-magic.ts
│ │ │ ├── module-esm.ts
│ │ │ ├── read-hello-world.ts
│ │ │ ├── relative-import.ts
│ │ │ ├── rely-on-hoisted.ts
│ │ │ ├── self/
│ │ │ │ ├── foo.ts
│ │ │ │ └── index.ts
│ │ │ ├── submodule.ts
│ │ │ ├── timeout.ts
│ │ │ ├── wasm/
│ │ │ │ ├── add.wasm
│ │ │ │ ├── wasm-bindgen/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index_bg.js
│ │ │ │ │ ├── index_bg.wasm
│ │ │ │ │ └── package.json
│ │ │ │ └── wasm-bindgen-no-cyclic/
│ │ │ │ ├── README.md
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── index.js
│ │ │ │ ├── index_bg.js
│ │ │ │ ├── index_bg.wasm
│ │ │ │ ├── index_bg.wasm.d.ts
│ │ │ │ └── package.json
│ │ │ └── web-worker/
│ │ │ ├── eventListenerWorker.ts
│ │ │ ├── mock/
│ │ │ │ ├── worker-dep.ts
│ │ │ │ └── worker.ts
│ │ │ ├── objectWorker.ts
│ │ │ ├── selfWorker.ts
│ │ │ ├── selfWorkerDep.ts
│ │ │ ├── sharedWorker.ts
│ │ │ ├── worker-globals.ts
│ │ │ └── worker.ts
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── injector-mock.test.ts.snap
│ │ │ │ ├── jest-expect.test.ts.snap
│ │ │ │ ├── mocked.test.ts.snap
│ │ │ │ ├── nested-suite.test.ts.snap
│ │ │ │ ├── serialize.test.ts.snap
│ │ │ │ ├── snapshot-concurrent-sync.test.ts.snap
│ │ │ │ ├── snapshot-concurrent.test.ts.snap
│ │ │ │ ├── snapshot.test.ts.snap
│ │ │ │ ├── suite.test.tsx.snap
│ │ │ │ ├── test-for-suite.test.ts.snap
│ │ │ │ └── test-for.test.ts.snap
│ │ │ ├── alias.test.ts
│ │ │ ├── basic.test.ts
│ │ │ ├── browserAutomocker.test.ts
│ │ │ ├── builtin.test.ts
│ │ │ ├── chai-style-assertions.test.ts
│ │ │ ├── chainable.test.ts
│ │ │ ├── child-specific.child_process.test.ts
│ │ │ ├── circular.test.ts
│ │ │ ├── cli-test.test.ts
│ │ │ ├── concurrent-suite.test.ts
│ │ │ ├── concurrent.spec.ts
│ │ │ ├── custom.test.ts
│ │ │ ├── date-mock.test.ts
│ │ │ ├── define-ssr.test.ts
│ │ │ ├── define-web.test.ts
│ │ │ ├── diff.test.ts
│ │ │ ├── do-mock-reset-modules.test.ts
│ │ │ ├── do-mock.test.ts
│ │ │ ├── dom-single-line-options.test.ts
│ │ │ ├── dom.test.ts
│ │ │ ├── dual-package-hazard.test.ts
│ │ │ ├── dynamic-import.test.ts
│ │ │ ├── each.test.ts
│ │ │ ├── edge.test.ts
│ │ │ ├── env-glob.test.ts
│ │ │ ├── env-jsdom.test.ts
│ │ │ ├── env-runtime.test.ts
│ │ │ ├── env.test.ts
│ │ │ ├── environments/
│ │ │ │ ├── custom-env.test.ts
│ │ │ │ ├── happy-dom.spec.ts
│ │ │ │ ├── jsdom.spec.ts
│ │ │ │ └── node.spec.ts
│ │ │ ├── error.test.ts
│ │ │ ├── esnext-decorator.test.ts
│ │ │ ├── esnext.test.ts
│ │ │ ├── execution-order.test.ts
│ │ │ ├── expect-circular.test.ts
│ │ │ ├── expect-poll.test.ts
│ │ │ ├── expect.test-d.ts
│ │ │ ├── expect.test.ts
│ │ │ ├── exports.test.ts
│ │ │ ├── external-module-directory.test.ts
│ │ │ ├── file-path.test.ts
│ │ │ ├── fixture-comments-between-destructure.test.ts
│ │ │ ├── fixture-concurrent-beforeEach.test.ts
│ │ │ ├── fixture-concurrent.test.ts
│ │ │ ├── fixture-initialization.test.ts
│ │ │ ├── fixture-options.test.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── hello-mock.ts
│ │ │ │ ├── hi.txt
│ │ │ │ ├── increment-indirect.ts
│ │ │ │ ├── increment.ts
│ │ │ │ ├── mocked-dependency.ts
│ │ │ │ ├── named-overwrite-all/
│ │ │ │ │ ├── dep1.js
│ │ │ │ │ ├── dep2.js
│ │ │ │ │ └── main.js
│ │ │ │ ├── snapshot-empty.txt
│ │ │ │ ├── snapshots/
│ │ │ │ │ ├── basic/
│ │ │ │ │ │ ├── input.json
│ │ │ │ │ │ └── output.css
│ │ │ │ │ └── multiple/
│ │ │ │ │ ├── input.json
│ │ │ │ │ └── output.css
│ │ │ │ ├── timers.suite.ts
│ │ │ │ └── virtual-module-indirect.ts
│ │ │ ├── fn.test.ts
│ │ │ ├── fs.test.ts
│ │ │ ├── handled-unhandled.test.ts
│ │ │ ├── happy-dom-custom.test.ts
│ │ │ ├── happy-dom.test.ts
│ │ │ ├── hoist-import.test.ts
│ │ │ ├── hoisted-async-simple.test.ts
│ │ │ ├── hoisted-simple.test.ts
│ │ │ ├── hooks-list.test.ts
│ │ │ ├── hooks-parallel.test.ts
│ │ │ ├── hooks-stack.test.ts
│ │ │ ├── hooks.test.js
│ │ │ ├── hooks.test.ts
│ │ │ ├── immutable.test.ts
│ │ │ ├── import-client.test.ts
│ │ │ ├── import-meta-resolve.test.ts
│ │ │ ├── imports.test.ts
│ │ │ ├── injector-esm.test.ts
│ │ │ ├── injector-mock.test.ts
│ │ │ ├── inline-snap.test.ts
│ │ │ ├── inlined.test.ts
│ │ │ ├── isolate.test.ts
│ │ │ ├── jest-expect-no-url.test.ts
│ │ │ ├── jest-expect.test.ts
│ │ │ ├── jest-matcher-utils.test.ts
│ │ │ ├── jest-mock.test.ts
│ │ │ ├── local-context.test.ts
│ │ │ ├── lot-of-tests.test.ts
│ │ │ ├── math.test.ts
│ │ │ ├── memory-limit.test.ts
│ │ │ ├── mock-fs.test.ts
│ │ │ ├── mock-internals.test.ts
│ │ │ ├── mocked-circular.test.ts
│ │ │ ├── mocked-class-restore-all.test.ts
│ │ │ ├── mocked-class-restore-explicit.test.ts
│ │ │ ├── mocked-class.test.ts
│ │ │ ├── mocked-import-circular.test.ts
│ │ │ ├── mocked-no-mocks-same.test.ts
│ │ │ ├── mocked-no-mocks.test.ts
│ │ │ ├── mocked-node-module.test.ts
│ │ │ ├── mocked-public-key.test.ts
│ │ │ ├── mocked.test.js
│ │ │ ├── mocked.test.ts
│ │ │ ├── mocking/
│ │ │ │ ├── already-hoisted.test.ts
│ │ │ │ ├── automocking-class-inheritence.test.ts
│ │ │ │ ├── automocking.spec.ts
│ │ │ │ ├── autospying.test.ts
│ │ │ │ ├── axios-mocked.test.ts
│ │ │ │ ├── axios-not-mocked.test.ts
│ │ │ │ ├── circular-mocks.spec.ts
│ │ │ │ ├── custom-module-directory.spec.ts
│ │ │ │ ├── cyclic-import-actual.spec.ts
│ │ │ │ ├── cyclic-import-original.spec.ts
│ │ │ │ ├── destructured.test.ts
│ │ │ │ ├── error-mock.spec.ts
│ │ │ │ ├── external.test.ts
│ │ │ │ ├── factory.test.ts
│ │ │ │ ├── has-extension.spec.ts
│ │ │ │ ├── hoisted.test.ts
│ │ │ │ ├── integration.test.ts
│ │ │ │ ├── nested-default.spec.ts
│ │ │ │ ├── retry-dynamic-import.test.ts
│ │ │ │ ├── self-importing.test.ts
│ │ │ │ ├── spaced.spec.ts
│ │ │ │ ├── tinyspy.test.ts
│ │ │ │ ├── vi-fn.test-d.ts
│ │ │ │ ├── vi-fn.test.ts
│ │ │ │ ├── vi-mockObject.test.ts
│ │ │ │ ├── vi-spyOn.test.ts
│ │ │ │ └── virtual.test.ts
│ │ │ ├── modes.test.ts
│ │ │ ├── module-diagnostic.test.ts
│ │ │ ├── module.test.ts
│ │ │ ├── moved-snapshot.test.ts
│ │ │ ├── moved-snapshot.test.ts.snap
│ │ │ ├── named-overwrite-all.test.ts
│ │ │ ├── nested-only.test.ts
│ │ │ ├── nested-suite.test.ts
│ │ │ ├── nested-test.test.ts
│ │ │ ├── node-protocol-jsdom.spec.ts
│ │ │ ├── node-protocol-node.spec.ts
│ │ │ ├── on-failed.test.ts
│ │ │ ├── on-finished.test.ts
│ │ │ ├── only.test.ts
│ │ │ ├── parse-cjs-conditions.test.ts
│ │ │ ├── pattern.test.ts
│ │ │ ├── propagate-options-nested-suite.test.ts
│ │ │ ├── random.test.ts
│ │ │ ├── repeats.test.ts
│ │ │ ├── replace-matcher.test.ts
│ │ │ ├── require.test.ts
│ │ │ ├── resolve-file-url.test.ts
│ │ │ ├── resolve-file-url~dep.js
│ │ │ ├── resolve-ssr.test.ts
│ │ │ ├── resolve-web.test.ts
│ │ │ ├── retry-condition.test.ts
│ │ │ ├── retry-delay.test.ts
│ │ │ ├── retry-only.test.ts
│ │ │ ├── retry.test.ts
│ │ │ ├── rpc.spec.ts
│ │ │ ├── run-if.test.ts
│ │ │ ├── self.test.ts
│ │ │ ├── sequencers.test.ts
│ │ │ ├── sequential.test.ts
│ │ │ ├── serialize.test.ts
│ │ │ ├── setup.ts
│ │ │ ├── skip-reset-state.test.ts
│ │ │ ├── skip.test.ts
│ │ │ ├── snapshot-1.txt
│ │ │ ├── snapshot-2.txt
│ │ │ ├── snapshot-async.test.ts
│ │ │ ├── snapshot-concurrent-sync.test.ts
│ │ │ ├── snapshot-concurrent.test.ts
│ │ │ ├── snapshot-custom-serializer.test.ts
│ │ │ ├── snapshot-file.test.ts
│ │ │ ├── snapshot-inline-(parentheses).test.ts
│ │ │ ├── snapshot-inline.test.ts
│ │ │ ├── snapshot-react-18.test.jsx
│ │ │ ├── snapshot-react.test.jsx
│ │ │ ├── snapshot.test.ts
│ │ │ ├── snapshots-outside.ts
│ │ │ ├── sourcemap.test.ts
│ │ │ ├── spy.test.ts
│ │ │ ├── strict.test.js
│ │ │ ├── stubbed-process.test.ts
│ │ │ ├── stubs.test.ts
│ │ │ ├── suite.test.tsx
│ │ │ ├── tab-effect.spec.mjs
│ │ │ ├── task-collector.test.ts
│ │ │ ├── task-names.test.ts
│ │ │ ├── test-extend-with-top-level-hooks.test.ts
│ │ │ ├── test-extend.test.ts
│ │ │ ├── test-for-suite.test.ts
│ │ │ ├── test-for.test.ts
│ │ │ ├── test-name-pattern.test.ts
│ │ │ ├── test-options.test.ts
│ │ │ ├── test-tags-filter.test.ts
│ │ │ ├── threads-specific.threads.test.ts
│ │ │ ├── timeout.spec.ts
│ │ │ ├── timers-getMockedSystemTime.test.ts
│ │ │ ├── timers-jsdom.test.ts
│ │ │ ├── timers-node.test.ts
│ │ │ ├── timers-queueMicrotask.test.ts
│ │ │ ├── unhandled.test.ts
│ │ │ ├── unmock-import.test.ts
│ │ │ ├── url-ssr.test.ts
│ │ │ ├── url-web.test.ts
│ │ │ ├── utils-display.spec.ts
│ │ │ ├── utils.spec.ts
│ │ │ ├── vi.spec.ts
│ │ │ ├── vi.test-d.ts
│ │ │ ├── wait.test.ts
│ │ │ ├── wasm.test.ts
│ │ │ ├── web-worker-jsdom.test.ts
│ │ │ ├── web-worker-mock.test.ts
│ │ │ ├── web-worker-node.test.ts
│ │ │ └── write-file-dynamic-import.test.ts
│ │ ├── tsconfig.typecheck.json
│ │ ├── types/
│ │ │ ├── env.d.ts
│ │ │ └── vite.d.ts
│ │ ├── vite.config.ts
│ │ └── vitest-environment-custom/
│ │ ├── index.ts
│ │ └── package.json
│ ├── coverage-test/
│ │ ├── fixtures/
│ │ │ ├── configs/
│ │ │ │ ├── vitest.config.conditional.ts
│ │ │ │ ├── vitest.config.configure-vitest-hook.ts
│ │ │ │ ├── vitest.config.decorators.ts
│ │ │ │ ├── vitest.config.multi-transform.ts
│ │ │ │ ├── vitest.config.multi-transforms.ts
│ │ │ │ ├── vitest.config.query-param-transform.ts
│ │ │ │ ├── vitest.config.thresholds-auto-update.ts
│ │ │ │ ├── vitest.config.ts
│ │ │ │ ├── vitest.config.virtual-files.ts
│ │ │ │ └── vitest.config.workspace.ts
│ │ │ ├── custom-provider.ts
│ │ │ ├── custom-reporter.cjs
│ │ │ ├── setup.isolation.ts
│ │ │ ├── setup.ts
│ │ │ ├── src/
│ │ │ │ ├── .should-be-excluded-from-coverage/
│ │ │ │ │ └── excluded-from-coverage.ts
│ │ │ │ ├── Vue/
│ │ │ │ │ ├── Counter/
│ │ │ │ │ │ ├── Counter.component.ts
│ │ │ │ │ │ ├── Counter.vue
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── Defined.vue
│ │ │ │ │ ├── Hello.vue
│ │ │ │ │ └── vue.shim.d.ts
│ │ │ │ ├── another-setup.ts
│ │ │ │ ├── branch.ts
│ │ │ │ ├── circularA.ts
│ │ │ │ ├── circularB.ts
│ │ │ │ ├── cjs-dependency.ts
│ │ │ │ ├── conditional/
│ │ │ │ │ ├── ssr.ts
│ │ │ │ │ └── web.ts
│ │ │ │ ├── covered.custom-1
│ │ │ │ ├── decorators.ts
│ │ │ │ ├── dynamic-files.ts
│ │ │ │ ├── empty-lines.ts
│ │ │ │ ├── even.ts
│ │ │ │ ├── file-to-change.ts
│ │ │ │ ├── ignore-hints.ts
│ │ │ │ ├── implicit-else.ts
│ │ │ │ ├── import-meta-env.ts
│ │ │ │ ├── in-source.ts
│ │ │ │ ├── json-data-import.ts
│ │ │ │ ├── json-data.json
│ │ │ │ ├── load-outside-vite.cjs
│ │ │ │ ├── math.ts
│ │ │ │ ├── mock-target.ts
│ │ │ │ ├── multi-environment.ts
│ │ │ │ ├── multi-suite.ts
│ │ │ │ ├── pre-bundle/
│ │ │ │ │ ├── bundle.js
│ │ │ │ │ ├── bundle.ts
│ │ │ │ │ ├── first.ts
│ │ │ │ │ └── second.ts
│ │ │ │ ├── pre-transpiled/
│ │ │ │ │ ├── original.ts
│ │ │ │ │ ├── transpiled.d.ts
│ │ │ │ │ └── transpiled.js
│ │ │ │ ├── query-param-transformed.ts
│ │ │ │ ├── should-be-excluded-by-default.cts
│ │ │ │ ├── test-that-looks-like-source-file.ts
│ │ │ │ ├── tested-with-]-in-filename.ts
│ │ │ │ ├── throws-error.ts
│ │ │ │ ├── types-only.ts
│ │ │ │ ├── uncovered.custom-1
│ │ │ │ ├── untested-file.ts
│ │ │ │ ├── untested-with-]-in-filename.ts
│ │ │ │ ├── virtual-files.ts
│ │ │ │ ├── worker-wrapper.ts
│ │ │ │ └── worker.ts
│ │ │ ├── test/
│ │ │ │ ├── allow-external-fixture.test.ts
│ │ │ │ ├── circular.test.ts
│ │ │ │ ├── cjs-dependency.test.ts
│ │ │ │ ├── clean-on-rerun-fixture.test.ts
│ │ │ │ ├── custom-1-syntax.test.ts
│ │ │ │ ├── error-location.test.ts
│ │ │ │ ├── even.test.ts
│ │ │ │ ├── file-to-change.test.ts
│ │ │ │ ├── ignore-hints-fixture.test.ts
│ │ │ │ ├── import-attributes-fixture.test.ts
│ │ │ │ ├── isolation-1-fixture.test.ts
│ │ │ │ ├── isolation-2-fixture.test.ts
│ │ │ │ ├── math.test.ts
│ │ │ │ ├── merge-fixture-1.test.ts
│ │ │ │ ├── merge-fixture-2.test.ts
│ │ │ │ ├── merge-fixture-3.test.ts
│ │ │ │ ├── mock-autospy-fixture.test.ts
│ │ │ │ ├── mock-importActual-fixture.test.ts
│ │ │ │ ├── mocking-in-js-file.test.js
│ │ │ │ ├── multi-environment-fixture-ssr.test.ts
│ │ │ │ ├── multi-environment-fixture-web.test.ts
│ │ │ │ ├── multi-suite-fixture.test.ts
│ │ │ │ ├── pre-transpiled-fixture.test.ts
│ │ │ │ ├── query-param.test.ts
│ │ │ │ ├── sources-with-]-in-filenames.test.ts
│ │ │ │ ├── virtual-files-fixture.test.ts
│ │ │ │ ├── vue-fixture.test.ts
│ │ │ │ └── web-worker.test.ts
│ │ │ └── workspaces/
│ │ │ ├── custom-2/
│ │ │ │ ├── src/
│ │ │ │ │ ├── covered.custom-2
│ │ │ │ │ └── uncovered.custom-2
│ │ │ │ └── test/
│ │ │ │ └── custom-2-syntax.test.ts
│ │ │ └── project/
│ │ │ ├── project1/
│ │ │ │ ├── src/
│ │ │ │ │ ├── id.ts
│ │ │ │ │ └── untested.ts
│ │ │ │ └── test/
│ │ │ │ └── id.test.ts
│ │ │ ├── project2/
│ │ │ │ ├── src/
│ │ │ │ │ ├── konst.ts
│ │ │ │ │ └── untested.ts
│ │ │ │ └── test/
│ │ │ │ └── konst.test.ts
│ │ │ └── shared/
│ │ │ ├── src/
│ │ │ │ └── utils.ts
│ │ │ └── test/
│ │ │ └── utils.test.ts
│ │ ├── package.json
│ │ ├── setup.native.ts
│ │ ├── setup.ts
│ │ ├── test/
│ │ │ ├── allow-external.test.ts
│ │ │ ├── bundled-sources.test.ts
│ │ │ ├── changed.test.ts
│ │ │ ├── cjs-dependency.test.ts
│ │ │ ├── clean-on-rerun.test.ts
│ │ │ ├── configuration-options.test-d.ts
│ │ │ ├── custom-provider.custom.test.ts
│ │ │ ├── custom-reporter.test.ts
│ │ │ ├── decorators.test.ts
│ │ │ ├── dynamic-files.test.ts
│ │ │ ├── empty-coverage-directory.test.ts
│ │ │ ├── exclude-after-remap.test.ts
│ │ │ ├── file-outside-vite.test.ts
│ │ │ ├── ignore-hints.test.ts
│ │ │ ├── implicit-else.istanbul.test.ts
│ │ │ ├── import-attributes.test.ts
│ │ │ ├── import-meta-env.test.ts
│ │ │ ├── in-source.test.ts
│ │ │ ├── include-exclude.test.ts
│ │ │ ├── isolation.test.ts
│ │ │ ├── merge-reports.test.ts
│ │ │ ├── mixed-versions-warning.unit.test.ts
│ │ │ ├── mock-autospy.test.ts
│ │ │ ├── mock-importActual.test.ts
│ │ │ ├── mocking-in-js-file.test.ts
│ │ │ ├── multi-environment.test.ts
│ │ │ ├── multi-suite.test.ts
│ │ │ ├── on-failure.test.ts
│ │ │ ├── pre-transpiled-source.test.ts
│ │ │ ├── query-param-transforms.test.ts
│ │ │ ├── reporters.test.ts
│ │ │ ├── results-snapshot.test.ts
│ │ │ ├── run-dynamic-coverage.test.ts
│ │ │ ├── setup-files.test.ts
│ │ │ ├── shard.test.ts
│ │ │ ├── source-maps.test.ts
│ │ │ ├── temporary-files.test.ts
│ │ │ ├── test-reporter-conflicts.test.ts
│ │ │ ├── threshold-100.test.ts
│ │ │ ├── threshold-auto-update.test.ts
│ │ │ ├── threshold-auto-update.unit.test.ts
│ │ │ ├── threshold-failure.test.ts
│ │ │ ├── threshold-glob.test.ts
│ │ │ ├── transform-plugin-order.istanbul.test.ts
│ │ │ ├── virtual-files.test.ts
│ │ │ ├── vue.test.ts
│ │ │ ├── web-worker.test.ts
│ │ │ ├── workspace.multi-transform.test.ts
│ │ │ └── workspace.project-filter.test.ts
│ │ ├── tsconfig.json
│ │ ├── utils.ts
│ │ └── vitest.config.ts
│ ├── node-runner/
│ │ ├── fixtures/
│ │ │ └── globalSetup/
│ │ │ ├── basic.test.js
│ │ │ └── failing.ts
│ │ ├── package.json
│ │ └── test/
│ │ └── cli.test.js
│ ├── snapshots/
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── ci.test.ts
│ │ │ ├── compare-keys.test.ts
│ │ │ ├── custom-environment.test.ts
│ │ │ ├── custom-serializers.test.ts
│ │ │ ├── file.test.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── ci/
│ │ │ │ │ ├── .gitignore
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── compare-keys/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── custom-serializers/
│ │ │ │ │ ├── custom-serializers.test.ts
│ │ │ │ │ ├── serializer-1.js
│ │ │ │ │ ├── serializer-2.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── custom-snapshot-environment/
│ │ │ │ │ ├── snapshot-environment.ts
│ │ │ │ │ ├── test/
│ │ │ │ │ │ └── snapshots.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── file/
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ ├── snapshot-1.txt
│ │ │ │ │ └── snapshot-2.txt
│ │ │ │ ├── indent/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── inline-multiple-calls/
│ │ │ │ │ ├── different.test.ts
│ │ │ │ │ ├── different2.test.ts
│ │ │ │ │ ├── each.test.ts
│ │ │ │ │ ├── same.test.ts
│ │ │ │ │ └── same2.test.ts
│ │ │ │ ├── jest-image-snapshot/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── obsolete/
│ │ │ │ │ ├── src/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── test1.test.ts.snap
│ │ │ │ │ │ │ └── test2.test.ts.snap
│ │ │ │ │ │ ├── test1.test.ts
│ │ │ │ │ │ └── test2.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── skip-test/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── repro.test.ts.snap
│ │ │ │ │ ├── repro.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── skip-test-custom/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── soft/
│ │ │ │ │ ├── .gitignore
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── soft-inline/
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── summary/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ ├── basic.test.ts
│ │ │ │ │ └── vitest.config.ts
│ │ │ │ ├── summary-removed/
│ │ │ │ │ ├── .gitignore
│ │ │ │ │ └── basic.test.ts
│ │ │ │ ├── test-update/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── retry-file.test.ts.snap
│ │ │ │ │ │ └── same-title-file.test.js.snap
│ │ │ │ │ ├── inline-concurrent.test.js
│ │ │ │ │ ├── inline.test.js
│ │ │ │ │ ├── retry-file.test.ts
│ │ │ │ │ ├── retry-inline.test.ts
│ │ │ │ │ ├── same-title-file.test.js
│ │ │ │ │ └── same-title-inline.test.js
│ │ │ │ ├── test-update-result/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── retry-file.test.ts.snap
│ │ │ │ │ │ └── same-title-file.test.js.snap
│ │ │ │ │ ├── inline-concurrent.test.js
│ │ │ │ │ ├── inline.test.js
│ │ │ │ │ ├── retry-file.test.ts
│ │ │ │ │ ├── retry-inline.test.ts
│ │ │ │ │ ├── same-title-file.test.js
│ │ │ │ │ └── same-title-inline.test.js
│ │ │ │ └── workspace/
│ │ │ │ ├── packages/
│ │ │ │ │ └── space/
│ │ │ │ │ ├── test/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── basic.test.ts.snap
│ │ │ │ │ │ └── basic.test.ts
│ │ │ │ │ └── vite.config.ts
│ │ │ │ └── vitest.config.ts
│ │ │ ├── indent.test.ts
│ │ │ ├── inline-multiple-calls.test.ts
│ │ │ ├── jest-image-snapshot.test.ts
│ │ │ ├── obsolete.test.ts
│ │ │ ├── skip-test.test.ts
│ │ │ ├── snapshots.test.ts
│ │ │ ├── soft-inline.test.ts
│ │ │ ├── soft.test.ts
│ │ │ ├── summary.test.ts
│ │ │ └── test-update.test.ts
│ │ └── vitest.config.ts
│ ├── test-utils/
│ │ ├── cli.ts
│ │ ├── fixtures/
│ │ │ └── external-math.ts
│ │ ├── index.ts
│ │ └── package.json
│ ├── tsconfig.json
│ ├── typescript/
│ │ ├── failing/
│ │ │ ├── expect-error.test-d.ts
│ │ │ ├── fail.test-d.ts
│ │ │ ├── js-fail.test-d.js
│ │ │ ├── node-types.test-d.ts
│ │ │ └── only.test-d.ts
│ │ ├── fixtures/
│ │ │ ├── dynamic-title/
│ │ │ │ ├── test/
│ │ │ │ │ └── dynamic-title.test-d.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── vitest.config.ts
│ │ │ └── source-error/
│ │ │ ├── src/
│ │ │ │ └── not-ok.ts
│ │ │ ├── test/
│ │ │ │ └── ok.test-d.ts
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.ts
│ │ ├── package.json
│ │ ├── test/
│ │ │ ├── __snapshots__/
│ │ │ │ └── runner.test.ts.snap
│ │ │ ├── runner.test.ts
│ │ │ ├── typecheck-error.test.ts
│ │ │ ├── typechecker.test.ts
│ │ │ ├── vitest.custom.config.ts
│ │ │ └── vitest.empty.config.ts
│ │ ├── test-d/
│ │ │ ├── expect-extend.test-d.ts
│ │ │ ├── js.test-d.js
│ │ │ ├── nested-suite1.test-d.ts
│ │ │ ├── nested-suite2.test-d.ts
│ │ │ └── test.test-d.ts
│ │ ├── tsconfig.custom.json
│ │ ├── tsconfig.empty.json
│ │ ├── tsconfig.fails.json
│ │ ├── tsconfig.json
│ │ └── vitest.config.fails.ts
│ ├── ui/
│ │ ├── .gitignore
│ │ ├── fixtures/
│ │ │ ├── annotated.test.ts
│ │ │ ├── console.test.ts
│ │ │ ├── coverage.test.ts
│ │ │ ├── coverage.ts
│ │ │ ├── error.test.ts
│ │ │ ├── example.txt
│ │ │ ├── sample.test.ts
│ │ │ ├── snapshot.test.ts
│ │ │ └── task-name.test.ts
│ │ ├── fixtures-browser/
│ │ │ └── visual-regression.test.ts
│ │ ├── package.json
│ │ ├── playwright.config.ts
│ │ ├── test/
│ │ │ ├── html-report.spec.ts
│ │ │ ├── ui-security.spec.ts
│ │ │ └── ui.spec.ts
│ │ ├── tsconfig.json
│ │ └── vitest.config.ts
│ ├── workspaces/
│ │ ├── .gitignore
│ │ ├── coverage-report-tests/
│ │ │ ├── check-coverage.test.ts
│ │ │ └── vitest.config.ts
│ │ ├── cwdPlugin.d.ts
│ │ ├── cwdPlugin.js
│ │ ├── globalTest.ts
│ │ ├── package.json
│ │ ├── space-multi-transform/
│ │ │ ├── src/
│ │ │ │ └── multi-transform.ts
│ │ │ └── test/
│ │ │ ├── project-1.test.ts
│ │ │ └── project-2.test.ts
│ │ ├── space-pools/
│ │ │ ├── forks.test.ts
│ │ │ ├── isolate.test.ts
│ │ │ ├── no-isolate.test.ts
│ │ │ └── threads.test.ts
│ │ ├── space_1/
│ │ │ ├── test/
│ │ │ │ ├── env-injected.spec.ts
│ │ │ │ ├── happy-dom.spec.ts
│ │ │ │ └── math.spec.ts
│ │ │ ├── vite.config.ts
│ │ │ └── vite.config.ts.timestamp-4345324-324424.mjs
│ │ ├── space_2/
│ │ │ └── test/
│ │ │ └── node.spec.ts
│ │ ├── space_3/
│ │ │ ├── fake-vitest/
│ │ │ │ ├── config.js
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── global-provide.space-3-test.ts
│ │ │ ├── localSetup.ts
│ │ │ ├── math.space-3-test.ts
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ └── multiply.ts
│ │ │ ├── vite.config.ts
│ │ │ └── vitest.config.ts
│ │ ├── space_shared/
│ │ │ ├── setup.jsdom.ts
│ │ │ ├── setup.node.ts
│ │ │ └── test.spec.ts
│ │ ├── src/
│ │ │ └── math.ts
│ │ ├── vitest.config.ts
│ │ └── vitest.config.watch.ts
│ └── workspaces-browser/
│ ├── .gitignore
│ ├── globalTest.ts
│ ├── package.json
│ ├── space_1/
│ │ ├── test/
│ │ │ ├── math.spec.ts
│ │ │ └── node.spec.ts
│ │ ├── vite.config.ts
│ │ └── vitest.config.ts.timestamp-4345324-324424.mjs
│ ├── space_browser/
│ │ ├── test/
│ │ │ └── browser.spec.ts
│ │ └── vitest.config.ts
│ ├── space_browser_inline/
│ │ ├── test/
│ │ │ └── basic.test.ts
│ │ └── test-alias-to.ts
│ ├── src/
│ │ └── math.ts
│ └── vitest.config.ts
├── tsconfig.base.json
├── tsconfig.build.json
└── tsconfig.check.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .claude/agents/vitest-test-writer.md
================================================
---
name: vitest-test-writer
description: "Use this agent when the user needs to write comprehensive tests for Vitest features. This includes unit tests for individual functions, integration tests for CLI functionality, and browser mode tests. The agent should be invoked when implementing new features that require test coverage, fixing bugs that need regression tests, or expanding test coverage for existing functionality.\\n\\nExamples:\\n\\n\\nContext: User has just implemented a new utility function in the codebase.\\nuser: \"I just added a new parseConfig function to the config package\"\\nassistant: \"I see you've added a new function. Let me use the vitest-test-writer agent to create comprehensive tests for it.\"\\n\\nSince a new function was added, use the Task tool to launch the vitest-test-writer agent to write unit tests in test/core.\\n \\n \\n\\n\\nContext: User is working on a CLI feature.\\nuser: \"Please add a --json flag to the list command\"\\nassistant: \"I'll implement the --json flag for the list command.\"\\n\\nassistant: \"Now let me use the vitest-test-writer agent to write integration tests for this new CLI flag.\"\\n\\nSince a CLI feature was implemented, use the Task tool to launch the vitest-test-writer agent to write integration tests in test/cli using runInlineTests.\\n \\n \\n\\n\\nContext: User wants to ensure a feature works in both normal and browser modes.\\nuser: \"Can you write tests for the new snapshot feature?\"\\nassistant: \"I'll use the vitest-test-writer agent to write comprehensive tests for the snapshot feature, covering both normal and browser modes.\"\\n\\nSince the feature needs testing in multiple modes, use the Task tool to launch the vitest-test-writer agent to write tests in test/cli (for features supporting both modes).\\n \\n "
model: opus
color: green
---
You are an expert test engineer specializing in the Vitest testing framework. You have deep knowledge of Vitest's architecture, testing patterns, and the specific conventions used in this monorepo.
## Your Core Responsibilities
You write comprehensive, high-quality tests that follow the established patterns in this repository. You understand the distinction between unit tests, integration tests, and browser tests, and you place them in the correct locations.
## Test Location Rules
- **Unit tests**: Place in `test/core/`. These test individual functions by importing them directly, regardless of which package defines them.
- **Integration tests**: Place in `test/cli/`. These test CLI functionality and features that require running Vitest as a process.
- **Browser mode tests**: Place in `test/browser/`. However, if a feature supports both normal tests AND browser tests, place the tests in `test/cli/`.
## Testing Patterns You Must Follow
### Use runInlineTests Utility
For integration tests, always use the `runInlineTests` utility to create and run test scenarios. This utility allows you to define inline test files and validate their output.
### Snapshot Validation with toMatchInlineSnapshot
Always validate output using `toMatchInlineSnapshot()`. The snapshot is automatically generated on the first run. This is the preferred method because it:
- Captures the exact expected output
- Makes changes visible in code review
- Catches regressions precisely
### Avoid toContain
Do NOT use `toContain()` for output validation. This method fails to catch:
- Extra unexpected output
- Repeated output that shouldn't occur
- Subtle formatting differences
### Handle Dynamic Content
When output contains dynamic content (timestamps, absolute paths, durations, etc.):
1. First check `test-utils` for existing utilities that normalize this content
2. If no utility exists, manually process with `stdout.replace(regexp, 'normalized-value')`
3. Common patterns to normalize:
- Timing information (e.g., `1.234s` → `[time]`)
- Root paths (e.g., `/Users/name/project` → ``)
- Process IDs or temporary file paths
### Validate Test Results with testTree or errorTree
To ensure all tests actually passed (not just that they ran), use `testTree` or `errorTree` helpers. Pass the result to `toMatchInlineSnapshot()` to verify:
- The correct number of tests ran
- Tests are organized in the expected suites
- No unexpected failures or skipped tests
## Writing Unit Tests
For unit tests in `test/core/`:
1. Import the function directly from its source package
2. Test pure functionality without process spawning
3. Cover edge cases, error conditions, and typical usage
4. Use descriptive test names that explain the scenario
## Writing Integration Tests
For integration tests in `test/cli/`:
1. Use `runInlineTests` to define test scenarios
2. Create realistic test file content
3. Validate both stderr and the test results structure
4. Test error scenarios and edge cases
5. Ensure tests are deterministic (no flaky behavior)
## Quality Standards
- Every test should have a clear purpose
- Test names should describe the behavior being verified
- Group related tests in describe blocks
- Include both positive (happy path) and negative (error) test cases
- Consider boundary conditions and edge cases
- Tests should be independent and not rely on execution order
- If you encounter a bug in the behaviour, write a **failing** test and report that there is a bug or an unexpected behaviour. If possible, delegate fixing the bug to the main agent
## Before Writing Tests
1. Read AGENTS.md for additional context and patterns
2. Look at existing tests in the target directory for style guidance
3. Identify the test utilities available in the codebase
4. Understand what behavior needs to be verified
## Output Format
When writing tests, provide:
1. The complete test file with all imports
2. Explanations of what each test verifies
3. Notes on any dynamic content normalization applied
4. Suggestions for additional test cases if relevant
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
test/cli/fixtures/reporters/indicator-position.test.js eol=crlf
================================================
FILE: .github/FUNDING.yml
================================================
github: [vitest-dev, sheremet-va, antfu, patak-dev]
open_collective: vitest
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐞 Bug report
description: Report an issue with Vitest
labels: [pending triage]
type: Bug
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: I am doing ... What I expect is ... What actually happening is ...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Please provide a link to a github repository that can reproduce the problem you ran into (feel free to clone one of the [examples](https://github.com/vitest-dev/vitest/tree/main/examples)). You can also use [StackBlitz](https://stackblitz.com/fork/github/vitest-dev/vitest/tree/main/examples/basic?initialPath=__vitest__/) if it works. A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is always required no matter how easy it is to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided after 3 days, it will be auto-closed.
placeholder: Reproduction
validations:
required: true
- type: textarea
id: system-info
attributes:
label: System Info
description: Output of `npx envinfo --system --npmPackages '{vitest*,@vitest/*,vite,@vitejs/*,playwright,webdriverio}' --binaries --browsers`
render: shell
placeholder: System, Binaries, Browsers
validations:
required: true
- type: dropdown
id: package-manager
attributes:
label: Used Package Manager
description: Select the used package manager
options:
- npm
- yarn
- pnpm
- bun
validations:
required: true
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Follow our [Code of Conduct](https://github.com/vitest-dev/vitest/blob/main/CODE_OF_CONDUCT.md)
required: true
- label: Read the [Contributing Guidelines](https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md).
required: true
- label: Read the [docs](https://vitest.dev/guide/).
required: true
- label: Check that there isn't [already an issue](https://github.com/vitest-dev/vitest/issues) that reports the same bug to avoid creating a duplicate.
required: true
- label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions) or join our [Discord Chat Server](https://chat.vitest.dev).
required: true
- label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: VS Code Extension Issues
url: https://github.com/vitest-dev/vscode/issues/new/choose
about: VS Code extension related issues should be reported on the vitest-dev/vscode repository.
- name: Discord Chat
url: https://chat.vitest.dev
about: Ask questions and discuss with other Vitest users in real time.
- name: Questions & Discussions
url: https://github.com/vitest-dev/vitest/discussions
about: Use GitHub discussions for message-board style questions and discussions.
================================================
FILE: .github/ISSUE_TEMPLATE/docs.yml
================================================
name: 📚 Documentation
description: Suggest a change or new page to be added to vitest.dev
labels: [documentation]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this issue!
- type: checkboxes
id: documentation_is
attributes:
label: Documentation is
options:
- label: Missing
- label: Outdated
- label: Confusing
- label: Not sure?
- type: textarea
id: description
attributes:
label: Explain in Detail
description: A clear and concise description of your suggestion. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: The description of ... page is not clear. I thought it meant ... but it wasn't.
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: Your Suggestion for Changes
validations:
required: true
- type: input
id: reproduction
attributes:
label: Reproduction
description: If you have a reproduction, please provide a link via [vitest.new](https://vitest.new/) or a link to a repo that can reproduce the problem you ran into.
placeholder: Reproduction URL
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: 🚀 New feature proposal
description: Propose a new feature to be added to Vitest
labels: ['enhancement: pending triage']
type: Feature
body:
- type: markdown
attributes:
value: |
Thanks for your interest in the project and taking the time to fill out this feature report!
- type: textarea
id: feature-description
attributes:
label: Clear and concise description of the problem
description: 'As a developer using Vitest I want [goal / wish] so that [benefit]. If you intend to submit a PR for this issue, tell us in the description. Thanks!'
validations:
required: true
- type: textarea
id: suggested-solution
attributes:
label: Suggested solution
description: We could provide following implementation...
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Alternative
description: Clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Any other context or screenshots about the feature request here.
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Follow our [Code of Conduct](https://github.com/vitest-dev/vitest/blob/main/CODE_OF_CONDUCT.md)
required: true
- label: Read the [Contributing Guidelines](https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md).
required: true
- label: Read the [docs](https://vitest.dev/guide/).
required: true
- label: Check that there isn't already an issue that requests the same feature to avoid creating a duplicate.
required: true
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
### Description
Resolves #issue-number
### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
- [ ] Ideally, include a test that fails without this PR but passes with it.
- [ ] Please, don't make changes to `pnpm-lock.yaml` unless you introduce a new test example.
- [ ] Please check [Allow edits by maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) to make review process faster. Note that this option is not available for repositories that are owned by Github organizations.
### Tests
- [ ] Run the tests with `pnpm test:ci`.
### Documentation
- [ ] If you introduce new functionality, document it. You can run documentation with `pnpm run docs` command.
### Changesets
- [ ] Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with `feat:`, `fix:`, `perf:`, `docs:`, or `chore:`.
================================================
FILE: .github/actions/setup-and-cache/action.yml
================================================
name: Setup and cache
description: Setup for node, pnpm and cache for browser testing binaries
inputs:
node-version:
required: false
description: Node version for setup-node
default: 24.x
runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Set node version to ${{ inputs.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
cache: pnpm
================================================
FILE: .github/actions/setup-playwright/action.yml
================================================
name: Setup Playwright
description: Setup and cache Playwright browser binaries
runs:
using: composite
steps:
- name: Resolve package versions
id: resolve-package-versions
shell: bash
run: >
echo "$(
node -e "
const fs = require('fs');
const lockfile = fs.readFileSync('./pnpm-lock.yaml', 'utf8');
const pattern = (name) => new RegExp(name + ':\\\s+specifier: [\\\s\\\w\\\.^]+version: (\\\d+\\\.\\\d+\\\.\\\d+)');
const playwrightVersion = lockfile.match(pattern('playwright'))[1];
console.log('PLAYWRIGHT_VERSION=' + playwrightVersion);
"
)" >> $GITHUB_OUTPUT
- name: Print versions
shell: bash
run: echo "${{ toJson(steps.resolve-package-versions.outputs) }}"
- name: Check resolved package versions
shell: bash
if: |
contains(fromJSON('[null, "", "undefined"]'), steps.resolve-package-versions.outputs.PLAYWRIGHT_VERSION)
run: echo "Failed to resolve package versions. See log above." && exit 1
- name: Cache Playwright v${{ steps.resolve-package-versions.outputs.PLAYWRIGHT_VERSION }}
uses: actions/cache@v5
id: playwright-cache
with:
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
key: ${{ runner.os }}-playwright-${{ steps.resolve-package-versions.outputs.PLAYWRIGHT_VERSION }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Dependencies
shell: bash
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps --only-shell
================================================
FILE: .github/commit-convention.md
================================================
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
### TL;DR:
Messages must be matched by the following regex:
```js
/^(revert: )?(feat|fix|docs|dx|refactor|perf|test|workflow|build|ci|chore|types|wip|release|deps)(\(.+\))?: .{1,50}/
```
#### Examples
Appears under "Features" header, `dev` subheader:
```
feat(dev): add 'comments' option
```
Appears under "Bug Fixes" header, `dev` subheader, with a link to issue #28:
```
fix(dev): fix dev error
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(build): remove 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(compiler): add 'comments' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
():
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit .`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying the place of the commit change. For example `dev`, `build`, `workflow`, `cli` etc...
### Subject
The subject contains a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
================================================
FILE: .github/copilot-instructions.md
================================================
# copilot-instructions.md
This file provides guidance to Copilot Agent when working with code in this repository.
## Codebase Overview
Vitest is a next-generation testing framework powered by Vite. This is a monorepo using pnpm workspaces.
## Essential references
- Agent-specific guide: See [AGENTS.md](../AGENTS.md)
================================================
FILE: .github/renovate.json5
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended", "schedule:weekly", "group:allNonMajor"],
"labels": ["dependencies"],
"rangeStrategy": "bump",
"packageRules": [
{
"groupName": "Eslint packages",
"matchPackageNames": ["/eslint/"]
},
{
"matchDepTypes": ["peerDependencies"],
"enabled": false
},
{
"matchDepTypes": ["action"],
"matchPackageNames": ["!actions/{/,}**", "!github/{/,}**"],
"pinDigests": true
}
],
"ignoreDeps": [
// manually bumping
"node",
"vite",
// we patch these packages
"@types/chai",
"@sinonjs/fake-timers",
"cac",
// Transitive dependency that we patch
"acorn",
// Keep using codemirror 5
"codemirror",
"react-18",
"react-is-18",
// webdriverio removed provenance: https://github.com/webdriverio/webdriverio/issues/14887
"webdriverio"
],
"ignorePaths": [
"**/node_modules/**"
]
}
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.cache/ms-playwright
VITEST_GENERATE_UI_TOKEN: 'true'
jobs:
lint:
timeout-minutes: 10
runs-on: ubuntu-latest
name: 'Lint: node-latest, ubuntu-latest'
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-and-cache
- name: Install
run: pnpm i
- name: Build
run: pnpm run build
- name: Generate CLI docs
run: pnpm -C docs run cli-table
# check uncommited LICENSE.md, auto-imports.d.ts, etc...
- name: Check stale build artifacts
run: git diff --exit-code
- name: Lint
run: pnpm run lint
- name: Typecheck
run: pnpm run typecheck
- name: Typecheck UI
run: pnpm run -C packages/ui typecheck:client
# From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
- name: Check workflow files
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color -shellcheck=""
changed:
runs-on: ubuntu-latest
name: 'Diff: node-latest, ubuntu-latest'
outputs:
should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}
steps:
- uses: actions/checkout@v6
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
with:
files: |
docs/**
.github/**
!.github/workflows/ci.yml
**.md
test:
needs: changed
name: 'Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}'
if: needs.changed.outputs.should_skip != 'true'
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
matrix:
os: [ubuntu-latest]
node_version: [20, 22, 24]
include:
- os: macos-latest
node_version: 24
- os: windows-latest
node_version: 24
fail-fast: false
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-and-cache
with:
node-version: ${{ matrix.node_version }}
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
- name: Install
run: pnpm i
- uses: ./.github/actions/setup-playwright
- name: Build
run: pnpm run build
- name: Test
run: pnpm run test:ci
- name: Test Examples
run: pnpm run test:examples
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: playwright-report-${{ matrix.os }}-node-${{ matrix.node_version }}
path: test/ui/test-results/
retention-days: 30
test-cached:
needs: changed
name: 'Cache&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}'
if: needs.changed.outputs.should_skip != 'true'
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
matrix:
node_version: [24]
os:
- macos-latest
- windows-latest
fail-fast: false
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-and-cache
with:
node-version: ${{ matrix.node_version }}
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
- name: Install
run: pnpm i
- uses: ./.github/actions/setup-playwright
- name: Build
run: pnpm run build
- name: Test
run: pnpm run test:ci:cache
test-browser:
needs: changed
name: 'Browsers: node-${{ matrix.node_version }}, ${{ matrix.os }}'
if: needs.changed.outputs.should_skip != 'true'
runs-on: ${{ matrix.os }}
strategy:
matrix:
node_version: [24]
os:
- macos-latest
- windows-latest
fail-fast: false
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-and-cache
with:
node-version: ${{ matrix.node_version }}
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
- uses: browser-actions/setup-firefox@fcf821c621167805dd63a29662bd7cb5676c81a8 # v1.7.1
- name: Install
run: pnpm i
- uses: ./.github/actions/setup-playwright
- name: Build
run: pnpm run build
- name: Test Browser (playwright)
run: pnpm run test:browser:playwright
- name: Test Browser (webdriverio)
run: pnpm run test:browser:webdriverio
test-rolldown:
needs: changed
# macos-latest is the fastest one
name: 'Rolldown&Test: node-22, macos-latest'
if: needs.changed.outputs.should_skip != 'true'
runs-on: macos-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-and-cache
with:
node-version: 22
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
- name: Install
run: |
yq -i '.overrides.vite = "npm:vite@8"' pnpm-workspace.yaml
git add . && git commit -m "ci" && pnpm i --prefer-offline --no-frozen-lockfile
- uses: ./.github/actions/setup-playwright
- name: Build
run: pnpm run build
- name: Test
run: pnpm run test:ci:no-bail
- name: Test Examples
if: ${{ !cancelled() }}
run: pnpm run test:examples
- name: Test Browser (playwright)
if: ${{ !cancelled() }}
run: pnpm run test:browser:playwright
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: playwright-report-rolldown
path: rolldown/test/ui/test-results/
retention-days: 30
================================================
FILE: .github/workflows/cr.yml
================================================
name: CR
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, labeled]
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.number }}
cancel-in-progress: true
jobs:
release:
if: github.repository == 'vitest-dev/vitest' && (github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'cr-tracked'))
runs-on: ubuntu-latest
name: 'Release: pkg.pr.new'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Set node version to 20
uses: actions/setup-node@v6
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install
run: pnpm install --frozen-lockfile --prefer-offline
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
- name: Build
run: pnpm build
env:
VITEST_GENERATE_UI_TOKEN: 'true'
VITE_TEST_WATCHER_DEBUG: 'false'
- name: Publish to StackBlitz
run: pnpx pkg-pr-new publish --compact --no-template --pnpm './packages/*'
================================================
FILE: .github/workflows/ecosystem-ci-trigger.yml
================================================
name: ecosystem-ci trigger
on:
issue_comment:
types: [created]
jobs:
trigger:
runs-on: ubuntu-latest
if: github.repository == 'vitest-dev/vitest' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
permissions:
issues: write # to add / delete reactions, post comments
pull-requests: write # to read PR data, and to add labels
actions: read # to check workflow status
contents: read # to clone the repo
steps:
- uses: actions/github-script@v8
with:
script: |
const user = context.payload.sender.login
console.log(`Validate user: ${user}`)
let hasTriagePermission = false
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: user,
});
hasTriagePermission = data.user.permissions.triage
} catch (e) {
console.warn(e)
}
if (hasTriagePermission) {
console.log('Allowed')
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: '+1',
})
} else {
console.log('Not allowed')
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: '-1',
})
throw new Error('not allowed')
}
- uses: actions/github-script@v8
id: get-pr-data
with:
script: |
console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`)
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
})
return {
num: context.issue.number,
branchName: pr.head.ref,
repo: pr.head.repo.full_name
}
- id: generate-token
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0
with:
app_id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }}
installation_retrieval_payload: '${{ github.repository_owner }}/vitest-ecosystem-ci'
private_key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }}
- uses: actions/github-script@v8
id: trigger
env:
COMMENT: ${{ github.event.comment.body }}
PR_DATA: ${{ steps.get-pr-data.outputs.result }}
with:
github-token: ${{ steps.generate-token.outputs.token }}
result-encoding: string
script: |
const comment = process.env.COMMENT.trim()
const prData = JSON.parse(process.env.PR_DATA)
const suite = comment.split('\n')[0].replace(/^\/ecosystem-ci run/, '').trim()
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: 'vitest-ecosystem-ci',
workflow_id: 'ecosystem-ci-from-pr.yml',
ref: 'main',
inputs: {
prNumber: '' + prData.num,
branchName: prData.branchName,
repo: prData.repo,
suite: suite === '' ? '-' : suite
}
})
================================================
FILE: .github/workflows/issue-close-require.yml
================================================
name: Issue Close Require
on:
schedule:
- cron: '0 0 * * *'
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write # for actions-cool/issues-helper to update issues
steps:
- name: needs reproduction
uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6
with:
actions: close-issues
token: ${{ secrets.GITHUB_TOKEN }}
labels: needs reproduction
inactive-day: 3
================================================
FILE: .github/workflows/issue-labeled.yml
================================================
name: Issue Labeled
on:
issues:
types: [labeled]
jobs:
reply-labeled:
runs-on: ubuntu-latest
permissions:
issues: write # for actions-cool/issues-helper to update issues
steps:
- name: needs reproduction
if: github.event.label.name == 'needs reproduction'
uses: actions-cool/issues-helper@71b62d7da76e59ff7b193904feb6e77d4dbb2777 # v3.7.6
with:
actions: create-comment
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://vitest.new) (you can also use [examples](https://github.com/vitest-dev/vitest/tree/main/examples)). Issues marked with `needs reproduction` will be closed if they have no activity within 3 days.
================================================
FILE: .github/workflows/lock-closed-issues.yml
================================================
name: Lock Closed Issues
on:
schedule:
- cron: '0 0 * * *'
permissions:
issues: write
jobs:
action:
if: github.repository == 'vitest-dev/vitest'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v6.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '14'
pr-inactive-days: '14'
issue-lock-reason: ''
pr-lock-reason: ''
process-only: issues,prs
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish Package
on:
push:
tags:
- 'v*'
permissions:
contents: write
id-token: write
env:
VITEST_GENERATE_UI_TOKEN: 'true'
VITE_TEST_WATCHER_DEBUG: 'false'
jobs:
publish:
if: github.repository == 'vitest-dev/vitest'
runs-on: ubuntu-latest
environment: Release
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0
- name: Set node version to 20
uses: actions/setup-node@v6
with:
node-version: 20
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install
run: pnpm install --frozen-lockfile --prefer-offline
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
- name: Build
run: pnpm build
- name: Publish to npm
run: npm i -g npm@^11.5.2 && pnpm run publish-ci ${{ github.ref_name }}
- name: Generate Changelog
run: npx changelogithub
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.cpuprofile
*.heapprofile
lib-cov
coverage
!**/integrations/coverage
node_modules
.env
.cache
dist
.idea
.vite-node
ltex*
.DS_Store
.zed
bench/test/*/*/
**/bench.json
**/browser/browser.json
docs/public/user-avatars
.eslintcache
docs/.vitepress/cache/
!test/cli/fixtures/dotted-files/**/.cache
test/**/__screenshots__/**/*
test/**/__traces__/**/*
test/browser/fixtures/update-snapshot/basic.test.ts
test/cli/fixtures/browser-multiple/basic-*
.vitest-reports
*.tsbuildinfo
# exclude static html reporter folder
test/browser/html/
test/core/html/
.vitest-attachments
explainFiles.txt
.vitest-dump
================================================
FILE: .npmrc
================================================
ignore-workspace-root-check=true
strict-peer-dependencies=false
provenance=true
shell-emulator=true
registry=https://registry.npmjs.org/
VITEST_MODULE_DIRECTORIES=/node_modules/,/packages/
================================================
FILE: .tazerc.json
================================================
{
"exclude": [
"vue",
"pretty-format"
],
"packageMode": {
"vue": "minor",
"codemirror": "minor",
"rollup": "minor"
}
}
================================================
FILE: .vscode/extensions.json
================================================
{
"recommendations": [
"vitest.explorer",
"dbaeumer.vscode-eslint"
]
}
================================================
FILE: .vscode/settings.json
================================================
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in you IDE, but still auto fix them
// "eslint.rules.customizations": [
// { "rule": "style/*", "severity": "off" },
// { "rule": "*-indent", "severity": "off" },
// { "rule": "*-spacing", "severity": "off" },
// { "rule": "*-spaces", "severity": "off" },
// { "rule": "*-order", "severity": "off" },
// { "rule": "*-dangle", "severity": "off" },
// { "rule": "*-newline", "severity": "off" },
// { "rule": "*quotes", "severity": "off" },
// { "rule": "*semi", "severity": "off" }
// ],
"vitest.ignoreWorkspace": true,
"vitest.configSearchPatternInclude": "test/{core,cli,config,browser,reporters}/{vitest,vite}.{config.ts,config.unit.mts}",
"testing.automaticallyOpenTestResults": "neverOpen",
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
],
// Use the project's typescript version
"typescript.tsdk": "node_modules/typescript/lib"
}
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "dev",
"label": "npm: dev",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
},
"background": {
"activeOnStart": true,
"beginsPattern": "bundes",
"endsPattern": "created"
}
}
},
{
"type": "npm",
"script": "ui:dev",
"label": "npm: ui",
"isBackground": true,
"dependsOn": ["npm: test"],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
},
"background": {
"activeOnStart": true,
"beginsPattern": "dev server running at",
"endsPattern": "ready in"
}
}
},
{
"type": "npm",
"script": "test",
"label": "npm: test",
"isBackground": true,
"dependsOn": ["npm: dev"],
"detail": "vitest -r test/core --api",
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
},
"background": {
"activeOnStart": true,
"beginsPattern": "WATCH",
"endsPattern": "Waiting for"
}
}
},
{
"type": "npm",
"script": "ci",
"problemMatcher": [],
"label": "npm: ci"
}
]
}
================================================
FILE: AGENTS.md
================================================
# Vitest AI Agent Guide
This document provides comprehensive information for AI agents working on the Vitest codebase.
## Project Overview
Vitest is a next-generation testing framework powered by Vite. This is a monorepo using pnpm workspaces with the following key characteristics:
- **Language**: TypeScript/JavaScript (ESM-first)
- **Package Manager**: pnpm (required)
- **Node Version**: ^20.0.0 || ^22.0.0 || >=24.0.0
- **Build System**: Vite + Rollup
- **Monorepo Structure**: 15+ packages in `packages/` directory
## Setup and Development
### Initial Setup
1. Run `pnpm install` to install dependencies
2. Run `pnpm build` to build all packages
3. Install Playwright browsers when working with browser features: `npx playwright install --with-deps`
### Key Scripts
- `pnpm build` - Build all packages
- `pnpm dev` - Watch mode for development
- `pnpm lint` - Run ESLint
- `pnpm lint:fix` - Fix linting issues automatically
- `pnpm typecheck` - Run TypeScript type checking
## Testing
### Running Tests
- **All tests**: `CI=true pnpm test:ci`
- **Examples**: `CI=true pnpm test:examples`
- **Specific test suite**: `CI=true cd test/ && pnpm test `
- **Core directory test**: `CI=true pnpm test ` (for `test/core`)
- **Browser tests**: `CI=true pnpm test:browser:playwright` or `CI=true pnpm test:browser:webdriverio`
**IMPORTANT: Do NOT use `--` when passing test filters to pnpm.**
Using `--` causes pnpm to drop the filter, resulting in a full test run instead of a filtered one.
```bash
# WRONG - runs ALL tests (filter is ignored):
pnpm test -- basic.test.ts -t 'expect'
# CORRECT - runs only matching tests:
pnpm test basic.test.ts -t 'expect'
```
When writing tests, AVOID using `toContain` for validation. Prefer using `toMatchInlineSnapshot` to include the test error and its stack. If snapshot is failing, update the snapshot instead of reverting it to `toContain`.
If you need to typecheck tests, run `pnpm typecheck` from the root of the workspace.
### Testing Utilities
- **`runInlineTests`** from `test/test-utils/index.ts` - You must use this for complex file system setups (>1 file)
- **`runVitest`** from `test/test-utils/index.ts` - You can use this to run Vitest programmatically
- **No mocking policy** - You must never mock anything in tests
## Project Structure
### Core Packages (`packages/`)
- `vitest` - Main testing framework
- `browser` - Browser testing support
- `ui` - Web UI for test results
- `runner` - Test runner core
- `expect` - Assertion library
- `spy` - Mocking and spying utilities
- `snapshot` - Snapshot testing
- `coverage-v8` / `coverage-istanbul` - Code coverage
- `utils` - Shared utilities
- `mocker` - Module mocking
### Test Organization (`test/`)
- `test/core` - Core functionality tests
- `test/browser` - Browser-specific tests
- Various test suites organized by feature
### Important Directories
- `docs/` - Documentation (Vite-powered)
- `examples/` - Example projects and integrations
- `scripts/` - Build and development scripts
- `.github/` - GitHub Actions workflows
- `patches/` - Package patches via pnpm
## Code Style and Conventions
### Formatting and Linting
- **Always run** `pnpm lint:fix` after making changes
- Fix non-auto-fixable errors manually
### TypeScript
- Strict TypeScript configuration
- Use `pnpm typecheck` to verify types
- Configuration files: `tsconfig.base.json`, `tsconfig.build.json`, `tsconfig.check.json`
### Code Quality
- ESM-first approach
- Follow existing patterns in the codebase
- Use utilities from `@vitest/utils/*` when available. Never import from `@vitest/utils` main entry point directly.
- Do not add comments explaining what the line does unless prompted to.
## Common Workflows
### Adding New Features
1. Identify the appropriate package in `packages/`
2. Follow existing code patterns
3. Add tests using testing utilities
4. Run `pnpm build && pnpm typecheck && pnpm lint:fix`
5. Add tests with relevant test suites
### Debugging
- Use VS Code: `⇧⌘B` (Shift+Cmd+B) or `Ctrl+Shift+B` for dev tasks
- Check `scripts/` directory for specialized development tools
### Documentation
- Main docs in `docs/` directory
- Built with `pnpm docs:build`
- Local dev server: `pnpm docs`
- When adding cli options, run `pnpm -C docs run cli-table` to update the cli-generated.md file
## Dependencies and Tools
### Key Dependencies
- **Vite** - Build tool and dev server
- **Rollup** - Bundler
- **ESLint** - Linting
- **TypeScript** - Type checking
- **Playwright** - Browser testing
- **Chai/Expect** - Assertions
- **Tinypool** - Worker threading
- **Tinybench** - Benchmarking
### Development Tools
- **tsx** - TypeScript execution
- **ni/nr** - Package manager abstraction
- **bumpp** - Version bumping
- **changelogithub** - Changelog generation
## Browser Testing
- Two modes: Playwright and WebDriverIO
- Separate test commands for each
- Component testing supported (Vue, React, Svelte, Lit, Marko)
## Performance Considerations
- This is a performance-critical testing framework
- Pay attention to import costs and bundle size
- Use lazy loading where appropriate
- Consider worker thread implications
## Troubleshooting
### Common Issues
- Ensure pnpm is used (not npm/yarn)
- Build before running tests
- Check Node.js version compatibility
- Playwright browsers must be installed for browser tests
### Getting Help
- Check existing issues and documentation
- Review CONTRIBUTING.md for detailed guidelines
- Follow patterns in existing code
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Codebase Overview
Vitest is a next-generation testing framework powered by Vite. This is a monorepo using pnpm workspaces.
## Essential references
- Agent-specific guide: See [AGENTS.md](AGENTS.md)
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code Of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, political party, or sexual identity and orientation. Note, however, that religion, political party, or other ideological affiliation provide no exemptions for the behavior we outline as unacceptable in this Code of Conduct.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team by sending an e-mail to vitest.dev@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
================================================
FILE: CONTRIBUTING.md
================================================
# Vitest Contributing Guide
Hi! We are really excited that you are interested in contributing to Vitest. Before submitting your contribution, please make sure to take a moment and read through the following guide:
## Repo Setup
The Vitest repo is a monorepo using pnpm workspaces. The package manager used to install and link dependencies must be [pnpm](https://pnpm.io/).
We recommend installing [ni](https://github.com/antfu/ni) to help switching between repos using different package managers. `ni` also provides the handy `nr` command which running npm scripts easier:
- `ni` is equivalent to `pnpm install`
- `nr test` is equivalent to `pnpm run test`
To develop and test `vitest` package:
1. Run `pnpm install` in `vitest`'s root folder
2. Run `pnpm run build` to build all monorepo packages
- after this, you can use `pnpm run dev` to rebuild packages as you modify code
3. Run
- `pnpm run test` to run core tests
- `pnpm run test:ci` to run all the suite
- `cd test/(dir) && pnpm run test` to run a specific test suite
> 💡 If you use VS Code, you can hit `⇧ ⌘ B` or `Ctrl + Shift + B` to launch all the necessary dev tasks.
### UI Development
If you want to improve Vitest Browser Mode, see the [Browser Mode development guide](./packages/ui/README.md) for setup instructions and development workflow.
## Debugging
### VS Code
If you want to use break point and explore code execution you can use the ["Run and debug"](https://code.visualstudio.com/docs/debugtest/debugging) feature from vscode.
1. Add a `debugger` statement where you want to stop the code execution.
2. Click on the "Run and Debug" icon in the activity bar of the editor.
3. Click on the "Javascript Debug Terminal" button.
4. It will open a terminal, then type the test command: `pnpm run test`
5. The execution will stop and you'll use the [Debug toolbar](https://code.visualstudio.com/docs/debugtest/debugging#_debug-actions) to continue, step over, restart the process...
## Testing Vitest against external packages
You may wish to test your locally-modified copy of Vitest against another package that is using it. For pnpm, after building Vitest, you can use [`pnpm.overrides`](https://pnpm.io/9.x/package_json#pnpmoverrides). Please note that `pnpm.overrides` must be specified in the root `package.json` and you must first list the package as a dependency in the root `package.json`:
```json
{
"dependencies": {
"vitest": "*"
},
"pnpm": {
"overrides": {
"vitest": "link:../path/to/vitest/packages/vitest"
}
}
}
```
And re-run `pnpm install` to link the package.
Add a `.npmrc` file with following line next to the `package.json`:
```sh
VITEST_MODULE_DIRECTORIES=/node_modules/,/packages/
```
## Pull Request Guidelines
- Checkout a topic branch from a base branch, e.g. `main`, and merge back against that branch.
- If adding a new feature:
- Add accompanying test case.
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- When adding cli options, run `pnpm -C docs run cli-table` to update the cli-generated.md file
- If fixing bug:
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`.
- Provide a detailed description of the bug in the PR. Live demo preferred.
- Add appropriate test coverage if applicable.
- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.
- Make sure tests pass!
- Commit messages must follow the [commit message convention](./.github/commit-convention.md) so that changelogs can be automatically generated.
- Use `pnpm run lint:fix` to format files according to the project guidelines.
## Maintenance Guidelines
> The following section is mostly for maintainers who have commit access, but it's helpful to go through if you intend to make non-trivial contributions to the codebase.
### Issue Triaging Workflow
```mermaid
flowchart TD
start{Followed issue template?}
start --NO--> close1[Close and ask to follow template]
start --YES--> dupe{Is duplicate?}
dupe --YES--> close2[Close and point to duplicate]
dupe --NO--> repro{Has proper reproduction?}
repro --NO--> close3[Label: 'needs reproduction' bot will auto close if no update has been made in 3 days]
repro --YES--> real{Is actually a bug?}
real --NO--> intended{Is the intended behaviour?}
intended --YES--> explain[Explain and close point to docs if needed]
intended --NO--> open[Keep open for discussion Remove 'pending triage' label]
real --YES--> real2["1. Remove 'pending triage' label 2. Add related feature label if applicable (e.g. 'feat: browser') 3. Add priority and meta labels (see below)"]
real2 --> unusable{Does the bug make Vitest unusable?}
unusable --YES--> maj{Does the bug affect the majority of Vitest users?}
maj --YES--> p5[p5: urgent]
maj --NO--> p4[p4: important]
unusable --NO--> workarounds{Are there workarounds for the bug?}
workarounds --YES--> p2[p2: edge case has workaround]
workarounds --NO--> p3[p3: minor bug]
```
### Pull Request Review Workflow
```mermaid
flowchart TD
start{Bug fix or feature}
start --BUG FIX--> strict_bug{"Is a 'strict fix' i.e. fixes an obvious oversight with no side effects"}
start --FEATURE--> feature[- Discuss feature necessity - Is this the best way to address the need - Review code quality - Add feature labels - Approve if you feel strongly that the feature is needed]
feature --> merge
strict_bug --YES--> strict[- Verify the fix locally - Review code quality - Require test case if applicable - Request changes if necessary]
strict_bug --NO--> non_strict[- Discuss the potential side effects of the fix, e.g. - Could it introduce implicit behavior changes in other cases? - Does it introduce too much changes?]
non_strict --> label["Add priority labels (see issue triaging workflow)"]
strict --> label
label --> approve
approve --> merge["Merge if approved by 2 or more team members - Use 'Squash and Merge' - Edit commit message to follow convention - In commit message body, list relevant issues being fixed e.g. 'fix #1234, fix #1235'"]
```
## Notes on Dependencies
Vitest aims to be lightweight, and this includes being aware of the number of npm dependencies and their size.
### Think before adding a dependency
Most deps should be added to `devDependencies` even if they are needed at runtime. Some exceptions are:
- Type packages. Example: `@types/*`.
- Deps that cannot be properly bundled due to binary files.
- Deps that ships its own types and its type is used in vitest's own public types.
Avoid deps that has large transitive dependencies that results in bloated size compared to the functionality it provides.
If there are libraries that are needed and don't comply with our size
requirements, a fork can be tried to reduce its size while we work with them to
upstream our changes.
### Think before adding yet another option
We already have many config options, and we should avoid fixing an issue by adding yet another one. Before adding an option, try to think about:
- Whether the problem is really worth addressing
- Whether the problem can be fixed with a smarter default
- Whether the problem has workaround using existing options
- Whether the problem can be addressed with a plugin instead
================================================
FILE: FUNDING.json
================================================
{
"drips": {
"ethereum": {
"ownedBy": "0x929Eb10Cf1621b26199120a521C785F8271e0b78"
}
}
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Vitest
Next generation testing framework powered by Vite.
Get involved!
Documentation | Getting Started | Examples | Why Vitest?
中文文档
## Features
- [Vite](https://vitejs.dev/)'s config, transformers, resolvers, and plugins. Use the same setup from your app!
- [Jest Snapshot](https://jestjs.io/docs/snapshot-testing)
- [Chai](https://www.chaijs.com/) built-in for assertions, with [Jest expect](https://jestjs.io/docs/expect) compatible APIs
- [Smart & instant watch mode](https://vitest.dev/guide/features.html#watch-mode), like HMR for tests!
- [Native code coverage](https://vitest.dev/guide/features.html#coverage) via [`v8`](https://v8.dev/blog/javascript-code-coverage) or [`istanbul`](https://istanbul.js.org/).
- [Tinyspy](https://github.com/tinylibs/tinyspy) built-in for mocking, stubbing, and spies.
- [JSDOM](https://github.com/jsdom/jsdom) and [happy-dom](https://github.com/capricorn86/happy-dom) for DOM and browser API mocking
- [Browser Mode](https://vitest.dev/guide/browser/) for running component tests in the browser
- Components testing ([Vue](https://github.com/vitest-tests/browser-examples/tree/main/examples/vue), [React](https://github.com/vitest-tests/browser-examples/tree/main/examples/react), [Svelte](https://github.com/vitest-tests/browser-examples/tree/main/examples/svelte), [Lit](./examples/lit), [Marko](https://github.com/marko-js/examples/tree/master/examples/library-ts))
- Benchmarking support with [Tinybench](https://github.com/tinylibs/tinybench)
- [Projects](https://vitest.dev/guide/projects) support
- [expect-type](https://github.com/mmkal/expect-type) for type-level testing
- ESM first, top level await
- Out-of-box TypeScript / JSX support
- Filtering, timeouts, concurrent for suite and tests
- Sharding support
- Reporting Uncaught Errors
- Run your tests in the browser natively
> Vitest requires Vite >=v6.0.0 and Node >=v20.0.0
```ts
import { assert, describe, expect, it } from 'vitest'
describe('suite name', () => {
it('foo', () => {
expect(1 + 1).toEqual(2)
expect(true).to.be.true
})
it('bar', () => {
assert.equal(Math.sqrt(4), 2)
})
it('snapshot', () => {
expect({ foo: 'bar' }).toMatchSnapshot()
})
})
```
```bash
$ npx vitest
```
## Sponsors
### Vladimir Sponsors
### Anthony Fu Sponsors
### Patak Sponsors
## Credits
Thanks to:
- [The Jest team and community](https://jestjs.io/) for creating a delightful testing API
- [@lukeed](https://github.com/lukeed) for the work on [uvu](https://github.com/lukeed/uvu) where we are inspired a lot from.
- [@pi0](https://github.com/pi0) for the idea and implementation of using Vite to transform and bundle the server code.
- [The Vite team](https://github.com/vitejs/vite) for brainstorming the initial idea.
- [@patak-dev](https://github.com/patak-dev) for the awesome package name!
## Contribution
See [Contributing Guide](https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md).
## License
[MIT](./LICENSE) License © 2021-Present VoidZero Inc. and Vitest contributors
================================================
FILE: SECURITY.md
================================================
# Reporting a Vulnerability
To report a vulnerability, please open a private vulnerability report at https://github.com/vitest-dev/vitest/security.
While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vitest to ensure your application remains as secure as possible.
================================================
FILE: docs/.vitepress/blog.data.ts
================================================
import { createContentLoader } from 'vitepress'
interface Post {
title: string
url: string
date: {
time: number
string: string
}
}
declare const data: Post[]
export { data }
export default createContentLoader('blog/*.md', {
// excerpt: true,
transform(raw): Post[] {
return raw
.map(({ url, frontmatter }) => ({
title: frontmatter.head.find((e: any) => e[1].property === 'og:title')[1]
.content,
url,
date: formatDate(frontmatter.date),
}))
.sort((a, b) => b.date.time - a.date.time)
},
})
function formatDate(raw: string): Post['date'] {
const date = new Date(raw)
date.setUTCHours(12)
return {
time: +date,
string: date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
}),
}
}
================================================
FILE: docs/.vitepress/components/Advanced.vue
================================================
advanced
================================================
FILE: docs/.vitepress/components/ArrowDown.vue
================================================
================================================
FILE: docs/.vitepress/components/BlogIndex.vue
================================================
================================================
FILE: docs/.vitepress/components/Box.vue
================================================
================================================
FILE: docs/.vitepress/components/CRoot.vue
================================================
================================================
FILE: docs/.vitepress/components/CourseLink.vue
================================================
================================================
FILE: docs/.vitepress/components/Deprecated.vue
================================================
deprecated
================================================
FILE: docs/.vitepress/components/Experimental.vue
================================================
experimental
================================================
FILE: docs/.vitepress/components/FeaturesList.vue
================================================
Vite 's config, transformers, resolvers, and plugins
Use the same setup from your app to run the tests!
Smart & instant watch mode, like HMR for tests!
Component testing for Vue, React, Svelte, Lit, Marko and more
Out-of-the-box TypeScript / JSX support
ESM first, top level await
Benchmarking support with Tinybench
Filtering, timeouts, concurrent for suite and tests
Projects support
Jest-compatible Snapshot
Chai built-in for assertions + Jest expect compatible APIs
Tinyspy built-in for mocking
happy-dom or jsdom for DOM mocking
Browser Mode for running component tests in the browser
Code coverage via v8 or istanbul
Rust-like in-source testing
Type Testing via expect-type
Sharding Support
Reporting Uncaught Errors
================================================
FILE: docs/.vitepress/components/HomePage.vue
================================================
================================================
FILE: docs/.vitepress/components/ListItem.vue
================================================
================================================
FILE: docs/.vitepress/components/Version.vue
================================================
+
================================================
FILE: docs/.vitepress/config.ts
================================================
import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
import { transformerNotationWordHighlight } from '@shikijs/transformers'
import { withPwa } from '@vite-pwa/vitepress'
import { defineConfig } from 'vitepress'
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
import {
groupIconMdPlugin,
groupIconVitePlugin,
} from 'vitepress-plugin-group-icons'
import llmstxt from 'vitepress-plugin-llms'
import { version } from '../../package.json'
import { teamMembers } from './contributors'
import {
bluesky,
contributing,
discord,
font,
github,
mastodon,
ogImage,
ogUrl,
releases,
vitestDescription,
vitestName,
} from './meta'
import { pwa } from './scripts/pwa'
import { transformHead } from './scripts/transformHead'
import { extendConfig } from '@voidzero-dev/vitepress-theme/config'
export default ({ mode }: { mode: string }) => {
return withPwa(extendConfig(defineConfig({
lang: 'en-US',
title: vitestName,
description: vitestDescription,
srcExclude: [
'**/guide/examples/*',
'**/guide/cli-generated.md',
],
locales: {
root: {
label: 'English',
lang: 'en-US',
},
zh: {
label: '简体中文',
lang: 'zh',
link: 'https://cn.vitest.dev/',
},
},
head: [
['meta', { name: 'theme-color', content: '#22FF84' }],
['link', { rel: 'icon', href: '/favicon.ico', sizes: '48x48' }],
['link', { rel: 'icon', href: '/logo-without-border.svg', type: 'image/svg+xml' }],
['meta', { name: 'author', content: `${teamMembers.map(c => c.name).join(', ')} and ${vitestName} contributors` }],
['meta', { name: 'keywords', content: 'vitest, vite, test, coverage, snapshot, react, vue, preact, svelte, solid, lit, marko, ruby, cypress, puppeteer, jsdom, happy-dom, test-runner, jest, typescript, esm, tinyspy, node' }],
['meta', { property: 'og:title', content: vitestName }],
['meta', { property: 'og:description', content: vitestDescription }],
['meta', { property: 'og:url', content: ogUrl }],
['meta', { property: 'og:image', content: ogImage }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['link', { rel: 'preload', as: 'style', onload: 'this.onload=null;this.rel=\'stylesheet\'', href: font }],
['noscript', {}, ` `],
['link', { rel: 'me', href: 'https://m.webtoo.ls/@vitest' }],
['link', { rel: 'mask-icon', href: '/logo.svg', color: '#ffffff' }],
['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }],
[
'script',
{
'src': 'https://cdn.usefathom.com/script.js',
'data-site': 'BEAFAKYG',
'data-spa': 'auto',
'defer': '',
},
],
],
lastUpdated: true,
vite: {
plugins: [
groupIconVitePlugin({
customIcon: {
'CLI': 'vscode-icons:file-type-shell',
'.spec.ts': 'vscode-icons:file-type-testts',
'.test.ts': 'vscode-icons:file-type-testts',
'.spec.js': 'vscode-icons:file-type-testjs',
'.test.js': 'vscode-icons:file-type-testjs',
'next': '',
},
}),
llmstxt(),
],
},
markdown: {
config(md) {
md.use(tabsMarkdownPlugin)
md.use(groupIconMdPlugin)
},
theme: {
light: 'github-light',
dark: 'github-dark',
},
codeTransformers: mode === 'development'
? [transformerNotationWordHighlight()]
: [
transformerNotationWordHighlight(),
transformerTwoslash({
processHoverInfo: (info) => {
if (info.includes(process.cwd())) {
return info.replace(new RegExp(process.cwd(), 'g'), '')
}
return info
},
}),
],
languages: ['js', 'jsx', 'ts', 'tsx'],
},
themeConfig: {
variant: 'vitest',
logo: '/logo.svg',
editLink: {
pattern: 'https://github.com/vitest-dev/vitest/edit/main/docs/:path',
text: 'Suggest changes to this page',
},
search: {
provider: 'local',
/* provider: 'algolia',
options: {
appId: 'ZTF29HGJ69',
apiKey: '9c3ced6fed60d2670bb36ab7e8bed8bc',
indexName: 'vitest',
// searchParameters: {
// facetFilters: ['tags:en'],
// },
}, */
},
banner: {
id: 'viteplus-alpha',
text: 'Announcing Vite+ Alpha: Open source. Unified. Next-gen.',
url: 'https://voidzero.dev/posts/announcing-vite-plus-alpha?utm_source=vitest&utm_content=top_banner',
},
carbonAds: {
code: 'CW7DVKJE',
placement: 'vitestdev',
},
socialLinks: [
{ icon: 'bluesky', link: bluesky },
{ icon: 'mastodon', link: mastodon },
{ icon: 'discord', link: discord },
{ icon: 'github', link: github },
],
footer: {
copyright: `© ${new Date().getFullYear()} VoidZero Inc. and Vitest contributors.`,
nav: [
{
title: 'Vitest',
items: [
{ text: 'Guides', link: '/guide/' },
{ text: 'API', link: '/api/test' },
{ text: 'Config', link: '/config/' },
],
},
{
title: 'Resources',
items: [
{ text: 'Team', link: '/team' },
{ text: 'Blog', link: '/blog' },
{ text: 'Releases', link: releases },
],
},
{
title: 'Versions',
items: [
{ text: 'Unreleased Docs', link: 'https://main.vitest.dev/' },
{ text: 'Vitest v3 Docs', link: 'https://v3.vitest.dev/' },
{ text: 'Vitest v2 Docs', link: 'https://v2.vitest.dev/' },
{ text: 'Vitest v1 Docs', link: 'https://v1.vitest.dev/' },
{ text: 'Vitest v0 Docs', link: 'https://v0.vitest.dev/' },
],
},
/* {
title: 'Legal',
items: [
{ text: 'Terms & Conditions', link: 'https://voidzero.dev/terms' },
{ text: 'Privacy Policy', link: 'https://voidzero.dev/privacy' },
{ text: 'Cookie Policy', link: 'https://voidzero.dev/cookies' },
],
}, */
],
social: [
{ icon: 'github', link: github },
{ icon: 'discord', link: discord },
// { icon: 'mastodon', link: mastodon }, -- the link shows github
{ icon: 'bluesky', link: bluesky },
],
},
nav: [
{ text: 'Guides', link: '/guide/', activeMatch: '^/guide/' },
{ text: 'API', link: '/api/test', activeMatch: '^/api/' },
{ text: 'Config', link: '/config/', activeMatch: '^/config/' },
{
text: 'Blog',
link: '/blog',
},
{
text: `v${version}`,
items: [
{
items: [
{
text: `v${version}`,
link: `https://github.com/vitest-dev/vitest/releases/tag/v${version}`,
},
{
text: 'Releases Notes',
link: releases,
},
{
text: 'Contributing',
link: contributing,
},
{
text: 'Team',
link: '/team',
},
],
},
{
items: [
{
text: 'unreleased',
link: 'https://main.vitest.dev/',
},
{
text: 'v3.x',
link: 'https://v3.vitest.dev/',
},
{
text: 'v2.x',
link: 'https://v2.vitest.dev/',
},
{
text: 'v1.x',
link: 'https://v1.vitest.dev/',
},
{
text: 'v0.x',
link: 'https://v0.vitest.dev/',
},
],
},
],
},
],
sidebar: {
'/config': [
{
text: 'Config Reference',
collapsed: false,
items: [
{
text: 'Config File',
link: '/config/',
},
{
text: 'include',
link: '/config/include',
},
{
text: 'exclude',
link: '/config/exclude',
},
{
text: 'includeSource',
link: '/config/include-source',
},
{
text: 'name',
link: '/config/name',
},
{
text: 'server',
link: '/config/server',
},
{
text: 'deps',
link: '/config/deps',
},
{
text: 'runner',
link: '/config/runner',
},
{
text: 'benchmark',
link: '/config/benchmark',
},
{
text: 'alias',
link: '/config/alias',
},
{
text: 'globals',
link: '/config/globals',
},
{
text: 'environment',
link: '/config/environment',
},
{
text: 'environmentOptions',
link: '/config/environmentoptions',
},
{
text: 'watch',
link: '/config/watch',
},
{
text: 'watchTriggerPatterns',
link: '/config/watchtriggerpatterns',
},
{
text: 'root',
link: '/config/root',
},
{
text: 'dir',
link: '/config/dir',
},
{
text: 'reporters',
link: '/config/reporters',
},
{
text: 'outputFile',
link: '/config/outputfile',
},
{
text: 'pool',
link: '/config/pool',
},
{
text: 'execArgv',
link: '/config/execargv',
},
{
text: 'vmMemoryLimit',
link: '/config/vmmemorylimit',
},
{
text: 'fileParallelism',
link: '/config/fileparallelism',
},
{
text: 'maxWorkers',
link: '/config/maxworkers',
},
{
text: 'testTimeout',
link: '/config/testtimeout',
},
{
text: 'hookTimeout',
link: '/config/hooktimeout',
},
{
text: 'teardownTimeout',
link: '/config/teardowntimeout',
},
{
text: 'silent',
link: '/config/silent',
},
{
text: 'setupFiles',
link: '/config/setupfiles',
},
{
text: 'provide',
link: '/config/provide',
},
{
text: 'globalSetup',
link: '/config/globalsetup',
},
{
text: 'forceRerunTriggers',
link: '/config/forcereruntriggers',
},
{
text: 'coverage',
link: '/config/coverage',
},
{
text: 'testNamePattern',
link: '/config/testnamepattern',
},
{
text: 'ui',
link: '/config/ui',
},
{
text: 'open',
link: '/config/open',
},
{
text: 'api',
link: '/config/api',
},
{
text: 'clearMocks',
link: '/config/clearmocks',
},
{
text: 'mockReset',
link: '/config/mockreset',
},
{
text: 'restoreMocks',
link: '/config/restoremocks',
},
{
text: 'unstubEnvs',
link: '/config/unstubenvs',
},
{
text: 'unstubGlobals',
link: '/config/unstubglobals',
},
{
text: 'snapshotFormat',
link: '/config/snapshotformat',
},
{
text: 'snapshotSerializers',
link: '/config/snapshotserializers',
},
{
text: 'resolveSnapshotPath',
link: '/config/resolvesnapshotpath',
},
{
text: 'allowOnly',
link: '/config/allowonly',
},
{
text: 'passWithNoTests',
link: '/config/passwithnotests',
},
{
text: 'logHeapUsage',
link: '/config/logheapusage',
},
{
text: 'css',
link: '/config/css',
},
{
text: 'maxConcurrency',
link: '/config/maxconcurrency',
},
{
text: 'cache',
link: '/config/cache',
},
{
text: 'sequence',
link: '/config/sequence',
},
{
text: 'tags',
link: '/config/tags',
},
{
text: 'strictTags',
link: '/config/stricttags',
},
{
text: 'typecheck',
link: '/config/typecheck',
},
{
text: 'slowTestThreshold',
link: '/config/slowtestthreshold',
},
{
text: 'chaiConfig',
link: '/config/chaiconfig',
},
{
text: 'bail',
link: '/config/bail',
},
{
text: 'retry',
link: '/config/retry',
},
{
text: 'onConsoleLog',
link: '/config/onconsolelog',
},
{
text: 'onStackTrace',
link: '/config/onstacktrace',
},
{
text: 'onUnhandledError',
link: '/config/onunhandlederror',
},
{
text: 'dangerouslyIgnoreUnhandled...',
link: '/config/dangerouslyignoreunhandlederrors',
},
{
text: 'diff',
link: '/config/diff',
},
{
text: 'fakeTimers',
link: '/config/faketimers',
},
{
text: 'projects',
link: '/config/projects',
},
{
text: 'isolate',
link: '/config/isolate',
},
{
text: 'includeTaskLocation',
link: '/config/includetasklocation',
},
{
text: 'snapshotEnvironment',
link: '/config/snapshotenvironment',
},
{
text: 'env',
link: '/config/env',
},
{
text: 'expect',
link: '/config/expect',
},
{
text: 'printConsoleTrace',
link: '/config/printconsoletrace',
},
{
text: 'attachmentsDir',
link: '/config/attachmentsdir',
},
{
text: 'hideSkippedTests',
link: '/config/hideskippedtests',
},
{
text: 'mode',
link: '/config/mode',
},
{
text: 'expandSnapshotDiff',
link: '/config/expandsnapshotdiff',
},
{
text: 'disableConsoleIntercept',
link: '/config/disableconsoleintercept',
},
{
text: 'experimental',
link: '/config/experimental',
},
],
},
{
text: 'Browser Mode',
collapsed: false,
items: [
{
text: 'Providers',
collapsed: false,
items: [
{
text: 'playwright',
link: '/config/browser/playwright',
},
{
text: 'webdriverio',
link: '/config/browser/webdriverio',
},
{
text: 'preview',
link: '/config/browser/preview',
},
],
},
{
text: 'browser.enabled',
link: '/config/browser/enabled',
},
{
text: 'browser.instances',
link: '/config/browser/instances',
},
{
text: 'browser.headless',
link: '/config/browser/headless',
},
{
text: 'browser.isolate',
link: '/config/browser/isolate',
},
{
text: 'browser.testerHtmlPath',
link: '/config/browser/testerhtmlpath',
},
{
text: 'browser.api',
link: '/config/browser/api',
},
{
text: 'browser.provider',
link: '/config/browser/provider',
},
{
text: 'browser.ui',
link: '/config/browser/ui',
},
{
text: 'browser.detailsPanelPosition',
link: '/config/browser/detailspanelposition',
},
{
text: 'browser.viewport',
link: '/config/browser/viewport',
},
{
text: 'browser.locators',
link: '/config/browser/locators',
},
{
text: 'browser.screenshotDirectory',
link: '/config/browser/screenshotdirectory',
},
{
text: 'browser.screenshotFailures',
link: '/config/browser/screenshotfailures',
},
{
text: 'browser.orchestratorScripts',
link: '/config/browser/orchestratorscripts',
},
{
text: 'browser.commands',
link: '/config/browser/commands',
},
{
text: 'browser.connectTimeout',
link: '/config/browser/connecttimeout',
},
{
text: 'browser.trace',
link: '/config/browser/trace',
},
{
text: 'browser.trackUnhandledErrors',
link: '/config/browser/trackunhandlederrors',
},
{
text: 'browser.expect',
link: '/config/browser/expect',
},
],
},
// {
// text: '@vitest/plugin-eslint',
// collapsed: true,
// items: [
// {
// text: 'Lints',
// link: '/config/eslint',
// },
// // TODO: generate
// {
// text: 'consistent-test-filename',
// link: '/config/eslint/consistent-test-filename',
// },
// {
// text: 'consistent-test-it',
// link: '/config/eslint/consistent-test-it',
// },
// ],
// },
// {
// text: 'vscode',
// link: '/config/vscode',
// },
],
'/guide': [
{
text: 'Introduction',
collapsed: false,
items: [
{
text: 'Why Vitest',
link: '/guide/why',
},
{
text: 'Getting Started',
link: '/guide/',
},
{
text: 'Features',
link: '/guide/features',
},
],
},
{
text: 'Browser Mode',
collapsed: false,
items: [
{
text: 'Why Browser Mode',
link: '/guide/browser/why',
docFooterText: 'Why Browser Mode | Browser Mode',
},
{
text: 'Getting Started',
link: '/guide/browser/',
docFooterText: 'Getting Started | Browser Mode',
},
{
text: 'Multiple Setups',
link: '/guide/browser/multiple-setups',
docFooterText: 'Multiple Setups | Browser Mode',
},
{
text: 'Component Testing',
link: '/guide/browser/component-testing',
docFooterText: 'Component Testing | Browser Mode',
},
{
text: 'Visual Regression Testing',
link: '/guide/browser/visual-regression-testing',
docFooterText: 'Visual Regression Testing | Browser Mode',
},
{
text: 'Trace View',
link: '/guide/browser/trace-view',
docFooterText: 'Trace View | Browser Mode',
},
],
},
{
text: 'Guides',
collapsed: false,
items: [
{
text: 'CLI',
link: '/guide/cli',
},
{
text: 'Test Filtering',
link: '/guide/filtering',
},
{
text: 'Test Tags',
link: '/guide/test-tags',
},
{
text: 'Test Context',
link: '/guide/test-context',
},
{
text: 'Test Environment',
link: '/guide/environment',
},
{
text: 'Test Run Lifecycle',
link: '/guide/lifecycle',
},
{
text: 'Snapshot',
link: '/guide/snapshot',
},
{
text: 'Mocking',
link: '/guide/mocking',
collapsed: true,
items: [
{
text: 'Mocking Dates',
link: '/guide/mocking/dates',
},
{
text: 'Mocking Functions',
link: '/guide/mocking/functions',
},
{
text: 'Mocking Globals',
link: '/guide/mocking/globals',
},
{
text: 'Mocking Modules',
link: '/guide/mocking/modules',
},
{
text: 'Mocking the File System',
link: '/guide/mocking/file-system',
},
{
text: 'Mocking Requests',
link: '/guide/mocking/requests',
},
{
text: 'Mocking Timers',
link: '/guide/mocking/timers',
},
{
text: 'Mocking Classes',
link: '/guide/mocking/classes',
},
],
},
{
text: 'Parallelism',
link: '/guide/parallelism',
},
{
text: 'Test Projects',
link: '/guide/projects',
},
{
text: 'Reporters',
link: '/guide/reporters',
},
{
text: 'Coverage',
link: '/guide/coverage',
},
{
text: 'Testing Types',
link: '/guide/testing-types',
},
{
text: 'Vitest UI',
link: '/guide/ui',
},
{
text: 'In-Source Testing',
link: '/guide/in-source',
},
{
text: 'Test Annotations',
link: '/guide/test-annotations',
},
{
text: 'Extending Matchers',
link: '/guide/extending-matchers',
},
{
text: 'IDE Integration',
link: '/guide/ide',
},
{
text: 'Debugging',
link: '/guide/debugging',
},
{
text: 'Common Errors',
link: '/guide/common-errors',
},
{
text: 'Migration Guide',
link: '/guide/migration',
collapsed: false,
items: [
{
text: 'Migrating to Vitest 4.0',
link: '/guide/migration#vitest-4',
},
{
text: 'Migrating from Jest',
link: '/guide/migration#jest',
},
{
text: 'Migrating from Mocha + Chai + Sinon',
link: '/guide/migration#mocha-chai-sinon',
},
],
},
{
text: 'Performance',
collapsed: false,
items: [
{
text: 'Profiling Test Performance',
link: '/guide/profiling-test-performance',
},
{
text: 'Improving Performance',
link: '/guide/improving-performance',
},
],
},
{
text: 'OpenTelemetry',
link: '/guide/open-telemetry',
},
],
},
{
text: 'Advanced',
collapsed: false,
items: [
{
text: 'Getting Started',
link: '/guide/advanced/',
},
{
text: 'Running Tests via API',
link: '/guide/advanced/tests',
},
{
text: 'Extending Reporters',
link: '/guide/advanced/reporters',
},
{
text: 'Custom Pool',
link: '/guide/advanced/pool',
},
],
},
{
items: [
{
text: 'Recipes',
link: '/guide/recipes',
},
{
text: 'Comparisons',
link: '/guide/comparisons',
},
],
},
],
'/api': [
{
text: 'Test API Reference',
items: [
{
text: 'Test',
link: '/api/test',
},
{
text: 'Describe',
link: '/api/describe',
},
{
text: 'Hooks',
link: '/api/hooks',
},
],
},
{
text: 'Mocks',
link: '/api/mock',
},
{
text: 'Vi Utility',
link: '/api/vi',
},
{
text: 'Expect',
link: '/api/expect',
},
{
text: 'ExpectTypeOf',
link: '/api/expect-typeof',
},
{
text: 'Assert',
link: '/api/assert',
},
{
text: 'AssertType',
link: '/api/assert-type',
},
{
text: 'Browser Mode',
items: [
{
text: 'Render Function',
collapsed: false,
items: [
{
text: 'react',
link: '/api/browser/react',
},
{
text: 'vue',
link: '/api/browser/vue',
},
{
text: 'svelte',
link: '/api/browser/svelte',
},
// {
// text: 'angular',
// link: '/api/browser/angular',
// },
],
},
{
text: 'Context',
link: '/api/browser/context',
},
{
text: 'Interactivity',
link: '/api/browser/interactivity',
},
{
text: 'Locators',
link: '/api/browser/locators',
},
{
text: 'Assertions',
link: '/api/browser/assertions',
},
{
text: 'Commands',
link: '/api/browser/commands',
},
],
},
{
text: 'Advanced',
collapsed: false,
items: [
{
text: 'Vitest',
link: '/api/advanced/vitest',
},
{
text: 'TestProject',
link: '/api/advanced/test-project',
},
{
text: 'TestSpecification',
link: '/api/advanced/test-specification',
},
{
text: 'TestCase',
link: '/api/advanced/test-case',
},
{
text: 'TestSuite',
link: '/api/advanced/test-suite',
},
{
text: 'TestModule',
link: '/api/advanced/test-module',
},
{
text: 'TestCollection',
link: '/api/advanced/test-collection',
},
{
text: 'VitestPlugin',
link: '/api/advanced/plugin',
},
{
text: 'VitestRunner',
link: '/api/advanced/runner',
},
{
text: 'Reporter',
link: '/api/advanced/reporters',
},
{
text: 'TaskMeta',
link: '/api/advanced/metadata',
},
{
text: 'TestArtifact',
link: '/api/advanced/artifacts',
},
],
},
// {
// text: 'Text Runner',
// collapsed: false,
// items: [
// // TODO: generate
// {
// text: 'test',
// link: '/api/test',
// },
// {
// text: 'describe',
// link: '/api/describe',
// },
// {
// text: 'beforeEach',
// link: '/api/before-each',
// },
// {
// text: 'afterEach',
// link: '/api/after-each',
// },
// ],
// },
// {
// text: 'Assertion API',
// collapsed: false,
// items: [
// {
// text: 'expect',
// link: '/api/expect',
// },
// {
// text: 'assert',
// link: '/api/assert',
// },
// {
// text: 'expectTypeOf',
// link: '/api/expect-typeof',
// },
// {
// text: 'assertType',
// link: '/api/assert-type',
// },
// ],
// },
// {
// text: 'Vi Utility API',
// collapsed: false,
// items: [
// {
// text: 'Mock Modules',
// link: '/api/vi/mock-modiles',
// },
// {
// text: 'Mock Functions',
// link: '/api/vi/mock-functions',
// },
// {
// text: 'Mock Timers',
// link: '/api/vi/mock-timers',
// },
// {
// text: 'Miscellaneous',
// link: '/api/vi/miscellaneous',
// },
// ],
// },
// {
// text: 'Browser Mode',
// collapsed: false,
// items: [
// // TODO: generate
// {
// text: 'page',
// link: '/api/browser/page',
// },
// {
// text: 'locators',
// link: '/api/browser/locators',
// },
// ],
// },
],
},
},
pwa,
transformHead,
})))
}
================================================
FILE: docs/.vitepress/contributors.ts
================================================
import type { DefaultTheme } from 'vitepress'
export interface Contributor {
name: string
avatar: string
}
export interface CoreTeam extends DefaultTheme.TeamMember {
// required to download avatars from GitHub
github: string
bluesky?: string
mastodon?: string
discord?: string
youtube?: string
}
function getAvatarUrl(name: string) {
return import.meta.hot ? `https://github.com/${name}.png` : `/user-avatars/${name}.png`
}
function createLinks(tm: CoreTeam): CoreTeam {
tm.links = [{ icon: 'github', link: `https://github.com/${tm.github}` }]
if (tm.bluesky) {
tm.links.push({ icon: 'bluesky', link: tm.bluesky })
}
if (tm.mastodon) {
tm.links.push({ icon: 'mastodon', link: tm.mastodon })
}
if (tm.discord) {
tm.links.push({ icon: 'discord', link: tm.discord })
}
if (tm.youtube) {
tm.links.push({ icon: 'youtube', link: `https://www.youtube.com/@${tm.youtube}` })
}
return tm
}
const plainTeamMembers: CoreTeam[] = [
{
avatar: getAvatarUrl('sheremet-va'),
name: 'Vladimir',
github: 'sheremet-va',
bluesky: 'https://bsky.app/profile/erus.dev',
mastodon: 'https://elk.zone/m.webtoo.ls/@sheremet_va',
sponsor: 'https://github.com/sponsors/sheremet-va',
title: 'Open source developer',
desc: 'Core team member of Vitest & Vite',
org: 'VoidZero',
orgLink: 'https://voidzero.dev/',
},
{
avatar: getAvatarUrl('antfu'),
name: 'Anthony Fu',
github: 'antfu',
bluesky: 'https://bsky.app/profile/antfu.me',
mastodon: 'https://elk.zone/m.webtoo.ls/@antfu',
discord: 'https://chat.antfu.me',
youtube: 'antfu',
sponsor: 'https://github.com/sponsors/antfu',
title: 'A fanatical open sourceror',
org: 'Vercel',
orgLink: 'https://vercel.com/',
desc: 'Core team member of Vite & Vue',
},
{
avatar: getAvatarUrl('AriPerkkio'),
name: 'Ari Perkkiö',
github: 'AriPerkkio',
bluesky: 'https://bsky.app/profile/ariperkkio.dev',
sponsor: 'https://github.com/sponsors/AriPerkkio',
title: 'Open source engineer',
desc: 'Core team member of Vitest',
org: 'Chromatic',
orgLink: 'https://www.chromatic.com/',
},
{
avatar: getAvatarUrl('hi-ogawa'),
name: 'Hiroshi Ogawa',
github: 'hi-ogawa',
bluesky: 'https://bsky.app/profile/hiogawa.bsky.social',
sponsor: 'https://github.com/sponsors/hi-ogawa',
title: 'Open source enthusiast',
desc: 'Team member of Vitest',
org: 'VoidZero',
orgLink: 'https://voidzero.dev/',
},
{
avatar: getAvatarUrl('patak-dev'),
name: 'Patak',
github: 'patak-dev',
bluesky: 'https://bsky.app/profile/patak.dev',
mastodon: 'https://elk.zone/m.webtoo.ls/@patak',
sponsor: 'https://github.com/sponsors/patak-dev',
title: 'Independent Open Source Adventurer',
desc: 'Core team member of Vite & Vue',
},
{
avatar: getAvatarUrl('userquin'),
name: 'Joaquín Sánchez',
github: 'userquin',
bluesky: 'https://bsky.app/profile/userquin.bsky.social',
mastodon: 'https://elk.zone/m.webtoo.ls/@userquin',
title: 'A fullstack and android developer',
desc: 'Vite\'s fanatical follower',
},
]
const plainTeamEmeritiMembers: CoreTeam[] = [
{
avatar: getAvatarUrl('Dunqing'),
name: 'Dunqing',
github: 'Dunqing',
title: 'A passionate enthusiast of open source contributions',
desc: 'Team member of oxc & UnoCSS',
},
{
avatar: getAvatarUrl('Aslemammad'),
name: 'Mohammad Bagher',
github: 'Aslemammad',
bluesky: 'https://bsky.app/profile/aslemammad.bsky.social',
mastodon: 'https://elk.zone/m.webtoo.ls/@aslemammad',
title: 'An open source developer',
desc: 'Team member of Poimandres & Vike',
},
{
avatar: getAvatarUrl('Demivan'),
name: 'Ivan Demchuk',
github: 'Demivan',
mastodon: 'https://elk.zone/fosstodon.org/@demivan',
title: 'A tech lead, fullstack developer',
desc: 'Author of fluent-vue',
},
{
avatar: getAvatarUrl('poyoho'),
name: 'Yoho Po',
github: 'poyoho',
title: 'It\'s no problem in my locall',
desc: 'Core team member of Vite & Team member of Vitest',
},
{
avatar: getAvatarUrl('zxch3n'),
name: 'Zixuan Chen',
github: 'zxch3n',
bluesky: 'https://bsky.app/profile/zxch3n.bsky.social',
mastodon: 'https://elk.zone/hachyderm.io/@zx',
title: 'A fullstack developer',
desc: 'Working on CRDTs & local-first software',
},
]
const teamMembers = plainTeamMembers.map(tm => createLinks(tm))
const teamEmeritiMembers = plainTeamEmeritiMembers.map(tm => createLinks(tm))
export { teamEmeritiMembers, teamMembers }
================================================
FILE: docs/.vitepress/meta.ts
================================================
// noinspection ES6PreferShortImport: IntelliJ IDE hint to avoid warning to use `~/contributors`, will fail on build if changed
/* Texts */
export const vitestName = 'Vitest'
export const vitestShortName = 'Vitest'
export const vitestDescription = 'Next generation testing framework powered by Vite'
/* CDN fonts and styles */
export const googleapis = 'https://fonts.googleapis.com'
export const gstatic = 'https://fonts.gstatic.com'
export const font = `${googleapis}/css2?family=Readex+Pro:wght@200;400;600&display=swap`
/* vitepress head */
export const ogUrl = 'https://vitest.dev/'
export const ogImage = `${ogUrl}og.jpg`
/* GitHub and social links */
export const github = 'https://github.com/vitest-dev/vitest'
export const releases = 'https://github.com/vitest-dev/vitest/releases'
export const contributing = 'https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md'
export const discord = 'https://chat.vitest.dev'
export const bluesky = 'https://bsky.app/profile/vitest.dev'
export const mastodon = 'https://elk.zone/m.webtoo.ls/@vitest'
/* Avatar/Image/Sponsors servers */
export const preconnectLinks = [googleapis, gstatic]
export const preconnectHomeLinks = [googleapis, gstatic]
/* PWA runtime caching urlPattern regular expressions */
export const pwaFontsRegex = new RegExp(`^${googleapis}/.*`, 'i')
export const pwaFontStylesRegex = new RegExp(`^${gstatic}/.*`, 'i')
// eslint-disable-next-line prefer-regex-literals
export const githubusercontentRegex = new RegExp('^https://((i.ibb.co)|((raw|user-images).githubusercontent.com))/.*', 'i')
================================================
FILE: docs/.vitepress/scripts/cli-generator.ts
================================================
import type { CLIOption, CLIOptions } from '../../../packages/vitest/src/node/cli/cli-config'
import { writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { cliOptionsConfig } from '../../../packages/vitest/src/node/cli/cli-config'
const docsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
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',
'configLoader',
'color',
'run',
'hideSkippedTests',
'dom',
'inspect',
'inspectBrk',
'project',
'ui',
'browser.name',
'browser.fileParallelism',
'clearCache',
'tagsFilter',
'listTags',
])
function resolveOptions(options: CLIOptions, parentName?: string) {
return Object.entries(options).flatMap(
([subcommandName, subcommandConfig]) => resolveCommand(
parentName ? `${parentName}.${subcommandName}` : subcommandName,
subcommandConfig,
),
).filter(nonNullable)
}
function resolveCommand(name: string, config: CLIOption | null): any {
if (!config || skipCli.has(name)) {
return null
}
let title = '`'
if (config.shorthand) {
title += `-${config.shorthand}, `
}
title += `--${config.alias || name}`
if ('argument' in config) {
title += ` ${config.argument}`
}
title += '`'
if ('subcommands' in config && config.subcommands) {
return resolveOptions(config.subcommands, name)
}
return {
title: name,
cli: title,
description: config.description,
}
}
const options = resolveOptions(cliOptionsConfig)
const template = options.map((option) => {
const title = option.title
const cli = option.cli
const [page, ...hash] = (title.startsWith('browser.') ? title.slice(8) : title).toLowerCase().split('.')
const config = skipConfig.has(title) ? '' : `[${title}](${title.includes('browser.') ? '/config/browser/' : '/config/'}${page}${hash.length ? `#${[page, ...hash].join('-')}` : ''})`
return `### ${title}\n\n- **CLI:** ${cli}\n${config ? `- **Config:** ${config}\n` : ''}\n${option.description.replace(/https:\/\/vitest\.dev\//g, '/')}\n`
}).join('\n')
writeFileSync(cliTablePath, template, 'utf-8')
================================================
FILE: docs/.vitepress/scripts/fetch-avatars.ts
================================================
import { existsSync, promises as fsp } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { dirname, join, resolve } from 'pathe'
import { teamEmeritiMembers, teamMembers } from '../contributors'
const docsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
const dirAvatars = resolve(docsDir, 'public/user-avatars/')
async function download(url: string, fileName: string) {
if (existsSync(fileName)) {
return
}
console.log('downloading', fileName)
try {
const image = await (await fetch(url)).arrayBuffer()
await fsp.writeFile(fileName, Buffer.from(image))
}
catch {}
}
async function fetchAvatars() {
if (!existsSync(dirAvatars)) {
await fsp.mkdir(dirAvatars, { recursive: true })
}
await Promise.all([...teamEmeritiMembers, ...teamMembers].map(c => c.github).map(name => download(`https://github.com/${name}.png?size=100`, join(dirAvatars, `${name}.png`))))
}
fetchAvatars()
================================================
FILE: docs/.vitepress/scripts/pwa.ts
================================================
import type { PwaOptions } from '@vite-pwa/vitepress'
import {
githubusercontentRegex,
pwaFontsRegex,
pwaFontStylesRegex,
vitestDescription,
vitestName,
vitestShortName,
} from '../meta'
export const pwa: PwaOptions = {
outDir: '.vitepress/dist',
registerType: 'autoUpdate',
// include all static assets under public/
manifest: {
id: '/',
name: vitestName,
short_name: vitestShortName,
description: vitestDescription,
theme_color: '#ffffff',
start_url: '/',
lang: 'en-US',
dir: 'ltr',
orientation: 'natural',
display: 'standalone',
display_override: ['window-controls-overlay'],
categories: ['development', 'developer tools'],
icons: [
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any',
},
{
src: 'maskable-icon.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
screenshots: [{
src: 'og.jpg',
sizes: '2258x1185',
type: 'image/jpeg',
label: `Screenshot of ${vitestName}`,
}],
handle_links: 'preferred',
launch_handler: {
client_mode: ['navigate-existing', 'auto'],
},
edge_side_panel: {
preferred_width: 480,
},
},
workbox: {
navigateFallbackDenylist: [/^\/new$/],
maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, // <== 3MB
globPatterns: ['**/*.{css,js,html,png,svg,ico,txt,woff2,json}'],
// Rollup 4 change the layout: don't calculate revision (hash)
dontCacheBustURLsMatching: /^assets\//,
runtimeCaching: [
{
urlPattern: pwaFontsRegex,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
urlPattern: pwaFontStylesRegex,
handler: 'CacheFirst',
options: {
cacheName: 'gstatic-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
{
urlPattern: githubusercontentRegex,
handler: 'CacheFirst',
options: {
cacheName: 'githubusercontent-images-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365, // <== 365 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
},
experimental: {
includeAllowlist: true,
},
}
================================================
FILE: docs/.vitepress/scripts/transformHead.ts
================================================
import type { HeadConfig, TransformContext } from 'vitepress'
import { preconnectHomeLinks, preconnectLinks } from '../meta'
export async function transformHead({ pageData }: TransformContext): Promise {
const head: HeadConfig[] = []
const home = pageData.relativePath === 'index.md'
;(home ? preconnectHomeLinks : preconnectLinks).forEach((link) => {
head.push(['link', { rel: 'dns-prefetch', href: link }])
head.push(['link', { rel: 'preconnect', href: link }])
})
head.push(['link', { rel: 'prefetch', href: '/logo.svg', as: 'image' }])
return head
}
================================================
FILE: docs/.vitepress/sponsors.ts
================================================
import type { SponsorTier } from '@voidzero-dev/vitepress-theme/src/types/sponsors'
export const sponsors: SponsorTier[] = [
{
tier: 'Special',
size: 'big',
items: [
{
name: 'Vercel',
url: 'https://vercel.com',
img: '/vercel.svg',
},
{
name: 'Chromatic',
url: 'https://www.chromatic.com/?utm_source=vitest&utm_medium=sponsorship&utm_campaign=vitestSponsorship',
img: '/chromatic.svg',
},
{
name: 'Zammad',
url: 'https://zammad.com',
img: '/zammad.svg',
},
],
},
{
tier: 'Platinum Sponsors',
size: 'big',
items: [
{
name: 'Bolt',
url: 'https://bolt.new',
img: '/bolt.svg',
},
],
},
{
tier: 'Gold',
size: 'medium',
items: [
{
name: 'vital',
url: 'https://vital.io/',
img: '/vital.svg',
},
{
name: 'OOMOL',
url: 'https://oomol.com/',
img: '/oomol.svg',
},
{
name: 'Mailmeteor',
url: 'https://mailmeteor.com/',
img: '/mailmeteor.svg',
},
{
name: 'Liminity',
url: 'https://www.liminity.se/',
img: '/liminity.svg',
},
{
name: 'Aerius Ventilation',
url: 'https://aerius.se/',
img: '/aerius.png',
},
],
},
]
================================================
FILE: docs/.vitepress/theme/FeatureGrid.vue
================================================
Vite Powered
Reuse Vite's config and plugins - consistent across your app and tests.
But it's not required to use Vitest!
Jest Compatible
Expect, snapshot, coverage, and more - migrating from Jest is
straightforward.
Smart & instant watch mode
Only rerun the related changes, just like HMR for tests!
ESM, TypeScript, JSX
Out-of-box ESM, TypeScript and JSX support powered by Oxc.
================================================
FILE: docs/.vitepress/theme/Hero.vue
================================================
By
Next Generation Testing Framework
A Vite-native testing framework. It's fast!
================================================
FILE: docs/.vitepress/theme/Home.vue
================================================
================================================
FILE: docs/.vitepress/theme/Intro.vue
================================================
Vitest was created to make testing just work for Vite apps. By building on top of Vite, Vitest
natively
understands your Vite config and is able to reuse the same resolve and
transform pipelines.
You can also use Vitest even if you are not using Vite. It is Jest-compatible
and works for backend code too.
Learn more
================================================
FILE: docs/.vitepress/theme/index.ts
================================================
import type { Theme } from 'vitepress'
import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client'
import { inBrowser } from 'vitepress'
import VitestTheme from '@voidzero-dev/vitepress-theme/src/vitest'
import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client'
import Version from '../components/Version.vue'
import CRoot from '../components/CRoot.vue'
import Deprecated from '../components/Deprecated.vue'
import Experimental from '../components/Experimental.vue'
import Advanced from '../components/Advanced.vue'
import CourseLink from '../components/CourseLink.vue'
import './styles.css'
import '@shikijs/vitepress-twoslash/style.css'
import 'virtual:group-icons.css'
if (inBrowser) {
// redirect old hash links (e.g. /config/#reporters -> /config/reporters)
// before hydration to avoid SSG hydration mismatch
const redirect = getRedirectPath(new URL(location.href))
if (redirect) {
location.replace(redirect)
}
import('./pwa')
}
function getRedirectPath(url: URL) {
if (url.pathname === '/api/' || url.pathname === '/api' || url.pathname === '/api/index.html') {
return '/api/test'
}
if (!url.hash) {
return
}
// /config/#reporters -> /config/reporters
// /config/#coverage-provider -> /config/coverage#coverage-provider
// /config/#browser.enabled -> /config/browser/enabled
if (url.pathname === '/config' || url.pathname === '/config/' || url.pathname === '/config.html') {
if (url.hash.startsWith('#browser.')) {
const [page, ...hash] = url.hash.slice('#browser.'.length).toLowerCase().split('-')
return `/config/browser/${page}${hash.length ? `#${[page, ...hash].join('-')}` : ''}`
}
const [page, ...hash] = url.hash.slice(1).toLowerCase().split('-')
return `/config/${page}${hash.length ? `#${[page, ...hash].join('-')}` : ''}`
}
// /guide/browser/config#browser.locators-testidattribute -> /config/browser/locators#browser-locators-testidattribute
if (url.pathname === '/guide/browser/config' || url.pathname === '/guide/browser/config/' || url.pathname === '/guide/browser/config.html') {
const [page, ...hash] = url.hash.slice('#browser.'.length).toLowerCase().split('-')
return `/config/browser/${page}${hash.length ? `#${[page, ...hash].join('-')}` : ''}`
}
}
export default {
extends: VitestTheme as unknown as any,
enhanceApp({ app }) {
app.component('Version', Version)
app.component('CRoot', CRoot)
app.component('Experimental', Experimental)
app.component('Deprecated', Deprecated)
app.component('Advanced', Advanced)
app.component('CourseLink', CourseLink)
app.use(TwoslashFloatingVue)
enhanceAppWithTabs(app)
},
} satisfies Theme
================================================
FILE: docs/.vitepress/theme/pwa.ts
================================================
import { registerSW } from 'virtual:pwa-register'
registerSW({ immediate: true })
================================================
FILE: docs/.vitepress/theme/styles.css
================================================
@import "@voidzero-dev/vitepress-theme/src/styles/index.css";
@source "./**/*.vue";
/* Vitest */
:root[data-variant="vitest"] {
--color-brand: #008039;
/* TODO: home page wcag-aa color contrast (remove this once fixed at void0 theme):
* - why vitest section and texts
* - vitest, resources, versions and social
* - footer
*/
--color-grey: #867e8e;
}
:root.dark:not([data-theme])[data-variant="vitest"],
:root[data-theme="dark"][data-variant="vitest"] {
--color-brand: var(--color-zest);
}
:root[data-variant="vitest"]:not(.dark):not([data-theme="light"]),
:root[data-theme="light"][data-variant="vitest"] {
--color-brand: #008039;
/* TODO: code block (remove this once fixed at void0 theme) */
--vp-code-color: #007d38;
}
.highlighted-word {
background-color: var(--vp-code-line-highlight-color);
transition: background-color 0.5s;
display: inline-block;
}
/* credit goes to https://dylanatsmith.com/wrote/styling-the-kbd-element */
html:not(.dark) .VPContent kbd {
--kbd-color-background: #f7f7f7;
--kbd-color-border: #cbcccd;
--kbd-color-text: #222325;
}
.VPContent kbd {
--kbd-color-background: #898b90;
--kbd-color-border: #3d3e42;
--kbd-color-text: #222325;
background-color: var(--kbd-color-background);
color: var(--kbd-color-text);
border-radius: 0.25rem;
border: 1px solid var(--kbd-color-border);
box-shadow: 0 2px 0 1px var(--kbd-color-border);
font-family: var(--font-family-sans-serif);
font-size: 0.75em;
line-height: 1;
min-width: 0.75rem;
text-align: center;
padding: 2px 5px;
position: relative;
top: -1px;
}
================================================
FILE: docs/api/advanced/artifacts.md
================================================
---
outline: deep
title: Test Artifacts
---
# Test Artifacts 4.0.11
::: warning
This is an advanced API. As a user, you most likely want to use [test annotations](/guide/test-annotations) to add notes or context to your tests instead. This is primarily used internally and by library authors.
:::
Test artifacts allow attaching or recording structured data, files, or metadata during test execution. This is a low-level feature primarily designed for:
- Internal use ([`annotate`](/guide/test-annotations) is built on top of the artifact system)
- Framework authors creating custom testing tools on top of Vitest
Each artifact includes:
- A type discriminator which is a unique identifier for the artifact type
- Custom data, can be any relevant information
- Optional attachments, either files or inline content associated with the artifact
- A source code location indicating where the artifact was created
Vitest automatically manages attachment serialization (files are copied to [`attachmentsDir`](/config/attachmentsdir)) and injects source location metadata, so you can focus on the data you want to record. All artifacts **must** extend from [`TestArtifactBase`](#testartifactbase) and all attachments from [`TestAttachment`](#testattachment) to be correctly handled internally.
## API
### `recordArtifact` {#recordartifact}
::: warning
`recordArtifact` is an experimental API. Breaking changes might not follow SemVer, please pin Vitest's version when using it.
The API surface may change based on feedback. We encourage you to try it out and share your experience with the team.
:::
```ts
function recordArtifact(task: Test, artifact: Artifact): Promise
```
The `recordArtifact` function records an artifact during test execution and returns it. It expects a [task](/api/advanced/runner#tasks) as the first parameter and an object assignable to [`TestArtifact`](#testartifact) as the second.
::: info
Artifacts must be recorded before the task is reported. Any artifacts recorded after that will not be included in the task.
:::
When an artifact is recorded on a test, it emits an `onTestArtifactRecord` runner event and a [`onTestCaseArtifactRecord` reporter event](/api/advanced/reporters#ontestcaseartifactrecord). To retrieve recorded artifacts from a test case, use the [`artifacts()`](/api/advanced/test-case#artifacts) method.
Note: annotations, [even though they're built on top of this feature](#relationship-with-annotations), won't appear in the `task.artifacts` array for backwards compatibility reasons until the next major version.
### `TestArtifact`
The `TestArtifact` type is a union containing all artifacts Vitest can produce, including custom ones. All artifacts extend from [`TestArtifactBase`](#testartifactbase)
### `TestArtifactBase` {#testartifactbase}
```ts
export interface TestArtifactBase {
/** File or data attachments associated with this artifact */
attachments?: TestAttachment[]
/** Source location where this artifact was created */
location?: TestArtifactLocation
}
```
The `TestArtifactBase` interface is the base for all test artifacts.
Extend this interface when creating custom test artifacts. Vitest automatically manages the `attachments` array and injects the `location` property to indicate where the artifact was created in your test code.
::: danger
When running with [`api.allowWrite`](/config/api#api-allowwrite) or [`browser.api.allowWrite`](/config/browser/api#api-allowwrite) disabled, Vitest empties the `attachments` array on every artifact before reporting it.
If your custom artifact narrows the `attachments` type (e.g. to a tuple), include `| []` in the union so the type reflects what actually happens at runtime.
:::
### `TestAttachment`
```ts
export interface TestAttachment {
/** MIME type of the attachment (e.g., 'image/png', 'text/plain') */
contentType?: string
/** File system path to the attachment */
path?: string
/** Inline attachment content as a string or raw binary data */
body?: string | Uint8Array
}
```
The `TestAttachment` interface represents a file or data attachment associated with a test artifact.
Attachments can be either file-based (via `path`) or inline content (via `body`). The `contentType` helps consumers understand how to interpret the attachment data.
### `TestArtifactLocation`
```ts
export interface TestArtifactLocation {
/** Line number in the source file (1-indexed) */
line: number
/** Column number in the line (1-indexed) */
column: number
/** Path to the source file */
file: string
}
```
The `TestArtifactLocation` interface represents the source code location information for a test artifact. It indicates where in the source code the artifact originated from.
### `TestArtifactRegistry`
The `TestArtifactRegistry` interface is a registry for custom test artifact types.
Augmenting this interface using [TypeScript's module augmentation feature](https://typescriptlang.org/docs/handbook/declaration-merging#module-augmentation) allows registering custom artifact types that tests can produce.
Each custom artifact should extend [`TestArtifactBase`](#testartifactbase) and include a unique `type` discriminator property.
Here are a few guidelines or best practices to follow:
- Try using a `Symbol` as the **registry key** to guarantee uniqueness
- The `type` property should follow the pattern `'package-name:artifact-name'`, **`'internal:'` is a reserved prefix**
- Use `attachments` to include files or data; extend [`TestAttachment`](#testattachment) for custom metadata
- If you narrow the `attachments` type (e.g. to a tuple), include `| []` in the union since Vitest may empty the array at runtime (see [`TestArtifactBase`](#testartifactbase))
- `location` property is automatically injected
## Custom Artifacts
To use and manage artifacts in a type-safe manner, you need to create its type and register it:
```ts
import type { TestArtifactBase, TestAttachment } from 'vitest'
interface A11yReportAttachment extends TestAttachment {
contentType: 'text/html'
path: string
}
interface AccessibilityArtifact extends TestArtifactBase {
type: 'a11y:report'
passed: boolean
wcagLevel: 'A' | 'AA' | 'AAA'
attachments: [A11yReportAttachment] | []
}
const a11yReportKey = Symbol('report')
declare module 'vitest' {
interface TestArtifactRegistry {
[a11yReportKey]: AccessibilityArtifact
}
}
```
As long as the types are assignable to their bases and don't have errors, everything should work fine and you should be able to record artifacts using [`recordArtifact`](#recordartifact):
```ts
async function toBeAccessible(
this: MatcherState,
actual: Element,
wcagLevel: 'A' | 'AA' | 'AAA' = 'AA'
): AsyncExpectationResult {
const report = await runAccessibilityAudit(actual, wcagLevel)
await recordArtifact(this.task, {
type: 'a11y:report',
passed: report.violations.length === 0,
wcagLevel,
attachments: [{
contentType: 'text/html',
path: report.path,
}],
})
return {
pass: violations.length === 0,
message: () => `Found ${report.violations.length} accessibility violation(s)`
}
}
```
## Relationship with Annotations
Test annotations are built on top of the artifact system. When using annotations in tests, they create `internal:annotation` artifacts under the hood. However, annotations are:
- Simpler to use
- Designed for end-users, not developers
Use annotations if you just want to add notes to your tests. Use artifacts if you need custom data.
================================================
FILE: docs/api/advanced/import-example.md
================================================
```ts
function import(moduleId: string): Promise
```
================================================
FILE: docs/api/advanced/metadata.md
================================================
# Task Metadata advanced
If you are developing a custom reporter or using Vitest Node.js API, you might find it useful to pass data from tests that are being executed in various contexts to your reporter or custom Vitest handler.
To accomplish this, relying on the [test context](/guide/test-context) is not feasible since it cannot be serialized. However, with Vitest, you can utilize the `meta` property available on every task (suite or test) to share data between your tests and the Node.js process. It's important to note that this communication is one-way only, as the `meta` property can only be modified from within the test context. Any changes made within the Node.js context will not be visible in your tests.
You can populate `meta` property on test context or inside `beforeAll`/`afterAll` hooks for suite tasks.
```ts
afterAll((suite) => {
suite.meta.done = true
})
test('custom', ({ task }) => {
task.meta.custom = 'some-custom-handler'
})
```
Once a test is completed, Vitest will send a task including the result and `meta` to the Node.js process using RPC, and then report it in `onTestCaseResult` and other hooks that have access to tasks. To process this test case, you can utilize the `onTestCaseResult` method available in your reporter implementation:
```ts [custom-reporter.js]
import type { Reporter, TestCase, TestModule } from 'vitest/node'
export default {
onTestCaseResult(testCase: TestCase) {
// custom === 'some-custom-handler' ✅
const { custom } = testCase.meta()
},
onTestRunEnd(testModule: TestModule) {
testModule.meta().done === true
testModule.children.at(0).meta().custom === 'some-custom-handler'
}
} satisfies Reporter
```
::: danger BEWARE
Vitest uses different methods to communicate with the Node.js process.
- If Vitest runs tests inside worker threads, it will send data via [message port](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort)
- If Vitest uses child process, the data will be send as a serialized Buffer via [`process.send`](https://nodejs.org/api/process.html#processsendmessage-sendhandle-options-callback) API
- If Vitest runs tests in the browser, the data will be stringified using [flatted](https://npmx.dev/package/flatted) package
This property is also present on every test in the `json` reporter, so make sure that data can be serialized into JSON.
Also, make sure you serialize [Error properties](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#error_types) before you set them.
:::
You can also get this information from Vitest state when tests finished running:
```ts
const vitest = await createVitest('test')
const { testModules } = await vitest.start()
const testModule = testModules[0]
testModule.meta().done === true
testModule.children.at(0).meta().custom === 'some-custom-handler'
```
It's also possible to extend type definitions when using TypeScript:
```ts
declare module 'vitest' {
interface TaskMeta {
done?: boolean
custom?: string
}
}
```
================================================
FILE: docs/api/advanced/plugin.md
================================================
---
title: Plugin API
outline: deep
---
# Plugin API 3.1.0 {#plugin-api}
::: warning
This is an advanced API. If you just want to [run tests](/guide/), you probably don't need this. It is primarily used by library authors.
This guide assumes you know how to work with [Vite plugins](https://vite.dev/guide/api-plugin.html).
:::
Vitest supports a `configureVitest` [plugin](https://vite.dev/guide/api-plugin.html) hook since version 3.1.
::: code-group
```ts [only vitest]
import type { Vite, VitestPluginContext } from 'vitest/node'
export function plugin(): Vite.Plugin {
return {
name: 'vitest:my-plugin',
configureVitest(context: VitestPluginContext) {
// ...
}
}
}
```
```ts [vite and vitest]
///
import type { Plugin } from 'vite'
export function plugin(): Plugin {
return {
name: 'vitest:my-plugin',
transform() {
// ...
},
configureVitest(context) {
// ...
}
}
}
```
:::
::: tip TypeScript
Vitest re-exports all Vite type-only imports via a `Vite` namespace, which you can use to keep your versions in sync. However, if you are writing a plugin for both Vite and Vitest, you can continue using the `Plugin` type from the `vite` entrypoint. Just make sure you have `vitest/config` referenced somewhere so that `configureVitest` is augmented correctly:
```ts
///
```
:::
Unlike [`reporter.onInit`](/api/advanced/reporters#oninit), this hooks runs early in Vitest lifecycle allowing you to make changes to configuration like `coverage` and `reporters`. A more notable change is that you can manipulate the global config from a [test project](/guide/projects) if your plugin is defined in the project and not in the global config.
## Context
### project
The current [test project](./test-project) that the plugin belongs to.
::: warning Browser Mode
Note that if you are relying on a browser feature, the `project.browser` field is not set yet. Use [`reporter.onBrowserInit`](./reporters#onbrowserinit) event instead.
:::
### vitest
The global [Vitest](./vitest) instance. You can change the global configuration by directly mutating the `vitest.config` property:
```ts
vitest.config.coverage.enabled = false
vitest.config.reporters.push([['my-reporter', {}]])
```
::: warning Config is Resolved
Note that Vitest already resolved the config, so some types might be different from the usual user configuration. This also means that some properties will not be resolved again, like `setupFile`. If you are adding new files, make sure to resolve it first.
At this point reporters are not created yet, so modifying `vitest.reporters` will have no effect because it will be overwritten. If you need to inject your own reporter, modify the config instead.
:::
### injectTestProjects
```ts
function injectTestProjects(
config: TestProjectConfiguration | TestProjectConfiguration[]
): Promise
```
This methods accepts a config glob pattern, a filepath to the config or an inline configuration. It returns an array of resolved [test projects](./test-project).
```ts
// inject a single project with a custom alias
const newProjects = await injectTestProjects({
// you can inherit the current project config by referencing `extends`
// note that you cannot have a project with the name that already exists,
// so it's a good practice to define a custom name
extends: project.vite.config.configFile,
test: {
name: 'my-custom-alias',
alias: {
customAlias: resolve('./custom-path.js'),
},
},
})
```
::: warning Projects are Filtered
Vitest filters projects during the config resolution, so if the user defined a filter, injected project might not be resolved unless it [matches the filter](./vitest#matchesprojectfilter). You can update the filter via the `vitest.config.project` option to always include your test project:
```ts
vitest.config.project.push('my-project-name')
```
Note that this will only affect projects injected with [`injectTestProjects`](#injecttestprojects) method.
:::
::: tip Referencing the Current Config
If you want to keep the user configuration, you can specify the `extends` property. All other properties will be merged with the user defined config.
The project's `configFile` can be accessed in Vite's config: `project.vite.config.configFile`.
Note that this will also inherit the `name` - Vitest doesn't allow multiple projects with the same name, so this will throw an error. Make sure you specified a different name. You can access the current name via the `project.name` property and all used names are available in the `vitest.projects` array.
:::
### experimental_defineCacheKeyGenerator 4.0.11 {#definecachekeygenerator}
```ts
interface CacheKeyIdGeneratorContext {
environment: DevEnvironment
id: string
sourceCode: string
}
function experimental_defineCacheKeyGenerator(
callback: (context: CacheKeyIdGeneratorContext) => string | undefined | null | false
): void
```
Define a generator that will be applied before hashing the cache key.
Use this to make sure Vitest generates correct hash. It is a good idea to define this function if your plugin can be registered with different options.
This is called only if [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache) is defined.
```ts
interface PluginOptions {
replacePropertyKey: string
replacePropertyValue: string
}
export function plugin(options: PluginOptions) {
return {
name: 'plugin-that-replaces-property',
transform(code) {
return code.replace(
options.replacePropertyKey,
options.replacePropertyValue
)
},
configureVitest({ experimental_defineCacheKeyGenerator }) {
experimental_defineCacheKeyGenerator(() => {
// since these options affect the transform result,
// return them together as a unique string
return options.replacePropertyKey + options.replacePropertyValue
})
}
}
}
```
If `false` is returned, the module will not be cached on the file system.
================================================
FILE: docs/api/advanced/reporters.md
================================================
# Reporters
::: warning
This is an advanced API. If you just want to configure built-in reporters, read the ["Reporters"](/guide/reporters) guide.
:::
Vitest has its own test run lifecycle. These are represented by reporter's methods:
- [`onInit`](#oninit)
- [`onTestRunStart`](#ontestrunstart)
- [`onTestModuleQueued`](#ontestmodulequeued)
- [`onTestModuleCollected`](#ontestmodulecollected)
- [`onTestModuleStart`](#ontestmodulestart)
- [`onTestSuiteReady`](#ontestsuiteready)
- [`onHookStart(beforeAll)`](#onhookstart)
- [`onHookEnd(beforeAll)`](#onhookend)
- [`onTestCaseReady`](#ontestcaseready)
- [`onTestCaseAnnotate`](#ontestcaseannotate) 3.2.0
- [`onTestCaseArtifactRecord`](#ontestcaseartifactrecord) 4.0.11
- [`onHookStart(beforeEach)`](#onhookstart)
- [`onHookEnd(beforeEach)`](#onhookend)
- [`onHookStart(afterEach)`](#onhookstart)
- [`onHookEnd(afterEach)`](#onhookend)
- [`onTestCaseResult`](#ontestcaseresult)
- [`onHookStart(afterAll)`](#onhookstart)
- [`onHookEnd(afterAll)`](#onhookend)
- [`onTestSuiteResult`](#ontestsuiteresult)
- [`onTestModuleEnd`](#ontestmoduleend)
- [`onCoverage`](#oncoverage)
- [`onTestRunEnd`](#ontestrunend)
Tests and suites within a single module will be reported in order unless they were skipped. All skipped tests are reported at the end of suite/module.
Note that since test modules can run in parallel, Vitest will report them in parallel.
This guide lists all supported reporter methods. However, don't forget that instead of creating your own reporter, you can [extend existing one](/guide/advanced/reporters) instead:
```ts [custom-reporter.js]
import { BaseReporter } from 'vitest/node'
export default class CustomReporter extends BaseReporter {
onTestRunEnd(testModules, errors) {
console.log(testModule.length, 'tests finished running')
super.onTestRunEnd(testModules, errors)
}
}
```
## onInit
```ts
function onInit(vitest: Vitest): Awaitable
```
This method is called when [Vitest](/api/advanced/vitest) was initiated or started, but before the tests were filtered.
::: info
Internally this method is called inside [`vitest.start`](/api/advanced/vitest#start), [`vitest.init`](/api/advanced/vitest#init) or [`vitest.mergeReports`](/api/advanced/vitest#mergereports). If you are using programmatic API, make sure to call either one depending on your needs before calling [`vitest.runTestSpecifications`](/api/advanced/vitest#runtestspecifications), for example. Built-in CLI will always run methods in correct order.
:::
Note that you can also get access to `vitest` instance from test cases, suites and test modules via a [`project`](/api/advanced/test-project) property, but it might also be useful to store a reference to `vitest` in this method.
::: details Example
```ts
import type { Reporter, TestSpecification, Vitest } from 'vitest/node'
class MyReporter implements Reporter {
private vitest!: Vitest
onInit(vitest: Vitest) {
this.vitest = vitest
}
onTestRunStart(specifications: TestSpecification[]) {
console.log(
specifications.length,
'test files will run in',
this.vitest.config.root,
)
}
}
export default new MyReporter()
```
:::
## onBrowserInit {#onbrowserinit}
```ts
function onBrowserInit(project: TestProject): Awaitable
```
This method is called when the browser instance is initiated. It receives an instance of the project for which the browser is initiated. `project.browser` will always be defined when this method is called.
## onTestRunStart
```ts
function onTestRunStart(
specifications: TestSpecification[]
): Awaitable
```
This method is called when a new test run has started. It receives an array of [test specifications](/api/advanced/test-specification) scheduled to run. This array is readonly and available only for information purposes.
If Vitest didn't find any test files to run, this event will be invoked with an empty array, and then [`onTestRunEnd`](#ontestrunend) will be called immediately after.
::: details Example
```ts
import type { Reporter, TestSpecification } from 'vitest/node'
class MyReporter implements Reporter {
onTestRunStart(specifications: TestSpecification[]) {
console.log(specifications.length, 'test files will run')
}
}
export default new MyReporter()
```
:::
## onTestRunEnd
```ts
function onTestRunEnd(
testModules: ReadonlyArray,
unhandledErrors: ReadonlyArray,
reason: TestRunEndReason
): Awaitable
```
This method is called after all tests have finished running and the coverage merged all reports, if it's enabled. Note that you can get the coverage information in [`onCoverage`](#oncoverage) hook.
It receives a readonly list of test modules. You can iterate over it via a [`testModule.children`](/api/advanced/test-collection) property to report the state and errors, if any.
The second argument is a readonly list of unhandled errors that Vitest wasn't able to attribute to any test. These can happen outside of the test run because of an error in a plugin, or inside the test run as a side-effect of a non-awaited function (for example, a timeout that threw an error after the test has finished running).
The third argument indicated why the test run was finished:
- `passed`: test run was finished normally and there are no errors
- `failed`: test run has at least one error (due to a syntax error during collection or an actual error during test execution)
- `interrupted`: test was interrupted by [`vitest.cancelCurrentRun`](/api/advanced/vitest#cancelcurrentrun) call or `Ctrl+C` was pressed in the terminal (note that it's still possible to have failed tests in this case)
If Vitest didn't find any test files to run, this event will be invoked with empty arrays of modules and errors, and the state will depend on the value of [`config.passWithNoTests`](/config/passwithnotests).
::: details Example
```ts
import type {
Reporter,
SerializedError,
TestModule,
TestRunEndReason,
TestSpecification
} from 'vitest/node'
class MyReporter implements Reporter {
onTestRunEnd(
testModules: ReadonlyArray,
unhandledErrors: ReadonlyArray,
reason: TestRunEndReason,
) {
if (reason === 'passed') {
testModules.forEach(module => console.log(module.moduleId, 'succeeded'))
}
else if (reason === 'failed') {
// note that this will skip possible errors in suites
// you can get them from testSuite.errors()
for (const testCase of testModules.children.allTests()) {
if (testCase.result().state === 'failed') {
console.log(testCase.fullName, 'in', testCase.module.moduleId, 'failed')
console.log(testCase.result().errors)
}
}
}
else {
console.log('test run was interrupted, skipping report')
}
}
}
export default new MyReporter()
```
:::
## onCoverage
```ts
function onCoverage(coverage: unknown): Awaitable
```
This hook is called after coverage results have been processed. Coverage provider's reporters are called after this hook. The typings of `coverage` depends on the `coverage.provider`. For Vitest's default built-in providers you can import the types from `istanbul-lib-coverage` package:
```ts
import type { CoverageMap } from 'istanbul-lib-coverage'
declare function onCoverage(coverage: CoverageMap): Awaitable
```
If Vitest didn't perform any coverage, this hook is not called.
## onTestModuleQueued
```ts
function onTestModuleQueued(testModule: TestModule): Awaitable
```
This method is called right before Vitest imports the setup file and the test module itself. This means that `testModule` will have no [`children`](/api/advanced/test-suite#children) yet, but you can start reporting it as the next test to run.
## onTestModuleCollected
```ts
function onTestModuleCollected(testModule: TestModule): Awaitable
```
This method is called when all tests inside the file were collected, meaning [`testModule.children`](/api/advanced/test-suite#children) collection is populated, but tests don't have any results yet.
## onTestModuleStart
```ts
function onTestModuleStart(testModule: TestModule): Awaitable
```
This method is called right after [`onTestModuleCollected`](#ontestmodulecollected) unless Vitest runs in collection mode ([`vitest.collect()`](/api/advanced/vitest#collect) or `vitest collect` in the CLI), in this case it will not be called at all because there are no tests to run.
## onTestModuleEnd
```ts
function onTestModuleEnd(testModule: TestModule): Awaitable
```
This method is called when every test in the module finished running. This means, every test inside [`testModule.children`](/api/advanced/test-suite#children) will have a `test.result()` that is not equal to `pending`.
## onHookStart
```ts
function onHookStart(context: ReportedHookContext): Awaitable
```
This method is called when any of these hooks have started running:
- `beforeAll`
- `afterAll`
- `beforeEach`
- `afterEach`
If `beforeAll` or `afterAll` are started, the `entity` will be either [`TestSuite`](/api/advanced/test-suite) or [`TestModule`](/api/advanced/test-module).
If `beforeEach` or `afterEach` are started, the `entity` will always be [`TestCase`](/api/advanced/test-case).
::: warning
`onHookStart` method will not be called if the hook did not run during the test run.
:::
## onHookEnd
```ts
function onHookEnd(context: ReportedHookContext): Awaitable
```
This method is called when any of these hooks have finished running:
- `beforeAll`
- `afterAll`
- `beforeEach`
- `afterEach`
If `beforeAll` or `afterAll` have finished, the `entity` will be either [`TestSuite`](/api/advanced/test-suite) or [`TestModule`](/api/advanced/test-module).
If `beforeEach` or `afterEach` have finished, the `entity` will always be [`TestCase`](/api/advanced/test-case).
::: warning
`onHookEnd` method will not be called if the hook did not run during the test run.
:::
## onTestSuiteReady
```ts
function onTestSuiteReady(testSuite: TestSuite): Awaitable
```
This method is called before the suite starts to run its tests. This method is also called if the suite was skipped.
If the file doesn't have any suites, this method will not be called. Consider using `onTestModuleStart` to cover this use case.
## onTestSuiteResult
```ts
function onTestSuiteResult(testSuite: TestSuite): Awaitable
```
This method is called after the suite has finished running tests. This method is also called if the suite was skipped.
If the file doesn't have any suites, this method will not be called. Consider using `onTestModuleEnd` to cover this use case.
## onTestCaseReady
```ts
function onTestCaseReady(testCase: TestCase): Awaitable
```
This method is called before the test starts to run or it was skipped. Note that `beforeEach` and `afterEach` hooks are considered part of the test because they can influence the result.
::: warning
Notice that it's possible to have [`testCase.result()`](/api/advanced/test-case#result) with `passed` or `failed` state already when `onTestCaseReady` is called. This can happen if test was running too fast and both `onTestCaseReady` and `onTestCaseResult` were scheduled to run in the same microtask.
:::
## onTestCaseResult
```ts
function onTestCaseResult(testCase: TestCase): Awaitable
```
This method is called when the test has finished running or was just skipped. Note that this will be called after the `afterEach` hook is finished, if there are any.
At this point, [`testCase.result()`](/api/advanced/test-case#result) will have non-pending state.
## onTestCaseAnnotate 3.2.0 {#ontestcaseannotate}
```ts
function onTestCaseAnnotate(
testCase: TestCase,
annotation: TestAnnotation,
): Awaitable
```
The `onTestCaseAnnotate` hook is associated with the [`context.annotate`](/guide/test-context#annotate) method. When `annotate` is invoked, Vitest serialises it and sends the same attachment to the main thread where reporter can interact with it.
If the path is specified, Vitest stores it in a separate directory (configured by [`attachmentsDir`](/config/attachmentsdir)) and modifies the `path` property to reference it.
## onTestCaseArtifactRecord 4.0.11 {#ontestcaseartifactrecord}
```ts
function onTestCaseArtifactRecord(
testCase: TestCase,
artifact: TestArtifact,
): Awaitable
```
The `onTestCaseArtifactRecord` hook is associated with the [`recordArtifact`](/api/advanced/artifacts#recordartifact) utility. When `recordArtifact` is invoked, Vitest serialises it and sends the same attachment to the main thread where reporter can interact with it.
If the path is specified, Vitest stores it in a separate directory (configured by [`attachmentsDir`](/config/attachmentsdir)) and modifies the `path` property to reference it.
Note: annotations, [even though they're built on top of this feature](/api/advanced/artifacts#relationship-with-annotations), won't hit this hook and won't appear in the `task.artifacts` array for backwards compatibility reasons until the next major version.
================================================
FILE: docs/api/advanced/runner.md
================================================
# Runner API advanced
::: warning
This is advanced API. If you just want to [run tests](/guide/), you probably don't need this. It is primarily used by library authors.
:::
You can specify a path to your test runner with the `runner` option in your configuration file. This file should have a default export with a class constructor implementing these methods:
```ts
export interface VitestRunner {
/**
* First thing that's getting called before actually collecting and running tests.
*/
onBeforeCollect?: (paths: string[]) => unknown
/**
* Called after collecting tests and before "onBeforeRun".
*/
onCollected?: (files: File[]) => unknown
/**
* Called when test runner should cancel next test runs.
* Runner should listen for this method and mark tests and suites as skipped in
* "onBeforeRunSuite" and "onBeforeRunTask" when called.
*/
onCancel?: (reason: CancelReason) => unknown
/**
* Called before running a single test. Doesn't have "result" yet.
*/
onBeforeRunTask?: (test: Test) => unknown
/**
* Called before actually running the test function. Already has "result" with "state" and "startTime".
*/
onBeforeTryTask?: (test: Test, options: { retry: number; repeats: number }) => unknown
/**
* Called after result and state are set.
*/
onAfterRunTask?: (test: Test) => unknown
/**
* Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
*/
onAfterTryTask?: (test: Test, options: { retry: number; repeats: number }) => unknown
/**
* Called after the retry resolution happened. Unlike `onAfterTryTask`, the test now has a new state.
* All `after` hooks were also called by this point.
*/
onAfterRetryTask?: (test: Test, options: { retry: number; repeats: number }) => unknown
/**
* Called before running a single suite. Doesn't have "result" yet.
*/
onBeforeRunSuite?: (suite: Suite) => unknown
/**
* Called after running a single suite. Has state and result.
*/
onAfterRunSuite?: (suite: Suite) => unknown
/**
* If defined, will be called instead of usual Vitest suite partition and handling.
* "before" and "after" hooks will not be ignored.
*/
runSuite?: (suite: Suite) => Promise
/**
* If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
* "before" and "after" hooks will not be ignored.
*/
runTask?: (test: TaskPopulated) => Promise
/**
* Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
*/
onTaskUpdate?: (task: [string, TaskResult | undefined, TaskMeta | undefined][]) => Promise
/**
* Called before running all tests in collected paths.
*/
onBeforeRunFiles?: (files: File[]) => unknown
/**
* Called right after running all tests in collected paths.
*/
onAfterRunFiles?: (files: File[]) => unknown
/**
* Called when new context for a test is defined. Useful, if you want to add custom properties to the context.
* If you only want to define custom context with a runner, consider using "beforeAll" in "setupFiles" instead.
*/
extendTaskContext?: (context: TestContext) => TestContext
/**
* Called when certain files are imported. Can be called in two situations: to collect tests and to import setup files.
*/
importFile: (filepath: string, source: VitestRunnerImportSource) => unknown
/**
* Function that is called when the runner attempts to get the value when `test.extend` is used with `{ injected: true }`
*/
injectValue?: (key: string) => unknown
/**
* Publicly available configuration.
*/
config: VitestRunnerConfig
/**
* The name of the current pool. Can affect how stack trace is inferred on the server side.
*/
pool?: string
}
```
When initiating this class, Vitest passes down Vitest config, - you should expose it as a `config` property:
```ts [runner.ts]
import type { RunnerTestFile, SerializedConfig, TestRunner, VitestTestRunner } from 'vitest'
class CustomRunner extends TestRunner implements VitestTestRunner {
public config: SerializedConfig
constructor(config: SerializedConfig) {
this.config = config
}
onAfterRunFiles(files: RunnerTestFile[]) {
console.log('finished running', files)
}
}
export default CustomRunner
```
::: warning
Vitest also injects an instance of `ModuleRunner` from `vite/module-runner` as `moduleRunner` property. You can use it to process files in `importFile` method (this is default behavior of `TestRunner` and `BenchmarkRunner`).
`ModuleRunner` exposes `import` method, which is used to import test files in a Vite-friendly environment. Meaning, it will resolve imports and transform file content at runtime so that Node can understand it:
```ts
export default class Runner {
async importFile(filepath: string) {
await this.moduleRunner.import(filepath)
}
}
```
:::
::: warning
If you don't have a custom runner or didn't define `runTest` method, Vitest will try to retrieve a task automatically. If you didn't add a function with `setFn`, it will fail.
:::
::: tip
Snapshot support and some other features depend on the runner. If you don't want to lose it, you can extend your runner from `VitestTestRunner` imported from `vitest/runners`. It also exposes `NodeBenchmarkRunner`, if you want to extend benchmark functionality.
:::
## Tasks
::: warning
The "Runner Tasks API" is experimental and should primarily be used only in the test runtime. Vitest also exposes the ["Reported Tasks API"](/api/advanced/test-module), which should be preferred when working in the main thread (inside the reporter, for example).
The team is currently discussing if "Runner Tasks" should be replaced by "Reported Tasks" in the future.
:::
Suites and tests are called `tasks` internally. Vitest runner initiates a `File` task before collecting any tests - this is a superset of `Suite` with a few additional properties. It is available on every task (including `File`) as a `file` property.
```ts
interface File extends Suite {
/**
* The name of the pool that the file belongs to.
* @default 'forks'
*/
pool?: string
/**
* The path to the file in UNIX format.
*/
filepath: string
/**
* The name of the test project the file belongs to.
*/
projectName: string | undefined
/**
* The time it took to collect all tests in the file.
* This time also includes importing all the file dependencies.
*/
collectDuration?: number
/**
* The time it took to import the setup file.
*/
setupDuration?: number
}
```
Every suite has a `tasks` property that is populated during collection phase. It is useful to traverse the task tree from the top down.
```ts
interface Suite extends TaskBase {
type: 'suite'
/**
* File task. It's the root task of the file.
*/
file: File
/**
* An array of tasks that are part of the suite.
*/
tasks: Task[]
}
```
Every task has a `suite` property that references a suite it is located in. If `test` or `describe` are initiated at the top level, they will not have a `suite` property (it will **not** be equal to `file`!). `File` also never has a `suite` property. It is useful to travers the tasks from the bottom up.
```ts
interface Test extends TaskBase {
type: 'test'
/**
* Test context that will be passed to the test function.
*/
context: TestContext & ExtraContext
/**
* File task. It's the root task of the file.
*/
file: File
/**
* Whether the task was skipped by calling `context.skip()`.
*/
pending?: boolean
/**
* Whether the task should succeed if it fails. If the task fails, it will be marked as passed.
*/
fails?: boolean
/**
* Store promises (from async expects) to wait for them before finishing the test
*/
promises?: Promise[]
}
```
Every task can have a `result` field. Suites can only have this field if an error thrown within a suite callback or `beforeAll`/`afterAll` callbacks prevents them from collecting tests. Tests always have this field after their callbacks are called - the `state` and `errors` fields are present depending on the outcome. If an error was thrown in `beforeEach` or `afterEach` callbacks, the thrown error will be present in `task.result.errors`.
```ts
export interface TaskResult {
/**
* State of the task. Inherits the `task.mode` during collection.
* When the task has finished, it will be changed to `pass` or `fail`.
* - **pass**: task ran successfully
* - **fail**: task failed
*/
state: TaskState
/**
* Errors that occurred during the task execution. It is possible to have several errors
* if `expect.soft()` failed multiple times.
*/
errors?: TestError[]
/**
* How long in milliseconds the task took to run.
*/
duration?: number
/**
* Time in milliseconds when the task started running.
*/
startTime?: number
/**
* Heap size in bytes after the task finished.
* Only available if `logHeapUsage` option is set and `process.memoryUsage` is defined.
*/
heap?: number
/**
* State of related to this task hooks. Useful during reporting.
*/
hooks?: Partial>
/**
* The amount of times the task was retried. The task is retried only if it
* failed and `retry` option is set.
*/
retryCount?: number
/**
* The amount of times the task was repeated. The task is repeated only if
* `repeats` option is set. This number also contains `retryCount`.
*/
repeatCount?: number
}
```
## Your Task Function
Vitest exposes `createTaskCollector` utility to create your own `test` method. It behaves the same way as a test, but calls a custom method during collection.
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 [custom.js]
export { afterAll, beforeAll, describe, TestRunner } from 'vitest'
// this function will be called during collection phase:
// don't call function handler here, add it to suite tasks
// with "getCurrentSuite().task()" method
// note: createTaskCollector provides support for "todo"/"each"/...
export const myCustomTask = TestRunner.createTaskCollector(
function (name, fn, timeout) {
TestRunner.getCurrentSuite().task(name, {
...this, // so "todo"/"skip"/... is tracked correctly
meta: {
customPropertyToDifferentiateTask: true
},
handler: fn,
timeout,
})
}
)
```
```js [tasks.test.js]
import {
afterAll,
beforeAll,
describe,
myCustomTask
} from './custom.js'
import { gardener } from './gardener.js'
describe('take care of the garden', () => {
beforeAll(() => {
gardener.putWorkingClothes()
})
myCustomTask('weed the grass', () => {
gardener.weedTheGrass()
})
myCustomTask.todo('mow the lawn', () => {
gardener.mowerTheLawn()
})
myCustomTask('water flowers', () => {
gardener.waterFlowers()
})
afterAll(() => {
gardener.goHome()
})
})
```
```bash
vitest ./garden/tasks.test.js
```
================================================
FILE: docs/api/advanced/test-case.md
================================================
# TestCase
The `TestCase` class represents a single test. This class is only available in the main thread. Refer to the ["Runner API"](/api/advanced/runner#tasks) if you are working with runtime tasks.
The `TestCase` instance always has a `type` property with the value of `test`. You can use it to distinguish between different task types:
```ts
if (task.type === 'test') {
task // TestCase
}
```
## project
This references the [`TestProject`](/api/advanced/test-project) that the test belongs to.
## module
This is a direct reference to the [`TestModule`](/api/advanced/test-module) where the test is defined.
## name
This is a test name that was passed to the `test` function.
```ts
import { test } from 'vitest'
// [!code word:'the validation works correctly']
test('the validation works correctly', () => {
// ...
})
```
## fullName
The name of the test including all parent suites separated with `>` symbol. This test has a full name "the validation logic > the validation works correctly":
```ts
import { describe, test } from 'vitest'
// [!code word:'the validation works correctly']
// [!code word:'the validation logic']
describe('the validation logic', () => {
test('the validation works correctly', () => {
// ...
})
})
```
## id
This is test's 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](/api/advanced/test-project) name, module ID and test order.
The ID looks like this:
```
1223128da3_0_0
^^^^^^^^^^ the file hash
^ suite index
^ test index
```
::: tip
You can generate file hash with `generateFileHash` function from `vitest/node` which is available since Vitest 3:
```ts
import { generateFileHash } from 'vitest/node'
const hash = generateFileHash(
'/file/path.js', // relative path
undefined, // the project name or `undefined` is not set
)
```
:::
::: danger
Don't try to parse the ID. It can have a minus at the start: `-1223128da3_0_0_0`.
:::
## location
The location in the module where the test was defined. Locations are collected only if [`includeTaskLocation`](/config/includetasklocation) is enabled in the config. Note that this option is automatically enabled if `--reporter=html`, `--ui` or `--browser` flags are used.
The location of this test will be equal to `{ line: 3, column: 1 }`:
```ts:line-numbers {3}
import { test } from 'vitest'
test('the validation works correctly', () => {
// ...
})
```
## parent
Parent [suite](/api/advanced/test-suite). If the test was called directly inside the [module](/api/advanced/test-module), the parent will be the module itself.
## options
```ts
interface TaskOptions {
readonly each: boolean | undefined
readonly fails: boolean | undefined
readonly concurrent: boolean | undefined
readonly shuffle: boolean | undefined
readonly retry: number | undefined
readonly repeats: number | undefined
readonly tags: string[] | undefined
readonly timeout: number | undefined
readonly mode: 'run' | 'only' | 'skip' | 'todo'
}
```
The options that test was collected with.
## tags 4.1.0 {#tags}
[Tags](/guide/test-tags) that were implicitly or explicitly assigned to the test.
## ok
```ts
function ok(): boolean
```
Checks if the test did not fail the suite. If the test is not finished yet or was skipped, it will return `true`.
## meta
```ts
function meta(): TaskMeta
```
Custom [metadata](/api/advanced/metadata) that was attached to the test during its execution. The meta can be attached by assigning a property to the `ctx.task.meta` object during a test run:
```ts {3,6}
import { test } from 'vitest'
test('the validation works correctly', ({ task }) => {
// ...
task.meta.decorated = false
})
```
If the test did not finish running yet, the meta will be an empty object, unless it has static meta:
```ts
test('the validation works correctly', { meta: { decorated: true } })
```
Since Vitest 4.1, Vitest inherits [`meta`](/api/advanced/test-suite#meta) property defined on the [suite](/api/advanced/test-suite).
## result
```ts
function result(): TestResult
```
Test results. If test is not finished yet or was just collected, it will be equal to `TestResultPending`:
```ts
export interface TestResultPending {
/**
* The test was collected, but didn't finish running yet.
*/
readonly state: 'pending'
/**
* Pending tests have no errors.
*/
readonly errors: undefined
}
```
If the test was skipped, the return value will be `TestResultSkipped`:
```ts
interface TestResultSkipped {
/**
* The test was skipped with `skip` or `todo` flag.
* You can see which one was used in the `options.mode` option.
*/
readonly state: 'skipped'
/**
* Skipped tests have no errors.
*/
readonly errors: undefined
/**
* A custom note passed down to `ctx.skip(note)`.
*/
readonly note: string | undefined
}
```
::: tip
If the test was skipped because another test has `only` flag, the `options.mode` will be equal to `skip`.
:::
If the test failed, the return value will be `TestResultFailed`:
```ts
interface TestResultFailed {
/**
* The test failed to execute.
*/
readonly state: 'failed'
/**
* Errors that were thrown during the test execution.
*/
readonly errors: ReadonlyArray
}
```
If the test passed, the return value will be `TestResultPassed`:
```ts
interface TestResultPassed {
/**
* The test passed successfully.
*/
readonly state: 'passed'
/**
* Errors that were thrown during the test execution.
*/
readonly errors: ReadonlyArray | undefined
}
```
::: warning
Note that the test with `passed` state can still have errors attached - this can happen if `retry` was triggered at least once.
:::
## diagnostic
```ts
function diagnostic(): TestDiagnostic | undefined
```
Useful information about the test like duration, memory usage, etc:
```ts
interface TestDiagnostic {
/**
* If the duration of the test is above `slowTestThreshold`.
*/
readonly slow: boolean
/**
* The amount of memory used by the test in bytes.
* This value is only available if the test was executed with `logHeapUsage` flag.
*/
readonly heap: number | undefined
/**
* The time it takes to execute the test in ms.
*/
readonly duration: number
/**
* The time in ms when the test started.
*/
readonly startTime: number
/**
* The amount of times the test was retried.
*/
readonly 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.
*/
readonly repeatCount: number
/**
* If test passed on a second retry.
*/
readonly flaky: boolean
}
```
::: info
`diagnostic()` will return `undefined` if the test was not scheduled to run yet.
:::
## annotations
```ts
function annotations(): ReadonlyArray
```
[Test annotations](/guide/test-annotations) added via the [`task.annotate`](/guide/test-context#annotate) API during the test execution.
## artifacts 4.0.11 {#artifacts}
```ts
function artifacts(): ReadonlyArray
```
[Test artifacts](/api/advanced/artifacts) recorded via the `recordArtifact` API during the test execution.
## toTestSpecification 4.1.0 {#totestspecification}
```ts
function toTestSpecification(): TestSpecification
```
Returns a new [test specification](/api/advanced/test-specification) that can be used to filter or run this specific test case.
================================================
FILE: docs/api/advanced/test-collection.md
================================================
# TestCollection
`TestCollection` represents a collection of top-level [suites](/api/advanced/test-suite) and [tests](/api/advanced/test-case) in a suite or a module. It also provides useful methods to iterate over itself.
::: info
Most methods return an iterator instead of an array for better performance in case you don't need every item in the collection. If you prefer working with array, you can spread the iterator: `[...children.allSuites()]`.
Also note that the collection itself is an iterator:
```ts
for (const child of module.children) {
console.log(child.type, child.name)
}
```
:::
## size
The number of tests and suites in the collection.
::: warning
This number includes only tests and suites at the top-level, it doesn't include nested suites and tests.
:::
## at
```ts
function at(index: number): TestCase | TestSuite | undefined
```
Returns the test or suite at a specific index. This method accepts negative indexes.
## array
```ts
function array(): (TestCase | TestSuite)[]
```
The same collection but as an array. This is useful if you want to use `Array` methods like `map` and `filter` that are not supported by the `TaskCollection` implementation.
## allSuites
```ts
function allSuites(): Generator
```
Filters all suites that are part of this collection and its children.
```ts
for (const suite of module.children.allSuites()) {
if (suite.errors().length) {
console.log('failed to collect', suite.errors())
}
}
```
## allTests
```ts
function allTests(state?: TestState): Generator
```
Filters all tests that are part of this collection and its children.
```ts
for (const test of module.children.allTests()) {
if (test.result().state === 'pending') {
console.log('test', test.fullName, 'did not finish')
}
}
```
You can pass down a `state` value to filter tests by the state.
## tests
```ts
function tests(state?: TestState): Generator
```
Filters only the tests that are part of this collection. You can pass down a `state` value to filter tests by the state.
## suites
```ts
function suites(): Generator
```
Filters only the suites that are part of this collection.
================================================
FILE: docs/api/advanced/test-module.md
================================================
# TestModule
The `TestModule` class represents a single module in a single project. This class is only available in the main thread. Refer to the ["Runner API"](/api/advanced/runner#tasks) if you are working with runtime tasks.
The `TestModule` instance always has a `type` property with the value of `module`. You can use it to distinguish between different task types:
```ts
if (task.type === 'module') {
task // TestModule
}
```
::: warning Extending Suite Methods
The `TestModule` class inherits all methods and properties from the [`TestSuite`](/api/advanced/test-suite). This guide will only list methods and properties unique to the `TestModule`.
:::
## moduleId
This is usually an absolute unix file path (even on Windows). It can be a virtual id if the file is not on the disk. This value corresponds to Vite's `ModuleGraph` id.
```ts
'C:/Users/Documents/project/example.test.ts' // ✅
'/Users/mac/project/example.test.ts' // ✅
'C:\\Users\\Documents\\project\\example.test.ts' // ❌
```
## relativeModuleId
Module id relative to the project. This is the same as `task.name` in the deprecated API.
```ts
'project/example.test.ts' // ✅
'example.test.ts' // ✅
'project\\example.test.ts' // ❌
```
## state
```ts
function state(): TestModuleState
```
Works the same way as [`testSuite.state()`](/api/advanced/test-suite#state), but can also return `queued` if module wasn't executed yet.
## meta 3.1.0 {#meta}
```ts
function meta(): TaskMeta
```
Custom [metadata](/api/advanced/metadata) that was attached to the module during its execution or collection. The meta can be attached by assigning a property to the `task.meta` object during a test run:
```ts {5,10}
import { test } from 'vitest'
describe('the validation works correctly', (task) => {
// assign "decorated" during collection
task.file.meta.decorated = false
test('some test', ({ task }) => {
// assign "decorated" during test run, it will be available
// only in onTestCaseReady hook
task.file.meta.decorated = false
})
})
```
:::tip
If metadata was attached during collection (outside of the `test` function), then it will be available in [`onTestModuleCollected`](./reporters#ontestmodulecollected) hook in the custom reporter.
:::
## diagnostic
```ts
function diagnostic(): ModuleDiagnostic
```
Useful information about the module like duration, memory usage, etc. If the module was not executed yet, all diagnostic values will return `0`.
```ts
interface ModuleDiagnostic {
/**
* The time it takes to import and initiate an environment.
*/
readonly environmentSetupDuration: number
/**
* The time it takes Vitest to setup test harness (runner, mocks, etc.).
*/
readonly prepareDuration: number
/**
* The time it takes to import the test module.
* This includes importing everything in the module and executing suite callbacks.
*/
readonly collectDuration: number
/**
* The time it takes to import the setup module.
*/
readonly setupDuration: number
/**
* Accumulated duration of all tests and hooks in the module.
*/
readonly duration: number
/**
* The amount of memory used by the module in bytes.
* This value is only available if the test was executed with `logHeapUsage` flag.
*/
readonly heap: number | undefined
/**
* The time spent importing every non-externalized dependency that Vitest has processed.
*/
readonly importDurations: Record
}
/** The time spent importing & executing a non-externalized file. */
interface ImportDuration {
/** The time spent importing & executing the file itself, not counting all non-externalized imports that the file does. */
selfTime: number
/** The time spent importing & executing the file and all its imports. */
totalTime: number
}
```
## viteEnvironment 4.1.0 {#viteenvironment}
This is a Vite's [`DevEnvironment`](https://vite.dev/guide/api-environment) that transforms all files inside of the test module.
::: details History
- `v4.0.15`: added as experimental
:::
## toTestSpecification 4.1.0 {#totestspecification}
```ts
function toTestSpecification(testCases?: TestCase[]): TestSpecification
```
Returns a new [test specification](/api/advanced/test-specification) that can be used to filter or run this specific test module.
It accepts an optional array of test cases that should be filtered.
================================================
FILE: docs/api/advanced/test-project.md
================================================
---
title: TestProject
---
# TestProject 3.0.0 {#testproject}
::: warning
This guide describes the advanced Node.js API. If you just want to define projects, follow the ["Test Projects"](/guide/projects) guide.
:::
## name
The name is a unique string assigned by the user or interpreted by Vitest. If user did not provide a name, Vitest tries to load a `package.json` in the root of the project and takes the `name` property from there. If there is no `package.json`, Vitest uses the name of the folder by default. Inline projects use numbers as the name (converted to string).
::: code-group
```ts [node.js]
import { createVitest } from 'vitest/node'
const vitest = await createVitest('test')
vitest.projects.map(p => p.name) === [
'@pkg/server',
'utils',
'2',
'custom'
]
```
```ts [vitest.config.js]
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
projects: [
'./packages/server', // has package.json with "@pkg/server"
'./utils', // doesn't have a package.json file
{
// doesn't customize the name
test: {
pool: 'threads',
},
},
{
// customized the name
test: {
name: 'custom',
},
},
],
},
})
```
:::
::: info
If the [root project](/api/advanced/vitest#getrootproject) is not part of user projects, its `name` will not be resolved.
:::
## vitest
`vitest` references the global [`Vitest`](/api/advanced/vitest) process.
## serializedConfig
This is the config that test processes receive. Vitest [serializes config](https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/config/serializeConfig.ts) manually by removing all functions and properties that are not possible to serialize. Since this value is available in both tests and node, its type is exported from the main entry point.
```ts
import type { SerializedConfig } from 'vitest'
const config: SerializedConfig = vitest.projects[0].serializedConfig
```
::: warning
The `serializedConfig` property is a getter. Every time it's accessed Vitest serializes the config again in case it was changed. This also means that it always returns a different reference:
```ts
project.serializedConfig === project.serializedConfig // ❌
```
:::
## globalConfig
The test config that [`Vitest`](/api/advanced/vitest) was initialized with. If this is the [root project](/api/advanced/vitest#getrootproject), `globalConfig` and `config` will reference the same object. This config is useful for values that cannot be set on the project level, like `coverage` or `reporters`.
```ts
import type { ResolvedConfig } from 'vitest/node'
vitest.config === vitest.projects[0].globalConfig
```
## config
This is the project's resolved test config.
## hash 3.2.0 {#hash}
The unique hash of this project. This value is consistent between the reruns.
It is based on the root of the project and its name. Note that the root path is not consistent between different OS, so the hash will also be different.
## vite
This is project's [`ViteDevServer`](https://vite.dev/guide/api-javascript#vitedevserver). All projects have their own Vite servers.
## browser
This value will be set only if tests are running in the browser. If `browser` is enabled, but tests didn't run yet, this will be `undefined`. If you need to check if the project supports browser tests, use `project.isBrowserEnabled()` method.
::: warning
The browser API is even more experimental and doesn't follow SemVer. The browser API will be standardized separately from the rest of the APIs.
:::
## provide
```ts
function provide(
key: T,
value: ProvidedContext[T],
): void
```
A way to provide custom values to tests in addition to [`config.provide`](/config/provide) field. All values are validated with [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) before they are stored, but the values on `providedContext` themselves are not cloned.
::: code-group
```ts [node.js]
import { createVitest } from 'vitest/node'
const vitest = await createVitest('test')
const project = vitest.projects.find(p => p.name === 'custom')
project.provide('key', 'value')
await vitest.start()
```
```ts [test.spec.js]
import { inject } from 'vitest'
const value = inject('key')
```
:::
The values can be provided dynamically. Provided value in tests will be updated on their next run.
::: tip
This method is also available to [global setup files](/config/globalsetup) for cases where you cannot use the public API:
```js
export default function setup({ provide }) {
provide('wsPort', 3000)
}
```
:::
## getProvidedContext
```ts
function getProvidedContext(): ProvidedContext
```
This returns the context object. Every project also inherits the global context set by `vitest.provide`.
```ts
import { createVitest } from 'vitest/node'
const vitest = await createVitest('test')
vitest.provide('global', true)
const project = vitest.projects.find(p => p.name === 'custom')
project.provide('key', 'value')
// { global: true, key: 'value' }
const context = project.getProvidedContext()
```
::: tip
Project context values will always override root project's context.
:::
## createSpecification
```ts
function createSpecification(
moduleId: string,
locations?: number[],
): TestSpecification
```
Create a [test specification](/api/advanced/test-specification) that can be used in [`vitest.runTestSpecifications`](/api/advanced/vitest#runtestspecifications). Specification scopes the test file to a specific `project` and test `locations` (optional). Test [locations](/api/advanced/test-case#location) are code lines where the test is defined in the source code. If locations are provided, Vitest will only run tests defined on those lines. Note that if [`testNamePattern`](/config/testnamepattern) is defined, then it will also be applied.
```ts
import { createVitest } from 'vitest/node'
import { resolve } from 'node:path/posix'
const vitest = await createVitest('test')
const project = vitest.projects[0]
const specification = project.createSpecification(
resolve('./example.test.ts'),
[20, 40], // optional test lines
)
await vitest.runTestSpecifications([specification])
```
::: warning
`createSpecification` expects resolved [module ID](/api/advanced/test-specification#moduleid). It doesn't auto-resolve the file or check that it exists on the file system.
Also note that `project.createSpecification` always returns a new instance.
:::
## isRootProject
```ts
function isRootProject(): boolean
```
Checks if the current project is the root project. You can also get the root project by calling [`vitest.getRootProject()`](/api/advanced/vitest#getrootproject).
## globTestFiles
```ts
function globTestFiles(filters?: string[]): {
/**
* Test files that match the filters.
*/
testFiles: string[]
/**
* Typecheck test files that match the filters. This will be empty unless `typecheck.enabled` is `true`.
*/
typecheckTestFiles: string[]
}
```
Globs all test files. This function returns an object with regular tests and typecheck tests.
This method accepts `filters`. Filters can only a part of the file path, unlike in other methods on the [`Vitest`](/api/advanced/vitest) instance:
```js
project.globTestFiles(['foo']) // ✅
project.globTestFiles(['basic/foo.js:10']) // ❌
```
::: tip
Vitest uses [fast-glob](https://npmx.dev/package/fast-glob) to find test files. `test.dir`, `test.root`, `root` or `process.cwd()` define the `cwd` option.
This method looks at several config options:
- `test.include`, `test.exclude` to find regular test files
- `test.includeSource`, `test.exclude` to find in-source tests
- `test.typecheck.include`, `test.typecheck.exclude` to find typecheck tests
:::
## matchesTestGlob
```ts
function matchesTestGlob(
moduleId: string,
source?: () => string
): boolean
```
This method checks if the file is a regular test file. It uses the same config properties that `globTestFiles` uses for validation.
This method also accepts a second parameter, which is the source code. This is used to validate if the file is an in-source test. If you are calling this method several times for several projects it is recommended to read the file once and pass it down directly. If the file is not a test file, but matches the `includeSource` glob, Vitest will synchronously read the file unless the `source` is provided.
```ts
import { createVitest } from 'vitest/node'
import { resolve } from 'node:path/posix'
const vitest = await createVitest('test')
const project = vitest.projects[0]
project.matchesTestGlob(resolve('./basic.test.ts')) // true
project.matchesTestGlob(resolve('./basic.ts')) // false
project.matchesTestGlob(resolve('./basic.ts'), () => `
if (import.meta.vitest) {
// ...
}
`) // true if `includeSource` is set
```
## import
Import a file using Vite module runner. The file will be transformed by Vite with provided project's config and executed in a separate context. Note that `moduleId` will be relative to the `config.root`.
::: danger
`project.import` reuses Vite's module graph, so importing the same module using a regular import will return a different module:
```ts
import * as staticExample from './example.js'
const dynamicExample = await project.import('./example.js')
dynamicExample !== staticExample // ✅
```
:::
::: info
Internally, Vitest uses this method to import global setups, custom coverage providers and custom reporters, meaning all of them share the same module graph as long as they belong to the same Vite server.
:::
## onTestsRerun
```ts
function onTestsRerun(cb: OnTestsRerunHandler): void
```
This is a shorthand for [`project.vitest.onTestsRerun`](/api/advanced/vitest#ontestsrerun). It accepts a callback that will be awaited when the tests have been scheduled to rerun (usually, due to a file change).
```ts
project.onTestsRerun((specs) => {
console.log(specs)
})
```
## isBrowserEnabled
```ts
function isBrowserEnabled(): boolean
```
Returns `true` if this project runs tests in the browser.
## close
```ts
function close(): Promise
```
Closes the project and all associated resources. This can only be called once; the closing promise is cached until the server restarts. If the resources are needed again, create a new project.
In detail, this method closes the Vite server, stops the typechecker service, closes the browser if it's running, deletes the temporary directory that holds the source code, and resets the provided context.
================================================
FILE: docs/api/advanced/test-specification.md
================================================
# TestSpecification
The `TestSpecification` class describes what module to run as a test and its parameters.
You can only create a specification by calling [`createSpecification`](/api/advanced/test-project#createspecification) method on a test project:
```ts
const specification = project.createSpecification(
resolve('./example.test.ts'),
{
testLines: [20, 40],
testNamePattern: /hello world/,
testIds: ['1223128da3_0_0_0', '1223128da3_0_0'],
testTagsFilter: ['frontend and backend'],
} // optional test filters
)
```
`createSpecification` expects resolved module identifier. It doesn't auto-resolve the file or check that it exists on the file system.
## taskId
[Test module's](/api/advanced/test-suite#id) identifier.
## project
This references the [`TestProject`](/api/advanced/test-project) that the test module belongs to.
## moduleId
The ID of the module in Vite's module graph. Usually, it's an absolute file path using posix separator:
```ts
'C:/Users/Documents/project/example.test.ts' // ✅
'/Users/mac/project/example.test.ts' // ✅
'C:\\Users\\Documents\\project\\example.test.ts' // ❌
```
## testModule
Instance of [`TestModule`](/api/advanced/test-module) associated with the specification. If test wasn't queued yet, this will be `undefined`.
## pool {#pool}
The [`pool`](/config/pool) in which the test module will run.
::: danger
It's possible to have multiple pools in a single test project with [`typecheck.enabled`](/config/typecheck#typecheck-enabled). This means it's possible to have several specifications with the same `moduleId` but different `pool`. In later versions, the project will only support a single pool.
:::
## testLines
This is an array of lines in the source code where the test files are defined. This field is defined only if the `createSpecification` method received an array.
Note that if there is no test on at least one of the lines, the whole suite will fail. An example of a correct `testLines` configuration:
::: code-group
```ts [script.js]
const specification = project.createSpecification(
resolve('./example.test.ts'),
[3, 8, 9],
)
```
```ts:line-numbers{3,8,9} [example.test.js]
import { test, describe } from 'vitest'
test('verification works')
describe('a group of tests', () => { // [!code error]
// ...
test('nested test')
test.skip('skipped test')
})
```
:::
## testNamePattern 4.1.0 {#testnamepattern}
A regexp that matches the name of the test in this module. This value will override the global [`testNamePattern`](/config/testnamepattern) option if it's set.
## testIds 4.1.0 {#testids}
The ids of tasks inside of this specification to run.
## testTagsFilter 4.1.0 {#testtagsfilter}
The [tags filter](/guide/test-tags#syntax) that a test must pass in order to be included in the run. Multiple filters are treated as `AND`.
## toJSON
```ts
function toJSON(): SerializedTestSpecification
```
`toJSON` generates a JSON-friendly object that can be consumed by the [Browser Mode](/guide/browser/) or [Vitest UI](/guide/ui).
================================================
FILE: docs/api/advanced/test-suite.md
================================================
# TestSuite
The `TestSuite` class represents a single suite. This class is only available in the main thread. Refer to the ["Runner API"](/api/advanced/runner#tasks) if you are working with runtime tasks.
The `TestSuite` instance always has a `type` property with the value of `suite`. You can use it to distinguish between different task types:
```ts
if (task.type === 'suite') {
task // TestSuite
}
```
## project
This references the [`TestProject`](/api/advanced/test-project) that the test belongs to.
## module
This is a direct reference to the [`TestModule`](/api/advanced/test-module) where the test is defined.
## name
This is a suite name that was passed to the `describe` function.
```ts
import { describe } from 'vitest'
// [!code word:'the validation logic']
describe('the validation logic', () => {
// ...
})
```
## fullName
The name of the suite including all parent suites separated with `>` symbol. This suite has a full name "the validation logic > validating cities":
```ts
import { describe, test } from 'vitest'
// [!code word:'the validation logic']
// [!code word:'validating cities']
describe('the validation logic', () => {
describe('validating cities', () => {
// ...
})
})
```
## id
This is suite's unique identifier. This ID is deterministic and will be the same for the same suite across multiple runs. The ID is based on the [project](/api/advanced/test-project) name, module ID and suite order.
The ID looks like this:
```
1223128da3_0_0_0
^^^^^^^^^^ the file hash
^ suite index
^ nested suite index
^ test index
```
::: tip
You can generate file hash with `generateFileHash` function from `vitest/node` which is available since Vitest 3:
```ts
import { generateFileHash } from 'vitest/node'
const hash = generateFileHash(
'/file/path.js', // relative path
undefined, // the project name or `undefined` is not set
)
```
:::
::: danger
Don't try to parse the ID. It can have a minus at the start: `-1223128da3_0_0_0`.
:::
## location
The location in the module where the suite was defined. Locations are collected only if [`includeTaskLocation`](/config/includetasklocation) is enabled in the config. Note that this option is automatically enabled if `--reporter=html`, `--ui` or `--browser` flags are used.
The location of this suite will be equal to `{ line: 3, column: 1 }`:
```ts:line-numbers {3}
import { describe } from 'vitest'
describe('the validation works correctly', () => {
// ...
})
```
## parent
Parent suite. If the suite was called directly inside the [module](/api/advanced/test-module), the parent will be the module itself.
## options
```ts
interface TaskOptions {
readonly each: boolean | undefined
readonly fails: boolean | undefined
readonly concurrent: boolean | undefined
readonly shuffle: boolean | undefined
readonly retry: number | undefined
readonly repeats: number | undefined
readonly tags: string[] | undefined
readonly mode: 'run' | 'only' | 'skip' | 'todo'
}
```
The options that suite was collected with.
## children
This is a [collection](/api/advanced/test-collection) of all suites and tests inside the current suite.
```ts
for (const task of suite.children) {
if (task.type === 'test') {
console.log('test', task.fullName)
}
else {
// task is TaskSuite
console.log('suite', task.name)
}
}
```
::: warning
Note that `suite.children` will only iterate the first level of nesting, it won't go deeper. If you need to iterate over all tests or suites, use [`children.allTests()`](/api/advanced/test-collection#alltests) or [`children.allSuites()`](/api/advanced/test-collection#allsuites). If you need to iterate over everything, use recursive function:
```ts
function visit(collection: TestCollection) {
for (const task of collection) {
if (task.type === 'suite') {
// report a suite
visit(task.children)
}
else {
// report a test
}
}
}
```
:::
## ok
```ts
function ok(): boolean
```
Checks if the suite has any failed tests. This will also return `false` if suite failed during collection. In that case, check the [`errors()`](#errors) for thrown errors.
## state
```ts
function state(): TestSuiteState
```
Checks the running state of the suite. Possible return values:
- **pending**: the tests in this suite did not finish running yet.
- **failed**: this suite has failed tests or they couldn't be collected. If [`errors()`](#errors) is not empty, it means the suite failed to collect tests.
- **passed**: every test inside this suite has passed.
- **skipped**: this suite was skipped during collection.
::: warning
Note that [test module](/api/advanced/test-module) also has a `state` method that returns the same values, but it can also return an additional `queued` state if the module wasn't executed yet.
:::
## errors
```ts
function errors(): TestError[]
```
Errors that happened outside of the test run during collection, like syntax errors.
```ts {4}
import { describe } from 'vitest'
describe('collection failed', () => {
throw new Error('a custom error')
})
```
::: warning
Note that errors are serialized into simple objects: `instanceof Error` will always return `false`.
:::
## meta 3.1.0 {#meta}
```ts
function meta(): TaskMeta
```
Custom [metadata](/api/advanced/metadata) that was attached to the suite during its execution or collection. Since Vitest 4.1, the meta can be attached by providing a `meta` object during test collection:
```ts {7,10}
import { describe, test, TestRunner } from 'vitest'
describe('the validation works correctly', { meta: { decorated: true } }, () => {
test('some test', ({ task }) => {
// assign "decorated" during test run, it will be available
// only in onTestCaseReady hook
task.suite.meta.decorated = false
// tests inherit suite's metadata
task.meta.decorated === true
})
})
```
Note that suite metadata will be inherited by tests since Vitest 4.1.
:::tip
If metadata was attached during collection (outside of the `test` function), then it will be available in [`onTestModuleCollected`](./reporters#ontestmodulecollected) hook in the custom reporter.
:::
## toTestSpecification 4.1.0 {#totestspecification}
```ts
function toTestSpecification(): TestSpecification
```
Returns a new [test specification](/api/advanced/test-specification) that can be used to filter or run this specific test suite.
================================================
FILE: docs/api/advanced/vitest.md
================================================
---
outline: deep
title: Vitest API
---
# Vitest
Vitest instance requires the current test mode. It can be either:
- `test` when running runtime tests
- `benchmark` when running benchmarks experimental
::: details New in Vitest 4
Vitest 4 added several new APIs (they are marked with a "4.0.0+" badge) and removed deprecated APIs:
- `invalidates`
- `changedTests` (use [`onFilterWatchedSpecification`](#onfilterwatchedspecification) instead)
- `server` (use [`vite`](#vite) instead)
- `getProjectsByTestFile` (use [`getModuleSpecifications`](#getmodulespecifications) instead)
- `getFileWorkspaceSpecs` (use [`getModuleSpecifications`](#getmodulespecifications) instead)
- `getModuleProjects` (filter by [`this.projects`](#projects) yourself)
- `updateLastChanged` (renamed to [`invalidateFile`](#invalidatefile))
- `globTestSpecs` (use [`globTestSpecifications`](#globtestspecifications) instead)
- `globTestFiles` (use [`globTestSpecifications`](#globtestspecifications) instead)
- `listFile` (use [`getRelevantTestSpecifications`](#getrelevanttestspecifications) instead)
:::
## mode
### test
Test mode will only call functions inside `test` or `it`, and throws an error when `bench` is encountered. This mode uses `include` and `exclude` options in the config to find test files.
### benchmark experimental
Benchmark mode calls `bench` functions and throws an error, when it encounters `test` or `it`. This mode uses `benchmark.include` and `benchmark.exclude` options in the config to find benchmark files.
## config
The root (or global) config. If projects are defined, they will reference this as `globalConfig`.
::: warning
This is Vitest config, it doesn't extend _Vite_ config. It only has resolved values from the `test` property.
:::
## vite
This is a global [`ViteDevServer`](https://vite.dev/guide/api-javascript#vitedevserver).
## state experimental
::: warning
Public `state` is an experimental API (except `vitest.state.getReportedEntity`). Breaking changes might not follow SemVer, please pin Vitest's version when using it.
:::
Global state stores information about the current tests. It uses the same API from `@vitest/runner` by default, but we recommend using the [Reported Tasks API](/api/advanced/reporters#reported-tasks) instead by calling `state.getReportedEntity()` on the `@vitest/runner` API:
```ts
const task = vitest.state.idMap.get(taskId) // old API
const testCase = vitest.state.getReportedEntity(task) // new API
```
In the future, the old API won't be exposed anymore.
## snapshot
The global snapshot manager. Vitest keeps track of all snapshots using the `snapshot.add` method.
You can get the latest summary of snapshots via the `vitest.snapshot.summary` property.
## cache
Cache manager that stores information about latest test results and test file stats. In Vitest itself this is only used by the default sequencer to sort tests.
## watcher 4.0.0 {#watcher}
The instance of a Vitest watcher with useful methods to track file changes and rerun tests. You can use `onFileChange`, `onFileDelete` or `onFileCreate` with your own watcher, if the built-in watcher is disabled.
## projects
An array of [test projects](/api/advanced/test-project) that belong to user's projects. If the user did not specify a them, this array will only contain a [root project](#getrootproject).
Vitest will ensure that there is always at least one project in this array. If the user specifies a non-existent `--project` name, Vitest will throw an error before this array is defined.
## getRootProject
```ts
function getRootProject(): TestProject
```
This returns the root test project. The root project generally doesn't run any tests and is not included in `vitest.projects` unless the user explicitly includes the root config in their configuration, or projects are not defined at all.
The primary goal of the root project is to setup the global config. In fact, `rootProject.config` references `rootProject.globalConfig` and `vitest.config` directly:
```ts
rootProject.config === rootProject.globalConfig === rootProject.vitest.config
```
## provide
```ts
function provide(
key: T,
value: ProvidedContext[T],
): void
```
Vitest exposes `provide` method which is a shorthand for `vitest.getRootProject().provide`. With this method you can pass down values from the main thread to tests. All values are checked with `structuredClone` before they are stored, but the values themselves are not cloned.
To receive the values in the test, you need to import `inject` method from `vitest` entrypoint:
```ts
import { inject } from 'vitest'
const port = inject('wsPort') // 3000
```
For better type safety, we encourage you to augment the type of `ProvidedContext`:
```ts
import { createVitest } from 'vitest/node'
const vitest = await createVitest('test', {
watch: false,
})
vitest.provide('wsPort', 3000)
declare module 'vitest' {
export interface ProvidedContext {
wsPort: number
}
}
```
::: warning
Technically, `provide` is a method of [`TestProject`](/api/advanced/test-project), so it is limited to the specific project. However, all projects inherit the values from the root project which makes `vitest.provide` universal way of passing down values to tests.
:::
## getProvidedContext
```ts
function getProvidedContext(): ProvidedContext
```
This returns the root context object. This is a shorthand for `vitest.getRootProject().getProvidedContext`.
## getProjectByName
```ts
function getProjectByName(name: string): TestProject
```
This method returns the project by its name. Similar to calling `vitest.projects.find`.
::: warning
In case the project doesn't exist, this method will return the root project - make sure to check the names again if the project you are looking for is the one returned.
If user didn't customize a name, the Vitest will assign an empty string as a name.
:::
## globTestSpecifications
```ts
function globTestSpecifications(
filters?: string[],
): Promise
```
This method constructs new [test specifications](/api/advanced/test-specification) by collecting every test in all projects with [`project.globTestFiles`](/api/advanced/test-project#globtestfiles). It accepts string filters to match the test files - these are the same filters that [CLI supports](/guide/filtering#cli).
This method automatically caches all test specifications. When you call [`getModuleSpecifications`](#getmodulespecifications) next time, it will return the same specifications unless [`clearSpecificationsCache`](#clearspecificationscache) was called before that.
::: warning
As of Vitest 3, it's possible to have multiple test specifications with the same module ID (file path) if `poolMatchGlob` has several pools or if `typecheck` is enabled. This possibility will be removed in Vitest 4.
:::
```ts
const specifications = await vitest.globTestSpecifications(['my-filter'])
// [TestSpecification{ moduleId: '/tests/my-filter.test.ts' }]
console.log(specifications)
```
## getRelevantTestSpecifications
```ts
function getRelevantTestSpecifications(
filters?: string[]
): Promise
```
This method resolves every test specification by calling [`project.globTestFiles`](/api/advanced/test-project#globtestfiles). It accepts string filters to match the test files - these are the same filters that [CLI supports](/guide/filtering#cli). If `--changed` flag was specified, the list will be filtered to include only files that changed. `getRelevantTestSpecifications` doesn't run any test files.
::: warning
This method can be slow because it needs to filter `--changed` flags. Do not use it if you just need a list of test files.
- If you need to get the list of specifications for known test files, use [`getModuleSpecifications`](#getmodulespecifications) instead.
- If you need to get the list of all possible test files, use [`globTestSpecifications`](#globtestspecifications).
:::
## mergeReports
```ts
function mergeReports(directory?: string): Promise
```
Merge reports from multiple runs located in the specified directory (value from `--merge-reports` if not specified). This value can also be set on `config.mergeReports` (by default, it will read `.vitest-reports` folder).
Note that the `directory` will always be resolved relative to the working directory.
This method is called automatically by [`startVitest`](/guide/advanced/tests) if `config.mergeReports` is set.
## collect
```ts
function collect(filters?: string[]): Promise
```
Execute test files without running test callbacks. `collect` returns unhandled errors and an array of [test modules](/api/advanced/test-module). It accepts string filters to match the test files - these are the same filters that [CLI supports](/guide/filtering#cli).
This method resolves tests specifications based on the config `include`, `exclude`, and `includeSource` values. Read more at [`project.globTestFiles`](/api/advanced/test-project#globtestfiles). If `--changed` flag was specified, the list will be filtered to include only files that changed.
::: warning
Note that Vitest doesn't use static analysis to collect tests. Vitest will run every test file in isolation, just like it runs regular tests.
This makes this method very slow, unless you disable isolation before collecting tests.
:::
## start
```ts
function start(filters?: string[]): Promise
```
Initialize reporters, the coverage provider, and run tests. This method accepts string filters to match the test files - these are the same filters that [CLI supports](/guide/filtering#cli).
::: warning
This method should not be called if [`vitest.init()`](#init) is also invoked. Use [`runTestSpecifications`](#runtestspecifications) or [`rerunTestSpecifications`](#reruntestspecifications) instead if you need to run tests after Vitest was initialised.
:::
This method is called automatically by [`startVitest`](/guide/advanced/tests) if `config.mergeReports` and `config.standalone` are not set.
## init
```ts
function init(): Promise
```
Initialize reporters and the coverage provider. This method doesn't run any tests. If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.
Internally, this method is called only if [`--standalone`](/guide/cli#standalone) flag is enabled.
::: warning
This method should not be called if [`vitest.start()`](#start) is also invoked.
:::
This method is called automatically by [`startVitest`](/guide/advanced/tests) if `config.standalone` is set.
## getModuleSpecifications
```ts
function getModuleSpecifications(moduleId: string): TestSpecification[]
```
Returns a list of test specifications related to the module ID. The ID should already be resolved to an absolute file path. If ID doesn't match `include` or `includeSource` patterns, the returned array will be empty.
This method can return already cached specifications based on the `moduleId` and `pool`. But note that [`project.createSpecification`](/api/advanced/test-project#createspecification) always returns a new instance and it's not cached automatically. However, specifications are automatically cached when [`runTestSpecifications`](#runtestspecifications) is called.
::: warning
As of Vitest 3, this method uses a cache to check if the file is a test. To make sure that the cache is not empty, call [`globTestSpecifications`](#globtestspecifications) at least once.
:::
## clearSpecificationsCache
```ts
function clearSpecificationsCache(moduleId?: string): void
```
Vitest automatically caches test specifications for each file when [`globTestSpecifications`](#globtestspecifications) or [`runTestSpecifications`](#runtestspecifications) is called. This method clears the cache for the given file or the whole cache altogether depending on the first argument.
## runTestSpecifications
```ts
function runTestSpecifications(
specifications: TestSpecification[],
allTestsRun = false
): Promise
```
This method runs every test based on the received [specifications](/api/advanced/test-specification). The second argument, `allTestsRun`, is used by the coverage provider to determine if it needs to include uncovered files in report.
::: warning
This method doesn't trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` callbacks. If you are rerunning tests based on the file change, consider using [`rerunTestSpecifications`](#reruntestspecifications) instead.
:::
## rerunTestSpecifications
```ts
function rerunTestSpecifications(
specifications: TestSpecification[],
allTestsRun = false
): Promise
```
This method emits `reporter.onWatcherRerun` and `onTestsRerun` events, then it runs tests with [`runTestSpecifications`](#runtestspecifications). If there were no errors in the main process, it will emit `reporter.onWatcherStart` event.
## runTestFiles 4.1.0 {#runtestfiles}
```ts
function runTestFiles(
filepaths: string[],
allTestsRun = false
): Promise
```
This automatically creates specifications to run based on filepaths filters.
This is different from [`start`](#start) because it does not create a coverage provider, trigger `onInit` and `onWatcherStart` events, or throw an error if there are no files to run (in this case, the function will return empty arrays without triggering a test run).
This function accepts the same filters as [`start`](#start) and the CLI.
## updateSnapshot
```ts
function updateSnapshot(files?: string[]): Promise
```
Update snapshots in specified files. If no files are provided, it will update files with failed tests and obsolete snapshots.
## collectTests
```ts
function collectTests(
specifications: TestSpecification[]
): Promise
```
Execute test files without running test callbacks. `collectTests` returns unhandled errors and an array of [test modules](/api/advanced/test-module).
This method works exactly the same as [`collect`](#collect), but you need to provide test specifications yourself.
::: warning
Note that Vitest doesn't use static analysis to collect tests. Vitest will run every test file in isolation, just like it runs regular tests.
This makes this method very slow, unless you disable isolation before collecting tests.
:::
## cancelCurrentRun
```ts
function cancelCurrentRun(reason: CancelReason): Promise
```
This method will gracefully cancel all ongoing tests. It will stop the on-going tests and will not run tests that were scheduled to run but haven't started yet.
## setGlobalTestNamePattern
```ts
function setGlobalTestNamePattern(pattern: string | RegExp): void
```
This methods overrides the global [test name pattern](/config/testnamepattern).
::: warning
This method doesn't start running any tests. To run tests with updated pattern, call [`runTestSpecifications`](#runtestspecifications).
:::
## getGlobalTestNamePattern 4.0.0 {#getglobaltestnamepattern}
```ts
function getGlobalTestNamePattern(): RegExp | undefined
```
Returns the regexp used for the global test name pattern.
## resetGlobalTestNamePattern
```ts
function resetGlobalTestNamePattern(): void
```
This methods resets the [test name pattern](/config/testnamepattern). It means Vitest won't skip any tests now.
::: warning
This method doesn't start running any tests. To run tests without a pattern, call [`runTestSpecifications`](#runtestspecifications).
:::
## enableSnapshotUpdate
```ts
function enableSnapshotUpdate(): void
```
Enable the mode that allows updating snapshots when running tests. Every test that runs after this method is called will update snapshots. To disable the mode, call [`resetSnapshotUpdate`](#resetsnapshotupdate).
::: warning
This method doesn't start running any tests. To update snapshots, run tests with [`runTestSpecifications`](#runtestspecifications).
:::
## resetSnapshotUpdate
```ts
function resetSnapshotUpdate(): void
```
Disable the mode that allows updating snapshots when running tests. This method doesn't start running any tests.
## invalidateFile
```ts
function invalidateFile(filepath: string): void
```
This method invalidates the file in the cache of every project. It is mostly useful if you rely on your own watcher because Vite's cache persist in memory.
::: danger
If you disable Vitest's watcher but keep Vitest running, it is important to manually clear the cache with this method because there is no way to disable the cache. This method will also invalidate file's importers.
:::
## import
Import a file using Vite module runner. The file will be transformed by Vite with the global config and executed in a separate context. Note that `moduleId` will be relative to the `config.root`.
::: danger
`project.import` reuses Vite's module graph, so importing the same module using a regular import will return a different module:
```ts
import * as staticExample from './example.js'
const dynamicExample = await vitest.import('./example.js')
dynamicExample !== staticExample // ✅
```
:::
::: info
Internally, Vitest uses this method to import global setups, custom coverage providers, and custom reporters, meaning all of them share the same module graph as long as they belong to the same Vite server.
:::
## close
```ts
function close(): Promise
```
Closes all projects and their associated resources. This can only be called once; the closing promise is cached until the server restarts.
## exit
```ts
function exit(force = false): Promise
```
Closes all projects and exit the process. If `force` is set to `true`, the process will exit immediately after closing the projects.
This method will also forcefully call `process.exit()` if the process is still active after [`config.teardownTimeout`](/config/teardowntimeout) milliseconds.
## shouldKeepServer
```ts
function shouldKeepServer(): boolean
```
This method will return `true` if the server should be kept running after the tests are done. This usually means that the `watch` mode was enabled.
## onServerRestart
```ts
function onServerRestart(fn: OnServerRestartHandler): void
```
Register a handler that will be called when the server is restarted due to a config change.
## onCancel
```ts
function onCancel(fn: (reason: CancelReason) => Awaitable): () => void
```
Register a handler that will be called when the test run is cancelled with [`vitest.cancelCurrentRun`](#cancelcurrentrun).
Since 4.0.10, `onCancel` experimentally returns a teardown function that will remove the listener. Since 4.1.0 this behaviour is considered stable.
## onClose
```ts
function onClose(fn: () => Awaitable): void
```
Register a handler that will be called when the server is closed.
## onTestsRerun
```ts
function onTestsRerun(fn: OnTestsRerunHandler): void
```
Register a handler that will be called when the tests are rerunning. The tests can rerun when [`rerunTestSpecifications`](#reruntestspecifications) is called manually or when a file is changed and the built-in watcher schedules a rerun.
## onFilterWatchedSpecification
```ts
function onFilterWatchedSpecification(
fn: (specification: TestSpecification) => boolean
): void
```
Register a handler that will be called when a file is changed. This callback should return `true` or `false`, indicating whether the test file needs to be rerun.
With this method, you can hook into the default watcher logic to delay or discard tests that the user doesn't want to keep track of at the moment:
```ts
const continuesTests: string[] = []
myCustomWrapper.onContinuesRunEnabled(testItem =>
continuesTests.push(item.fsPath)
)
vitest.onFilterWatchedSpecification(specification =>
continuesTests.includes(specification.moduleId)
)
```
Vitest can create different specifications for the same file depending on the `pool` or `locations` options, so do not rely on the reference. Vitest can also return cached specification from [`vitest.getModuleSpecifications`](#getmodulespecifications) - the cache is based on the `moduleId` and `pool`. Note that [`project.createSpecification`](/api/advanced/test-project#createspecification) always returns a new instance.
## matchesProjectFilter 3.1.0 {#matchesprojectfilter}
```ts
function matchesProjectFilter(name: string): boolean
```
Check if the name matches the current [project filter](/guide/cli#project). If there is no project filter, this will always return `true`.
It is not possible to programmatically change the `--project` CLI option.
## waitForTestRunEnd 4.0.0 {#waitfortestrunend}
```ts
function waitForTestRunEnd(): Promise
```
If there is a test run happening, returns a promise that will resolve when the test run is finished.
## createCoverageProvider 4.0.0 {#createcoverageprovider}
```ts
function createCoverageProvider(): Promise
```
Creates a coverage provider if `coverage` is enabled in the config. This is done automatically if you are running tests with [`start`](#start) or [`init`](#init) methods.
::: warning
This method will also clean all previous reports if [`coverage.clean`](/config/coverage#coverage-clean) is not set to `false`.
:::
## enableCoverage 4.0.0 {#enablecoverage}
```ts
function enableCoverage(): Promise
```
This method enables coverage for tests that run after this call. `enableCoverage` doesn't run any tests; it only sets up Vitest to collect coverage.
It creates a new coverage provider if one doesn't already exist.
## disableCoverage 4.0.0 {#disablecoverage}
```ts
function disableCoverage(): void
```
This method disables coverage collection for tests that run afterwards.
## getSeed 4.0.0 {#getseed}
```ts
function getSeed(): number | null
```
Returns the seed, if tests are running in a random order.
## experimental_parseSpecification 4.0.0 {#parsespecification}
```ts
function experimental_parseSpecification(
specification: TestSpecification
): Promise
```
This function will collect all tests inside the file without running it. It uses rollup's `parseAst` function on top of Vite's `ssrTransform` to statically analyse the file and collect all tests that it can.
::: warning
If Vitest could not analyse the name of the test, it will inject a `dynamic: true` property to the test or a suite. The `id` will also have a postfix with `-dynamic` to not break tests that were collected properly.
Vitest always injects this property in tests with `for` or `each` modifier or tests with a dynamic name (like, `hello ${property}` or `'hello' + ${property}`). Vitest will still assign a name to the test, but it cannot be used to filter tests.
There is nothing Vitest can do to make it possible to filter dynamic tests, but you can turn a test with `for` or `each` modifier into a name pattern with `escapeTestName` function:
```ts
import { escapeTestName } from 'vitest/node'
// turns into /hello, .+?/
const escapedPattern = new RegExp(escapeTestName('hello, %s', true))
```
:::
::: warning
Vitest will only collect tests defined in the file. It will never follow imports to other files.
Vitest collects all `it`, `test`, `suite` and `describe` definitions even if they were not imported from the `vitest` entry point.
:::
## experimental_parseSpecifications 4.0.0 {#parsespecifications}
```ts
function experimental_parseSpecifications(
specifications: TestSpecification[],
options?: {
concurrency?: number
}
): Promise
```
This method will [collect tests](#parsespecification) from an array of specifications. By default, Vitest will run only `os.availableParallelism()` number of specifications at a time to reduce the potential performance degradation. You can specify a different number in a second argument.
## experimental_clearCache 4.0.11 {#clearcache}
```ts
function experimental_clearCache(): Promise
```
Deletes all Vitest caches, including [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache).
## experimental_getSourceModuleDiagnostic 4.0.15 {#getsourcemodulediagnostic}
```ts
export function experimental_getSourceModuleDiagnostic(
moduleId: string,
testModule?: TestModule,
): Promise
```
::: details Types
```ts
export interface ModuleDefinitionLocation {
line: number
column: number
}
export interface SourceModuleLocations {
modules: ModuleDefinitionDiagnostic[]
untracked: ModuleDefinitionDiagnostic[]
}
export interface ModuleDefinitionDiagnostic {
start: ModuleDefinitionLocation
end: ModuleDefinitionLocation
startIndex: number
endIndex: number
url: string
resolvedId: string
}
export interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic {
selfTime: number
totalTime: number
external?: boolean
}
export interface UntrackedModuleDefinitionDiagnostic {
url: string
resolvedId: string
selfTime: number
totalTime: number
external?: boolean
}
export interface SourceModuleDiagnostic {
modules: ModuleDefinitionDurationsDiagnostic[]
untrackedModules: UntrackedModuleDefinitionDiagnostic[]
}
```
:::
Returns module's diagnostic. If [`testModule`](/api/advanced/test-module) is not provided, `selfTime` and `totalTime` will be aggregated across all tests that were running the last time. If the module was not transformed or executed, the diagnostic will be empty.
::: warning
At the moment, the [browser](/guide/browser/) modules are not supported.
:::
================================================
FILE: docs/api/assert-type.md
================================================
# assertType
::: warning
During runtime this function doesn't do anything. To [enable typechecking](/guide/testing-types#run-typechecking), don't forget to pass down `--typecheck` flag.
:::
- **Type:** `(value: T): void`
You can use this function as an alternative for [`expectTypeOf`](/api/expect-typeof) to easily assert that the argument type is equal to the generic provided.
```ts
import { assertType } from 'vitest'
function concat(a: string, b: string): string
function concat(a: number, b: number): number
function concat(a: string | number, b: string | number): string | number
assertType(concat('a', 'b'))
assertType(concat(1, 2))
// @ts-expect-error wrong types
assertType(concat('a', 2))
```
================================================
FILE: docs/api/assert.md
================================================
# assert
Vitest reexports the `assert` method from [`chai`](https://www.chaijs.com/api/assert/) for verifying invariants.
## assert
- **Type:** `(expression: any, message?: string) => asserts expression`
Assert that the given `expression` is truthy, otherwise the assertion fails.
```ts
import { assert, test } from 'vitest'
test('assert', () => {
assert('foo' !== 'bar', 'foo should not be equal to bar')
})
```
## fail
- **Type:**
- `(message?: string) => never`
- `(actual: T, expected: T, message?: string, operator?: string) => never`
Force an assertion failure.
```ts
import { assert, test } from 'vitest'
test('assert.fail', () => {
assert.fail('error message on failure')
assert.fail('foo', 'bar', 'foo is not bar', '===')
})
```
## isOk
- **Type:** `(value: T, message?: string) => asserts value`
- **Alias** `ok`
Assert that the given `value` is truthy.
```ts
import { assert, test } from 'vitest'
test('assert.isOk', () => {
assert.isOk('foo', 'every truthy is ok')
assert.isOk(false, 'this will fail since false is not truthy')
})
```
## isNotOk
- **Type:** `(value: T, message?: string) => void`
- **Alias** `notOk`
Assert that the given `value` is falsy.
```ts
import { assert, test } from 'vitest'
test('assert.isNotOk', () => {
assert.isNotOk('foo', 'this will fail, every truthy is not ok')
assert.isNotOk(false, 'this will pass since false is falsy')
})
```
## equal
- **Type:** `(actual: T, expected: T, message?: string) => void`
Asserts non-strict equality (==) of `actual` and `expected`.
```ts
import { assert, test } from 'vitest'
test('assert.equal', () => {
assert.equal(Math.sqrt(4), '2')
})
```
## notEqual
- **Type:** `(actual: T, expected: T, message?: string) => void`
Asserts non-strict inequality (!=) of `actual` and `expected`.
```ts
import { assert, test } from 'vitest'
test('assert.equal', () => {
assert.notEqual(Math.sqrt(4), 3)
})
```
## strictEqual
- **Type:** `(actual: T, expected: T, message?: string) => void`
Asserts strict equality (===) of `actual` and `expected`.
```ts
import { assert, test } from 'vitest'
test('assert.strictEqual', () => {
assert.strictEqual(Math.sqrt(4), 2)
})
```
## deepEqual
- **Type:** `(actual: T, expected: T, message?: string) => void`
Asserts that `actual` is deeply equal to `expected`.
```ts
import { assert, test } from 'vitest'
test('assert.deepEqual', () => {
assert.deepEqual({ color: 'green' }, { color: 'green' })
})
```
## notDeepEqual
- **Type:** `(actual: T, expected: T, message?: string) => void`
Assert that `actual` is not deeply equal to `expected`.
```ts
import { assert, test } from 'vitest'
test('assert.notDeepEqual', () => {
assert.notDeepEqual({ color: 'green' }, { color: 'red' })
})
```
## isAbove
- **Type:** `(valueToCheck: number, valueToBeAbove: number, message?: string) => void`
Assert that `valueToCheck` is strictly greater than (>) `valueToBeAbove`.
```ts
import { assert, test } from 'vitest'
test('assert.isAbove', () => {
assert.isAbove(5, 2, '5 is strictly greater than 2')
})
```
## isAtLeast
- **Type:** `(valueToCheck: number, valueToBeAtLeast: number, message?: string) => void`
Assert that `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast`.
```ts
import { assert, test } from 'vitest'
test('assert.isAtLeast', () => {
assert.isAtLeast(5, 2, '5 is greater or equal to 2')
assert.isAtLeast(3, 3, '3 is greater or equal to 3')
})
```
## isBelow
- **Type:** `(valueToCheck: number, valueToBeBelow: number, message?: string) => void`
Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`.
```ts
import { assert, test } from 'vitest'
test('assert.isBelow', () => {
assert.isBelow(3, 6, '3 is strictly less than 6')
})
```
## isAtMost
- **Type:** `(valueToCheck: number, valueToBeAtMost: number, message?: string) => void`
Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost`.
```ts
import { assert, test } from 'vitest'
test('assert.isAtMost', () => {
assert.isAtMost(3, 6, '3 is less than or equal to 6')
assert.isAtMost(4, 4, '4 is less than or equal to 4')
})
```
## isTrue
- **Type:** `(value: T, message?: string) => asserts value is true`
Asserts that `value` is true.
```ts
import { assert, test } from 'vitest'
const testPassed = true
test('assert.isTrue', () => {
assert.isTrue(testPassed)
})
```
## isNotTrue
- **Type:** `(value: T, message?: string) => asserts value is Exclude`
Asserts that `value` is not true.
```ts
import { assert, test } from 'vitest'
const testPassed = 'ok'
test('assert.isNotTrue', () => {
assert.isNotTrue(testPassed)
})
```
## isFalse
- **Type:** `(value: T, message?: string) => asserts value is false`
Asserts that `value` is false.
```ts
import { assert, test } from 'vitest'
const testPassed = false
test('assert.isFalse', () => {
assert.isFalse(testPassed)
})
```
## isNotFalse
- **Type:** `(value: T, message?: string) => asserts value is Exclude`
Asserts that `value` is not false.
```ts
import { assert, test } from 'vitest'
const testPassed = 'no'
test('assert.isNotFalse', () => {
assert.isNotFalse(testPassed)
})
```
## isNull
- **Type:** `(value: T, message?: string) => asserts value is null`
Asserts that `value` is null.
```ts
import { assert, test } from 'vitest'
const error = null
test('assert.isNull', () => {
assert.isNull(error, 'error is null')
})
```
## isNotNull
- **Type:** `(value: T, message?: string) => asserts value is Exclude`
Asserts that `value` is not null.
```ts
import { assert, test } from 'vitest'
const error = { message: 'error was occurred' }
test('assert.isNotNull', () => {
assert.isNotNull(error, 'error is not null but object')
})
```
## isNaN
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is NaN.
```ts
import { assert, test } from 'vitest'
const calculation = 1 * 'vitest'
test('assert.isNaN', () => {
assert.isNaN(calculation, '1 * "vitest" is NaN')
})
```
## isNotNaN
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not NaN.
```ts
import { assert, test } from 'vitest'
const calculation = 1 * 2
test('assert.isNotNaN', () => {
assert.isNotNaN(calculation, '1 * 2 is Not NaN but 2')
})
```
## exists
- **Type:** `(value: T, message?: string) => asserts value is NonNullable`
Asserts that `value` is neither null nor undefined.
```ts
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.exists', () => {
assert.exists(name, 'foo is neither null nor undefined')
})
```
## notExists
- **Type:** `(value: T, message?: string) => asserts value is null | undefined`
Asserts that `value` is either null nor undefined.
```ts
import { assert, test } from 'vitest'
const foo = null
const bar = undefined
test('assert.notExists', () => {
assert.notExists(foo, 'foo is null so not exist')
assert.notExists(bar, 'bar is undefined so not exist')
})
```
## isUndefined
- **Type:** `(value: T, message?: string) => asserts value is undefined`
Asserts that `value` is undefined.
```ts
import { assert, test } from 'vitest'
const name = undefined
test('assert.isUndefined', () => {
assert.isUndefined(name, 'name is undefined')
})
```
## isDefined
- **Type:** `(value: T, message?: string) => asserts value is Exclude`
Asserts that `value` is not undefined.
```ts
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.isDefined', () => {
assert.isDefined(name, 'name is not undefined')
})
```
## isFunction
- **Type:** `(value: T, message?: string) => void`
- **Alias:** `isCallable`
Asserts that `value` is a function.
```ts
import { assert, test } from 'vitest'
function name() { return 'foo' };
test('assert.isFunction', () => {
assert.isFunction(name, 'name is function')
})
```
## isNotFunction
- **Type:** `(value: T, message?: string) => void`
- **Alias:** `isNotCallable`
Asserts that `value` is not a function.
```ts
import { assert, test } from 'vitest'
const name = 'foo'
test('assert.isNotFunction', () => {
assert.isNotFunction(name, 'name is not function but string')
})
```
## isObject
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects.
```ts
import { assert, test } from 'vitest'
const someThing = { color: 'red', shape: 'circle' }
test('assert.isObject', () => {
assert.isObject(someThing, 'someThing is object')
})
```
## isNotObject
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not an object of type Object (as revealed by Object.prototype.toString). The assertion does not match subclassed objects.
```ts
import { assert, test } from 'vitest'
const someThing = 'redCircle'
test('assert.isNotObject', () => {
assert.isNotObject(someThing, 'someThing is not object but string')
})
```
## isArray
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is an array.
```ts
import { assert, test } from 'vitest'
const color = ['red', 'green', 'yellow']
test('assert.isArray', () => {
assert.isArray(color, 'color is array')
})
```
## isNotArray
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not an array.
```ts
import { assert, test } from 'vitest'
const color = 'red'
test('assert.isNotArray', () => {
assert.isNotArray(color, 'color is not array but string')
})
```
## isString
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is a string.
```ts
import { assert, test } from 'vitest'
const color = 'red'
test('assert.isString', () => {
assert.isString(color, 'color is string')
})
```
## isNotString
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not a string.
```ts
import { assert, test } from 'vitest'
const color = ['red', 'green', 'yellow']
test('assert.isNotString', () => {
assert.isNotString(color, 'color is not string but array')
})
```
## isNumber
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is a number.
```ts
import { assert, test } from 'vitest'
const colors = 3
test('assert.isNumber', () => {
assert.isNumber(colors, 'colors is number')
})
```
## isNotNumber
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not a number.
```ts
import { assert, test } from 'vitest'
const colors = '3 colors'
test('assert.isNotNumber', () => {
assert.isNotNumber(colors, 'colors is not number but strings')
})
```
## isFinite
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is a finite number (not NaN, Infinity).
```ts
import { assert, test } from 'vitest'
const colors = 3
test('assert.isFinite', () => {
assert.isFinite(colors, 'colors is number not NaN or Infinity')
})
```
## isBoolean
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is a boolean.
```ts
import { assert, test } from 'vitest'
const isReady = true
test('assert.isBoolean', () => {
assert.isBoolean(isReady, 'isReady is a boolean')
})
```
## isNotBoolean
- **Type:** `(value: T, message?: string) => void`
Asserts that `value` is not a boolean.
```ts
import { assert, test } from 'vitest'
const isReady = 'sure'
test('assert.isBoolean', () => {
assert.isBoolean(isReady, 'isReady is not a boolean but string')
})
```
## typeOf
- **Type:** `(value: T, name: string, message?: string) => void`
Asserts that `value`’s type is `name`, as determined by Object.prototype.toString.
```ts
import { assert, test } from 'vitest'
test('assert.typeOf', () => {
assert.typeOf({ color: 'red' }, 'object', 'we have an object')
assert.typeOf(['red', 'green'], 'array', 'we have an array')
assert.typeOf('red', 'string', 'we have a string')
assert.typeOf(/red/, 'regexp', 'we have a regular expression')
assert.typeOf(null, 'null', 'we have a null')
assert.typeOf(undefined, 'undefined', 'we have an undefined')
})
```
## notTypeOf
- **Type:** `(value: T, name: string, message?: string) => void`
Asserts that `value`’s type is not `name`, as determined by Object.prototype.toString.
```ts
import { assert, test } from 'vitest'
test('assert.notTypeOf', () => {
assert.notTypeOf('red', 'number', '"red" is not a number')
})
```
## instanceOf
- **Type:** `(value: T, constructor: Function, message?: string) => asserts value is T`
Asserts that `value` is an instance of `constructor`.
```ts
import { assert, test } from 'vitest'
function Person(name) { this.name = name }
const foo = new Person('foo')
class Tea {
constructor(name) {
this.name = name
}
}
const coffee = new Tea('coffee')
test('assert.instanceOf', () => {
assert.instanceOf(foo, Person, 'foo is an instance of Person')
assert.instanceOf(coffee, Tea, 'coffee is an instance of Tea')
})
```
## notInstanceOf
- **Type:** `(value: T, constructor: Function, message?: string) => asserts value is Exclude`
Asserts that `value` is not an instance of `constructor`.
```ts
import { assert, test } from 'vitest'
function Person(name) { this.name = name }
const foo = new Person('foo')
class Tea {
constructor(name) {
this.name = name
}
}
const coffee = new Tea('coffee')
test('assert.instanceOf', () => {
assert.instanceOf(foo, Tea, 'foo is not an instance of Tea')
})
```
## include
- **Type:**
- `(haystack: string, needle: string, message?: string) => void`
- `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void`
- `(haystack: WeakSet, needle: T, message?: string) => void`
- `(haystack: T, needle: Partial, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a value in an array, a substring in a string, or a subset of properties in an object.
```ts
import { assert, test } from 'vitest'
test('assert.include', () => {
assert.include([1, 2, 3], 2, 'array contains value')
assert.include('foobar', 'foo', 'string contains substring')
assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property')
})
```
## notInclude
- **Type:**
- `(haystack: string, needle: string, message?: string) => void`
- `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void`
- `(haystack: WeakSet, needle: T, message?: string) => void`
- `(haystack: T, needle: Partial, message?: string) => void`
Asserts that `haystack` does not include `needle`. It can be used to assert the absence of a value in an array, a substring in a string, or a subset of properties in an object.
```ts
import { assert, test } from 'vitest'
test('assert.notInclude', () => {
assert.notInclude([1, 2, 3], 4, 'array doesn\'t contain 4')
assert.notInclude('foobar', 'baz', 'foobar doesn\'t contain baz')
assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn\'t contain property')
})
```
## deepInclude
- **Type:**
- `(haystack: string, needle: string, message?: string) => void`
- `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void`
- `(haystack: T, needle: T extends WeakSet ? never : Partial, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a value in an array or a subset of properties in an object. Deep equality is used.
```ts
import { assert, test } from 'vitest'
const obj1 = { a: 1 }
const obj2 = { b: 2 }
test('assert.deepInclude', () => {
assert.deepInclude([obj1, obj2], { a: 1 })
assert.deepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 1 } })
})
```
## notDeepInclude
- **Type:**
- `(haystack: string, needle: string, message?: string) => void`
- `(haystack: readonly T[] | ReadonlySet | ReadonlyMap, needle: T, message?: string) => void`
- `(haystack: T, needle: T extends WeakSet ? never : Partial, message?: string) => void`
Asserts that `haystack` does not include `needle`. It can be used to assert the absence of a value in an array or a subset of properties in an object. Deep equality is used.
```ts
import { assert, test } from 'vitest'
const obj1 = { a: 1 }
const obj2 = { b: 2 }
test('assert.notDeepInclude', () => {
assert.notDeepInclude([obj1, obj2], { a: 10 })
assert.notDeepInclude({ foo: obj1, bar: obj2 }, { foo: { a: 10 } })
})
```
## nestedInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
```ts
import { assert, test } from 'vitest'
test('assert.nestedInclude', () => {
assert.nestedInclude({ '.a': { b: 'x' } }, { '\\.a.[b]': 'x' })
assert.nestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'x' })
})
```
## notNestedInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` does not include `needle`. Can be used to assert the inclusion of a subset of properties in an object. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
```ts
import { assert, test } from 'vitest'
test('assert.nestedInclude', () => {
assert.notNestedInclude({ '.a': { b: 'x' } }, { '\\.a.b': 'y' })
assert.notNestedInclude({ a: { '[b]': 'x' } }, { 'a.\\[b\\]': 'y' })
})
```
## deepNestedInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
```ts
import { assert, test } from 'vitest'
test('assert.deepNestedInclude', () => {
assert.deepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { x: 1 } })
assert.deepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { x: 1 } })
})
```
## notDeepNestedInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` not includes `needle`. Can be used to assert the absence of a subset of properties in an object while checking for deep equality. Enables the use of dot- and bracket-notation for referencing nested properties. ‘[]’ and ‘.’ in property names can be escaped using double backslashes.
```ts
import { assert, test } from 'vitest'
test('assert.notDeepNestedInclude', () => {
assert.notDeepNestedInclude({ a: { b: [{ x: 1 }] } }, { 'a.b[0]': { y: 1 } })
assert.notDeepNestedInclude({ '.a': { '[b]': { x: 1 } } }, { '\\.a.\\[b\\]': { y: 2 } })
})
```
## ownInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties.
```ts
import { assert, test } from 'vitest'
test('assert.ownInclude', () => {
assert.ownInclude({ a: 1 }, { a: 1 })
})
```
## notOwnInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties.
```ts
import { assert, test } from 'vitest'
const obj1 = {
b: 2
}
const obj2 = object.create(obj1)
obj2.a = 1
test('assert.notOwnInclude', () => {
assert.notOwnInclude(obj2, { b: 2 })
})
```
## deepOwnInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` includes `needle`. Can be used to assert the inclusion of a subset of properties in an object while ignoring inherited properties and checking for deep equality.
```ts
import { assert, test } from 'vitest'
test('assert.deepOwnInclude', () => {
assert.deepOwnInclude({ a: { b: 2 } }, { a: { b: 2 } })
})
```
## notDeepOwnInclude
- **Type:** `(haystack: any, needle: any, message?: string) => void`
Asserts that `haystack` not includes `needle`. Can be used to assert the absence of a subset of properties in an object while ignoring inherited properties and checking for deep equality.
```ts
import { assert, test } from 'vitest'
test('assert.notDeepOwnInclude', () => {
assert.notDeepOwnInclude({ a: { b: 2 } }, { a: { c: 3 } })
})
```
## match
- **Type:** `(value: string, regexp: RegExp, message?: string) => void`
Asserts that `value` matches the regular expression `regexp`.
```ts
import { assert, test } from 'vitest'
test('assert.match', () => {
assert.match('foobar', /^foo/, 'regexp matches')
})
```
## notMatch
- **Type:** `(value: string, regexp: RegExp, message?: string) => void`
Asserts that `value` does not matches the regular expression `regexp`.
```ts
import { assert, test } from 'vitest'
test('assert.notMatch', () => {
assert.notMatch('foobar', /^foo/, 'regexp does not match')
})
```
## property
- **Type:** `(object: T, property: string, message?: string) => void`
Asserts that `object` has a direct or inherited property named by `property`
```ts
import { assert, test } from 'vitest'
test('assert.property', () => {
assert.property({ tea: { green: 'matcha' } }, 'tea')
assert.property({ tea: { green: 'matcha' } }, 'toString')
})
```
## notProperty
- **Type:** `(object: T, property: string, message?: string) => void`
Asserts that `object` does not have a direct or inherited property named by `property`
```ts
import { assert, test } from 'vitest'
test('assert.notProperty', () => {
assert.notProperty({ tea: { green: 'matcha' } }, 'coffee')
})
```
## propertyVal
- **Type:** `(object: T, property: string, value: V, message?: string) => void`
Asserts that `object` has a direct or inherited property named by `property` with a value given by `value`. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notPropertyVal', () => {
assert.propertyVal({ tea: 'is good' }, 'tea', 'is good')
})
```
## notPropertyVal
- **Type:** `(object: T, property: string, value: V, message?: string) => void`
Asserts that `object` does not have a direct or inherited property named by `property` with a value given by `value`. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notPropertyVal', () => {
assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad')
assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good')
})
```
## deepPropertyVal
- **Type:** `(object: T, property: string, value: V, message?: string) => void`
Asserts that `object` has a direct or inherited property named by `property` with a value given by `value`. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' })
})
```
## notDeepPropertyVal
- **Type:** `(object: T, property: string, value: V, message?: string) => void`
Asserts that `object` does not have a direct or inherited property named by `property` with a value given by `value`. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' })
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' })
assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' })
})
```
## nestedProperty
- **Type:** `(object: T, property: string, message?: string) => void`
Asserts that `object` has a direct or inherited property named by `property`, which can be a string using dot- and bracket-notation for nested reference.
```ts
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.nestedProperty({ tea: { green: 'matcha' } }, 'tea.green')
})
```
## notNestedProperty
- **Type:** `(object: T, property: string, message?: string) => void`
Asserts that `object` does not have a direct or inherited property named by `property`, which can be a string using dot- and bracket-notation for nested reference.
```ts
import { assert, test } from 'vitest'
test('assert.deepPropertyVal', () => {
assert.notNestedProperty({ tea: { green: 'matcha' } }, 'tea.oolong')
})
```
## nestedPropertyVal
- **Type:** `(object: T, property: string, value: any, message?: string) => void`
Asserts that `object` has a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.nestedPropertyVal', () => {
assert.nestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'matcha')
})
```
## notNestedPropertyVal
- **Type:** `(object: T, property: string, value: any, message?: string) => void`
Asserts that `object` does not have a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})
```
## deepNestedPropertyVal
- **Type:** `(object: T, property: string, value: any, message?: string) => void`
Asserts that `object` has a property named by `property` with a value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a deep equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notNestedPropertyVal', () => {
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'tea.green', 'konacha')
assert.notNestedPropertyVal({ tea: { green: 'matcha' } }, 'coffee.green', 'matcha')
})
```
## notDeepNestedPropertyVal
- **Type:** `(object: T, property: string, value: any, message?: string) => void`
Asserts that `object` does not have a property named by `property` with value given by `value`. `property` can use dot- and bracket-notation for nested reference. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.notDeepNestedPropertyVal', () => {
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' })
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' })
assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' })
})
```
## lengthOf
- **Type:** `(object: T, length: number, message?: string) => void`
Asserts that `object` has a `length` or `size` with the expected value.
```ts
import { assert, test } from 'vitest'
test('assert.lengthOf', () => {
assert.lengthOf([1, 2, 3], 3, 'array has length of 3')
assert.lengthOf('foobar', 6, 'string has length of 6')
assert.lengthOf(new Set([1, 2, 3]), 3, 'set has size of 3')
assert.lengthOf(new Map([['a', 1], ['b', 2], ['c', 3]]), 3, 'map has size of 3')
})
```
## hasAnyKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has at least one of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'iDontExist', 'baz'])
assert.hasAnyKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, iDontExist: 99, baz: 1337 })
assert.hasAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.hasAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ foo: 'bar' }, 'anotherKey'])
})
```
## hasAllKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has all and only all of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.hasAllKeys', () => {
assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
assert.hasAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
assert.hasAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.hasAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})
```
## containsAllKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has all of the `keys` provided but may have more keys not listed. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.containsAllKeys', () => {
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, ['foo', 'bar', 'baz'])
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, baz: 1337 })
assert.containsAllKeys({ foo: 1, bar: 2, baz: 3 }, { foo: 30, bar: 99, baz: 1337 })
assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }])
assert.containsAllKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ foo: 1 }, 'key'])
assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }]))
assert.containsAllKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ foo: 'bar' }, 'anotherKey']))
})
```
## doesNotHaveAnyKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has none of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyKeys', () => {
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example'])
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example'])
assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey'], [{ one: 'two' }, 'example']))
})
```
## doesNotHaveAllKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` does not have at least one of the `keys` provided. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.hasAnyKeys', () => {
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, ['one', 'two', 'example'])
assert.doesNotHaveAnyKeys({ foo: 1, bar: 2, baz: 3 }, { one: 1, two: 2, example: 'foo' })
assert.doesNotHaveAnyKeys(new Map([[{ foo: 1 }, 'bar'], ['key', 'value']]), [{ one: 'two' }, 'example'])
assert.doesNotHaveAnyKeys(new Set([{ foo: 'bar' }, 'anotherKey']), [{ one: 'two' }, 'example'])
})
```
## hasAnyDeepKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has at least one of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' })
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), [{ one: 'one' }, { two: 'two' }])
assert.hasAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' })
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { three: 'three' }])
assert.hasAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})
```
## hasAllDeepKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has all and only all of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.hasAnyDeepKeys', () => {
assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne']]), { one: 'one' })
assert.hasAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.hasAllDeepKeys(new Set([{ one: 'one' }]), { one: 'one' })
assert.hasAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})
```
## containsAllDeepKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` contains all of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.containsAllDeepKeys', () => {
assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { one: 'one' })
assert.containsAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ one: 'one' }, { two: 'two' }])
assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { one: 'one' })
assert.containsAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { two: 'two' }])
})
```
## doesNotHaveAnyDeepKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` has none of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotHaveAnyDeepKeys', () => {
assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' })
assert.doesNotHaveAnyDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { fifty: 'fifty' }])
assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' })
assert.doesNotHaveAnyDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ twenty: 'twenty' }, { fifty: 'fifty' }])
})
```
## doesNotHaveAllDeepKeys
- **Type:** `(object: T, keys: Array | { [key: string]: any }, message?: string) => void`
Asserts that `object` does not have at least one of the `keys` provided. Since Sets and Maps can have objects as keys you can use this assertion to perform a deep comparison. You can also provide a single object instead of a keys array and its keys will be used as the expected set of keys.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotHaveAllDeepKeys', () => {
assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [1, 2]]), { thisDoesNot: 'exist' })
assert.doesNotHaveAllDeepKeys(new Map([[{ one: 'one' }, 'valueOne'], [{ two: 'two' }, 'valueTwo']]), [{ twenty: 'twenty' }, { one: 'one' }])
assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), { twenty: 'twenty' })
assert.doesNotHaveAllDeepKeys(new Set([{ one: 'one' }, { two: 'two' }]), [{ one: 'one' }, { fifty: 'fifty' }])
})
```
## throws
- **Type:**
- `(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void`
- `(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void`
- **Alias:**
- `throw`
- `Throw`
If `errorLike` is an Error constructor, asserts that `fn` will throw an error that is an instance of `errorLike`. If errorLike is an Error instance, asserts that the error thrown is the same instance as `errorLike`. If `errMsgMatcher` is provided, it also asserts that the error thrown will have a message matching `errMsgMatcher`.
```ts
import { assert, test } from 'vitest'
test('assert.throws', () => {
assert.throws(fn, 'Error thrown must have this msg')
assert.throws(fn, /Error thrown must have a msg that matches this/)
assert.throws(fn, ReferenceError)
assert.throws(fn, errorInstance)
assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg')
assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg')
assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/)
assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/)
})
```
## doesNotThrow
- **Type:** `(fn: () => void, errMsgMatcher?: RegExp | string, ignored?: any, message?: string) => void`
- **Type:** `(fn: () => void, errorLike?: ErrorConstructor | Error | null, errMsgMatcher?: RegExp | string | null, message?: string) => void`
If `errorLike` is an Error constructor, asserts that `fn` will not throw an error that is an instance of `errorLike`. If errorLike is an Error instance, asserts that the error thrown is not the same instance as `errorLike`. If `errMsgMatcher` is provided, it also asserts that the error thrown will not have a message matching `errMsgMatcher`.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotThrow', () => {
assert.doesNotThrow(fn, 'Any Error thrown must not have this message')
assert.doesNotThrow(fn, /Any Error thrown must not match this/)
assert.doesNotThrow(fn, Error)
assert.doesNotThrow(fn, errorInstance)
assert.doesNotThrow(fn, Error, 'Error must not have this message')
assert.doesNotThrow(fn, errorInstance, 'Error must not have this message')
assert.doesNotThrow(fn, Error, /Error must not match this/)
assert.doesNotThrow(fn, errorInstance, /Error must not match this/)
})
```
## operator
- **Type:** `(val1: OperatorComparable, operator: Operator, val2: OperatorComparable, message?: string) => void`
Compare `val1` and `val2` using `operator`.
```ts
import { assert, test } from 'vitest'
test('assert.operator', () => {
assert.operator(1, '<', 2, 'everything is ok')
})
```
## closeTo
- **Type:** `(actual: number, expected: number, delta: number, message?: string) => void`
- **Alias:** `approximately`
Asserts that the `actual` is equal `expected`, to within a +/- `delta` range.
```ts
import { assert, test } from 'vitest'
test('assert.closeTo', () => {
assert.closeTo(1.5, 1, 0.5, 'numbers are close')
})
```
## sameMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` have the same members in any order. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.sameMembers', () => {
assert.sameMembers([1, 2, 3], [2, 1, 3], 'same members')
})
```
## notSameMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` don't have the same members in any order. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.sameMembers', () => {
assert.notSameMembers([1, 2, 3], [5, 1, 3], 'not same members')
})
```
## sameDeepMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` have the same members in any order. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})
```
## notSameDeepMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` don’t have the same members in any order. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.sameDeepMembers', () => {
assert.sameDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members')
})
```
## sameOrderedMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` have the same members in the same order. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.sameOrderedMembers', () => {
assert.sameOrderedMembers([1, 2, 3], [1, 2, 3], 'same ordered members')
})
```
## notSameOrderedMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` have the same members in the same order. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notSameOrderedMembers', () => {
assert.notSameOrderedMembers([1, 2, 3], [2, 1, 3], 'not same ordered members')
})
```
## sameDeepOrderedMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` have the same members in the same order. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.sameDeepOrderedMembers', () => {
assert.sameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { c: 3 }], 'same deep ordered members')
})
```
## notSameDeepOrderedMembers
- **Type:** `(set1: T[], set2: T[], message?: string) => void`
Asserts that `set1` and `set2` don’t have the same members in the same order. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.notSameDeepOrderedMembers', () => {
assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }, { z: 5 }], 'not same deep ordered members')
assert.notSameDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { c: 3 }], 'not same deep ordered members')
})
```
## includeMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` is included in `superset` in any order. Uses a strict equality check (===). Duplicates are ignored.
```ts
import { assert, test } from 'vitest'
test('assert.includeMembers', () => {
assert.includeMembers([1, 2, 3], [2, 1, 2], 'include members')
})
```
## notIncludeMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` isn't included in `superset` in any order. Uses a strict equality check (===). Duplicates are ignored.
```ts
import { assert, test } from 'vitest'
test('assert.notIncludeMembers', () => {
assert.notIncludeMembers([1, 2, 3], [5, 1], 'not include members')
})
```
## includeDeepMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` is included in `superset` in any order. Uses a deep equality check. Duplicates are ignored.
```ts
import { assert, test } from 'vitest'
test('assert.includeDeepMembers', () => {
assert.includeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }, { b: 2 }], 'include deep members')
})
```
## notIncludeDeepMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` isn’t included in `superset` in any order. Uses a deep equality check. Duplicates are ignored.
```ts
import { assert, test } from 'vitest'
test('assert.notIncludeDeepMembers', () => {
assert.notIncludeDeepMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { f: 5 }], 'not include deep members')
})
```
## includeOrderedMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` is included in `superset` in the same order beginning with the first element in `superset`. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.includeOrderedMembers', () => {
assert.includeOrderedMembers([1, 2, 3], [1, 2], 'include ordered members')
})
```
## notIncludeOrderedMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` isn't included in `superset` in the same order beginning with the first element in `superset`. Uses a strict equality check (===).
```ts
import { assert, test } from 'vitest'
test('assert.notIncludeOrderedMembers', () => {
assert.notIncludeOrderedMembers([1, 2, 3], [2, 1], 'not include ordered members')
assert.notIncludeOrderedMembers([1, 2, 3], [2, 3], 'not include ordered members')
})
```
## includeDeepOrderedMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` is included in `superset` in the same order beginning with the first element in `superset`. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
assert.includeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { b: 2 }], 'include deep ordered members')
})
```
## notIncludeDeepOrderedMembers
- **Type:** `(superset: T[], subset: T[], message?: string) => void`
Asserts that `subset` isn’t included in `superset` in the same order beginning with the first element in superset. Uses a deep equality check.
```ts
import { assert, test } from 'vitest'
test('assert.includeDeepOrderedMembers', () => {
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ a: 1 }, { f: 5 }], 'not include deep ordered members')
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { a: 1 }], 'not include deep ordered members')
assert.notIncludeDeepOrderedMembers([{ a: 1 }, { b: 2 }, { c: 3 }], [{ b: 2 }, { c: 3 }], 'not include deep ordered members')
})
```
## oneOf
- **Type:** `(inList: T, list: T[], message?: string) => void`
Asserts that non-object, non-array value `inList` appears in the flat array `list`.
```ts
import { assert, test } from 'vitest'
test('assert.oneOf', () => {
assert.oneOf(1, [2, 1], 'Not found in list')
})
```
## changes
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` changes the `object` of a `property`.
```ts
import { assert, test } from 'vitest'
test('assert.changes', () => {
const obj = { val: 10 }
function fn() { obj.val = 22 };
assert.changes(fn, obj, 'val')
})
```
## changesBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` changes the `object` of a `property` by a `change`.
```ts
import { assert, test } from 'vitest'
test('assert.changesBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 2 };
assert.changesBy(fn, obj, 'val', 2)
})
```
## doesNotChange
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` does not changes the `object` of a `property`.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotChange', () => {
const obj = { val: 10 }
function fn() { obj.val += 2 };
assert.doesNotChange(fn, obj, 'val', 2)
})
```
## changesButNotBy
- **Type:** `(modifier: Function, object: T, property: string, change:number, message?: string) => void`
Asserts that a `modifier` does not change the `object` of a `property` or of a `modifier` return value by a `change`.
```ts
import { assert, test } from 'vitest'
test('assert.changesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 10 };
assert.changesButNotBy(fn, obj, 'val', 5)
})
```
## increases
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` increases a numeric `object`'s `property`.
```ts
import { assert, test } from 'vitest'
test('assert.increases', () => {
const obj = { val: 10 }
function fn() { obj.val = 13 };
assert.increases(fn, obj, 'val')
})
```
## increasesBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` increases a numeric `object`'s `property` or a `modifier` return value by an `change`.
```ts
import { assert, test } from 'vitest'
test('assert.increasesBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 10 };
assert.increasesBy(fn, obj, 'val', 10)
})
```
## doesNotIncrease
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` does not increases a numeric `object`'s `property`.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotIncrease', () => {
const obj = { val: 10 }
function fn() { obj.val = 8 }
assert.doesNotIncrease(fn, obj, 'val')
})
```
## increasesButNotBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` does not increases a numeric `object`'s `property` or a `modifier` return value by an `change`.
```ts
import { assert, test } from 'vitest'
test('assert.increasesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val += 15 };
assert.increasesButNotBy(fn, obj, 'val', 10)
})
```
## decreases
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` decreases a numeric `object`'s `property`.
```ts
import { assert, test } from 'vitest'
test('assert.decreases', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.decreases(fn, obj, 'val')
})
```
## decreasesBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` decreases a numeric `object`'s `property` or a `modifier` return value by a `change`.
```ts
import { assert, test } from 'vitest'
test('assert.decreasesBy', () => {
const obj = { val: 10 }
function fn() { obj.val -= 5 };
assert.decreasesBy(fn, obj, 'val', 5)
})
```
## doesNotDecrease
- **Type:** `(modifier: Function, object: T, property: string, message?: string) => void`
Asserts that a `modifier` dose not decrease a numeric `object`'s `property`.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotDecrease', () => {
const obj = { val: 10 }
function fn() { obj.val = 15 }
assert.doesNotDecrease(fn, obj, 'val')
})
```
## doesNotDecreaseBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` does not decrease a numeric `object`'s `property` or a `modifier` return value by a `change`.
```ts
import { assert, test } from 'vitest'
test('assert.doesNotDecreaseBy', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.doesNotDecreaseBy(fn, obj, 'val', 1)
})
```
## decreasesButNotBy
- **Type:** `(modifier: Function, object: T, property: string, change: number, message?: string) => void`
Asserts that a `modifier` does not decrease a numeric `object`'s `property` or a `modifier` return value by a `change`.
```ts
import { assert, test } from 'vitest'
test('assert.decreasesButNotBy', () => {
const obj = { val: 10 }
function fn() { obj.val = 5 };
assert.decreasesButNotBy(fn, obj, 'val', 1)
})
```
## ifError
- **Type:** `(object: T, message?: string) => void`
Asserts if `object` is not a false value, and throws if it is a true value. This is added to allow for chai to be a drop-in replacement for Node’s assert class.
```ts
import { assert, test } from 'vitest'
test('assert.ifError', () => {
const err = new Error('I am a custom error')
assert.ifError(err) // Rethrows err!
})
```
## isExtensible
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `extensible`
Asserts that `object` is extensible (can have new properties added to it).
```ts
import { assert, test } from 'vitest'
test('assert.isExtensible', () => {
assert.isExtensible({})
})
```
## isNotExtensible
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `notExtensible`
Asserts that `object` is not extensible (can not have new properties added to it).
```ts
import { assert, test } from 'vitest'
test('assert.isNotExtensible', () => {
const nonExtensibleObject = Object.preventExtensions({})
const sealedObject = Object.seal({})
const frozenObject = Object.freeze({})
assert.isNotExtensible(nonExtensibleObject)
assert.isNotExtensible(sealedObject)
assert.isNotExtensible(frozenObject)
})
```
## isSealed
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `sealed`
Asserts that `object` is sealed (cannot have new properties added to it and its existing properties cannot be removed).
```ts
import { assert, test } from 'vitest'
test('assert.isSealed', () => {
const sealedObject = Object.seal({})
const frozenObject = Object.seal({})
assert.isSealed(sealedObject)
assert.isSealed(frozenObject)
})
```
## isNotSealed
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `notSealed`
Asserts that `object` is not sealed (can have new properties added to it and its existing properties can be removed).
```ts
import { assert, test } from 'vitest'
test('assert.isNotSealed', () => {
assert.isNotSealed({})
})
```
## isFrozen
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `frozen`
Asserts that object is frozen (cannot have new properties added to it and its existing properties cannot be modified).
```ts
import { assert, test } from 'vitest'
test('assert.isFrozen', () => {
const frozenObject = Object.freeze({})
assert.frozen(frozenObject)
})
```
## isNotFrozen
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `notFrozen`
Asserts that `object` is not frozen (can have new properties added to it and its existing properties can be modified).
```ts
import { assert, test } from 'vitest'
test('assert.isNotFrozen', () => {
assert.isNotFrozen({})
})
```
## isEmpty
- **Type:** `(target: T, message?: string) => void`
- **Alias:** `empty`
Asserts that the `target` does not contain any values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys.
```ts
import { assert, test } from 'vitest'
test('assert.isEmpty', () => {
assert.isEmpty([])
assert.isEmpty('')
assert.isEmpty(new Map())
assert.isEmpty({})
})
```
## isNotEmpty
- **Type:** `(object: T, message?: string) => void`
- **Alias:** `notEmpty`
Asserts that the `target` contains values. For arrays and strings, it checks the length property. For Map and Set instances, it checks the size property. For non-function objects, it gets the count of its own enumerable string keys.
```ts
import { assert, test } from 'vitest'
test('assert.isNotEmpty', () => {
assert.isNotEmpty([1, 2])
assert.isNotEmpty('34')
assert.isNotEmpty(new Set([5, 6]))
assert.isNotEmpty({ key: 7 })
})
```
================================================
FILE: docs/api/browser/assertions.md
================================================
---
title: Assertion API | Browser Mode
---
# Assertion API
Vitest provides a wide range of DOM assertions out of the box forked from [`@testing-library/jest-dom`](https://github.com/testing-library/jest-dom) library with the added support for locators and built-in retry-ability.
::: tip TypeScript Support
If you are using [TypeScript](/guide/browser/#typescript) or want to have correct type hints in `expect`, make sure you have `vitest/browser` referenced somewhere. If you never imported from there, you can add a `reference` comment in any file that's covered by your `tsconfig.json`:
```ts
///
```
:::
Tests in the browser might fail inconsistently due to their asynchronous nature. Because of this, it is important to have a way to guarantee that assertions succeed even if the condition is delayed (by a timeout, network request, or animation, for example). For this purpose, Vitest provides retriable assertions out of the box via the [`expect.poll`](/api/expect#poll) and `expect.element` APIs:
```ts
import { expect, test } from 'vitest'
import { page } from 'vitest/browser'
test('error banner is rendered', async () => {
triggerError()
// This creates a locator that will try to find the element
// when any of its methods are called.
// This call by itself doesn't check the existence of the element.
const banner = page.getByRole('alert', {
name: /error/i,
})
// Vitest provides `expect.element` with built-in retry-ability
// It will repeatedly check that the element exists in the DOM and that
// the content of `element.textContent` is equal to "Error!"
// until all the conditions are met
await expect.element(banner).toHaveTextContent('Error!')
})
```
We recommend to always use `expect.element` when working with `page.getBy*` locators to reduce test flakiness. Note that `expect.element` accepts a second option:
```ts
interface ExpectPollOptions {
// The interval to retry the assertion for in milliseconds
// Defaults to "expect.poll.interval" config option
interval?: number
// Time to retry the assertion for in milliseconds
// Defaults to "expect.poll.timeout" config option
timeout?: number
// The message printed when the assertion fails
message?: string
}
```
::: tip
`expect.element` is a shorthand for `expect.poll(() => element)` and works in exactly the same way.
`toHaveTextContent` and all other assertions are still available on a regular `expect` without a built-in retry-ability mechanism:
```ts
// will fail immediately if .textContent is not `'Error!'`
expect(banner).toHaveTextContent('Error!')
```
:::
## toBeDisabled
```ts
function toBeDisabled(): Promise
```
Allows you to check whether an element is disabled from the user's perspective.
Matches if the element is a form control and the `disabled` attribute is specified on this element or the
element is a descendant of a form element with a `disabled` attribute.
Note that only native control elements such as HTML `button`, `input`, `select`, `textarea`, `option`, `optgroup`
can be disabled by setting "disabled" attribute. "disabled" attribute on other elements is ignored, unless it's a custom element.
```html
submit
```
```ts
await expect.element(getByTestId('button')).toBeDisabled() // ✅
await expect.element(getByTestId('button')).not.toBeDisabled() // ❌
```
## toBeEnabled
```ts
function toBeEnabled(): Promise
```
Allows you to check whether an element is not disabled from the user's perspective.
Works like [`not.toBeDisabled()`](#tobedisabled). Use this matcher to avoid double negation in your tests.
```html
submit
```
```ts
await expect.element(getByTestId('button')).toBeEnabled() // ✅
await expect.element(getByTestId('button')).not.toBeEnabled() // ❌
```
## toBeEmptyDOMElement
```ts
function toBeEmptyDOMElement(): Promise
```
This allows you to assert whether an element has no visible content for the user. It ignores comments but will fail if the element contains white-space.
```html
```
```ts
await expect.element(getByTestId('empty')).toBeEmptyDOMElement()
await expect.element(getByTestId('not-empty')).not.toBeEmptyDOMElement()
await expect.element(
getByTestId('with-whitespace')
).not.toBeEmptyDOMElement()
```
## toBeInTheDocument
```ts
function toBeInTheDocument(): Promise
```
Assert whether an element is present in the document or not.
```html
```
```ts
await expect.element(getByTestId('svg-element')).toBeInTheDocument()
await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument()
```
::: warning
This matcher does not find detached elements. The element must be added to the document to be found by `toBeInTheDocument`. If you desire to search in a detached element, please use: [`toContainElement`](#tocontainelement).
:::
## toBeInvalid
```ts
function toBeInvalid(): Promise
```
This allows you to check if an element, is currently invalid.
An element is invalid if it has an [`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) with no value or a value of `"true"`, or if the result of [`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation) is `false`.
```html
```
```ts
await expect.element(getByTestId('no-aria-invalid')).not.toBeInvalid()
await expect.element(getByTestId('aria-invalid')).toBeInvalid()
await expect.element(getByTestId('aria-invalid-value')).toBeInvalid()
await expect.element(getByTestId('aria-invalid-false')).not.toBeInvalid()
await expect.element(getByTestId('valid-form')).not.toBeInvalid()
await expect.element(getByTestId('invalid-form')).toBeInvalid()
```
## toBeRequired
```ts
function toBeRequired(): Promise
```
This allows you to check if a form element is currently required.
An element is required if it is having a `required` or `aria-required="true"` attribute.
```html
```
```ts
await expect.element(getByTestId('required-input')).toBeRequired()
await expect.element(getByTestId('aria-required-input')).toBeRequired()
await expect.element(getByTestId('conflicted-input')).toBeRequired()
await expect.element(getByTestId('aria-not-required-input')).not.toBeRequired()
await expect.element(getByTestId('optional-input')).not.toBeRequired()
await expect.element(getByTestId('unsupported-type')).not.toBeRequired()
await expect.element(getByTestId('select')).toBeRequired()
await expect.element(getByTestId('textarea')).toBeRequired()
await expect.element(getByTestId('supported-role')).not.toBeRequired()
await expect.element(getByTestId('supported-role-aria')).toBeRequired()
```
## toBeValid
```ts
function toBeValid(): Promise
```
This allows you to check if the value of an element, is currently valid.
An element is valid if it has no [`aria-invalid` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) or an attribute value of "false". The result of [`checkValidity()`](https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation) must also be `true` if it's a form element.
```html
```
```ts
await expect.element(getByTestId('no-aria-invalid')).toBeValid()
await expect.element(getByTestId('aria-invalid')).not.toBeValid()
await expect.element(getByTestId('aria-invalid-value')).not.toBeValid()
await expect.element(getByTestId('aria-invalid-false')).toBeValid()
await expect.element(getByTestId('valid-form')).toBeValid()
await expect.element(getByTestId('invalid-form')).not.toBeValid()
```
## toBeVisible
```ts
function toBeVisible(): Promise
```
This allows you to check if an element is currently visible to the user.
Element is considered visible when it has non-empty bounding box and does not have `visibility:hidden` computed style.
Note that according to this definition:
- Elements of zero size **are not** considered visible.
- Elements with `display:none` **are not** considered visible.
- Elements with `opacity:0` **are** considered visible.
To check that at least one element from the list is visible, use `locator.first()`.
```ts
// A specific element is visible.
await expect.element(page.getByText('Welcome')).toBeVisible()
// At least one item in the list is visible.
await expect.element(page.getByTestId('todo-item').first()).toBeVisible()
// At least one of the two elements is visible, possibly both.
await expect.element(
page.getByRole('button', { name: 'Sign in' })
.or(page.getByRole('button', { name: 'Sign up' }))
.first()
).toBeVisible()
```
## toBeInViewport 4.0.0 {#tobeinviewport}
```ts
function toBeInViewport(options: { ratio?: number }): Promise
```
This allows you to check if an element is currently in viewport with [IntersectionObserver API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
You can pass `ratio` argument as option, which means the minimal ratio of the element should be in viewport. `ratio` should be in 0~1.
```ts
// A specific element is in viewport.
await expect.element(page.getByText('Welcome')).toBeInViewport()
// 50% of a specific element should be in viewport
await expect.element(page.getByText('To')).toBeInViewport({ ratio: 0.5 })
// Full of a specific element should be in viewport
await expect.element(page.getByText('Vitest')).toBeInViewport({ ratio: 1 })
```
## toContainElement
```ts
function toContainElement(element: HTMLElement | SVGElement | Locator | null): Promise
```
This allows you to assert whether an element contains another element as a descendant or not.
```html
```
```ts
const ancestor = getByTestId('ancestor')
const descendant = getByTestId('descendant')
const nonExistantElement = getByTestId('does-not-exist')
await expect.element(ancestor).toContainElement(descendant)
await expect.element(descendant).not.toContainElement(ancestor)
await expect.element(ancestor).not.toContainElement(nonExistantElement)
```
## toContainHTML
```ts
function toContainHTML(htmlText: string): Promise
```
Assert whether a string representing a HTML element is contained in another element. The string should contain valid html, and not any incomplete html.
```html
```
```ts
// These are valid usages
await expect.element(getByTestId('parent')).toContainHTML(' ')
await expect.element(getByTestId('parent')).toContainHTML(' ')
await expect.element(getByTestId('parent')).not.toContainHTML(' ')
// These won't work
await expect.element(getByTestId('parent')).toContainHTML('data-testid="child"')
await expect.element(getByTestId('parent')).toContainHTML('data-testid')
await expect.element(getByTestId('parent')).toContainHTML('')
```
::: warning
Chances are you probably do not need to use this matcher. We encourage testing from the perspective of how the user perceives the app in a browser. That's why testing against a specific DOM structure is not advised.
It could be useful in situations where the code being tested renders html that was obtained from an external source, and you want to validate that html code was used as intended.
It should not be used to check DOM structure that you control. Please, use [`toContainElement`](#tocontainelement) instead.
:::
## toHaveAccessibleDescription
```ts
function toHaveAccessibleDescription(description?: string | RegExp): Promise
```
This allows you to assert that an element has the expected
[accessible description](https://w3c.github.io/accname/).
You can pass the exact string of the expected accessible description, or you can
make a partial match passing a regular expression, or by using
[`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching).
```html
Start
About
The logo of Our Company
```
```ts
await expect.element(getByTestId('link')).toHaveAccessibleDescription()
await expect.element(getByTestId('link')).toHaveAccessibleDescription('A link to start over')
await expect.element(getByTestId('link')).not.toHaveAccessibleDescription('Home page')
await expect.element(getByTestId('extra-link')).not.toHaveAccessibleDescription()
await expect.element(getByTestId('avatar')).not.toHaveAccessibleDescription()
await expect.element(getByTestId('logo')).not.toHaveAccessibleDescription('Company logo')
await expect.element(getByTestId('logo')).toHaveAccessibleDescription(
'The logo of Our Company',
)
await expect.element(getByTestId('logo2')).toHaveAccessibleDescription(
'The logo of Our Company',
)
```
## toHaveAccessibleErrorMessage
```ts
function toHaveAccessibleErrorMessage(message?: string | RegExp): Promise
```
This allows you to assert that an element has the expected
[accessible error message](https://w3c.github.io/aria/#aria-errormessage).
You can pass the exact string of the expected accessible error message.
Alternatively, you can perform a partial match by passing a regular expression
or by using
[`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching).
```html
This field is invalid
```
```ts
// Inputs with Valid Error Messages
await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage()
await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage(
'This field is invalid',
)
await expect.element(getByRole('textbox', { name: 'Has Error' })).toHaveAccessibleErrorMessage(
/invalid/i,
)
await expect.element(
getByRole('textbox', { name: 'Has Error' }),
).not.toHaveAccessibleErrorMessage('This field is absolutely correct!')
// Inputs without Valid Error Messages
await expect.element(
getByRole('textbox', { name: 'No Error Attributes' }),
).not.toHaveAccessibleErrorMessage()
await expect.element(
getByRole('textbox', { name: 'Not Invalid' }),
).not.toHaveAccessibleErrorMessage()
```
## toHaveAccessibleName
```ts
function toHaveAccessibleName(name?: string | RegExp): Promise
```
This allows you to assert that an element has the expected
[accessible name](https://w3c.github.io/accname/). It is useful, for instance,
to assert that form elements and buttons are properly labelled.
You can pass the exact string of the expected accessible name, or you can make a
partial match passing a regular expression, or by using
[`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching).
```html
Test title
Test content
Test
```
```javascript
await expect.element(getByTestId('img-alt')).toHaveAccessibleName('Test alt')
await expect.element(getByTestId('img-empty-alt')).not.toHaveAccessibleName()
await expect.element(getByTestId('svg-title')).toHaveAccessibleName('Test title')
await expect.element(getByTestId('button-img-alt')).toHaveAccessibleName()
await expect.element(getByTestId('img-paragraph')).not.toHaveAccessibleName()
await expect.element(getByTestId('svg-button')).toHaveAccessibleName()
await expect.element(getByTestId('svg-without-title')).not.toHaveAccessibleName()
await expect.element(getByTestId('input-title')).toHaveAccessibleName()
```
## toHaveAttribute
```ts
function toHaveAttribute(attribute: string, value?: unknown): Promise
```
This allows you to check whether the given element has an attribute or not. You
can also optionally check that the attribute has a specific expected value or
partial match using [`expect.stringContaining`](/api/expect#expect-stringcontaining) or [`expect.stringMatching`](/api/expect#expect-stringmatching).
```html
ok
```
```ts
const button = getByTestId('ok-button')
await expect.element(button).toHaveAttribute('disabled')
await expect.element(button).toHaveAttribute('type', 'submit')
await expect.element(button).not.toHaveAttribute('type', 'button')
await expect.element(button).toHaveAttribute(
'type',
expect.stringContaining('sub')
)
await expect.element(button).toHaveAttribute(
'type',
expect.not.stringContaining('but')
)
```
## toHaveClass
```ts
function toHaveClass(...classNames: string[], options?: { exact: boolean }): Promise
function toHaveClass(...classNames: (string | RegExp)[]): Promise
```
This allows you to check whether the given element has certain classes within
its `class` attribute. You must provide at least one class, unless you are
asserting that an element does not have any classes.
The list of class names may include strings and regular expressions. Regular
expressions are matched against each individual class in the target element, and
it is NOT matched against its full `class` attribute value as whole.
::: warning
Note that you cannot use `exact: true` option when only regular expressions are provided.
:::
```html
No Classes
```
```ts
const deleteButton = getByTestId('delete-button')
const noClasses = getByTestId('no-classes')
await expect.element(deleteButton).toHaveClass('extra')
await expect.element(deleteButton).toHaveClass('btn-danger btn')
await expect.element(deleteButton).toHaveClass(/danger/, 'btn')
await expect.element(deleteButton).toHaveClass('btn-danger', 'btn')
await expect.element(deleteButton).not.toHaveClass('btn-link')
await expect.element(deleteButton).not.toHaveClass(/link/)
// ⚠️ regexp matches against individual classes, not the whole classList
await expect.element(deleteButton).not.toHaveClass(/btn extra/)
// the element has EXACTLY a set of classes (in any order)
await expect.element(deleteButton).toHaveClass('btn-danger extra btn', {
exact: true
})
// if it has more than expected it is going to fail
await expect.element(deleteButton).not.toHaveClass('btn-danger extra', {
exact: true
})
await expect.element(noClasses).not.toHaveClass()
```
## toHaveFocus
```ts
function toHaveFocus(): Promise
```
This allows you to assert whether an element has focus or not.
```html
```
```ts
const input = page.getByTestId('element-to-focus')
input.element().focus()
await expect.element(input).toHaveFocus()
input.element().blur()
await expect.element(input).not.toHaveFocus()
```
## toHaveFormValues
```ts
function toHaveFormValues(expectedValues: Record): Promise
```
This allows you to check if a form or fieldset contains form controls for each given name, and having the specified value.
::: tip
It is important to stress that this matcher can only be invoked on a [form](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement) or a [fieldset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFieldSetElement) element.
This allows it to take advantage of the [`.elements`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements) property in `form` and `fieldset` to reliably fetch all form controls within them.
This also avoids the possibility that users provide a container that contains more than one `form`, thereby intermixing form controls that are not related, and could even conflict with one another.
:::
This matcher abstracts away the particularities with which a form control value
is obtained depending on the type of form control. For instance, ` `
elements have a `value` attribute, but `` elements do not. Here's a list
of all cases covered:
- ` ` elements return the value as a **number**, instead of
a string.
- ` ` elements:
- if there's a single one with the given `name` attribute, it is treated as a
**boolean**, returning `true` if the checkbox is checked, `false` if
unchecked.
- if there's more than one checkbox with the same `name` attribute, they are
all treated collectively as a single form control, which returns the value
as an **array** containing all the values of the selected checkboxes in the
collection.
- ` ` elements are all grouped by the `name` attribute, and
such a group treated as a single form control. This form control returns the
value as a **string** corresponding to the `value` attribute of the selected
radio button within the group.
- ` ` elements return the value as a **string**. This also
applies to ` ` elements having any other possible `type` attribute
that's not explicitly covered in different rules above (e.g. `search`,
`email`, `date`, `password`, `hidden`, etc.)
- `` elements without the `multiple` attribute return the value as a
**string** corresponding to the `value` attribute of the selected `option`, or
`undefined` if there's no selected option.
- `` elements return the value as an **array** containing all
the values of the [selected options](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedOptions).
- `