-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
@vitest/web-worker
error when using browser environment
#4899
Comments
This package is exclusively for running tests in Node.js environment. |
Do I have any alternative for getting coverage report for workers then? |
From what I understand, it should just work in the browser because worker import is processed on the server. cc @AriPerkkio However I guess it can't send the data about coverage to the main thread. |
I'm not actually sure how this works right now. My guess is that runner in browser doesn't see worker's scope and cannot collect the coverage from |
Hello @DenizUgur. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with |
I can reproduce the issue now. However when debugging anything browser-mode related with locally linked Vitest, whole test run freezes completely. Need to figure out that one first. This kind of issues come up quite often - browser mode is experimental. |
That's true. Let me know if I can be of assistance in any way. |
Coverage collection for browser's Workers is not supported. I don't think this has been looked into before as there as been no feature requests for it. Istanbul instrumented files collect the coverage data into global scope. In Vitest's case that's in // Inject this at the end of all workers that are loaded through Vite
const original = self.onmessage;
self.onmessage = (event) => {
if(event.data === "__VITEST_COLLECT_COVERAGE__") {
const coverage = globalThis.__VITEST_COVERAGE__;
return self.postMessage({ coverage }) // Not sure if JSON.stringify would be needed here
}
original?.(event);
} And when ever const worker = new Worker(new URL(TestWorker, import.meta.url).href, {type: 'module'})
// Inject this by Vitest - let's hope this new reference doesn't introduce memory leaks
+ globalThis.__VITEST_INTERCEPTED_WORKERS__ = globalThis.__VITEST_INTERCEPTED_WORKERS__ || []
+ globalThis.__VITEST_INTERCEPTED_WORKERS__.push(worker); And then in here we would also collect coverage from each worker: vitest/packages/coverage-istanbul/src/index.ts Lines 10 to 19 in 9ec3f74
let coverage = globalThis[COVERAGE_STORE_KEY]
if (globalThis.__VITEST_INTERCEPTED_WORKERS__?.length) {
// Demonstrating just a single worker now, intentional [0] index access
const worker = globalThis.__VITEST_INTERCEPTED_WORKERS__[0]
const promise = new Promise((resolve) => {
worker.onmessage = (event) => {
if (event.data.coverage) {
resolve(event.data.coverage)
}
}
})
worker.postMessage('__VITEST_GET_COVERAGE__')
const workerCoverage = await promise
coverage = {
...coverage, // This holds coverage of the file that loaded Worker, main.ts in repro's case
...workerCoverage, // Coverage of worker.ts
};
} I did some quick hacky testing and run into issues with Istanbul. For some reason writing into So to summarize: It should be possible to collect coverage from Workers. If something like this would be implemented I think we should also look into hooking into |
This is fantastic progress, thank you. Although this seems like the proper way to approach this problem, wouldn't be easier if we force worker to run in main thread? Like what What exactly blocks us from doing that? We get a syntax error when we try to use it but if that gets resolved, it should just work right? See this new branch on my demo repo |
This package is not trying to run web workers in the same thread, it's a side effect of trying to bring Web Worker API to Node.js. Since web workers are already supported in the browser, this package is not needed there. The proper way would be to communicate with the worker, although I am not sure it's a good idea to send messages to user workers which would trigger user land event listeners. Maybe something like BroadcastChannel API is better suited. We can inject it by checking for |
Will this be implemented or is it in the backlog? Just asking to set my expectations. Thank you |
At the moment this is not being worked on. I cannot give any time estimates right now but at some point we should try to implement this. This won't be easy task so I would imagine some kind of proof-of-concept work to be needed first. Supporting browser's Workers would be a good first step before looking into |
Got it, thank you for the clarification. |
Hi @AriPerkkio, I'm really invested in this idea and would like to help bring Worker coverage support for both browser and Node. If nobody is working on this atm I can try to propose a PR. For that though, I might need some pointers. Are you open to discussing this feature? |
I'm not yet sure how exactly the implementation would go. I would need to do some proof-of-concept work before to see the bigger picture. But basically the idea would be:
I think main thread should also know how many Workers it should be waiting for in |
Let me know if I can be any help. I'll have some time soon, I can work on it. |
Also a quick note, it's not related to this issue but if we were to attach |
I also ran into the same issue. Here I tried to implement something like |
Now that we have V8 coverage for browser mode, I would have expected worker's coverage to be automatically collected from there. I'm not sure if it's even possible to control worker via CDP when it's created inside browser and not with playwright. 🤔 |
This looks like a relevant issue on playwright side (which is unfortunately closed as out of scope 😢) They sound like it's technically possible by manually creating cdp session with FWIW, Vitest can technically inject any code on worker entry using |
Describe the bug
I'm trying to get test coverage output with istanbul but I've found out vitest can't see codes executed in web workers (per #2911). So I figured I could wrap my worker with
@vitest/web-worker
and execute it in main thread. However, since that worker executes WebAssembly I want to keep using browser environment.Now, in theory I don't see any problem with this approach but I'm getting a dynamic import error.
This could be just a configuration error on my side, maybe there is a way to bundle this worker wrapper in browser environment but that didn't shine any ideas to my mind.
Reproduction
If the problem is not obvious I'll create a reproduction project
System Info
Used Package Manager
npm
Validations
The text was updated successfully, but these errors were encountered: