diff --git a/packages/browser/src/node/rpc.ts b/packages/browser/src/node/rpc.ts
index 3566a7848176..80af962ed797 100644
--- a/packages/browser/src/node/rpc.ts
+++ b/packages/browser/src/node/rpc.ts
@@ -409,13 +409,11 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject, defaultMocke
function cloneByOwnProperties(value: any) {
// Clones the value's properties into a new Object. The simpler approach of
// Object.assign() won't work in the case that properties are not enumerable.
- return Object.getOwnPropertyNames(value).reduce(
- (clone, prop) => ({
- ...clone,
- [prop]: value[prop],
- }),
- {},
- )
+ const clone: Record = {}
+ for (const prop of Object.getOwnPropertyNames(value)) {
+ clone[prop] = value[prop]
+ }
+ return clone
}
/**
diff --git a/packages/runner/src/utils/collect.ts b/packages/runner/src/utils/collect.ts
index 0a727488708f..961503a3d6cb 100644
--- a/packages/runner/src/utils/collect.ts
+++ b/packages/runner/src/utils/collect.ts
@@ -18,6 +18,10 @@ export function interpretTaskModes(
allowOnly?: boolean,
): void {
const matchedLocations: number[] = []
+ const testLocationsSet = testLocations !== undefined && testLocations.length !== 0
+ ? new Set(testLocations)
+ : undefined
+ const testIdsSet = testIds ? new Set(testIds) : undefined
const traverseSuite = (suite: Suite, parentIsOnly?: boolean, parentMatchedWithLocation?: boolean) => {
const suiteIsOnly = parentIsOnly || suite.mode === 'only'
@@ -54,8 +58,8 @@ export function interpretTaskModes(
// Match test location against provided locations, only run if present
// in `testLocations`. Note: if `includeTaskLocation` is not enabled,
// all test will be skipped.
- if (testLocations !== undefined && testLocations.length !== 0) {
- if (t.location && testLocations?.includes(t.location.line)) {
+ if (testLocationsSet !== undefined) {
+ if (t.location && testLocationsSet.has(t.location.line)) {
t.mode = 'run'
matchedLocations.push(t.location.line)
hasLocationMatch = true
@@ -72,7 +76,7 @@ export function interpretTaskModes(
if (namePattern && !getTaskFullName(t).match(namePattern)) {
t.mode = 'skip'
}
- if (testIds && !testIds.includes(t.id)) {
+ if (testIdsSet && !testIdsSet.has(t.id)) {
t.mode = 'skip'
}
if (testTagsFilter && !testTagsFilter(t.tags || [])) {
diff --git a/packages/ui/client/components/dashboard/ErrorEntry.vue b/packages/ui/client/components/dashboard/ErrorEntry.vue
index a593e55ca102..c6151b80de50 100644
--- a/packages/ui/client/components/dashboard/ErrorEntry.vue
+++ b/packages/ui/client/components/dashboard/ErrorEntry.vue
@@ -20,13 +20,13 @@ defineProps<{
This error originated in {{ error.VITEST_TEST_PATH }} test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
- The latest test that might've caused the error is
{{ error.VITEST_TEST_NAME }}. It might mean one of the following:
+ The last test to run before this error was "
{{ error.VITEST_TEST_NAME }}. This means either:
-
- The error was thrown, while Vitest was running this test.
+ The error was thrown while Vitest was running this test
-
- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+ The error was thrown after the test completed, and this was the most recent test at that point
diff --git a/packages/vitest/src/node/ast-collect.ts b/packages/vitest/src/node/ast-collect.ts
index 724d27fae3c4..78488ccc5c3d 100644
--- a/packages/vitest/src/node/ast-collect.ts
+++ b/packages/vitest/src/node/ast-collect.ts
@@ -49,6 +49,16 @@ interface LocalCallDefinition {
const debug = createDebugger('vitest:ast-collect-info')
const verbose = createDebugger('vitest:ast-collect-verbose')
+const INTERMEDIATE_CALL_PROPERTIES = new Set([
+ 'each',
+ 'for',
+ 'skipIf',
+ 'runIf',
+ 'extend',
+ 'scoped',
+ 'override',
+])
+
function isTestFunctionName(name: string) {
return name === 'it' || name === 'test' || name.startsWith('test') || name.endsWith('Test')
}
@@ -153,7 +163,7 @@ function astParseFile(filepath: string, code: string) {
const properties = getProperties(callee)
const property = callee?.property?.name
// intermediate calls like .each(), .for() will be picked up in the next iteration
- if (property && ['each', 'for', 'skipIf', 'runIf', 'extend', 'scoped', 'override'].includes(property)) {
+ if (property && INTERMEDIATE_CALL_PROPERTIES.has(property)) {
return
}
// skip properties on return values of calls - e.g., test('name', fn).skip()
diff --git a/packages/vitest/src/node/pools/pool.ts b/packages/vitest/src/node/pools/pool.ts
index eeccdc8aa825..bb6cab29c8b8 100644
--- a/packages/vitest/src/node/pools/pool.ts
+++ b/packages/vitest/src/node/pools/pool.ts
@@ -346,7 +346,7 @@ function deepEqual(obj1: any, obj2: any): boolean {
}
for (const key of keys1) {
- if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
+ if (!Object.prototype.hasOwnProperty.call(obj2, key) || !deepEqual(obj1[key], obj2[key])) {
return false
}
}
diff --git a/packages/vitest/src/node/printError.ts b/packages/vitest/src/node/printError.ts
index 3fc6f50ae78c..53135a0eaba0 100644
--- a/packages/vitest/src/node/printError.ts
+++ b/packages/vitest/src/node/printError.ts
@@ -237,11 +237,11 @@ function printErrorInner(
if (testName) {
logger.error(
c.red(
- `The latest test that might've caused the error is "${c.bold(
+ `The last test to run before this error was "${c.bold(
testName,
- )}". It might mean one of the following:`
- + '\n- The error was thrown, while Vitest was running this test.'
- + '\n- If the error occurred after the test had been completed, this was the last documented test before it was thrown.',
+ )}". This means either:`
+ + '\n- the error was thrown while Vitest was running this test, or'
+ + '\n- the error was thrown after the test completed, and this was the most recent test at that point.',
),
)
}
diff --git a/packages/vitest/src/node/reporters/base.ts b/packages/vitest/src/node/reporters/base.ts
index b1543f1f0308..b5442314c44f 100644
--- a/packages/vitest/src/node/reporters/base.ts
+++ b/packages/vitest/src/node/reporters/base.ts
@@ -679,10 +679,21 @@ export abstract class BaseReporter implements Reporter {
return
}
- const dangerImports = allImports.filter(imp => imp.totalTime >= thresholds.danger)
- const warnImports = allImports.filter(imp => imp.totalTime >= thresholds.warn)
- const hasDangerImports = dangerImports.length > 0
- const hasWarnImports = warnImports.length > 0
+ let dangerImportsCount = 0
+ let hasWarnImports = false
+ let totalSelfTime = 0
+ let totalTotalTime = 0
+ for (const imp of allImports) {
+ if (imp.totalTime >= thresholds.danger) {
+ dangerImportsCount++
+ }
+ if (imp.totalTime >= thresholds.warn) {
+ hasWarnImports = true
+ }
+ totalSelfTime += imp.selfTime
+ totalTotalTime += imp.totalTime
+ }
+ const hasDangerImports = dangerImportsCount > 0
// Determine if we should print
const shouldFail = failOnDanger && hasDangerImports
@@ -695,9 +706,6 @@ export abstract class BaseReporter implements Reporter {
const maxTotalTime = sortedImports[0].totalTime
const limit = this.ctx.config.experimental.importDurations.limit
const topImports = sortedImports.slice(0, limit)
-
- const totalSelfTime = allImports.reduce((sum, imp) => sum + imp.selfTime, 0)
- const totalTotalTime = allImports.reduce((sum, imp) => sum + imp.totalTime, 0)
const slowestImport = sortedImports[0]
this.log()
@@ -750,7 +758,7 @@ export abstract class BaseReporter implements Reporter {
if (shouldFail) {
this.log()
this.ctx.logger.error(
- `ERROR: ${dangerImports.length} import(s) exceeded the danger threshold of ${thresholds.danger}ms`,
+ `ERROR: ${dangerImportsCount} import(s) exceeded the danger threshold of ${thresholds.danger}ms`,
)
process.exitCode = 1
}
@@ -993,7 +1001,7 @@ function deepEqual(a: any, b: any): boolean {
}
for (const key of keysA) {
- if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
+ if (!Object.prototype.hasOwnProperty.call(b, key) || !deepEqual(a[key], b[key])) {
return false
}
}
diff --git a/test/browser/specs/errors.test.ts b/test/browser/specs/errors.test.ts
index 22851a1ab85b..f0c40b6f84af 100644
--- a/test/browser/specs/errors.test.ts
+++ b/test/browser/specs/errors.test.ts
@@ -11,7 +11,7 @@ test('prints correct unhandled error stack', async () => {
expect(stderr).toContain('throw-unhandled-error.test.ts:9:10')
expect(stderr).toContain('This error originated in "throw-unhandled-error.test.ts" test file.')
- expect(stderr).toContain('The latest test that might\'ve caused the error is "unhandled exception".')
+ expect(stderr).toContain('The last test to run before this error was "unhandled exception".')
if (instances.some(({ browser }) => browser === 'webkit')) {
expect(stderr).toContain('throw-unhandled-error.test.ts:9:20')
diff --git a/test/e2e/test/reporters/__snapshots__/junit.test.ts.snap b/test/e2e/test/reporters/__snapshots__/junit.test.ts.snap
index b8e60be0cea9..1271a53c0863 100644
--- a/test/e2e/test/reporters/__snapshots__/junit.test.ts.snap
+++ b/test/e2e/test/reporters/__snapshots__/junit.test.ts.snap
@@ -73,9 +73,9 @@ Error: uncaught timer
❯ Timeout._onTimeout multi.test.ts:7:11
This error originated in "multi.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
-The latest test that might've caused the error is "triggers two rejections and one uncaught exception". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+The last test to run before this error was "triggers two rejections and one uncaught exception". This means either:
+- the error was thrown while Vitest was running this test, or
+- the error was thrown after the test completed, and this was the most recent test at that point.
@@ -84,9 +84,9 @@ Error: first rejection
❯ multi.test.ts:4:23
This error originated in "multi.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
-The latest test that might've caused the error is "triggers two rejections and one uncaught exception". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+The last test to run before this error was "triggers two rejections and one uncaught exception". This means either:
+- the error was thrown while Vitest was running this test, or
+- the error was thrown after the test completed, and this was the most recent test at that point.
@@ -95,9 +95,9 @@ Error: second rejection
❯ multi.test.ts:5:23
This error originated in "multi.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
-The latest test that might've caused the error is "triggers two rejections and one uncaught exception". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+The last test to run before this error was "triggers two rejections and one uncaught exception". This means either:
+- the error was thrown while Vitest was running this test, or
+- the error was thrown after the test completed, and this was the most recent test at that point.
@@ -234,9 +234,9 @@ Error: rejection from space-1
❯ test/reject.test.ts:4:23
This error originated in "test/reject.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
-The latest test that might've caused the error is "triggers a rejection from project 1". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+The last test to run before this error was "triggers a rejection from project 1". This means either:
+- the error was thrown while Vitest was running this test, or
+- the error was thrown after the test completed, and this was the most recent test at that point.
@@ -245,9 +245,9 @@ Error: rejection from space-2
❯ test/reject.test.ts:4:23
This error originated in "test/reject.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
-The latest test that might've caused the error is "triggers a rejection from project 2". It might mean one of the following:
-- The error was thrown, while Vitest was running this test.
-- If the error occurred after the test had been completed, this was the last documented test before it was thrown.
+The last test to run before this error was "triggers a rejection from project 2". This means either:
+- the error was thrown while Vitest was running this test, or
+- the error was thrown after the test completed, and this was the most recent test at that point.