Files
karma/ui/src/Common/Fetch.test.ts
2023-07-25 19:16:46 +01:00

126 lines
3.5 KiB
TypeScript

import { CommonOptions, FetchGet, FetchRetryConfig } from "./Fetch";
import merge from "lodash.merge";
import fetchMock from "fetch-mock";
beforeEach(() => {
fetchMock.reset();
fetchMock.mock("*", {
status: 200,
body: "ok",
});
});
afterEach(() => {
jest.restoreAllMocks();
fetchMock.reset();
});
describe("Fetch", () => {
const tests = {
FetchGet: FetchGet,
};
const methodOptions: { [key: string]: RequestInit } = {
FetchGet: { method: "GET", mode: "cors" },
};
for (const [name, func] of Object.entries(tests)) {
it(`${name}: passes '{credentials: include}' to all requests`, async () => {
const request = func("http://example.com/", {}, jest.fn());
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
merge({}, CommonOptions, methodOptions[name]),
);
});
it(`${name}: custom keys are merged with defaults`, async () => {
const request = func(
"http://example.com/",
{
keepalive: false,
},
() => {},
);
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
merge(
{},
CommonOptions,
methodOptions[name],
{ keepalive: false },
() => {},
),
);
});
it(`${name}: custom credentials are used when passed`, async () => {
const request = func(
"http://example.com",
{
credentials: "omit",
redirect: "follow",
},
() => {},
);
await expect(request).resolves.toMatchObject({ status: 200 });
expect(fetchMock.lastUrl()).toBe("http://example.com/");
expect(fetchMock.lastOptions()).toEqual(
merge({}, CommonOptions, methodOptions[name], {
credentials: "omit",
redirect: "follow",
}),
);
});
}
it("FetchGet switches to no-cors for the last retry", async () => {
fetchMock.reset();
fetchMock.mock("*", {
throws: new Error("Fetch error"),
});
const request = FetchGet("http://example.com", {}, jest.fn());
await expect(request).rejects.toThrow("Fetch error");
expect(fetchMock.calls()).toHaveLength(FetchRetryConfig.retries + 1);
expect(fetchMock.calls().map((r) => r[1])).toMatchObject(
Array.from(Array(FetchRetryConfig.retries + 1).keys(), (i) => ({
mode: i < FetchRetryConfig.retries ? "cors" : "no-cors",
credentials: "include",
})),
);
// ensure that the the second to last call was with cors
expect(fetchMock.calls()[fetchMock.calls().length - 2][1]).toMatchObject({
mode: "cors",
credentials: "include",
});
// ensure that the last call was with no-cors
expect(fetchMock.lastOptions()).toMatchObject({
mode: "no-cors",
credentials: "include",
});
});
it("FetchGet calls beforeRetry before each retry", async () => {
fetchMock.reset();
fetchMock.mock("*", {
throws: new Error("Fetch error"),
});
const beforeRetrySpy = jest.fn();
const request = FetchGet("http://example.com", {}, beforeRetrySpy);
await expect(request).rejects.toThrow("Fetch error");
expect(beforeRetrySpy).toHaveBeenCalledTimes(FetchRetryConfig.retries + 1);
for (let i = 0; i < FetchRetryConfig.retries + 1; i++) {
expect(beforeRetrySpy.mock.calls[i][0]).toBe(i + 1);
}
});
});