| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -548,10 +548,6 @@ export class Vitest { | |||
| 548 | 548 | await this._reportFileTask(file) | |
| 549 | 549 | } | |
| 550 | 550 | ||
| 551 | - if (hasFailed(files)) { | ||
| 552 | - process.exitCode = 1 | ||
| 553 | - } | ||
| 554 | - | ||
| 555 | 551 | this._checkUnhandledErrors(errors) | |
| 556 | 552 | await this._testRun.end(specifications, errors).catch(noop) | |
| 557 | 553 | await this.initCoverageProvider() | |
@@ -632,22 +628,14 @@ export class Vitest { | |||
| 632 | 628 | ||
| 633 | 629 | // if run with --changed, don't exit if no tests are found | |
| 634 | 630 | if (!files.length) { | |
| 635 | - const throwAnError = !this.config.watch || !(this.config.changed || this.config.related?.length) | ||
| 636 | - | ||
| 637 | 631 | await this._testRun.start([]) | |
| 638 | 632 | const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true }) | |
| 639 | 633 | ||
| 640 | - // set exit code before calling `onTestRunEnd` so the lifecycle is consistent | ||
| 641 | - if (throwAnError) { | ||
| 642 | - const exitCode = this.config.passWithNoTests ? 0 : 1 | ||
| 643 | - process.exitCode = exitCode | ||
| 644 | - } | ||
| 645 | - | ||
| 646 | 634 | await this._testRun.end([], [], coverage) | |
| 647 | 635 | // Report coverage for uncovered files | |
| 648 | 636 | await this.reportCoverage(coverage, true) | |
| 649 | 637 | ||
| 650 | - if (throwAnError) { | ||
| 638 | + if (!this.config.watch || !(this.config.changed || this.config.related?.length)) { | ||
| 651 | 639 | throw new FilesNotFoundError(this.mode) | |
| 652 | 640 | } | |
| 653 | 641 | } | |
@@ -784,10 +772,6 @@ export class Vitest { | |||
| 784 | 772 | ||
| 785 | 773 | const files = this.state.getFiles() | |
| 786 | 774 | ||
| 787 | - if (hasFailed(files)) { | ||
| 788 | - process.exitCode = 1 | ||
| 789 | - } | ||
| 790 | - | ||
| 791 | 775 | this.cache.results.updateResults(files) | |
| 792 | 776 | try { | |
| 793 | 777 | await this.cache.results.writeToCache() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,6 +13,7 @@ import type { Vitest } from './core' | |||
| 13 | 13 | import type { TestProject } from './project' | |
| 14 | 14 | import type { ReportedHookContext, TestCase, TestCollection, TestModule } from './reporters/reported-tasks' | |
| 15 | 15 | import type { TestSpecification } from './spec' | |
| 16 | + import type { TestRunEndReason } from './types/reporter' | ||
| 16 | 17 | import assert from 'node:assert' | |
| 17 | 18 | import { createHash } from 'node:crypto' | |
| 18 | 19 | import { copyFile, mkdir } from 'node:fs/promises' | |
@@ -89,14 +90,18 @@ export class TestRun { | |||
| 89 | 90 | const modules = specifications.map(spec => spec.testModule).filter(s => s != null) | |
| 90 | 91 | const files = modules.map(m => m.task) | |
| 91 | 92 | ||
| 92 | - const state = this.vitest.isCancelling | ||
| 93 | + const state: TestRunEndReason = this.vitest.isCancelling | ||
| 93 | 94 | ? 'interrupted' | |
| 94 | 95 | // by this point, the run will be marked as failed if there are any errors, | |
| 95 | 96 | // should it be done by testRun.end? | |
| 96 | - : process.exitCode | ||
| 97 | + : this.hasFailed(modules) | ||
| 97 | 98 | ? 'failed' | |
| 98 | 99 | : 'passed' | |
| 99 | 100 | ||
| 101 | + if (state !== 'passed') { | ||
| 102 | + process.exitCode = 1 | ||
| 103 | + } | ||
| 104 | + | ||
| 100 | 105 | try { | |
| 101 | 106 | await Promise.all([ | |
| 102 | 107 | this.vitest.report('onTestRunEnd', modules, [...errors] as SerializedError[], state), | |
@@ -111,6 +116,14 @@ export class TestRun { | |||
| 111 | 116 | } | |
| 112 | 117 | } | |
| 113 | 118 | ||
| 119 | + private hasFailed(modules: TestModule[]) { | ||
| 120 | + if (!modules.length) { | ||
| 121 | + return !this.vitest.config.passWithNoTests | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + return modules.some(m => !m.ok()) | ||
| 125 | + } | ||
| 126 | + | ||
| 114 | 127 | private async reportEvent(id: string, event: TaskUpdateEvent, data: TaskEventData | undefined) { | |
| 115 | 128 | const task = this.vitest.state.idMap.get(id) | |
| 116 | 129 | const entity = task && this.vitest.state.getReportedEntity(task) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,7 @@ import type { | |||
| 8 | 8 | TestSpecification, | |
| 9 | 9 | TestSuite, | |
| 10 | 10 | UserConfig, | |
| 11 | + Vitest, | ||
| 11 | 12 | } from 'vitest/node' | |
| 12 | 13 | import { rmSync } from 'node:fs' | |
| 13 | 14 | import { resolve, sep } from 'node:path' | |
@@ -1011,6 +1012,88 @@ describe('type checking', () => { | |||
| 1011 | 1012 | }) | |
| 1012 | 1013 | }) | |
| 1013 | 1014 | ||
| 1015 | + describe('test run result', () => { | ||
| 1016 | + test('test run is interrupted', async () => { | ||
| 1017 | + let vitest: Vitest | ||
| 1018 | + let reason: TestRunEndReason | undefined | ||
| 1019 | + | ||
| 1020 | + await runInlineTests({ | ||
| 1021 | + 'example.test.js': ` | ||
| 1022 | + test('basic', () => new Promise(() => {})) | ||
| 1023 | + `, | ||
| 1024 | + }, { | ||
| 1025 | + globals: true, | ||
| 1026 | + reporters: [ | ||
| 1027 | + { | ||
| 1028 | + onInit(ctx) { | ||
| 1029 | + vitest = ctx | ||
| 1030 | + }, | ||
| 1031 | + async onTestModuleCollected() { | ||
| 1032 | + await vitest.cancelCurrentRun('keyboard-input') | ||
| 1033 | + }, | ||
| 1034 | + onTestRunEnd(_, __, reason_) { | ||
| 1035 | + reason = reason_ | ||
| 1036 | + }, | ||
| 1037 | + }, | ||
| 1038 | + ], | ||
| 1039 | + }) | ||
| 1040 | + | ||
| 1041 | + expect(reason).toBe('interrupted') | ||
| 1042 | + }) | ||
| 1043 | + | ||
| 1044 | + test('test run failed, but passed afterwards', async () => { | ||
| 1045 | + let reason: TestRunEndReason | undefined | ||
| 1046 | + | ||
| 1047 | + const { fs } = await runInlineTests({ | ||
| 1048 | + 'example.test.js': ` | ||
| 1049 | + test('basic', () => { | ||
| 1050 | + expect(1).toBe(2) | ||
| 1051 | + }) | ||
| 1052 | + `, | ||
| 1053 | + }, { | ||
| 1054 | + globals: true, | ||
| 1055 | + watch: true, | ||
| 1056 | + reporters: [ | ||
| 1057 | + { | ||
| 1058 | + onTestRunEnd(_, __, reason_) { | ||
| 1059 | + reason = reason_ | ||
| 1060 | + }, | ||
| 1061 | + }, | ||
| 1062 | + ], | ||
| 1063 | + }) | ||
| 1064 | + | ||
| 1065 | + expect(reason).toBe('failed') | ||
| 1066 | + | ||
| 1067 | + fs.editFile('./example.test.js', c => c.replace('toBe(2)', 'toBe(1)')) | ||
| 1068 | + | ||
| 1069 | + await expect.poll(() => reason).toBe('passed') | ||
| 1070 | + }) | ||
| 1071 | + | ||
| 1072 | + test('test run passed', async () => { | ||
| 1073 | + let reason: TestRunEndReason | undefined | ||
| 1074 | + | ||
| 1075 | + await runInlineTests({ | ||
| 1076 | + 'example.test.js': ` | ||
| 1077 | + test('basic', () => { | ||
| 1078 | + expect(1).toBe(1) | ||
| 1079 | + }) | ||
| 1080 | + `, | ||
| 1081 | + }, { | ||
| 1082 | + globals: true, | ||
| 1083 | + watch: true, | ||
| 1084 | + reporters: [ | ||
| 1085 | + { | ||
| 1086 | + onTestRunEnd(_, __, reason_) { | ||
| 1087 | + reason = reason_ | ||
| 1088 | + }, | ||
| 1089 | + }, | ||
| 1090 | + ], | ||
| 1091 | + }) | ||
| 1092 | + | ||
| 1093 | + expect(reason).toBe('passed') | ||
| 1094 | + }) | ||
| 1095 | + }) | ||
| 1096 | + | ||
| 1014 | 1097 | interface ReporterOptions { | |
| 1015 | 1098 | printTestRunEvents?: boolean | |
| 1016 | 1099 | roots?: string[] | |
| Back | FazBrowse Home | New Git URL |
0 commit comments