11/**
22 * FLAKINESS AUDIT (im8092sn):
33 *
4- * 1. HARDCODED TEST DIRECTORY: Uses `.test-migration` relative to source file.
5- * Risk: If multiple test runs overlap or cleanup fails, stale directory
6- * may interfere with subsequent runs.
4+ * 1. HARDCODED TEST DIRECTORY - FIXED: Now uses mkdtemp for unique temp directories.
5+ * Creates isolated test directories per test, eliminating collision risk.
76 *
87 * 2. PROCESS.CWD() CHANGES: Tests change working directory via process.chdir().
98 * Risk: If a test fails before afterEach, cwd remains changed for subsequent tests.
10- * Cleanup in afterEach properly restores cwd to import.meta.dir .
9+ * Cleanup in afterEach properly restores originalCwd .
1110 *
1211 * 3. ASYNC FILESYSTEM OPS: Uses async mkdir/rm/writeFile for setup/teardown.
13- * Good practice, but cleanup in afterEach must complete before next test.
12+ * Good practice, and cleanup in afterEach properly completes before next test.
1413 *
15- * 4. NO UNIQUE TEST ISOLATION: Tests share the same TEST_DIR path .
16- * If cleanup fails, subsequent test runs may see leftover files .
14+ * 4. TEST ISOLATION - FIXED: Each test gets unique temp directory via mkdtemp .
15+ * No risk of leftover files interfering between test runs .
1716 */
1817import { test , expect , beforeEach , afterEach , mock } from "bun:test" ;
1918import { existsSync } from "node:fs" ;
20- import { mkdir , rm , writeFile } from "node:fs/promises" ;
19+ import { mkdir , rm , writeFile , mkdtemp } from "node:fs/promises" ;
2120import { join } from "node:path" ;
21+ import { tmpdir } from "node:os" ;
2222import { hasLegacyTodoDir , hasNewTodoDir , migrateIfNeeded } from "./migration" ;
2323
24- // Use a temp directory for testing
25- const TEST_DIR = join ( import . meta . dir , ".test-migration" ) ;
24+ let testDir : string ;
25+ let originalCwd : string ;
2626
2727beforeEach ( async ( ) => {
28- // Clean up and create fresh test directory
29- if ( existsSync ( TEST_DIR ) ) {
30- await rm ( TEST_DIR , { recursive : true } ) ;
31- }
32- await mkdir ( TEST_DIR , { recursive : true } ) ;
28+ // Create unique temp directory for this test
29+ testDir = await mkdtemp ( join ( tmpdir ( ) , "math-migration-test-" ) ) ;
30+ originalCwd = process . cwd ( ) ;
3331
3432 // Change to test directory
35- process . chdir ( TEST_DIR ) ;
33+ process . chdir ( testDir ) ;
3634} ) ;
3735
3836afterEach ( async ( ) => {
39- // Go back to original directory and clean up
40- process . chdir ( import . meta. dir ) ;
41- if ( existsSync ( TEST_DIR ) ) {
42- await rm ( TEST_DIR , { recursive : true } ) ;
43- }
37+ // Restore original directory and clean up
38+ process . chdir ( originalCwd ) ;
39+ await rm ( testDir , { recursive : true , force : true } ) ;
4440} ) ;
4541
4642test ( "hasLegacyTodoDir returns false when no todo/ exists" , ( ) => {
4743 expect ( hasLegacyTodoDir ( ) ) . toBe ( false ) ;
4844} ) ;
4945
5046test ( "hasLegacyTodoDir returns false when todo/ exists but is empty" , async ( ) => {
51- await mkdir ( join ( TEST_DIR , "todo" ) ) ;
47+ await mkdir ( join ( testDir , "todo" ) ) ;
5248 expect ( hasLegacyTodoDir ( ) ) . toBe ( false ) ;
5349} ) ;
5450
5551test ( "hasLegacyTodoDir returns true when todo/ has TASKS.md" , async ( ) => {
56- await mkdir ( join ( TEST_DIR , "todo" ) ) ;
57- await writeFile ( join ( TEST_DIR , "todo" , "TASKS.md" ) , "# Tasks" ) ;
52+ await mkdir ( join ( testDir , "todo" ) ) ;
53+ await writeFile ( join ( testDir , "todo" , "TASKS.md" ) , "# Tasks" ) ;
5854 expect ( hasLegacyTodoDir ( ) ) . toBe ( true ) ;
5955} ) ;
6056
6157test ( "hasLegacyTodoDir returns true when todo/ has PROMPT.md" , async ( ) => {
62- await mkdir ( join ( TEST_DIR , "todo" ) ) ;
63- await writeFile ( join ( TEST_DIR , "todo" , "PROMPT.md" ) , "# Prompt" ) ;
58+ await mkdir ( join ( testDir , "todo" ) ) ;
59+ await writeFile ( join ( testDir , "todo" , "PROMPT.md" ) , "# Prompt" ) ;
6460 expect ( hasLegacyTodoDir ( ) ) . toBe ( true ) ;
6561} ) ;
6662
6763test ( "hasLegacyTodoDir returns true when todo/ has LEARNINGS.md" , async ( ) => {
68- await mkdir ( join ( TEST_DIR , "todo" ) ) ;
69- await writeFile ( join ( TEST_DIR , "todo" , "LEARNINGS.md" ) , "# Learnings" ) ;
64+ await mkdir ( join ( testDir , "todo" ) ) ;
65+ await writeFile ( join ( testDir , "todo" , "LEARNINGS.md" ) , "# Learnings" ) ;
7066 expect ( hasLegacyTodoDir ( ) ) . toBe ( true ) ;
7167} ) ;
7268
@@ -75,13 +71,13 @@ test("hasNewTodoDir returns false when .math/todo/ does not exist", () => {
7571} ) ;
7672
7773test ( "hasNewTodoDir returns true when .math/todo/ exists" , async ( ) => {
78- await mkdir ( join ( TEST_DIR , ".math" , "todo" ) , { recursive : true } ) ;
74+ await mkdir ( join ( testDir , ".math" , "todo" ) , { recursive : true } ) ;
7975 expect ( hasNewTodoDir ( ) ) . toBe ( true ) ;
8076} ) ;
8177
8278test ( "migrateIfNeeded returns true when already migrated" , async ( ) => {
8379 // Create new structure
84- await mkdir ( join ( TEST_DIR , ".math" , "todo" ) , { recursive : true } ) ;
80+ await mkdir ( join ( testDir , ".math" , "todo" ) , { recursive : true } ) ;
8581
8682 const result = await migrateIfNeeded ( ) ;
8783 expect ( result ) . toBe ( true ) ;
@@ -98,7 +94,7 @@ test("migrateIfNeeded returns true when no legacy directory exists", async () =>
9894
9995test ( "migrateIfNeeded moves files when user confirms (simulated)" , async ( ) => {
10096 // Create legacy structure with files
101- const legacyDir = join ( TEST_DIR , "todo" ) ;
97+ const legacyDir = join ( testDir , "todo" ) ;
10298 await mkdir ( legacyDir ) ;
10399 await writeFile ( join ( legacyDir , "TASKS.md" ) , "# Tasks\ncontent" ) ;
104100 await writeFile ( join ( legacyDir , "PROMPT.md" ) , "# Prompt\ncontent" ) ;
@@ -112,8 +108,8 @@ test("migrateIfNeeded moves files when user confirms (simulated)", async () => {
112108 // the pre-conditions and post-conditions that file moving would achieve
113109 // by manually performing what performMigration does
114110 const { rename } = await import ( "node:fs/promises" ) ;
115- const mathDir = join ( TEST_DIR , ".math" ) ;
116- const newTodoDir = join ( TEST_DIR , ".math" , "todo" ) ;
111+ const mathDir = join ( testDir , ".math" ) ;
112+ const newTodoDir = join ( testDir , ".math" , "todo" ) ;
117113
118114 await mkdir ( mathDir , { recursive : true } ) ;
119115 await rename ( legacyDir , newTodoDir ) ;
@@ -127,7 +123,7 @@ test("migrateIfNeeded moves files when user confirms (simulated)", async () => {
127123} ) ;
128124
129125test ( "legacy directory with multiple files is correctly detected" , async ( ) => {
130- const legacyDir = join ( TEST_DIR , "todo" ) ;
126+ const legacyDir = join ( testDir , "todo" ) ;
131127 await mkdir ( legacyDir ) ;
132128 await writeFile ( join ( legacyDir , "TASKS.md" ) , "# Tasks" ) ;
133129 await writeFile ( join ( legacyDir , "PROMPT.md" ) , "# Prompt" ) ;
@@ -137,7 +133,7 @@ test("legacy directory with multiple files is correctly detected", async () => {
137133} ) ;
138134
139135test ( "legacy directory with unrelated files is not detected" , async ( ) => {
140- const legacyDir = join ( TEST_DIR , "todo" ) ;
136+ const legacyDir = join ( testDir , "todo" ) ;
141137 await mkdir ( legacyDir ) ;
142138 await writeFile ( join ( legacyDir , "random.txt" ) , "random content" ) ;
143139
@@ -146,15 +142,15 @@ test("legacy directory with unrelated files is not detected", async () => {
146142
147143test ( "new todo directory detection is independent of file contents" , async ( ) => {
148144 // .math/todo just needs to exist, no files required
149- await mkdir ( join ( TEST_DIR , ".math" , "todo" ) , { recursive : true } ) ;
145+ await mkdir ( join ( testDir , ".math" , "todo" ) , { recursive : true } ) ;
150146 expect ( hasNewTodoDir ( ) ) . toBe ( true ) ;
151147
152148 // Even empty, it should be detected
153- expect ( existsSync ( join ( TEST_DIR , ".math" , "todo" , "TASKS.md" ) ) ) . toBe ( false ) ;
149+ expect ( existsSync ( join ( testDir , ".math" , "todo" , "TASKS.md" ) ) ) . toBe ( false ) ;
154150} ) ;
155151
156152test ( "migration preserves file contents" , async ( ) => {
157- const legacyDir = join ( TEST_DIR , "todo" ) ;
153+ const legacyDir = join ( testDir , "todo" ) ;
158154 await mkdir ( legacyDir ) ;
159155
160156 const tasksContent = "# Tasks\n\n## Phase 1\n\n### task-1\n- content: Test task" ;
@@ -167,8 +163,8 @@ test("migration preserves file contents", async () => {
167163
168164 // Perform migration manually (simulating user confirmation)
169165 const { rename, readFile } = await import ( "node:fs/promises" ) ;
170- const newTodoDir = join ( TEST_DIR , ".math" , "todo" ) ;
171- await mkdir ( join ( TEST_DIR , ".math" ) , { recursive : true } ) ;
166+ const newTodoDir = join ( testDir , ".math" , "todo" ) ;
167+ await mkdir ( join ( testDir , ".math" ) , { recursive : true } ) ;
172168 await rename ( legacyDir , newTodoDir ) ;
173169
174170 // Verify file contents are preserved
0 commit comments