Skip to content

COLDBOX-1457 Browser testing for ColdBox apps: BrowserTestCase and named route helpers - #708

Open
lmajano wants to merge 8 commits into
developmentfrom
claude/bx-playwright-research-plan-ddfqpm
Open

lmajano wants to merge 8 commits into
developmentfrom
claude/bx-playwright-research-plan-ddfqpm

Conversation

@lmajano

@lmajano lmajano commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Description

Jira Issues

COLDBOX-1457 (blocked by TESTBOX-470)

Browser testing for ColdBox applications, built on TestBox's new BrowserSpec support (Ortus-Solutions/TestBox#212) and the bx-playwright BoxLang module.

coldbox.system.testing.BrowserTestCase (BoxLang only)

  • Extends BaseTestCase, so the app loads for route lookups.
  • Delegates to TestBox's BrowserSupport:
    • browse(), this.playwright(), browserAvailable()
    • the @browserProfile and @baseURL annotations
    • the browser matchers, such as expect( page ).toSee( "Welcome" )
    • automatic attachment of screenshots, traces and videos
  • routeURL( name, params ): the path and query, built by ColdBox's own event.route().
  • visitRoute( page, name, params ) visits a named route.
  • assertRouteIs( page, name, params ) waits until the page is on that route. Without params it matches the route pattern; with params it matches the exact path.
  • Browser specs skip cleanly when TestBox browser support or bx-playwright is not installed; the route helpers still run.
  • Logged-in tests use bx-playwright saved sessions, with no test-only login endpoints in ColdBox:
    this.playwright().session( "admin", ( page ) => visitRoute( page, "login" ).fill( "Email", "admin@site.com" ).fill( "Password", "secret" ).click( "Sign in" ) )
    browse( ( page ) => visitRoute( page, "admin.dashboard" ), { session : "admin" } )

Fixes

  • event.route( "name@module" ) built links with no slash after the module entry point (bloglogin/3/). There is a unit test in RequestContextTest.
  • On Adobe, RequestContext.getMemento() included a this key, so RequestContextDecorator methods ran against the original context and missed its mocks. Regression specs in RequestContextDecoratorTest.

Harness and tests

  • Test-harness routes users.show, plus a plain login form (browserTesting.login) and browserTesting.whoami for the saved-session specs.
  • tests/runner.cfm skips the BoxLang-only /browser folder on other engines.
  • BrowserTestCaseSpec covers route paths (app and module routes, through the resourcesTest module), assertRouteIs(), a saved session created through the login form, and per-page session isolation.

Type of change

Checklist

🤖 Generated with Claude Code

https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi

claude added 4 commits October 1, 2026 11:58
event.route( "name@module" ) joined the module inherited entry point and the
route pattern without a separator, so "login@BrowserTesting" built
"__browser-testinglogin/3/". ModuleService stores inherited entry points
without a trailing slash, so the link now joins them with a single slash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
…dpoints

GET /__browser-testing/login/:id and GET /__browser-testing/logout call the
login and logout closures of moduleSettings.browserTesting. Every request
gets a plain 404 unless the environment is testing, the module is enabled,
a token is configured and matches the X-Browser-Testing-Token header or the
token variable (compared in constant time), and the closure is set. The
test harness enables it, and runs in its testing environment on 127.0.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
coldbox.system.testing.BrowserTestCase (BoxLang) extends BaseTestCase and
delegates to TestBox's BrowserSupport like BrowserSpec: browse(),
this.playwright(), browserAvailable(), the browserProfile and baseURL
annotations, the browser matchers and the afterAll closeBrowser() hook.
It adds routeURL(), visitRoute() and assertRouteIs() for named routes, and
loginAs() and logout() through the BrowserTesting core module.

The specs live in tests/specs/browser, which tests/runner.cfm skips on
engines other than BoxLang; the browser specs skip without bx-playwright.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Test Results

0 tests  ±0   0 ✅ ±0   0s ⏱️ ±0s
0 suites ±0   0 💤 ±0 
0 files   ±0   0 ❌ ±0 

Results for commit af17e82. ± Comparison against base commit 0a20ed3.

♻️ This comment has been updated with latest results.

…corator mocks on Adobe

BrowserTestCase registered testbox.system.browser.BrowserMatchers in its
pseudo constructor, so every runner.cfm request on BoxLang failed with a 500
on released TestBox builds that do not ship testbox.system.browser yet. It
now detects TestBox browser support, registers the matchers only when present,
and skips browser specs with a clear reason otherwise. The route helpers still
run.

RequestContext.getMemento() returned the `this` reference that Adobe keeps in
the variables scope. RequestContextDecorator restored it, so on Adobe the
decorator's inherited methods ran with `this` pointing to the original context
and mocked methods failed with "Element _MOCKRESULTS is undefined in THIS"
(BrowserTestingModuleSpec header token spec). The memento now leaves it out,
with regression specs in RequestContextDecoratorTest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi

lmajano commented Oct 1, 2026 •

Copy link
Copy Markdown
Member Author

CI status on 32e827b: the remaining red jobs are not caused by this PR.

These need a re-run of the failed jobs (runs 36863474898 and 36863469751). I don't have permission to re-run them (403), so a maintainer needs to. I'll keep watching the PR.


Generated by Claude Code

@lmajano lmajano changed the title Browser testing for ColdBox apps: BrowserTestCase, named route helpers and test-only loginAs() COLDBOX-1457 Browser testing for ColdBox apps: BrowserTestCase, named route helpers and test-only loginAs() Oct 1, 2026
claude added 2 commits October 1, 2026 15:08
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
The test-only login endpoints were a backdoor. Logged-in browser tests now
use bx-playwright saved sessions: log in through the login page once with
this.playwright().session(), then browse( ..., { session : "name" } ).

The test harness gets a plain login form for the saved session specs, and
goes back to its development environment on 127.0.0.1. Module route specs
use the resourcesTest module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
@lmajano lmajano changed the title COLDBOX-1457 Browser testing for ColdBox apps: BrowserTestCase, named route helpers and test-only loginAs() COLDBOX-1457 Browser testing for ColdBox apps: BrowserTestCase and named route helpers Oct 1, 2026
@lmajano
lmajano requested a balanced review from Copilot October 1, 2026 20:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Route helpers incorrectly skip without browser support and fail to match valid optional route variants.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds BoxLang browser testing support to ColdBox and fixes request-context routing/decorator regressions.

Changes:

  • Introduces BrowserTestCase with browser and named-route helpers.
  • Adds browser harness routes, fixtures, and integration coverage.
  • Fixes module route joining and decorator memento handling.
File Description
AGENTS.md Documents BoxLang annotation and optional-value conventions.
changelog.md Records the feature and fixes.
system/​testing/​BrowserTestCase.bx Implements browser and route-testing helpers.
system/​web/​context/​RequestContext.cfc Fixes module links and memento copying.
test-harness/​config/​Router.cfc Registers browser-test routes.
test-harness/​handlers/​browserTesting.cfc Provides browser-test pages and login flow.
tests/​resources/​browser/​FakePage.bx Adds a browser-independent page test double.
tests/​runner.cfm Excludes BoxLang browser specs on other engines.
tests/​specs/​browser/​BrowserTestCaseSpec.bx Covers browser and route helpers.
tests/​specs/​web/​context/​RequestContextDecoratorTest.cfc Tests decorator scope isolation.
tests/​specs/​web/​context/​RequestContextTest.cfc Tests module route slash handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread system/testing/BrowserTestCase.bx Outdated
Comment thread system/testing/BrowserTestCase.bx Outdated
- visitRoute() no longer skips the spec without browser support: it only
  visits the page it gets, and pages come from browse(), which skips.
- assertRouteIs() matches every route registered with the name, so a route
  with optional placeholders (/posts/:id?, registered as /posts/:id and
  /posts) matches with and without them. Module routes use the module
  routing table.
- The harness login form renders the logged-in page instead of relocating:
  the harness runs with the test controller, which intercepts relocations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU9aLossoYUkQNwubnitBi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants