@hyper-fetch/core
Version:
Cache, Queue and Persist your requests no matter if you are online or offline!
176 lines (158 loc) • 5.88 kB
text/typescript
import { waitFor } from "@testing-library/dom";
import type { CacheValueType } from "cache";
import { Client, Time, xhrExtra } from "index";
import { createCache, createLazyCacheAdapter } from "../../utils";
describe("Cache [ Garbage Collector ]", () => {
const cacheKey = "test";
const staleTime = 30000;
const version = "test";
const cacheTime = 10000;
const cacheData: CacheValueType = {
data: null,
error: null,
status: 200,
success: true,
extra: xhrExtra,
retries: 0,
requestTimestamp: +new Date(),
responseTimestamp: +new Date(),
addedTimestamp: +new Date(),
triggerTimestamp: +new Date(),
isCanceled: false,
isOffline: false,
willRetry: false,
cached: true,
staleTime,
version,
cacheTime,
cacheKey,
scope: null,
};
let client = new Client({ url: "shared-base-url" });
let request = client.createRequest()({ endpoint: "shared-endpoint", cacheKey, staleTime, cacheTime });
let cache = createCache(client, {
version,
});
beforeEach(async () => {
client = new Client({ url: "shared-base-url" });
request = client.createRequest()({ endpoint: "shared-endpoint", cacheKey, staleTime, cacheTime });
cache = createCache(client, {
version,
});
vi.resetAllMocks();
vi.clearAllMocks();
cacheData.requestTimestamp = +new Date();
cacheData.responseTimestamp = +new Date();
cacheData.addedTimestamp = +new Date();
cacheData.triggerTimestamp = +new Date();
});
describe("when garbage collector is triggered", () => {
it("should not schedule garbage collector for non existing key", async () => {
cache.scheduleGarbageCollector(cacheKey);
expect(Array.from(cache.garbageCollectors.keys())).toHaveLength(0);
});
it("should garbage collect data from sync storage", async () => {
cache.set(request.setCacheTime(10), cacheData);
await waitFor(() => {
expect(cache.get(cacheKey)).not.toBeDefined();
});
});
it("should garbage collect data from lazy storage", async () => {
cache.set(request, cacheData);
cache.scheduleGarbageCollector(request.cacheKey);
await waitFor(async () => {
expect(await cache.options?.lazyStorage?.get(cacheKey)).not.toBeDefined();
});
});
it("should schedule garbage collection on mount", async () => {
const storage = new Map().set("cacheKey", cacheData);
const cacheInstance = createCache(new Client({ url: "shared-base-url" }), {
storage,
version,
});
expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(1);
});
it("should not schedule lazy storage garbage collection on mount", async () => {
const lazyStorage = new Map<string, CacheValueType>();
lazyStorage.set(cacheKey, cacheData);
const cacheInstance = createCache(client, {
lazyStorage: createLazyCacheAdapter(lazyStorage),
version,
});
await waitFor(() => {
expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(0);
});
});
it("should schedule garbage collection when resource is added", async () => {
const spy = vi.spyOn(cache, "scheduleGarbageCollector");
cache.set(request, cacheData);
expect(spy).toHaveBeenCalledTimes(1);
});
it("should remove resource with not matching lazy version", async () => {
const lazyStorage = new Map<string, CacheValueType>();
const data = { ...cacheData, cacheTime: Time.MIN };
lazyStorage.set(request.cacheKey, data);
const newCache = createCache(client, {
lazyStorage: createLazyCacheAdapter(lazyStorage),
version: "new-clear-key",
});
const spy = vi.spyOn(lazyStorage, "delete");
// get to trigger garbage collector
newCache.get(request.cacheKey);
await waitFor(() => {
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(cacheKey);
});
});
it("should remove resource with not matching sync version", async () => {
const syncStorage = new Map<string, CacheValueType>();
const data = { ...cacheData, cacheTime: Time.MIN };
syncStorage.set(request.cacheKey, data);
const newCache = createCache(client, {
storage: syncStorage,
version: "new-clear-key",
});
const spy = vi.spyOn(syncStorage, "delete");
// get to trigger garbage collector
newCache.get(request.cacheKey);
await waitFor(() => {
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(cacheKey);
});
});
it("should not schedule garbage collection for Infinity", async () => {
const storage = new Map();
storage.set(cacheKey, { ...cacheData, cacheTime: Infinity });
const cacheInstance = createCache(client, {
storage,
version,
});
await waitFor(() => {
expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(0);
});
});
it("should garbage collect when time left is less than zero", async () => {
const pastTimestamp = +new Date() - 20000; // 20 seconds ago
const staleData = {
...cacheData,
responseTimestamp: pastTimestamp,
cacheTime: 10000, // 10 seconds
};
cache.set(request, staleData);
await waitFor(() => {
expect(cache.get(cacheKey)).not.toBeDefined();
});
});
it("should not schedule garbage collection for null", async () => {
const storage = new Map();
storage.set(cacheKey, { ...cacheData, cacheTime: null });
const cacheInstance = createCache(client, {
storage,
version,
});
await waitFor(() => {
expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(0);
});
});
});
});