From 56af96f1da8a85b3e9c516684ea59537e678030a Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Tue, 26 Apr 2022 16:48:33 +0200 Subject: [PATCH] feat(ajax): add an option to initialize the cache interceptors even when useCache is turned off in the global options --- .changeset/silent-ravens-smell.md | 5 +++ packages/ajax/src/Ajax.js | 7 ++-- .../src/interceptors/cacheInterceptors.js | 20 ++++++---- packages/ajax/test/Ajax.test.js | 39 +++++++++++++++++++ .../interceptors/cacheInterceptors.test.js | 10 +---- packages/ajax/types/types.d.ts | 1 + 6 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 .changeset/silent-ravens-smell.md diff --git a/.changeset/silent-ravens-smell.md b/.changeset/silent-ravens-smell.md new file mode 100644 index 000000000..d9362530c --- /dev/null +++ b/.changeset/silent-ravens-smell.md @@ -0,0 +1,5 @@ +--- +'@lion/ajax': minor +--- + +Add an option "addCaching" to the Ajax config, in order to add cache interceptors when useCache is turned off. In this situation, all requests are cached proactively. diff --git a/packages/ajax/src/Ajax.js b/packages/ajax/src/Ajax.js index 337337b41..e2a64fe4d 100644 --- a/packages/ajax/src/Ajax.js +++ b/packages/ajax/src/Ajax.js @@ -23,11 +23,12 @@ export class Ajax { */ constructor(config = {}) { /** - * @type {Partial} + * @type {AjaxConfig} * @private */ this.__config = { addAcceptLanguage: true, + addCaching: false, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', jsonPrefix: '', @@ -53,7 +54,7 @@ export class Ajax { } const { cacheOptions } = this.__config; - if (cacheOptions?.useCache) { + if (cacheOptions.useCache || this.__config.addCaching) { const { cacheRequestInterceptor, cacheResponseInterceptor } = createCacheInterceptors( cacheOptions.getCacheIdentifier, cacheOptions, @@ -65,7 +66,7 @@ export class Ajax { /** * Configures the Ajax instance - * @param {Partial} config configuration for the Ajax instance + * @param {AjaxConfig} config configuration for the Ajax instance */ set options(config) { this.__config = config; diff --git a/packages/ajax/src/interceptors/cacheInterceptors.js b/packages/ajax/src/interceptors/cacheInterceptors.js index f00c1803b..dd440a9ea 100644 --- a/packages/ajax/src/interceptors/cacheInterceptors.js +++ b/packages/ajax/src/interceptors/cacheInterceptors.js @@ -10,6 +10,15 @@ import { isCurrentSessionId, } from '../cacheManager.js'; +/** + * Tests whether the request method is supported according to the `cacheOptions` + * @param {ValidatedCacheOptions} cacheOptions + * @param {string} method + * @returns {boolean} + */ +const isMethodSupported = (cacheOptions, method) => + cacheOptions.methods.includes(method.toLowerCase()); + /** * Request interceptor to return relevant cached requests * @param {function(): string} getCacheId used to invalidate cache if identifier is changed @@ -36,9 +45,8 @@ const createCacheRequestInterceptor = } const requestId = cacheOptions.requestIdFunction(request); - const isMethodSupported = cacheOptions.methods.includes(request.method.toLowerCase()); - if (!isMethodSupported) { + if (!isMethodSupported(cacheOptions, request.method)) { invalidateMatchingCache(requestId, cacheOptions); return request; } @@ -81,12 +89,9 @@ const createCacheResponseInterceptor = ...response.request.cacheOptions, }); - const requestId = cacheOptions.requestIdFunction(response.request); - const isAlreadyFromCache = !!response.fromCache; - const isCacheActive = cacheOptions.useCache; - const isMethodSupported = cacheOptions.methods.includes(response.request?.method.toLowerCase()); + if (!response.fromCache && isMethodSupported(cacheOptions, response.request.method)) { + const requestId = cacheOptions.requestIdFunction(response.request); - if (!isAlreadyFromCache && isCacheActive && isMethodSupported) { if (isCurrentSessionId(response.request.cacheSessionId)) { // Cache the response ajaxCache.set(requestId, response.clone()); @@ -95,6 +100,7 @@ const createCacheResponseInterceptor = // Mark the pending request as resolved pendingRequestStore.resolve(requestId); } + return response; }; diff --git a/packages/ajax/test/Ajax.test.js b/packages/ajax/test/Ajax.test.js index 08c117f81..8679e2955 100644 --- a/packages/ajax/test/Ajax.test.js +++ b/packages/ajax/test/Ajax.test.js @@ -43,6 +43,7 @@ describe('Ajax', () => { }; const expected = { addAcceptLanguage: true, + addCaching: false, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', jsonPrefix: ")]}',", @@ -303,6 +304,44 @@ describe('Ajax', () => { getCacheIdentifier = () => String(cacheId); }); + it('does not add cache interceptors when useCache is turned off', () => { + const customAjax = new Ajax({ + cacheOptions: { + maxAge: 100, + getCacheIdentifier, + }, + }); + + expect(customAjax._requestInterceptors.length).to.equal(2); + expect(customAjax._responseInterceptors.length).to.equal(0); + }); + + it('adds cache interceptors when useCache is turned on', () => { + const customAjax = new Ajax({ + cacheOptions: { + useCache: true, + maxAge: 100, + getCacheIdentifier, + }, + }); + + expect(customAjax._requestInterceptors.length).to.equal(3); + expect(customAjax._responseInterceptors.length).to.equal(1); + }); + + it('adds cache interceptors when addCaching is turned on', () => { + const customAjax = new Ajax({ + addCaching: true, + cacheOptions: { + maxAge: 100, + getCacheIdentifier, + }, + }); + + expect(customAjax._requestInterceptors.length).to.equal(3); + expect(customAjax._responseInterceptors.length).to.equal(1); + }); + describe('caching interceptors', async () => { /** * @type {Ajax} diff --git a/packages/ajax/test/interceptors/cacheInterceptors.test.js b/packages/ajax/test/interceptors/cacheInterceptors.test.js index da9157f83..ca14abe42 100644 --- a/packages/ajax/test/interceptors/cacheInterceptors.test.js +++ b/packages/ajax/test/interceptors/cacheInterceptors.test.js @@ -150,14 +150,12 @@ describe('cache interceptors', () => { expect(fetchStub.callCount).to.equal(1); }); - // TODO: Check if this is the behaviour we want - it('all calls with non-default `maxAge` are cached proactively', async () => { + it('all calls are cached proactively', async () => { // Given newCacheId(); addCacheInterceptors(ajax, { useCache: false, - maxAge: 100, }); // When @@ -169,11 +167,7 @@ describe('cache interceptors', () => { expect(fetchStub.callCount).to.equal(1); // When - await ajax.fetch('/test', { - cacheOptions: { - useCache: true, - }, - }); + await ajax.fetch('/test'); // Then expect(fetchStub.callCount).to.equal(2); diff --git a/packages/ajax/types/types.d.ts b/packages/ajax/types/types.d.ts index 0a8a231ab..fa63fea9f 100644 --- a/packages/ajax/types/types.d.ts +++ b/packages/ajax/types/types.d.ts @@ -12,6 +12,7 @@ export interface LionRequestInit extends Omit { export interface AjaxConfig { addAcceptLanguage: boolean; + addCaching: boolean; xsrfCookieName: string | null; xsrfHeaderName: string | null; cacheOptions: CacheOptionsWithIdentifier;