Skip to content

test(desktop): vite-workspace-packages child can outlive its tests and holds the dist suite until the 900s ceiling #4940

Description

@orangeCatDeveloper

Observed on run 34061414876 (PR #4878 CI, 2026-09-06): the desktop workspace reported 2357 pass / 0 fail / 1 cancelled, yet node --test never finished — scripts/vite-workspace-packages.test.mjs stayed pending for 811s until the workspace hit its 900s ceiling:

⚠ scripts/vite-workspace-packages.test.mjs
✔ renderer loads a newly exported workspace module after its manifest changes (198ms)
✔ renderer-facing Runtime Host protocol does not load Node crypto (44ms)
✖ scripts/vite-workspace-packages.test.mjs (811706ms)
  'Promise resolution is still pending but the event loop has already resolved'
[desktop] timed out after 900000ms

Both subtests completed and reported; the child process did not exit. #4748 removed this failure mode for the second test by disabling its watcher, but the first test needs its watcher (it asserts restart-on-manifest-change), so it stays exposed.

Root cause (reproduced ~7% of iterations under a 3-way CPU/IO load on Linux, node 24, vite 8.2.2): workspacePackagesPlugin registers manifests as configFileDependencies, chokidar therefore also watches each manifest's parent directory; the manifest edit mid-test triggers a dev-server restart whose fresh watcher keeps scanning in the background; server.close() does not wait for (or cancel) that scan, and the vite-bundled, pnpm-patched chokidar 3.6.0 (the top-level chokidar 5.0.0 is not in this call chain) drops the closer of an fs.watch it already created: _handleDir() creates the directory watcher and returns its closer, but the caller _addToNodeFs() registers it with _addPathCloser() only after re-checking this.fsw.closed — when close() lands inside that await gap, it sweeps a still-empty _closers list and the resumed _addToNodeFs discards the closer at the closed check. An independent forced-interleave reproduction confirms the drop point (closed=true, closers empty, native fs.watch still open; invoking the lost closer by hand closes it). Chokidar 5.0.0 shares the same structure, so this is a chokidar bug, vendored (and patched) by vite. The orphan (FSEventWrap + pending FSReqCallback, confirmed via process.getActiveResourcesInfo() after close) keeps the child alive forever.

Proposed fix: --test-force-exit on the desktop test:dist runner, so tests that already completed report normally while lingering handles can no longer hold the workspace run hostage.

Activity

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