refactor(coding-agent): migrated fetch mocks to hookFetch utility with resource cleanup

- Replaced vi.spyOn fetch mocking pattern with hookFetch utility across 5 test files.
- Migrated fetch mocks to use resource management with 'using' keyword for automatic cleanup.
- Removed @ts-expect-error comments related to fetch.preconnect type issues.
- Updated ts-hook-fetch rule documentation with expanded patterns and clearer lifecycle guidance.
This commit is contained in:
can1357
2026-03-08 16:22:18 +01:00
parent 9d4ddef7b6
commit 486e585f39
5 changed files with 120 additions and 102 deletions
+25 -11
View File
@@ -1,20 +1,20 @@
---
description: Use hookFetch instead of assigning globalThis.fetch directly in tests
condition: "globalThis\\.fetch\\s*="
description: Use hookFetch instead of assigning or spying on globalThis.fetch in tests
condition: "globalThis\\.fetch\\s*=|spyOn\\(globalThis.*fetch"
scope: "tool:edit(**/*.test.{ts,tsx,js,jsx}), tool:write(**/*.test.{ts,tsx,js,jsx})"
---
**Do not assign `globalThis.fetch = ...` directly in tests.**
**Do not assign `globalThis.fetch` or use `vi.spyOn(globalThis, "fetch")` in tests.**
## Why it's wrong
- It bypasses the project's standard fetch mocking helper
- It is easier to forget restoration and leak state across tests
- It makes test mocking inconsistent across the codebase
- Forgetting restoration leaks state across tests
- `vi.spyOn` ties fetch mocking to vitest lifecycle instead of explicit scoping
- Makes test mocking inconsistent across the codebase
## What to use instead
Use `hookFetch` from `@oh-my-pi/pi-utils`:
Use `hookFetch` from `@oh-my-pi/pi-utils`. It returns a `Disposable` — use `using` for automatic cleanup:
```ts
import { hookFetch } from "@oh-my-pi/pi-utils";
@@ -30,8 +30,22 @@ using _hook = hookFetch((input, init, next) => {
// WRONG
globalThis.fetch = async () => new Response("ok");
// RIGHT
using _hook = hookFetch(() => new Response("ok"));
```
// WRONG
vi.spyOn(globalThis, "fetch").mockResolvedValue(new Response("ok"));
If you need to intercept fetch in tests, use `hookFetch`.
// RIGHT — fixed response
using _hook = hookFetch(() => new Response("ok"));
// RIGHT — conditional mock with passthrough
using _hook = hookFetch((input, init, next) => {
if (String(input).includes("127.0.0.1")) {
return new Response(JSON.stringify({ data: [] }));
}
return next(input, init);
});
// RIGHT — when you need vi.fn() for mock assertions
const fetchSpy = vi.fn(() => new Response("ok"));
using _hook = hookFetch(fetchSpy);
// later: expect(fetchSpy.mock.calls[0]).toEqual(...)
```