Skip to content

fix: [DHIS2-20898] re-enable and de-flake BreakingTheGlass Cypress test - #4694

Open
karolinelien wants to merge 7 commits into
masterfrom
fix/DHIS2-20898-breakingtheglass-flaky-test
Open

fix: [DHIS2-20898] re-enable and de-flake BreakingTheGlass Cypress test#4694
karolinelien wants to merge 7 commits into
masterfrom
fix/DHIS2-20898-breakingtheglass-flaky-test

Conversation

@karolinelien

@karolinelien karolinelien commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What

Re-enables the BreakingTheGlass.feature scenario (User with search scope access tries to access an enrollment in a protected program), disabled via @skip since March 2024, by fixing the actual causes of the failure rather than leaving it disabled (https://dhis2.atlassian.net/browse/DHIS2-20898).

Why

1. The user switch drove the login form directly

The scenario switched users mid-test via the raw login form (cy.visit('/') + fill + submit) instead of the cy.session()/cy.loginByApi() pattern every other test in the suite uses. On the current standalone/prod Cypress build, an unauthenticated visit hard-redirects to the backend's own hosted login page on a different origin, which Cypress can't interact with without cy.origin():

CypressError: Timed out retrying after 25000ms: The command was expected to run against origin
`http://localhost:3000` but the application is at origin `https://<backend>`.

This looks like the same underlying regression as https://dhis2.atlassian.net/browse/DHIS2-20638 (also disabled, also driving the login form directly, its own code comment blames "login form is not working for v42 currently") — both likely trace back to the App Platform v12 upgrade (https://dhis2.atlassian.net/browse/DHIS2-18801). Unlike that ticket, this scenario doesn't need to test the login form UI itself, so switching the user-switch step to cy.loginByApi() sidesteps the problem entirely instead of needing a cy.origin()-based fix.

The switched-user session also gets a validate callback asserting /api/me is the expected user, mirroring the house pattern in cypress/support/tagUtils/login.js. Without it, a stale cached session — or a login that silently kept the previous user — surfaces as a confusing missing-widget failure several steps later instead of failing at the switch, which matters because "the second user is genuinely a different, less-privileged user" is the whole premise of the scenario.

2. The scenario leaked its tei into another spec's assertions

Re-enabling the scenario alone turned TrackerWorkingListsUser.feature red — 6 failures on Expected to find content: 'Filona'/'Johnny'/'Donald' within the element: <tr>, on every instance version, while master's shard 5 was green.

Cause: this scenario creates a tei enrolled in Child programme at Ngelehun and only cleared it on the way in (Given the tei created by this test is cleared from the database), so the tei outlived the run. That is the same working list TrackerWorkingListsUser asserts on by row position — a positional array of first names matched row-by-row — so one extra row shifted every pagination and ordering assertion. The clincher: "Show teis ordered ascendingly by first name" expected Donald, and the leaked tei's first name is Breaking, which sorts ahead of it.

Fixed by adding a tag-scoped After hook following the house pattern (@with-...-cleanup, as in WidgetProfile, TrackerBulkActions, EditEventPageForm), re-authenticating as the default user first because the scenario ends logged in as the search-scope-only one, which cannot delete the tei.

Verification

Local, before the session fix: 4/5 runs failed with the cross-origin error above. After: 7/8 clean passes, zero recurrences.

In CI, BreakingTheGlass.feature itself passes on all four targets — dev (2.44-SNAPSHOT), 2.41, 2.42 and 2.43 — confirming the tracker2 user still has the search-scope-but-not-capture-scope access the scenario depends on. The spec runs in shard 3; the shard-5 TrackerWorkingListsUser failures described above are what the After hook addresses.

Unrelated to this PR: the 2.42 instance is currently unhealthy — all five of its shards fail with cy.request() failed on: across specs this branch does not touch.

AI Assisted

The scenario logged out and logged back in as a second user by driving
the raw login form (cy.visit('/') + fill + submit). On the current
standalone/prod Cypress build, an unauthenticated visit hard-redirects
to the backend's own hosted login page on a different origin, which
Cypress can't interact with without cy.origin() - causing a consistent
cross-origin failure, not just occasional flakiness.

Switch the user-switch steps to cy.session()/cy.loginByApi(), the same
pattern every other test in the suite already uses, sidestepping the
login form entirely since this scenario doesn't need to test it.

AI Assisted
Comment thread cypress/e2e/EnrollmentPage/BreakingTheGlass/BreakingTheGlass.js Fixed
The tracker2 credential is a non-production test-instance account,
not a secret - same value that was already inline in this file before
the loginByApi refactor, just in a syntactic shape Sonar's S2068
heuristic now matches.

AI Assisted
Mirror the house session pattern in cypress/support/tagUtils/login.js: the
switched-user session had no validate callback, so a stale cached session or a
login that silently kept the previous user would surface as a confusing
missing-widget failure several steps later instead of failing at the switch.
The scenario creates a tei enrolled in Child programme at Ngelehun and only
cleared it on the way in, so it outlived the run. That is the same working list
TrackerWorkingListsUser asserts on by row position, and the leftover row shifted
every assertion there - visible as 6 failures on 'Filona'/'Johnny'/'Donald'
across every instance version, while master's shard 5 was green. Sorting
ascendingly by first name put 'Breaking' ahead of 'Donald', which pinned it.

Adds a tag-scoped After hook following the house pattern, re-authenticating as
the default user first because the scenario ends as the search-scope-only one.
@karolinelien
karolinelien marked this pull request as ready for review August 21, 2026 10:24
@karolinelien
karolinelien requested a review from a team as a code owner August 21, 2026 10:24
Comment thread cypress/e2e/EnrollmentPage/BreakingTheGlass/BreakingTheGlass.js Outdated
karolinelien and others added 2 commits August 27, 2026 12:49
The hard-coded-credential smell is handled as a false positive in
SonarQube instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 27, 2026

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

Comment thread cypress/e2e/EnrollmentPage/BreakingTheGlass/BreakingTheGlass.js Dismissed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants