test(e2e): a localhost connect the machine dropped is tried again on the test side
On a Windows host a burst of test traffic can drop a loopback connect now and then (every port, any program — measured on the dev desktop). The browser resends it and only waits; Node (libuv) sends a loopback SYN once and fails at ~300 ms with "connect ETIMEDOUT". `e2e/retryConnect.ts` wraps Playwright's request context so that one error is tried again (0.5 / 1 / 2 / 4 / 8 s, the system's own retry waits) while every other failure goes straight to the test; global.setup's health check, login and /api/me and speed.measure's share probe go through it. Unit-tested; e2e 61/61.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// The e2e suite's request wrapper (e2e/retryConnect.ts): a connect that never came about is tried
|
||||
// again, as every TCP stack would; any other failure, or an answer, goes straight to the test.
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { retryConnect } from "../../e2e/retryConnect";
|
||||
|
||||
const noConnection = () => new Error("apiRequestContext.get: connect ETIMEDOUT 127.0.0.1:8080");
|
||||
|
||||
describe("retryConnect", () => {
|
||||
it("tries a connect that timed out again, and hands back the answer that came", async () => {
|
||||
vi.useFakeTimers();
|
||||
const get = vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(noConnection())
|
||||
.mockRejectedValueOnce(noConnection())
|
||||
.mockResolvedValue("ok");
|
||||
const api = retryConnect({ get });
|
||||
const answer = api.get("/healthz");
|
||||
await vi.runAllTimersAsync();
|
||||
await expect(answer).resolves.toBe("ok");
|
||||
expect(get).toHaveBeenCalledTimes(3);
|
||||
expect(get).toHaveBeenLastCalledWith("/healthz");
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("passes any other failure straight on, untried", async () => {
|
||||
const post = vi.fn().mockRejectedValue(new Error("read ECONNRESET"));
|
||||
await expect(retryConnect({ post }).post("/auth/password-login")).rejects.toThrow("ECONNRESET");
|
||||
expect(post).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("gives up after its last wait, with the connect error", async () => {
|
||||
vi.useFakeTimers();
|
||||
const get = vi.fn().mockRejectedValue(noConnection());
|
||||
const answer = retryConnect({ get }).get("/api/me");
|
||||
const settled = expect(answer).rejects.toThrow("ETIMEDOUT");
|
||||
await vi.runAllTimersAsync();
|
||||
await settled;
|
||||
expect(get).toHaveBeenCalledTimes(6); // the first try and five more
|
||||
vi.useRealTimers();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user