## Description - Enabled the rule `@typescript-eslint/no-explicit-any` - Suppressed errors with comment ``` // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any ``` Fixes #35308 ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/10181176984> > Commit: 7fc604e24fa234da7ab2ff56e0b1c715268796ee > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10181176984&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Wed, 31 Jul 2024 15:00:45 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No
662 lines
23 KiB
TypeScript
662 lines
23 KiB
TypeScript
import { APP_MODE } from "entities/App";
|
|
import type { TApplicationParams } from "./serviceWorkerUtils";
|
|
import {
|
|
matchBuilderPath,
|
|
matchViewerPath,
|
|
getSearchQuery,
|
|
getConsolidatedApiPrefetchRequest,
|
|
getApplicationParamsFromUrl,
|
|
getPrefetchRequests,
|
|
PrefetchApiService,
|
|
} from "./serviceWorkerUtils";
|
|
import { Mutex } from "async-mutex";
|
|
import { Request as NFRequest, Response as NFResponse } from "node-fetch";
|
|
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).fetch = jest.fn() as jest.Mock;
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).caches = {
|
|
open: jest.fn(),
|
|
delete: jest.fn(),
|
|
};
|
|
|
|
const baseApplicationId = "b0123456789abcdef0000000";
|
|
const basePageId = "a0123456789abcdef0000000";
|
|
|
|
describe("serviceWorkerUtils", () => {
|
|
describe("matchBuilderPath", () => {
|
|
it("should match the standard builder path", () => {
|
|
const pathName = `/app/applicationSlug/pageSlug-${basePageId}/edit`;
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("applicationSlug");
|
|
expect(result.params).toHaveProperty("pageSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should match the standard builder path for alphanumeric basePageId", () => {
|
|
const pathName = `/app/applicationSlug/pageSlug-${basePageId}/edit`;
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("applicationSlug");
|
|
expect(result.params).toHaveProperty("pageSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should match the custom builder path", () => {
|
|
const pathName = `/app/customSlug-custom-${basePageId}/edit`;
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("customSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should match the deprecated builder path", () => {
|
|
const pathName = `/applications/${baseApplicationId}/pages/${basePageId}/edit`;
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty(
|
|
"baseApplicationId",
|
|
baseApplicationId,
|
|
);
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should not match incorrect builder path", () => {
|
|
const pathName = "/app/applicationSlug/nonMatching-123";
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeFalsy();
|
|
});
|
|
|
|
it("should not match when no basePageId is present", () => {
|
|
const pathName = "/app/applicationSlug/pageSlug-edit";
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
expect(result).toBeFalsy();
|
|
});
|
|
|
|
it("should match when the path is edit widgets", () => {
|
|
const pathName = `/app/applicationSlug/pageSlug-${basePageId}/edit/widgets/t36hb2zukr`;
|
|
const options = { end: false };
|
|
const result = matchBuilderPath(pathName, options);
|
|
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("applicationSlug");
|
|
expect(result.params).toHaveProperty("pageSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("matchViewerPath", () => {
|
|
it("should match the standard viewer path", () => {
|
|
const pathName = `/app/applicationSlug/pageSlug-${basePageId}`;
|
|
const result = matchViewerPath(pathName);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("applicationSlug");
|
|
expect(result.params).toHaveProperty("pageSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should match the custom viewer path", () => {
|
|
const pathName = `/app/customSlug-custom-${basePageId}`;
|
|
const result = matchViewerPath(pathName);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty("customSlug");
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should match the deprecated viewer path", () => {
|
|
const pathName = `/applications/${baseApplicationId}/pages/${basePageId}`;
|
|
const result = matchViewerPath(pathName);
|
|
|
|
expect(result).toBeTruthy();
|
|
if (result) {
|
|
expect(result.params).toHaveProperty(
|
|
"baseApplicationId",
|
|
baseApplicationId,
|
|
);
|
|
expect(result.params).toHaveProperty("basePageId", basePageId);
|
|
} else {
|
|
fail("Expected result to be truthy");
|
|
}
|
|
});
|
|
|
|
it("should not match when no basePageId is present", () => {
|
|
const pathName = "/app/applicationSlug/pageSlug";
|
|
const result = matchViewerPath(pathName);
|
|
|
|
expect(result).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe("getSearchQuery", () => {
|
|
it("should return the search query from the URL", () => {
|
|
const search = "?key=value";
|
|
const key = "key";
|
|
const result = getSearchQuery(search, key);
|
|
expect(result).toEqual("value");
|
|
});
|
|
|
|
it("should return an empty string if the key is not present in the URL", () => {
|
|
const search = "?key=value";
|
|
const key = "invalid";
|
|
const result = getSearchQuery(search, key);
|
|
expect(result).toEqual("");
|
|
});
|
|
|
|
it("should return an empty string if the search query is empty", () => {
|
|
const search = "";
|
|
const key = "key";
|
|
const result = getSearchQuery(search, key);
|
|
expect(result).toEqual("");
|
|
});
|
|
});
|
|
|
|
describe("getApplicationParamsFromUrl", () => {
|
|
it("should parse URL and return correct params for builder path", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/app/my-app/page-${basePageId}/edit?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId: undefined,
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should parse URL and return correct params for viewer path", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/app/my-app/page-${basePageId}?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId: undefined,
|
|
branchName: "main",
|
|
appMode: APP_MODE.PUBLISHED,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should return null if the path does not match any pattern", () => {
|
|
const url = new URL("https://app.appsmith.com/invalid/path?branch=main");
|
|
expect(getApplicationParamsFromUrl(url)).toBeNull();
|
|
});
|
|
|
|
it("should parse deprecated builder path and return correct params", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/applications/${baseApplicationId}/pages/${basePageId}/edit?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId,
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should parse deprecated viewer path and return correct params", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/applications/${baseApplicationId}/pages/${basePageId}?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId,
|
|
branchName: "main",
|
|
appMode: APP_MODE.PUBLISHED,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should parse custom builder path and return correct params", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/app/custom-app-${basePageId}/edit?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId: undefined,
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should parse custom viewer path and return correct params", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/app/custom-app-${basePageId}?branch=main`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId: undefined,
|
|
branchName: "main",
|
|
appMode: APP_MODE.PUBLISHED,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
|
|
it("should parse URL and return params with empty branch name if branch query param is not present", () => {
|
|
const url = new URL(
|
|
`https://app.appsmith.com/app/my-app/page-${basePageId}/edit`,
|
|
);
|
|
const expectedParams: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId: undefined,
|
|
branchName: "",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
expect(getApplicationParamsFromUrl(url)).toEqual(expectedParams);
|
|
});
|
|
});
|
|
|
|
describe("getConsolidatedApiPrefetchRequest", () => {
|
|
beforeAll(() => {
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).Request = NFRequest;
|
|
});
|
|
|
|
it("should return null if basePageId is not provided", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
expect(getConsolidatedApiPrefetchRequest(params)).toBeNull();
|
|
});
|
|
|
|
it("should create request for EDIT mode with applicationId", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId,
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
const request = getConsolidatedApiPrefetchRequest(params);
|
|
expect(request).toBeInstanceOf(Request);
|
|
expect(request?.url).toBe(
|
|
`https://app.appsmith.com/api/v1/consolidated-api/edit?defaultPageId=${basePageId}&applicationId=${baseApplicationId}`,
|
|
);
|
|
expect(request?.method).toBe("GET");
|
|
expect(request?.headers.get("Branchname")).toBe("main");
|
|
});
|
|
|
|
it("should create request for PUBLISHED mode with applicationId", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId,
|
|
baseApplicationId,
|
|
branchName: "main",
|
|
appMode: APP_MODE.PUBLISHED,
|
|
};
|
|
|
|
const request = getConsolidatedApiPrefetchRequest(params);
|
|
expect(request).toBeInstanceOf(Request);
|
|
expect(request?.url).toBe(
|
|
`https://app.appsmith.com/api/v1/consolidated-api/view?defaultPageId=${basePageId}&applicationId=${baseApplicationId}`,
|
|
);
|
|
expect(request?.method).toBe("GET");
|
|
expect(request?.headers.get("Branchname")).toBe("main");
|
|
});
|
|
|
|
it("should create request for EDIT mode without applicationId", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId: "page123",
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
};
|
|
|
|
const request = getConsolidatedApiPrefetchRequest(params);
|
|
expect(request).toBeInstanceOf(Request);
|
|
expect(request?.url).toBe(
|
|
`https://app.appsmith.com/api/v1/consolidated-api/edit?defaultPageId=page123`,
|
|
);
|
|
expect(request?.method).toBe("GET");
|
|
expect(request?.headers.get("Branchname")).toBe("main");
|
|
});
|
|
|
|
it("should create request for PUBLISHED mode without applicationId", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId: "page123",
|
|
branchName: "main",
|
|
appMode: APP_MODE.PUBLISHED,
|
|
};
|
|
|
|
const request = getConsolidatedApiPrefetchRequest(params);
|
|
expect(request).toBeInstanceOf(Request);
|
|
expect(request?.url).toBe(
|
|
`https://app.appsmith.com/api/v1/consolidated-api/view?defaultPageId=page123`,
|
|
);
|
|
expect(request?.method).toBe("GET");
|
|
expect(request?.headers.get("Branchname")).toBe("main");
|
|
});
|
|
|
|
it("should return null for an unknown app mode", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
basePageId: "page123",
|
|
branchName: "main",
|
|
appMode: "UNKNOWN" as APP_MODE,
|
|
};
|
|
|
|
expect(getConsolidatedApiPrefetchRequest(params)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("getPrefetchRequests", () => {
|
|
it("should return prefetch requests with consolidated api request", () => {
|
|
const params: TApplicationParams = {
|
|
origin: "https://app.appsmith.com",
|
|
branchName: "main",
|
|
appMode: APP_MODE.EDIT,
|
|
basePageId: "page123",
|
|
};
|
|
const requests = getPrefetchRequests(params);
|
|
expect(requests).toHaveLength(1);
|
|
const [consolidatedAPIRequest] = requests;
|
|
expect(consolidatedAPIRequest).toBeInstanceOf(Request);
|
|
expect(consolidatedAPIRequest?.url).toBe(
|
|
`https://app.appsmith.com/api/v1/consolidated-api/edit?defaultPageId=page123`,
|
|
);
|
|
expect(consolidatedAPIRequest?.method).toBe("GET");
|
|
expect(consolidatedAPIRequest?.headers.get("Branchname")).toBe("main");
|
|
});
|
|
});
|
|
|
|
describe("PrefetchApiService", () => {
|
|
let prefetchApiService: PrefetchApiService;
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
let mockCache: any;
|
|
|
|
beforeEach(() => {
|
|
prefetchApiService = new PrefetchApiService();
|
|
mockCache = {
|
|
put: jest.fn(),
|
|
match: jest.fn(),
|
|
delete: jest.fn(),
|
|
};
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).caches.open.mockResolvedValue(mockCache);
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).Request = NFRequest;
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).Response = NFResponse;
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe("getRequestKey", () => {
|
|
it("should return the correct request key", () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
request.headers.append("branchname", "main");
|
|
const key = prefetchApiService.getRequestKey(request);
|
|
expect(key).toBe("GET:https://app.appsmith.com/:branchname:main");
|
|
});
|
|
|
|
it("should only append branchname header in request key", () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
request.headers.append("branchname", "main");
|
|
request.headers.append("another-header-key", "another-header-value");
|
|
request.headers.append("Content-Type", "application/json");
|
|
const key = prefetchApiService.getRequestKey(request);
|
|
expect(key).toBe("GET:https://app.appsmith.com/:branchname:main");
|
|
});
|
|
});
|
|
|
|
describe("aqcuireFetchMutex", () => {
|
|
it("should acquire a new mutex if not present", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const acquireSpy = jest.spyOn(Mutex.prototype, "acquire");
|
|
await prefetchApiService.aqcuireFetchMutex(request);
|
|
expect(acquireSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should reuse existing mutex if present", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const mutex = new Mutex();
|
|
prefetchApiService.prefetchFetchMutexMap.set(
|
|
prefetchApiService.getRequestKey(request),
|
|
mutex,
|
|
);
|
|
const acquireSpy = jest.spyOn(mutex, "acquire");
|
|
await prefetchApiService.aqcuireFetchMutex(request);
|
|
expect(acquireSpy).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("waitForUnlock", () => {
|
|
it("should wait for the mutex to unlock if it exists", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const mutex = new Mutex();
|
|
prefetchApiService.prefetchFetchMutexMap.set(
|
|
prefetchApiService.getRequestKey(request),
|
|
mutex,
|
|
);
|
|
const waitForUnlockSpy = jest.spyOn(mutex, "waitForUnlock");
|
|
await prefetchApiService.waitForUnlock(request);
|
|
expect(waitForUnlockSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should do nothing if the mutex does not exist", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
await expect(
|
|
prefetchApiService.waitForUnlock(request),
|
|
).resolves.not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe("releaseFetchMutex", () => {
|
|
it("should release the mutex if it exists", () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const mutex = new Mutex();
|
|
prefetchApiService.prefetchFetchMutexMap.set(
|
|
prefetchApiService.getRequestKey(request),
|
|
mutex,
|
|
);
|
|
const releaseSpy = jest.spyOn(mutex, "release");
|
|
prefetchApiService.releaseFetchMutex(request);
|
|
expect(releaseSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should do nothing if the mutex does not exist", () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
expect(() =>
|
|
prefetchApiService.releaseFetchMutex(request),
|
|
).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe("cacheApi", () => {
|
|
it("should acquire the mutex, fetch the request, cache the response, and release the mutex", async () => {
|
|
const request = new Request("https://app.appsmith.com/sdfsdf", {
|
|
method: "GET",
|
|
});
|
|
const response = new Response("Test response", {
|
|
status: 200,
|
|
statusText: "OK",
|
|
});
|
|
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).fetch.mockResolvedValue(response);
|
|
|
|
const acquireSpy = jest.spyOn(Mutex.prototype, "acquire");
|
|
const releaseSpy = jest.spyOn(Mutex.prototype, "release");
|
|
|
|
await prefetchApiService.cacheApi(request);
|
|
|
|
expect(acquireSpy).toHaveBeenCalled();
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
expect((global as any).fetch).toHaveBeenCalledWith(request);
|
|
expect(mockCache.put).toHaveBeenCalledWith(
|
|
request,
|
|
expect.objectContaining({
|
|
status: 200,
|
|
statusText: "OK",
|
|
}),
|
|
);
|
|
expect(releaseSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should delete the cache and release the mutex if fetch fails", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
// TODO: Fix this the next time the file is edited
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
(global as any).fetch.mockRejectedValue(new Error("Fetch error"));
|
|
|
|
const acquireSpy = jest.spyOn(Mutex.prototype, "acquire");
|
|
const releaseSpy = jest.spyOn(Mutex.prototype, "release");
|
|
|
|
await prefetchApiService.cacheApi(request);
|
|
|
|
expect(acquireSpy).toHaveBeenCalled();
|
|
expect(mockCache.delete).toHaveBeenCalledWith(request);
|
|
expect(releaseSpy).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("getCachedResponse", () => {
|
|
it("should wait for the mutex to unlock, get the cached response if valid, and delete it afterwards", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const response = new Response("test response", {
|
|
headers: { date: new Date(Date.now() - 1000).toUTCString() },
|
|
});
|
|
mockCache.match.mockResolvedValue(response);
|
|
const mutex = new Mutex();
|
|
prefetchApiService.prefetchFetchMutexMap.set(
|
|
prefetchApiService.getRequestKey(request),
|
|
mutex,
|
|
);
|
|
const waitForUnlockSpy = jest.spyOn(Mutex.prototype, "waitForUnlock");
|
|
|
|
const cachedResponse =
|
|
await prefetchApiService.getCachedResponse(request);
|
|
|
|
expect(waitForUnlockSpy).toHaveBeenCalled();
|
|
expect(mockCache.match).toHaveBeenCalledWith(request);
|
|
expect(mockCache.delete).toHaveBeenCalledWith(request);
|
|
expect(cachedResponse).toBe(response);
|
|
});
|
|
|
|
it("should return null if the cache is invalid", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
const response = new Response("test response", {
|
|
headers: { date: new Date(Date.now() - 3 * 60 * 1000).toUTCString() },
|
|
});
|
|
mockCache.match.mockResolvedValue(response);
|
|
|
|
const cachedResponse =
|
|
await prefetchApiService.getCachedResponse(request);
|
|
|
|
expect(mockCache.match).toHaveBeenCalledWith(request);
|
|
expect(mockCache.delete).toHaveBeenCalledWith(request);
|
|
expect(cachedResponse).toBeNull();
|
|
});
|
|
|
|
it("should return null if there is no cached response", async () => {
|
|
const request = new Request("https://app.appsmith.com", {
|
|
method: "GET",
|
|
});
|
|
mockCache.match.mockResolvedValue(null);
|
|
|
|
const cachedResponse =
|
|
await prefetchApiService.getCachedResponse(request);
|
|
|
|
expect(mockCache.match).toHaveBeenCalledWith(request);
|
|
expect(cachedResponse).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
});
|