Skip to main content

max / makenotwork

Mount the git landing page, and assert both at-the-flip rules on every described document quasi::git_explore shipped undeclared. A module missing from mod.rs is not compiled, so /git answered nothing after browsing::git_landing was deleted with its template, and the module's seven tests never ran. Declared and mounted beside git_repos under the same browse limiter, which is what the source-level limiter test was already written to catch. The four workflows::git_browser failures reported as unowned were this, and the target's 40 tests now pass. Both at-the-flip rules now hold at every described document rather than most of them. The parity test asserts the rendered <body> as well as Screen::document, which is the shape feeds and export_portal set and the six conversions since did not follow. The spinner guard reaches feeds, pricing and every branch of fan_plus; fan_plus asserted only the branch that draws the subscribe control, so a spelling reappearing on the member or just-subscribed branch would have passed. No template carried a spelling into any of the six screens converted here except fan_plus, whose data-loading-text left with Action::awaiting.
Author: Max Johnson <me@maxj.phd> · 2026-09-01 16:37 UTC
Signed with PGP, not checked
Commit: c26dff42d5c1833c18700b24699ff7f4a1589c3d
Parent: b154427
10 files changed, +119 insertions, -9 deletions
@@ -295,6 +295,11 @@
295 295 screen.document.body_class.as_deref(),
296 296 Some("padded-page collection-page")
297 297 );
298 + let rendered = html(&loaded(2, true));
299 + assert!(
300 + rendered.contains("class=\"padded-page collection-page\""),
301 + "{rendered}"
302 + );
298 303 }
299 304
300 305 /// The title is the collection's and the owner's, in that order, which is
@@ -268,6 +268,11 @@
268 268 screen.document.body_class.as_deref(),
269 269 Some("padded-page creators-page")
270 270 );
271 + let rendered = html(&Standing::Visitor);
272 + assert!(
273 + rendered.contains("class=\"padded-page creators-page\""),
274 + "{rendered}"
275 + );
271 276 }
272 277
273 278 /// Every tier the table listed is still listed, and its price is read
@@ -244,6 +244,11 @@
244 244 screen.document.body_class.as_deref(),
245 245 Some("padded-page fan-plus-page")
246 246 );
247 + let rendered = html(&Standing::Visitor, false);
248 + assert!(
249 + rendered.contains("class=\"padded-page fan-plus-page\""),
250 + "{rendered}"
251 + );
247 252 }
248 253
249 254 /// The visitor branch, which is the one the template's own comment exists
@@ -349,13 +354,30 @@
349 354 }
350 355
351 356 /// `736f45a5`: the wait on the Stripe handoff is said by the description.
357 + /// The template spelled it `data-loading-text="Redirecting to Stripe..."`
358 + /// on the subscribe button, so the branch that draws that control asserts
359 + /// the word replacing it, and every branch asserts the four spellings are
360 + /// absent.
352 361 #[test]
353 362 fn the_subscribe_control_spells_no_spinner() {
354 - let html = html(&Standing::Unsubscribed, false);
363 + assert!(
364 + html(&Standing::Unsubscribed, false).contains("data-awaiting="),
365 + "{}",
366 + html(&Standing::Unsubscribed, false)
367 + );
355 368
356 - assert!(html.contains("data-awaiting="), "{html}");
357 - for spelling in ["htmx-indicator", "spinner", "loading-text", "loading-state"] {
358 - assert!(!html.contains(spelling), "{spelling} survives in {html}");
369 + for rendered in [
370 + html(&Standing::Visitor, false),
371 + html(&Standing::Unsubscribed, false),
372 + html(&Standing::Member { period_end: None }, false),
373 + html(&Standing::Unsubscribed, true),
374 + ] {
375 + for spelling in ["htmx-indicator", "spinner", "loading-text", "loading-state"] {
376 + assert!(
377 + !rendered.contains(spelling),
378 + "{spelling} survives in {rendered}"
379 + );
380 + }
359 381 }
360 382 }
361 383 }
@@ -616,6 +616,20 @@
616 616 assert!(public(1, 2).contains("class=\"padded-page feed-page\""));
617 617 }
618 618
619 + /// `736f45a5`. The template carried no indicator and neither does the
620 + /// screen: the listing waits on nothing a reader presses.
621 + #[test]
622 + fn the_page_spells_no_spinner() {
623 + let rendered = public(1, 2);
624 +
625 + for spelling in ["htmx-indicator", "spinner", "loading-text", "loading-state"] {
626 + assert!(
627 + !rendered.contains(spelling),
628 + "{spelling} survives in {rendered}"
629 + );
630 + }
631 + }
632 +
619 633 /// The title `pages/feed.html` drew as `<h1 class="page-title">`, drawn by
620 634 /// the description instead. The class moved with it, which is what
621 635 /// `style.css` had to be retargeted for.
@@ -98,9 +98,9 @@
98 98 .into_iter()
99 99 .take(limit)
100 100 .map(|repo| Repo {
101 - owner: repo.owner_username.to_string(),
102 - name: repo.name.clone(),
103 - description: repo.description.clone(),
101 + owner: repo.owner_username,
102 + name: repo.name,
103 + description: repo.description,
104 104 })
105 105 .collect(),
106 106 page,
@@ -232,6 +232,8 @@
232 232 let screen = page_screen(&loaded(1, 1, false, false));
233 233
234 234 assert_eq!(screen.document.body_class.as_deref(), Some("padded-page"));
235 + let rendered = html(&loaded(1, 1, false, false));
236 + assert!(rendered.contains("class=\"padded-page\""), "{rendered}");
235 237 }
236 238
237 239 /// Each row says `owner/name` and opens that repository.
@@ -276,7 +278,10 @@
276 278 assert!(!first.contains("page=0"), "{first}");
277 279
278 280 let middle = html(&loaded(3, 2, true, false));
279 - assert!(middle.contains("page=1") && middle.contains("page=3"), "{middle}");
281 + assert!(
282 + middle.contains("page=1") && middle.contains("page=3"),
283 + "{middle}"
284 + );
280 285
281 286 let last = html(&loaded(3, 4, false, false));
282 287 assert!(last.contains("page=3"), "{last}");
@@ -244,6 +244,8 @@
244 244 let screen = page_screen(&loaded(1, false));
245 245
246 246 assert_eq!(screen.document.body_class.as_deref(), Some("padded-page"));
247 + let rendered = html(&loaded(1, false));
248 + assert!(rendered.contains("class=\"padded-page\""), "{rendered}");
247 249 }
248 250
249 251 /// The title names whose repositories these are, as the template's did.
@@ -52,6 +52,7 @@
52 52 pub mod fan_plus;
53 53 pub mod feeds;
54 54 pub mod forum_memberships;
55 + pub mod git_explore;
55 56 pub mod git_repos;
56 57 pub mod item_files;
57 58 pub mod item_sales;
@@ -405,6 +406,7 @@
405 406 fan_plus::PATH,
406 407 creators::PATH,
407 408 collections::PATH,
409 + git_explore::PATH,
408 410 git_repos::PATH,
409 411 ];
410 412
@@ -618,7 +620,25 @@
618 620 // these routes walk bare repositories on disk. The mount is an
619 621 // `axum::Router`, so the layer goes on here rather than through a
620 622 // parameter, and the limiter is rebuilt from the same constants
621 - // `routes::git` reads. See `git_repos`'s module header.
623 + // `routes::git` reads. See `git_repos`'s module header. Both git
624 + // listings mount here, and a module that is declared but not mounted is
625 + // an address nothing answers: `git_explore` shipped that way and its own
626 + // tests did not run either, because an undeclared module is not compiled.
627 + (
628 + git_explore::PATH,
629 + public_document_mount(
630 + app,
631 + git_explore::PATH,
632 + git_explore::screen,
633 + git_explore::renderer,
634 + )
635 + .layer(tower_governor::GovernorLayer::new(
636 + crate::helpers::rate_limiter_ms(
637 + crate::constants::GIT_BROWSE_RATE_LIMIT_MS,
638 + crate::constants::GIT_BROWSE_RATE_LIMIT_BURST,
639 + ),
640 + )),
641 + ),
622 642 (
623 643 git_repos::PATH,
624 644 public_document_mount(app, git_repos::PATH, git_repos::screen, git_repos::renderer)
@@ -232,6 +232,11 @@
232 232 screen.document.body_class.as_deref(),
233 233 Some("padded-page policy-page")
234 234 );
235 + assert!(
236 + html().contains("class=\"padded-page policy-page\""),
237 + "{}",
238 + html()
239 + );
235 240 }
236 241
237 242 /// The two things rows would have flattened, which is the whole argument
@@ -875,6 +875,33 @@
875 875 Some(crate::shell::body_class(MEASURE, &[]).as_str())
876 876 );
877 877 assert_eq!(screen.document.body_class.as_deref(), Some("centered-page"));
878 +
879 + use quasi_axum::Serves as _;
880 +
881 + let rendered = Webview::new().screen(&page(
882 + &state(false),
883 + &Dials::read(&state(false), &carrying(&[])),
884 + ));
885 + assert!(rendered.contains("class=\"centered-page\""), "{rendered}");
886 + }
887 +
888 + /// `736f45a5`. The calculator answers in the page rather than over the
889 + /// wire, so there is no wait to draw and no spelling to carry.
890 + #[test]
891 + fn the_page_spells_no_spinner() {
892 + use quasi_axum::Serves as _;
893 +
894 + let rendered = Webview::new().screen(&page(
895 + &state(false),
896 + &Dials::read(&state(false), &carrying(&[])),
897 + ));
898 +
899 + for spelling in ["htmx-indicator", "spinner", "loading-text", "loading-state"] {
900 + assert!(
901 + !rendered.contains(spelling),
902 + "{spelling} survives in {rendered}"
903 + );
904 + }
878 905 }
879 906
880 907 /// Where the reader sits against the crossover, drawn only when there is a
@@ -375,6 +375,11 @@
375 375 screen.document.body_class.as_deref(),
376 376 Some("padded-page use-cases-page")
377 377 );
378 + let rendered = html();
379 + assert!(
380 + rendered.contains("class=\"padded-page use-cases-page\""),
381 + "{rendered}"
382 + );
378 383 }
379 384
380 385 /// Every card the template drew is still drawn, and still reachable by the