diff --git a/app/javascript/dashboard/helper/CacheHelper/dispatchCacheRevalidations.js b/app/javascript/dashboard/helper/CacheHelper/dispatchCacheRevalidations.js new file mode 100644 index 000000000..72c5797a4 --- /dev/null +++ b/app/javascript/dashboard/helper/CacheHelper/dispatchCacheRevalidations.js @@ -0,0 +1,10 @@ +import { cacheableModels } from './cacheableModels'; + +export const dispatchCacheRevalidations = (store, keys = {}) => + Promise.all( + cacheableModels + .filter(model => keys[model.name] !== undefined) + .map(model => + store.dispatch(model.dispatchPath, { newKey: keys[model.name] }) + ) + ); diff --git a/app/javascript/dashboard/helper/ReconnectService.js b/app/javascript/dashboard/helper/ReconnectService.js index 39b48ebff..59467ca55 100644 --- a/app/javascript/dashboard/helper/ReconnectService.js +++ b/app/javascript/dashboard/helper/ReconnectService.js @@ -6,7 +6,7 @@ import { isAInboxViewRoute, isNotificationRoute, } from 'dashboard/helper/routeHelpers'; -import { cacheableModels } from 'dashboard/helper/CacheHelper/cacheableModels'; +import { dispatchCacheRevalidations } from 'dashboard/helper/CacheHelper/dispatchCacheRevalidations'; const MAX_DISCONNECT_SECONDS = 10800; @@ -101,13 +101,7 @@ class ReconnectService { revalidateCaches = async () => { const keys = (await this.store.dispatch('accounts/getCacheKeys')) || {}; - await Promise.all( - cacheableModels - .filter(model => keys[model.name] !== undefined) - .map(model => - this.store.dispatch(model.dispatchPath, { newKey: keys[model.name] }) - ) - ); + await dispatchCacheRevalidations(this.store, keys); }; handleRouteSpecificFetch = async () => { diff --git a/app/javascript/dashboard/helper/actionCable.js b/app/javascript/dashboard/helper/actionCable.js index cdf1496e1..c7958b6f5 100644 --- a/app/javascript/dashboard/helper/actionCable.js +++ b/app/javascript/dashboard/helper/actionCable.js @@ -14,7 +14,7 @@ import { import { VOICE_CALL_PROVIDERS } from 'dashboard/helper/inbox'; import { VOICE_CALL_DIRECTION } from 'dashboard/components-next/message/constants'; import { FEATURE_FLAGS } from 'dashboard/featureFlags'; -import { cacheableModels } from './CacheHelper/cacheableModels'; +import { dispatchCacheRevalidations } from './CacheHelper/dispatchCacheRevalidations'; const { isImpersonating } = useImpersonation(); const UNREAD_COUNTS_REFETCH_THROTTLE_MS = 5000; @@ -270,12 +270,7 @@ class ActionCableConnector extends BaseActionCableConnector { }; onCacheInvalidate = data => { - const keys = data.cache_keys || {}; - cacheableModels.forEach(model => { - const newKey = keys[model.name]; - if (newKey === undefined) return; - this.app.$store.dispatch(model.dispatchPath, { newKey }); - }); + dispatchCacheRevalidations(this.app.$store, data.cache_keys); }; onVoiceCallIncoming = data => { diff --git a/app/javascript/dashboard/helper/specs/CacheHelper/dispatchCacheRevalidations.spec.js b/app/javascript/dashboard/helper/specs/CacheHelper/dispatchCacheRevalidations.spec.js new file mode 100644 index 000000000..e31559f0f --- /dev/null +++ b/app/javascript/dashboard/helper/specs/CacheHelper/dispatchCacheRevalidations.spec.js @@ -0,0 +1,37 @@ +import { dispatchCacheRevalidations } from '../../CacheHelper/dispatchCacheRevalidations'; + +describe('dispatchCacheRevalidations', () => { + it('dispatches revalidate actions for cacheable models present in the key payload', async () => { + const store = { + dispatch: vi.fn().mockResolvedValue(), + }; + + await dispatchCacheRevalidations(store, { + inbox: 'inbox-key', + label: 'label-key', + canned_response: 'canned-key', + unknown_model: 'ignored-key', + }); + + expect(store.dispatch).toHaveBeenCalledWith('inboxes/revalidate', { + newKey: 'inbox-key', + }); + expect(store.dispatch).toHaveBeenCalledWith('labels/revalidate', { + newKey: 'label-key', + }); + expect(store.dispatch).toHaveBeenCalledWith('revalidateCannedResponses', { + newKey: 'canned-key', + }); + expect(store.dispatch).toHaveBeenCalledTimes(3); + }); + + it('treats missing keys as an empty payload', async () => { + const store = { + dispatch: vi.fn(), + }; + + await dispatchCacheRevalidations(store); + + expect(store.dispatch).not.toHaveBeenCalled(); + }); +});