microsoft / microsoft/playwright
feat(electron): add timeout option to electronApp.close() for force-kill escalation
- Dominant language
- TypeScript
- Stars
- 96.3k
- Forks
- 6.5k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 180
Description
Feature Request
Is your feature request related to a problem?
electronApp.close() currently waits indefinitely for the Electron process to exit. If the application has before-quit handlers that prevent shutdown, leaky IPC handlers, or child processes that keep it alive, close() hangs forever until the test-level timeout kills everything.
This is a well-documented pain point:
- #12189 —
app.quit()called but process sticks around - #27523 — Electron tests freeze 30s on close
- #39248 — Leaky IPC handlers cause hangs on Linux/Windows
- #13874 — Electron hangs closing context
PR #11336 rightfully removed the old hardcoded 30s timeout (which was inconsistent with other close() methods). But now there is no way for users to specify a grace period with force-kill escalation.
The force-kill infrastructure already exists in processLauncher.ts (killProcess() → SIGKILL / taskkill /T /F) but is only reachable via OS signals (SIGINT/SIGTERM), not through the public close() API.
Describe the solution
Add an opt-in timeout option to electronApp.close():
// Default: wait forever (unchanged behavior)
await electronApp.close();
// With timeout: force-kill if app does not exit within 10s
await electronApp.close({ timeout: 10_000 });
When specified:
- Initiate graceful shutdown (existing flow:
browser.close()→app.quit()→worker._disconnect()) - Start a timer
- If the process exits within the timeout, clear the timer (no force-kill)
- If the timer fires first, call the existing
kill()fromprocessLauncher(SIGKILL/taskkill) - Wait for the process to fully exit
This is different from the removed behavior (#11336) because:
- Opt-in: no timeout by default (backward compatible)
- Force-kills instead of throwing: the old timeout threw an error and left the process running
- Uses existing infrastructure: wires the
killfunction fromlaunchProcessintoElectronApplication
Real-world use case
We maintain E2E tests for a VS Code extension using Playwright Electron. Our test teardown was flaky because close() would occasionally hang when the Electron app did not exit cleanly. We had to build a 3-layer workaround: app.quit() → app.close() wrapped in Promise.race with manual timer → SIGKILL fallback. This feature would replace that pattern with a single API call.
I have a PR ready if you are open to this.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.