Support asynchronous tests (#600)

* Tweak the implementation of heap closures

This commit updates the implementation of the `Closure` type to internally store
an `Rc` and be suitable for dropping a `Closure` during the execution of the
closure. This is currently needed for promises but may be generally useful as
well!

* Support asynchronous tests

This commit adds support for executing tests asynchronously. This is modeled
by tests returning a `Future` instead of simply executing inline, and is
signified with `#[wasm_bindgen_test(async)]`.

Support for this is added through a new `wasm-bindgen-futures` crate which is a
binding between the `futures` crate and JS `Promise` objects.

Lots more details can be found in the details of the commit, but one of the end
results is that the `web-sys` tests are now entirely contained in the same test
suite and don't need `npm install` to be run to execute them!

* Review tweaks

* Add some bindings for `Function.call` to `js_sys`

Name them `call0`, `call1`, `call2`, ... for the number of arguments being
passed.

* Use oneshots channels with `JsFuture`

It did indeed clean up the implementation!
This commit is contained in:
Alex Crichton
2018-08-01 15:52:24 -05:00
committed by GitHub
parent 4181afea45
commit eee71de0ce
34 changed files with 1167 additions and 333 deletions

View File

@ -20,17 +20,18 @@
}
};
console.log = function() {
if (window.global_cx)
window.global_cx.console_log(orig_console_log, arguments);
if (window.console_log_redirect)
window.console_log_redirect(orig_console_log, arguments);
else
orig_console_log.apply(this, arguments);
};
console.error = function() {
if (window.global_cx)
window.global_cx.console_error(orig_console_error, arguments);
if (window.console_error_redirect)
window.console_error_redirect(orig_console_error, arguments);
else
orig_console_error.apply(this, arguments);
};
window.__wbg_test_invoke = f => f();
</script>
<script src='run.js' type=module></script>
</body>

View File

@ -8,17 +8,19 @@
const orig_console_log = console.log;
const orig_console_error = console.error;
console.log = function() {
if (window.global_cx)
window.global_cx.console_log(orig_console_log, arguments);
if (window.console_log_redirect)
window.console_log_redirect(orig_console_log, arguments);
else
orig_console_log.apply(this, arguments);
};
console.error = function() {
if (window.global_cx)
window.global_cx.console_error(orig_console_error, arguments);
if (window.console_error_redirect)
window.console_error_redirect(orig_console_error, arguments);
else
orig_console_error.apply(this, arguments);
};
window.__wbg_test_invoke = f => f();
</script>
<script src='run.js' type=module></script>
</body>

View File

@ -12,33 +12,38 @@ pub fn execute(module: &str, tmpdir: &Path, args: &[OsString], tests: &[String])
let mut js_to_execute = format!(r#"
const {{ exit }} = require('process');
let cx = null;
let console_log_redirect = null;
let console_error_redirect = null;
// override `console.log` and `console.error` before we import tests to
// ensure they're bound correctly in wasm. This'll allow us to intercept
// all these calls and capture the output of tests
const prev_log = console.log;
console.log = function() {{
if (cx === null) {{
if (console_log_redirect === null) {{
prev_log.apply(null, arguments);
}} else {{
cx.console_log(prev_log, arguments);
console_log_redirect(prev_log, arguments);
}}
}};
const prev_error = console.error;
console.error = function() {{
if (cx === null) {{
if (console_error_redirect === null) {{
prev_error.apply(null, arguments);
}} else {{
cx.console_error(prev_error, arguments);
console_error_redirect(prev_error, arguments);
}}
}};
function main(tests) {{
global.__wbg_test_invoke = f => f();
async function main(tests) {{
const support = require("./{0}");
const wasm = require("./{0}_bg");
cx = new support.Context();
console_log_redirect = support.__wbgtest_console_log;
console_error_redirect = support.__wbgtest_console_error;
// Forward runtime arguments. These arguments are also arguments to the
// `wasm-bindgen-test-runner` which forwards them to node which we
@ -46,7 +51,8 @@ pub fn execute(module: &str, tmpdir: &Path, args: &[OsString], tests: &[String])
// filters for now.
cx.args(process.argv.slice(2));
if (!cx.run(tests.map(n => wasm[n])))
const ok = await cx.run(tests.map(n => wasm[n]));
if (!ok)
exit(1);
}}
@ -64,6 +70,10 @@ pub fn execute(module: &str, tmpdir: &Path, args: &[OsString], tests: &[String])
// And as a final addendum, exit with a nonzero code if any tests fail.
js_to_execute.push_str("
main(tests)
.catch(e => {
console.error(e);
exit(1);
});
");
let js_path = tmpdir.join("run.js");

View File

@ -16,7 +16,7 @@ pub fn spawn(
tests: &[String],
) -> Result<Server<impl Fn(&Request) -> Response + Send + Sync>, Error> {
let mut js_to_execute = format!(r#"
import {{ Context }} from './{0}';
import {{ Context, __wbgtest_console_log, __wbgtest_console_error }} from './{0}';
import * as wasm from './{0}_bg';
// Now that we've gotten to the point where JS is executing, update our
@ -30,7 +30,8 @@ pub fn spawn(
await wasm.booted;
const cx = Context.new();
window.global_cx = cx;
window.console_log_redirect = __wbgtest_console_log;
window.console_error_redirect = __wbgtest_console_error;
// Forward runtime arguments. These arguments are also arguments to the
// `wasm-bindgen-test-runner` which forwards them to node which we
@ -38,7 +39,7 @@ pub fn spawn(
// filters for now.
cx.args({1:?});
cx.run(test.map(s => wasm[s]));
await cx.run(test.map(s => wasm[s]));
}}
const tests = [];