Skip to content

fix(e2e): modernize Playwright selectors for the Tailwind frontend - #5615

Merged
norman-abramovitz merged 4 commits into
cloudfoundry:developfrom
nabramovitz:norm/fix/e2e-selector-modernization
Jul 11, 2026
Merged

fix(e2e): modernize Playwright selectors for the Tailwind frontend#5615
norman-abramovitz merged 4 commits into
cloudfoundry:developfrom
nabramovitz:norm/fix/e2e-selector-modernization

Conversation

@nabramovitz

Copy link
Copy Markdown
Contributor

What

The Playwright e2e suite was mass-failing: every application/CF test timed out at waitForPage. The page objects still targeted Material-era selectors that the Tailwind modernization removed or turned into zero-height CDK portal sources (app-page-header, app-page-tabs, mat-tab-group, mat-dialog-container, ...). The failures were load-independent — the app rendered fine; the tests were looking at elements that can never become visible.

Changes

Page objects & shared components — re-point at the rendered DOM:

  • header/title → app-show-page-header (portal target), tabs → app-page-side-nav
  • shared pageTab() matcher that matches the tab label span exactly (link text includes the icon ligature, and substring matching collides on "Services" vs "User Services")
  • page actions → .page-header-sub-nav, confirm dialog → app-dialog-confirm
  • create-route and map-existing-route both live on the routed Add Route page now; the map flow drives the data-test="available-routes" list with filter-first radio selection
  • add the waitForPage() the org/space specs already call

Specs — sweep the inline copies: mat-dialog-container[role="dialog"] (~60 refs), dead component anchors → real ones, row actions opened via the more_vert menu, fixed sleeps replaced with waits on real state transitions, extended click timeouts where the "Retrieving…" loading overlay races actionability.

Test infra — three latent bugs found while verifying:

  • the cfApi fixture teardown label-swept all stratos-e2e-test apps after every test, deleting parallel workers' apps mid-test (source of most "random" flakes at 2+ workers)
  • unmapRoute() passed the app guid where CF v3 expects the destination guid — it always 422'd and was swallowed by .catch()
  • API request contexts inherited the 10s actionTimeout; CF writes regularly exceed that under load → explicit 30s, plus one retry on CC's intermittent destination-write 500s

Verification

application-routes @2 workers against a live dev stack (4 CF endpoints): 26 passed / 2 failed / 4 skipped, up from 0 passing before the series. The 2 remaining failures are a single map-existing-route flow (Create after radio selection), tracked as follow-up work along with running the CF org/space suites against these page objects.

Notes for reviewers

  • All changes are under e2e/; no product code touched.
  • Selector choices were harvested from the live rendered DOM (the templates hide most of this behind portals), then verified by the runs above.
  • Draft until the map-existing flow follow-up lands and the CF-level suites get a verification run.

The CF API helper's proxied reads/writes were hitting the backend
without the passthrough headers, so every proxied call returned 400.
Route the 42 proxy operations through pget/ppost/ppatch/pdelete wrappers
that set cfApiBase=/pp/v1/proxy/v3 and inject x-cap-cnsi-list plus
x-cap-passthrough: true; /api/v1/endpoints stays a plain call.

getDomains queried /v3/domains?space_guids= — CF v3 has no such filter,
so it 400'd. Resolve the space's org and query
/v3/organizations/:org/domains instead.

request.helper get/post/patch/delete now take optional extraHeaders, and
error throws append the CF response body so 400/422 reasons are visible
instead of hidden.
The Material-era selectors no longer exist in the rendered DOM:
app-page-header and app-page-tabs are CDK portal sources whose host
elements render zero-height, so every waitFor(visible) timed out and
the whole suite mass-failed before reaching any assertion.

Re-point to where content actually renders:
- header/title: app-show-page-header (h1 projected via portal)
- tabs: app-page-side-nav side-nav links; shared pageTab() matcher
  matches the label span exactly, since link text includes the icon
  ligature and substring matching collides (Services vs User Services)
- page actions: .page-header-sub-nav (buttons portal out of the
  action-bar host, which is hidden for stopped apps)
- confirm dialog: app-dialog-confirm
- create/map route: both flows live on the routed Add Route page;
  route-map-dialog now drives its available-routes list (data-test
  hooks) with a filter-first radio selection
- add missing waitForPage() to org/space page objects (specs call it;
  Playwright strips types unchecked so this only failed at runtime)
Sweep the spec-inline copies of dead Material selectors:
- mat-dialog-container -> [role="dialog"] (the Tailwind dialog
  service renders a plain div panel; ~60 references suite-wide)
- mat-tab / mat-nav-list -> side-nav items and their active class
- app-application-page / app-applications-list -> components that
  exist (app-page-side-nav anchor, app-application-wall)
- host/port inputs -> formcontrolname (placeholder matching is
  case-sensitive and never matched "Host")

Flow updates for the modernized routes tab:
- row actions (unmap/delete) moved behind the more_vert menu; open
  it before locating the action button
- replace fixed sleeps after create/map with waits on the Add Route
  stepper closing, and nudge a list refresh when the routes list
  comes back cached
- clicks that race the "Retrieving..." loading overlay get an
  extended timeout so actionability retry outlasts it
Three test-infra bugs surfaced while verifying the selector work:

- The cfApi fixture teardown ran cleanupTestResources() after every
  test, label-sweeping ALL stratos-e2e-test apps on the CF — including
  a parallel worker's app mid-test. At 2+ workers this randomly
  deleted apps under running tests (redirects to the app wall,
  "app does not exist" on fixture calls, constant cleanup 404
  noise). Fixtures already delete their own resources by guid, so
  drop the per-test sweep.

- unmapRoute() passed the app guid where the CF v3 API expects the
  destination guid; the call always failed 422 and was swallowed by
  .catch() at most call sites. Look up the destination for the app
  and delete by its guid.

- API request contexts inherited the 10s actionTimeout; CF writes
  (app create) regularly exceed that under load. Set an explicit 30s
  context timeout, and retry once on CC's intermittent 500s on
  destination writes.

Result on application-routes @2 workers: 26 passed / 2 failed
(remaining failures are one map-existing-route flow, tracked
separately), up from 0 passing before the series.
@norman-abramovitz
norman-abramovitz marked this pull request as ready for review July 11, 2026 15:52

@norman-abramovitz norman-abramovitz 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.

LGTM - First Phase

@norman-abramovitz
norman-abramovitz merged commit efddb13 into cloudfoundry:develop Jul 11, 2026
18 checks passed
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.

2 participants