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:
+25
-11
@@ -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(...)
|
||||
```
|
||||
Reference in New Issue
Block a user