pi-lens 1.3.13 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,38 +1,30 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
2
  import { TestRunnerClient } from "./test-runner-client.js";
3
- import * as fs from "node:fs";
3
+ import { createTempFile, setupTestEnvironment } from "./test-utils.js";
4
4
  import * as path from "node:path";
5
- import * as os from "node:os";
6
5
 
7
6
  describe("TestRunnerClient", () => {
8
7
  let client: TestRunnerClient;
9
8
  let tmpDir: string;
10
-
11
- function createTempFile(name: string, content: string): string {
12
- const filePath = path.join(tmpDir, name);
13
- const dir = path.dirname(filePath);
14
- if (!fs.existsSync(dir)) {
15
- fs.mkdirSync(dir, { recursive: true });
16
- }
17
- fs.writeFileSync(filePath, content);
18
- return filePath;
19
- }
9
+ let cleanup: () => void;
20
10
 
21
11
  beforeEach(() => {
22
12
  client = new TestRunnerClient();
23
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-test-runner-"));
13
+ ({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-test-runner-"));
14
+ });
15
+
16
+ afterEach(() => {
17
+ cleanup();
24
18
  });
25
19
 
26
20
  afterEach(() => {
27
- if (tmpDir && fs.existsSync(tmpDir)) {
28
- fs.rmSync(tmpDir, { recursive: true });
29
- }
21
+ cleanup();
30
22
  });
31
23
 
32
24
  describe("detectRunner", () => {
33
25
  it("should detect vitest from config file", () => {
34
- createTempFile("vitest.config.ts", "export default {}");
35
- createTempFile("src/app.ts", "export const app = {};");
26
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
27
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
36
28
 
37
29
  const result = client.detectRunner(tmpDir);
38
30
  expect(result).not.toBeNull();
@@ -40,8 +32,8 @@ describe("TestRunnerClient", () => {
40
32
  });
41
33
 
42
34
  it("should detect jest from config file", () => {
43
- createTempFile("jest.config.js", "module.exports = {}");
44
- createTempFile("src/app.ts", "export const app = {};");
35
+ createTempFile(tmpDir, "jest.config.js", "module.exports = {}");
36
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
45
37
 
46
38
  const result = client.detectRunner(tmpDir);
47
39
  expect(result).not.toBeNull();
@@ -49,8 +41,8 @@ describe("TestRunnerClient", () => {
49
41
  });
50
42
 
51
43
  it("should detect pytest from config file", () => {
52
- createTempFile("pytest.ini", "[tool:pytest]");
53
- createTempFile("src/app.py", "x = 1");
44
+ createTempFile(tmpDir, "pytest.ini", "[tool:pytest]");
45
+ createTempFile(tmpDir, "src/app.py", "x = 1");
54
46
 
55
47
  const result = client.detectRunner(tmpDir);
56
48
  expect(result).not.toBeNull();
@@ -59,8 +51,8 @@ describe("TestRunnerClient", () => {
59
51
 
60
52
  it("should detect runner from node_modules", () => {
61
53
  // Create a node_modules/vitest to simulate installed package
62
- createTempFile("node_modules/vitest/package.json", "{}");
63
- createTempFile("src/app.ts", "export const app = {};");
54
+ createTempFile(tmpDir, "node_modules/vitest/package.json", "{}");
55
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
64
56
 
65
57
  const result = client.detectRunner(tmpDir);
66
58
  // Should detect vitest from node_modules
@@ -68,9 +60,9 @@ describe("TestRunnerClient", () => {
68
60
  });
69
61
 
70
62
  it("should prefer vitest over jest when both exist", () => {
71
- createTempFile("vitest.config.ts", "export default {}");
72
- createTempFile("jest.config.js", "module.exports = {}");
73
- createTempFile("src/app.ts", "export const app = {};");
63
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
64
+ createTempFile(tmpDir, "jest.config.js", "module.exports = {}");
65
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
74
66
 
75
67
  const result = client.detectRunner(tmpDir);
76
68
  expect(result!.runner).toBe("vitest");
@@ -79,9 +71,9 @@ describe("TestRunnerClient", () => {
79
71
 
80
72
  describe("findTestFile", () => {
81
73
  it("should find test file with .test.ts suffix", () => {
82
- createTempFile("vitest.config.ts", "export default {}");
83
- createTempFile("src/app.ts", "export const app = {};");
84
- createTempFile("src/app.test.ts", "describe('app', () => {});");
74
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
75
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
76
+ createTempFile(tmpDir, "src/app.test.ts", "describe('app', () => {});");
85
77
 
86
78
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
87
79
  expect(result).not.toBeNull();
@@ -90,9 +82,9 @@ describe("TestRunnerClient", () => {
90
82
  });
91
83
 
92
84
  it("should find test file with .spec.ts suffix", () => {
93
- createTempFile("vitest.config.ts", "export default {}");
94
- createTempFile("src/app.ts", "export const app = {};");
95
- createTempFile("src/app.spec.ts", "describe('app', () => {});");
85
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
86
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
87
+ createTempFile(tmpDir, "src/app.spec.ts", "describe('app', () => {});");
96
88
 
97
89
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
98
90
  expect(result).not.toBeNull();
@@ -100,9 +92,9 @@ describe("TestRunnerClient", () => {
100
92
  });
101
93
 
102
94
  it("should find test file in __tests__ directory", () => {
103
- createTempFile("vitest.config.ts", "export default {}");
104
- createTempFile("src/app.ts", "export const app = {};");
105
- createTempFile("src/__tests__/app.test.ts", "describe('app', () => {});");
95
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
96
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
97
+ createTempFile(tmpDir, "src/__tests__/app.test.ts", "describe('app', () => {});");
106
98
 
107
99
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
108
100
  expect(result).not.toBeNull();
@@ -110,9 +102,9 @@ describe("TestRunnerClient", () => {
110
102
  });
111
103
 
112
104
  it("should find test file in top-level tests/ directory", () => {
113
- createTempFile("vitest.config.ts", "export default {}");
114
- createTempFile("src/app.ts", "export const app = {};");
115
- createTempFile("tests/app.test.ts", "describe('app', () => {});");
105
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
106
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
107
+ createTempFile(tmpDir, "tests/app.test.ts", "describe('app', () => {});");
116
108
 
117
109
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
118
110
  expect(result).not.toBeNull();
@@ -120,9 +112,9 @@ describe("TestRunnerClient", () => {
120
112
  });
121
113
 
122
114
  it("should find pytest test file with test_ prefix", () => {
123
- createTempFile("pytest.ini", "[tool:pytest]");
124
- createTempFile("src/app.py", "x = 1");
125
- createTempFile("tests/test_app.py", "def test_app(): pass");
115
+ createTempFile(tmpDir, "pytest.ini", "[tool:pytest]");
116
+ createTempFile(tmpDir, "src/app.py", "x = 1");
117
+ createTempFile(tmpDir, "tests/test_app.py", "def test_app(): pass");
126
118
 
127
119
  const result = client.findTestFile(path.join(tmpDir, "src/app.py"), tmpDir);
128
120
  expect(result).not.toBeNull();
@@ -131,8 +123,8 @@ describe("TestRunnerClient", () => {
131
123
  });
132
124
 
133
125
  it("should return null when no test file found", () => {
134
- createTempFile("vitest.config.ts", "export default {}");
135
- createTempFile("src/app.ts", "export const app = {};");
126
+ createTempFile(tmpDir, "vitest.config.ts", "export default {}");
127
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
136
128
 
137
129
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
138
130
  expect(result).toBeNull();
@@ -140,9 +132,9 @@ describe("TestRunnerClient", () => {
140
132
 
141
133
  it("should find test file even without config (if runner installed)", () => {
142
134
  // Simulate vitest installed in node_modules
143
- createTempFile("node_modules/vitest/package.json", "{}");
144
- createTempFile("src/app.ts", "export const app = {};");
145
- createTempFile("src/app.test.ts", "describe('app', () => {});");
135
+ createTempFile(tmpDir, "node_modules/vitest/package.json", "{}");
136
+ createTempFile(tmpDir, "src/app.ts", "export const app = {};");
137
+ createTempFile(tmpDir, "src/app.test.ts", "describe('app', () => {});");
146
138
 
147
139
  const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
148
140
  // Should find the test file since vitest is "installed"
@@ -0,0 +1,31 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+
5
+ /**
6
+ * Creates a temporary file within the given temp directory.
7
+ * Automatically creates parent directories if they don't exist.
8
+ */
9
+ export function createTempFile(tmpDir: string, name: string, content: string): string {
10
+ const filePath = path.join(tmpDir, name);
11
+ const dir = path.dirname(filePath);
12
+ if (!fs.existsSync(dir)) {
13
+ fs.mkdirSync(dir, { recursive: true });
14
+ }
15
+ fs.writeFileSync(filePath, content);
16
+ return filePath;
17
+ }
18
+
19
+ /**
20
+ * Creates a temporary directory for testing.
21
+ * Returns the path and a cleanup function.
22
+ */
23
+ export function setupTestEnvironment(prefix: string): { tmpDir: string; cleanup: () => void } {
24
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
25
+ const cleanup = () => {
26
+ if (tmpDir && fs.existsSync(tmpDir)) {
27
+ fs.rmSync(tmpDir, { recursive: true });
28
+ }
29
+ };
30
+ return { tmpDir, cleanup };
31
+ }
@@ -1,37 +1,24 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
2
  import { TodoScanner } from "./todo-scanner.js";
3
- import * as fs from "node:fs";
4
- import * as path from "node:path";
5
- import * as os from "node:os";
3
+ import { createTempFile, setupTestEnvironment } from "./test-utils.js";
6
4
 
7
5
  describe("TodoScanner", () => {
8
- let scanner: TodoScanner;
6
+ let client: TodoScanner;
9
7
  let tmpDir: string;
10
-
11
- function createTempFile(name: string, content: string): string {
12
- const filePath = path.join(tmpDir, name);
13
- const dir = path.dirname(filePath);
14
- if (!fs.existsSync(dir)) {
15
- fs.mkdirSync(dir, { recursive: true });
16
- }
17
- fs.writeFileSync(filePath, content);
18
- return filePath;
19
- }
8
+ let cleanup: () => void;
20
9
 
21
10
  beforeEach(() => {
22
- scanner = new TodoScanner();
23
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-todo-test-"));
11
+ client = new TodoScanner();
12
+ ({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-todo-test-"));
24
13
  });
25
14
 
26
15
  afterEach(() => {
27
- if (tmpDir && fs.existsSync(tmpDir)) {
28
- fs.rmSync(tmpDir, { recursive: true });
29
- }
16
+ cleanup();
30
17
  });
31
18
 
32
19
  describe("scanFile", () => {
33
20
  it("should return empty array for non-existent files", () => {
34
- const result = scanner.scanFile("/nonexistent/file.ts");
21
+ const result = client.scanFile("/nonexistent/file.ts");
35
22
  expect(result).toEqual([]);
36
23
  });
37
24
 
@@ -40,8 +27,8 @@ describe("TodoScanner", () => {
40
27
  // TODO: implement this function
41
28
  function foo() {}
42
29
  `;
43
- const filePath = createTempFile("test.ts", content);
44
- const result = scanner.scanFile(filePath);
30
+ const filePath = createTempFile(tmpDir, "test.ts", content);
31
+ const result = client.scanFile(filePath);
45
32
 
46
33
  expect(result.length).toBe(1);
47
34
  expect(result[0].type).toBe("TODO");
@@ -53,8 +40,8 @@ function foo() {}
53
40
  // FIXME: this is broken
54
41
  function foo() {}
55
42
  `;
56
- const filePath = createTempFile("test.ts", content);
57
- const result = scanner.scanFile(filePath);
43
+ const filePath = createTempFile(tmpDir, "test.ts", content);
44
+ const result = client.scanFile(filePath);
58
45
 
59
46
  expect(result.length).toBe(1);
60
47
  expect(result[0].type).toBe("FIXME");
@@ -65,8 +52,8 @@ function foo() {}
65
52
  // HACK: temporary workaround
66
53
  const x = 1;
67
54
  `;
68
- const filePath = createTempFile("test.ts", content);
69
- const result = scanner.scanFile(filePath);
55
+ const filePath = createTempFile(tmpDir, "test.ts", content);
56
+ const result = client.scanFile(filePath);
70
57
 
71
58
  expect(result.length).toBe(1);
72
59
  expect(result[0].type).toBe("HACK");
@@ -77,8 +64,8 @@ const x = 1;
77
64
  // BUG: this causes a crash
78
65
  const x = 1;
79
66
  `;
80
- const filePath = createTempFile("test.ts", content);
81
- const result = scanner.scanFile(filePath);
67
+ const filePath = createTempFile(tmpDir, "test.ts", content);
68
+ const result = client.scanFile(filePath);
82
69
 
83
70
  expect(result.length).toBe(1);
84
71
  expect(result[0].type).toBe("BUG");
@@ -89,8 +76,8 @@ const x = 1;
89
76
  // NOTE: important design decision
90
77
  const x = 1;
91
78
  `;
92
- const filePath = createTempFile("test.ts", content);
93
- const result = scanner.scanFile(filePath);
79
+ const filePath = createTempFile(tmpDir, "test.ts", content);
80
+ const result = client.scanFile(filePath);
94
81
 
95
82
  expect(result.length).toBe(1);
96
83
  expect(result[0].type).toBe("NOTE");
@@ -103,8 +90,8 @@ const x = 1;
103
90
  */
104
91
  const x = 1;
105
92
  `;
106
- const filePath = createTempFile("test.ts", content);
107
- const result = scanner.scanFile(filePath);
93
+ const filePath = createTempFile(tmpDir, "test.ts", content);
94
+ const result = client.scanFile(filePath);
108
95
 
109
96
  expect(result.length).toBe(1);
110
97
  expect(result[0].type).toBe("TODO");
@@ -117,8 +104,8 @@ const x = 1;
117
104
  */
118
105
  function foo() {}
119
106
  `;
120
- const filePath = createTempFile("test.ts", content);
121
- const result = scanner.scanFile(filePath);
107
+ const filePath = createTempFile(tmpDir, "test.ts", content);
108
+ const result = client.scanFile(filePath);
122
109
 
123
110
  expect(result.length).toBe(1);
124
111
  expect(result[0].type).toBe("TODO");
@@ -130,8 +117,8 @@ function foo() {}
130
117
  def foo():
131
118
  pass
132
119
  `;
133
- const filePath = createTempFile("test.py", content);
134
- const result = scanner.scanFile(filePath);
120
+ const filePath = createTempFile(tmpDir, "test.py", content);
121
+ const result = client.scanFile(filePath);
135
122
 
136
123
  expect(result.length).toBe(1);
137
124
  expect(result[0].type).toBe("TODO");
@@ -141,8 +128,8 @@ def foo():
141
128
  const content = `
142
129
  const message = "TODO: buy milk";
143
130
  `;
144
- const filePath = createTempFile("test.ts", content);
145
- const result = scanner.scanFile(filePath);
131
+ const filePath = createTempFile(tmpDir, "test.ts", content);
132
+ const result = client.scanFile(filePath);
146
133
 
147
134
  expect(result.length).toBe(0);
148
135
  });
@@ -154,8 +141,8 @@ const y = 2;
154
141
  // TODO: fix this
155
142
  const z = 3;
156
143
  `;
157
- const filePath = createTempFile("test.ts", content);
158
- const result = scanner.scanFile(filePath);
144
+ const filePath = createTempFile(tmpDir, "test.ts", content);
145
+ const result = client.scanFile(filePath);
159
146
 
160
147
  expect(result[0].line).toBe(4);
161
148
  });
@@ -166,8 +153,8 @@ const z = 3;
166
153
  // FIXME: second
167
154
  // HACK: third
168
155
  `;
169
- const filePath = createTempFile("test.ts", content);
170
- const result = scanner.scanFile(filePath);
156
+ const filePath = createTempFile(tmpDir, "test.ts", content);
157
+ const result = client.scanFile(filePath);
171
158
 
172
159
  expect(result.length).toBe(3);
173
160
  });
@@ -175,41 +162,41 @@ const z = 3;
175
162
 
176
163
  describe("scanDirectory", () => {
177
164
  it("should scan all files in directory", () => {
178
- createTempFile("file1.ts", "// TODO: task 1");
179
- createTempFile("file2.ts", "// FIXME: bug 1");
180
- createTempFile("file3.py", "# HACK: workaround");
165
+ createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
166
+ createTempFile(tmpDir, "file2.ts", "// FIXME: bug 1");
167
+ createTempFile(tmpDir, "file3.py", "# HACK: workaround");
181
168
 
182
- const result = scanner.scanDirectory(tmpDir);
169
+ const result = client.scanDirectory(tmpDir);
183
170
 
184
171
  expect(result.items.length).toBe(3);
185
172
  });
186
173
 
187
174
  it("should skip node_modules", () => {
188
- createTempFile("src/file.ts", "// TODO: task 1");
189
- createTempFile("node_modules/lib/file.ts", "// TODO: should be skipped");
175
+ createTempFile(tmpDir, "src/file.ts", "// TODO: task 1");
176
+ createTempFile(tmpDir, "node_modules/lib/file.ts", "// TODO: should be skipped");
190
177
 
191
- const result = scanner.scanDirectory(tmpDir);
178
+ const result = client.scanDirectory(tmpDir);
192
179
 
193
180
  expect(result.items.length).toBe(1);
194
181
  expect(result.items[0].file).not.toContain("node_modules");
195
182
  });
196
183
 
197
184
  it("should group items by type", () => {
198
- createTempFile("file1.ts", "// TODO: task 1");
199
- createTempFile("file2.ts", "// TODO: task 2");
200
- createTempFile("file3.ts", "// FIXME: bug 1");
185
+ createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
186
+ createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
187
+ createTempFile(tmpDir, "file3.ts", "// FIXME: bug 1");
201
188
 
202
- const result = scanner.scanDirectory(tmpDir);
189
+ const result = client.scanDirectory(tmpDir);
203
190
 
204
191
  expect(result.byType.get("TODO")?.length).toBe(2);
205
192
  expect(result.byType.get("FIXME")?.length).toBe(1);
206
193
  });
207
194
 
208
195
  it("should group items by file", () => {
209
- createTempFile("file1.ts", "// TODO: task 1\n// FIXME: bug 1");
210
- createTempFile("file2.ts", "// TODO: task 2");
196
+ createTempFile(tmpDir, "file1.ts", "// TODO: task 1\n// FIXME: bug 1");
197
+ createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
211
198
 
212
- const result = scanner.scanDirectory(tmpDir);
199
+ const result = client.scanDirectory(tmpDir);
213
200
 
214
201
  const file1Items = [...result.byFile.entries()].find(([k]) => k.includes("file1.ts"));
215
202
  expect(file1Items?.[1].length).toBe(2);
@@ -219,7 +206,7 @@ const z = 3;
219
206
  describe("formatResult", () => {
220
207
  it("should return empty string for no results", () => {
221
208
  const result = { items: [], byType: new Map(), byFile: new Map() };
222
- expect(scanner.formatResult(result)).toBe("");
209
+ expect(client.formatResult(result)).toBe("");
223
210
  });
224
211
 
225
212
  it("should format results with counts", () => {
@@ -232,7 +219,7 @@ const z = 3;
232
219
  byFile: new Map([["test.ts", [{ type: "TODO" as const, message: "task 1", file: "test.ts", line: 1, column: 0 }]]]),
233
220
  };
234
221
 
235
- const formatted = scanner.formatResult(result);
222
+ const formatted = client.formatResult(result);
236
223
  expect(formatted).toContain("2 annotation(s)");
237
224
  expect(formatted).toContain("TODO");
238
225
  expect(formatted).toContain("FIXME");
@@ -248,7 +235,7 @@ const z = 3;
248
235
  byFile: new Map(),
249
236
  };
250
237
 
251
- const formatted = scanner.formatResult(result);
238
+ const formatted = client.formatResult(result);
252
239
  // Check that FIXME line comes before TODO line in the sorted output
253
240
  const fixmeLineIndex = formatted.indexOf("🔴");
254
241
  const todoLineIndex = formatted.indexOf("📝");
@@ -268,7 +255,7 @@ const z = 3;
268
255
  byFile: new Map(),
269
256
  };
270
257
 
271
- const formatted = scanner.formatResult(result);
258
+ const formatted = client.formatResult(result);
272
259
  expect(formatted).toContain("🔴"); // FIXME
273
260
  expect(formatted).toContain("🟠"); // HACK
274
261
  expect(formatted).toContain("🐛"); // BUG
@@ -130,6 +130,8 @@ export class TodoScanner {
130
130
  } else if (extensions.some(ext => entry.name.endsWith(ext))) {
131
131
  // Skip this scanner file — its own type literals and regex cause false positives
132
132
  if (entry.name === "todo-scanner.ts" || entry.name === "todo-scanner.js") continue;
133
+ // Skip test files — intentional annotations are test fixtures, not work items
134
+ if (/\.(test|spec)\.[jt]sx?$/.test(entry.name)) continue;
133
135
  items.push(...this.scanFile(fullPath));
134
136
  }
135
137
  }
@@ -1,22 +1,23 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
2
  import { TypeCoverageClient } from "./type-coverage-client.js";
3
- import * as fs from "node:fs";
4
- import * as path from "node:path";
5
- import * as os from "node:os";
3
+ import { setupTestEnvironment } from "./test-utils.js";
6
4
 
7
5
  describe("TypeCoverageClient", () => {
8
6
  let client: TypeCoverageClient;
9
7
  let tmpDir: string;
8
+ let cleanup: () => void;
10
9
 
11
10
  beforeEach(() => {
12
11
  client = new TypeCoverageClient();
13
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-typecoverage-test-"));
12
+ ({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-typecoverage-test-"));
14
13
  });
15
14
 
16
15
  afterEach(() => {
17
- if (tmpDir && fs.existsSync(tmpDir)) {
18
- fs.rmSync(tmpDir, { recursive: true });
19
- }
16
+ cleanup();
17
+ });
18
+
19
+ afterEach(() => {
20
+ cleanup();
20
21
  });
21
22
 
22
23
  describe("isAvailable", () => {
@@ -1,32 +1,23 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
2
  import { TypeScriptClient } from "./typescript-client.js";
3
- import * as fs from "node:fs";
4
- import * as path from "node:path";
5
- import * as os from "node:os";
3
+ import { createTempFile, setupTestEnvironment } from "./test-utils.js";
6
4
 
7
5
  describe("TypeScriptClient", () => {
8
6
  let client: TypeScriptClient;
9
7
  let tmpDir: string;
10
-
11
- function createTempFile(name: string, content: string): string {
12
- const filePath = path.join(tmpDir, name);
13
- const dir = path.dirname(filePath);
14
- if (!fs.existsSync(dir)) {
15
- fs.mkdirSync(dir, { recursive: true });
16
- }
17
- fs.writeFileSync(filePath, content);
18
- return filePath;
19
- }
8
+ let cleanup: () => void;
20
9
 
21
10
  beforeEach(() => {
22
11
  client = new TypeScriptClient();
23
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-ts-test-"));
12
+ ({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-ts-test-"));
13
+ });
14
+
15
+ afterEach(() => {
16
+ cleanup();
24
17
  });
25
18
 
26
19
  afterEach(() => {
27
- if (tmpDir && fs.existsSync(tmpDir)) {
28
- fs.rmSync(tmpDir, { recursive: true });
29
- }
20
+ cleanup();
30
21
  });
31
22
 
32
23
  describe("isTypeScriptFile", () => {
@@ -51,7 +42,7 @@ describe("TypeScriptClient", () => {
51
42
  const content = `
52
43
  const x: number = "string"; // Type error
53
44
  `;
54
- const filePath = createTempFile("test.ts", content);
45
+ const filePath = createTempFile(tmpDir, "test.ts", content);
55
46
 
56
47
  client.updateFile(filePath, content);
57
48
  const diags = client.getDiagnostics(filePath);
@@ -65,7 +56,7 @@ const x: number = "string"; // Type error
65
56
  const x: number = 42;
66
57
  const y: string = "hello";
67
58
  `;
68
- const filePath = createTempFile("test.ts", content);
59
+ const filePath = createTempFile(tmpDir, "test.ts", content);
69
60
 
70
61
  client.updateFile(filePath, content);
71
62
  const diags = client.getDiagnostics(filePath);
@@ -81,7 +72,7 @@ function test() {
81
72
  return undefinedVariable;
82
73
  }
83
74
  `;
84
- const filePath = createTempFile("test.ts", content);
75
+ const filePath = createTempFile(tmpDir, "test.ts", content);
85
76
 
86
77
  client.updateFile(filePath, content);
87
78
  const diags = client.getDiagnostics(filePath);
@@ -96,7 +87,7 @@ function add(a: number, b: number): number {
96
87
  }
97
88
  const result = add(1);
98
89
  `;
99
- const filePath = createTempFile("test.ts", content);
90
+ const filePath = createTempFile(tmpDir, "test.ts", content);
100
91
 
101
92
  client.updateFile(filePath, content);
102
93
  const diags = client.getDiagnostics(filePath);