Skip to content

Commit fda4dc0

Browse files
committed
[deno] Print uncaptured errors to stderr, unless preventDefault() is called
This is useful when running test snippets. Update READMEs including to mention how to do that.
1 parent 5e6c151 commit fda4dc0

File tree

8 files changed

+135
-36
lines changed

8 files changed

+135
-36
lines changed

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ spirv = "0.3"
187187
static_assertions = "1.1"
188188
strum = { version = "0.27.1", default-features = false, features = ["derive"] }
189189
syn = "2.0.98"
190+
tempfile = "3"
190191
toml = "0.9.0"
191192
trybuild = "1"
192193
tracy-client = "0.18"

cts_runner/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ deno_webidl.workspace = true
2222
deno_webgpu.workspace = true
2323
tokio = { workspace = true, features = ["full"] }
2424
termcolor.workspace = true
25+
26+
[dev-dependencies]
27+
tempfile.workspace = true

cts_runner/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# cts_runner
2+
3+
This crate contains infrastructure for running the WebGPU conformance tests on
4+
Deno's `wgpu`-based implementation of WebGPU.
5+
6+
Instructions for running the tests via the CTS `xtask` are in the
7+
[top-level README](https://github.com/gfx-rs/wgpu/blob/trunk/README.md#webgpu-conformance-test-suite).
8+
The file [revision.txt](./revision.txt) specifies the version of the CTS that
9+
will be used by default.
10+
11+
`cts_runner` is somewhat misnamed at this point, in that it is useful for
12+
things other than just running the CTS:
13+
14+
- The [tests](./tests) directory contains a few directed tests for
15+
Deno's bindings to `wgpu`.
16+
- Standalone JavaScript snippets that use WebGPU can be run
17+
with a command like: `cargo run -p cts_runner -- test.js`.

cts_runner/tests/features.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

cts_runner/tests/integration.rs

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
// As of June 2025, these tests are not run in CI.
44

55
use std::{
6-
fmt::{self, Debug, Display},
6+
ffi::OsStr,
7+
io::Write,
78
path::PathBuf,
8-
process::Command,
9+
process::{Command, Output},
910
str,
1011
};
1112

13+
use tempfile::NamedTempFile;
14+
1215
pub fn target_dir() -> PathBuf {
1316
let current_exe = std::env::current_exe().unwrap();
1417
let target_dir = current_exe.parent().unwrap().parent().unwrap();
@@ -24,38 +27,83 @@ pub fn cts_runner_exe_path() -> PathBuf {
2427
p
2528
}
2629

27-
pub struct JsError;
30+
fn exec_cts_runner(script_file: impl AsRef<OsStr>) -> Output {
31+
Command::new(cts_runner_exe_path())
32+
.arg(script_file)
33+
.output()
34+
.unwrap()
35+
}
2836

29-
impl Display for JsError {
30-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31-
write!(f, "JavaScript test returned an error")
32-
}
37+
fn exec_js_file(script_file: impl AsRef<OsStr>) {
38+
let output = exec_cts_runner(script_file);
39+
println!("{}", str::from_utf8(&output.stdout).unwrap());
40+
eprintln!("{}", str::from_utf8(&output.stderr).unwrap());
41+
assert!(output.status.success());
3342
}
3443

35-
impl Debug for JsError {
36-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37-
write!(f, "{self}")
38-
}
44+
fn check_js_stderr(script: &str, expected: &str) {
45+
let mut tempfile = NamedTempFile::new().unwrap();
46+
tempfile.write_all(script.as_bytes()).unwrap();
47+
tempfile.flush().unwrap();
48+
let output = exec_cts_runner(tempfile.path());
49+
assert!(output.stdout.is_empty());
50+
assert_eq!(str::from_utf8(&output.stderr).unwrap(), expected);
51+
assert!(output.status.success());
3952
}
4053

41-
type JsResult = Result<(), JsError>;
54+
fn exec_js(script: &str) {
55+
check_js_stderr(script, "");
56+
}
4257

43-
fn exec_js_test(script: &str) -> JsResult {
44-
let output = Command::new(cts_runner_exe_path())
45-
.arg(script)
46-
.output()
47-
.unwrap();
48-
println!("{}", str::from_utf8(&output.stdout).unwrap());
49-
eprintln!("{}", str::from_utf8(&output.stderr).unwrap());
50-
output.status.success().then_some(()).ok_or(JsError)
58+
#[test]
59+
fn hello_compute_example() {
60+
exec_js_file("examples/hello-compute.js");
5161
}
5262

5363
#[test]
54-
fn hello_compute_example() -> JsResult {
55-
exec_js_test("examples/hello-compute.js")
64+
fn features() {
65+
exec_js(
66+
r#"
67+
const adapter = await navigator.gpu.requestAdapter();
68+
69+
if (adapter.features.has("mappable-primary-buffers")) {
70+
throw new TypeError("Adapter should not report support for wgpu native-only features");
71+
}
72+
"#,
73+
);
5674
}
5775

5876
#[test]
59-
fn features() -> JsResult {
60-
exec_js_test("tests/features.js")
77+
fn uncaptured_error() {
78+
for suppress in [false, true] {
79+
let (handler, expected_err) = if suppress {
80+
(
81+
"device.onuncapturederror = (event) => { event.preventDefault(); };",
82+
"",
83+
)
84+
} else {
85+
(
86+
"",
87+
"Uncaptured WebGPU error:
88+
Shader '' parsing error: the type of `val` is expected to be `u32`, but got `{AbstractFloat}`
89+
┌─ wgsl:1:7
90+
91+
1 │ const val: u32 = 1.1;
92+
│ ^^^ definition of `val`\n\n\n",
93+
)
94+
};
95+
let script = [
96+
r#"
97+
const code = `const val: u32 = 1.1;`;
98+
99+
const adapter = await navigator.gpu.requestAdapter();
100+
const device = await adapter.requestDevice();
101+
"#,
102+
handler,
103+
r#"device.createShaderModule({ code })"#,
104+
]
105+
.concat();
106+
107+
check_js_stderr(&script, expected_err);
108+
}
61109
}

deno_webgpu/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ a
1414
[wgpu trace](https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications#tracing-infrastructure)
1515
to the specified directory.
1616

17-
For testing this op crate will make use of the WebGPU conformance tests suite,
18-
running through our WPT runner. This will be used to validate implementation
19-
conformance.
20-
21-
GitHub CI doesn't run with GPUs, so testing relies on software like DX WARP &
22-
Vulkan lavapipe. Currently, only using DX WARP works, so tests are only run on
23-
Windows.
17+
This op crate is tested primarily by running the
18+
[WebGPU conformance test suite](https://github.com/gpuweb/cts) using `wgpu`'s
19+
[`cts_runner`](https://github.com/gfx-rs/wgpu/blob/trunk/README.md#webgpu-conformance-test-suite).
20+
`cts_runner` also has a few
21+
[directed tests](https://github.com/gfx-rs/wgpu/tree/trunk/cts_runner/tests)
22+
to fill in missing coverage.
23+
24+
GPU availability in GitHub CI is limited, so some configurations rely on
25+
software like DX WARP & Vulkan lavapipe.
2426

2527
## Links
2628

deno_webgpu/error.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,32 @@ impl DeviceErrorHandler {
144144
let obj = v8::Object::new(scope);
145145
let key = v8::String::new(scope, "error").unwrap();
146146
obj.set(scope, key.into(), error);
147+
let key = v8::String::new(scope, "cancelable").unwrap();
148+
let val = v8::Boolean::new(scope, true).into();
149+
obj.set(scope, key.into(), val);
147150

148151
let event = constructor
149152
.new_instance(scope, &[kind.into(), obj.into()])
150153
.unwrap();
151154

152155
let recv = v8::Local::new(scope, device);
153156
func.open(scope).call(scope, recv, &[event.into()]);
157+
158+
let default_prevented =
159+
v8::String::new(scope, "defaultPrevented").unwrap();
160+
if !event
161+
.get(scope, default_prevented.into())
162+
.unwrap()
163+
.boolean_value(scope)
164+
{
165+
let msg = err.to_string();
166+
let space = if msg.chars().next().is_some_and(char::is_whitespace) {
167+
""
168+
} else {
169+
" "
170+
};
171+
eprintln!("Uncaptured WebGPU error:{space}{msg}");
172+
}
154173
});
155174
}
156175
}

0 commit comments

Comments
 (0)