diff --git a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx index 5c754b584c..180de98a46 100644 --- a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx +++ b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx @@ -16,12 +16,8 @@ import React from 'react'; import { renderHook, waitFor } from '@testing-library/react'; -import { - fetchApiRef, - discoveryApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; -import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; +import { fetchApiRef, discoveryApiRef } from '@backstage/core-plugin-api'; +import { TestApiProvider } from '@backstage/test-utils'; import { useCookieAuthRefresh } from './useCookieAuthRefresh'; describe('useCookieAuthRefresh', () => { @@ -43,8 +39,6 @@ describe('useCookieAuthRefresh', () => { }), }; - const storageApiMock = MockStorageApi.create(); - beforeEach(() => { jest.useFakeTimers({ now }); jest.clearAllMocks(); @@ -69,7 +63,6 @@ describe('useCookieAuthRefresh', () => { fetch: jest.fn().mockRejectedValue(error), }, ], - [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -100,7 +93,6 @@ describe('useCookieAuthRefresh', () => { .mockReturnValue(new Promise(() => {})), }, ], - [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -153,7 +145,6 @@ describe('useCookieAuthRefresh', () => { .mockReturnValue(new Promise(() => {})), }, ], - [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -208,7 +199,6 @@ describe('useCookieAuthRefresh', () => { fetch: jest.fn().mockRejectedValue(error), }, ], - [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -235,7 +225,6 @@ describe('useCookieAuthRefresh', () => { @@ -268,7 +257,6 @@ describe('useCookieAuthRefresh', () => { @@ -281,12 +269,14 @@ describe('useCookieAuthRefresh', () => { now + 2 * tenMinutesInMilliseconds; // simulating other tab refreshing the cookie - storageApiMock - .forBucket(`${pluginId}-auth-cookie-storage`) - .set( - 'expiresAt', - new Date(twentyMinutesFromNowInMilliseconds).toISOString(), - ); + new global.BroadcastChannel( + `${pluginId}-auth-cookie-expires-at`, + ).postMessage({ + action: 'COOKIE_REFRESH_SUCCESS', + payload: { + expiresAt: new Date(twentyMinutesFromNowInMilliseconds).toISOString(), + }, + }); // advance the timers in 10 minutes to match the old expires at jest.advanceTimersByTime(tenMinutesInMilliseconds); @@ -309,7 +299,6 @@ describe('useCookieAuthRefresh', () => { @@ -345,7 +334,6 @@ describe('useCookieAuthRefresh', () => { diff --git a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx index b5b5444e71..dfb13289db 100644 --- a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx +++ b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx @@ -14,11 +14,10 @@ * limitations under the License. */ -import { useEffect, useCallback } from 'react'; +import { useEffect, useCallback, useMemo } from 'react'; import { discoveryApiRef, fetchApiRef, - storageApiRef, useApi, } from '@backstage/core-plugin-api'; import { useAsync, useMountEffect } from '@react-hookz/web'; @@ -40,10 +39,13 @@ export function useCookieAuthRefresh(options: { | { status: 'success'; data: { expiresAt: string } } { const { pluginId, path = '/cookie' } = options ?? {}; const fetchApi = useApi(fetchApiRef); - const storageApi = useApi(storageApiRef); const discoveryApi = useApi(discoveryApiRef); - const store = storageApi.forBucket(`${pluginId}-auth-cookie-storage`); + const channel = useMemo(() => { + return 'BroadcastChannel' in window + ? new BroadcastChannel(`${pluginId}-auth-cookie-expires-at`) + : null; + }, [pluginId]); const [state, actions] = useAsync<{ expiresAt: string }>(async () => { const apiOrigin = await discoveryApi.getBaseUrl(pluginId); @@ -84,21 +86,26 @@ export function useCookieAuthRefresh(options: { if (state.status !== 'success' || !state.result) { return () => {}; } - const expiresAt = state.result.expiresAt; - store.set('expiresAt', expiresAt); - let cancel = refresh({ expiresAt }); - const subscription = store - .observe$('expiresAt') - .subscribe(({ value }) => { - if (!value) return; + channel?.postMessage({ + action: 'COOKIE_REFRESH_SUCCESS', + payload: state.result, + }); + let cancel = refresh(state.result); + const listener = ( + event: MessageEvent<{ action: string; payload: { expiresAt: string } }>, + ) => { + const { action, payload } = event.data; + if (action === 'COOKIE_REFRESH_SUCCESS') { cancel(); - cancel = refresh({ expiresAt: value }); - }); + cancel = refresh(payload); + } + }; + channel?.addEventListener('message', listener); return () => { cancel(); - subscription.unsubscribe(); + channel?.removeEventListener('message', listener); }; - }, [state, refresh, store]); + }, [state, refresh, channel]); // Initialising if (state.status === 'not-executed') { diff --git a/plugins/auth-react/src/setupTests.ts b/plugins/auth-react/src/setupTests.ts index 658016ffdd..6580ddffad 100644 --- a/plugins/auth-react/src/setupTests.ts +++ b/plugins/auth-react/src/setupTests.ts @@ -14,3 +14,36 @@ * limitations under the License. */ import '@testing-library/jest-dom'; + +global.BroadcastChannel = jest + .fn() + .mockImplementation((_channelName: string) => { + const listeners: ((event: { data: any }) => void)[] = []; + + return { + addEventListener: ( + type: string, + listener: (event: { data: any }) => void, + ) => { + if (type === 'message') { + listeners.push(listener); + } + }, + removeEventListener: ( + type: string, + listener: (event: { data: any }) => void, + ) => { + if (type === 'message') { + const index = listeners.indexOf(listener); + if (index !== -1) { + listeners.splice(index, 1); + } + } + }, + postMessage: (message: any) => { + listeners.forEach(listener => { + listener({ data: message }); + }); + }, + }; + }); diff --git a/plugins/techdocs-addons-test-utils/src/test-utils.tsx b/plugins/techdocs-addons-test-utils/src/test-utils.tsx index c3e7281116..51a4650f99 100644 --- a/plugins/techdocs-addons-test-utils/src/test-utils.tsx +++ b/plugins/techdocs-addons-test-utils/src/test-utils.tsx @@ -22,17 +22,12 @@ import { screen } from 'testing-library__dom'; import { Route } from 'react-router-dom'; import { act, render } from '@testing-library/react'; -import { - wrapInTestApp, - TestApiProvider, - MockStorageApi, -} from '@backstage/test-utils'; +import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils'; import { FlatRoutes } from '@backstage/core-app-api'; import { ApiRef, discoveryApiRef, fetchApiRef, - storageApiRef, } from '@backstage/core-plugin-api'; import { @@ -78,8 +73,6 @@ const scmIntegrationsApi = { fromConfig: jest.fn().mockReturnValue({}), }; -const storageApiMock = MockStorageApi.create(); - const discoveryApi = { getBaseUrl: jest .fn() @@ -232,7 +225,6 @@ export class TechDocsAddonTester { build() { const apis: TechdocsAddonTesterApis = [ [fetchApiRef, fetchApi], - [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApi], [techdocsApiRef, techdocsApi], [techdocsStorageApiRef, techdocsStorageApi], diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index abea660b62..ed8b05c661 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -19,7 +19,6 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { MockConfigApi, - MockStorageApi, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -39,7 +38,6 @@ import { configApiRef, discoveryApiRef, fetchApiRef, - storageApiRef, } from '@backstage/core-plugin-api'; const mockEntityMetadata = { @@ -82,8 +80,6 @@ const techdocsStorageApiMock: jest.Mocked = { syncEntityDocs: jest.fn(), }; -const storageApiMock = MockStorageApi.create(); - const discoveryApiMock = { getBaseUrl: jest .fn() @@ -121,7 +117,6 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {