Skip to content

feat: deprecate workspace in favor of projects #7923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Next generation testing framework powered by Vite.
- 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))
- Workers multi-threading via [Tinypool](https://github.com/tinylibs/tinypool) (a lightweight fork of [Piscina](https://github.com/piscinajs/piscina))
- Benchmarking support with [Tinybench](https://github.com/tinylibs/tinybench)
- [Workspace](https://vitest.dev/guide/workspace) support
- [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
Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/components/FeaturesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<ListItem>Workers multi-threading via <a target="_blank" href="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/tinylibs/tinypool" rel="noopener noreferrer">Tinypool</a></ListItem>
<ListItem>Benchmarking support with <a target="_blank" href="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/tinylibs/tinybench" rel="noopener noreferrer">Tinybench</a></ListItem>
<ListItem>Filtering, timeouts, concurrent for suite and tests</ListItem>
<ListItem><a href="/guide/workspace">Workspace</a> support</ListItem>
<ListItem><a href="/guide/projects">Projects</a> support</ListItem>
<ListItem>
<a href="/guide/snapshot">
Jest-compatible Snapshot
Expand Down
4 changes: 2 additions & 2 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,8 @@ function guide(): DefaultTheme.SidebarItem[] {
link: '/guide/filtering',
},
{
text: 'Workspace',
link: '/guide/workspace',
text: 'Test Projects',
link: '/guide/projects',
},
{
text: 'Reporters',
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ If you pass down the config to the `startVitest` or `createVitest` APIs, Vitest
:::

::: warning
The `resolveConfig` doesn't resolve the `workspace`. To resolve workspace configs, Vitest needs an established Vite server.
The `resolveConfig` doesn't resolve `projects`. To resolve projects configs, Vitest needs an established Vite server.

Also note that `viteConfig.test` will not be fully resolved. If you need Vitest config, use `vitestConfig` instead.
:::
Expand Down
4 changes: 2 additions & 2 deletions docs/advanced/api/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Vitest re-exports all Vite type-only imports via a `Vite` namespace, which you c
```
:::

Unlike [`reporter.onInit`](/advanced/api/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 [workspace project](/guide/workspace) if your plugin is defined in the project and not in the global config.
Unlike [`reporter.onInit`](/advanced/api/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

Expand Down Expand Up @@ -107,7 +107,7 @@ const newProjects = await injectTestProjects({
```

::: 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 workspace project:
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')
Expand Down
46 changes: 25 additions & 21 deletions docs/advanced/api/test-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ title: TestProject

# TestProject <Version>3.0.0</Version> {#testproject}

- **Alias**: `WorkspaceProject` before 3.0.0

::: warning
This guide describes the advanced Node.js API. If you just want to create a workspace, follow the ["Workspace"](/guide/workspace) guide.
This guide describes the advanced Node.js API. If you just want to define projects, follow the ["Test Projects"](/guide/projects) guide.
:::

## name
Expand All @@ -26,28 +24,34 @@ vitest.projects.map(p => p.name) === [
'custom'
]
```
```ts [vitest.workspace.js]
export default [
'./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',
},
```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](/advanced/api/vitest#getroottestproject) is not part of a user workspace, its `name` will not be resolved.
If the [root project](/advanced/api/vitest#getroottestproject) is not part of user projects, its `name` will not be resolved.
:::

## vitest
Expand Down Expand Up @@ -279,7 +283,7 @@ dynamicExample !== staticExample // ✅
:::

::: info
Internally, Vitest uses this method to import global setups, custom coverage providers, workspace file, and custom reporters, meaning all of them share the same module graph as long as they belong to the same Vite server.
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
Expand Down
10 changes: 5 additions & 5 deletions docs/advanced/api/vitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Benchmark mode calls `bench` functions and throws an error, when it encounters `

## config

The root (or global) config. If workspace feature is enabled, projects will reference this as `globalConfig`.
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.
Expand Down Expand Up @@ -101,17 +101,17 @@ Cache manager that stores information about latest test results and test file st

## projects

An array of [test projects](/advanced/api/test-project) that belong to the user's workspace. If the user did not specify a custom workspace, the workspace will only have a [root project](#getrootproject).
An array of [test projects](/advanced/api/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 the workspace. If the user specifies a non-existent `--project` name, Vitest will throw an error.
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 workspace, or the workspace is not defined at all.
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:

Expand Down Expand Up @@ -433,7 +433,7 @@ dynamicExample !== staticExample // ✅
:::

::: info
Internally, Vitest uses this method to import global setups, custom coverage providers, workspace file, and custom reporters, meaning all of them share the same module graph as long as they belong to the same Vite server.
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
Expand Down
10 changes: 3 additions & 7 deletions docs/advanced/pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ export default defineConfig({
})
```

If you need to run tests in different pools, use the [workspace](/guide/workspace) feature:
If you need to run tests in different pools, use the [`projects`](/guide/projects) feature:

```ts [vitest.config.ts]
export default defineConfig({
test: {
workspace: [
projects: [
{
extends: true,
test: {
Expand All @@ -48,10 +48,6 @@ export default defineConfig({
})
```

::: info
The `workspace` field was introduced in Vitest 3. To define a workspace in [Vitest 2](https://v2.vitest.dev/), create a separate `vitest.workspace.ts` file.
:::

## API

The file specified in `pool` option should export a function (can be async) that accepts `Vitest` interface as its first option. This function needs to return an object matching `ProcessPool` interface:
Expand All @@ -69,7 +65,7 @@ export interface ProcessPool {

The function is called only once (unless the server config was updated), and it's generally a good idea to initialize everything you need for tests inside that function and reuse it when `runTests` is called.

Vitest calls `runTest` when new tests are scheduled to run. It will not call it if `files` is empty. The first argument is an array of [TestSpecifications](/advanced/api/test-specification). Files are sorted using [`sequencer`](/config/#sequence-sequencer) before `runTests` is called. It's possible (but unlikely) to have the same file twice, but it will always have a different project - this is implemented via [`vitest.workspace.ts`](/guide/workspace) configuration.
Vitest calls `runTest` when new tests are scheduled to run. It will not call it if `files` is empty. The first argument is an array of [TestSpecifications](/advanced/api/test-specification). Files are sorted using [`sequencer`](/config/#sequence-sequencer) before `runTests` is called. It's possible (but unlikely) to have the same file twice, but it will always have a different project - this is implemented via [`projects`](/guide/projects) configuration.

Vitest will wait until `runTests` is executed before finishing a run (i.e., it will emit [`onFinished`](/advanced/reporters) only after `runTests` is resolved).

Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/runner.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ interface File extends Suite {
*/
filepath: string
/**
* The name of the workspace project the file belongs to.
* The name of the test project the file belongs to.
*/
projectName: string | undefined
/**
Expand Down
2 changes: 1 addition & 1 deletion docs/blog/vitest-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ You can follow the design process in [#7069](https://github.com/vitest-dev/vites

## Inline Workspace

Rejoice! No more separate files to define your [workspace](/guide/workspace) - specify an array of projects using the `workspace` field in your `vitest.config` file:
Rejoice! No more separate files to define your [workspace](/guide/projects) - specify an array of projects using the `workspace` field in your `vitest.config` file:

```jsx
import { defineConfig } from 'vitest/config'
Expand Down
25 changes: 18 additions & 7 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default defineConfig({

Since Vitest uses Vite config, you can also use any configuration option from [Vite](https://vitejs.dev/config/). For example, `define` to define global variables, or `resolve.alias` to define aliases - these options should be defined on the top level, _not_ within a `test` property.

Configuration options that are not supported inside a [workspace](/guide/workspace) project config have <NonProjectOption /> sign next to them. This means they can only be set in the root Vitest config.
Configuration options that are not supported inside a [project](/guide/projects) config have <NonProjectOption /> sign next to them. This means they can only be set in the root Vitest config.
:::

### include
Expand Down Expand Up @@ -586,15 +586,15 @@ These options are passed down to `setup` method of current [`environment`](#envi
- **Default:** `[]`

::: danger DEPRECATED
This API was deprecated in Vitest 3. Use [workspace](/guide/workspace) to define different configurations instead.
This API was deprecated in Vitest 3. Use [projects](/guide/projects) to define different configurations instead.

```ts
export default defineConfig({
test: {
environmentMatchGlobs: [ // [!code --]
['./*.jsdom.test.ts', 'jsdom'], // [!code --]
], // [!code --]
workspace: [ // [!code ++]
projects: [ // [!code ++]
{ // [!code ++]
extends: true, // [!code ++]
test: { // [!code ++]
Expand Down Expand Up @@ -633,15 +633,15 @@ export default defineConfig({
- **Default:** `[]`

::: danger DEPRECATED
This API was deprecated in Vitest 3. Use [workspace](/guide/workspace) to define different configurations instead:
This API was deprecated in Vitest 3. Use [projects](/guide/projects) to define different configurations instead:

```ts
export default defineConfig({
test: {
poolMatchGlobs: [ // [!code --]
['./*.threads.test.ts', 'threads'], // [!code --]
], // [!code --]
workspace: [ // [!code ++]
projects: [ // [!code ++]
{ // [!code ++]
test: { // [!code ++]
extends: true, // [!code ++]
Expand Down Expand Up @@ -2396,14 +2396,25 @@ Tells fake timers to clear "native" (i.e. not fake) timers by delegating to thei

### workspace<NonProjectOption /> {#workspace}

- **Type:** `string | TestProjectConfiguration`
::: danger DEPRECATED
This options is deprecated and will be removed in the next major. Please, use [`projects`](#projects) instead.
:::

- **Type:** `string | TestProjectConfiguration[]`
- **CLI:** `--workspace=./file.js`
- **Default:** `vitest.{workspace,projects}.{js,ts,json}` close to the config file or root

Path to a [workspace](/guide/workspace) config file relative to [root](#root).
Path to a [workspace](/guide/projects) config file relative to [root](#root).

Since Vitest 3, you can also define the workspace array in the root config. If the `workspace` is defined in the config manually, Vitest will ignore the `vitest.workspace` file in the root.

### projects<NonProjectOption /> {#projects}

- **Type:** `TestProjectConfiguration[]`
- **Default:** `[]`

An array of [projects](/guide/projects).

### isolate

- **Type:** `boolean`
Expand Down
72 changes: 38 additions & 34 deletions docs/guide/browser/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ outline: deep
This page provides information about the experimental browser mode feature in the Vitest API, which allows you to run your tests in the browser natively, providing access to browser globals like window and document. This feature is currently under development, and APIs may change in the future.

::: tip
If you are looking for documentation for `expect`, `vi` or any general API like workspaces or type testing, refer to the ["Getting Started" guide](/guide/).
If you are looking for documentation for `expect`, `vi` or any general API like test projects or type testing, refer to the ["Getting Started" guide](/guide/).
:::

<img alt="Vitest UI" img-light src="/ui-browser-1-light.png">
Expand Down Expand Up @@ -209,44 +209,48 @@ export default defineConfig({
```
:::

If you need to run some tests using Node-based runner, you can define a [workspace](/guide/workspace) file with separate configurations for different testing strategies:
If you need to run some tests using Node-based runner, you can define a [`projects`](/guide/projects) option with separate configurations for different testing strategies:

{#workspace-config}
{#projects-config}

```ts [vitest.workspace.ts]
import { defineWorkspace } from 'vitest/config'
```ts [vitest.config.ts]
import { defineConfig } from 'vitest/config'

export default defineWorkspace([
{
test: {
// an example of file based convention,
// you don't have to follow it
include: [
'tests/unit/**/*.{test,spec}.ts',
'tests/**/*.unit.{test,spec}.ts',
],
name: 'unit',
environment: 'node',
},
},
{
test: {
// an example of file based convention,
// you don't have to follow it
include: [
'tests/browser/**/*.{test,spec}.ts',
'tests/**/*.browser.{test,spec}.ts',
],
name: 'browser',
browser: {
enabled: true,
instances: [
{ browser: 'chromium' },
],
export default defineConfig({
test: {
projects: [
{
test: {
// an example of file based convention,
// you don't have to follow it
include: [
'tests/unit/**/*.{test,spec}.ts',
'tests/**/*.unit.{test,spec}.ts',
],
name: 'unit',
environment: 'node',
},
},
},
{
test: {
// an example of file based convention,
// you don't have to follow it
include: [
'tests/browser/**/*.{test,spec}.ts',
'tests/**/*.browser.{test,spec}.ts',
],
name: 'browser',
browser: {
enabled: true,
instances: [
{ browser: 'chromium' },
],
},
},
},
],
},
])
})
```

## Browser Option Types
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/browser/multiple-setups.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Since Vitest 3, you can specify several different browser setups using the new [`browser.instances`](/guide/browser/config#browser-instances) option.

The main advantage of using the `browser.instances` over the [workspace](/guide/workspace) is improved caching. Every project will use the same Vite server meaning the file transform and [dependency pre-bundling](https://vite.dev/guide/dep-pre-bundling.html) has to happen only once.
The main advantage of using the `browser.instances` over the [test projects](/guide/projects) is improved caching. Every project will use the same Vite server meaning the file transform and [dependency pre-bundling](https://vite.dev/guide/dep-pre-bundling.html) has to happen only once.

## Several Browsers

Expand Down
Loading
Loading