Skip to content

Commit 54034a5

Browse files
authored
Add --list, --ignored and --exact to wasm-bindgen-test-runner (#4356)
1 parent dfb9d92 commit 54034a5

File tree

10 files changed

+158
-46
lines changed

10 files changed

+158
-46
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
* Support importing memory and using `wasm_bindgen::module()` in Node.js.
1515
[#4349](https://github.com/rustwasm/wasm-bindgen/pull/4349)
1616

17+
* Add `--list`, `--ignored`, `--exact` and `--nocapture` to `wasm-bindgen-test-runner`, analogous to `cargo test`.
18+
[#4356](https://github.com/rustwasm/wasm-bindgen/pull/4356)
19+
1720
### Changed
1821

1922
* Optional parameters are now typed as `T | undefined | null` to reflect the actual JS behavior.
@@ -34,6 +37,9 @@
3437
* Remove `WASM_BINDGEN_THREADS_MAX_MEMORY` and `WASM_BINDGEN_THREADS_STACK_SIZE`. The maximum memory size can be set via `-Clink-arg=--max-memory=<size>`. The stack size of a thread can be set when initializing the thread via the `default` function.
3538
[#4363](https://github.com/rustwasm/wasm-bindgen/pull/4363)
3639

40+
* `console.*()` calls in tests are now always intercepted by default. To show them use `--nocapture`. When shown they are always printed in-place instead of after test results, analogous to `cargo test`.
41+
[#4356](https://github.com/rustwasm/wasm-bindgen/pull/4356)
42+
3743
### Fixed
3844

3945
- Fixed using [JavaScript keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords) as identifiers not being handled correctly.

crates/cli/src/bin/wasm-bindgen-test-runner/deno.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub fn execute(module: &str, tmpdir: &Path, cli: Cli, tests: &[String]) -> Resul
1313
let mut js_to_execute = format!(
1414
r#"import * as wasm from "./{module}.js";
1515
16+
const nocapture = {nocapture};
1617
{console_override}
1718
1819
window.__wbg_test_invoke = f => f();
@@ -21,6 +22,7 @@ pub fn execute(module: &str, tmpdir: &Path, cli: Cli, tests: &[String]) -> Resul
2122
2223
const tests = [];
2324
"#,
25+
nocapture = cli.nocapture.clone(),
2426
console_override = SHARED_SETUP,
2527
args = cli.into_args(),
2628
);

crates/cli/src/bin/wasm-bindgen-test-runner/headless.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,15 @@ pub fn run(
210210
println!("output div contained:\n{}", tab(&output));
211211
}
212212
}
213-
if !logs.is_empty() {
214-
println!("console.log div contained:\n{}", tab(&logs));
215-
}
216-
if !errors.is_empty() {
217-
println!("console.log div contained:\n{}", tab(&errors));
218-
}
219213

220214
if !output.contains("test result: ok") {
215+
if !logs.is_empty() {
216+
println!("console.log div contained:\n{}", tab(&logs));
217+
}
218+
if !errors.is_empty() {
219+
println!("console.log div contained:\n{}", tab(&errors));
220+
}
221+
221222
bail!("some tests failed")
222223
}
223224

crates/cli/src/bin/wasm-bindgen-test-runner/index-headless.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@
1818
}
1919
};
2020

21+
// {NOCAPTURE}
2122
const wrap = method => {
2223
const og = orig(`console_${method}`);
2324
const on_method = `on_console_${method}`;
2425
console[method] = function (...args) {
26+
if (nocapture) {
27+
orig("output").apply(this, args);
28+
}
2529
if (window[on_method]) {
2630
window[on_method](args);
2731
}

crates/cli/src/bin/wasm-bindgen-test-runner/main.rs

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
1414
use anyhow::{bail, Context};
1515
use clap::Parser;
16+
use clap::ValueEnum;
1617
use std::env;
1718
use std::fs;
1819
use std::path::Path;
@@ -34,14 +35,32 @@ struct Cli {
3435
help = "The file to test. `cargo test` passes this argument for you."
3536
)]
3637
file: PathBuf,
37-
#[arg(long = "include-ignored", help = "Run ignored tests")]
38+
#[arg(long, conflicts_with = "ignored", help = "Run ignored tests")]
3839
include_ignored: bool,
40+
#[arg(long, conflicts_with = "include_ignored", help = "Run ignored tests")]
41+
ignored: bool,
42+
#[arg(long, help = "Exactly match filters rather than by substring")]
43+
exact: bool,
3944
#[arg(
40-
long = "skip",
45+
long,
4146
value_name = "FILTER",
4247
help = "Skip tests whose names contain FILTER (this flag can be used multiple times)"
4348
)]
4449
skip: Vec<String>,
50+
#[arg(long, help = "List all tests and benchmarks")]
51+
list: bool,
52+
#[arg(
53+
long,
54+
help = "don't capture `console.*()` of each task, allow printing directly"
55+
)]
56+
nocapture: bool,
57+
#[arg(
58+
long,
59+
value_enum,
60+
value_name = "terse",
61+
help = "Configure formatting of output"
62+
)]
63+
format: Option<FormatSetting>,
4564
#[arg(
4665
index = 2,
4766
value_name = "FILTER",
@@ -54,6 +73,8 @@ struct Cli {
5473
impl Cli {
5574
fn into_args(self) -> String {
5675
let include_ignored = self.include_ignored;
76+
let ignored = self.ignored;
77+
let exact = self.exact;
5778
let skip = self.skip;
5879
let filter = if let Some(filter) = self.filter {
5980
&format!("\"{filter}\"")
@@ -65,6 +86,8 @@ impl Cli {
6586
r#"
6687
// Forward runtime arguments.
6788
cx.include_ignored({include_ignored:?});
89+
cx.ignored({ignored:?});
90+
cx.exact({exact:?});
6891
cx.skip({skip:?});
6992
cx.filter({filter});
7093
"#
@@ -85,10 +108,6 @@ fn main() -> anyhow::Result<()> {
85108
.map(Path::new)
86109
.context("file to test is not a valid file, can't extract file name")?;
87110

88-
let tmpdir = tempfile::tempdir()?;
89-
90-
let module = "wasm-bindgen-test";
91-
92111
// Collect all tests that the test harness is supposed to run. We assume
93112
// that any exported function with the prefix `__wbg_test` is a test we need
94113
// to execute.
@@ -98,12 +117,45 @@ fn main() -> anyhow::Result<()> {
98117
let mut tests = Vec::new();
99118

100119
for export in wasm.exports.iter() {
101-
if !export.name.starts_with("__wbgt_") {
102-
continue;
120+
if export.name.starts_with("__wbgt_") {
121+
tests.push(export.name.to_string());
103122
}
104-
tests.push(export.name.to_string());
105123
}
106124

125+
if cli.list {
126+
'outer: for test in tests {
127+
if !cli.ignored || test.starts_with("__wbgt_$") {
128+
if let Some(filter) = &cli.filter {
129+
let matches = if cli.exact {
130+
test == *filter
131+
} else {
132+
test.contains(filter)
133+
};
134+
135+
if !matches {
136+
continue;
137+
}
138+
}
139+
140+
for skip in &cli.skip {
141+
if test.contains(skip) {
142+
continue 'outer;
143+
}
144+
}
145+
146+
println!("{}: test", test.split_once("::").unwrap().1);
147+
}
148+
}
149+
150+
// Returning cleanly has the strange effect of outputting
151+
// an additional empty line with spaces in it.
152+
std::process::exit(0);
153+
}
154+
155+
let tmpdir = tempfile::tempdir()?;
156+
157+
let module = "wasm-bindgen-test";
158+
107159
// Right now there's a bug where if no tests are present then the
108160
// `wasm-bindgen-test` runtime support isn't linked in, so just bail out
109161
// early saying everything is ok.
@@ -348,3 +400,10 @@ fn coverage_args(file_name: &Path) -> PathBuf {
348400
None => PathBuf::from(generated(file_name, &prefix)),
349401
}
350402
}
403+
404+
/// Possible values for the `--format` option.
405+
#[derive(Debug, Clone, Copy, ValueEnum)]
406+
enum FormatSetting {
407+
/// Display one character per test
408+
Terse,
409+
}

crates/cli/src/bin/wasm-bindgen-test-runner/node.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ const wrap = method => {
1515
const og = console[method];
1616
const on_method = `on_console_${method}`;
1717
console[method] = function (...args) {
18-
og.apply(this, args);
18+
if (nocapture) {
19+
og.apply(this, args);
20+
}
1921
if (handlers[on_method]) {
2022
handlers[on_method](args);
2123
}
2224
};
2325
};
2426
27+
// save original `console.log`
28+
global.__wbgtest_og_console_log = console.log;
2529
// override `console.log` and `console.error` etc... before we import tests to
2630
// ensure they're bound correctly in wasm. This'll allow us to intercept
2731
// all these calls and capture the output of tests
@@ -53,6 +57,7 @@ pub fn execute(
5357
{fs};
5458
{wasm};
5559
60+
const nocapture = {nocapture};
5661
{console_override}
5762
5863
global.__wbg_test_invoke = f => f();
@@ -88,6 +93,7 @@ pub fn execute(
8893
r"import fs from 'node:fs/promises'".to_string()
8994
},
9095
coverage = coverage.display(),
96+
nocapture = cli.nocapture.clone(),
9197
console_override = SHARED_SETUP,
9298
args = cli.into_args(),
9399
);

crates/cli/src/bin/wasm-bindgen-test-runner/server.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub(crate) fn spawn(
7070
)
7171
};
7272

73+
let nocapture = cli.nocapture;
7374
let args = cli.into_args();
7475

7576
if test_mode.is_worker() {
@@ -102,9 +103,13 @@ pub(crate) fn spawn(
102103

103104
worker_script.push_str(&format!(
104105
r#"
106+
const nocapture = {nocapture};
105107
const wrap = method => {{
106108
const on_method = `on_console_${{method}}`;
107109
self.console[method] = function (...args) {{
110+
if (nocapture) {{
111+
self.__wbg_test_output_writeln(args);
112+
}}
108113
if (self[on_method]) {{
109114
self[on_method](args);
110115
}}
@@ -297,6 +302,7 @@ pub(crate) fn spawn(
297302
} else {
298303
include_str!("index.html")
299304
};
305+
let s = s.replace("// {NOCAPTURE}", &format!("const nocapture = {nocapture};"));
300306
let s = if !test_mode.is_worker() && test_mode.no_modules() {
301307
s.replace(
302308
"<!-- {IMPORT_SCRIPTS} -->",

crates/test-macro/src/lib.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
extern crate proc_macro;
55

66
use proc_macro2::*;
7-
use quote::format_ident;
87
use quote::quote;
98
use quote::quote_spanned;
10-
use std::sync::atomic::*;
11-
12-
static CNT: AtomicUsize = AtomicUsize::new(0);
139

1410
#[proc_macro_attribute]
1511
pub fn wasm_bindgen_test(
@@ -94,18 +90,16 @@ pub fn wasm_bindgen_test(
9490
quote! { cx.execute_sync(test_name, #ident, #should_panic_par, #ignore_par); }
9591
};
9692

97-
// We generate a `#[no_mangle]` with a known prefix so the test harness can
98-
// later slurp up all of these functions and pass them as arguments to the
99-
// main test harness. This is the entry point for all tests.
100-
let name = format_ident!("__wbgt_{}_{}", ident, CNT.fetch_add(1, Ordering::SeqCst));
93+
let ignore_name = if ignore.is_some() { "$" } else { "" };
94+
10195
let wasm_bindgen_path = attributes.wasm_bindgen_path;
10296
tokens.extend(
10397
quote! {
10498
const _: () = {
10599
#wasm_bindgen_path::__rt::wasm_bindgen::__wbindgen_coverage! {
106-
#[no_mangle]
100+
#[export_name = ::core::concat!("__wbgt_", #ignore_name, ::core::module_path!(), "::", ::core::stringify!(#ident))]
107101
#[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
108-
pub extern "C" fn #name(cx: &#wasm_bindgen_path::__rt::Context) {
102+
extern "C" fn __wbgt_test(cx: &#wasm_bindgen_path::__rt::Context) {
109103
let test_name = ::core::concat!(::core::module_path!(), "::", ::core::stringify!(#ident));
110104
#test_body
111105
}

0 commit comments

Comments
 (0)