-
Notifications
You must be signed in to change notification settings - Fork 868
Description
Summary
Running the ACT rules test suite triggers Node's MaxListenersExceededWarning because each spec file leaves a dangling exit listener on process that is never cleaned up.
Call chain
Each of the ~35 spec files calls act-runner.js, which in its before() hook calls getWebdriver() (act-runner.js#L32):
driver = getWebdriver();getWebdriver() calls Builder.build(), which spawns a ChromeDriver subprocess via selenium-webdriver's internal exec() function. On every spawn, exec() registers a cleanup listener (selenium-webdriver/io/exec.js#L134):
process.once('exit', onProcessExit)This listener is designed to self-clean when the child process exits (exec.js#L139):
process.removeListener('exit', onProcessExit)Root cause
The after() hook tears down the driver with driver.close() (act-runner.js#L50):
after(async () => {
await driver.close();
await new Promise(r => server.close(r));
});driver.close() closes the browser window but does not stop the ChromeDriver service process. Because the subprocess never exits during the test run, the onProcessExit listener on process is never removed. With ~35 spec files each creating their own driver, 35 dangling exit listeners accumulate on process.
Fix
Change driver.close() to driver.quit() at act-runner.js#L50:
- await driver.close();
+ await driver.quit();driver.quit() sends DELETE /session, which terminates the ChromeDriver process. That causes proc.once('exit', ...) in exec.js to fire, which calls process.removeListener('exit', onProcessExit) and properly cleans up the listener. This aligns with the best practice from Selenium itself for managing sessions.
Extra Notes
Any PRs submitting to fix this, need to orchestrate a setup (probably a quick matrix) that runs this test suite 10 times. To prove it is not flaky anymore from this leak.