Skip to content

Fix QAN search page-object race with debounced search - #1189

Closed
claude[bot] wants to merge 1 commit into
mainfrom
claude/elegant-cerf-8jss69
Closed

Fix QAN search page-object race with debounced search#1189
claude[bot] wants to merge 1 commit into
mainfrom
claude/elegant-cerf-8jss69

Conversation

@claude

@claude claude Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Failures fixed (investigator)

  • source: Nightly E2E tests Matrix run 31916469379 (main @ 37a003d, server perconalab/pmm-server:3-dev-latest), job test execution / @qan|@menu|@valkey-nightly|@permissions-nightly|@pt-summary-nightly|@pbm-nightly. Same two tests also failed in the previous night's run (31852756475) — not a one-off.
  • tests:
    • codeceptjs-e2e/tests/QAN/details_explain_test.js / @qan — PMM-T1790 "Verify that there is any no error on Explains after switching between queries from different DB servers"
    • codeceptjs-e2e/tests/QAN/overview_test.js / @qan — PMM-T1061 "Verify Plan and PlanID with pg_stat_monitor"

What failed

Both tests died on the same page-object step, with the same error:

Clickable element "//input[contains(@name, "search")]" was not found by text|CSS|XPath
  ✖ I.click("//input[contains(@name, "search")]")  at QueryAnalyticsData.searchByValue (queryAnalyticsData.js:158:7)
  ✔ I.clearField("//input[contains(@name, "search")]")                              (:157)
  ✔ I.wait(1)                                                                        (:156)
  ✔ I.waitForVisible("//input[contains(@name, "search")]", 30)                        (:155)

The input is visible at :155 and gone by :158.

Root cause — a race in our page object, not the product

QAN Overview search is search-as-you-type (debounced) since PMM-14848 / percona/pmm#5537.

searchByValue(value) {
  I.waitForVisible(this.elements.queryRow(0), 30);
  I.waitForVisible(this.fields.searchBy, 30);
  I.wait(1);
  I.clearField(this.fields.searchBy);   // -> empty search -> Overview panel reloads
  I.click(this.fields.searchBy);        // <- panel is mid-reload; input is unmounted
  ...

I.clearField fires a change on the debounced field, which kicks off an empty-search reload of the Overview panel. The panel unmounts the search input while it reloads. I.click (proceedClickassertElementExists) asserts existence without waiting for it, so if it lands inside that window it fails immediately.

Whether it lands there is purely a matter of how long the reload takes. Codecept's waitForAction: 500 sits between the two steps, so a reload shorter than ~500 ms is invisible and a longer one is fatal — which is why this is deterministic on the nightly (14 client shards feeding one server) and invisible on a small setup.

Evidence — throwaway Linode VM, PMM 3.9.1-v3-0c89674a1 (3-dev-latest), Chrome 151.0.7922.34 (same as CI)

Setups: --database ps --database psmdb --database pdpgsql (the services these two specs filter on: ps-dev, mongodb, pdpgsql_pmm).

1. The unmount is real. Instrumented the DOM across a clearField on an idle server — the input detaches for ~200 ms:

search inputs before clear: 1
search input EVER detached after clear: true (~200ms)

~200 ms is under waitForAction: 500, so both specs pass individually on an idle box — exactly why this doesn't show up in light environments.

2. With a CI-like reload duration it fails deterministically. Same page, same session, POST /v1/qan/metrics:getReport delayed 3 s, replaying both step sequences verbatim (clearField = fill(''), click = existence assert with no wait, waitForAction: 500 between steps):

OLD  clearField -> click     : found=0 -> FAIL: ElementNotFound (== CI)
NEW  click -> fillField      : found=1 -> pass (value="SELECT * FROM")

3. Unforced reproduction + no regressions. Full @qan tag run twice on the same VM, back to back, main vs this branch:

passed failed
main (37a003d) 45 18
this branch 47 16

Failing-test diff:

  • fixed by this change: PMM-T1790 (@qan), PMM-T215 (@qan)
  • regressions: none
  • unchanged: 16, all from the 11 client setups this VM doesn't have (pgsql_pgss_pmm, mysql_pmm_, pxc_node__1, pxc-dev-cluster, pagination counts) — identical on both runs

The main run failed PMM-T1790 with the CI error verbatim, at queryAnalyticsData.js:158, with no throttling involved.

The fix

Don't clear before clicking. Click the already-loaded grid first and let I.fillField clear-and-type (Playwright fill clears the field) — one debounce cycle instead of two, and no click against a reloading panel. Settle with waitForLoaded() afterwards, and apply the same settle to clearSearchValue().

Notes

  • This restores commit 0b2c040, written during the 3.9.0-rc dry-run and described in RC dry-run test fixes: QAN search race + RC CLI version resolution #1184 — that branch was later rewritten and the commit is no longer in it, so nothing on main or in any open PR carries the fix.
  • PMM-T1061 passed in both full runs on this VM (it is the more load-sensitive of the two: its failing search comes after resetAllFilters()). It fails in CI with the identical error at the identical page-object line, and evidence 2 reproduces its exact failure deterministically. Only the next real nightly can confirm it end-to-end under the full 14-shard load.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dtd6vCp2nyWfx2T8VdfnJj


Generated by Claude Code

The QAN Overview search became search-as-you-type (debounced) in
PMM-14848 (percona/pmm#5537). searchByValue()/click() cleared the field
before clicking it, which kicks off an empty-search reload of the
Overview panel; the panel unmounts the search input while it reloads, so
the immediately following I.click() -- which asserts existence without
waiting for it -- fails with ElementNotFound (PMM-T1061, PMM-T1790, and
any @qan spec that searches).

Click the already-loaded grid first and let I.fillField clear+type
(Playwright fill clears the field), then wait for the panel to settle.
Apply the same settle to clearSearchValue().

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dtd6vCp2nyWfx2T8VdfnJj
Signed-off-by: Claude <noreply@anthropic.com>
@travagliad travagliad closed this Aug 16, 2026
@travagliad
travagliad deleted the claude/elegant-cerf-8jss69 branch August 16, 2026 09:44
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