Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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: 4 additions & 0 deletions packages/browser/src/client/tester/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ export function createBrowserRunner(
}
}

onCollectStart = (file: File) => {
return rpc().onQueued(file)
}

onCollected = async (files: File[]): Promise<unknown> => {
files.forEach((file) => {
file.prepareDuration = state.durations.prepare
Expand Down
4 changes: 4 additions & 0 deletions packages/browser/src/node/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ export function setupBrowserRpc(server: BrowserServer) {
}
ctx.state.catchError(error, type)
},
async onQueued(file) {
ctx.state.collectFiles(project, [file])
await ctx.report('onQueued', file)
},
async onCollected(files) {
ctx.state.collectFiles(project, files)
await ctx.report('onCollected', files)
Expand Down
1 change: 1 addition & 0 deletions packages/browser/src/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface WebSocketBrowserHandlers {
resolveSnapshotPath: (testPath: string) => string
resolveSnapshotRawPath: (testPath: string, rawPath: string) => string
onUnhandledError: (error: unknown, type: string) => Promise<void>
onQueued: (file: RunnerTestFile) => void
onCollected: (files?: RunnerTestFile[]) => Promise<void>
onTaskUpdate: (packs: TaskResultPack[]) => void
onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void
Expand Down
4 changes: 4 additions & 0 deletions packages/runner/src/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export async function collectTests(
config.allowOnly,
)

if (file.mode === 'queued') {
file.mode = 'run'
}

files.push(file)
}

Expand Down
4 changes: 2 additions & 2 deletions packages/runner/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ async function callCleanupHooks(cleanups: HookCleanupCallback[]) {
export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
await runner.onBeforeRunTask?.(test)

if (test.mode !== 'run') {
if (test.mode !== 'run' && test.mode !== 'queued') {
return
}

Expand Down Expand Up @@ -458,7 +458,7 @@ export async function runSuite(suite: Suite, runner: VitestRunner): Promise<void
failTask(suite.result, e, runner.config.diffOptions)
}

if (suite.mode === 'run') {
if (suite.mode === 'run' || suite.mode === 'queued') {
if (!runner.config.passWithNoTests && !hasTests(suite)) {
suite.result.state = 'fail'
if (!suite.result.errors?.length) {
Expand Down
3 changes: 2 additions & 1 deletion packages/runner/src/types/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Awaitable, ErrorWithDiff } from '@vitest/utils'
import type { FixtureItem } from '../fixture'
import type { ChainableFunction } from '../utils/chain'

export type RunMode = 'run' | 'skip' | 'only' | 'todo'
export type RunMode = 'run' | 'skip' | 'only' | 'todo' | 'queued'
export type TaskState = RunMode | 'pass' | 'fail'

export interface TaskBase {
Expand All @@ -23,6 +23,7 @@ export interface TaskBase {
* - **only**: only this task and other tasks with `only` mode will run
* - **todo**: task is marked as a todo, alias for `skip`
* - **run**: task will run or already ran
* - **queued**: task will start running next. It can only exist on the File
*/
mode: RunMode
/**
Expand Down
8 changes: 4 additions & 4 deletions packages/runner/src/utils/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ export function interpretTaskModes(
})

// if all subtasks are skipped, mark as skip
if (suite.mode === 'run') {
if (suite.tasks.length && suite.tasks.every(i => i.mode !== 'run')) {
if (suite.mode === 'run' || suite.mode === 'queued') {
if (suite.tasks.length && suite.tasks.every(i => i.mode !== 'run' && i.mode !== 'queued')) {
suite.mode = 'skip'
}
}
Expand Down Expand Up @@ -115,7 +115,7 @@ export function someTasksAreOnly(suite: Suite): boolean {

function skipAllTasks(suite: Suite) {
suite.tasks.forEach((t) => {
if (t.mode === 'run') {
if (t.mode === 'run' || t.mode === 'queued') {
t.mode = 'skip'
if (t.type === 'suite') {
skipAllTasks(t)
Expand Down Expand Up @@ -172,7 +172,7 @@ export function createFileTask(
id: generateHash(`${path}${projectName || ''}`),
name: path,
type: 'suite',
mode: 'run',
mode: 'queued',
filepath,
tasks: [],
meta: Object.create(null),
Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/node/cli/cli-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ function forEachSuite(tasks: Task[], callback: (suite: Suite) => void) {

export function formatCollectedAsJSON(files: File[]) {
return files.map((file) => {
const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'only')
const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'queued' || test.mode === 'only')
return tests.map((test) => {
const result: any = {
name: getNames(test).slice(1).join(' > '),
Expand All @@ -276,7 +276,7 @@ export function formatCollectedAsJSON(files: File[]) {

export function formatCollectedAsString(files: File[]) {
return files.map((file) => {
const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'only')
const tests = getTests(file).filter(test => test.mode === 'run' || test.mode === 'queued' || test.mode === 'only')
return tests.map((test) => {
const name = getNames(test).join(' > ')
if (test.file.projectName) {
Expand Down
10 changes: 9 additions & 1 deletion packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,15 @@ export class Vitest {
return { tests: [], errors: [] }
}

await this.collectFiles(files)
const reporters = this.reporters
this.reporters = []

try {
await this.collectFiles(files)
}
finally {
this.reporters = reporters
}

return {
tests: this.state.getFiles(),
Expand Down
4 changes: 4 additions & 0 deletions packages/vitest/src/node/pools/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export function createMethodsRPC(project: TestProject, options: MethodsOptions =
ctx.state.collectPaths(paths)
return ctx.report('onPathsCollected', paths)
},
onQueued(file) {
ctx.state.collectFiles(project, [file])
return ctx.report('onQueued', file)
},
onCollected(files) {
ctx.state.collectFiles(project, files)
return ctx.report('onCollected', files)
Expand Down
3 changes: 2 additions & 1 deletion packages/vitest/src/node/reporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export abstract class BaseReporter implements Reporter {
if (
!('filepath' in task)
|| !task.result?.state
|| task.result?.state === 'run') {
|| task.result?.state === 'run'
|| task.result?.state === 'queued') {
return
}

Expand Down
3 changes: 2 additions & 1 deletion packages/vitest/src/node/reporters/benchmark/table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ export class TableReporter extends BaseReporter {
&& task.type === 'suite'
&& task.result?.state
&& task.result?.state !== 'run'
&& task.result?.state !== 'queued'
) {
// render static table when all benches inside single suite are finished
const benches = task.tasks.filter(t => t.meta.benchmark)
if (
benches.length > 0
&& benches.every(t => t.result?.state !== 'run')
&& benches.every(t => t.result?.state !== 'run' && t.result?.state !== 'queued')
) {
let title = ` ${getStateSymbol(task)} ${getFullName(
task,
Expand Down
4 changes: 4 additions & 0 deletions packages/vitest/src/node/reporters/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export class DefaultReporter extends BaseReporter {
}
}

onQueued(file: File) {
this.summary?.onQueued(file)
}

onInit(ctx: Vitest) {
super.onInit(ctx)
this.summary?.onInit(ctx, { verbose: this.verbose })
Expand Down
7 changes: 4 additions & 3 deletions packages/vitest/src/node/reporters/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const StatusMap: Record<TaskState, Status> = {
run: 'pending',
skip: 'skipped',
todo: 'todo',
queued: 'pending',
}

export interface JsonAssertionResult {
Expand Down Expand Up @@ -95,7 +96,7 @@ export class JsonReporter implements Reporter {

const numFailedTestSuites = suites.filter(s => s.result?.state === 'fail').length
const numPendingTestSuites = suites.filter(
s => s.result?.state === 'run' || s.mode === 'todo',
s => s.result?.state === 'run' || s.result?.state === 'queued' || s.mode === 'todo',
).length
const numPassedTestSuites = numTotalTestSuites - numFailedTestSuites - numPendingTestSuites

Expand All @@ -104,7 +105,7 @@ export class JsonReporter implements Reporter {
).length
const numPassedTests = tests.filter(t => t.result?.state === 'pass').length
const numPendingTests = tests.filter(
t => t.result?.state === 'run' || t.mode === 'skip' || t.result?.state === 'skip',
t => t.result?.state === 'run' || t.result?.state === 'queued' || t.mode === 'skip' || t.result?.state === 'skip',
).length
const numTodoTests = tests.filter(t => t.mode === 'todo').length
const testResults: Array<JsonTestResult> = []
Expand Down Expand Up @@ -154,7 +155,7 @@ export class JsonReporter implements Reporter {
} satisfies JsonAssertionResult
})

if (tests.some(t => t.result?.state === 'run')) {
if (tests.some(t => t.result?.state === 'run' || t.result?.state === 'queued')) {
this.ctx.logger.warn(
'WARNING: Some tests are still running when generating the JSON report.'
+ 'This is likely an internal bug in Vitest.'
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/reporters/renderers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export function getStateSymbol(task: Task) {
return pending
}

if (task.result.state === 'run') {
if (task.result.state === 'run' || task.result.state === 'queued') {
if (task.type === 'suite') {
return pointer
}
Expand Down
6 changes: 3 additions & 3 deletions packages/vitest/src/node/reporters/reported-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class TestCase extends ReportedTaskImplementation {
*/
public result(): TestResult | undefined {
const result = this.task.result
if (!result || result.state === 'run') {
if (!result || result.state === 'run' || result.state === 'queued') {
return undefined
}
const state = result.state === 'fail'
Expand Down Expand Up @@ -163,7 +163,7 @@ export class TestCase extends ReportedTaskImplementation {
public diagnostic(): TestDiagnostic | undefined {
const result = this.task.result
// startTime should always be available if the test has properly finished
if (!result || result.state === 'run' || !result.startTime) {
if (!result || result.state === 'run' || result.state === 'queued' || !result.startTime) {
return undefined
}
const duration = result.duration || 0
Expand Down Expand Up @@ -400,7 +400,7 @@ export interface TaskOptions {
shuffle: boolean | undefined
retry: number | undefined
repeats: number | undefined
mode: 'run' | 'only' | 'skip' | 'todo'
mode: 'run' | 'only' | 'skip' | 'todo' | 'queued'
}

function buildOptions(
Expand Down
4 changes: 4 additions & 0 deletions packages/vitest/src/node/reporters/summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export class SummaryReporter extends TaskParser implements Reporter {
})
}

onQueued(file: File) {
this.onTestFilePrepare(file)
}

onPathsCollected(paths?: string[]) {
this.suites.total = (paths || []).length
}
Expand Down
9 changes: 4 additions & 5 deletions packages/vitest/src/node/reporters/task-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class TaskParser {
const task = this.ctx.state.idMap.get(pack[0])

if (task?.type === 'suite' && 'filepath' in task && task.result?.state) {
if (task?.result?.state === 'run') {
if (task?.result?.state === 'run' || task?.result?.state === 'queued') {
startingTestFiles.push(task)
}
else {
Expand All @@ -55,7 +55,7 @@ export class TaskParser {
}

if (task?.type === 'test') {
if (task.result?.state === 'run') {
if (task.result?.state === 'run' || task.result?.state === 'queued') {
startingTests.push(task)
}
else if (task.result?.hooks?.afterEach !== 'run') {
Expand All @@ -65,7 +65,7 @@ export class TaskParser {

if (task?.result?.hooks) {
for (const [hook, state] of Object.entries(task.result.hooks)) {
if (state === 'run') {
if (state === 'run' || state === 'queued') {
startingHooks.push({ name: hook, file: task.file, id: task.id, type: task.type })
}
else {
Expand All @@ -81,7 +81,6 @@ export class TaskParser {

startingTestFiles.forEach(file => this.onTestFilePrepare(file))
startingTests.forEach(test => this.onTestStart(test))
startingHooks.forEach(hook => this.onHookStart(hook),
)
startingHooks.forEach(hook => this.onHookStart(hook))
}
}
1 change: 1 addition & 0 deletions packages/vitest/src/node/reporters/verbose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class VerboseReporter extends DefaultReporter {
&& task.type === 'test'
&& task.result?.state
&& task.result?.state !== 'run'
&& task.result?.state !== 'queued'
) {
let title = ` ${getStateSymbol(task)} `
if (task.file.projectName) {
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/node/types/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Reporter {
onInit?: (ctx: Vitest) => void
onPathsCollected?: (paths?: string[]) => Awaitable<void>
onSpecsCollected?: (specs?: SerializedTestSpecification[]) => Awaitable<void>
onQueued?: (file: File) => Awaitable<void>
onCollected?: (files?: File[]) => Awaitable<void>
onFinished?: (
files: File[],
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/runtime/runners/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async function runBenchmarkSuite(suite: Suite, runner: NodeBenchmarkRunner) {
const benchmarkGroup: Benchmark[] = []
const benchmarkSuiteGroup = []
for (const task of suite.tasks) {
if (task.mode !== 'run') {
if (task.mode !== 'run' && task.mode !== 'queued') {
continue
}

Expand Down
6 changes: 6 additions & 0 deletions packages/vitest/src/runtime/runners/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ export async function resolveTestRunner(
return p
}

const originalOnCollectStart = testRunner.onCollectStart
testRunner.onCollectStart = async (file) => {
await rpc().onQueued(file)
await originalOnCollectStart?.call(testRunner, file)
}

const originalOnCollected = testRunner.onCollected
testRunner.onCollected = async (files) => {
const state = getWorkerState()
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/runtime/runners/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class VitestTestRunner implements VitestRunner {
test.mode = 'skip'
}

if (test.mode !== 'run') {
if (test.mode !== 'run' && test.mode !== 'queued') {
return
}

Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/typecheck/collect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { File, Suite, Test } from '@vitest/runner'
import type { File, RunMode, Suite, Test } from '@vitest/runner'
import type { Node } from 'estree'
import type { RawSourceMap } from 'vite-node'
import type { TestProject } from '../node/project'
Expand Down Expand Up @@ -32,7 +32,7 @@ interface LocalCallDefinition {
end: number
name: string
type: 'suite' | 'test'
mode: 'run' | 'skip' | 'only' | 'todo'
mode: RunMode
task: ParsedSuite | ParsedFile | ParsedTest
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/typecheck/typechecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class Typechecker {
if ('tasks' in task) {
markTasks(task.tasks)
}
if (!task.result?.state && task.mode === 'run') {
if (!task.result?.state && (task.mode === 'run' || task.mode === 'queued')) {
task.result = {
state: 'pass',
}
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/types/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface RuntimeRPC {
onPathsCollected: (paths: string[]) => void
onUserConsoleLog: (log: UserConsoleLog) => void
onUnhandledError: (err: unknown, type: string) => void
onQueued: (file: File) => void
onCollected: (files: File[]) => Promise<void>
onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void
onTaskUpdate: (pack: TaskResultPack[]) => Promise<void>
Expand Down
5 changes: 5 additions & 0 deletions test/reporters/fixtures/long-loading-task.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from 'vitest'

await new Promise(r => setTimeout(r, 500))

test('works')
Loading
Loading