UNPKG

@daiso-tech/core

Version:

The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.

1,164 lines 76.3 kB
/** * @module Cache */ import { vi, } from "vitest"; import { KeyNotFoundCacheError, CACHE_EVENTS, KeyExistsCacheError, } from "../../../cache/contracts/_module.js"; import { Key } from "../../../namespace/_module.js"; import { Task } from "../../../task/implementations/_module.js"; import {} from "../../../time-span/contracts/time-span.contract.js"; import { TimeSpan } from "../../../time-span/implementations/_module.js"; import {} from "../../../utilities/_module.js"; /** * The `cacheTestSuite` function simplifies the process of testing your custom implementation of {@link ICache | `ICache`} with `vitest`. * * IMPORT_PATH: `"@daiso-tech/core/cache/test-utilities"` * @group TestUtilities * @example * ```ts * import { beforeEach, describe, expect, test } from "vitest"; * import { cacheTestSuite } from "@daiso-tech/core/cache/test-utilities"; * import { MemoryCacheAdapter } from "@daiso-tech/core/cache/memory-cache-adapter"; * import { Cache } from "@daiso-tech/core/cache"; * * describe("class: Cache", () => { * cacheTestSuite({ * createCache: () => { * return new Cache({ * adapter: new MemoryCacheAdapter(), * }); * }, * test, * beforeEach, * expect, * describe, * }); * }); * ``` */ export function cacheTestSuite(settings) { const { expect, test, createCache, describe, beforeEach, excludeEventTests = false, } = settings; let cache; beforeEach(async () => { cache = (await createCache()); }); async function delay(ttl) { await Task.delay(ttl); } const TTL = TimeSpan.fromMilliseconds(50); const LONG_TTL = TimeSpan.fromMinutes(5); describe("Api tests:", () => { describe("method: exists", () => { test("Should return false when key does not exists", async () => { const key = "a"; const result = await cache.exists(key); expect(result).toBe(false); }); test("Should return false when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = await cache.exists(key); expect(result).toBe(false); }); test("Should return true when key exists", async () => { const key = "a"; await cache.add(key, 1); const result = await cache.exists(key); expect(result).toBe(true); }); test("Should return true when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); const result = await cache.exists(key); expect(result).toBe(true); }); }); describe("method: missing", () => { test("Should return true when key does not exists", async () => { const key = "a"; const result = await cache.missing(key); expect(result).toBe(true); }); test("Should return true when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = await cache.missing(key); expect(result).toBe(true); }); test("Should return false when key exists", async () => { const key = "a"; await cache.add(key, 1); const result = await cache.missing(key); expect(result).toBe(false); }); test("Should return false when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); const result = await cache.missing(key); expect(result).toBe(false); }); }); describe("method: get", () => { test("Should return null when key does not exists", async () => { const key = "a"; const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return null when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const result = await cache.get(key); expect(result).toBe(value); }); test("Should return value when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const result = await cache.get(key); expect(result).toBe(value); }); }); describe("method: getOrFail", () => { test("Should throw KeyNotFoundCacheError when key does not exists", async () => { const key = "a"; const result = cache.getOrFail(key); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should throw KeyNotFoundCacheError when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = cache.getOrFail(key); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should return value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const result = await cache.getOrFail(key); expect(result).toBe(value); }); test("Should return value when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const result = await cache.getOrFail(key); expect(result).toBe(value); }); }); describe("method: getOr", () => { test("Should return default value when key does not exists", async () => { const key = "a"; const defaultValue = -1; const result = await cache.getOr(key, defaultValue); expect(result).toBe(defaultValue); }); test("Should return default value when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const defaultValue = -1; const result = await cache.getOr(key, defaultValue); expect(result).toBe(defaultValue); }); test("Should return value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const defaultValue = -1; const result = await cache.getOr(key, defaultValue); expect(result).toBe(value); }); test("Should return value when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const defaultValue = -1; const result = await cache.getOr(key, defaultValue); expect(result).toBe(value); }); }); describe("method: getAndRemove", () => { test("Should return null when key does not exists", async () => { const key = "a"; const result = await cache.getAndRemove(key); expect(result).toBeNull(); }); test("Should return null when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = await cache.getAndRemove(key); expect(result).toBeNull(); }); test("Should return value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const result = await cache.getAndRemove(key); expect(result).toBe(value); }); test("Should return value when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const result = await cache.getAndRemove(key); expect(result).toBe(value); }); test("Should remove key when exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); await cache.getAndRemove(key); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should remove key when is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); await cache.getAndRemove(key); const result = await cache.get(key); expect(result).toBeNull(); }); }); describe("method: getOrAdd", () => { test("Should return value to add when key does not exists", async () => { const key = "a"; const valueToAdd = -1; const result = await cache.getOrAdd(key, valueToAdd); expect(result).toBe(valueToAdd); }); test("Should persist value when key does not exists", async () => { const key = "a"; const valueToAdd = -1; await cache.getOrAdd(key, valueToAdd); const result = await cache.get(key); expect(result).toBe(valueToAdd); }); test("Should return value to add when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const valueToAdd = -1; const result = await cache.getOrAdd(key, valueToAdd); expect(result).toBe(valueToAdd); }); test("Should persist value when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const valueToAdd = -1; await cache.getOrAdd(key, valueToAdd); const result = await cache.get(key); expect(result).toBe(valueToAdd); }); test("Should return value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const valueToAdd = -1; const result = await cache.getOrAdd(key, valueToAdd); expect(result).toBe(value); }); test("Should not persist value when key exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const valueToAdd = -1; await cache.getOrAdd(key, valueToAdd); const result = await cache.get(key); expect(result).toBe(value); }); test("Should return value when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const valueToAdd = -1; const result = await cache.getOrAdd(key, valueToAdd); expect(result).toBe(value); }); test("Should not persist when key is unexpired", async () => { const key = "a"; const value = 1; await cache.add(key, value, { ttl: LONG_TTL }); const valueToAdd = -1; await cache.getOrAdd(key, valueToAdd); const result = await cache.get(key); expect(result).toBe(value); }); }); describe("method: add", () => { test("Should return true when key does not exists", async () => { const key = "a"; const value = 1; const result = await cache.add(key, value); expect(result).toBe(true); }); test("Should persist value when key does not exists", async () => { const key = "a"; const value = 1; await cache.add(key, value); const result = await cache.get(key); expect(result).toBe(value); }); test("Should return true when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = await cache.add(key, value2); expect(result).toBe(true); }); test("Should persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; await cache.add(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should return false when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = await cache.add(key, value2); expect(result).toBe(false); }); test("Should return false when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = await cache.add(key, value2); expect(result).toBe(false); }); test("Should not persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.add(key, value2); const result = await cache.get(key); expect(result).toBe(value1); }); test("Should not persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.add(key, value2); const result = await cache.get(key); expect(result).toBe(value1); }); }); describe("method: addOrFail", () => { test("Should not throw error when key does not exists", async () => { const key = "a"; const value = 1; const result = cache.addOrFail(key, value); await expect(result).resolves.toBeUndefined(); }); test("Should persist value when key does not exists", async () => { const key = "a"; const value = 1; await cache.addOrFail(key, value); const result = await cache.get(key); expect(result).toBe(value); }); test("Should not throw error when key is expired", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = cache.addOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; await cache.addOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should throw KeyExistsCacheError when key exists", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1); const value2 = 2; const result = cache.addOrFail(key, value2); await expect(result).rejects.toBeInstanceOf(KeyExistsCacheError); }); test("Should throw KeyExistsCacheError when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1, { ttl: LONG_TTL, }); const value2 = 2; const result = cache.addOrFail(key, value2); await expect(result).rejects.toBeInstanceOf(KeyExistsCacheError); }); test("Should not persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1); const value2 = 2; try { await cache.addOrFail(key, value2); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBe(value1); }); test("Should not persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.addOrFail(key, value1, { ttl: LONG_TTL, }); const value2 = 2; try { await cache.addOrFail(key, value2); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBe(value1); }); }); describe("method: put", () => { test("Should return true when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = await cache.put(key, value2); expect(result).toBe(true); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.put(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should persist ttl when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.put(key, value2, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return true when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = await cache.put(key, value2); expect(result).toBe(true); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.put(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should persist ttl when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.put(key, value2, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return false when key does not exist", async () => { const key = "a"; const value = 1; const result = await cache.put(key, value); expect(result).toBe(false); }); test("Should persist value when key does not exist", async () => { const key = "a"; const value = 2; await cache.put(key, value); const result = await cache.get(key); expect(result).toBe(value); }); test("Should persist ttl when key does not exist", async () => { const key = "a"; const value = 2; await cache.put(key, value, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); const result = await cache.get(key); expect(result).toBeNull(); }); }); describe("method: update", () => { test("Should return false when key does not exists", async () => { const key = "a"; const value = 1; const result = await cache.update(key, value); expect(result).toBe(false); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; await cache.update(key, value); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return false when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = await cache.update(key, value2); expect(result).toBe(false); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; await cache.update(key, value2); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return true when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = await cache.update(key, value2); expect(result).toBe(true); }); test("Should return true when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = await cache.update(key, value2); expect(result).toBe(true); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.update(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.update(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); }); describe("method: updateOrFail", () => { test("Should throw KeyNotFoundCacheError when key does not exists", async () => { const key = "a"; const value = 1; const result = cache.updateOrFail(key, value); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; try { await cache.updateOrFail(key, value); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should throw KeyNotFoundCacheError when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = cache.updateOrFail(key, value2); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; try { await cache.updateOrFail(key, value2); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should not throw error when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = cache.updateOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should not throw error when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = cache.updateOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.updateOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.updateOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(value2); }); }); describe("method: increment", () => { test("Should return false when key does not exists", async () => { const key = "a"; const value = 1; const result = await cache.increment(key, value); expect(result).toBe(false); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; await cache.increment(key, value); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return false when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = await cache.increment(key, value2); expect(result).toBe(false); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; await cache.increment(key, value2); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return true when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = await cache.increment(key, value2); expect(result).toBe(true); }); test("Should return true when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = await cache.increment(key, value2); expect(result).toBe(true); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.increment(key, value2); const result = await cache.get(key); expect(result).toBe(3); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.increment(key, value2); const result = await cache.get(key); expect(result).toBe(3); }); }); describe("method: incrementOrFail", () => { test("Should throw KeyNotFoundCacheError when key does not exists", async () => { const key = "a"; const value = 1; const result = cache.incrementOrFail(key, value); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; try { await cache.incrementOrFail(key, value); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should throw KeyNotFoundCacheError when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = cache.incrementOrFail(key, value2); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; try { await cache.incrementOrFail(key, value2); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should not throw error when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = cache.incrementOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should not throw error when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = cache.incrementOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.incrementOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(3); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.incrementOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(3); }); }); describe("method: decrement", () => { test("Should return false when key does not exists", async () => { const key = "a"; const value = 1; const result = await cache.decrement(key, value); expect(result).toBe(false); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; await cache.decrement(key, value); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return false when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = await cache.decrement(key, value2); expect(result).toBe(false); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; await cache.decrement(key, value2); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should return true when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = await cache.decrement(key, value2); expect(result).toBe(true); }); test("Should return true when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = await cache.decrement(key, value2); expect(result).toBe(true); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.decrement(key, value2); const result = await cache.get(key); expect(result).toBe(-1); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.decrement(key, value2); const result = await cache.get(key); expect(result).toBe(-1); }); }); describe("method: decrementOrFail", () => { test("Should throw KeyNotFoundCacheError when key does not exists", async () => { const key = "a"; const value = 1; const result = cache.decrementOrFail(key, value); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key does not exists", async () => { const key = "a"; const value = 1; try { await cache.decrementOrFail(key, value); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should throw KeyNotFoundCacheError when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; const result = cache.decrementOrFail(key, value2); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not persist value when key is expired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const value2 = 2; try { await cache.decrementOrFail(key, value2); } catch { /* EMPTY */ } const result = await cache.get(key); expect(result).toBeNull(); }); test("Should not throw error when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; const result = cache.decrementOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should not throw error when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; const result = cache.decrementOrFail(key, value2); await expect(result).resolves.toBeUndefined(); }); test("Should persist value when key exists", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1); const value2 = 2; await cache.decrementOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(-1); }); test("Should persist value when key is unexpired", async () => { const key = "a"; const value1 = 1; await cache.add(key, value1, { ttl: LONG_TTL }); const value2 = 2; await cache.decrementOrFail(key, value2); const result = await cache.get(key); expect(result).toBe(-1); }); }); describe("method: remove", () => { test("Should return false when key does not exists", async () => { const key = "a"; const result = await cache.remove(key); expect(result).toBe(false); }); test("Should return false when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = await cache.remove(key); expect(result).toBe(false); }); test("Should return true when key exists", async () => { const key = "a"; await cache.add(key, 1); const result = await cache.remove(key); expect(result).toBe(true); }); test("Should return true when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); const result = await cache.remove(key); expect(result).toBe(true); }); test("Should persist removal when key exists", async () => { const key = "a"; await cache.add(key, 1); await cache.remove(key); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should persist removal when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); await cache.remove(key); const result = await cache.get(key); expect(result).toBeNull(); }); }); describe("method: removeOrFail", () => { test("Should throw KeyNotFoundCacheError when key does not exists", async () => { const key = "a"; const result = cache.removeOrFail(key); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should throw KeyNotFoundCacheError when key is expired", async () => { const key = "a"; await cache.add(key, 1, { ttl: TTL, }); await delay(TTL.addMilliseconds(10)); const result = cache.removeOrFail(key); await expect(result).rejects.toBeInstanceOf(KeyNotFoundCacheError); }); test("Should not throw error when key exists", async () => { const key = "a"; await cache.add(key, 1); const result = cache.removeOrFail(key); await expect(result).resolves.toBeUndefined(); }); test("Should not throw error when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); const result = cache.removeOrFail(key); await expect(result).resolves.toBeUndefined(); }); test("Should persist removal when key exists", async () => { const key = "a"; await cache.add(key, 1); await cache.removeOrFail(key); const result = await cache.get(key); expect(result).toBeNull(); }); test("Should persist removal when key is unexpired", async () => { const key = "a"; await cache.add(key, 1, { ttl: LONG_TTL }); await cache.removeOrFail(key); const result = await cache.get(key); expect(result).toBeNull(); }); }); describe("method: removeMany", () => { test("Should return false when all keys dont exists", async () => { const keyA = "a"; const keyB = "b"; const keyC = "c"; await cache.add(keyA, 1, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); const result = await cache.removeMany([keyA, keyB, keyC]); expect(result).toBe(false); }); test("Should return true when one key exists", async () => { const keyA = "a"; const keyB = "b"; const keyC = "c"; await cache.add(keyA, 1, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); await cache.add(keyC, 2); const result = await cache.removeMany([keyA, keyB, keyC]); expect(result).toBe(true); }); test("Should persist removal when one key exists", async () => { const keyA = "a"; const keyB = "b"; const keyC = "c"; await cache.add(keyA, 1, { ttl: TTL }); await delay(TTL.addMilliseconds(10)); await cache.add(keyC, 2); await cache.removeMany([keyA, keyB, keyC]); const resultA = await cache.get(keyA); expect(resultA).toBeNull(); const resultB = await cache.get(keyB); expect(resultB).toBeNull(); const resultC = await cache.get(keyC); expect(resultC).toBeNull(); }); }); }); describe.skipIf(excludeEventTests)("Event tests:", () => { describe("method: exists", () => { test("Should dispatch NotFoundCacheEvent when key doesnt exists", async () => { const handlerFn = vi.fn((_event) => { }); await cache.addListener(CACHE_EVENTS.NOT_FOUND, handlerFn); const key = "a"; await cache.exists(key); expect(handlerFn).toHaveBeenCalledOnce(); expect(handlerFn).toHaveBeenCalledWith({ key: expect.any(Key), }); const keyObj = handlerFn.mock.calls[0]?.[0].key; expect(keyObj?.get()).toBe(key); }); test("Should dispatch FoundCacheEvent when key exists", async () => { const handlerFn = vi.fn((_event) => { }); await cache.addListener(CACHE_EVENTS.FOUND, handlerFn); const key = "a"; const value = 1; await cache.add(key, value); await cache.exists(key); expect(handlerFn).toHaveBeenCalledOnce(); expect(handlerFn).toHaveBeenCalledWith({ key: expect.any(Key), value, }); const keyObj = handlerFn.mock.calls[0]?.[0].key; expect(keyObj?.get()).toBe(key); }); }); descri