@hyper-fetch/core
Version:
Cache, Queue and Persist your requests no matter if you are online or offline!
225 lines (197 loc) • 7.84 kB
text/typescript
import EventEmitter from "events";
import { createHttpMockingServer, sleep } from "@hyper-fetch/testing";
import type { RequestProgressEventType } from "managers";
import { getRequestManagerEvents } from "managers";
import { Client } from "client";
import type { RequestInstance } from "request";
const { resetMocks, startServer, stopServer, mockRequest } = createHttpMockingServer();
describe("RequestManager [ Base ]", () => {
const abortKey = "abort-key";
const queryKey = "query-key";
const cacheKey = "cache-key";
const requestId = "some-id";
let client = new Client({ url: "shared-base-url" });
let events = getRequestManagerEvents(new EventEmitter());
beforeAll(() => {
startServer();
});
beforeEach(() => {
resetMocks();
vi.resetAllMocks();
client = new Client({ url: "shared-base-url" });
events = getRequestManagerEvents(new EventEmitter());
});
afterAll(() => {
stopServer();
});
describe("When app manager is initialized", () => {
it("should allow to add abort controller", async () => {
expect(client.requestManager.getAbortController(abortKey, requestId)).toBeUndefined();
client.requestManager.addAbortController(abortKey, requestId);
expect(client.requestManager.getAbortController(abortKey, requestId)).toBeDefined();
});
it("should allow to remove abort controller", async () => {
client.requestManager.addAbortController(abortKey, requestId);
client.requestManager.removeAbortController(abortKey, requestId);
expect(client.requestManager.getAbortController(abortKey, requestId)).toBeUndefined();
});
it("should not throw when removing non-existing controller", async () => {
expect(() => client.requestManager.removeAbortController(abortKey, requestId)).not.toThrow();
});
});
describe("When request is being aborted", () => {
it("should remove it from dispatcher's queue storage", async () => {
const spy = vi.fn();
const request = client.createRequest()({ endpoint: "shared-base-endpoint" });
mockRequest(request);
client.onResponse((response) => {
spy();
return response;
});
client.fetchDispatcher.add(request);
await sleep(5);
client.requestManager.abortAll();
await sleep(1);
const queue = client.fetchDispatcher.getQueue(request.queryKey);
expect(queue.requests).toHaveLength(0);
expect(spy).toHaveBeenCalledTimes(1);
});
});
describe("When events get emitted", () => {
it("should propagate the loading events", async () => {
const spy = vi.fn();
const spyQueue = vi.fn();
const spyById = vi.fn();
events.onLoadingByCache(cacheKey, spy);
events.onLoadingByQueue(queryKey, spyQueue);
events.onLoadingById(requestId, spyById);
const data = {
request: client.createRequest()({ endpoint: "shared-base-endpoint", cacheKey, queryKey }),
requestId,
loading: false,
isRetry: false,
isOffline: false,
};
events.emitLoading(data);
expect(spy).toHaveBeenCalledTimes(1);
expect(spyQueue).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should propagate the request start events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onRequestStartByQueue(queryKey, spy);
events.onRequestStartById(requestId, spyById);
const request = client.createRequest()({ endpoint: "shared-base-endpoint", cacheKey, queryKey });
events.emitRequestStart({ request, requestId });
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should propagate the response start events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onResponseStartByQueue(queryKey, spy);
events.onResponseStartById(requestId, spyById);
const request = client.createRequest()({ endpoint: "shared-base-endpoint", cacheKey, queryKey });
events.emitResponseStart({ request, requestId });
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should propagate the upload events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onUploadProgressByQueue(queryKey, spy);
events.onUploadProgressById(requestId, spyById);
const request = client.createRequest()({ endpoint: "shared-base-endpoint", cacheKey, queryKey });
const details: RequestProgressEventType<RequestInstance> = {
requestId,
request,
progress: 0,
timeLeft: 0,
sizeLeft: 0,
total: 0,
loaded: 0,
startTimestamp: 0,
};
events.emitUploadProgress(details);
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should propagate the download events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onDownloadProgressByQueue(queryKey, spy);
events.onDownloadProgressById(requestId, spyById);
const request = client.createRequest()({ endpoint: "shared-base-endpoint", cacheKey, queryKey });
const details: RequestProgressEventType<RequestInstance> = {
requestId,
request,
progress: 0,
timeLeft: 0,
sizeLeft: 0,
total: 0,
loaded: 0,
startTimestamp: 0,
};
events.emitDownloadProgress(details);
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
});
describe("When events get emitted", () => {
it("should propagate the response events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onResponseByCache(cacheKey, spy);
events.onResponseById(requestId, spyById);
events.emitResponse({
request: client.createRequest()({ endpoint: "shared-base-endpoint", queryKey, cacheKey }),
requestId,
response: {
data: null,
error: null,
status: 200,
success: true,
extra: null,
requestTimestamp: +new Date(),
responseTimestamp: +new Date(),
},
details: {
retries: 0,
isCanceled: false,
isOffline: false,
willRetry: false,
requestTimestamp: +new Date(),
responseTimestamp: +new Date(),
triggerTimestamp: +new Date(),
addedTimestamp: +new Date(),
},
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should propagate the remove events", async () => {
const spy = vi.fn();
const spyById = vi.fn();
events.onRemoveByQueue(queryKey, spy);
events.onRemoveById(requestId, spyById);
const request = client.createRequest()({ endpoint: "shared-base-endpoint", queryKey, cacheKey });
events.emitRemove({
requestId,
request,
resolved: true,
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spyById).toHaveBeenCalledTimes(1);
});
it("should not throw on not existing controller", async () => {
client.requestManager.addAbortController("test2", "test2");
const emptyAbortController = client.requestManager.getAbortController("test", "test");
const emptyAbortController2 = client.requestManager.getAbortController("test2", "test");
expect(emptyAbortController).not.toBeDefined();
expect(emptyAbortController2).not.toBeDefined();
expect(() => client.requestManager.useAbortController("test", "test")).not.toThrow();
expect(() => client.requestManager.useAbortController("test2", "test")).not.toThrow();
});
});
});