Skip to content

Commit d32dd15

Browse files
committed
refactor(tests): replace mock with spy for improved test accuracy and remove unnecessary mock restores
1 parent 41ecb79 commit d32dd15

10 files changed

+51
-64
lines changed

tests/dos-prevention.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import { afterAll, describe, expect, test, mock } from "bun:test"
2-
3-
afterAll(() => {
4-
mock.restore()
5-
})
1+
import { describe, expect, test } from "bun:test"
62

73
describe("DoS and Resource Exhaustion Security Tests", () => {
84
describe("Request Parameter Validation", () => {

tests/enhanced-hooks.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@ import {
99
beforeEach,
1010
jest,
1111
afterAll,
12-
mock,
12+
spyOn,
1313
} from "bun:test"
1414
import { FetchProxy } from "../src/proxy"
1515
import { CircuitState } from "../src/types"
1616
import type { ProxyRequestOptions, CircuitBreakerResult } from "../src/types"
1717

18-
// Mock fetch for testing
19-
const mockFetch = jest.fn()
20-
;(global as any).fetch = mockFetch
18+
// Spy on fetch for testing
19+
let fetchSpy: ReturnType<typeof spyOn>
2120

2221
afterAll(() => {
23-
mock.restore()
22+
fetchSpy?.mockRestore()
2423
})
2524

2625
describe("Enhanced Hook Naming Conventions", () => {
@@ -39,8 +38,9 @@ describe("Enhanced Hook Naming Conventions", () => {
3938
headers: new Headers({ "content-type": "application/json" }),
4039
})
4140

42-
mockFetch.mockClear()
43-
mockFetch.mockResolvedValue(mockResponse)
41+
fetchSpy = spyOn(global, "fetch")
42+
fetchSpy.mockClear()
43+
fetchSpy.mockResolvedValue(mockResponse)
4444
})
4545

4646
describe("beforeRequest Hook", () => {
@@ -56,7 +56,7 @@ describe("Enhanced Hook Naming Conventions", () => {
5656

5757
expect(beforeRequestHook).toHaveBeenCalledTimes(1)
5858
expect(beforeRequestHook).toHaveBeenCalledWith(request, options)
59-
expect(mockFetch).toHaveBeenCalledTimes(1)
59+
expect(fetchSpy).toHaveBeenCalledTimes(1)
6060
})
6161

6262
it("should handle async beforeRequest hooks", async () => {
@@ -139,7 +139,7 @@ describe("Enhanced Hook Naming Conventions", () => {
139139
const request = new Request("https://example.com/test")
140140
const error = new Error("Network error")
141141

142-
mockFetch.mockRejectedValueOnce(error)
142+
fetchSpy.mockRejectedValueOnce(error)
143143

144144
const options: ProxyRequestOptions = {
145145
afterCircuitBreakerExecution: afterCircuitBreakerHook,
@@ -166,7 +166,7 @@ describe("Enhanced Hook Naming Conventions", () => {
166166
const request = new Request("https://example.com/test")
167167

168168
// Add some delay to the fetch
169-
mockFetch.mockImplementationOnce(
169+
fetchSpy.mockImplementationOnce(
170170
() =>
171171
new Promise((resolve) => setTimeout(() => resolve(mockResponse), 50)),
172172
)
@@ -296,8 +296,8 @@ describe("Enhanced Hook Naming Conventions", () => {
296296
await proxy.proxy(request, undefined, options)
297297

298298
// Verify the mock was called (we can't easily verify exact headers due to internal processing)
299-
expect(mockFetch).toHaveBeenCalledTimes(1)
300-
expect(mockFetch).toHaveBeenCalledWith(
299+
expect(fetchSpy).toHaveBeenCalledTimes(1)
300+
expect(fetchSpy).toHaveBeenCalledWith(
301301
expect.any(String),
302302
expect.objectContaining({
303303
headers: expect.any(Headers),
@@ -315,7 +315,7 @@ describe("Enhanced Hook Naming Conventions", () => {
315315
},
316316
})
317317

318-
mockFetch.mockResolvedValueOnce(originalResponse)
318+
fetchSpy.mockResolvedValueOnce(originalResponse)
319319

320320
const request = new Request("https://example.com/test")
321321

tests/header-injection.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
/**
22
* Security tests for header injection vulnerabilities
33
*/
4-
import { describe, expect, it, afterAll, mock } from "bun:test"
4+
import { describe, expect, it } from "bun:test"
55

66
import { recordToHeaders } from "../src/utils"
77

8-
afterAll(() => {
9-
mock.restore()
10-
})
11-
128
describe("Header Injection Security Tests", () => {
139
describe("CRLF Header Injection", () => {
1410
it("should reject header names with CRLF characters", () => {

tests/http-method-validation.test.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import { describe, it, expect, beforeEach, afterAll, mock } from "bun:test"
1+
import { describe, it, expect, beforeEach, spyOn, afterEach } from "bun:test"
22
import { validateHttpMethod } from "../src/utils"
33
import { FetchProxy } from "../src/proxy"
44

5-
afterAll(() => {
6-
mock.restore()
7-
})
8-
95
describe("HTTP Method Validation Security Tests", () => {
6+
let fetchSpy: ReturnType<typeof spyOn>
7+
8+
afterEach(() => {
9+
fetchSpy?.mockRestore()
10+
})
1011
describe("Direct Method Validation", () => {
1112
it("should reject CONNECT method", () => {
1213
expect(() => {
@@ -75,6 +76,15 @@ describe("HTTP Method Validation Security Tests", () => {
7576
base: "http://httpbin.org", // Use a real service for testing
7677
circuitBreaker: { enabled: false },
7778
})
79+
80+
// Mock fetch to return a successful response
81+
fetchSpy = spyOn(global, "fetch").mockResolvedValue(
82+
new Response("", {
83+
status: 200,
84+
statusText: "OK",
85+
headers: new Headers({ "content-type": "text/plain" }),
86+
})
87+
)
7888
})
7989

8090
it("should reject CONNECT method in proxy (if runtime allows it)", async () => {
@@ -107,6 +117,9 @@ describe("HTTP Method Validation Security Tests", () => {
107117
// The normalized request should work fine
108118
const response = await proxy.proxy(request)
109119
expect(response.status).toBe(200)
120+
121+
// Verify fetch was called
122+
expect(fetchSpy).toHaveBeenCalledTimes(1)
110123
})
111124

112125
it("should allow safe methods in proxy", async () => {
@@ -116,6 +129,9 @@ describe("HTTP Method Validation Security Tests", () => {
116129

117130
const response = await proxy.proxy(request)
118131
expect(response.status).toBe(200)
132+
133+
// Verify fetch was called
134+
expect(fetchSpy).toHaveBeenCalledTimes(1)
119135
})
120136

121137
it("should validate methods when passed through request options", async () => {

tests/index.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, beforeAll, afterAll, mock } from "bun:test"
1+
import { describe, it, expect, beforeAll, afterAll, spyOn } from "bun:test"
22
import createFetchGate, { FetchProxy } from "../src/index"
33
import {
44
buildURL,
@@ -55,7 +55,7 @@ describe("fetch-gate", () => {
5555

5656
afterAll(() => {
5757
server?.stop()
58-
mock.restore()
58+
// No need for explicit restore with spyOn as it's automatically cleaned up
5959
})
6060

6161
describe("createFetchGate", () => {
@@ -308,10 +308,9 @@ describe("fetch-gate", () => {
308308

309309
describe("Circuit Breaker Edge Cases", () => {
310310
it("should transition to HALF_OPEN state after reset timeout", async () => {
311-
// Custom mock for Date.now()
312-
const originalDateNow = Date.now
313-
let now = originalDateNow()
314-
global.Date.now = () => now
311+
// Spy on Date.now()
312+
let now = Date.now()
313+
const dateNowSpy = spyOn(Date, "now").mockImplementation(() => now)
315314

316315
const circuitBreaker = new CircuitBreaker({
317316
failureThreshold: 1,
@@ -330,8 +329,8 @@ describe("fetch-gate", () => {
330329

331330
expect(circuitBreaker.getState()).toBe(CircuitState.HALF_OPEN)
332331

333-
// Restore original Date.now()
334-
global.Date.now = originalDateNow
332+
// Restore Date.now() spy
333+
dateNowSpy.mockRestore()
335334
})
336335

337336
it("should reset failures after successful execution in HALF_OPEN state", async () => {

tests/logging.test.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
import {
2-
describe,
3-
expect,
4-
it,
5-
beforeEach,
6-
spyOn,
7-
afterAll,
8-
mock,
9-
} from "bun:test"
1+
import { describe, expect, it, beforeEach, spyOn, afterAll } from "bun:test"
102
import { FetchProxy } from "../src/proxy"
113
import {
124
ProxyLogger,
@@ -15,11 +7,11 @@ import {
157
} from "../src/logger"
168
import { CircuitState } from "../src/types"
179

18-
// Mock fetch for testing
19-
const originalFetch = global.fetch
10+
// Spy on fetch for testing
11+
let fetchSpy: ReturnType<typeof spyOn>
2012

2113
afterAll(() => {
22-
mock.restore()
14+
fetchSpy?.mockRestore()
2315
})
2416

2517
describe("Logging Integration", () => {

tests/path-traversal.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
import { describe, expect, test, mock, afterAll } from "bun:test"
1+
import { describe, expect, test } from "bun:test"
22
import { normalizeSecurePath } from "../src/utils"
33

4-
afterAll(() => {
5-
mock.restore()
6-
})
7-
84
describe("Path Traversal Security", () => {
95
describe("normalizeSecurePath", () => {
106
test("should normalize simple valid paths", () => {

tests/query-injection.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import { describe, it, expect, mock, afterAll } from "bun:test"
1+
import { describe, it, expect } from "bun:test"
22
import { buildQueryString } from "../src/utils"
33
import { FetchProxy } from "../src/proxy"
44

5-
afterAll(() => {
6-
mock.restore()
7-
})
8-
95
describe("Query String Injection Security Tests", () => {
106
describe("Parameter Name Validation", () => {
117
it("should handle parameter names with special characters safely", () => {

tests/security.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
import { describe, it, expect, afterAll, mock } from "bun:test"
1+
import { describe, it, expect } from "bun:test"
22
import { buildURL } from "../src/utils"
33

4-
afterAll(() => {
5-
mock.restore()
6-
})
7-
84
describe("Security Tests", () => {
95
describe("SSRF Prevention", () => {
106
it("should prevent file:// protocol access", () => {

tests/utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, mock, beforeEach } from "bun:test"
1+
import { describe, it, expect, beforeEach } from "bun:test"
22
import {
33
buildURL,
44
filterHeaders,

0 commit comments

Comments
 (0)