Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(runner): long synchronous tasks does not time out (fix #2920) #6944

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
4 changes: 3 additions & 1 deletion packages/runner/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export function withTimeout<T extends (...args: any[]) => any>(
// this function name is used to filter error in test/cli/test/fails.test.ts
return (function runWithTimeout(...args: T extends (...args: infer A) => any ? A : never) {
return Promise.race([
fn(...args),
new Promise((resolve, reject) => {
const timer = setTimeout(() => {
clearTimeout(timer)
Expand All @@ -52,6 +51,9 @@ export function withTimeout<T extends (...args: any[]) => any>(
// `unref` might not exist in browser
timer.unref?.()
}),
Promise.resolve(fn(...args)).then((result) => {
return new Promise(resolve => setTimeout(resolve, 0, result))
}),
Comment on lines +54 to +56
Copy link
Contributor

@hi-ogawa hi-ogawa Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took a while to understand this but the idea is more or less like this? Executing fn in sync as usual, but holding off returning until setTimeout(.., 0) to flush other setTimeout callbacks. I think code is fine as is, but it's just my commentary.

      (async () => {
        const result = await fn(...args);
        await new Promise(resolve => setTimeout(resolve, 0))
        return result;
      })()

Oh, well it looks like this code actually breaks test.extend, so I'm not sure I understood this well 😅 Ah I forgot about args

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! Yes that's the same thing, I can try refactor with your code if it's best.

]) as Awaitable<void>
}) as T
}
Expand Down
7 changes: 7 additions & 0 deletions test/cli/fixtures/fails/test-timeout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ test('hi', async () => {
await new Promise(resolve => setTimeout(resolve, 1000))
}, 10)

test('timeout on long synchronous task', async () => {
const start = Date.now();

while (Date.now() < start + 20) {
}
}, 15)

suite('suite timeout', {
timeout: 100,
}, () => {
Expand Down
1 change: 1 addition & 0 deletions test/cli/test/__snapshots__/fails.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ exports[`should fail test-timeout.test.ts > test-timeout.test.ts 1`] = `
"Error: Test timed out in 20ms.
Error: Test timed out in 200ms.
Error: Test timed out in 100ms.
Error: Test timed out in 15ms.
Error: Test timed out in 10ms."
`;

Expand Down
2 changes: 2 additions & 0 deletions test/reporters/tests/merge-reports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ test('merge reports', async () => {

stdout | first.test.ts > test 1-2
beforeEach

stdout | first.test.ts > test 1-2
test 1-2

❯ first.test.ts (2 tests | 1 failed) <time>
Expand Down
Loading