بنقرة واحدة
testing
How tests work in this repo — Rust crates use
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
How tests work in this repo — Rust crates use
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
One iteration of the bench improvement loop — run a scenario, pick the top friction item, fix it, rerun, compare, keep or revert. Designed to be driven by /loop (e.g. `/loop /bench-iterate from-scratch`).
Submit (and query/update) a bug in a tonk space using the `tonk` CLI and asserted-notation. Use whenever asked to file, report, triage, or list bugs in a tonk repo. Covers the `bug` concept schema, value conventions, the next-ident lookup, and the create/retract notation that actually works against this CLI.
| name | testing |
| description | How tests work in this repo — Rust crates use |
| allowed-tools | Read, Bash, Glob, Grep |
Three layers of tests, each with its own harness. Default to #[dialog_common::test] — the macro picks the right runtime per target so the same test source runs everywhere.
#[dialog_common::test], not #[test] or #[tokio::test]The macro expands to:
#[tokio::test] for async functions, #[test] for sync.wasm32-unknown-unknown: #[wasm_bindgen_test], runs in headless Chrome via chromedriver.Same source, both targets. Browser tests need it because plain #[test] doesn't run in a browser; native tests benefit because future runtime changes happen in one place.
// Right
#[dialog_common::test]
async fn it_does_a_thing() {
let result = some_async_call().await.unwrap();
assert_eq!(result, 42);
}
// Wrong — won't run on wasm32, won't be picked up by `test:web:debug`
#[tokio::test]
async fn it_does_a_thing() { /* ... */ }
#[dialog_common::test][dev-dependencies]
dialog-common = { workspace = true, features = ["helpers"] }
tokio = { workspace = true, features = ["macros", "rt"] }
wasm-bindgen-test = { workspace = true }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(dialog_test_native_integration)',
'cfg(dialog_test_wasm_integration)',
'cfg(feature, values("web-integration-tests"))',
] }
Skip tokio if there are zero async tests, skip wasm-bindgen-test if the crate doesn't compile to wasm — but the typical crate needs both. The [lints.rust] block silences spurious "unexpected cfg" warnings the macro emits per its check-cfg expectations.
wasm_bindgen_test_configure! to wasm-runnable test modswasm-bindgen-test defaults to running tests in Node.js, which CI's test:web:* environment doesn't have. The test fails with Error: failed to find or execute Node.js and 33 other tests get cancelled because of fail-fast.
Every test mod whose tests run on wasm32 must explicitly select a browser-side runner:
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test_configure;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test_configure!(run_in_browser);
#[dialog_common::test]
fn my_test() { /* ... */ }
}
Always include the configure line, even for sync unit tests that don't look like they need a runtime. dialog_common::test expands to #[wasm_bindgen_test] on wasm regardless, and the runtime selection still applies.
Pick the right host:
run_in_browser — when the tests need window / document / DOM APIs, or when the test body does no I/O at all and you just want the tests to run somewhere. Default for unit tests in tonk-notation, tonk-language-server, tonk-invite, tonk-code, tonk-schema.run_in_service_worker — when the tests need IndexedDB / Cache API / Storage / caches etc. Default for tonk-worker router tests.The #[cfg(target_arch = "wasm32")] guards keep the configure line out of the way on native (where it doesn't apply); the test attribute itself dispatches per target so the tests don't need any cfg.
Live next to the code in #[cfg(test)] mod tests blocks. Run with the macro's basic mode — #[dialog_common::test] fn (sync) or async fn (async).
#[cfg(test)]
mod tests {
use super::*;
#[dialog_common::test]
async fn parses_yaml() {
let parsed = parse("a: 1");
assert!(parsed.diagnostics.is_empty());
}
}
Live in the same #[cfg(test)] mod tests blocks but gated to wasm32. Use wasm_bindgen_test_configure! to choose the JS execution context:
run_in_browser — needs window / document / DOM APIs (e.g. tonk-invite, tonk-code).run_in_service_worker — needs IndexedDB / Cache API / Storage etc. (e.g. tonk-worker).#[cfg(all(test, target_arch = "wasm32", target_os = "unknown"))]
mod tests {
use wasm_bindgen_test::wasm_bindgen_test_configure;
wasm_bindgen_test_configure!(run_in_service_worker);
use crate::worker::TonkState;
#[dialog_common::test]
async fn it_does_browser_things() {
// ...
}
}
These run via nix develop -c test:web:debug (or :release), which builds a wasm test archive and drives Chrome through chromedriver.
For testing the real built app — the actual tonk-ui SPA, the actual <tonk-code> editor bundle, real LSP wiring through Caddy + the access service. These take a TestEnvironment parameter from tonk_ui::helpers:
#[dialog_common::test]
async fn it_does_a_real_thing(env: TestEnvironment) -> Result<()> {
let driver = env.driver().await?;
// Wait for something via CSS selector
driver.query(By::Css(".space-banner-title")).first().await?;
// Or eval JS in the page
let result = driver.execute(
r#"const el = document.querySelector("tonk-code");
el.value = "hello";
return el.value;"#,
vec![],
).await?;
assert_eq!(result.json().as_str(), Some("hello"));
driver.quit().await?;
Ok(())
}
The macro detects "function takes a parameter" and generates an integration test instead of a unit test. The test:
tonk-ui (with all assets including tonk-code/*)./ucan/* proxying.TestEnvironment with the URLs.Examples in rust/tonk-ui/src/components.rs (it_falls_back_to_index_for_unhandled_routes, it_configures_upstream, it_syncs_via_sync_route, etc.).
This is the right harness whenever the test needs to verify real bundle behavior — CodeMirror diagnostics rendering, LSP round-tripping, service-worker registration, full SPA navigation. Don't try to fake the bundle with stubs; use the real one.
In the dev shell (nix develop):
| Command | What it runs |
|---|---|
test:native:debug | Workspace minus tonk-ui and tonk-core, native target, integration-tests feature. |
test:native:release | Same, release profile. |
test:web:debug | Workspace, wasm32-unknown-unknown, headless Chrome via chromedriver. |
test:web:release | Same, release profile. |
test:all | All four. |
tonk-ui's real-browser integration tests are excluded from the default workspace test runs (the flake explicitly --exclude tonk-ui). They run via cargo test -p tonk-ui --features integration-tests against a separately-spun tonk-ui-test-server process. CI doesn't yet wire this up by default; if you add tonk-ui integration tests, document the run command and wire it up.
#[cfg(all(test, target_arch = "wasm32", target_os = "unknown"))]
mod tests {
wasm_bindgen_test_configure!(run_in_service_worker);
#[dialog_common::test]
async fn it_returns_something() {
let state = test_state().await;
let (app, _lsp) = api_router(state);
let response = app
.oneshot(Request::builder()
.uri("/api/...")
.body(Body::empty()).unwrap())
.await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}
}
test_state() and put_repo() are convenience helpers in tonk-worker/src/router.rs::tests — copy the pattern when adding to that suite.
#[dialog_common::test]
async fn it_drives_the_editor(env: TestEnvironment) -> Result<()> {
let driver = env.driver().await?;
// Wait for the page to be ready
driver.query(By::Css(".space-banner-title")).first().await?;
// Find the editor element
let editor = driver.query(By::Css("tonk-code")).first().await?;
// Drive it
let value = driver.execute(
r#"
const el = arguments[0];
el.value = "person-name:\n attribute:\n the: x/y\n";
return el.value;
"#,
vec![editor.to_json()?],
).await?;
assert!(value.json().as_str().unwrap_or("").contains("person-name"));
driver.quit().await?;
Ok(())
}
#[tokio::test] directly — won't run on wasm. Use #[dialog_common::test].#[wasm_bindgen_test] directly — won't run on native. Same.futures::executor::block_on(async_call()) inside #[test] — the test isn't async. Make it #[dialog_common::test] async fn and .await instead.<tonk-code> editor — use a real-browser integration test in tonk-ui. Stubs verify your own contract; they don't catch CodeMirror/LSP bugs.nix develop -c test:* runs.| Pattern | Look at |
|---|---|
| Sync unit test | tonk-notation/src/parse.rs::tests |
| Async unit test | tonk-schema/src/interpret.rs::tests |
| Wasm-in-service-worker test | tonk-worker/src/router.rs::tests (the entire mod) |
| Wasm-in-browser test | tonk-invite/src/lib.rs::tests |
| Real-browser integration test | tonk-ui/src/components.rs::tests (it_falls_back_…, it_configures_upstream) |
| Provider machinery for the integration tests | tonk-ui/src/helpers.rs (TestEnvironment, TestServers) |
| Flake test commands | flake.nix commands.test:* |