Skip to content

Flaky CI: sharded-jest-tests (4) — ControlPanelsContainer.test.tsx "renders ControlPanelSections" (un-awaited userEvent.click after user-event v14) #44314

Closed

Description

@SEPURI-SAI-KRISHNA

Bug description

Since @testing-library/user-event was bumped from 12.8.3 to 14.x in #43512 (merged 2026-09-12), sharded-jest-tests (4) intermittently fails in superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx:

● ControlPanelsContainer › renders ControlPanelSections

  expect(received).toHaveLength(expected)

  Expected length: 5
  Received length: 4

The four headers received are the Data tab's sections (GROUP BY, NOT GROUPED BY, Query, and an unlabeled one): the Customize tab's section never rendered before the assertion gave up.

Failures seen, all on shard 4, all on 2026-09-14:

Branch Job
master https://github.com/apache/superset/actions/runs/34872184919/job/104072150381
feature-canvas-filter https://github.com/apache/superset/actions/runs/34792812860/job/103821930836
sc-120488-starting-version-row https://github.com/apache/superset/actions/runs/34894590802/job/104146817041

That is 3 of roughly 214 Frontend Build CI runs that day, on unrelated changes.

Cause. Line 142 calls userEvent.click(...) without await:

userEvent.click(screen.getByRole('tab', { name: /customize/i }));
await waitFor(() => {
  expect(screen.getAllByTestId('collapsible-control-panel-header')).toHaveLength(5);
});

Under user-event 12 click was synchronous, so this was fine. Under 14 every API call returns a promise and dispatches its pointer events across setTimeout yields (delay: 0), wrapped in RTL's asyncWrapper. Without the await, waitFor starts while the click is still being dispatched, so the click's own dispatch time is taken out of waitFor's default 1000 ms budget. Instrumenting the test locally:

click resolves waitFor polls
no await (current) +100 ms, during waitFor 4
await +81 ms, before waitFor starts 1

#43512 updated 114 test files for the v14 API but not this one (last touched in #40229).

Screenshots/recordings

No response

Superset version

master / latest-dev

Python version

N/A (frontend test)

Node version

18 or greater (CI: 24.16.0)

Browser

Not applicable

Additional context

I could not force the failure locally: the unmodified test passed 12/12 runs under full CPU load, and CI shard 4 (npm run test -- --coverage --shard=4/8) passed 3/3 runs pinned to 4 cores. The evidence is the CI history above plus the timing measurement.

Precedent for the same class of fix: #35918, #35993.

Checklist

  • I have searched Superset docs and Slack and didn't find a solution to my problem.
  • I have searched the GitHub issue tracker and didn't find a similar bug report.
  • I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.

Activity

  1. kokhlo commented on Sep 15, 2026

    @kokhlo
    Contributor

    Confirming the RCA on current master: superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx line 142 is the file's only userEvent call and it is still un-awaited. After #43512 every user-event API returns a promise and dispatches pointer events across delay: 0 yields inside RTL's asyncWrapper, so an un-awaited click runs its dispatch inside waitFor's 1000 ms budget — exactly the "4 headers, Customize never rendered" shape in the CI runs above. #43512 updated 114 files for the v14 API but missed this one (last touched in #40229).

    Plan: add the missing await on line 142, matching the convention the rest of the suite already uses after #43512 and the precedent fixes #35918 / #35993. One-line diff, no behavior change beyond letting the click finish before the assertion starts polling. PR within the hour.

  2. kokhlo commented on Sep 15, 2026

    @kokhlo
    Contributor

    Correction to my comment above: #44315 landed while I was still verifying the file on master — it was opened before my claim, so please treat that claim as withdrawn. No competing PR from me.

    I checked the #44315 diff against master: it adds exactly the missing await on the line 142 userEvent.click, which is the file's only userEvent call — nothing else in the file needs the v14 treatment. That is the complete fix for this flake; happy to review it.

  3. SEPURI-SAI-KRISHNA commented on Sep 15, 2026

    @SEPURI-SAI-KRISHNA
    ContributorAuthor

    Thanks for independently confirming the RCA, and for the review offer, appreciated.

  4. mikebridge commented on Sep 15, 2026

    @mikebridge
    Contributor

    Correction (2026-09-17): My two local observations below did not establish an upstream regression or a user-event root cause. I retract the broader diagnosis, the assertion that the migration missed these cases, and the proposed blanket await/waitFor fix. SEPURI reports that all 24 userEvent calls are already awaited, with passing same-source CI and 46/46 local tests across three runs on Node 24.16.0. The cause of our local failures remains unconfirmed pending environment reproduction.

    Please keep #44314 scoped to the verified ControlPanelsContainer await fix. #44315 fixes that issue; I am not claiming it fixes the AdhocFilter suite.

    Historical local observation — not an upstream diagnosis

    On September 15 I reported two local runs against a184395eca7c291d0b8b438f00690c633112f4d7 with these same 12 failing test names in AdhocFilterEditPopoverSimpleTabContent.test.tsx. I am investigating the original command, dependency/generated-output state and logs; these observations alone do not establish deterministic failures in a correctly built upstream environment:

    advanced data type operator list should update after API response
    does not say the list is partial when it is complete
    drops the note once suggestions load again
    ignores a stale failing response that loses the race to a newer success
    loads comparator values from the server
    save button should be disabled if error message from API is returned
    says the list is partial when the server capped it
    sends the typed text to the server rather than filtering the loaded page
    should call API when column has advanced data type
    shows a plain empty list when the server has no values
    stays quiet when the server refuses the request
    stores the picked value, not the option object
    

    Shared test helpers, generated workspace outputs, dependency skew and portal timing are unverified hypotheses, not established causes. I will update this comment with reproduction evidence or explicit limitations; no repo-wide fix is justified by the evidence currently available.

    Focused reproduction update (2026-09-17)

    I recovered the original transcript: the temporary clone used a node_modules symlink to a separate superset-2 checkout. I also independently verified that the superset-frontend Git tree is identical at dbccb3bc, a184395e, and b1380cf4 (90aa8ba925051955cc1c21b65edd4b576bc36216).

    On an isolated checkout of a184395eca7c291d0b8b438f00690c633112f4d7, Node 24.16.0, reusing that surviving dependency directory read-only, the focused in-band Jest run reproduced 12 failed / 34 passed, with exactly the same twelve names above. The log contains You must call SupersetClient.configure(...) before calling other methods. The test setup imports the clone-local client via a relative path, while Jest's @superset-ui/core mapping follows the shared node_modules symlink into the other checkout: these are different module instances.

    Control: without changing source, dependencies, or generated outputs, I used an external Jest config overriding only ^@superset-ui/core$ and ^@superset-ui/core/(.*)$ to the clone-local package source. The same test file then passed 46/46 (15.668s); the original configuration failed in 28.154s. This establishes a module-resolution problem in this reproduced shared-dependency environment, not an upstream await regression.

    Limits: this was not a fresh-install/plugin-build comparison. The original September 15 Node version and full failure log were not recovered, and the shared dependency checkout has moved since then, so I cannot prove every detail of that historical environment. No source fix or blanket waitFor change is proposed. Thanks for challenging the diagnosis and pointing us back to the environment.

  5. SEPURI-SAI-KRISHNA commented on Sep 16, 2026

    @SEPURI-SAI-KRISHNA
    ContributorAuthor

    Thanks for looking into this. I can't reproduce those failures, and I think this file is a false lead.

    Checking on master itself rather than a branch: the last master run that actually executed Jest before your commit is dbccb3bc, and shard 4 of that run shows this file passing:

    PASS src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/AdhocFilterEditPopoverSimpleTabContent.test.tsx (37.884 s)
    Test Suites: 1 skipped, 162 passed, 162 of 163 total
    Tests:       14 skipped, 1638 passed, 1652 total
    

    a184395e is a docs-only oxfmt bump, and no superset-frontend/ file changed between dbccb3bc, a184395e and current master b1380cf4. The frontend tree at the commit you tested is therefore byte-identical to the one CI shows green, so there is no window for 12 deterministic failures to have been introduced.

    That matches locally: 46/46 pass for me on Node 24.16.0 across three runs (twice plain, once with --coverage), with the test file, index.tsx, useAdvancedDataTypes.ts, package.json, jest.config.js and spec/helpers/testing-library.tsx all byte-identical to master.

    Worth noting that a184395e's own sharded-jest-tests job was skipped by the workflow's path filters, since the commit only touches /docs — so that run never exercised the frontend suite. Locally, skipping npm run plugins:build after npm ci will also fail a cluster of tests in a way that looks deterministic rather than flaky.

    On the proposed cause: all 24 userEvent calls in this file are already awaited. #43512 is in fact the file's most recent commit, so the v14 pass landed here fully. Both document.querySelector('.ant-select-dropdown-list') uses are awaited as well — one wrapped in waitFor, the other following an await userEvent.type — so the portal-timing symptom doesn't apply either.

    If you're still seeing it, could you post the full Jest output and your Node version? Absent a reproducible failure I'd rather keep this issue scoped to the single ControlPanelsContainer line it was opened for, and #44315 fixes that one.

  6. added a commit that references this issue on Sep 16, 2026
    29a12ee
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions