deno icon indicating copy to clipboard operation
deno copied to clipboard

Proposal: import.meta.test gating pattern

Open guybedford opened this issue 4 years ago • 8 comments

I'm wondering if this might be a nice pattern for inline tests:

if (import.meta.test) {
  Deno.test("test", async function () {
    assert(fn(), 'value');
  });
}

Where the import.meta.test guard is automatically optimized out for bundling / runtime builds.

The above pattern would then integrate into deno test invocation as necessary.

guybedford avatar Oct 17 '20 13:10 guybedford

Oooh, I like that idea. I think with the new bundling that is being worked on, those would be elided quite easily.

kitsonk avatar Oct 18 '20 09:10 kitsonk

Great to hear. Note that the benefit of having this on import.meta is that per-module filtering can be applied to which tests run.

guybedford avatar Oct 19 '20 13:10 guybedford

Note that the benefit of having this on import.meta is that per-module filtering can be applied to which tests run.

Still not sure I understand why this belongs in import.meta. How does the value vary between modules?

nayeemrmn avatar Oct 29 '20 23:10 nayeemrmn

It is better than putting it in the Deno namespace, but any node that we can detect and elide. We will be moving to a Rust/swc emit for everything, and being able to co-locate runtime code with test code would really improve the ease of use of testing... So we would just elide the node from the emit with deno run and deno bundle but when we go with deno test we wouldn't drop it. So it is effectively spec compliant way of achieving something like #[cfg(test)] that we have in Rust.

Also, if we put the flag in the Deno namespace, then that module becomes potentially a lot less portable, where if it is import.meta.test then it should effectively just be a no-op.

So effectively people could write code like this:

export function myGreatFunction() {
  // ...
}

if (import.meta.test) {
  Deno.test("test my function", () => {
    // ...
  });
}

Which allows them to co-locate all the test code in the same module, have 0 "production" runtime load, be stripped for bundles, and still work unaltered (potentially) in a browser.

kitsonk avatar Oct 30 '20 00:10 kitsonk

Strongly against then. This is a flagrant misuse of import.meta as it isn't module-specific metadata and it's hard to see the point when import.meta.test is still not generally detectable.

If the end-feature is so important, statically analysable (and portable) directives are supposed to use code comments, as adopted by Deno in lots of other places. import.meta is completely random.

nayeemrmn avatar Oct 30 '20 00:10 nayeemrmn

I strongly agree with @nayeemrmn on this one, import.meta.test would depend on runtime "mode" and not concrete module which seems like a misuse of import.meta. Also I don't really see any gain from this pattern - it would complicate transpilation pipeline significantly as one would get different results depending on subcommand used (in addition to different tsconfig).

bartlomieju avatar Nov 18 '20 13:11 bartlomieju

I'm surprised Deno.test(...) even makes it into bundled builds. Would this issue even be a problem if Deno.test() statements were stripped out of deno bundle-bundles (optionally with cli flag)? Would that lead to other problems/am I missing something?

marcushultman avatar Dec 06 '20 13:12 marcushultman

I'm surprised Deno.test(...) even makes it into bundled builds. Would this issue even be a problem if Deno.test() statements were stripped out of deno bundle-bundles (optionally with cli flag)? Would that lead to other problems/am I missing something?

Not really, in theory there's no problem with that, but it might involve significant effort to achieve, eg. Deno.test could be aliased in user code to test - we'd need to involve scope analysis to make this work which would be a huge task.

bartlomieju avatar Aug 07 '21 22:08 bartlomieju

Is their a downside to just using if (Deno.test) { ... }

wrnrlr avatar Jul 18 '23 16:07 wrnrlr

Is their a downside to just using if (Deno.test) { ... }

Deno.test is always defined, even if not using deno test subcommand - in such case this function is a noop.

bartlomieju avatar Jul 18 '23 16:07 bartlomieju

Oh, what is the advised way to put tests in the same file as your code (ala rust), otherwise I think this suggestion or something like it is a good idea.

wrnrlr avatar Jul 19 '23 02:07 wrnrlr

You can put them directly in the file using Deno.test(). Unless you use deno test that code will be ignored and test cases never run.

bartlomieju avatar Jul 19 '23 09:07 bartlomieju