- Introduced `.prettierrc.json` to enforce consistent code formatting across the project. - Updated unit and e2e test files to address formatting issues, improve readability, and ensure alignment with the new Prettier configuration.
166 lines
4.4 KiB
JavaScript
166 lines
4.4 KiB
JavaScript
import axios from "axios";
|
|
import { beforeEach, afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
__configureRequestQueueForTests,
|
|
__resetRequestQueueForTests,
|
|
requestQueueState,
|
|
} from "@/services/requestQueue.js";
|
|
import {
|
|
__resetAxiosRequestQueueInstallerForTests,
|
|
installAxiosRequestQueue,
|
|
} from "@/services/installAxiosRequestQueue.js";
|
|
|
|
const flushMicrotasks = async () => {
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
};
|
|
|
|
const flushManyMicrotasks = async (rounds = 10) => {
|
|
for (let index = 0; index < rounds; index += 1) {
|
|
await Promise.resolve();
|
|
}
|
|
};
|
|
|
|
const createDeferred = () => {
|
|
let resolve;
|
|
let reject;
|
|
const promise = new Promise((res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
});
|
|
|
|
return { promise, resolve, reject };
|
|
};
|
|
|
|
const createResponse = (data) => ({
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {},
|
|
config: {},
|
|
data,
|
|
});
|
|
|
|
describe("axios request queue interceptor", () => {
|
|
beforeEach(() => {
|
|
__resetAxiosRequestQueueInstallerForTests();
|
|
__resetRequestQueueForTests();
|
|
__configureRequestQueueForTests({ maxConcurrentGet: 1, maxConcurrentOther: 1, spacingMs: 0 });
|
|
installAxiosRequestQueue();
|
|
});
|
|
|
|
afterEach(() => {
|
|
__resetAxiosRequestQueueInstallerForTests();
|
|
__resetRequestQueueForTests();
|
|
});
|
|
|
|
it("queues plain axios requests system-wide", async () => {
|
|
const first = createDeferred();
|
|
const second = createDeferred();
|
|
const adapters = [first, second];
|
|
|
|
const requestOne = axios({
|
|
url: "/queue-test-1",
|
|
method: "GET",
|
|
adapter: () => adapters.shift()?.promise,
|
|
});
|
|
|
|
const requestTwo = axios({
|
|
url: "/queue-test-2",
|
|
method: "GET",
|
|
adapter: () => adapters.shift()?.promise,
|
|
});
|
|
|
|
await flushMicrotasks();
|
|
|
|
expect(requestQueueState.active).toBe(1);
|
|
expect(requestQueueState.pending).toBe(1);
|
|
expect(requestQueueState.batchTotal).toBe(2);
|
|
|
|
first.resolve(createResponse({ id: 1 }));
|
|
await flushManyMicrotasks();
|
|
|
|
expect(requestQueueState.active).toBe(1);
|
|
expect(requestQueueState.pending).toBe(0);
|
|
|
|
second.resolve(createResponse({ id: 2 }));
|
|
const [responseOne, responseTwo] = await Promise.all([requestOne, requestTwo]);
|
|
|
|
expect(responseOne.data).toEqual({ id: 1 });
|
|
expect(responseTwo.data).toEqual({ id: 2 });
|
|
|
|
await flushMicrotasks();
|
|
|
|
expect(requestQueueState.active).toBe(0);
|
|
expect(requestQueueState.pending).toBe(0);
|
|
expect(requestQueueState.batchCompleted).toBe(2);
|
|
expect(requestQueueState.batchFailed).toBe(0);
|
|
});
|
|
|
|
it("allows 5 concurrent GET requests", async () => {
|
|
__configureRequestQueueForTests({ maxConcurrentGet: 5, maxConcurrentOther: 1, spacingMs: 0 });
|
|
|
|
const allDeferred = Array.from({ length: 6 }, () => createDeferred());
|
|
const pendingAdapters = [...allDeferred];
|
|
const adapter = () => pendingAdapters.shift()?.promise;
|
|
|
|
const requests = Array.from({ length: 6 }, (_, index) =>
|
|
axios({
|
|
url: `/queue-get-${index + 1}`,
|
|
method: "GET",
|
|
adapter,
|
|
})
|
|
);
|
|
|
|
await flushMicrotasks();
|
|
|
|
expect(requestQueueState.active).toBe(5);
|
|
expect(requestQueueState.pending).toBe(1);
|
|
|
|
for (let index = 0; index < 5; index += 1) {
|
|
allDeferred[index].resolve(createResponse({ id: index + 1 }));
|
|
}
|
|
|
|
await flushManyMicrotasks();
|
|
|
|
expect(requestQueueState.active).toBe(1);
|
|
expect(requestQueueState.pending).toBe(0);
|
|
|
|
allDeferred[5].resolve(createResponse({ id: 6 }));
|
|
const responses = await Promise.all(requests);
|
|
|
|
expect(responses.map((item) => item.data.id)).toEqual([1, 2, 3, 4, 5, 6]);
|
|
});
|
|
|
|
it("retries configured response status codes", async () => {
|
|
__configureRequestQueueForTests({
|
|
maxConcurrentGet: 1,
|
|
maxConcurrentOther: 1,
|
|
spacingMs: 0,
|
|
retryByStatusCode: { 429: 2 },
|
|
retryDelayBaseMs: 0,
|
|
retryDelayMaxMs: 0,
|
|
retryDelayJitterMs: 0,
|
|
});
|
|
|
|
let attempts = 0;
|
|
const request = axios({
|
|
url: "/queue-retry-429",
|
|
method: "GET",
|
|
adapter: async () => {
|
|
attempts += 1;
|
|
if (attempts < 3) {
|
|
throw { response: { status: 429 } };
|
|
}
|
|
return createResponse({ ok: true, attempts });
|
|
},
|
|
});
|
|
|
|
const response = await request;
|
|
|
|
expect(response.data).toEqual({ ok: true, attempts: 3 });
|
|
expect(attempts).toBe(3);
|
|
expect(requestQueueState.batchCompleted).toBe(1);
|
|
expect(requestQueueState.batchFailed).toBe(0);
|
|
});
|
|
});
|