Skip to content

[Fix] Flush Tremor Tooltip timers in user_edit_view tests#25480

Merged
yuneng-berri merged 1 commit intomainfrom
litellm_/eloquent-allen
Apr 10, 2026
Merged

[Fix] Flush Tremor Tooltip timers in user_edit_view tests#25480
yuneng-berri merged 1 commit intomainfrom
litellm_/eloquent-allen

Conversation

@yuneng-berri
Copy link
Copy Markdown
Collaborator

Summary

Failure Path (Before Fix)

Tremor's internal Tooltip component sets a setTimeout that fires after the jsdom test environment is torn down, causing a ReferenceError: window is not defined during vitest runs of user_edit_view.test.tsx. This produced a false-positive warning that could mask real test failures.

Fix

Added an afterEach block that switches to fake timers, flushes all pending timers (so the Tooltip callback runs while jsdom is still alive), restores real timers, and calls cleanup().

Testing

  • npx vitest run src/components/user_edit_view.test.tsx — all 25 tests pass with no unhandled errors

Type

🐛 Bug Fix
✅ Test

Tremor's internal Tooltip component sets a setTimeout that fires after
the jsdom test environment tears down, causing a ReferenceError. Add
afterEach that flushes pending timers before cleanup.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Apr 10, 2026 7:12am

Request Review

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq Bot commented Apr 10, 2026

Merging this PR will not alter performance

✅ 16 untouched benchmarks


Comparing litellm_/eloquent-allen (a771e19) with main (9e6d2d2)

Open in CodSpeed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 10, 2026

Greptile Summary

This PR adds an afterEach block to user_edit_view.test.tsx to suppress a ReferenceError: window is not defined warning caused by Tremor's Tooltip component firing a setTimeout after jsdom teardown. The fix switches to fake timers, flushes the pending queue, restores real timers, and explicitly calls cleanup() before the test environment is torn down.

Confidence Score: 5/5

Safe to merge — test-only change that resolves a post-teardown warning without weakening any assertions.

The single finding is P2: the fake-timer strategy may not capture pre-scheduled real timers, but the explicit cleanup() call provides the actual fix and tests are confirmed passing. No production code is touched, no assertions are weakened, and test coverage is unchanged.

No files require special attention — the @tremor/react mock block could optionally include a Tooltip stub to address the root cause more cleanly, but this is a style-level improvement.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/user_edit_view.test.tsx Adds afterEach with fake-timer flush and explicit cleanup() to prevent Tremor Tooltip setTimeout from firing after jsdom teardown. Minor concern: vi.useFakeTimers() called after real timers are set may not capture those already-scheduled handles; explicit cleanup() is also redundant since testing-library auto-cleans.

Sequence Diagram

sequenceDiagram
    participant Test as Vitest Test
    participant JSDOM as jsdom Environment
    participant Tremor as Tremor Tooltip
    participant RTL as @testing-library/react

    Note over Test,RTL: Before Fix
    Test->>JSDOM: render component
    JSDOM->>Tremor: mount Tooltip
    Tremor->>JSDOM: setTimeout(callback, N)
    Test->>RTL: waitFor / assertions
    JSDOM-->>Test: test passes
    JSDOM->>JSDOM: teardown (window removed)
    Tremor-->>JSDOM: timer fires → ReferenceError: window is not defined ❌

    Note over Test,RTL: After Fix (afterEach)
    Test->>RTL: waitFor / assertions
    JSDOM-->>Test: test passes
    Test->>JSDOM: vi.useFakeTimers()
    Test->>JSDOM: vi.runAllTimers() (flushes fake queue only)
    Test->>JSDOM: vi.useRealTimers()
    Test->>RTL: cleanup() → unmount component while jsdom alive ✅
    JSDOM->>JSDOM: teardown
Loading

Reviews (1): Last reviewed commit: "Fix unhandled "window is not defined" er..." | Re-trigger Greptile

Comment on lines +143 to +150
afterEach(() => {
// Tremor's internal Tooltip sets a setTimeout that fires after teardown,
// causing "window is not defined". Flush pending timers before cleanup.
vi.useFakeTimers();
vi.runAllTimers();
vi.useRealTimers();
cleanup();
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 vi.useFakeTimers() post-hoc cannot capture already-scheduled real timers

vi.useFakeTimers() replaces the global setTimeout at the moment it's called, but any setTimeout that Tremor's Tooltip already scheduled during the test body runs against the real timer queue and is not moved into the fake queue. vi.runAllTimers() therefore only flushes timers set after useFakeTimers() was called — not the Tooltip's pre-existing handle. The fix's apparent effect is more likely coming from the explicit cleanup() call (unmounting the component while jsdom is still alive, so when the real timer fires there's no React tree to update).

A more reliable and self-documenting approach is to mock Tremor's Tooltip inside the existing @tremor/react mock block so it never schedules a timer:

vi.mock("@tremor/react", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@tremor/react")>();
  const React = await import("react");
  // Prevent Tremor's Tooltip internal setTimeout from firing after jsdom teardown
  const Tooltip = ({ children }: { children?: React.ReactNode }) =>
    React.createElement(React.Fragment, null, children);
  Tooltip.displayName = "Tooltip";
  const SelectItem = ({ value, children, title }: any) => { ... };
  SelectItem.displayName = "SelectItem";
  return { ...actual, Tooltip, SelectItem };
});

This eliminates the root cause instead of racing against it, and the afterEach block can be removed entirely.

The explicit cleanup() call is also redundant — @testing-library/react registers an afterEach hook automatically when the module is first imported, so cleanup() already fires without this block.

@ryan-crabbe-berri ryan-crabbe-berri self-requested a review April 10, 2026 22:10
@yuneng-berri yuneng-berri merged commit f2f2a91 into main Apr 10, 2026
96 of 100 checks passed
@yuneng-berri yuneng-berri deleted the litellm_/eloquent-allen branch April 10, 2026 22:11
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