@@ -8,6 +8,13 @@ import type {
88import type { SerializedError , TestError } from '@vitest/utils'
99import type { TestProject } from '../project'
1010
11+ interface ReportedTaskOptions {
12+ /**
13+ * @default true
14+ */
15+ register ?: boolean
16+ }
17+
1118class ReportedTaskImplementation {
1219 /**
1320 * Task instance.
@@ -33,10 +40,14 @@ class ReportedTaskImplementation {
3340 public readonly location : { line : number ; column : number } | undefined
3441
3542 /** @internal */
36- protected constructor (
43+ constructor (
3744 task : RunnerTask ,
3845 project : TestProject ,
46+ options : ReportedTaskOptions = { } ,
3947 ) {
48+ if ( options . register !== false ) {
49+ storeTask ( project , task , this as unknown as TestModule | TestCase | TestSuite )
50+ }
4051 this . task = task
4152 this . project = project
4253 this . id = task . id
@@ -57,9 +68,7 @@ class ReportedTaskImplementation {
5768 * @internal
5869 */
5970 static register ( task : RunnerTask , project : TestProject ) {
60- const state = new this ( task , project ) as TestCase | TestSuite | TestModule
61- storeTask ( project , task , state )
62- return state
71+ return new this ( task , project ) as TestCase | TestSuite | TestModule
6372 }
6473}
6574
@@ -86,9 +95,9 @@ export class TestCase extends ReportedTaskImplementation {
8695 public readonly options : TaskOptions
8796
8897 /**
89- * Parent suite. If the test was called directly inside the module, the parent will be the module itself.
98+ * Parent suite.
9099 */
91- public readonly parent : TestSuite | TestModule
100+ public readonly parent : TestSuite
92101
93102 /** @internal */
94103 protected constructor ( task : RunnerTestCase , project : TestProject ) {
@@ -101,7 +110,7 @@ export class TestCase extends ReportedTaskImplementation {
101110 this . parent = getReportedTask ( project , suite ) as TestSuite
102111 }
103112 else {
104- this . parent = this . module
113+ this . parent = this . module . suite
105114 }
106115 this . options = buildOptions ( task )
107116 }
@@ -111,7 +120,7 @@ export class TestCase extends ReportedTaskImplementation {
111120 */
112121 public get fullName ( ) : string {
113122 if ( this . #fullName === undefined ) {
114- if ( this . parent . type !== ' module' ) {
123+ if ( this . parent . task !== this . module . task ) {
115124 this . #fullName = `${ this . parent . fullName } > ${ this . name } `
116125 }
117126 else {
@@ -325,8 +334,12 @@ abstract class SuiteImplementation extends ReportedTaskImplementation {
325334 public readonly children : TestCollection
326335
327336 /** @internal */
328- protected constructor ( task : RunnerTestSuite | RunnerTestFile , project : TestProject ) {
329- super ( task , project )
337+ protected constructor (
338+ task : RunnerTestSuite | RunnerTestFile ,
339+ project : TestProject ,
340+ options ?: ReportedTaskOptions ,
341+ ) {
342+ super ( task , project , options )
330343 this . children = new TestCollection ( task , project )
331344 }
332345
@@ -356,31 +369,42 @@ export class TestSuite extends SuiteImplementation {
356369 public readonly module : TestModule
357370
358371 /**
359- * Parent suite. If suite was called directly inside the module, the parent will be the module itself .
372+ * Parent suite. If suite was called directly inside the module, the parent will be undefined .
360373 */
361- public readonly parent : TestSuite | TestModule
374+ public readonly parent : TestSuite | undefined
362375
363376 /**
364377 * Options that suite was initiated with.
365378 */
366379 public readonly options : TaskOptions
367380
368381 /** @internal */
369- protected constructor ( task : RunnerTestSuite , project : TestProject ) {
370- super ( task , project )
382+ constructor (
383+ task : RunnerTestSuite ,
384+ project : TestProject ,
385+ testModule ?: TestModule ,
386+ options ?: ReportedTaskOptions ,
387+ ) {
388+ super ( task , project , options )
371389
372390 this . name = task . name
373- this . module = getReportedTask ( project , task . file ) as TestModule
391+ this . module = testModule || getReportedTask ( project , task . file ) as TestModule
374392 const suite = this . task . suite
375393 if ( suite ) {
376394 this . parent = getReportedTask ( project , suite ) as TestSuite
377395 }
378- else {
379- this . parent = this . module
396+ else if ( this . module . suite && this !== this . module . suite ) {
397+ this . parent = this . module . suite
380398 }
381399 this . options = buildOptions ( task )
382400 }
383401
402+ static fromTestModule ( testModule : TestModule ) : TestSuite {
403+ return new this ( testModule . task , testModule . project , testModule , {
404+ register : false ,
405+ } )
406+ }
407+
384408 /**
385409 * Checks if the suite has any failed tests.
386410 * This will also return `false` if suite failed during collection.
@@ -399,7 +423,7 @@ export class TestSuite extends SuiteImplementation {
399423 */
400424 public get fullName ( ) : string {
401425 if ( this . #fullName === undefined ) {
402- if ( this . parent . type !== 'module' ) {
426+ if ( this . parent ) {
403427 this . #fullName = `${ this . parent . fullName } > ${ this . name } `
404428 }
405429 else {
@@ -415,6 +439,7 @@ export class TestModule extends SuiteImplementation {
415439 declare public readonly task : RunnerTestFile
416440 declare public readonly location : undefined
417441 public readonly type = 'module'
442+ public readonly suite : TestSuite
418443
419444 /**
420445 * This is usually an absolute UNIX file path.
@@ -427,6 +452,7 @@ export class TestModule extends SuiteImplementation {
427452 protected constructor ( task : RunnerTestFile , project : TestProject ) {
428453 super ( task , project )
429454 this . moduleId = task . filepath
455+ this . suite = TestSuite . fromTestModule ( this )
430456 }
431457
432458 /**
0 commit comments