Skip to content

Fixes 31518: Stabilize Data Quality and Incident Manager tests - #31519

Open
shah-harshit wants to merge 4 commits into
mainfrom
diagnose-flaky-ui-tests
Open

Fixes 31518: Stabilize Data Quality and Incident Manager tests#31519
shah-harshit wants to merge 4 commits into
mainfrom
diagnose-flaky-ui-tests

Conversation

@shah-harshit

@shah-harshit shah-harshit commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes #31518

This PR stabilizes two independent Playwright flakes in the Data Quality and Incident Manager suites. Both failures came from synchronizing on an event weaker than the product state the test intended to verify:

  1. The pagination test clicked a hover-triggered page-size control.
  2. The Incident Manager test treated completion of the assignment write as proof that both the target row and the search-backed filtered listing had converged.

No product behavior or API contract changes. The patch only makes the existing tests interact with the real UI contract and wait for the exact observable state.

Root cause analysis

1. Data Quality pagination page-size dropdown

Failure signature

locator.waitFor: Timeout 5000ms exceeded
waiting for locator('.ant-dropdown-menu') to be visible

The failure happened after the page-size trigger was clicked. The captured DOM showed the page-size button as active, but no visible dropdown menu was mounted during the fixed five-second window.

Product interaction contract

The pagination component wraps the page-size button in Ant Design Dropdown without an explicit trigger: NextPrevious.tsx lines 125-144.

  • Without an explicit trigger, the component uses the hover interaction.
  • The nested button's click handler only calls preventDefault().
  • A click therefore does not itself satisfy the component contract. It opens the menu only if the pointer movement around that click happens to produce the required hover state.

The original test clicked the trigger and then waited on the broad .ant-dropdown-menu selector with a hard five-second timeout: original DataQuality.spec.ts lines 1460-1474.

This was flaky for two independent reasons:

  • It relied on incidental pointer hover generated around a click instead of deliberately performing the configured interaction.
  • .ant-dropdown-menu can match Ant menus that remain mounted but hidden, so it did not uniquely identify the popup associated with this trigger.

A controlled repetition reproduced the original failure after four successful iterations. That pass/pass/pass/pass/fail pattern is consistent with an input-event race, not a consistently slow render.

Fix

The corrected flow is at DataQuality.spec.ts lines 1460-1474:

  1. Assert that the page-size trigger is visible.
  2. Use hover(), matching the component contract.
  3. Scope the menu to .ant-dropdown:not(.ant-dropdown-hidden) so only the visible popup is considered.
  4. Use Playwright's web-first visibility assertion instead of a manually constrained five-second waitFor.
  5. Count semantic menuitem roles within the visible popup.

The explanatory comment for the non-obvious hover behavior is at lines 1468-1471.

Increasing the original timeout would only give an incorrect click interaction more time; it would not guarantee that the hover-triggered menu opens.

2. Incident Manager assignee filter

This failure had two original synchronization defects, followed by one authentication defect exposed by the first version of the index-polling fix.

2a. The post-assignment assertion targeted the wrong incident row

The assignment helper identifies the target row by test-case identifier before opening its editor: incidentManager.ts lines 177-185.

The original post-write assertion then discarded that identity and read page.getByTestId('assignee').first(): original incidentManager.ts lines 254-272.

On a multi-row Incident Manager listing, the first assignee is not necessarily the incident just updated. If the first unrelated row is unassigned, the assertion receives No Assignee even when the target assignment succeeded. The previous global owner-link.first() wait had the same problem: it proved only that some owner link existed somewhere on the page.

The helper now preserves target identity and reads the assignee within the exact incident row: incidentManager.ts lines 258-275. The 30-second web-first assertion permits that row to re-render after the acknowledged update without a blind sleep. The reason for row scoping is documented at lines 261-269.

2b. The assignment write completed before the search listing converged

Assignment waits for the task-resolution POST response: task.ts lines 60-65, consumed at incidentManager.ts lines 254-256.

That response acknowledges the write side. The assignee filter reads from /api/v1/dataQuality/testCases/testCaseIncidentStatus/search/list?assignee=..., so it observes the asynchronously updated search document. A successful task transition does not guarantee that the updated assignee is already searchable.

The original filter flow waited for exactly one search response and immediately asserted its rows: original IncidentManager.spec.ts lines 1081-1090. If that first request reached search before indexing completed, it returned a valid but stale result. Waiting longer on an already completed response cannot make its payload current.

Why the existing helper needed to be extended

waitForIncidentToBeIndexed already existed, but before this PR it called the database-backed incident endpoint: original dataQuality.ts lines 577-611.

The two server routes have different consistency boundaries:

Therefore, the unchanged helper could return as soon as the database row existed while Incident Manager's search document still contained the prior assignee. A generic search-presence check would also be insufficient: document existence does not prove that the assignee transition has been indexed.

The extended helper polls the same search-backed route and verifies the exact FQN, status, and nested assignee: dataQuality.ts lines 569-638.

It now:

  1. Calls /testCaseIncidentStatus/search/list.
  2. Filters by the exact test-case FQN.
  3. Retains the bounded event window and 60-second polling budget.
  4. Optionally filters and verifies resolution status.
  5. Optionally filters and verifies assignee.
  6. Uses updatedAt for assignee transitions because they update an existing incident whose original timestamp remains unchanged.
  7. Rejects non-success responses instead of trying to parse them as incident data.
  8. Verifies the returned source rather than trusting query parameters alone.

2c. Follow-up CI failure: the index poll was unauthenticated

The first implementation passed page.request to the extended helper. The subsequent ingestion CI failure timed out in waitForIncidentToBeIndexed with Expected: true / Received: false.

Inspection of the failed job's server diagnostics provided an artifact-level reproduction without rerunning the test: failed ingestion job.

The relevant request sequence was:

14:28:04 POST /api/v1/tasks/<task-id>/resolve                                      200
14:28:04 GET  /api/v1/dataQuality/testCases/testCaseIncidentStatus/stateId/<id>   200
14:28:04 GET  /api/v1/dataQuality/testCases/testCaseIncidentStatus/search/list?... 401
14:28:05 GET  /api/v1/dataQuality/testCases/testCaseIncidentStatus/search/list?... 401
...
14:29:02 GET  /api/v1/dataQuality/testCases/testCaseIncidentStatus/search/list?... 401

The retry repeated the same pattern from 14:31:50 through 14:32:49. Every poll returned HTTP 401 with a 58-byte response. This rules out an index query mismatch as the cause of this particular timeout: the helper never reached the search read at all.

The application stores its JWT in browser local storage. Browser-originated API calls inject that bearer token, but the request made through page.request did not inherit it. The repository's authenticated context explicitly reads the page token and adds Authorization: Bearer <token>: common.ts lines 58-76, wrapped by getApiContext(page) at common.ts lines 294-305.

The corrected test now:

  1. Completes the UI assignment.
  2. Creates an authenticated API context from the current page token.
  3. Reuses waitForIncidentToBeIndexed with Assigned + <username>.
  4. Disposes the temporary context in finally.
  5. Applies the UI assignee filter only after the exact indexed state is observable.

This sequence is at IncidentManager.spec.ts lines 1063-1104. The authentication rationale is documented inline at lines 1073-1076.

The original product race is still a search-index propagation issue, so the existing helper remains the right synchronization primitive after extending it to verify the indexed assignee. The follow-up CI failure was in how that helper was called, not evidence that the indexing diagnosis was wrong.

Why these failures were flaky

Failure State that varied between runs Incorrect synchronization
Data Quality page-size menu Whether click/pointer processing incidentally produced Ant Dropdown's hover state A click followed by a fixed five-second wait
Incident row assignee Which incident appeared first and whether the target row had rerendered A global assignee.first() assertion
Incident assignee filter Whether search consumed the assignment before the first filtered GET Waiting for one HTTP response regardless of its data
Follow-up index poll Not an index race: every helper request lacked authorization Retrying HTTP 401 as if it meant “not indexed yet”

Scope and risk

  • Test-only changes; no production UI, API, database, or search behavior is modified.
  • Existing expectations remain unchanged: three page-size options and the selected assignee must be visible.
  • Index polling is bounded and scoped to the exact test case, status, and assignee.
  • The poll now uses the same authenticated API-context pattern already established in the spec.
  • The temporary context is always disposed.
  • Locators are narrower and identify the visible menu or exact incident row.
  • No new dependency is introduced.

Type of change:

  • Bug fix

High-level design:

The tests synchronize on observable business state:

  • UI interaction uses the component's configured trigger and visible popup.
  • List assertions retain the target incident identity.
  • Search-backed assertions wait through an authenticated request for the exact target-assignee association, then refetch the filtered UI.

Tests:

Use cases covered

  • Test-case pagination exposes all three page-size choices from the visible page-size menu.
  • Incident assignment verifies the assignee on the incident actually updated.
  • Incident Manager assignee filtering tolerates bounded search-index propagation delay.
  • The helper returns immediately when the indexed assignment is already current.
  • The helper call is authenticated using the current page's bearer token.

Unit tests

  • Not applicable — Playwright-only change.

Backend integration tests

  • Not applicable — no backend changes.

Ingestion integration tests

  • Not applicable — no ingestion changes.

Playwright (UI) tests

  • Updated existing Playwright scenarios.
  • Initial investigation reproduced the pagination failure after four successful iterations.
  • The follow-up Incident Manager failure was reproduced from CI request logs: assignment/state reads returned 200, while every helper poll returned 401.
  • Post-fix Playwright execution was not run per request.

Static validation performed

  • UI organize-imports completed for all changed Playwright files.
  • ESLint completed with zero errors; two expected multi-user-login warnings are outside the changed lines.
  • Prettier completed successfully.
  • git diff --check passed.
  • The repository-wide Playwright TypeScript check reports existing baseline errors in unrelated files; it produced no diagnostic for the changed files.

UI screen recording / screenshots:

Not applicable — no product UI behavior changed.

Checklist:

  • I have read the contribution guidelines.
  • My PR title follows the required format.
  • I have linked the related issue.
  • I have updated existing tests that prove the corrected synchronization behavior.

Bug fix:

  • I have updated the tests to cover the corrected synchronization behavior.

@shah-harshit shah-harshit added UI UI specific issues safe to test Add this label to run secure Github workflows on PRs skip-pr-checks Bypass PR metadata validation check labels Aug 14, 2026
@shah-harshit shah-harshit self-assigned this Aug 14, 2026
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

✅ Playwright Results — workflow succeeded

Validated commit e3e0516832e1308898acccd1775a57ddb69d0fa7 in Playwright run 31812385168, attempt 1.

✅ 772 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 0 skipped · 🧰 0 lifecycle flaky

Performance

Blocking targets: ✅ met · Optimization targets: 🟡 in progress

Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting.

🕒 Full workflow signal wall (to summary) 51m 28s

⏱️ Max setup 3m 3s · max shard execution 18m 4s · max shard-job elapsed before upload 21m 25s · reporting 6s

🌐 212.77 requests/attempt · 2.64 app boots/UI scenario · 4.34% common-shard skew

Optimization targets still in progress:

  • Browser traffic was 212.77 requests per attempt (convergence target: fewer than 200).
  • Application boot ratio was 2.64 per UI scenario (2154 boots / 816 scenarios; convergence target: at most 1).
Shard Passed Failed Flaky Skipped Lifecycle failed Lifecycle flaky
✅ Shard chromium-01 145 0 0 0 0 0
✅ Shard chromium-02 133 0 0 0 0 0
✅ Shard chromium-03 144 0 0 0 0 0
✅ Shard chromium-04 139 0 0 0 0 0
✅ Shard data-asset-rules-01 61 0 0 0 0 0
✅ Shard domain-isolation-01 14 0 0 0 0 0
✅ Shard global-state-01 34 0 0 0 0 0
✅ Shard import-export-01 26 0 0 0 0 0
✅ Shard ingestion-01 32 0 0 0 0 0
✅ Shard reindex-01 5 0 0 0 0 0
✅ Shard search-01 10 0 0 0 0 0
✅ Shard search-rbac-01 29 0 0 0 0 0

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

@gitar-bot

gitar-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Stabilizes flaky Data Quality and Incident Manager Playwright tests by replacing unreliable click triggers and global assertions with proper hover interactions and search-index polling. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs skip-pr-checks Bypass PR metadata validation check UI UI specific issues

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Fix flaky Data Quality pagination and Incident Manager filter tests

2 participants