Skip to content

Commit

Permalink
fix(vitest): don't initialize globalSetup if workspace doesn't run te…
Browse files Browse the repository at this point in the history
…sts (#4213)
  • Loading branch information
sheremet-va authored Oct 2, 2023
1 parent 98fe3d5 commit 0646197
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 96 deletions.
4 changes: 2 additions & 2 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ globalThis.resetBeforeEachTest = true

- **Type:** `string | string[]`

Path to global setup files, relative to project root
Path to global setup files, relative to project root.

A global setup file can either export named functions `setup` and `teardown` or a `default` function that returns a teardown function ([example](https://github.com/vitest-dev/vitest/blob/main/test/global-setup/vitest.config.ts)).

Expand All @@ -933,7 +933,7 @@ Multiple globalSetup files are possible. setup and teardown are executed sequent
:::

::: warning
Beware that the global setup is run in a different global scope, so your tests don't have access to variables defined here.
Beware that the global setup is running in a different global scope, so your tests don't have access to variables defined here. Also, since Vitest 1.0.0-beta, global setup runs only if there is at least one running test. This means that global setup might start running during watch mode after test file is changed, for example (the test file will wait for global setup to finish before running).
:::


Expand Down
6 changes: 6 additions & 0 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ export class Vitest {
return Array.from(projects).map(project => [project, file] as WorkspaceSpec)
}

async initializeGlobalSetup(paths: WorkspaceSpec[]) {
await Promise.all(paths.map(async ([project]) => project.initializeGlobalSetup()))
}

async runFiles(paths: WorkspaceSpec[]) {
const filepaths = paths.map(([, file]) => file)
this.state.collectPaths(filepaths)
Expand All @@ -440,6 +444,8 @@ export class Vitest {
this.invalidates.clear()
this.snapshot.clear()
this.state.clearErrors()
await this.initializeGlobalSetup(paths)

try {
await this.pool.runTests(paths, invalidates)
}
Expand Down
38 changes: 38 additions & 0 deletions packages/vitest/src/node/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { toArray } from '@vitest/utils'
import type { ViteNodeRunner } from 'vite-node/client'
import type { WorkspaceProject } from './workspace'

export interface GlobalSetupFile {
file: string
setup?: () => Promise<Function | void> | void
teardown?: Function
}

export async function loadGlobalSetupFiles(project: WorkspaceProject): Promise<GlobalSetupFile[]> {
const globalSetupFiles = toArray(project.server.config.test?.globalSetup)
return Promise.all(globalSetupFiles.map(file => loadGlobalSetupFile(file, project.runner)))
}

async function loadGlobalSetupFile(file: string, runner: ViteNodeRunner): Promise<GlobalSetupFile> {
const m = await runner.executeFile(file)
for (const exp of ['default', 'setup', 'teardown']) {
if (m[exp] != null && typeof m[exp] !== 'function')
throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`)
}
if (m.default) {
return {
file,
setup: m.default,
}
}
else if (m.setup || m.teardown) {
return {
file,
setup: m.setup,
teardown: m.teardown,
}
}
else {
throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`)
}
}
90 changes: 0 additions & 90 deletions packages/vitest/src/node/plugins/globalSetup.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/vitest/src/node/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { resolveApiServerConfig } from '../config'
import { Vitest } from '../core'
import { generateScopedClassName } from '../../integrations/css/css-modules'
import { SsrReplacerPlugin } from './ssrReplacer'
import { GlobalSetupPlugin } from './globalSetup'
import { CSSEnablerPlugin } from './cssEnabler'
import { CoverageTransform } from './coverageTransform'
import { MocksPlugin } from './mocks'
Expand Down Expand Up @@ -178,7 +177,6 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
},
},
SsrReplacerPlugin(),
GlobalSetupPlugin(ctx, ctx.logger),
...CSSEnablerPlugin(ctx),
CoverageTransform(ctx),
options.ui
Expand Down
2 changes: 0 additions & 2 deletions packages/vitest/src/node/plugins/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type { ResolvedConfig, UserWorkspaceConfig } from '../../types'
import { CoverageTransform } from './coverageTransform'
import { CSSEnablerPlugin } from './cssEnabler'
import { SsrReplacerPlugin } from './ssrReplacer'
import { GlobalSetupPlugin } from './globalSetup'
import { MocksPlugin } from './mocks'
import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow } from './utils'
import { VitestResolver } from './vitestResolver'
Expand Down Expand Up @@ -123,7 +122,6 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp
SsrReplacerPlugin(),
...CSSEnablerPlugin(project),
CoverageTransform(project.ctx),
GlobalSetupPlugin(project, project.ctx.logger),
MocksPlugin(),
VitestResolver(project.ctx),
VitestOptimizer(),
Expand Down
52 changes: 52 additions & 0 deletions packages/vitest/src/node/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { dirname, relative, resolve, toNamespacedPath } from 'pathe'
import type { ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite'
import { ViteNodeRunner } from 'vite-node/client'
import { ViteNodeServer } from 'vite-node/server'
import c from 'picocolors'
import { createBrowserServer } from '../integrations/browser/server'
import type { ArgumentsType, Reporter, ResolvedConfig, UserConfig, UserWorkspaceConfig, Vitest } from '../types'
import { deepMerge, hasFailed } from '../utils'
Expand All @@ -14,6 +15,9 @@ import { getBrowserProvider } from '../integrations/browser'
import { isBrowserEnabled, resolveConfig } from './config'
import { WorkspaceVitestPlugin } from './plugins/workspace'
import { createViteServer } from './vite'
import type { GlobalSetupFile } from './globalSetup'
import { loadGlobalSetupFiles } from './globalSetup'
import { divider } from './reporters/renderers/utils'

interface InitializeProjectOptions extends UserWorkspaceConfig {
workspaceConfigPath: string
Expand Down Expand Up @@ -64,6 +68,9 @@ export class WorkspaceProject {

testFilesList: string[] = []

private _globalSetupInit = false
private _globalSetups: GlobalSetupFile[] = []

constructor(
public path: string | number,
public ctx: Vitest,
Expand All @@ -77,6 +84,50 @@ export class WorkspaceProject {
return this.ctx.getCoreWorkspaceProject() === this
}

async initializeGlobalSetup() {
if (this._globalSetupInit)
return

this._globalSetupInit = true

this._globalSetups = await loadGlobalSetupFiles(this)

try {
for (const globalSetupFile of this._globalSetups) {
const teardown = await globalSetupFile.setup?.()
if (teardown == null || !!globalSetupFile.teardown)
continue
if (typeof teardown !== 'function')
throw new Error(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`)
globalSetupFile.teardown = teardown
}
}
catch (e) {
this.logger.error(`\n${c.red(divider(c.bold(c.inverse(' Error during global setup '))))}`)
await this.logger.printError(e)
process.exit(1)
}
}

async teardownGlobalSetup() {
if (!this._globalSetupInit || !this._globalSetups.length)
return
for (const globalSetupFile of this._globalSetups.reverse()) {
try {
await globalSetupFile.teardown?.()
}
catch (error) {
this.logger.error(`error during global teardown of ${globalSetupFile.file}`, error)
await this.logger.printError(error)
process.exitCode = 1
}
}
}

get logger() {
return this.ctx.logger
}

// it's possible that file path was imported with different queries (?raw, ?url, etc)
getModulesByFilepath(file: string) {
const set = this.server.moduleGraph.getModulesByFile(file)
Expand Down Expand Up @@ -337,6 +388,7 @@ export class WorkspaceProject {
this.server.close(),
this.typechecker?.stop(),
this.browser?.close(),
this.teardownGlobalSetup(),
].filter(Boolean))
}
return this.closingPromise
Expand Down
5 changes: 5 additions & 0 deletions test/global-setup-fail/fixtures/example.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect, test } from 'vitest'

test('example test', () => {
expect(1 + 1).toBe(2)
})

0 comments on commit 0646197

Please sign in to comment.