Skip to content

fix(tests): fix flaky FileHandler test by awaiting LaunchQueue consumer in afterEach#39508

Merged
sadpandajoe merged 3 commits into
apache:masterfrom
mistercrunch:fix-filehandler-flaky-tests
May 21, 2026
Merged

fix(tests): fix flaky FileHandler test by awaiting LaunchQueue consumer in afterEach#39508
sadpandajoe merged 3 commits into
apache:masterfrom
mistercrunch:fix-filehandler-flaky-tests

Conversation

@mistercrunch
Copy link
Copy Markdown
Member

@mistercrunch mistercrunch commented Apr 21, 2026

SUMMARY

Fixes flaky FileHandler/index.test.tsx tests that intermittently timeout at 20s. Observed on multiple tests including "handles Parquet file correctly" and "handles Excel (.xls) file correctly" (e.g. GHA job 71282515731 on PR #39345).

Root cause: setupLaunchQueue's mocked setConsumer invoked the consumer callback inside setTimeout(fn, 0) but did not capture or await the resulting Promise. The async work kicked off by one test (file reads, setState calls, history.push) could still be in flight when the next test started, racing the new test's render and assertions.

Fix:

  • Capture the consumer's return value as a module-scoped consumerPromise
  • await consumerPromise in afterEach so all async work settles before the next test begins
  • Log (rather than swallow) any rejection so unexpected failures stay visible in test output

Why we keep the setTimeout(fn, 0) deferral: an earlier attempt called the consumer synchronously inside setConsumer. That deadlocked Jest — jsDomWithFetchAPI's MessageChannel mock forces React to schedule updates via setTimeout, and a fully-synchronous path inside the useEffect ran ahead of React's scheduler. The macrotask deferral plus pendingTimerIds cleanup is intentional and stays.

Drive-by: removed a stale // @ts-expect-error react-dnd types not updated for React 18 in spec/helpers/testing-library.tsx that pre-commit's targeted type-check flagged as unused once index.test.tsx was changed (react-dnd types now satisfy React 18 without the directive).

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A - test-only change

TESTING INSTRUCTIONS

  • cd superset-frontend && npm run test -- src/pages/FileHandler/index.test.tsx — verify all 10 tests pass (1 skipped)
  • Run the file repeatedly to confirm no flakiness

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 21, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit de4a61d
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a0e4e7dfadaa600078bb300
😎 Deploy Preview https://deploy-preview-39508--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@mistercrunch mistercrunch force-pushed the fix-filehandler-flaky-tests branch from 4961039 to ddfcf60 Compare May 9, 2026 00:04
@codecov
Copy link
Copy Markdown

codecov Bot commented May 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.83%. Comparing base (f67dd4a) to head (8e8991c).
⚠️ Report is 235 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #39508      +/-   ##
==========================================
- Coverage   63.83%   63.83%   -0.01%     
==========================================
  Files        2589     2589              
  Lines      137821   137821              
  Branches    31928    31928              
==========================================
- Hits        87978    87975       -3     
- Misses      48327    48330       +3     
  Partials     1516     1516              
Flag Coverage Δ
javascript 66.53% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mistercrunch mistercrunch marked this pull request as ready for review May 20, 2026 20:01
…ardown

The flaky tests in FileHandler/index.test.tsx were caused by the async
consumer promise (returned from the mocked setConsumer callback) not
being awaited before the next test ran. In-flight state updates from
one test could bleed into the next, causing intermittent 20s timeouts
on tests like "handles Parquet file correctly" and "handles Excel (.xls)
file correctly" (e.g. GHA job 71282515731 on PR apache#39345).

The setTimeout(fn, 0) deferral and pendingTimerIds tracking are kept
intentionally: calling the consumer synchronously inside setConsumer
deadlocks Jest because jsDomWithFetchAPI's MessageChannel mock forces
React to schedule via setTimeout, so the inline path was tried and
reverted.

Changes:
- Capture the consumer's return value as consumerPromise
- Await consumerPromise in afterEach so async work settles before the
  next test starts
- Log (rather than swallow) any rejection from the awaited promise so
  unexpected failures stay visible
- Remove a stale @ts-expect-error in spec/helpers/testing-library.tsx
  flagged by pre-commit's targeted type-check (react-dnd types no
  longer need the directive under React 18)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sadpandajoe sadpandajoe force-pushed the fix-filehandler-flaky-tests branch from ddfcf60 to de4a61d Compare May 21, 2026 00:14
Comment thread superset-frontend/src/pages/FileHandler/index.test.tsx Outdated
@bito-code-review
Copy link
Copy Markdown
Contributor

The catch in afterEach suppresses rejections from the LaunchQueue consumer, which can lead to false-positive test passes when background work fails unexpectedly. The suggested fix is to re-throw the error after logging it to ensure test failures are properly captured. This is a valid and important fix to apply for maintaining test suite reliability.

superset-frontend/src/pages/FileHandler/index.test.tsx

await consumerPromise.catch(e => {
  console.warn('LaunchQueue consumer rejected:', e);
  throw e; // Re-throw to fail the test
});

Pre-commit's targeted tscw (composite: false, no project refs) flagged
the prior @ts-expect-error in spec/helpers/testing-library.tsx as
unused, so it was removed. CI's full tsc (with project references)
still sees DndProviderProps as omitting `children` under React 18 types,
which broke lint-frontend. Use @ts-ignore so the suppression is silent
under tscw but still effective under the full tsc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR targets frontend test stability by ensuring async work triggered via the mocked launchQueue.setConsumer() is tracked and awaited between tests, reducing cross-test interference and intermittent timeouts in FileHandler tests.

Changes:

  • Track the Promise returned by the launchQueue consumer callback and await it in afterEach to ensure async work settles between tests.
  • Keep macrotask deferral (setTimeout(..., 0)) while adding cleanup of scheduled timer IDs.
  • Adjust a TypeScript suppression comment in the shared Testing Library wrapper helper.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
superset-frontend/src/pages/FileHandler/index.test.tsx Captures and awaits the launchQueue consumer Promise in teardown to reduce test flakiness from overlapping async work.
superset-frontend/spec/helpers/testing-library.tsx Updates the TypeScript suppression directive/comment for the react-dnd wrapper in test utilities.

Comment thread superset-frontend/src/pages/FileHandler/index.test.tsx Outdated

if (useDnd) {
// @ts-expect-error react-dnd types not updated for React 18
// @ts-ignore react-dnd's DndProviderProps omits `children` under React 18 types
…-write-wins

The module-scoped `consumerPromise` was overwritten on each setTimeout
callback. If React's useEffect re-fired during a test (the useHistory
mock returns a fresh `{ push }` object each call, so deps look stale
after a re-render), a second setConsumer call would queue a second
setTimeout that overwrote the earlier promise — leaving the first
consumer's async work orphaned even though afterEach awaited
`consumerPromise`.

Collect every consumer promise into an array and Promise.allSettled
them in afterEach so all in-flight work settles before the next test,
regardless of how many times the useEffect re-registered the consumer.
Reset by length=0 in place — no beforeEach needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sadpandajoe sadpandajoe changed the title fix(tests): fix flaky FileHandler test by removing setTimeout-based LaunchQueue mock fix(tests): fix flaky FileHandler test by awaiting LaunchQueue consumer in afterEach May 21, 2026
Copy link
Copy Markdown
Member

@sadpandajoe sadpandajoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation: APPROVE
Verdict: consumerPromises array refactor in 8e8991c cleanly addresses the last-write-wins race; adversarial walk turned up nothing actionable.

Walked the delta:

  • consumerPromises.length = 0 — correct in-place reset for a const array; no aliases.
  • Promise.allSettled over Promise.all — right call. Promise.all would short-circuit on first rejection and orphan the rest, which is the exact failure mode being fixed.
  • forEach over PromiseSettledResult keeps the prior console.warn-on-rejection semantics.
  • No test body mutates the array outside setupLaunchQueue.
  • The window between length = 0 and delete window.launchQueue is fully synchronous — no macrotask can sneak between them.

One theoretical residual: a useEffect re-fire during the allSettled await could push a new promise after the snapshot. Mocked consumers resolve in microtasks so the window is effectively zero — not worth surfacing.

@sadpandajoe sadpandajoe merged commit b1ca8ca into apache:master May 21, 2026
74 checks passed
@bito-code-review
Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants