Repository navigation
BUGFIX: wheels.dispatch component not found in Linux during test run - #16
Merged
Merged
Conversation
The test suite should be looking for `wheels.Dispatch` in case sensitive environments.
4 of 7 tasks
bpamiri
added a commit
that referenced
this pull request
Apr 29, 2026
* docs(docs): add batch E plan for browser test infrastructure fixes Plan covers findings #10, #11, #12 from the 2026-04-29 fresh-VM onboarding triage. #10 (test DB seeding) and #11 (selector ambiguity) have known fixes; #12 (final assertion failure) is diagnostic-first with a hypothesis-tree similar to batch D. Implementation lands in subsequent commits on this branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(web/guides): scope chapter 7 comment-submit selector to new-comment frame The post show page has two submit buttons after chapter 5 — the Delete button (from buttonTo(method="delete")) and the Post comment button — so the existing button[type=submit] selector hit Playwright's strict-mode rejection. Scope to turbo-frame##new_comment button[type=submit] so the locator is unambiguous, and add an explainer bullet for the ##-escape pattern. Closes finding #11 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md * feat(test): wheels test runs against <appname>_test datasource by default The scaffolder already creates db/test.sqlite and registers a <appname>_test datasource at wheels new time, but no runtime path used it. wheels test ran against the dev datasource through the running dev server, so chapter 6's manual signup of [email protected] bled into chapter 7's SignupFlowSpec and the spec failed on uniqueness validation. Make app-runner.cfm consult url.useTestDB and swap application.wheels.dataSourceName to the matching _test datasource for the duration of the run. Restore on exit via try/finally so the swap is unwound even if a spec throws or aborts. The CLI passes useTestDB=true by default; --no-test-db opts out for users who want to point app tests at the dev DB. Generate a default tests/populate.cfm at scaffold time that runs migrateToLatest() against the active datasource. The framework includes the user's populate.cfm only when the test DB has no migrator-versions table — every subsequent run reuses the schema. Add a thin TestDbResolver helper (CFC) so the swap rule is unit-testable without HTTP. Three regression specs cover the useTestDB=true / false / missing-key cases. Closes finding #10 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md. Subsumes April 19 #16 (populate.cfm not documented at tutorial level). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(web/guides): explain wheels test ↔ db/test.sqlite contract in chapter 7 Previously chapter 7 mentioned tests/populate.cfm only in troubleshooting. Now that the framework auto-swaps to the <appname>_test datasource and runs the user's populate.cfm on first empty run, document the contract explicitly so readers know: - their dev DB and test DB are separate - chapter 6's manual signup does NOT leak into chapter 7 specs - populate.cfm ships with wheels new and runs their migrations - --no-test-db opts back into the dev DB Aligns the tutorial with the new wheels test default introduced in the framework commit landed in this batch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(test): add chapter-7 canary harness for test-DB isolation Scaffolds a fresh app, applies a chapter-2-minimum schema, seeds a chapter-6-equivalent contamination row in the dev DB, then runs wheels test with a spec that asserts post-count == 0. The spec only passes if the runner correctly isolates against the test DB. Then re-runs with --no-test-db to confirm the opt-out path lands the spec on the dev DB (where it must fail because of the seeded row). Catches three regressions before users see them: - the test-DB swap silently breaking - tests/populate.cfm not shipping with wheels new - the --no-test-db flag being lost Lighter than a full chapter-7 SignupFlowSpec canary (which would need Playwright JARs); browser-spec coverage tracked as a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(controller): set Content-Type to text/vnd.turbo-stream.html for stream responses Turbo 7+ requires `Content-Type: text/vnd.turbo-stream.html` on the response or the browser-side runtime ignores <turbo-stream> elements and falls back to a regular navigation. Without this header, chapter 7's SignupFlowSpec final assertion silently fails because the test browser navigates to /posts/<id>/comments instead of letting Turbo process the inline comment append. Add a $applyTurboStreamContentType helper to renderPartial that sniffs the rendered body's first non-whitespace bytes — if it starts with a <turbo-stream> opening tag, the helper sets the response Content-Type via getPageContext().getResponse().setContentType (mirroring the SSE pattern in vendor/wheels/controller/sse.cfc; cfheader doesn't reliably set Content-Type on Lucee). Conservative trigger: only matches when <turbo-stream> is the first real element. Plain HTML partials are unaffected. Public method so controllers can opt in for renderText / renderWith paths too. Closes finding #12 in docs/superpowers/plans/2026-04-29-fresh-vm-onboarding-findings.md on the strength of textual evidence (the original journal named the Content-Type as the suspect; Turbo 7+ docs confirm the requirement). End-to-end verification via the canary harness lands separately — the unit tests here pin the regex contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(docs): mark batch E items shipped + close April 19 #16 Records the four commits landed in batch E for findings #10, #11, and #12 from the 2026-04-29 fresh-VM onboarding triage. Also closes April 19 #16 (test fixture setup at tutorial level), which is subsumed by finding #10's framework-side fix. #12 closure note: shipped on the strength of textual evidence (the H1 hypothesis from the original journal); end-to-end browser-spec verification through the canary harness lands separately once Playwright JARs are available in the run environment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bpamiri
added a commit
that referenced
this pull request
May 1, 2026
Bundles 9 fixes uncovered by the 2026-04-30 fresh-VM tutorial bake. Each chapter is a focused edit; the bundle ships one PR / one CI run since they all live under web/sites/guides/. Chapter 1 (Hello, Wheels): - Drop `Controller.cfc` and `Model.cfc` from the "What got created" file tree — `wheels new` doesn't emit those base classes; the tree was aspirational. Add `rewrite.config` at the repo root, which IS emitted but wasn't listed. Finding #15. - Add a "First start downloads ~74 MB" Aside before the welcome-page step so a 30-second wait isn't a surprise. Finding #16. Chapter 2 (Your First Model): - Replace the made-up `Migration complete.` Expected output with the shape the runner actually emits today (`Migrating from 0 up to <ts>` + `Created table posts`), and note that the wording can drift across snapshots so readers verify on the `Created table` line. Finding #10. - Update the `t.timestamps()` description to mention all three columns it adds (`createdAt`, `updatedAt`, `deletedAt`) and link forward to Part 5's soft-delete callout. Previously claimed only two columns. Chapter 3 (CRUD Scaffold): - Rephrase the scaffold caution: it does NOT unconditionally append `.resources("posts")` to routes; it only appends when no resources line for the model exists. Chapter 2 already adds one, so the file is left alone. Finding #13. - Update the "generator emits findByKey(params.key) everywhere" claim — actually it uses `params.post` (route model binding) on key-scoped actions; only positional helpers fall back to `findByKey`. Finding #14. Chapter 4 (Validations + Turbo Frames): - Drop the manual `<label>` wrappers around helpers in `_form.cfm` and use the helpers' own `label="..."` argument instead. The previous shape produced nested `<label>` elements — exactly what chapter 3's caution about object-bound helpers warned against. Finding #11. Chapter 6 (Authentication, Part 6b): - Name `app/events/onapplicationstart.cfm` explicitly as the place to register the session strategy, and explain why `config/app.cfm` is the wrong place (`Application.cfc` this-scope, DI container not yet initialized). The previous "or equivalent on-init block" hedge cost the runner real time. Finding #6. - Recommend scraping `<meta name="csrf-token">` uniformly for curl smoke tests instead of mixing meta-tag-vs-form-input rules. Some forms (login raw inputs, comments, basecoat-rewritten views) don't always include the hidden input. Finding #7. - Replace the `--data-urlencode` recipe with a known-working raw `--data` form that pre-encodes brackets and `@`. The previous "use the `=` separator" advice was incomplete — Lucee's form parser treats any bracketed key as a nested-struct path regardless of encoding form. Finding #8. Findings deliberately not addressed in this PR: - #9 (soft-delete callout) — verified against current code: `t.timestamps()` emits all three columns including `deletedAt`, and `softDeleteProperty` defaults to `deletedAt`. Chapter 5's callout matches reality. The runner's snapshot-1660 observation likely predates the current behavior. - #12 (cosmetic migration drift) — aligning the docs to the generator's uglier emitted shape is value-negative; either source can drift again in a future release. - #17 (silent `brew tap`) — `exit 0` with no output is brew convention; adding a "no output expected" note is noise. - #19 (chapter 6 Compare table renders as wall) — markdown source is well-formed GFM; if the rendered output is broken it's a build/CSS issue not a source issue. Investigate in a follow-up if reproducible. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 of 9 tasks
bpamiri
added a commit
that referenced
this pull request
Oct 3, 2026
…dobe 2023)
A quoted named argument in a direct call -- `c.URLFor("$argsResolved" = x)` --
is a compile error on Adobe CF 2023 (`MissingNameException`: "each parameter
must have a name"), which zeroed the entire adobe2023 matrix leg across every
database. Adobe misattributes it to the enclosing describe() line, and Lucee
6/7, BoxLang and Adobe 2025 all accept the quoted name, so Lucee-only local
verification missed it (invariant #16 family).
Build the args in a struct and pass them through argumentCollection, which
sidesteps named-argument-name parsing entirely and is byte-identical in effect.
Verified locally, view suite 608/0/0 on all three: adobe2023, adobe2025, lucee7
(Adobe containers restarted after the edit to clear cached classes).
Refs #4151
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
bpamiri
added a commit
that referenced
this pull request
Oct 5, 2026
* test(view): add the linkTo/URLFor differential gate for #4151 (passes on develop) Characterization spec that pins the exact output of a linkTo/URLFor corpus so the planned per-call cost reductions (de-dup $args, literal Replace in $urlForSubstituteVariables, lighter $tag) stay byte-identical. Two mechanisms: - End-to-end GOLDEN strings for engine-independent cases (deterministic URLs; $tag already sorts attributes alphabetically, so tag output is order-stable). These guard the de-dup-$args call-flow change and the $tag change, and assert the internal $argsResolved sentinel never leaks into output. - A verbatim REFERENCE COPY of $urlForSubstituteVariables with a sub-corpus that includes regex-backref values (\1, $1) in a pattern variable. That behaviour is engine-specific (the pattern has no capture groups), so the live function is asserted equal to the frozen reference on the running engine rather than a fixed golden. Guards the literal-Replace change. No production change yet; this is the gate the optimization commits must keep green. Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * perf(view): skip URLFor's redundant $args when linkTo already resolved them (#4151 W1) linkTo runs $args(name="linkTo") then calls URLFor, which ran $args(name="URLFor") again on the same struct — a second generic normalisation pass (the $get( "showErrorInformation") check and the empty reserved/required/combine loops). On Adobe that pass measured ~200us. URLFor gains a declared boolean $argsResolved param (default false). linkTo sets it true before calling URLFor. When set, URLFor skips the generic $args pass but STILL applies its own app-level defaults via structAppendDefaults(functions.URLFor), so set(functionName="URLFor", …) overrides keep reaching linkTo URLs. Declaring $argsResolved as a real argument keeps the sentinel out of the generated query string. Byte-identical: the differential gate now also asserts URLFor($argsResolved=true) equals URLFor($argsResolved=false) (incl. with an app-level override) and that the sentinel never appears in output. before/after (Lucee 7): linkTo 56 -> 54 us/call; the larger win is on Adobe, where the duplicated $args pass is far costlier. Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * perf(router): substitute URL placeholders with literal Replace instead of regex (#4151 W2) $urlForSubstituteVariables ran two regex operations per route variable — ReFind to test the `[prop]` / `[*prop]` placeholder presence and ReReplace to substitute the value. Route variable names are alphanumeric tokens with no regex metacharacters, so literal Find/Replace of the exact placeholder is equivalent and cheaper (the regex is the per-call hot spot on RustCFML and Adobe especially). Presence is now Find("[prop]") / Find("[*prop]"); substitution replaces the first matching literal placeholder with first-occurrence Replace (matching ReReplace's one scope). A value containing a backslash or `$` is kept on the ReReplace path, because those are regex-replacement metacharacters whose behaviour (no capture groups here) is engine-specific — the frozen reference-copy in the differential spec pins that per engine, and this fallback preserves it exactly. Byte-identical: the differential gate's $urlForSubstituteVariables reference-copy test (incl. \1 / $1 key values) stays green. before/after (Lucee 7): URLFor 26 -> 24, linkTo 54 -> 52 us/call; larger on RustCFML/Adobe where the per-variable regex is costlier. Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * perf(view): resolve the HTML-attribute encode flag once per tag, not per attribute (#4151 W3) $tag called $tagAttribute per attribute, and each $tagAttribute called $get("encodeHtmlAttributes"). $tag now resolves that flag once and passes it in; $tagAttribute gains an optional encodeHtmlAttributes argument and only falls back to $get when a caller omits it (not a signature default, so the $get is never evaluated at parse time). The attribute sort/ordering is unchanged. Byte-identical: the differential gate's $element goldens (5-attribute and skipStartingWith cases) stay green. before/after (Adobe 2023, where $get is costliest): $element 256 -> 235 us/call, linkTo 375 -> 354; flat on Lucee (its $get is ~free). Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(view): cover W2's wildcard/earliest-placeholder branch in the #4151 gate The reference-copy probes for $urlForSubstituteVariables were all plain [prop], so W2's literal-Replace path for wildcard [*prop] placeholders and its "replace the earliest of [prop]/[*prop]" branch had no oracle (rev1-r3). Add probes: a wildcard [*path] with a slash value (encode on and off), both [key] and [*key] in each order, and a wildcard value carrying a backslash (the ReReplace fallback). Each asserts the live $urlForSubstituteVariables equals the frozen develop reference on the running engine. Gate stays green on the W1+W2+W3 branch. Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(view): make the #4151 differential gate independent of ambient routes The full compat suite runs route-manipulating specs before this one, leaving the route table (and the application-scoped urlForCache) in a state the corpus did not expect — the matrix failed with "Could not find the `posts`/`editPost` route". Isolated runs passed because the default app routes were intact. Install a known route table in beforeEach ($clearRoutes + a mapKey wildcard and root, then $setNamedRoutePositions) and restore the real routes in afterEach, resetting the urlForCache around each test (mirrors linksSpec.cfc). Drop the url_route_root case: the named-route lookup is sensitive to route-cache state a redefined table doesn't fully rebuild here, and its pattern substitution is already covered by the $urlForSubstituteVariables reference-copy test. Verified: isolated 3/0/0, and the whole view suite 608/0/0 (so it is stable after linksSpec clears/redefines routes). Draft for 4.3 (#4151). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(view): restore every route-state struct in the linkTo/URLFor gate The differential spec's afterEach restored only application.wheels.routes, but beforeEach also mutates two sibling caches: $setNamedRoutePositions() *appends* into namedRoutePositions and mapper().end() rebuilds staticRoutes. Restoring only routes left those two dirty, so a later spec in the full suite inherited stale indices -- the same stale-index class this gate exists to catch. Snapshot and restore all three (routes + staticRoutes + namedRoutePositions) and clear all three in $clearRoutes(), mirroring linksSpec. Clearing namedRoutePositions before the append also makes URLFor(route="root") deterministic again, so url_route_root is restored to the golden corpus. Remove the url.capture debug branch. Verified on Lucee 7: view suite 608/0/0; full core suite 6516 pass with only pre-existing TestClient loopback-port artifacts (unrelated). Refs #4151 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * test(view): pass the $argsResolved sentinel via argumentCollection (Adobe 2023) A quoted named argument in a direct call -- `c.URLFor("$argsResolved" = x)` -- is a compile error on Adobe CF 2023 (`MissingNameException`: "each parameter must have a name"), which zeroed the entire adobe2023 matrix leg across every database. Adobe misattributes it to the enclosing describe() line, and Lucee 6/7, BoxLang and Adobe 2025 all accept the quoted name, so Lucee-only local verification missed it (invariant #16 family). Build the args in a struct and pass them through argumentCollection, which sidesteps named-argument-name parsing entirely and is byte-identical in effect. Verified locally, view suite 608/0/0 on all three: adobe2023, adobe2025, lucee7 (Adobe containers restarted after the edit to clear cached classes). Refs #4151 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * docs(changelog): add performance fragment for linkTo/URLFor overhead (#4151) Signed-off-by: Peter Amiri <peter@alurium.com> --------- Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The test suite should be looking for
wheels.Dispatchin case sensitiveenvironments.