QuantEcon / QuantEcon/QuantEcon.py
WASM: add a WebAssembly/JupyterLite smoke-test job to CI
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.4k
- Forks
- 2.3k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 3
Description
[!NOTE]
Updated 2026-08-21. The seed is now onmainvia #938 (ci/wasm/environment.yml,ci/wasm/smoke_test.py, the Playwright harnessci/wasm/test_jupyterlite.py, and the native gate inci_wasm_smoke.yml), so the Approach below names it instead of "the config from #928", and a task list for the runner PR has been added. What that list corrects: the parked job (2026-08-19 comment) still needs triggers, the gini expectation in both suite files is inverted now that numba 0.67.0 build 1 serialisesparallel=True(patch 0010, emscripten-forge/recipes#6293), the two jitted-generator tests will hang without a real guard,test_simplex_gridfails on a warm cache (#944), andsmoke_test.pyis not yet shipped into the kernel. The original text is preserved in the edit history.
Part of #925 (Phase 3 — keep it working).
Goal
Browser support must not regress once established: add a wasm job to GitHub Actions that runs a smoke suite in the real browser stack.
Approach
- Seed: PR #938 (merged 2026-08-21) —
ci/wasm/environment.yml(xeus-python kernel env, emscripten-forge-4x + conda-forge channels), the sentinel-driven Playwright harnessci/wasm/test_jupyterlite.py, and the native gate jobnativein.github/workflows/ci_wasm_smoke.yml, which runsci/wasm/smoke_test.pyagainst repo source on every PR. The Emscripten runner job is parked in the 2026-08-19 comment below. - Execute in the xeus-python kernel via headless Chromium + Playwright (the route #938 chose).
pytester, emscripten-forge's pyjs-based recipe-test harness, remains the alternative only if quantecon is later packaged on emscripten-forge (#932). - pandas and pytest are both packaged for WASM, so meaningful portions of the real test suite can eventually run in-browser — start with the smoke list from #928 (
smoke_test.py) and grow from there. - Track the emscripten-forge numba/llvmlite versions in the job the way conda-forge versions are tracked today;
environment.ymlpins barenumba, so have the job log the resolved build (only 0.67.0 build 1 carries patch 0010, see task 2).
This job is also the natural watchpoint for upstreaming: the blog post signals intent to merge the WASM engine into Numba mainline, and once that ships, the patched-recipe caveats (the recipe now carries ten patches, e.g. the serial fallback for parallel=True added by patch 0010 and the ufunc caching disabled by patch 0007) may start dissolving. Until then the job tests the released conda-forge noarch quantecon, not repo source, so per-PR triggering is not useful long-term.
Tasks for the runner PR
- Add the parked
wasmjob with its own triggers. The snippet in the 2026-08-19 comment is a job block and has noon:;ci_wasm_smoke.yml'son:ispush/pull_requesttomain. Either addschedule+workflow_dispatchto that sharedon:block and guard the job withif: github.event_name != 'pull_request', or move it to its own workflow file — in which caseneeds: nativeno longer resolves (it only sees jobs in the same workflow) and must be dropped or replaced. Iterate underpull_requestfirst, as the 2026-08-19 comment describes, then flip. - Flip the gini expectation. numba 0.67.0 build 1 on emscripten-forge-4x (patch 0010, emscripten-forge/recipes#6293, merged 2026-08-18) demotes
@njit(parallel=True)to the serial pipeline, and the barenumbapin resolves to it.test_gini_coefficient'sxfail(IS_EMSCRIPTEN, strict=True)insmoke_test.pywould XPASS and fail;test_gini_fails_on_emscriptenintest_jupyterlite.pyasserts an error and would fail. Both become plain pass assertions (browser-unverified; inferred from the merged patch). PR #937's O(n log n) rewrite (#926) is a performance change on top of this, not a prerequisite. - Guard the two jitted-generator tests.
test_support_enumerationandtest_vertex_enumerationinsmoke_test.pycall@njitgenerators (support_enumeration.py:96,vertex_enumeration.py:118) that never return on Emscripten (#927, https://github.com/QuantEcon/QuantEcon.py/issues/927#issuecomment-5338104706). Usepytest.mark.skipif(IS_EMSCRIPTEN, ...)orxfail(IS_EMSCRIPTEN, run=False, strict=True)— a plainxfailstill executes the test, andpytest-timeout(SIGALRM /threading.Timer) cannot interrupt a native loop in the single-threaded kernel. Intest_jupyterlite.py, skiptest_support_enumerationor run it last: Playwright'sEXEC_MS(180 s) bounds it host-side, but the module-scoped kernel stays wedged and the following test fails spuriously. Add the minimal bare@njitgenerator test (for i in range(n): yield i) alongside, guarded the same way, as the isolated upstream repro and regression watch. - Mark
test_simplex_gridas expected to fail on a warm cache and cite #944. Its comment currently says "(#929)"; the actual failure isRuntimeError: no compiled object yet for comb_jit(#944, reported upstream as emscripten-forge/recipes#6309), which triggers only when acache=Truecaller links a callee restored from the persistent cache — a cold single-session run passes. A regression test needs a second session or a pre-seeded/drive/.cache/numba. - Ship
smoke_test.pyinto the kernel and run it in-kernel. The parked job runs only the Playwright harness (6 cells: kernel boot, import, tauchen,np.linalg.solve,support_enumeration, gini), so a green run fills at most 5 of #928's 13 rows. #938 assigned in-kernel pytest execution ofsmoke_test.py(16 tests) here (commit 1e0c598 also droppedpytestfromenvironment.yml, so it has to be added back). Copy the file into the site contents, invoke pytest inside the xeus-python kernel, and surface per-test results. - Bump
mamba-org/setup-micromamba@v2to@v3in the parked YAML (v3.0.0 moved to Node 24; the inputs used —micromamba-binary-path,init-shell,generate-run-shell— are unchanged).actions/checkout@v7andactions/setup-python@v7are current.
Expected outcome of the first browser run once 1–6 are done, on numba 0.67.0 build 1: test_gini_coefficient passes; test_support_enumeration, test_vertex_enumeration and the bare-generator test are skipped/xfail(run=False) pending the upstream generator report (#927); test_simplex_grid passes cold and fails warm (#944); everything else is expected to pass. Record the per-function table in #928.
Acceptance criteria
- A CI job builds a JupyterLite deployment containing quantecon and runs the smoke suite in a headless browser
-
ci/wasm/smoke_test.pyexecutes inside the xeus-python kernel (not only the Playwright harness), so every #928 row gets a browser result - Failures are actionable — per-function results rather than a monolithic pass/fail
- Known in-browser failures (#927 generators, #944 warm-cache
comb_jit) are guarded so they cannot consume the job's time limit, and each guard cites its issue
Related
- #938 — seed (merged 2026-08-21):
ci/wasm/environment.yml,smoke_test.py,test_jupyterlite.py, native gate - #928 — results table this job fills;
smoke_test.pyis its checklist - #927 and https://github.com/QuantEcon/QuantEcon.py/issues/927#issuecomment-5338104706 — jitted-generator hang (
support_enumeration,vertex_enumeration); LAPACK verified working - #944 —
cache=Truecallers of cache-restored functions fail on a warm cache (simplex_grid→num_compositions_jit→comb_jit); upstream emscripten-forge/recipes#6309 - #926 / PR #937 — gini O(n log n) rewrite, approved and awaiting merge
- emscripten-forge/recipes#6293 — patch 0010, serial fallback for
parallel=True(numba 0.67.0 build 1) - #932 — if quantecon is packaged on emscripten-forge, this job switches channel and
pytesterbecomes an option
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with .github/workflows/ci_wasm_smoke.yml and the existing files ci/wasm/environment.yml, ci/wasm/smoke_test.py, and ci/wasm/test_jupyterlite.py. Run the native smoke gate first, then inspect the parked runner job and the referenced tests and upstream issues. Done means a browser CI job runs the in-kernel smoke suite with per-function results and guards the documented failures.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, jupyter, playwright, python, wasm
- Domain
- ci-cd, devops, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100