| 23 | let tmpDir; |
| 24 | |
| 25 | function removeTmpDir(dir) { |
| 26 | if (!dir) return; |
| 27 | try { |
| 28 | fs.rmSync(dir, { |
| 29 | recursive: true, |
| 30 | force: true, |
| 31 | maxRetries: process.platform === 'win32' ? 20 : 3, |
| 32 | retryDelay: 100, |
| 33 | }); |
| 34 | } catch (err) { |
| 35 | // Best-effort teardown. This runs in afterEach, AFTER the test's |
| 36 | // assertions have already passed. On Windows a daemon spawned with |
| 37 | // cwd=tmpDir (or a grandchild that outlives the synchronous spawnSync) |
| 38 | // can hold a handle on the directory past the retry window, so rmSync |
| 39 | // still throws EBUSY — which surfaced as a `hookFailed` red on |
| 40 | // `loop-mode EVOLVE_BRIDGE default (#96)`. CI runners are ephemeral and a |
| 41 | // leftover temp dir is harmless, so a cleanup race must never fail an |
| 42 | // otherwise-passing test. |
| 43 | console.warn(`[loopMode.test] best-effort tmp cleanup failed: ${err && (err.code || err.message)}`); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | beforeEach(() => { |
| 48 | tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'evolver-loop-test-')); |