[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(runner): async assertion auto await should timeout (#6391)

authored by

Hiroshi Ogawa and committed by
GitHub
(Sep 3, 2024, 11:21 AM +0200) ad6e72fc cf148645

+42 -18
+2 -2
packages/expect/src/jest-expect.ts
··· 960 960 return result instanceof chai.Assertion ? proxy : result 961 961 } 962 962 963 - return async (...args: any[]) => { 963 + return (...args: any[]) => { 964 964 const promise = obj.then( 965 965 (value: any) => { 966 966 utils.flag(this, 'object', value) ··· 1022 1022 return result instanceof chai.Assertion ? proxy : result 1023 1023 } 1024 1024 1025 - return async (...args: any[]) => { 1025 + return (...args: any[]) => { 1026 1026 const promise = wrapper.then( 1027 1027 (value: any) => { 1028 1028 const _error = new AssertionError(
+2 -1
packages/runner/src/context.ts
··· 41 41 42 42 const { setTimeout, clearTimeout } = getSafeTimers() 43 43 44 - return ((...args: T extends (...args: infer A) => any ? A : never) => { 44 + // this function name is used to filter error in test/cli/test/fails.test.ts 45 + return (function runWithTimeout(...args: T extends (...args: infer A) => any ? A : never) { 45 46 return Promise.race([ 46 47 fn(...args), 47 48 new Promise((resolve, reject) => {
-10
packages/runner/src/run.ts
··· 224 224 } 225 225 await fn() 226 226 } 227 - // some async expect will be added to this array, in case user forget to await theme 228 - if (test.promises) { 229 - const result = await Promise.allSettled(test.promises) 230 - const errors = result 231 - .map(r => (r.status === 'rejected' ? r.reason : undefined)) 232 - .filter(Boolean) 233 - if (errors.length) { 234 - throw errors 235 - } 236 - } 237 227 238 228 await runner.onAfterTryTask?.(test, { 239 229 retry: retryCount,
+18 -1
packages/runner/src/suite.ts
··· 20 20 SuiteHooks, 21 21 Task, 22 22 TaskCustomOptions, 23 + TaskPopulated, 23 24 Test, 24 25 TestAPI, 25 26 TestFunction, ··· 346 347 setFn( 347 348 task, 348 349 withTimeout( 349 - withFixtures(handler, context), 350 + withAwaitAsyncAssetions(withFixtures(handler, context), task), 350 351 options?.timeout ?? runner.config.testTimeout, 351 352 ), 352 353 ) ··· 479 480 480 481 collectTask(collector) 481 482 return collector 483 + } 484 + 485 + function withAwaitAsyncAssetions<T extends (...args: any[]) => any>(fn: T, task: TaskPopulated): T { 486 + return (async (...args: any[]) => { 487 + await fn(...args) 488 + // some async expect will be added to this array, in case user forget to await them 489 + if (task.promises) { 490 + const result = await Promise.allSettled(task.promises) 491 + const errors = result 492 + .map(r => (r.status === 'rejected' ? r.reason : undefined)) 493 + .filter(Boolean) 494 + if (errors.length) { 495 + throw errors 496 + } 497 + } 498 + }) as T 482 499 } 483 500 484 501 function createSuite() {
+1 -1
test/cli/test/fails.test.ts
··· 17 17 const msg = String(stderr) 18 18 .split(/\n/g) 19 19 .reverse() 20 - .filter(i => i.includes('Error: ') && !i.includes('Command failed') && !i.includes('stackStr') && !i.includes('at runTest')) 20 + .filter(i => i.includes('Error: ') && !i.includes('Command failed') && !i.includes('stackStr') && !i.includes('at runTest') && !i.includes('at runWithTimeout')) 21 21 .map(i => i.trim().replace(root, '<rootDir>'), 22 22 ).join('\n') 23 23 expect(msg).toMatchSnapshot(file)
+1 -1
test/core/test/jest-expect.test.ts
··· 789 789 790 790 describe('promise auto queuing', () => { 791 791 it.fails('fails', () => { 792 - expect(() => new Promise((resolve, reject) => setTimeout(reject, 500))) 792 + expect(new Promise((resolve, reject) => setTimeout(reject, 500))) 793 793 .resolves 794 794 .toBe('true') 795 795 })
+6
test/cli/fixtures/fails/async-assertion.test.ts
··· 1 + import { test, expect } from "vitest" 2 + 3 + test('multiple errors', () => { 4 + expect(new Promise((r) => r("xx"))).resolves.toBe("yy"); 5 + expect(new Promise((r) => setTimeout(() => r("xx"), 10))).resolves.toBe("zz"); 6 + })
+5 -1
test/cli/fixtures/fails/test-timeout.test.ts
··· 1 - import { suite, test } from 'vitest' 1 + import { expect, suite, test } from 'vitest' 2 2 3 3 test('hi', async () => { 4 4 await new Promise(resolve => setTimeout(resolve, 1000)) ··· 17 17 await new Promise(resolve => setTimeout(resolve, 500)) 18 18 }) 19 19 }, 200) 20 + 21 + test('auto await async assertion', { timeout: 20 }, () => { 22 + expect(new Promise(() => {})).resolves.toBe(0) 23 + })
+7 -1
test/cli/test/__snapshots__/fails.test.ts.snap
··· 2 2 3 3 exports[`should fail .dot-folder/dot-test.test.ts > .dot-folder/dot-test.test.ts 1`] = `"AssertionError: expected true to be false // Object.is equality"`; 4 4 5 + exports[`should fail async-assertion.test.ts > async-assertion.test.ts 1`] = ` 6 + "AssertionError: expected 'xx' to be 'zz' // Object.is equality 7 + AssertionError: expected 'xx' to be 'yy' // Object.is equality" 8 + `; 9 + 5 10 exports[`should fail concurrent-suite-deadlock.test.ts > concurrent-suite-deadlock.test.ts 1`] = `"Error: Test timed out in 500ms."`; 6 11 7 12 exports[`should fail concurrent-test-deadlock.test.ts > concurrent-test-deadlock.test.ts 1`] = `"Error: Test timed out in 500ms."`; ··· 85 90 exports[`should fail test-extend/test-without-destructuring.test.ts > test-extend/test-without-destructuring.test.ts 1`] = `"Error: The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "context"."`; 86 91 87 92 exports[`should fail test-timeout.test.ts > test-timeout.test.ts 1`] = ` 88 - "Error: Test timed out in 200ms. 93 + "Error: Test timed out in 20ms. 94 + Error: Test timed out in 200ms. 89 95 Error: Test timed out in 100ms. 90 96 Error: Test timed out in 10ms." 91 97 `;