mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
feat(runner): Add full names to tasks (#9087)
This commit is contained in:
parent
2cc34e0d4a
commit
821aa20021
@ -42,7 +42,7 @@ export async function collectTests(
|
|||||||
|
|
||||||
runner.onCollectStart?.(file)
|
runner.onCollectStart?.(file)
|
||||||
|
|
||||||
clearCollectorContext(filepath, runner)
|
clearCollectorContext(file, runner)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const setupFiles = toArray(config.setupFiles)
|
const setupFiles = toArray(config.setupFiles)
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import { getHooks, setFn, setHooks, setTestFixture } from './map'
|
|||||||
import { getCurrentTest } from './test-state'
|
import { getCurrentTest } from './test-state'
|
||||||
import { findTestFileStackTrace } from './utils'
|
import { findTestFileStackTrace } from './utils'
|
||||||
import { createChainable } from './utils/chain'
|
import { createChainable } from './utils/chain'
|
||||||
|
import { createTaskName } from './utils/tasks'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
|
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
|
||||||
@ -213,14 +214,15 @@ function createDefaultSuite(runner: VitestRunner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function clearCollectorContext(
|
export function clearCollectorContext(
|
||||||
filepath: string,
|
file: File,
|
||||||
currentRunner: VitestRunner,
|
currentRunner: VitestRunner,
|
||||||
): void {
|
): void {
|
||||||
if (!defaultSuite) {
|
if (!defaultSuite) {
|
||||||
defaultSuite = createDefaultSuite(currentRunner)
|
defaultSuite = createDefaultSuite(currentRunner)
|
||||||
}
|
}
|
||||||
|
defaultSuite.file = file
|
||||||
runner = currentRunner
|
runner = currentRunner
|
||||||
currentTestFilepath = filepath
|
currentTestFilepath = file.filepath
|
||||||
collectorContext.tasks.length = 0
|
collectorContext.tasks.length = 0
|
||||||
defaultSuite.clear()
|
defaultSuite.clear()
|
||||||
collectorContext.currentSuite = defaultSuite
|
collectorContext.currentSuite = defaultSuite
|
||||||
@ -297,10 +299,16 @@ function createSuiteCollector(
|
|||||||
|
|
||||||
const task = function (name = '', options: TaskCustomOptions = {}) {
|
const task = function (name = '', options: TaskCustomOptions = {}) {
|
||||||
const timeout = options?.timeout ?? runner.config.testTimeout
|
const timeout = options?.timeout ?? runner.config.testTimeout
|
||||||
|
const currentSuite = collectorContext.currentSuite?.suite
|
||||||
const task: Test = {
|
const task: Test = {
|
||||||
id: '',
|
id: '',
|
||||||
name,
|
name,
|
||||||
suite: collectorContext.currentSuite?.suite,
|
fullName: createTaskName([
|
||||||
|
currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName,
|
||||||
|
name,
|
||||||
|
]),
|
||||||
|
fullTestName: createTaskName([currentSuite?.fullTestName, name]),
|
||||||
|
suite: currentSuite,
|
||||||
each: options.each,
|
each: options.each,
|
||||||
fails: options.fails,
|
fails: options.fails,
|
||||||
context: undefined!,
|
context: undefined!,
|
||||||
@ -439,11 +447,18 @@ function createSuiteCollector(
|
|||||||
suiteOptions = { timeout: suiteOptions }
|
suiteOptions = { timeout: suiteOptions }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentSuite = collectorContext.currentSuite?.suite
|
||||||
|
|
||||||
suite = {
|
suite = {
|
||||||
id: '',
|
id: '',
|
||||||
type: 'suite',
|
type: 'suite',
|
||||||
name,
|
name,
|
||||||
suite: collectorContext.currentSuite?.suite,
|
fullName: createTaskName([
|
||||||
|
currentSuite?.fullName ?? collectorContext.currentSuite?.file?.fullName,
|
||||||
|
name,
|
||||||
|
]),
|
||||||
|
fullTestName: createTaskName([currentSuite?.fullTestName, name]),
|
||||||
|
suite: currentSuite,
|
||||||
mode,
|
mode,
|
||||||
each,
|
each,
|
||||||
file: undefined!,
|
file: undefined!,
|
||||||
|
|||||||
@ -18,6 +18,40 @@ export interface TaskBase {
|
|||||||
* Task name provided by the user. If no name was provided, it will be an empty string.
|
* Task name provided by the user. If no name was provided, it will be an empty string.
|
||||||
*/
|
*/
|
||||||
name: string
|
name: string
|
||||||
|
/**
|
||||||
|
* Full name including the file path, any parent suites, and this task's name.
|
||||||
|
*
|
||||||
|
* Uses ` > ` as the separator between levels.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // file
|
||||||
|
* 'test/task-names.test.ts'
|
||||||
|
* @example
|
||||||
|
* // suite
|
||||||
|
* 'test/task-names.test.ts > meal planning'
|
||||||
|
* 'test/task-names.test.ts > meal planning > grocery lists'
|
||||||
|
* @example
|
||||||
|
* // test
|
||||||
|
* 'test/task-names.test.ts > meal planning > grocery lists > calculates ingredients'
|
||||||
|
*/
|
||||||
|
fullName: string
|
||||||
|
/**
|
||||||
|
* Full name excluding the file path, including any parent suites and this task's name. `undefined` for file tasks.
|
||||||
|
*
|
||||||
|
* Uses ` > ` as the separator between levels.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // file
|
||||||
|
* undefined
|
||||||
|
* @example
|
||||||
|
* // suite
|
||||||
|
* 'meal planning'
|
||||||
|
* 'meal planning > grocery lists'
|
||||||
|
* @example
|
||||||
|
* // test
|
||||||
|
* 'meal planning > grocery lists > calculates ingredients'
|
||||||
|
*/
|
||||||
|
fullTestName?: string
|
||||||
/**
|
/**
|
||||||
* Task mode.
|
* Task mode.
|
||||||
* - **skip**: task is skipped
|
* - **skip**: task is skipped
|
||||||
@ -291,6 +325,7 @@ export interface Test<ExtraContext = object> extends TaskPopulated {
|
|||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
artifacts: TestArtifact[]
|
artifacts: TestArtifact[]
|
||||||
|
fullTestName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Task = Test | Suite | File
|
export type Task = Test | Suite | File
|
||||||
@ -630,6 +665,7 @@ export interface SuiteCollector<ExtraContext = object> {
|
|||||||
)[]
|
)[]
|
||||||
scoped: (fixtures: Fixtures<any, ExtraContext>) => void
|
scoped: (fixtures: Fixtures<any, ExtraContext>) => void
|
||||||
fixtures: () => FixtureItem[] | undefined
|
fixtures: () => FixtureItem[] | undefined
|
||||||
|
file?: File
|
||||||
suite?: Suite
|
suite?: Suite
|
||||||
task: (name: string, options?: TaskCustomOptions) => Test<ExtraContext>
|
task: (name: string, options?: TaskCustomOptions) => Test<ExtraContext>
|
||||||
collect: (file: File) => Promise<Suite>
|
collect: (file: File) => Promise<Suite>
|
||||||
|
|||||||
@ -187,6 +187,7 @@ export function createFileTask(
|
|||||||
const file: File = {
|
const file: File = {
|
||||||
id: generateFileHash(path, projectName),
|
id: generateFileHash(path, projectName),
|
||||||
name: path,
|
name: path,
|
||||||
|
fullName: path,
|
||||||
type: 'suite',
|
type: 'suite',
|
||||||
mode: 'queued',
|
mode: 'queued',
|
||||||
filepath,
|
filepath,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export {
|
|||||||
export { limitConcurrency } from './limit-concurrency'
|
export { limitConcurrency } from './limit-concurrency'
|
||||||
export { partitionSuiteChildren } from './suite'
|
export { partitionSuiteChildren } from './suite'
|
||||||
export {
|
export {
|
||||||
|
createTaskName,
|
||||||
getFullName,
|
getFullName,
|
||||||
getNames,
|
getNames,
|
||||||
getSuites,
|
getSuites,
|
||||||
|
|||||||
@ -80,3 +80,7 @@ export function getFullName(task: Task, separator = ' > '): string {
|
|||||||
export function getTestName(task: Task, separator = ' > '): string {
|
export function getTestName(task: Task, separator = ' > '): string {
|
||||||
return getNames(task).slice(1).join(separator)
|
return getNames(task).slice(1).join(separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTaskName(names: readonly (string | undefined)[], separator = ' > '): string {
|
||||||
|
return names.filter(name => name !== undefined).join(separator)
|
||||||
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ const fileWithTextStacks: RunnerTestFile = {
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
filepath: 'test/plain-stack-trace.ts',
|
filepath: 'test/plain-stack-trace.ts',
|
||||||
|
fullName: 'test/plain-stack-trace.ts',
|
||||||
meta: {},
|
meta: {},
|
||||||
result: {
|
result: {
|
||||||
state: 'fail',
|
state: 'fail',
|
||||||
@ -98,6 +99,7 @@ describe('ViewReport', () => {
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
filepath: 'test/plain-stack-trace.ts',
|
filepath: 'test/plain-stack-trace.ts',
|
||||||
|
fullName: 'test/plain-stack-trace.ts',
|
||||||
meta: {},
|
meta: {},
|
||||||
result: {
|
result: {
|
||||||
state: 'fail',
|
state: 'fail',
|
||||||
@ -157,6 +159,7 @@ describe('ViewReport', () => {
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
filepath: 'test/plain-stack-trace.ts',
|
filepath: 'test/plain-stack-trace.ts',
|
||||||
|
fullName: 'test/plain-stack-trace.ts',
|
||||||
meta: {},
|
meta: {},
|
||||||
result: {
|
result: {
|
||||||
state: 'fail',
|
state: 'fail',
|
||||||
|
|||||||
@ -46,6 +46,7 @@ const failed = computed(() => {
|
|||||||
id: file!.id,
|
id: file!.id,
|
||||||
file: file!,
|
file: file!,
|
||||||
name: file!.name,
|
name: file!.name,
|
||||||
|
fullName: file!.name,
|
||||||
level: 0,
|
level: 0,
|
||||||
type: 'suite',
|
type: 'suite',
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type { TestProject } from './project'
|
|||||||
import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping'
|
import { originalPositionFor, TraceMap } from '@jridgewell/trace-mapping'
|
||||||
import {
|
import {
|
||||||
calculateSuiteHash,
|
calculateSuiteHash,
|
||||||
|
createTaskName,
|
||||||
generateHash,
|
generateHash,
|
||||||
interpretTaskModes,
|
interpretTaskModes,
|
||||||
someTasksAreOnly,
|
someTasksAreOnly,
|
||||||
@ -193,6 +194,7 @@ export function createFailedFileTask(project: TestProject, filepath: string, err
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
id: /* @__PURE__ */ generateHash(`${testFilepath}${project.config.name || ''}`),
|
id: /* @__PURE__ */ generateHash(`${testFilepath}${project.config.name || ''}`),
|
||||||
name: testFilepath,
|
name: testFilepath,
|
||||||
|
fullName: testFilepath,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
tasks: [],
|
tasks: [],
|
||||||
start: 0,
|
start: 0,
|
||||||
@ -252,6 +254,7 @@ function createFileTask(
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
id: /* @__PURE__ */ generateHash(`${testFilepath}${options.name || ''}`),
|
id: /* @__PURE__ */ generateHash(`${testFilepath}${options.name || ''}`),
|
||||||
name: testFilepath,
|
name: testFilepath,
|
||||||
|
fullName: testFilepath,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
tasks: [],
|
tasks: [],
|
||||||
start: ast.start,
|
start: ast.start,
|
||||||
@ -324,6 +327,8 @@ function createFileTask(
|
|||||||
tasks: [],
|
tasks: [],
|
||||||
mode,
|
mode,
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
|
fullName: createTaskName([latestSuite.fullName, definition.name]),
|
||||||
|
fullTestName: createTaskName([latestSuite.fullTestName, definition.name]),
|
||||||
end: definition.end,
|
end: definition.end,
|
||||||
start: definition.start,
|
start: definition.start,
|
||||||
location,
|
location,
|
||||||
@ -343,6 +348,8 @@ function createFileTask(
|
|||||||
mode,
|
mode,
|
||||||
context: {} as any, // not used on the server
|
context: {} as any, // not used on the server
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
|
fullName: createTaskName([latestSuite.fullName, definition.name]),
|
||||||
|
fullTestName: createTaskName([latestSuite.fullTestName, definition.name]),
|
||||||
end: definition.end,
|
end: definition.end,
|
||||||
start: definition.start,
|
start: definition.start,
|
||||||
location,
|
location,
|
||||||
|
|||||||
@ -327,6 +327,8 @@ export class JUnitReporter implements Reporter {
|
|||||||
id: file.id,
|
id: file.id,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: file.name,
|
name: file.name,
|
||||||
|
fullName: file.name,
|
||||||
|
fullTestName: file.name,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
result: file.result,
|
result: file.result,
|
||||||
meta: {},
|
meta: {},
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import type { Rollup } from 'vite'
|
|||||||
import type { TestProject } from '../node/project'
|
import type { TestProject } from '../node/project'
|
||||||
import {
|
import {
|
||||||
calculateSuiteHash,
|
calculateSuiteHash,
|
||||||
|
createTaskName,
|
||||||
generateHash,
|
generateHash,
|
||||||
interpretTaskModes,
|
interpretTaskModes,
|
||||||
someTasksAreOnly,
|
someTasksAreOnly,
|
||||||
@ -60,6 +61,7 @@ export async function collectTests(
|
|||||||
type: 'suite',
|
type: 'suite',
|
||||||
id: generateHash(`${testFilepath}${typecheckSubprojectName}`),
|
id: generateHash(`${testFilepath}${typecheckSubprojectName}`),
|
||||||
name: testFilepath,
|
name: testFilepath,
|
||||||
|
fullName: testFilepath,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
tasks: [],
|
tasks: [],
|
||||||
start: ast.start,
|
start: ast.start,
|
||||||
@ -185,6 +187,8 @@ export async function collectTests(
|
|||||||
tasks: [],
|
tasks: [],
|
||||||
mode,
|
mode,
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
|
fullName: createTaskName([lastSuite.fullName, definition.name]),
|
||||||
|
fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
|
||||||
end: definition.end,
|
end: definition.end,
|
||||||
start: definition.start,
|
start: definition.start,
|
||||||
meta: {
|
meta: {
|
||||||
@ -205,6 +209,8 @@ export async function collectTests(
|
|||||||
timeout: 0,
|
timeout: 0,
|
||||||
context: {} as any, // not used in typecheck
|
context: {} as any, // not used in typecheck
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
|
fullName: createTaskName([lastSuite.fullName, definition.name]),
|
||||||
|
fullTestName: createTaskName([lastSuite.fullTestName, definition.name]),
|
||||||
end: definition.end,
|
end: definition.end,
|
||||||
start: definition.start,
|
start: definition.start,
|
||||||
annotations: [],
|
annotations: [],
|
||||||
|
|||||||
@ -83,9 +83,12 @@ async function onMessage(message: WorkerRequest, project: TestProject, options:
|
|||||||
)
|
)
|
||||||
taskFile.mode = 'run'
|
taskFile.mode = 'run'
|
||||||
taskFile.result = { state: 'pass' }
|
taskFile.result = { state: 'pass' }
|
||||||
|
const taskName = 'custom test'
|
||||||
const taskTest: RunnerTestCase = {
|
const taskTest: RunnerTestCase = {
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'custom test',
|
name: taskName,
|
||||||
|
fullName: `${taskFile.fullName} > ${taskName}`,
|
||||||
|
fullTestName: `${taskFile.fullTestName} > ${taskName}`,
|
||||||
id: `${taskFile.id}_0`,
|
id: `${taskFile.id}_0`,
|
||||||
context: {} as any,
|
context: {} as any,
|
||||||
suite: taskFile,
|
suite: taskFile,
|
||||||
|
|||||||
325
test/core/test/task-names.test.ts
Normal file
325
test/core/test/task-names.test.ts
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
/**
|
||||||
|
* This test is self-referential - it validates its own structure and the structure of the tests defined below.
|
||||||
|
*
|
||||||
|
* The order and nesting of these test definitions MUST match the assertions, or the test will fail. The assertions use array indices (e.g., `task.file.tasks[0]`) to access specific tests, so reordering will break the test.
|
||||||
|
*
|
||||||
|
* If you need to modify this structure, update both the setup below AND the corresponding assertions above to maintain consistency.
|
||||||
|
*/
|
||||||
|
import type { RunnerTestSuite } from 'vitest'
|
||||||
|
import { describe, test } from 'vitest'
|
||||||
|
|
||||||
|
test('tasks have correct `fullName` and `fullTestName` properties', ({ expect, task }) => {
|
||||||
|
// this test validates the structure defined at the bottom of this file.
|
||||||
|
//
|
||||||
|
// structure (must match setup at bottom):
|
||||||
|
//
|
||||||
|
// task-names.test.ts
|
||||||
|
// ├─ [0] tasks have correct `fullName` and `fullTestName` properties (this test)
|
||||||
|
// ├─ [1] creates new recipe
|
||||||
|
// ├─ [2] searches by ingredient
|
||||||
|
// ├─ [3] recipe management/
|
||||||
|
// │ ├─ [0] saves recipe
|
||||||
|
// │ └─ [1] deletes recipe
|
||||||
|
// └─ [4] meal planning/
|
||||||
|
// ├─ [0] generates weekly plan
|
||||||
|
// ├─ [1] grocery lists/
|
||||||
|
// │ ├─ [0] calculates ingredients
|
||||||
|
// │ ├─ [1] combines duplicate items
|
||||||
|
// │ └─ [2] shopping/
|
||||||
|
// │ ├─ [0] marks items as purchased
|
||||||
|
// │ └─ [1] estimates total cost
|
||||||
|
// ├─ [2] exports calendar
|
||||||
|
// └─ [3] nutrition tracking/
|
||||||
|
// ├─ [0] calculates daily calories
|
||||||
|
// └─ [1] tracks macros
|
||||||
|
|
||||||
|
// validate this test itself (task.file.tasks[0])
|
||||||
|
expect(task.suite).toBe(undefined)
|
||||||
|
expect(
|
||||||
|
task.fullName,
|
||||||
|
).toBe('test/task-names.test.ts > tasks have correct `fullName` and `fullTestName` properties')
|
||||||
|
expect(
|
||||||
|
task.fullTestName,
|
||||||
|
).toBe('tasks have correct `fullName` and `fullTestName` properties')
|
||||||
|
|
||||||
|
expect(task.file.fullName).toBe('test/task-names.test.ts')
|
||||||
|
expect(task.file.fullTestName).toBe(undefined)
|
||||||
|
|
||||||
|
const thisTest = task.file.tasks[0]
|
||||||
|
expect(thisTest.suite).toBe(undefined)
|
||||||
|
expect(thisTest.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > tasks have correct `fullName` and `fullTestName` properties',
|
||||||
|
)
|
||||||
|
expect(thisTest.fullTestName).toBe(
|
||||||
|
'tasks have correct `fullName` and `fullTestName` properties',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
task.file.tasks,
|
||||||
|
).toHaveLength(5)
|
||||||
|
|
||||||
|
// top-level tests
|
||||||
|
const createsRecipe = task.file.tasks[1]
|
||||||
|
expect(createsRecipe.suite).toBe(undefined)
|
||||||
|
expect(createsRecipe.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > creates new recipe',
|
||||||
|
)
|
||||||
|
expect(createsRecipe.fullTestName).toBe(
|
||||||
|
'creates new recipe',
|
||||||
|
)
|
||||||
|
|
||||||
|
const searchIngredient = task.file.tasks[2]
|
||||||
|
expect(searchIngredient.suite).toBe(undefined)
|
||||||
|
expect(searchIngredient.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > searches by ingredient',
|
||||||
|
)
|
||||||
|
expect(searchIngredient.fullTestName).toBe(
|
||||||
|
'searches by ingredient',
|
||||||
|
)
|
||||||
|
|
||||||
|
// single-level suite
|
||||||
|
const recipeManagement = task.file.tasks[3] as RunnerTestSuite
|
||||||
|
expect(recipeManagement.suite).toBe(undefined)
|
||||||
|
expect(recipeManagement.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > recipe management',
|
||||||
|
)
|
||||||
|
expect(recipeManagement.fullTestName).toBe(
|
||||||
|
'recipe management',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(recipeManagement.tasks).toHaveLength(2)
|
||||||
|
|
||||||
|
const savesRecipe = recipeManagement.tasks[0]
|
||||||
|
expect(savesRecipe.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > recipe management',
|
||||||
|
)
|
||||||
|
expect(savesRecipe.suite?.fullTestName).toBe(
|
||||||
|
'recipe management',
|
||||||
|
)
|
||||||
|
expect(savesRecipe.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > recipe management > saves recipe',
|
||||||
|
)
|
||||||
|
expect(savesRecipe.fullTestName).toBe(
|
||||||
|
'recipe management > saves recipe',
|
||||||
|
)
|
||||||
|
|
||||||
|
const deletesRecipe = recipeManagement.tasks[1]
|
||||||
|
expect(deletesRecipe.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > recipe management',
|
||||||
|
)
|
||||||
|
expect(deletesRecipe.suite?.fullTestName).toBe(
|
||||||
|
'recipe management',
|
||||||
|
)
|
||||||
|
expect(deletesRecipe.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > recipe management > deletes recipe',
|
||||||
|
)
|
||||||
|
expect(deletesRecipe.fullTestName).toBe(
|
||||||
|
'recipe management > deletes recipe',
|
||||||
|
)
|
||||||
|
|
||||||
|
// nested suites with mixed patterns
|
||||||
|
const mealPlanning = task.file.tasks[4] as RunnerTestSuite
|
||||||
|
expect(mealPlanning.suite).toBe(undefined)
|
||||||
|
expect(mealPlanning.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning',
|
||||||
|
)
|
||||||
|
expect(mealPlanning.fullTestName).toBe(
|
||||||
|
'meal planning',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(mealPlanning.tasks).toHaveLength(4)
|
||||||
|
|
||||||
|
const generatesPlan = mealPlanning.tasks[0]
|
||||||
|
expect(generatesPlan.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning',
|
||||||
|
)
|
||||||
|
expect(generatesPlan.suite?.fullTestName).toBe(
|
||||||
|
'meal planning',
|
||||||
|
)
|
||||||
|
expect(generatesPlan.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > generates weekly plan',
|
||||||
|
)
|
||||||
|
expect(generatesPlan.fullTestName).toBe(
|
||||||
|
'meal planning > generates weekly plan',
|
||||||
|
)
|
||||||
|
|
||||||
|
const groceryList = mealPlanning.tasks[1] as RunnerTestSuite
|
||||||
|
expect(groceryList.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning',
|
||||||
|
)
|
||||||
|
expect(groceryList.suite?.fullTestName).toBe(
|
||||||
|
'meal planning',
|
||||||
|
)
|
||||||
|
expect(groceryList.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(groceryList.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(groceryList.tasks).toHaveLength(3)
|
||||||
|
|
||||||
|
const calculatesIngredients = groceryList.tasks[0]
|
||||||
|
expect(calculatesIngredients.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(calculatesIngredients.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(calculatesIngredients.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > calculates ingredients',
|
||||||
|
)
|
||||||
|
expect(calculatesIngredients.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > calculates ingredients',
|
||||||
|
)
|
||||||
|
|
||||||
|
const combinesItems = groceryList.tasks[1]
|
||||||
|
expect(combinesItems.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(combinesItems.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(combinesItems.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > combines duplicate items',
|
||||||
|
)
|
||||||
|
expect(combinesItems.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > combines duplicate items',
|
||||||
|
)
|
||||||
|
|
||||||
|
const shopping = groceryList.tasks[2] as RunnerTestSuite
|
||||||
|
expect(shopping.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(shopping.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists',
|
||||||
|
)
|
||||||
|
expect(shopping.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
expect(shopping.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(shopping.tasks).toHaveLength(2)
|
||||||
|
|
||||||
|
const marksItemsPurchased = shopping.tasks[0]
|
||||||
|
expect(marksItemsPurchased.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
expect(marksItemsPurchased.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
expect(marksItemsPurchased.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > shopping > marks items as purchased',
|
||||||
|
)
|
||||||
|
expect(marksItemsPurchased.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > shopping > marks items as purchased',
|
||||||
|
)
|
||||||
|
|
||||||
|
const estimatesTotalCost = shopping.tasks[1]
|
||||||
|
expect(estimatesTotalCost.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
expect(estimatesTotalCost.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > shopping',
|
||||||
|
)
|
||||||
|
expect(estimatesTotalCost.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > grocery lists > shopping > estimates total cost',
|
||||||
|
)
|
||||||
|
expect(estimatesTotalCost.fullTestName).toBe(
|
||||||
|
'meal planning > grocery lists > shopping > estimates total cost',
|
||||||
|
)
|
||||||
|
|
||||||
|
const exportsCalendar = mealPlanning.tasks[2]
|
||||||
|
expect(exportsCalendar.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning',
|
||||||
|
)
|
||||||
|
expect(exportsCalendar.suite?.fullTestName).toBe(
|
||||||
|
'meal planning',
|
||||||
|
)
|
||||||
|
expect(exportsCalendar.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > exports calendar',
|
||||||
|
)
|
||||||
|
expect(exportsCalendar.fullTestName).toBe(
|
||||||
|
'meal planning > exports calendar',
|
||||||
|
)
|
||||||
|
|
||||||
|
const nutritionTracking = mealPlanning.tasks[3] as RunnerTestSuite
|
||||||
|
expect(nutritionTracking.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning',
|
||||||
|
)
|
||||||
|
expect(nutritionTracking.suite?.fullTestName).toBe(
|
||||||
|
'meal planning',
|
||||||
|
)
|
||||||
|
expect(nutritionTracking.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
expect(nutritionTracking.fullTestName).toBe(
|
||||||
|
'meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(nutritionTracking.tasks).toHaveLength(2)
|
||||||
|
|
||||||
|
const calculatesCalories = nutritionTracking.tasks[0]
|
||||||
|
expect(calculatesCalories.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
expect(calculatesCalories.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
expect(calculatesCalories.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > nutrition tracking > calculates daily calories',
|
||||||
|
)
|
||||||
|
expect(calculatesCalories.fullTestName).toBe(
|
||||||
|
'meal planning > nutrition tracking > calculates daily calories',
|
||||||
|
)
|
||||||
|
|
||||||
|
const tracksMacros = nutritionTracking.tasks[1]
|
||||||
|
expect(tracksMacros.suite?.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
expect(tracksMacros.suite?.fullTestName).toBe(
|
||||||
|
'meal planning > nutrition tracking',
|
||||||
|
)
|
||||||
|
expect(tracksMacros.fullName).toBe(
|
||||||
|
'test/task-names.test.ts > meal planning > nutrition tracking > tracks macros',
|
||||||
|
)
|
||||||
|
expect(tracksMacros.fullTestName).toBe(
|
||||||
|
'meal planning > nutrition tracking > tracks macros',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// setup
|
||||||
|
|
||||||
|
// top-level tests
|
||||||
|
test('creates new recipe')
|
||||||
|
test('searches by ingredient')
|
||||||
|
|
||||||
|
// single-level suite
|
||||||
|
describe('recipe management', () => {
|
||||||
|
test('saves recipe')
|
||||||
|
test('deletes recipe')
|
||||||
|
})
|
||||||
|
|
||||||
|
// nested suites with mixed patterns
|
||||||
|
describe('meal planning', () => {
|
||||||
|
test('generates weekly plan')
|
||||||
|
|
||||||
|
describe('grocery lists', () => {
|
||||||
|
test('calculates ingredients')
|
||||||
|
test('combines duplicate items')
|
||||||
|
|
||||||
|
describe('shopping', () => {
|
||||||
|
test('marks items as purchased')
|
||||||
|
test('estimates total cost')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('exports calendar')
|
||||||
|
|
||||||
|
describe('nutrition tracking', () => {
|
||||||
|
test('calculates daily calories')
|
||||||
|
test('tracks macros')
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -12,10 +12,13 @@ file.result = {
|
|||||||
duration: 145.99284195899963,
|
duration: 145.99284195899963,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const suiteName = 'suite'
|
||||||
const suite: RunnerTestSuite = {
|
const suite: RunnerTestSuite = {
|
||||||
id: `${file.id}_0`,
|
id: `${file.id}_0`,
|
||||||
type: 'suite',
|
type: 'suite',
|
||||||
name: 'suite',
|
name: suiteName,
|
||||||
|
fullName: `${file.fullName} > ${suiteName}`,
|
||||||
|
fullTestName: `${file.fullTestName} > ${suiteName}`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
meta: {},
|
meta: {},
|
||||||
file,
|
file,
|
||||||
@ -34,6 +37,8 @@ passedFile.tasks.push({
|
|||||||
id: `${file.id}_1`,
|
id: `${file.id}_1`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'Math.sqrt()',
|
name: 'Math.sqrt()',
|
||||||
|
fullName: `${suite.fullName} > Math.sqrt()`,
|
||||||
|
fullTestName: `${suite.fullTestName} > Math.sqrt()`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
suite,
|
suite,
|
||||||
@ -75,6 +80,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_0`,
|
id: `${suite.id}_0`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'Math.sqrt()',
|
name: 'Math.sqrt()',
|
||||||
|
fullName: `${suite.fullName} > Math.sqrt()`,
|
||||||
|
fullTestName: `${suite.fullTestName} > Math.sqrt()`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
meta: {},
|
meta: {},
|
||||||
@ -98,6 +105,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_1`,
|
id: `${suite.id}_1`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'JSON',
|
name: 'JSON',
|
||||||
|
fullName: `${suite.fullName} > JSON`,
|
||||||
|
fullTestName: `${suite.fullTestName} > JSON`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
annotations: [],
|
annotations: [],
|
||||||
artifacts: [],
|
artifacts: [],
|
||||||
@ -113,6 +122,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_3`,
|
id: `${suite.id}_3`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'async with timeout',
|
name: 'async with timeout',
|
||||||
|
fullName: `${suite.fullName} > async with timeout`,
|
||||||
|
fullTestName: `${suite.fullTestName} > async with timeout`,
|
||||||
mode: 'skip',
|
mode: 'skip',
|
||||||
suite,
|
suite,
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
@ -128,6 +139,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_4`,
|
id: `${suite.id}_4`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'timeout',
|
name: 'timeout',
|
||||||
|
fullName: `${suite.fullName} > timeout`,
|
||||||
|
fullTestName: `${suite.fullTestName} > timeout`,
|
||||||
annotations: [],
|
annotations: [],
|
||||||
artifacts: [],
|
artifacts: [],
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
@ -143,6 +156,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_5`,
|
id: `${suite.id}_5`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'callback setup success ',
|
name: 'callback setup success ',
|
||||||
|
fullName: `${suite.fullName} > callback setup success `,
|
||||||
|
fullTestName: `${suite.fullTestName} > callback setup success `,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
suite,
|
suite,
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
@ -158,6 +173,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_6`,
|
id: `${suite.id}_6`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'callback test success ',
|
name: 'callback test success ',
|
||||||
|
fullName: `${suite.fullName} > callback test success `,
|
||||||
|
fullTestName: `${suite.fullTestName} > callback test success `,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
suite,
|
suite,
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
@ -173,6 +190,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_7`,
|
id: `${suite.id}_7`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'callback setup success done(false)',
|
name: 'callback setup success done(false)',
|
||||||
|
fullName: `${suite.fullName} > callback setup success done(false)`,
|
||||||
|
fullTestName: `${suite.fullTestName} > callback setup success done(false)`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
suite,
|
suite,
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
@ -188,6 +207,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_8`,
|
id: `${suite.id}_8`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'callback test success done(false)',
|
name: 'callback test success done(false)',
|
||||||
|
fullName: `${suite.fullName} > callback test success done(false)`,
|
||||||
|
fullTestName: `${suite.fullTestName} > callback test success done(false)`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
suite,
|
suite,
|
||||||
fails: undefined,
|
fails: undefined,
|
||||||
@ -211,6 +232,8 @@ const tasks: RunnerTestCase[] = [
|
|||||||
id: `${suite.id}_9`,
|
id: `${suite.id}_9`,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'todo test',
|
name: 'todo test',
|
||||||
|
fullName: `${suite.fullName} > todo test`,
|
||||||
|
fullTestName: `${suite.fullTestName} > todo test`,
|
||||||
mode: 'todo',
|
mode: 'todo',
|
||||||
suite,
|
suite,
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ exports[`html reporter > resolves to "failing" status for test file "json-fail"
|
|||||||
"environmentLoad": 0,
|
"environmentLoad": 0,
|
||||||
"file": [Circular],
|
"file": [Circular],
|
||||||
"filepath": "<rootDir>/test/reporters/fixtures/json-fail.test.ts",
|
"filepath": "<rootDir>/test/reporters/fixtures/json-fail.test.ts",
|
||||||
|
"fullName": "json-fail.test.ts",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"importDurations": {},
|
"importDurations": {},
|
||||||
"meta": {},
|
"meta": {},
|
||||||
@ -28,6 +29,8 @@ exports[`html reporter > resolves to "failing" status for test file "json-fail"
|
|||||||
"annotations": [],
|
"annotations": [],
|
||||||
"artifacts": [],
|
"artifacts": [],
|
||||||
"file": [Circular],
|
"file": [Circular],
|
||||||
|
"fullName": "json-fail.test.ts > should fail",
|
||||||
|
"fullTestName": "should fail",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"location": {
|
"location": {
|
||||||
"column": 1,
|
"column": 1,
|
||||||
@ -129,6 +132,7 @@ exports[`html reporter > resolves to "passing" status for test file "all-passing
|
|||||||
"environmentLoad": 0,
|
"environmentLoad": 0,
|
||||||
"file": [Circular],
|
"file": [Circular],
|
||||||
"filepath": "<rootDir>/test/reporters/fixtures/all-passing-or-skipped.test.ts",
|
"filepath": "<rootDir>/test/reporters/fixtures/all-passing-or-skipped.test.ts",
|
||||||
|
"fullName": "all-passing-or-skipped.test.ts",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"importDurations": {},
|
"importDurations": {},
|
||||||
"meta": {},
|
"meta": {},
|
||||||
@ -148,6 +152,8 @@ exports[`html reporter > resolves to "passing" status for test file "all-passing
|
|||||||
"annotations": [],
|
"annotations": [],
|
||||||
"artifacts": [],
|
"artifacts": [],
|
||||||
"file": [Circular],
|
"file": [Circular],
|
||||||
|
"fullName": "all-passing-or-skipped.test.ts > 2 + 3 = 5",
|
||||||
|
"fullTestName": "2 + 3 = 5",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"location": {
|
"location": {
|
||||||
"column": 1,
|
"column": 1,
|
||||||
@ -170,6 +176,8 @@ exports[`html reporter > resolves to "passing" status for test file "all-passing
|
|||||||
"annotations": [],
|
"annotations": [],
|
||||||
"artifacts": [],
|
"artifacts": [],
|
||||||
"file": [Circular],
|
"file": [Circular],
|
||||||
|
"fullName": "all-passing-or-skipped.test.ts > 3 + 3 = 6",
|
||||||
|
"fullTestName": "3 + 3 = 6",
|
||||||
"id": "1111755131_1",
|
"id": "1111755131_1",
|
||||||
"location": {
|
"location": {
|
||||||
"column": 6,
|
"column": 6,
|
||||||
|
|||||||
@ -10,19 +10,26 @@ const root = resolve(import.meta.dirname, '../fixtures')
|
|||||||
test('calc the duration used by junit', () => {
|
test('calc the duration used by junit', () => {
|
||||||
const result: RunnerTaskResult = { state: 'pass', duration: 0 }
|
const result: RunnerTaskResult = { state: 'pass', duration: 0 }
|
||||||
const file: RunnerTestFile = createFileTask('/test.ts', '/', 'test')
|
const file: RunnerTestFile = createFileTask('/test.ts', '/', 'test')
|
||||||
|
const suiteName
|
||||||
|
= 'suite'
|
||||||
const suite: RunnerTestSuite = {
|
const suite: RunnerTestSuite = {
|
||||||
id: '1_0',
|
id: '1_0',
|
||||||
type: 'suite',
|
type: 'suite',
|
||||||
name: 'suite',
|
name: suiteName,
|
||||||
|
fullName: `${file.fullName} > ${suiteName}`,
|
||||||
|
fullTestName: `${file.fullTestName} > ${suiteName}`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
tasks: [],
|
tasks: [],
|
||||||
file,
|
file,
|
||||||
meta: {},
|
meta: {},
|
||||||
}
|
}
|
||||||
|
const taskName = 'timeout'
|
||||||
const task: RunnerTestCase = {
|
const task: RunnerTestCase = {
|
||||||
id: '1_0_0',
|
id: '1_0_0',
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name: 'timeout',
|
name: taskName,
|
||||||
|
fullName: `${suite.fullName} > ${suiteName}`,
|
||||||
|
fullTestName: `${suite.fullTestName} > ${suiteName}`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
result,
|
result,
|
||||||
annotations: [],
|
annotations: [],
|
||||||
|
|||||||
@ -286,6 +286,8 @@ function createTest(name: string, file: File): Test {
|
|||||||
return {
|
return {
|
||||||
type: 'test',
|
type: 'test',
|
||||||
name,
|
name,
|
||||||
|
fullName: `${file.fullName} > ${name}`,
|
||||||
|
fullTestName: `${file.fullTestName} > ${name}`,
|
||||||
id: `${file.id}_0`,
|
id: `${file.id}_0`,
|
||||||
mode: 'run',
|
mode: 'run',
|
||||||
file,
|
file,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user