vitest
vitest copied to clipboard
console.log from webworker, when using browser runner, does not get captured
Describe the bug
When using the browser runner, if a test starts a webworker, and that worker calls console.log, the log messages are not shown as stdout like log messages from the main thread.
The only way I've found to see the log messages is to run in non-headless mode and open the JavaScript console.
Reproduction
https://stackblitz.com/edit/vitest-dev-vitest-oszejgfz?file=test%2Fbasic.test.ts
System Info
N/A
See stackblitz reproduction.
Used Package Manager
npm
Validations
- [x] Follow our Code of Conduct
- [x] Read the Contributing Guidelines.
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [x] The provided reproduction is a minimal reproducible example of the bug.
EDIT: I mixed up and I initially posted the comment https://github.com/vitest-dev/vitest/issues/7440#issuecomment-2641581817 here.
Similar to https://github.com/vitest-dev/vitest/issues/7440, here is node worker thread version https://stackblitz.com/edit/vitest-dev-vitest-q9nkjrvd?file=test%2Fbasic.test.ts.
This is also a fundamental difference how main and worker tied together on browser and on node. For node worker threads, stdio are reused, so console log shows up automatically in the terminal. To support something similar for browser worker, we need an extra mechanism to send log from worker to main.
Here is an example to proxy logs and unhandled errors using BroadcastChannel https://stackblitz.com/edit/vitest-dev-vitest-yzjj5amy?file=test%2Fbasic.test.ts
// worker.js
const channel = new BroadcastChannel('my-worker-channel');
self.onerror = (event) => {
channel.postMessage({ type: 'error', payload: event });
};
console.log = (...args) => {
channel.postMessage({ type: 'log', payload: args });
};
// basic.test.js
const channel = new BroadcastChannel('my-worker-channel');
channel.onmessage = (event) => {
if (event.data.type === 'error') {
throw new Error('[Worker error] ' + event.data.payload);
}
if (event.data.type === 'log') {
console.log('[Worker console]', ...event.data.payload);
}
};
chromium Browser runner started at http://localhost:63315/
...
stdout | test/basic.test.ts
[Worker console] Hello
...
✓ chromium test/basic.test.ts (1 test) 32ms
✓ create worker
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Vitest caught 1 unhandled error during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Error ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: [Worker error] Uncaught Error: Some error not caught
❯ channel.onmessage test/basic.test.ts:8:12
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Is there a way that vitest can inject some code to do that in every worker automatically? Maybe by monkey patching the Worker global?
Yeah, that's probably the plan. Vite uses a special url for worker entry file and we already do this:
https://github.com/vitest-dev/vitest/blob/c82387d36f7dc0cf8f558b96bf97f782b0b3637a/packages/browser/src/node/plugin.ts#L398-L411
This issue has been stalled for 3 months, and is complicating our migration to vitest browser mode. We are using vitest-fail-on-console to throw an error on every console.error. I maintain a design system, and do not want console errors to go unnoticed during my unit tests, otherwise client applications will get them too. With my only error message being "null", I have to spy console.error just to add a debugger statement so I can go back in the stack trace to find the original error.
It doesn't happen on every console error, but this time it was "ResizeObserver loop completed with undelivered notifications."