Skip to content

test: stop Iconify's API query from firing into a torn-down jsdom - #202

Merged
kipavy merged 1 commit into
devfrom
fix/iconify-test-teardown
Sep 1, 2026
Merged

test: stop Iconify's API query from firing into a torn-down jsdom#202
kipavy merged 1 commit into
devfrom
fix/iconify-test-teardown

Conversation

@kipavy

@kipavy kipavy commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The failure

CI has been failing intermittently with every test passing:

Test Files  519 passed (519)
Tests       3977 passed (3977)
Errors      1 error

ReferenceError: window is not defined
 ❯ resolveUpdatePriority  react-dom/cjs/react-dom-client.development.js:1308:7
 ❯ dispatchSetState       react-dom/cjs/react-dom-client.development.js:9126:14
 ❯ cleanup                @iconify/react/dist/iconify.js:1833:13
 ❯ Timeout._onTimeout     @iconify/react/dist/iconify.js:845:10

Most recently on #199, where a re-run cleared it with no code change.

Root cause

Rendering an <Icon> whose icon is not already in a loaded collection makes Iconify query its public API. That query arms retry/timeout timers — measured in this repo as 750ms, 499ms and 4000ms — and it arms them one tick after the render, not during it.

A test file that finishes inside 4s leaves the last timer live. When it fires, jsdom has been torn down, so Iconify's setState reaches react-dom, which touches window and throws. Vitest counts that as an unhandled error and fails the run even though nothing actually failed.

Whether it happens depends only on how long the run takes, which is why it never reproduced on a single file — src/plugins/docker/components/PortChips.test.tsx, the file CI blamed, passes cleanly five runs in a row on its own. The blamed file is just whichever one happened to be running when a stray timer fired.

A side effect worth noting: the suite has been reaching api.iconify.design on every icon render.

Fix

A new vitest.setup.ts installs an inert Iconify API module, so no query is ever created, no timers are armed, and nothing leaves the machine.

This matches the app: preloadIcons() registers every collection from bundled packages, and the API is never used in production either. Rendered output does not change — icons already came out as an empty <span> in tests, because the query never resolved in time anyway.

src/utils/iconifyTestApi.test.tsx guards it.

Verification

  • The guard test is red before green. Without the setup file it fails with expected [ 750, 499, 4000 ] to deeply equal []; with it, it passes.
  • tsc --noEmit clean.
  • Full suite green: 521 files, 3985 tests, 0 errors, exit 0.

Note

This does not make icons render in tests — it makes them deterministically not render, which is what they already did. Loading the real collections in the setup file would render them for real, but it changes the DOM every icon-bearing test sees, so it is deliberately not part of this change.

CI failed intermittently with every test passing:

    Test Files  519 passed (519)
    Tests       3977 passed (3977)
    Errors      1 error
    ReferenceError: window is not defined
      at cleanup @iconify/react/dist/iconify.js:1833

Rendering an <Icon> whose icon is not already in a loaded collection makes
Iconify query its public API, and that query arms retry/timeout timers —
measured here as 750ms, 499ms and 4000ms, armed one tick after render rather
than during it. A test file that finishes inside 4s leaves the last one live;
when it fires, jsdom is gone, so Iconify's setState reaches react-dom, which
touches `window` and throws. Vitest counts that as an unhandled error and
fails the run. Whether it happens depends only on how long the run takes,
which is why it never reproduced on a single file.

It also meant the suite was reaching api.iconify.design on every icon render.

An inert API module in a new setup file creates no query, so no timers are
armed and nothing leaves the machine. This matches the app, where
`preloadIcons()` registers every collection from bundled packages and the API
is never used. Rendered output does not change: icons already came out as an
empty <span> in tests, because the query never resolved in time anyway.
@kipavy
kipavy merged commit d33ef0c into dev Sep 1, 2026
4 checks passed
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.

1 participant