Skip to content

Commit

Permalink
feat: add --workspace option, fix root resolution in workspaces (#4773)
Browse files Browse the repository at this point in the history
Co-authored-by: Ari Perkkiö <ari.perkkio@gmail.com>
  • Loading branch information
sheremet-va and AriPerkkio committed Dec 19, 2023
1 parent 8dabef8 commit 67d93ed
Show file tree
Hide file tree
Showing 13 changed files with 87 additions and 36 deletions.
9 changes: 9 additions & 0 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2028,3 +2028,12 @@ Relevant only when using with `shouldAdvanceTime: true`. increment mocked time b
- **Default:** `false`

Tells fake timers to clear "native" (i.e. not fake) timers by delegating to their respective handlers. These are not cleared by default, leading to potentially unexpected behavior if timers existed prior to starting fake timers session.

### workspace

- **Type:** `string`
- **CLI:** `--workspace=./file.js`
- **Default:** `vitest.{workspace,projects}.{js,ts,json}` close to the config file or root
- **Version:** Since Vitest 1.1.0

Path to a [workspace](/guide/workspace) config file relative to [root](#root).
2 changes: 1 addition & 1 deletion docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ Run only [benchmark](https://vitest.dev/guide/features.html#benchmarking-experim
| `--outputFile <filename/-s>` | Write test results to a file when the `--reporter=json` or `--reporter=junit` option is also specified <br /> Via [cac's dot notation] you can specify individual outputs for multiple reporters |
| `--coverage` | Enable coverage report |
| `--run` | Do not watch |
| `--mode` | Override Vite mode (default: `test`) |
| `--mode <name>` | Override Vite mode (default: `test`) |
| `--workspace <path>` | Path to a workspace configuration file |
| `--globals` | Inject APIs globally |
| `--dom` | Mock browser API with happy-dom |
| `--browser [options]` | Run tests in [the browser](/guide/browser) (default: `false`) |
Expand Down
6 changes: 6 additions & 0 deletions packages/vitest/src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cli
.option('--coverage.all', 'Whether to include all files, including the untested ones into report', { default: true })
.option('--run', 'Disable watch mode')
.option('--mode <name>', 'Override Vite mode (default: test)')
.option('--workspace <path>', 'Path to a workspace configuration file')
.option('--globals', 'Inject apis globally')
.option('--dom', 'Mock browser API with happy-dom')
.option('--browser [options]', 'Run tests in the browser (default: false)')
Expand Down Expand Up @@ -150,6 +151,11 @@ function normalizeCliOptions(argv: CliOptions): CliOptions {
else
delete argv.config

if (argv.workspace)
argv.workspace = normalize(argv.workspace)
else
delete argv.workspace

if (argv.dir)
argv.dir = normalize(argv.dir)
else
Expand Down
49 changes: 22 additions & 27 deletions packages/vitest/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ const extraInlineDeps = [
'@nuxt/test-utils',
]

function resolvePath(path: string, root: string) {
return normalize(
resolveModule(path, { paths: [root] })
?? resolve(root, path),
)
}

export function resolveApiServerConfig<Options extends ApiConfig & UserConfig>(
options: Options,
): ApiConfig | undefined {
Expand Down Expand Up @@ -193,10 +200,8 @@ export function resolveConfig(
resolved.server.deps.moduleDirectories ??= []
resolved.server.deps.moduleDirectories.push(...resolved.deps.moduleDirectories)

if (resolved.runner) {
resolved.runner = resolveModule(resolved.runner, { paths: [resolved.root] })
?? resolve(resolved.root, resolved.runner)
}
if (resolved.runner)
resolved.runner = resolvePath(resolved.runner, resolved.root)

resolved.testNamePattern = resolved.testNamePattern
? resolved.testNamePattern instanceof RegExp
Expand Down Expand Up @@ -274,19 +279,18 @@ export function resolveConfig(
}
}

if (!builtinPools.includes(resolved.pool as BuiltinPool)) {
resolved.pool = normalize(
resolveModule(resolved.pool, { paths: [resolved.root] })
?? resolve(resolved.root, resolved.pool),
)
if (resolved.workspace) {
// if passed down from the CLI and it's relative, resolve relative to CWD
resolved.workspace = options.workspace && options.workspace[0] === '.'
? resolve(process.cwd(), options.workspace)
: resolvePath(resolved.workspace, resolved.root)
}

if (!builtinPools.includes(resolved.pool as BuiltinPool))
resolved.pool = resolvePath(resolved.pool, resolved.root)
resolved.poolMatchGlobs = (resolved.poolMatchGlobs || []).map(([glob, pool]) => {
if (!builtinPools.includes(pool as BuiltinPool)) {
pool = normalize(
resolveModule(pool, { paths: [resolved.root] })
?? resolve(resolved.root, pool),
)
}
if (!builtinPools.includes(pool as BuiltinPool))
pool = resolvePath(pool, resolved.root)
return [glob, pool]
})

Expand Down Expand Up @@ -315,16 +319,10 @@ export function resolveConfig(
}

resolved.setupFiles = toArray(resolved.setupFiles || []).map(file =>
normalize(
resolveModule(file, { paths: [resolved.root] })
?? resolve(resolved.root, file),
),
resolvePath(file, resolved.root),
)
resolved.globalSetup = toArray(resolved.globalSetup || []).map(file =>
normalize(
resolveModule(file, { paths: [resolved.root] })
?? resolve(resolved.root, file),
),
resolvePath(file, resolved.root),
)
resolved.coverage.exclude.push(...resolved.setupFiles.map(file => `${resolved.coverage.allowExternal ? '**/' : ''}${relative(resolved.root, file)}`))

Expand All @@ -334,10 +332,7 @@ export function resolveConfig(
]

if (resolved.diff) {
resolved.diff = normalize(
resolveModule(resolved.diff, { paths: [resolved.root] })
?? resolve(resolved.root, resolved.diff),
)
resolved.diff = resolvePath(resolved.diff, resolved.root)
resolved.forceRerunTriggers.push(resolved.diff)
}

Expand Down
20 changes: 16 additions & 4 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,31 @@ export class Vitest {
|| this.projects[0]
}

private async resolveWorkspace(cliOptions: UserConfig) {
private async getWorkspaceConfigPath() {
if (this.config.workspace)
return this.config.workspace

const configDir = this.server.config.configFile
? dirname(this.server.config.configFile)
: this.config.root

const rootFiles = await fs.readdir(configDir)

const workspaceConfigName = workspaceFiles.find((configFile) => {
return rootFiles.includes(configFile)
})

if (!workspaceConfigName)
return [await this.createCoreProject()]
return null

const workspaceConfigPath = join(configDir, workspaceConfigName)
return join(configDir, workspaceConfigName)
}

private async resolveWorkspace(cliOptions: UserConfig) {
const workspaceConfigPath = await this.getWorkspaceConfigPath()

if (!workspaceConfigPath)
return [await this.createCoreProject()]

const workspaceModule = await this.runner.executeFile(workspaceConfigPath) as {
default: (string | UserWorkspaceConfig)[]
Expand Down Expand Up @@ -244,7 +256,7 @@ export class Vitest {

const workspacesByFolder = resolvedWorkspacesPaths
.reduce((configByFolder, filepath) => {
const dir = dirname(filepath)
const dir = filepath.endsWith('/') ? filepath.slice(0, -1) : dirname(filepath)
configByFolder[dir] ??= []
configByFolder[dir].push(filepath)
return configByFolder
Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/node/plugins/workspace.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { dirname, relative } from 'pathe'
import { basename, dirname, relative } from 'pathe'
import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
import { configDefaults } from '../../defaults'
import { generateScopedClassName } from '../../integrations/css/css-modules'
Expand Down Expand Up @@ -36,7 +36,7 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp
let name = testConfig.name
if (!name) {
if (typeof options.workspacePath === 'string')
name = dirname(options.workspacePath).split('/').pop()
name = basename(options.workspacePath.endsWith('/') ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath))
else
name = options.workspacePath.toString()
}
Expand Down
6 changes: 5 additions & 1 deletion packages/vitest/src/node/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ export async function initializeProject(workspacePath: string | number, ctx: Vit
? false
: workspacePath

const root = options.root || (typeof workspacePath === 'number' ? undefined : dirname(workspacePath))
const root = options.root || (
typeof workspacePath === 'number'
? undefined
: workspacePath.endsWith('/') ? workspacePath : dirname(workspacePath)
)

const config: ViteInlineConfig = {
...options,
Expand Down
5 changes: 5 additions & 0 deletions packages/vitest/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ export interface InlineConfig {
*/
poolMatchGlobs?: [string, Exclude<Pool, 'browser'>][]

/**
* Path to a workspace configuration file
*/
workspace?: string

/**
* Update snapshot
*
Expand Down
1 change: 1 addition & 0 deletions test/config/fixtures/workspace/nested/e2e.projects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default ['project-1']
5 changes: 5 additions & 0 deletions test/config/fixtures/workspace/project-1/calculator-1.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect, it } from 'vitest';

it('1 + 1 = 2', () => {
expect(1 + 1).toBe(2);
})
5 changes: 5 additions & 0 deletions test/config/fixtures/workspace/project-2/calculator-2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect, it } from 'vitest';

it('2 + 2 = 4', () => {
expect(2 + 2).toBe(4);
})
9 changes: 9 additions & 0 deletions test/config/test/workspace.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { expect, it } from 'vitest'
import { runVitestCli } from '../../test-utils'

it('correctly runs workspace tests when workspace config path is specified', async () => {
const { stderr, stdout } = await runVitestCli('run', '--root', 'fixtures/workspace', '--workspace', './nested/e2e.projects.js')
expect(stderr).toBe('')
expect(stdout).toContain('1 + 1 = 2')
expect(stdout).not.toContain('2 + 2 = 4')
})
2 changes: 1 addition & 1 deletion test/workspaces/vitest.workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import remapping from '@ampproject/remapping'
import type { Plugin } from 'vite'

export default defineWorkspace([
'./space_2/*',
'space_2',
'./space_*/*.config.ts',
{
test: {
Expand Down

0 comments on commit 67d93ed

Please sign in to comment.