workerd icon indicating copy to clipboard operation
workerd copied to clipboard

[feature request] script eval

Open panva opened this issue 3 years ago • 5 comments

I would like a simple way to have workerd evaluate a script input. The runtime globals would be present. No need to register an event listener.

Having this capability would make it so much easier to test universal js libraries for this runtime.

panva avatar Sep 29 '22 11:09 panva

Additionally, being able to programmatically set the process exit code would be great.

panva avatar Sep 29 '22 13:09 panva

Hmm, it sounds like what you really want is some sort of test harness?

"Just eval this script" doesn't necessarily make sense in workerd. Normally, Workers are not permitted to do I/O at the global scope. We have this restriction because we want to reserve the right to make clever use of snapshots in the future -- so when you deploy a worker on Cloudflare, we might snapshot it immediately after evaluating the global scope, and distribute the snapshot, rather than evaluate the global scope on every machine. This wouldn't work if the global scope could have side effects, so we disable I/O, and Date.now() always returns zero.

But I've long felt that we should have some way to write unit tests, where you register test functions, and those are called in an I/O context. We should support running these not just with workerd but also uploading to Cloudflare and running them on the edge. It could even be cool to let people write tests that Cloudflare itself could then run to validate new versions of the runtime before we deploy them. Also, perhaps this would be a good way to write new tests for workerd itself (which are sorely missing right now, since our test suite is too dependent on our internal code...).

kentonv avatar Sep 30 '22 01:09 kentonv

Correct, I would like to be able to test a universal js library. That means importing a test harness, e.g. QUnit, defining a test suite and letting it run to completion (event loop being empty?, or exiting programatically with an exit code) and capturing stdout.

panva avatar Sep 30 '22 07:09 panva

@panva, if this was structured something like the following would it work for you? Using the worker ESM syntax only:

export default {
  async fetch(req, env) {
    return new Response("Hello World\n");
  },

  // Unit test is exported on the default alongside the fetch export
  async test(context, env) {
    // Requests against the fetch handler as if it were a regular incoming request...
    const resp = await context.fetch('...');
    // assertions and checks here...
  },
};

With, of course, the ability to properly capture console log output as we are discussing in the other issue.

There would be some interesting details to work out with this approach if both the test and the fetch it is testing are running in the same process with the same worker and same isolate (easily both a good and bad thing depending on what you're wanting to test) but wanted to at least start with something concrete we can kick around.

jasnell avatar Oct 03 '22 05:10 jasnell

I think it'd be best if you hid this boilerplate from the developers.

In the simplest scenario we really just need to pass a file to the workerd binary and have it spit out console logs. Anything more than that and you'll likely be passing on the opportunity to have your platform easily a part of libraries' test pipelines.

panva avatar Oct 03 '22 06:10 panva

This was sorta resolved with the introduction workerd test

panva avatar Jan 09 '24 16:01 panva