From 6923ddd519425c717aefadb6e34d6f59114bc6f2 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Sun, 22 Mar 2026 10:03:42 -0600 Subject: [PATCH] fix(tests): add maxRetries to rmSync cleanup for Windows EPERM compatibility Windows holds file handles briefly after close, causing EPERM on rmSync in afterEach cleanup. Node's maxRetries/retryDelay options handle this by retrying after a short delay. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../gsd/tests/commands-workflow-custom.test.ts | 2 +- .../tests/custom-engine-loop-integration.test.ts | 2 +- .../gsd/tests/custom-workflow-engine.test.ts | 2 +- .../gsd/tests/definition-loader.test.ts | 16 ++++++++-------- .../e2e-workflow-pipeline-integration.test.ts | 2 +- .../gsd/tests/graph-operations.test.ts | 2 +- .../gsd/tests/iterate-engine-integration.test.ts | 2 +- .../extensions/gsd/tests/run-manager.test.ts | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts b/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts index b86698a4b..7f80367a9 100644 --- a/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +++ b/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts @@ -36,7 +36,7 @@ afterEach(() => { process.chdir(savedCwd); } for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; }); diff --git a/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts b/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts index 8a0cd07c2..bd7474aa8 100644 --- a/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +++ b/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts @@ -32,7 +32,7 @@ function makeTmpDir(): string { afterEach(() => { _resetPendingResolve(); for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; }); diff --git a/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts b/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts index a6e6b4aae..0ba53de99 100644 --- a/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +++ b/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts @@ -29,7 +29,7 @@ function makeTmpDir(): string { afterEach(() => { for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; }); diff --git a/src/resources/extensions/gsd/tests/definition-loader.test.ts b/src/resources/extensions/gsd/tests/definition-loader.test.ts index 53bb946de..3cf425813 100644 --- a/src/resources/extensions/gsd/tests/definition-loader.test.ts +++ b/src/resources/extensions/gsd/tests/definition-loader.test.ts @@ -90,7 +90,7 @@ test("loadDefinition: valid 3-step YAML returns correct structure", () => { assert.deepEqual(def.steps[2].requires, ["outline"]); assert.deepEqual(def.steps[2].produces, ["draft.md"]); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -235,7 +235,7 @@ test("loadDefinition: missing file → descriptive error", () => { }, ); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -258,7 +258,7 @@ steps: }, ); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -281,7 +281,7 @@ steps: const def = loadDefinition(dir, "test-workflow"); assert.deepEqual(def.steps[1].requires, ["first"]); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -302,7 +302,7 @@ steps: const def = loadDefinition(dir, "test-workflow"); assert.deepEqual(def.steps[1].contextFrom, ["first"]); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -738,7 +738,7 @@ steps: const def = loadDefinition(dir, "test-workflow"); assert.equal(def.params, undefined); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -755,7 +755,7 @@ steps: const def = loadDefinition(dir, "test-workflow"); assert.equal(def.description, undefined); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); @@ -773,6 +773,6 @@ steps: assert.deepEqual(def.steps[0].requires, []); assert.deepEqual(def.steps[0].produces, []); } finally { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } }); diff --git a/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts b/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts index f2bde438a..a78cfd6da 100644 --- a/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +++ b/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts @@ -52,7 +52,7 @@ function makeTmpDir(): string { afterEach(() => { for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; }); diff --git a/src/resources/extensions/gsd/tests/graph-operations.test.ts b/src/resources/extensions/gsd/tests/graph-operations.test.ts index 368e7bc96..9c18aa282 100644 --- a/src/resources/extensions/gsd/tests/graph-operations.test.ts +++ b/src/resources/extensions/gsd/tests/graph-operations.test.ts @@ -32,7 +32,7 @@ function makeTmpDir(): string { } function cleanupDir(dir: string): void { - rmSync(dir, { recursive: true, force: true }); + rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } /** Minimal valid graph for testing. */ diff --git a/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts b/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts index 6386e1056..78a90c2f1 100644 --- a/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +++ b/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts @@ -39,7 +39,7 @@ function makeTmpDir(): string { afterEach(() => { for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; }); diff --git a/src/resources/extensions/gsd/tests/run-manager.test.ts b/src/resources/extensions/gsd/tests/run-manager.test.ts index f03ab9baa..3db024b64 100644 --- a/src/resources/extensions/gsd/tests/run-manager.test.ts +++ b/src/resources/extensions/gsd/tests/run-manager.test.ts @@ -34,7 +34,7 @@ function makeTmpBase(): string { afterEach(() => { for (const d of tmpDirs) { - rmSync(d, { recursive: true, force: true }); + rmSync(d, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } tmpDirs.length = 0; });