self-refreshing-cache.spec.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { createSelfRefreshingCache, SelfRefreshingCache } from './self-refreshing-cache';
  2. describe('SelfRefreshingCache', () => {
  3. let testCache: SelfRefreshingCache<number, [string]>;
  4. const fetchFn = jest.fn().mockImplementation((arg: string) => arg.length);
  5. let currentTime = 0;
  6. beforeAll(async () => {
  7. testCache = await createSelfRefreshingCache<number, [string]>({
  8. name: 'test',
  9. ttl: 1000,
  10. refresh: {
  11. fn: async arg => {
  12. return fetchFn(arg) as number;
  13. },
  14. defaultArgs: ['default'],
  15. },
  16. getTimeFn: () => currentTime,
  17. });
  18. });
  19. it('fetches value on first call', async () => {
  20. const result = await testCache.value();
  21. expect(result).toBe(7);
  22. expect(fetchFn.mock.calls.length).toBe(1);
  23. });
  24. it('passes default args on first call', () => {
  25. expect(fetchFn.mock.calls[0]).toEqual(['default']);
  26. });
  27. it('return from cache on second call', async () => {
  28. const result = await testCache.value();
  29. expect(result).toBe(7);
  30. expect(fetchFn.mock.calls.length).toBe(1);
  31. });
  32. it('automatically refresh after ttl expires', async () => {
  33. currentTime = 1001;
  34. const result = await testCache.value('custom');
  35. expect(result).toBe(6);
  36. expect(fetchFn.mock.calls.length).toBe(2);
  37. });
  38. it('refresh forces fetch with supplied args', async () => {
  39. const result = await testCache.refresh('new arg which is longer');
  40. expect(result).toBe(23);
  41. expect(fetchFn.mock.calls.length).toBe(3);
  42. expect(fetchFn.mock.calls[2]).toEqual(['new arg which is longer']);
  43. });
  44. describe('memoization', () => {
  45. const memoizedFn = jest.fn();
  46. let getMemoized: (arg1: string, arg2: number) => Promise<number>;
  47. beforeAll(() => {
  48. getMemoized = async (arg1, arg2) => {
  49. return testCache.memoize([arg1, arg2], ['quux'], async (value, a1, a2) => {
  50. memoizedFn(a1, a2);
  51. return value * +a2;
  52. });
  53. };
  54. });
  55. it('calls the memoized function only once for the given args', async () => {
  56. const result1 = await getMemoized('foo', 1);
  57. expect(result1).toBe(23 * 1);
  58. expect(memoizedFn.mock.calls.length).toBe(1);
  59. expect(memoizedFn.mock.calls[0]).toEqual(['foo', 1]);
  60. const result2 = await getMemoized('foo', 1);
  61. expect(result2).toBe(23 * 1);
  62. expect(memoizedFn.mock.calls.length).toBe(1);
  63. });
  64. it('calls the memoized function when args change', async () => {
  65. const result1 = await getMemoized('foo', 2);
  66. expect(result1).toBe(23 * 2);
  67. expect(memoizedFn.mock.calls.length).toBe(2);
  68. expect(memoizedFn.mock.calls[1]).toEqual(['foo', 2]);
  69. });
  70. it('retains memoized results from earlier calls', async () => {
  71. const result1 = await getMemoized('foo', 1);
  72. expect(result1).toBe(23 * 1);
  73. expect(memoizedFn.mock.calls.length).toBe(2);
  74. });
  75. it('re-fetches and re-runs memoized function after ttl expires', async () => {
  76. currentTime = 3000;
  77. const result1 = await getMemoized('foo', 1);
  78. expect(result1).toBe(4 * 1);
  79. expect(memoizedFn.mock.calls.length).toBe(3);
  80. await getMemoized('foo', 1);
  81. expect(memoizedFn.mock.calls.length).toBe(3);
  82. });
  83. it('works with alternating calls', async () => {
  84. const result1 = await getMemoized('foo', 1);
  85. expect(result1).toBe(4 * 1);
  86. expect(memoizedFn.mock.calls.length).toBe(3);
  87. const result2 = await getMemoized('foo', 3);
  88. expect(result2).toBe(4 * 3);
  89. expect(memoizedFn.mock.calls.length).toBe(4);
  90. const result3 = await getMemoized('foo', 1);
  91. expect(result3).toBe(4 * 1);
  92. expect(memoizedFn.mock.calls.length).toBe(4);
  93. const result4 = await getMemoized('foo', 3);
  94. expect(result4).toBe(4 * 3);
  95. expect(memoizedFn.mock.calls.length).toBe(4);
  96. const result5 = await getMemoized('foo', 1);
  97. expect(result5).toBe(4 * 1);
  98. expect(memoizedFn.mock.calls.length).toBe(4);
  99. });
  100. });
  101. });