diff --git a/eslint.config.js b/eslint.config.js index 1c420d5..64122df 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -135,9 +135,14 @@ module.exports = [ }, }, - // Unit tests, and the helpers they require: jest on node. + // Unit tests, the helpers they require, and the test files they hand to + // jest: jest on node. { - files: ["tests/**/*.test.js", "tests/support/**/*.js"], + files: [ + "tests/**/*.test.js", + "tests/support/**/*.js", + "tests/fixtures/**/*.js", + ], languageOptions: { ...commonjs, globals: { ...globals.node, ...globals.jest }, diff --git a/package.json b/package.json index 2080619..403a6f0 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "jest": { "setupFiles": [ "/tests/support/navigatorLocks.js" - ] + ], + "workerIdleMemoryLimit": "200MB" }, "devDependencies": { "@eslint/js": "10.0.1", diff --git a/tests/fixtures/leavesIntervalRunning.js b/tests/fixtures/leavesIntervalRunning.js new file mode 100644 index 0000000..a0229cb --- /dev/null +++ b/tests/fixtures/leavesIntervalRunning.js @@ -0,0 +1,7 @@ +// A test file that starts an interval and never clears it. +// tests/jestRunner.test.js runs script/lib/jest.js on this file alone. The +// name does not end in .test.js, so the normal run never picks it up. + +test("starts an interval and never clears it", () => { + setInterval(() => {}, 1000); +}); diff --git a/tests/jestRunner.test.js b/tests/jestRunner.test.js new file mode 100644 index 0000000..38299d0 --- /dev/null +++ b/tests/jestRunner.test.js @@ -0,0 +1,29 @@ +// script/lib/jest.js, which package.json's test scripts run, fails a run in +// which jest force-stopped a worker process because a test left an open +// handle. + +const { spawnSync } = require("child_process"); +const path = require("path"); + +const root = path.join(__dirname, ".."); + +test("a test that leaves an interval running fails the run", () => { + // The memory limit in package.json makes jest run even this one file in a + // worker process. The interval keeps that worker from exiting, so jest + // force-stops it after the run. + const result = spawnSync( + process.execPath, + [ + "script/lib/jest.js", + "--maxWorkers=1", + "--testMatch", + "/tests/fixtures/leavesIntervalRunning.js", + ], + { cwd: root, encoding: "utf8", timeout: 20000 }, + ); + + expect(result.signal).toBeNull(); + expect(result.status).toBe(1); + expect(result.stderr).toContain("1 passed"); + expect(result.stderr).toContain("jest force-stopped a worker process"); +});