Run the shipped scripts in a browser, and fix the two bugs that found
Decided in quasicoherent 4e7f8380 2026-08-30, replacing a deno decision made
the same day and withdrawn on re-measurement.
Twelve .js files under src/ reach every described document and not one line of
them was executed by a test. The Rust tests assert that the script tag is in
the head, that without_htmx drops it, and that the constant and the default
path agree -- all three true of a file that does nothing.
THE HARNESS. mocha and chai as script tags, then the script under test as
shipped, then the assertions. This is what Big Sky does for htmx itself, and
copying it is not incidental: these are htmx handlers, and htmx exists to
exploit real browser behaviour. No npm, no package.json, no node_modules, no
bundler, and not a line changed in the twelve files to make them testable --
each is a bare IIFE that installs its own listeners, which is the right shape
for a <script> and the wrong shape for every import-and-call runner.
run.py is standard library only. WebDriver is REST over HTTP, so a runner
needs no package; a requirements.txt beside a suite whose argument is that it
needs no package manager would be answering itself. Firefox rather than
Chrome because Google publishes no Linux arm64 chrome-for-testing and astra is
aarch64, so one browser is one story rather than two.
AND IT FOUND TWO BUGS, which is the argument for it.
d131a14c, the fold. `settle` started its walk at `null` and only ever learned
about a *descendant's* chevron, never the pressed row's own state, so shutting
a branch hid nothing at all. A reader could open a branch and not close one.
Seeded from the row that was clicked.
The second is new, and the emitter's own comment already claimed otherwise
("filters by it, pressing its chevron does not"). The chevron listener bubbled,
so its stopPropagation stopped nothing that had already run: a listener on the
row is below the document in the bubble path and fires first. node.rs hangs a
table row's activate on the row element and filters it with
`click[!event.target.closest('[data-act]')]`, which a chevron is not -- so
pressing the chevron on a row that both discloses and activates folded the
branch and navigated away from it. The listener captures now, which is the one
place that knows what a chevron is.
focus.js needed no fix and now has the test 98548a35's done condition asked
for and never got: swap a region holding a focused input, assert focus and the
caret survive. Five cases, all green. htmx is deliberately not loaded -- what
focus.js owns is the pair of events, and raising them to test it would be
testing htmx.
20 files changed,
+33010 insertions,
-43 deletions
| 3425 |
3425 |
|
|
| 3426 |
3426 |
|
[[package]]
|
| 3427 |
3427 |
|
name = "quasi"
|
| 3428 |
|
- |
version = "0.91.0"
|
|
3428 |
+ |
version = "0.91.1"
|
| 3429 |
3429 |
|
|
| 3430 |
3430 |
|
[[package]]
|
| 3431 |
3431 |
|
name = "quasi-axum"
|
| 3432 |
|
- |
version = "0.91.0"
|
|
3432 |
+ |
version = "0.91.1"
|
| 3433 |
3433 |
|
dependencies = [
|
| 3434 |
3434 |
|
"axum",
|
| 3435 |
3435 |
|
"http",
|
| 3443 |
3443 |
|
|
| 3444 |
3444 |
|
[[package]]
|
| 3445 |
3445 |
|
name = "quasi-basics"
|
| 3446 |
|
- |
version = "0.91.0"
|
|
3446 |
+ |
version = "0.91.1"
|
| 3447 |
3447 |
|
dependencies = [
|
| 3448 |
3448 |
|
"makeover-layout",
|
| 3449 |
3449 |
|
"quasi-http",
|
| 3453 |
3453 |
|
|
| 3454 |
3454 |
|
[[package]]
|
| 3455 |
3455 |
|
name = "quasi-bench"
|
| 3456 |
|
- |
version = "0.91.0"
|
|
3456 |
+ |
version = "0.91.1"
|
| 3457 |
3457 |
|
dependencies = [
|
| 3458 |
3458 |
|
"dhat",
|
| 3459 |
3459 |
|
"makeover",
|
| 3468 |
3468 |
|
|
| 3469 |
3469 |
|
[[package]]
|
| 3470 |
3470 |
|
name = "quasi-http"
|
| 3471 |
|
- |
version = "0.91.0"
|
|
3471 |
+ |
version = "0.91.1"
|
| 3472 |
3472 |
|
dependencies = [
|
| 3473 |
3473 |
|
"form_urlencoded",
|
| 3474 |
3474 |
|
"http",
|
| 3477 |
3477 |
|
|
| 3478 |
3478 |
|
[[package]]
|
| 3479 |
3479 |
|
name = "quasi-immediate"
|
| 3480 |
|
- |
version = "0.91.0"
|
|
3480 |
+ |
version = "0.91.1"
|
| 3481 |
3481 |
|
dependencies = [
|
| 3482 |
3482 |
|
"docengine",
|
| 3483 |
3483 |
|
"egui",
|
| 3488 |
3488 |
|
|
| 3489 |
3489 |
|
[[package]]
|
| 3490 |
3490 |
|
name = "quasi-notifs"
|
| 3491 |
|
- |
version = "0.91.0"
|
|
3491 |
+ |
version = "0.91.1"
|
| 3492 |
3492 |
|
dependencies = [
|
| 3493 |
3493 |
|
"quasi-router",
|
| 3494 |
3494 |
|
"synckit-config",
|
| 3498 |
3498 |
|
|
| 3499 |
3499 |
|
[[package]]
|
| 3500 |
3500 |
|
name = "quasi-router"
|
| 3501 |
|
- |
version = "0.91.0"
|
|
3501 |
+ |
version = "0.91.1"
|
| 3502 |
3502 |
|
dependencies = [
|
| 3503 |
3503 |
|
"makeover-layout",
|
| 3504 |
3504 |
|
]
|
| 3515 |
3515 |
|
|
| 3516 |
3516 |
|
[[package]]
|
| 3517 |
3517 |
|
name = "quasi-tauri"
|
| 3518 |
|
- |
version = "0.91.0"
|
|
3518 |
+ |
version = "0.91.1"
|
| 3519 |
3519 |
|
dependencies = [
|
| 3520 |
3520 |
|
"http",
|
| 3521 |
3521 |
|
"quasi-http",
|
| 3526 |
3526 |
|
|
| 3527 |
3527 |
|
[[package]]
|
| 3528 |
3528 |
|
name = "quasi-tui"
|
| 3529 |
|
- |
version = "0.91.0"
|
|
3529 |
+ |
version = "0.91.1"
|
| 3530 |
3530 |
|
dependencies = [
|
| 3531 |
3531 |
|
"docengine",
|
| 3532 |
3532 |
|
"makeover",
|
| 3539 |
3539 |
|
|
| 3540 |
3540 |
|
[[package]]
|
| 3541 |
3541 |
|
name = "quasi-webview"
|
| 3542 |
|
- |
version = "0.91.0"
|
|
3542 |
+ |
version = "0.91.1"
|
| 3543 |
3543 |
|
dependencies = [
|
| 3544 |
3544 |
|
"docengine",
|
| 3545 |
3545 |
|
"makeover-layout",
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-axum"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "The axum host adapter for quasi-router: an HTTP request in, a rendered description out"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|
| 13 |
13 |
|
workspace = true
|
| 14 |
14 |
|
|
| 15 |
15 |
|
[dependencies]
|
| 16 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0" }
|
| 17 |
|
- |
quasi-http = { path = "../quasi-http", version = "0.91.0" }
|
|
16 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1" }
|
|
17 |
+ |
quasi-http = { path = "../quasi-http", version = "0.91.1" }
|
| 18 |
18 |
|
axum = "0.8.8"
|
| 19 |
19 |
|
http = "1.3.1"
|
| 20 |
20 |
|
tokio = { version = "1.50.0", features = ["rt"] }
|
| 21 |
21 |
|
|
| 22 |
22 |
|
[dev-dependencies]
|
| 23 |
|
- |
quasi-webview = { path = "../quasi-webview", version = "0.91.0" }
|
|
23 |
+ |
quasi-webview = { path = "../quasi-webview", version = "0.91.1" }
|
| 24 |
24 |
|
tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread"] }
|
| 25 |
25 |
|
tower = { version = "0.5.3", features = ["util"] }
|
| 26 |
26 |
|
http-body-util = "0.1.3"
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-basics"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "The first-party widget set: named assemblies of primitives, shared across our apps"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|
| 13 |
13 |
|
workspace = true
|
| 14 |
14 |
|
|
| 15 |
15 |
|
[dependencies]
|
| 16 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0" }
|
|
16 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1" }
|
| 17 |
17 |
|
makeover-layout = "0.41.0"
|
| 18 |
18 |
|
|
| 19 |
19 |
|
[dev-dependencies]
|
| 20 |
20 |
|
# A widget's guarantees are claims about what a renderer draws, so they are
|
| 21 |
21 |
|
# tested against a real one rather than by walking the tree the assembly just
|
| 22 |
22 |
|
# built. The webview is the renderer that recognises names today.
|
| 23 |
|
- |
quasi-webview = { path = "../quasi-webview", version = "0.91.0" }
|
| 24 |
|
- |
quasi-http = { path = "../quasi-http", version = "0.91.0" }
|
|
23 |
+ |
quasi-webview = { path = "../quasi-webview", version = "0.91.1" }
|
|
24 |
+ |
quasi-http = { path = "../quasi-http", version = "0.91.1" }
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-bench"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "What a described screen costs to render, in time and in allocations"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|
| 22 |
22 |
|
count = ["dep:dhat"]
|
| 23 |
23 |
|
|
| 24 |
24 |
|
[dependencies]
|
| 25 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0" }
|
| 26 |
|
- |
quasi-webview = { path = "../quasi-webview", version = "0.91.0" }
|
| 27 |
|
- |
quasi-tui = { path = "../quasi-tui", version = "0.91.0" }
|
|
25 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1" }
|
|
26 |
+ |
quasi-webview = { path = "../quasi-webview", version = "0.91.1" }
|
|
27 |
+ |
quasi-tui = { path = "../quasi-tui", version = "0.91.1" }
|
| 28 |
28 |
|
# `Serves` is the trait carrying `screen` and `fragment`, which is what the
|
| 29 |
29 |
|
# webview is measured through. Taken directly rather than through quasi-webview
|
| 30 |
30 |
|
# because a bench calling a trait method should name the trait it calls.
|
| 31 |
|
- |
quasi-http = { path = "../quasi-http", version = "0.91.0" }
|
|
31 |
+ |
quasi-http = { path = "../quasi-http", version = "0.91.1" }
|
| 32 |
32 |
|
makeover-layout = "0.41.0"
|
| 33 |
33 |
|
makeover-tui = { version = "0.41.0", features = ["theme"] }
|
| 34 |
34 |
|
# Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-http"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "The http-shaped seam quasi's webview host adapters share: decoding in, a rendered description out"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|
| 13 |
13 |
|
workspace = true
|
| 14 |
14 |
|
|
| 15 |
15 |
|
[dependencies]
|
| 16 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0" }
|
|
16 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1" }
|
| 17 |
17 |
|
http = "1.3.1"
|
| 18 |
18 |
|
form_urlencoded = "1.2.2"
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-immediate"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
edition = "2024"
|
| 5 |
5 |
|
description = "The immediate-mode renderer for quasi-router: a described screen in, an egui frame out. Immediate mode is the constraint that matters, not the library."
|
| 6 |
6 |
|
license = "MIT"
|
| 12 |
12 |
|
categories = ["gui"]
|
| 13 |
13 |
|
|
| 14 |
14 |
|
[dependencies]
|
| 15 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0" }
|
|
15 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1" }
|
| 16 |
16 |
|
# The node drawing, which is the makeover layer's and not this crate's. Every
|
| 17 |
17 |
|
# widget here that is not a container comes from it: a screen walk that painted
|
| 18 |
18 |
|
# its own meter would be the divergence the suite exists to end, one copy per
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-notifs"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "Declared notification kinds and the registry that holds them: what a notification says and what it is for, apart from how it reaches a person"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|
| 28 |
28 |
|
tauri = ["dep:tauri", "dep:tauri-plugin-notification"]
|
| 29 |
29 |
|
|
| 30 |
30 |
|
[dependencies]
|
| 31 |
|
- |
quasi-router = { path = "../quasi-router", version = "0.91.0", optional = true }
|
|
31 |
+ |
quasi-router = { path = "../quasi-router", version = "0.91.1", optional = true }
|
| 32 |
32 |
|
synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }
|
| 33 |
33 |
|
tauri-plugin-notification = { version = "2.3.3", optional = true }
|
| 34 |
34 |
|
# Default features off, for `quasi-tauri`'s reason: this takes an `AppHandle`
|
| 1 |
1 |
|
[package]
|
| 2 |
2 |
|
name = "quasi-router"
|
| 3 |
|
- |
version = "0.91.0"
|
|
3 |
+ |
version = "0.91.1"
|
| 4 |
4 |
|
description = "Host-agnostic router: a request in, a renderer-agnostic description out"
|
| 5 |
5 |
|
edition.workspace = true
|
| 6 |
6 |
|
rust-version.workspace = true
|