@@ -1138,6 +1138,43 @@ describe("fetchWithSsrFGuard hardening", () => {
|
1138 | 1138 | await result.release(); |
1139 | 1139 | }); |
1140 | 1140 | |
| 1141 | +it("rejects timed-out fetches even when dispatcher close stalls", async () => { |
| 1142 | +agentCtor.mockImplementationOnce(function MockAgent(this: { close: () => Promise<void> }) { |
| 1143 | +this.close = () => new Promise(() => {}); |
| 1144 | +}); |
| 1145 | +(globalThis as Record<string, unknown>)[TEST_UNDICI_RUNTIME_DEPS_KEY] = { |
| 1146 | +Agent: agentCtor, |
| 1147 | +EnvHttpProxyAgent: envHttpProxyAgentCtor, |
| 1148 | +ProxyAgent: proxyAgentCtor, |
| 1149 | +fetch: vi.fn(async () => okResponse()), |
| 1150 | +}; |
| 1151 | +const fetchImpl = vi.fn( |
| 1152 | +(_input: RequestInfo | URL, init?: RequestInit) => |
| 1153 | +new Promise<Response>((_resolve, reject) => { |
| 1154 | +init?.signal?.addEventListener("abort", () => { |
| 1155 | +reject(init.signal?.reason ?? new Error("aborted")); |
| 1156 | +}); |
| 1157 | +}), |
| 1158 | +); |
| 1159 | + |
| 1160 | +const fetchPromise = fetchWithSsrFGuard({ |
| 1161 | +url: "https://public.example/resource", |
| 1162 | + fetchImpl, |
| 1163 | +lookupFn: createPublicLookup(), |
| 1164 | +timeoutMs: 1, |
| 1165 | +}); |
| 1166 | + |
| 1167 | +const outcome = await Promise.race([ |
| 1168 | +fetchPromise.then( |
| 1169 | +() => "resolved", |
| 1170 | +(error: unknown) => (error instanceof Error ? error.name : "rejected"), |
| 1171 | +), |
| 1172 | +new Promise<string>((resolve) => setTimeout(() => resolve("hung"), 250)), |
| 1173 | +]); |
| 1174 | + |
| 1175 | +expect(outcome).toBe("TimeoutError"); |
| 1176 | +}); |
| 1177 | + |
1141 | 1178 | it("inherits the configured global stream timeout for guarded direct dispatchers", async () => { |
1142 | 1179 | try { |
1143 | 1180 | ensureGlobalUndiciStreamTimeouts({ timeoutMs: 1_900_000 }); |
|