Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 5 additions & 7 deletions packages/browser/src/node/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown> = {}
for (const prop of Object.getOwnPropertyNames(value)) {
clone[prop] = value[prop]
}
return clone
}

/**
Expand Down
10 changes: 7 additions & 3 deletions packages/runner/src/utils/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand All @@ -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 || [])) {
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/client/components/dashboard/ErrorEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ defineProps<{
This error originated in <span font-bold>{{ error.VITEST_TEST_PATH }}</span> test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
</p>
<div v-if="error.VITEST_TEST_NAME" text="sm" mb-2>
The latest test that might've caused the error is <span font-bold>{{ error.VITEST_TEST_NAME }}</span>. It might mean one of the following:<br>
The last test to run before this error was "<span font-bold>{{ error.VITEST_TEST_NAME }}</span>. This means either:<br>
<ul>
<li>
The error was thrown, while Vitest was running this test.
The error was thrown while Vitest was running this test
</li>
<li>
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
</li>
</ul>
</div>
Expand Down
12 changes: 11 additions & 1 deletion packages/vitest/src/node/ast-collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/pools/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
8 changes: 4 additions & 4 deletions packages/vitest/src/node/printError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
),
)
}
Expand Down
26 changes: 17 additions & 9 deletions packages/vitest/src/node/reporters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/browser/specs/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
30 changes: 15 additions & 15 deletions test/e2e/test/reporters/__snapshots__/junit.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ Error: uncaught timer
❯ Timeout._onTimeout multi.test.ts:7:11

This error originated in &quot;multi.test.ts&quot; test file. It doesn&apos;t mean the error was thrown inside the file itself, but while it was running.
The latest test that might&apos;ve caused the error is &quot;triggers two rejections and one uncaught exception&quot;. 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 &quot;triggers two rejections and one uncaught exception&quot;. 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.
</error>
</testcase>
<testcase classname="vitest unhandled errors" name="Unhandled Rejection: first rejection" time="...">
Expand All @@ -84,9 +84,9 @@ Error: first rejection
❯ multi.test.ts:4:23

This error originated in &quot;multi.test.ts&quot; test file. It doesn&apos;t mean the error was thrown inside the file itself, but while it was running.
The latest test that might&apos;ve caused the error is &quot;triggers two rejections and one uncaught exception&quot;. 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 &quot;triggers two rejections and one uncaught exception&quot;. 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.
</error>
</testcase>
<testcase classname="vitest unhandled errors" name="Unhandled Rejection: second rejection" time="...">
Expand All @@ -95,9 +95,9 @@ Error: second rejection
❯ multi.test.ts:5:23

This error originated in &quot;multi.test.ts&quot; test file. It doesn&apos;t mean the error was thrown inside the file itself, but while it was running.
The latest test that might&apos;ve caused the error is &quot;triggers two rejections and one uncaught exception&quot;. 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 &quot;triggers two rejections and one uncaught exception&quot;. 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.
</error>
</testcase>
</testsuite>
Expand Down Expand Up @@ -234,9 +234,9 @@ Error: rejection from space-1
❯ test/reject.test.ts:4:23

This error originated in &quot;test/reject.test.ts&quot; test file. It doesn&apos;t mean the error was thrown inside the file itself, but while it was running.
The latest test that might&apos;ve caused the error is &quot;triggers a rejection from project 1&quot;. 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 &quot;triggers a rejection from project 1&quot;. 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.
</error>
</testcase>
<testcase classname="vitest unhandled errors" file="space-2/test/reject.test.ts" name="Unhandled Rejection: rejection from space-2" time="...">
Expand All @@ -245,9 +245,9 @@ Error: rejection from space-2
❯ test/reject.test.ts:4:23

This error originated in &quot;test/reject.test.ts&quot; test file. It doesn&apos;t mean the error was thrown inside the file itself, but while it was running.
The latest test that might&apos;ve caused the error is &quot;triggers a rejection from project 2&quot;. 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 &quot;triggers a rejection from project 2&quot;. 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.
</error>
</testcase>
</testsuite>
Expand Down
Loading