lowlight
lowlight9mo ago

Deno.test without Deno namespace ?

Hi there, Does someone know if it's possible to run a test from Deno.test without the Deno namespace ? I tried using a workaround by using Web workers and performing a delete self.Deno which does work but... stumbled upon this issue https://github.com/denoland/deno/issues/13206 . So while I can perform my tests, now I can't get the code coverage since web workers don't collect it. I'd like to avoid deleting Deno from the main realm since I assume it'd eventually give me some weird behavior My use-case is to test some functions that behave differently depending on the runtime (like for example whether ˋglobalThis.Deno` is defined or not)
GitHub
Code coverage is not collected from Worker context(s) · Issue #13...
$ deno --version deno 1.17.0 (release, x86_64-unknown-linux-gnu) v8 9.7.106.15 typescript 4.5.2 It seems code coverage is not collected for scripts from the worker contexts (neither from the worker...
6 Replies
Deno AI Helper
Deno AI Helper9mo ago
Based on the documentation, the Deno namespace is now available in workers by default. This means that you can use Deno namespace APIs in your web workers by default, provided the required permissions are set. However, the documentation does not provide a way to run Deno.test without the Deno namespace. It seems that the Deno namespace is integral to the functioning of Deno.test. As for your use-case, if you want to test functions that behave differently depending on the runtime, you might need to structure your tests to account for the presence of the Deno namespace. For example, you could have separate tests or separate test files for the Deno environment and other environments. Remember that manipulating the Deno namespace or the global environment can lead to unexpected behavior, as you've noted. It's generally best to write your tests in a way that they can run successfully in the intended environment without needing to alter the global environment. Please note that this advice is not explicitly stated in the documentation, but is a general recommendation based on the information provided.
Kofi GOLO
Kofi GOLO9mo ago
The best would be to actually not get rid of the Deno namespace. Just test if Deno is there and if not, it’s probably something else. Best to establish a way to identify the JavaScript runtime (Node, Deno, or Bun) then do what you have to do. 1. You know that if globalThis.Deno, it’s Deno. You can also use navigator.userAgent.split("/")[0] === "Deno" 2. You know that if globalThis.process.release.name === 'node', it’s probably node. 3. For bun navigator.userAgent.split("/")[0] === "Bun"
let runtime = null;
if (globalThis.Deno) {
runtime = 'deno'
} else if (globalThis?.navigator?.userAgent.split("/")[0] === 'Bun') { // must be before the node test because process?.release?.name also === 'node' in bun
runtime = 'bun'
} else if (process?.release?.name === 'node') {
runtime = 'node'
} else {
throw new Error('Unable to identify the JavaScript Runtime')
}
console.log(runtime);
let runtime = null;
if (globalThis.Deno) {
runtime = 'deno'
} else if (globalThis?.navigator?.userAgent.split("/")[0] === 'Bun') { // must be before the node test because process?.release?.name also === 'node' in bun
runtime = 'bun'
} else if (process?.release?.name === 'node') {
runtime = 'node'
} else {
throw new Error('Unable to identify the JavaScript Runtime')
}
console.log(runtime);
Could be done in a switch statement too I guess… unfortunately there’s no match statement in JavaScript at the moment 🥲
Kofi GOLO
Kofi GOLO9mo ago
Yes it works
No description
lowlight
lowlight9mo ago
I got this part right, but my question was more oriented towards testing and coverage Like in your example, how would you use Deno.test to pass into the "non-deno" branch ? I'd like to avoid using something this (unless it's the only way):
const {Deno:_Deno} = globalThis
Deno.test("deno", () => { func() })
Deno.test("non-deno", () => { delete globalThis.Deno; func(); globalThis.Deno = _Deno })
const {Deno:_Deno} = globalThis
Deno.test("deno", () => { func() })
Deno.test("non-deno", () => { delete globalThis.Deno; func(); globalThis.Deno = _Deno })
Currently I use something like this so it doesn't affect the global env as workers are kind of sepearate thread, but because of the bug mentionned, the code executed within workers is not covered
Deno.test("deno", () => { func() })
Deno.test("non-deno", async () => {
const script = `delete self.Deno; self.postMessage((${func.toString()})()); self.close`
const worker = new Worker(`data:text/javascript;base64,${btoa(script)}`, {type:"module"})
const promise = deferred()
worker.addEventListener("message", ({data}) => promise.resolve(data))
await promise
})
Deno.test("deno", () => { func() })
Deno.test("non-deno", async () => {
const script = `delete self.Deno; self.postMessage((${func.toString()})()); self.close`
const worker = new Worker(`data:text/javascript;base64,${btoa(script)}`, {type:"module"})
const promise = deferred()
worker.addEventListener("message", ({data}) => promise.resolve(data))
await promise
})
But basically I'm looking for something like this (but even in the web worker this option was removed as deno is always available so I assume it's not possible to do it anymore)
Deno.test("non-deno", {deno:{namespace:false}}, () => { func()})
Deno.test("non-deno", {deno:{namespace:false}}, () => { func()})
Kofi GOLO
Kofi GOLO9mo ago
But why do you want du delete it? Just don’t use it. Design pattern Strategy is what you need. According to the value of the runtime variable you will execute the code you need. Also I don’t think you should test Bun code in Deno tests if you use Bun APIs. But yes you might have the ability to test everything if you code is Node compatible as Bun and Deno are drop-in replacements for Node. So just import your code, with dynamic imports: const yourModule = await import('your-module.ts') Then do some tests like assertions. There’s no point of deleting Deno namespace. You will have zero benefits. What you want to do is test YOUR CODE. Or, even better if you use Deno and Bun APIs, your source folder should look like this:
- src/common #reusable native JS code that can be used in other libraries your write in your code leveraging bun or deno
- src/bun # when your code uses bun APIs
- src/deno # when your code uses Deno APIs
- tests/common # when your tests cover code that leverage native JS
- tests/bun # when your tests cover code that leverage bun APIs
- tests/deno # when your tests cover code that leverage Deno APIs
- src/common #reusable native JS code that can be used in other libraries your write in your code leveraging bun or deno
- src/bun # when your code uses bun APIs
- src/deno # when your code uses Deno APIs
- tests/common # when your tests cover code that leverage native JS
- tests/bun # when your tests cover code that leverage bun APIs
- tests/deno # when your tests cover code that leverage Deno APIs
And you might need to use at least 2 runtimes: Deno and Bun. And they can each tests there own code, and Node code In your deno.json, you would have to either include common and Deno tests, or exclude the bun tests
{
"test": {
"include": [
"tests/common/",
"tests/deno/"
]
}
}
// or
{
"test": {
"exclude": ["tests/bun/"]
}
}
{
"test": {
"include": [
"tests/common/",
"tests/deno/"
]
}
}
// or
{
"test": {
"exclude": ["tests/bun/"]
}
}
Or use directly in command line : deno test tests/common/ tests/deno Then for the code you use in your Workers, don’t put it directly inside your Workers. Put them in their own files, that you will import in your Workers files. That way, you will have the ability to tests the code without worrying about it if Deno Tests don’t cover what happens in Workers. Try that <:hooray_deno:1035517542200004688> P.S.: dynamic imports work for Deno, but not for Node. That’s what I saw in MDN, Mozilla Developer Network. For Bun I don’t know.
lowlight
lowlight9mo ago
Yeah finally I went with just not testing other environments in Deno. It makes more sense like you said and seems more clean indeed. It just that the ocd was triggered by the red lines shown in deno coverage Just to clarify, the workers weren't really part of the code, it was just a workaround for creating a "Realm" since ShadowRealms are not yet supported. Removing deno namespace from them was mostly to "simulate" a browser environment. Thanks for taking the time to answer and for your thoughtful explanation