Skip to content

Add real wasm32 smoke tests and CI job#109

Merged
gordonwoodhull merged 5 commits into
mainfrom
feature/wasm-testing-and-cleanup
Jul 2, 2026
Merged

Add real wasm32 smoke tests and CI job#109
gordonwoodhull merged 5 commits into
mainfrom
feature/wasm-testing-and-cleanup

Conversation

@cderv

@cderv cderv commented Apr 9, 2026

Copy link
Copy Markdown
Member

Replace the lost cfg proxy coverage (removed in #116) with 6 real WASM smoke tests
in crates/pampa/tests/wasm_lua.rs that compile and run on wasm32-unknown-unknown:

  • Restricted Lua VM creation (Lua::new_with())
  • Filter execution through the WASM code path (VFS + synthetic io/os)
  • Shortcode engine initialization
  • Error handling (validates panic_unwind works)
  • Synthetic io and os module registration

These run in a new wasm-tests CI job (Linux, nightly + Clang).

Infrastructure

  • crates/wasm-c-shim/ — shared C stdlib shim crate for wasm32 (no libc on wasm32,
    C deps like tree-sitter and Lua need malloc, fprintf, etc. at link time)
  • .cargo/config.toml — wasm-bindgen-test runner config
  • Gate proptest, insta, tempfile, tokio dev-deps on not(wasm32) to avoid
    pulling getrandom 0.3.4 which doesn't compile for wasm32
  • Gate pampa [[bin]] targets via required-features to prevent compilation during
    WASM test runs (Add an option to skip building binaries when there are integration tests rust-lang/cargo#12980)
  • Use RUSTUP_TOOLCHAIN=nightly in CI to bypass rust-toolchain.toml sysroot conflict
    with -Zbuild-std

Known blocker

The wasm-tests CI job currently fails because quarto-system-runtime/src/wasm.rs
has 4 raw_module extern blocks (/src/wasm-js-bridge/{template,sass,cache,fetch}.js)
that get baked into any wasm32 binary. wasm-bindgen-test-runner generates require()
calls for these absolute paths, which fail in Node.js.

Recommended fix: feature-gate the JS bridge in quarto-system-runtime — add a
js-bridge feature, gate the 4 extern blocks, provide stubs when off.
wasm-quarto-hub-client enables js-bridge; pampa test builds don't.

Depends on #116.

@cderv cderv force-pushed the feature/wasm-testing-and-cleanup branch 2 times, most recently from 52923e7 to 60df573 Compare April 9, 2026 13:34
@cderv cderv force-pushed the feature/wasm-testing-and-cleanup branch from 8c6bfe2 to 89d90e0 Compare April 9, 2026 15:46
@cderv cderv changed the base branch from main to fix/wasm-cfg-proxy-and-cleanup April 14, 2026 12:30
@cderv cderv changed the title Clean up WASM testing: remove dead crate, fix cfg proxy, add real wasm32 tests Add real wasm32 smoke tests and CI job Apr 14, 2026
@cderv cderv force-pushed the feature/wasm-testing-and-cleanup branch from 267f27a to ba0ec15 Compare April 14, 2026 14:21
@cderv cderv force-pushed the fix/wasm-cfg-proxy-and-cleanup branch from 6009f60 to 2db6f1e Compare April 16, 2026 12:58
Base automatically changed from fix/wasm-cfg-proxy-and-cleanup to main April 16, 2026 15:45
gordonwoodhull added a commit that referenced this pull request Apr 18, 2026
The four `raw_module` extern blocks in quarto-system-runtime/src/wasm.rs
import absolute paths (/src/wasm-js-bridge/{template,sass,cache,fetch}.js)
that hub-client serves through Vite at runtime. wasm-bindgen generates
unconditional `require()` calls for these paths in the shim it produces,
so any wasm32 binary that links quarto-system-runtime — including the
new pampa wasm_lua tests — fails to load under Node.js with
`MODULE_NOT_FOUND` before any test body runs.

Add a `js-bridge` Cargo feature, default off. Gate the four extern blocks
behind it, and provide stubs that return `Err("js-bridge feature not
enabled")` / `false` when off so the SystemRuntime impl still compiles.
wasm-quarto-hub-client opts in via `features = ["js-bridge"]`; pampa's
wasm test build does not, so the require()s disappear from the shim.

Native builds are unaffected (wasm.rs is `#![cfg(target_arch = "wasm32")]`).

This clears the blocker documented in PR #109. A separate downstream
issue is now visible: rust_lua_throw panics propagate as wasm
RuntimeError instead of being caught by rust_lua_protected_call, so the
6 wasm tests still fail. That looks like a panic-strategy problem in
wasm-c-shim, unrelated to the JS bridge fix.
@gordonwoodhull

gordonwoodhull commented Apr 20, 2026

Copy link
Copy Markdown
Member

@cderv, thanks for writing these tests!

I was trying to understand why these paths weren't tested, and either misunderstood or miscommunicated this to Claude, testing them the wrong way! This was the mistake you fixed in

I've fixed the remaining issues with this PR and it runs clean here:
https://github.com/quarto-dev/q2/actions/runs/24612984662

I also rebased onto latest main. May I force push, or do you have other work on this branch?

@cderv

cderv commented Apr 21, 2026

Copy link
Copy Markdown
Member Author

Oh thanks for chiming in ! I was going to continue with this this week. It needed to be rebased on main and it is also related to work I started in #125

My aim was that we have some wasm build test, but I was sorting out quarto-hub build from other wasm build.

interested to see your change !

Yes you can force push here. And maybe we can discuss quickly all this together if you have time today.

@gordonwoodhull gordonwoodhull force-pushed the feature/wasm-testing-and-cleanup branch from ba0ec15 to 901f9f7 Compare April 21, 2026 11:58
@gordonwoodhull

gordonwoodhull commented Apr 21, 2026

Copy link
Copy Markdown
Member

Thanks! I've pushed. It's really just

  • the feature-gate fix you suggested above
  • build flags enabling the same error handling / panic strategy for wasm32-unknown-unknown tests as used for the lua-wasm build in wasm-quarto-hub-client
  • merge/rebase conflict resolution
  • docs

(I'm going for a hike today since I stupidly worked over the weekend, glad to discuss later in the week.)

cderv and others added 4 commits July 1, 2026 21:02
Design spec (claude-notes/designs/2026-04-03-wasm-testing-and-cleanup.md)
and plan (claude-notes/plans/2026-04-07-wasm-testing-and-cleanup.md) for
replacing the lost cfg-proxy coverage (removed in #116) with real wasm32
smoke tests. Incorporates design-review findings: wasm-bindgen-cli
version pinning via cargo xtask dev-setup, the C toolchain prerequisite,
and Linux-CI-only scope (skipped on Windows).
Add 6 smoke tests in crates/pampa/tests/wasm_lua.rs that compile and run
on wasm32-unknown-unknown:

- Restricted Lua VM creation (Lua::new_with())
- Filter execution through the WASM code path (VFS + synthetic io/os)
- Shortcode engine initialization
- Error handling (validates panic_unwind works)
- Synthetic io and os module registration

They run in a new wasm-tests CI job (Linux, Clang), and locally on
Linux/macOS — see dev-docs/wasm.md.

Build infrastructure, including findings from the CI bring-up:

- .cargo/config.toml: wasm-bindgen-test-runner for the wasm32 target
- Gate proptest, insta, tempfile, tokio dev-deps on not(wasm32) — they
  pull in getrandom, which does not compile for wasm32
- Gate pampa [[bin]] targets via required-features so cargo skips them
  during WASM test runs (rust-lang/cargo#12980)
- Absolute -isystem paths for the wasm sysroot; -fno-builtin
- Docs: dev-docs/wasm.md, .claude/rules/wasm.md, pampa CLAUDE.md,
  claude-notes/instructions/testing.md
Move the ~980-line c_shim.rs from wasm-quarto-hub-client into a new
wasm-c-shim crate. This provides #[no_mangle] C stdlib stubs (malloc,
fprintf, snprintf, abort, etc.) needed by tree-sitter and Lua when
compiled for wasm32-unknown-unknown, which has no libc.

The crate is a no-op on native targets (all exports gated on wasm32).
Both wasm-quarto-hub-client (production) and pampa WASM tests now
depend on wasm-c-shim for the shared symbols.
…rategy

The raw_module extern blocks in quarto-system-runtime/src/wasm.rs import
absolute paths (/src/wasm-js-bridge/*.js) that hub-client serves through
Vite at runtime. wasm-bindgen generates unconditional require() calls
for these paths in the shim it produces, so any wasm32 binary that links
quarto-system-runtime — including the pampa wasm_lua tests — fails to
load under Node.js with MODULE_NOT_FOUND before any test body runs.

Add a js-bridge Cargo feature, default off. Gate the extern blocks
behind it, and provide stubs that return Err("js-bridge feature not
enabled") / false when off so the SystemRuntime impl still compiles.
wasm-quarto-hub-client opts in via features = ["js-bridge"]; pampa's
wasm test build does not, so the require()s disappear from the shim.
Native builds are unaffected (wasm.rs is #![cfg(target_arch = "wasm32")]).

That exposed a downstream panic-strategy problem: rust_lua_throw panics
propagated as wasm RuntimeError instead of being caught by
rust_lua_protected_call. Fix by mirroring wasm-quarto-hub-client's
rustflags (-C panic=unwind, +bulk-memory,+exception-handling,
-Zwasm-c-abi=spec) in the workspace-root .cargo/config.toml for wasm32
builds, and moving the LuaThrow marker type into wasm-c-shim so the
production build and the tests share it. Update design/plan docs and
dev-docs/wasm.md accordingly.
@gordonwoodhull gordonwoodhull force-pushed the feature/wasm-testing-and-cleanup branch from 901f9f7 to b816828 Compare July 2, 2026 01:04
@posit-snyk-bot

posit-snyk-bot commented Jul 2, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

…lchain

This branch predates the 2026-04-20 wasm-shim-merge work and the bd-at72
toolchain pin; rebasing onto current main needed alignment beyond
conflict resolution:

- wasm-c-shim: the rebase carried main's evolved c_shim.rs content into
  shim.rs via rename detection; declare the wasm-printf-fmt dependency
  it uses for snprintf/vsnprintf.
- Root Cargo.toml: patch tree-sitter-language to the local wasm-shim
  fork (same patch wasm-quarto-hub-client uses) so tree-sitter core does
  not compile upstream's wasm32 stdio/stdlib/string stubs, which collide
  with wasm-c-shim at link time. The fork has byte-identical Rust source
  and a no-op build.rs on native targets.
- wasm-tests CI: run on the pinned toolchain from rust-toolchain.toml
  (now a nightly with rust-src and the wasm32 target) instead of
  RUSTUP_TOOLCHAIN=nightly — bd-at72 pinned the toolchain because later
  nightlies SIGSEGV in LLVM ThinLTO on wasm32 builds of this workspace.
  The E0152 duplicate-lang-item conflict the override worked around no
  longer reproduces on the pinned toolchain.
- wasm_lua.rs: SourceInfo::for_test() (SourceInfo::default() is
  deprecated under -D deprecated), and pass the new attribution
  argument (None) to apply_lua_filters.
- Regenerate Cargo.lock and crates/wasm-quarto-hub-client/Cargo.lock.

Verified: cargo build + nextest workspace green (9862 passed); all 6
wasm tests pass under wasm-bindgen-test-runner (macOS, Homebrew LLVM
clang, pinned nightly); production build-wasm.js succeeds.
@gordonwoodhull gordonwoodhull force-pushed the feature/wasm-testing-and-cleanup branch from b816828 to bf370a0 Compare July 2, 2026 01:16
@gordonwoodhull gordonwoodhull marked this pull request as ready for review July 2, 2026 01:20
@gordonwoodhull

Copy link
Copy Markdown
Member

I dropped the unrelated stuff from

and squashed this. I'll go ahead and merge it now.

Thanks @cderv!

@gordonwoodhull gordonwoodhull merged commit e26a8b8 into main Jul 2, 2026
8 checks passed
@gordonwoodhull gordonwoodhull deleted the feature/wasm-testing-and-cleanup branch July 2, 2026 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants