Repository navigation
Unit-test the shipped frontend JavaScript with standard JS tooling (vitest) #7611
Description
Problem
The JavaScript Reflex ships to every app (state.js, react-theme.js, upload.js, client state, the helpers and components under .templates/web/utils/) has no test suite of its own. Its behavior is only reachable through compiled output: Python unit tests can assert on generated source but not on runtime behavior, and Playwright integration tests are slow and indirect for things like provider teardown, SSR-versus-client branches, subscription bookkeeping, reconnect backoff or event-queue ordering. The two existing runtime checks (tests/units/compiler/state_js.test.mjs, tests/units/reflex_base/client_event_queue_runtime.mjs) are bespoke node scripts driven from pytest.
Proposal
Test the shipped JS with standard tooling: vitest + jsdom, with its own package.json and a committed package-lock.json, installed with npm ci and run as a js-unit-tests job in unit_tests.yml that blocks merges through unit-tests-gate.
- Tests must not live inside the template tree that
reflex initcopies verbatim into a user's.web. While the runtime is still a template tree they live intests/js/and resolve$/...through a vitest alias; once the runtime ships as a package (Ship the frontend runtime JavaScript as an installable npm package #7609) they move into the package atreflex_base/frontend/tests/. $/utils/statehas to be stubbed today because the real module imports socket.io, react-router and the per-app generatedutils/context.js. Decoupling the runtime from generated artifacts (part of Ship the frontend runtime JavaScript as an installable npm package #7609) makesstate.jsitself unit-testable.- Where JS and Python share a constant (for example the client-state registry key in
constants/state.py, or the_downloadpayload matcher instate.jsversus the Var's_js_expr), a test asserts the two definitions agree so they cannot drift. - Document the suite, and when to reach for it versus Playwright, in
AGENTS.md(npm --prefix tests/js ci && npm --prefix tests/js test). - New JS test files are formatted with biome under pre-commit; codespell skips committed lockfiles.
Pending work
- Promote client state to rx.client_state with a scoped store #6936 (ClientStateVar refactor, Refactor ClientStateVar: scoped client state via a useClientState hook (rx.client_state) #7610) introduces
tests/js/:vitest.config.js,client_state.test.js, thejs-unit-testsCI job and its gate wiring, and theAGENTS.mdsection. - The npm package branch for Ship the frontend runtime JavaScript as an installable npm package #7609 adds
reflex_base/frontend/tests/withstate.test.js,runtime.test.jsandhelpers.test.js, and makesstate.jsimportable in tests. - Land the suite with whichever of the two merges first, then reconcile the other so there is one
package.json/lockfile and one CI job. - Follow-up: fold the existing
.mjsruntime checks into the vitest suite so there is a single JS test entry point.
Activity
linear-code commentedon Oct 20, 2026
ENG-13451