Skip to content
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

fix(vitest): don't initialize globalSetup if workspace doesn't run tests #4213

Merged
merged 3 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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)
})
Loading