Start supporting in-browser testing

This commit starts to add support for in-browser testing with
`wasm-bindgen-test-runner`. The current idea here is that somehow it'll be
configured and it'll spawn a little HTTP server serving up files from the
filesystem. This has been tested in various ways but isn't hooked up just yet,
wanted to make sure this was somewhat standalone! Future support for actually
running these tests will be coming in later commits.
This commit is contained in:
Alex Crichton
2018-07-24 11:27:06 -07:00
parent 7e16690f10
commit 0770f830e7
5 changed files with 259 additions and 79 deletions

View File

@ -0,0 +1,100 @@
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::process::Command;
use failure::{ResultExt, Error};
pub fn execute(module: &str, tmpdir: &Path, args: &[OsString], tests: &[String])
-> Result<(), Error>
{
let mut js_to_execute = format!(r#"
const {{ exit }} = require('process');
let cx = 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) {{
prev_log.apply(null, arguments);
}} else {{
cx.console_log(prev_log, arguments);
}}
}};
const prev_error = console.error;
console.error = function() {{
if (cx === null) {{
prev_error.apply(null, arguments);
}} else {{
cx.console_error(prev_error, arguments);
}}
}};
function main(tests) {{
const support = require("./{0}");
const wasm = require("./{0}_bg");
// Hack for now to support 0 tests in a binary. This should be done
// better...
if (support.Context === undefined)
process.exit(0);
cx = new support.Context();
// Forward runtime arguments. These arguments are also arguments to the
// `wasm-bindgen-test-runner` which forwards them to node which we
// forward to the test harness. this is basically only used for test
// filters for now.
cx.args(process.argv.slice(2));
if (!cx.run(tests.map(n => wasm[n])))
exit(1);
}}
const tests = [];
"#,
module
);
// Note that we're collecting *JS objects* that represent the functions to
// execute, and then those objects are passed into wasm for it to execute
// when it sees fit.
for test in tests {
js_to_execute.push_str(&format!("tests.push('{}')\n", test));
}
// And as a final addendum, exit with a nonzero code if any tests fail.
js_to_execute.push_str("
main(tests)
");
let js_path = tmpdir.join("run.js");
fs::write(&js_path, js_to_execute)
.context("failed to write JS file")?;
let path = env::var("NODE_PATH").unwrap_or_default();
let mut path = env::split_paths(&path).collect::<Vec<_>>();
path.push(env::current_dir().unwrap());
exec(
Command::new("node")
.env("NODE_PATH", env::join_paths(&path).unwrap())
.arg(&js_path)
.args(args)
)
}
#[cfg(unix)]
fn exec(cmd: &mut Command) -> Result<(), Error> {
use std::os::unix::prelude::*;
Err(Error::from(cmd.exec()).context("failed to execute `node`").into())
}
#[cfg(windows)]
fn exec(cmd: &mut Command) -> Result<(), Error> {
let status = cmd.status()?;
process::exit(status.code().unwrap_or(3));
}