From aaab35ee171447b192be4879209aad70cff949f8 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 14 Mar 2024 08:42:35 +0100 Subject: [PATCH] refactor: apply second round of suggestions Signed-off-by: Camila Belo --- plugins/auth-react/api-report.md | 53 ++++----- plugins/auth-react/package.json | 2 +- .../CookieAuthRefreshProvider.test.tsx | 29 +++-- .../CookieAuthRefreshProvider.tsx | 37 +++--- .../src/hooks/useCookieAuthRefresh/index.ts | 5 +- .../useCookieAuthRefresh.test.tsx | 109 +++++------------- .../useCookieAuthRefresh.tsx | 76 +++++------- plugins/auth-react/src/setupTests.ts | 25 ---- .../src/test-utils.tsx | 10 +- .../TechDocsReaderPage.test.tsx | 28 +---- plugins/techdocs/src/setupTests.ts | 25 ---- yarn.lock | 4 +- 12 files changed, 145 insertions(+), 258 deletions(-) diff --git a/plugins/auth-react/api-report.md b/plugins/auth-react/api-report.md index 0e8a7dc8b7..9c2cf4622d 100644 --- a/plugins/auth-react/api-report.md +++ b/plugins/auth-react/api-report.md @@ -3,41 +3,38 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { AsyncState } from '@react-hookz/web'; -import { default as React_2 } from 'react'; import { ReactNode } from 'react'; -import { UseAsyncActions } from '@react-hookz/web'; // @public -export type CookieAuthRefreshOptions = { +export function CookieAuthRefreshProvider( + props: CookieAuthRefreshProviderProps, +): JSX.Element; + +// @public +export type CookieAuthRefreshProviderProps = { pluginId: string; - path?: string; -}; - -// @public -export function CookieAuthRefreshProvider({ - children, - ...rest -}: CookieAuthRefreshProviderProps): - | string - | number - | boolean - | Iterable - | React_2.JSX.Element - | null - | undefined; - -// @public -export type CookieAuthRefreshProviderProps = CookieAuthRefreshOptions & { + options?: { + path?: string; + }; children: ReactNode; }; // @public -export function useCookieAuthRefresh({ - pluginId, - path, -}: CookieAuthRefreshOptions): { - state: AsyncState; - actions: UseAsyncActions; +export function useCookieAuthRefresh(params: { + pluginId: string; + options?: { + path?: string; + }; +}): { + loading: boolean; + error: Error | undefined; + value: + | { + expiresAt: string; + } + | undefined; + retry: (...args: unknown[]) => Promise<{ + expiresAt: string; + }>; }; ``` diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 7bc248be67..875cb2f12f 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -36,7 +36,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", "@material-ui/core": "^4.9.13", - "@react-hookz/web": "^24.0.4", + "@react-hookz/web": "^24.0.0", "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0" }, "devDependencies": { diff --git a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx index e8e5eea24d..786136261c 100644 --- a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx +++ b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.test.tsx @@ -18,10 +18,19 @@ import React from 'react'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { CookieAuthRefreshProvider } from './CookieAuthRefreshProvider'; -import { TestApiProvider, renderInTestApp } from '@backstage/test-utils'; -import { discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api'; +import { + MockStorageApi, + TestApiProvider, + renderInTestApp, +} from '@backstage/test-utils'; +import { + discoveryApiRef, + fetchApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; describe('CookieAuthRefreshProvider', () => { + const storageApiMock = MockStorageApi.create(); const discoveryApiMock = { getBaseUrl: jest .fn() @@ -33,12 +42,6 @@ describe('CookieAuthRefreshProvider', () => { return new Date(Date.now() + tenMinutesInMilliseconds).toISOString(); } - global.BroadcastChannel = jest.fn().mockImplementation(() => ({ - postMessage: jest.fn(), - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - })); - it('should render a progress bar', async () => { const fetchApiMock = { fetch: jest.fn().mockReturnValue(new Promise(() => {})), @@ -48,6 +51,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -57,7 +61,9 @@ describe('CookieAuthRefreshProvider', () => { , ); - expect(screen.getByTestId('progress')).toBeInTheDocument(); + expect(screen.queryByText('Test Content')).not.toBeInTheDocument(); + + expect(screen.getByTestId('progress')).toBeVisible(); }); it('should render an error panel', async () => { @@ -70,6 +76,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -100,6 +107,7 @@ describe('CookieAuthRefreshProvider', () => { @@ -118,6 +126,8 @@ describe('CookieAuthRefreshProvider', () => { expect(fetchApiMock.fetch).toHaveBeenCalledTimes(1); + expect(screen.queryByText('Test Content')).not.toBeInTheDocument(); + expect(screen.getByText(error.message)).toBeInTheDocument(); await userEvent.click(screen.getByText('Retry')); @@ -143,6 +153,7 @@ describe('CookieAuthRefreshProvider', () => { diff --git a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.tsx b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.tsx index 4265b25cf0..2b553f33e8 100644 --- a/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.tsx +++ b/plugins/auth-react/src/components/CookieAuthRefreshProvider/CookieAuthRefreshProvider.tsx @@ -18,13 +18,20 @@ import React, { ReactNode } from 'react'; import { ErrorPanel } from '@backstage/core-components'; import { useApp } from '@backstage/core-plugin-api'; import { Button } from '@material-ui/core'; -import { useCookieAuthRefresh, CookieAuthRefreshOptions } from '../../hooks'; +import { useCookieAuthRefresh } from '../../hooks'; /** * @public * Props for the {@link CookieAuthRefreshProvider} component. */ -export type CookieAuthRefreshProviderProps = CookieAuthRefreshOptions & { +export type CookieAuthRefreshProviderProps = { + // The plugin ID to used for discovering the API origin + pluginId: string; + // Options for configuring the refresh cookie endpoint + options?: { + // The path to used for calling the refresh cookie endpoint, default to '/cookie' + path?: string; + }; // The children to render when the refresh is successful children: ReactNode; }; @@ -33,28 +40,28 @@ export type CookieAuthRefreshProviderProps = CookieAuthRefreshOptions & { * @public * A provider that will refresh the cookie when it is about to expire. */ -export function CookieAuthRefreshProvider({ - children, - ...rest -}: CookieAuthRefreshProviderProps) { +export function CookieAuthRefreshProvider( + props: CookieAuthRefreshProviderProps, +): JSX.Element { + const { children, ...params } = props; const app = useApp(); const { Progress } = app.getComponents(); - const { state, actions } = useCookieAuthRefresh(rest); + const { loading, error, retry } = useCookieAuthRefresh(params); - if (state.status === 'error' && state.error) { + if (loading) { + return ; + } + + if (error) { return ( - - ); } - if (state.status === 'loading') { - return ; - } - - return children; + return <>{children}; } diff --git a/plugins/auth-react/src/hooks/useCookieAuthRefresh/index.ts b/plugins/auth-react/src/hooks/useCookieAuthRefresh/index.ts index 43b1882959..42b60840f8 100644 --- a/plugins/auth-react/src/hooks/useCookieAuthRefresh/index.ts +++ b/plugins/auth-react/src/hooks/useCookieAuthRefresh/index.ts @@ -14,7 +14,4 @@ * limitations under the License. */ -export { - useCookieAuthRefresh, - type CookieAuthRefreshOptions, -} from './useCookieAuthRefresh'; +export { useCookieAuthRefresh } from './useCookieAuthRefresh'; diff --git a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx index 42fe6f4fca..eee3659c71 100644 --- a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx +++ b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.test.tsx @@ -16,8 +16,12 @@ import React from 'react'; import { renderHook, waitFor } from '@testing-library/react'; -import { fetchApiRef, discoveryApiRef } from '@backstage/core-plugin-api'; -import { TestApiProvider } from '@backstage/test-utils'; +import { + fetchApiRef, + discoveryApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { MockStorageApi, TestApiProvider } from '@backstage/test-utils'; import { useCookieAuthRefresh } from './useCookieAuthRefresh'; describe('useCookieAuthRefresh', () => { @@ -39,31 +43,11 @@ describe('useCookieAuthRefresh', () => { }), }; - type Listener = (event: { data: any }) => void; - - let listeners: Listener[]; - let channelMock: any; + const storageApiMock = MockStorageApi.create(); beforeEach(() => { jest.useFakeTimers({ now }); jest.clearAllMocks(); - listeners = []; - channelMock = { - postMessage: jest.fn((message: any) => { - listeners.forEach(listener => listener({ data: message })); - }), - addEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners.push(listener); - } - }), - removeEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners = listeners.filter(l => l !== listener); - } - }), - }; - global.BroadcastChannel = jest.fn().mockImplementation(() => channelMock); }); afterEach(() => { @@ -83,6 +67,7 @@ describe('useCookieAuthRefresh', () => { fetch: jest.fn(), }, ], + [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -92,7 +77,7 @@ describe('useCookieAuthRefresh', () => { }, ); - expect(result.current.state.status).toBe('loading'); + expect(result.current.loading).toBeTruthy(); }); it('should return an error status when the refresh has failed', async () => { @@ -110,6 +95,7 @@ describe('useCookieAuthRefresh', () => { fetch: jest.fn().mockRejectedValue(error), }, ], + [storageApiRef, storageApiMock], [discoveryApiRef, discoveryApiMock], ]} > @@ -119,9 +105,7 @@ describe('useCookieAuthRefresh', () => { }, ); - await waitFor(() => expect(result.current.state.status).toBe('error')); - - expect(result.current.state.error).toStrictEqual(error); + await waitFor(() => expect(result.current.error).toStrictEqual(error)); }); it('should call the api to get the cookie and use it', async () => { @@ -132,6 +116,7 @@ describe('useCookieAuthRefresh', () => { @@ -148,46 +133,18 @@ describe('useCookieAuthRefresh', () => { ), ); - expect(result.current.state.result).toMatchObject({ expiresAt }); - }); - - it('should send a message to other tabs when the cookie is refreshed', async () => { - renderHook(() => useCookieAuthRefresh({ pluginId: 'techdocs' }), { - wrapper: ({ children }) => ( - - {children} - - ), - }); - - expect(global.BroadcastChannel).toHaveBeenCalledWith( - 'techdocs-auth-cookie-channel', - ); - - await waitFor(() => - expect(channelMock.postMessage).toHaveBeenCalledTimes(1), - ); - - // posting the message to other tabs when the cookie is requested in the first time - await waitFor(() => - expect(channelMock.postMessage).toHaveBeenCalledWith({ - action: 'COOKIE_REFRESHED', - payload: { expiresAt }, - }), - ); + expect(result.current.value).toMatchObject({ expiresAt }); }); it('should cancel the refresh when a message is received from another tab', async () => { - renderHook(() => useCookieAuthRefresh({ pluginId: 'techdocs' }), { + const pluginId = 'techdocs'; + + renderHook(() => useCookieAuthRefresh({ pluginId }), { wrapper: ({ children }) => ( @@ -196,29 +153,25 @@ describe('useCookieAuthRefresh', () => { ), }); - await waitFor(() => - expect(channelMock.addEventListener).toHaveBeenCalledTimes(1), - ); - const twentyMinutesFromNowInMilliseconds = now + 2 * tenMinutesInMilliseconds; // simulating other tab refreshing the cookie - channelMock.postMessage({ - action: 'COOKIE_REFRESHED', - payload: { - expiresAt: new Date(twentyMinutesFromNowInMilliseconds).toISOString(), - }, - }); + storageApiMock + .forBucket(`${pluginId}-auth-cookie-storage`) + .set( + 'expiresAt', + new Date(twentyMinutesFromNowInMilliseconds).toISOString(), + ); // advance the timers in 10 minutes to match the old expires at jest.advanceTimersByTime(tenMinutesInMilliseconds); // should not call the api - expect(fetchApiMock.fetch).toHaveBeenCalledTimes(1); + await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledTimes(1)); // advance the timers in more 10 minutes to match the new expires at - jest.advanceTimersByTime(tenMinutesInMilliseconds); + jest.advanceTimersByTime(tenMinutesInMilliseconds - 1000); // should call the api await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledTimes(2)); @@ -232,6 +185,7 @@ describe('useCookieAuthRefresh', () => { @@ -243,16 +197,10 @@ describe('useCookieAuthRefresh', () => { await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledTimes(1)); - expect(result.current.state.result).toMatchObject({ expiresAt }); + expect(result.current.value).toMatchObject({ expiresAt }); unmount(); - expect(channelMock.removeEventListener).toHaveBeenCalledTimes(1); - expect(channelMock.removeEventListener).toHaveBeenCalledWith( - 'message', - expect.any(Function), - ); - // advance the timers to ensure that the refresh is not called jest.advanceTimersByTime(tenMinutesInMilliseconds); @@ -268,6 +216,7 @@ describe('useCookieAuthRefresh', () => { @@ -279,7 +228,7 @@ describe('useCookieAuthRefresh', () => { await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledTimes(1)); // advance the timers to the expiration date - jest.advanceTimersByTime(tenMinutesInMilliseconds); + jest.advanceTimersByTime(tenMinutesInMilliseconds - 1000); // should call the api await waitFor(() => expect(fetchApiMock.fetch).toHaveBeenCalledTimes(2)); diff --git a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx index 2d495d54c4..8bf43f3e0c 100644 --- a/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx +++ b/plugins/auth-react/src/hooks/useCookieAuthRefresh/useCookieAuthRefresh.tsx @@ -14,51 +14,38 @@ * limitations under the License. */ -import { useEffect, useState, useCallback } from 'react'; +import { useEffect, useCallback } from 'react'; import { discoveryApiRef, fetchApiRef, + storageApiRef, useApi, } from '@backstage/core-plugin-api'; import { useAsync, useMountEffect } from '@react-hookz/web'; import { ResponseError } from '@backstage/errors'; -type CookieAuthRefreshMessage = MessageEvent<{ - action: string; - payload: { - expiresAt: string; - }; -}>; - -/** - * @public - * The options for the {@link useCookieAuthRefresh} hook. - */ -export type CookieAuthRefreshOptions = { - // The plugin ID to used for discovering the API origin - pluginId: string; - // The path to used for calling the refresh cookie endpoint, default to '/cookie' - path?: string; -}; - /** * @public * A hook that will refresh the cookie when it is about to expire. - * @remarks - * This hook expects a `BroadcastChannel` to be available in the global scope. */ -export function useCookieAuthRefresh({ - pluginId, - path = '/cookie', -}: CookieAuthRefreshOptions) { +export function useCookieAuthRefresh(params: { + // The plugin ID to used for discovering the API origin + pluginId: string; + // Options for configuring the refresh cookie endpoint + options?: { + // The path to used for calling the refresh cookie endpoint, default to '/cookie' + path?: string; + }; +}) { + const { pluginId, options: { path = '/cookie' } = {} } = params; + const fetchApi = useApi(fetchApiRef); + const storageApi = useApi(storageApiRef); const discoveryApi = useApi(discoveryApiRef); - const [channel] = useState( - () => new BroadcastChannel(`${pluginId}-auth-cookie-channel`), - ); + const store = storageApi.forBucket(`${pluginId}-auth-cookie-storage`); - const [state, actions] = useAsync(async () => { + const [state, actions] = useAsync<{ expiresAt: string }>(async () => { const apiOrigin = await discoveryApi.getBaseUrl(pluginId); const requestUrl = `${apiOrigin}${path}`; const response = await fetchApi.fetch(`${requestUrl}`, { @@ -86,28 +73,27 @@ export function useCookieAuthRefresh({ useEffect(() => { if (!state.result) return () => {}; - channel.postMessage({ - action: 'COOKIE_REFRESHED', - payload: state.result, - }); + store.set('expiresAt', state.result.expiresAt); let cancel = refresh(state.result); - const handleMessage = (event: CookieAuthRefreshMessage): void => { - const { action, payload } = event.data; - if (action === 'COOKIE_REFRESHED') { - cancel(); - cancel = refresh(payload); - } - }; - - channel.addEventListener('message', handleMessage); + const observable = store.observe$('expiresAt'); + const subscription = observable.subscribe(({ value }) => { + if (!value) return; + cancel(); + cancel = refresh({ expiresAt: value }); + }); return () => { cancel(); - channel.removeEventListener('message', handleMessage); + subscription.unsubscribe(); }; - }, [state, refresh, channel]); + }, [state, refresh, store]); - return { state, actions }; + return { + loading: state.status === 'loading', + error: state.error, + value: state.result, + retry: actions.execute, + }; } diff --git a/plugins/auth-react/src/setupTests.ts b/plugins/auth-react/src/setupTests.ts index 0ab6a810cf..658016ffdd 100644 --- a/plugins/auth-react/src/setupTests.ts +++ b/plugins/auth-react/src/setupTests.ts @@ -14,28 +14,3 @@ * limitations under the License. */ import '@testing-library/jest-dom'; - -type Listener = (event: { data: any }) => void; - -global.BroadcastChannel = jest - .fn() - .mockImplementation((_channelName: string) => { - let listeners: Listener[] = []; - return { - postMessage: jest.fn((message: any) => { - // Simulate message event for all listeners - listeners.forEach(listener => listener({ data: message })); - }), - addEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners.push(listener); - } - }), - removeEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners = listeners.filter(l => l !== listener); - } - }), - close: jest.fn(), - }; - }); diff --git a/plugins/techdocs-addons-test-utils/src/test-utils.tsx b/plugins/techdocs-addons-test-utils/src/test-utils.tsx index 51a4650f99..c3e7281116 100644 --- a/plugins/techdocs-addons-test-utils/src/test-utils.tsx +++ b/plugins/techdocs-addons-test-utils/src/test-utils.tsx @@ -22,12 +22,17 @@ import { screen } from 'testing-library__dom'; import { Route } from 'react-router-dom'; import { act, render } from '@testing-library/react'; -import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + wrapInTestApp, + TestApiProvider, + MockStorageApi, +} from '@backstage/test-utils'; import { FlatRoutes } from '@backstage/core-app-api'; import { ApiRef, discoveryApiRef, fetchApiRef, + storageApiRef, } from '@backstage/core-plugin-api'; import { @@ -73,6 +78,8 @@ const scmIntegrationsApi = { fromConfig: jest.fn().mockReturnValue({}), }; +const storageApiMock = MockStorageApi.create(); + const discoveryApi = { getBaseUrl: jest .fn() @@ -225,6 +232,7 @@ 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 8295ea0688..abea660b62 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -19,6 +19,7 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; import { MockConfigApi, + MockStorageApi, renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; @@ -38,6 +39,7 @@ import { configApiRef, discoveryApiRef, fetchApiRef, + storageApiRef, } from '@backstage/core-plugin-api'; const mockEntityMetadata = { @@ -80,6 +82,8 @@ const techdocsStorageApiMock: jest.Mocked = { syncEntityDocs: jest.fn(), }; +const storageApiMock = MockStorageApi.create(); + const discoveryApiMock = { getBaseUrl: jest .fn() @@ -117,6 +121,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => { ', () => { beforeEach(() => { - type Listener = (event: { data: any }) => void; - - global.BroadcastChannel = jest - .fn() - .mockImplementation((_channelName: string) => { - let listeners: Listener[] = []; - return { - postMessage: jest.fn((message: any) => { - listeners.forEach(listener => listener({ data: message })); - }), - addEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners.push(listener); - } - }), - removeEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners = listeners.filter(l => l !== listener); - } - }), - }; - }); - getEntityMetadata.mockResolvedValue(mockEntityMetadata); getTechDocsMetadata.mockResolvedValue(mockTechDocsMetadata); getCookie.mockResolvedValue({ diff --git a/plugins/techdocs/src/setupTests.ts b/plugins/techdocs/src/setupTests.ts index 0bdcc73ccb..6c7fc2d3e3 100644 --- a/plugins/techdocs/src/setupTests.ts +++ b/plugins/techdocs/src/setupTests.ts @@ -17,28 +17,3 @@ import '@testing-library/jest-dom'; Element.prototype.scrollIntoView = jest.fn(); - -type Listener = (event: { data: any }) => void; - -global.BroadcastChannel = jest - .fn() - .mockImplementation((_channelName: string) => { - let listeners: Listener[] = []; - return { - postMessage: jest.fn((message: any) => { - // Simulate message event for all listeners - listeners.forEach(listener => listener({ data: message })); - }), - addEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners.push(listener); - } - }), - removeEventListener: jest.fn((event: string, listener: Listener) => { - if (event === 'message') { - listeners = listeners.filter(l => l !== listener); - } - }), - close: jest.fn(), - }; - }); diff --git a/yarn.lock b/yarn.lock index 07c751cc3b..d432f7a958 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5120,7 +5120,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/test-utils": "workspace:^" "@material-ui/core": ^4.9.13 - "@react-hookz/web": ^24.0.4 + "@react-hookz/web": ^24.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 @@ -15728,7 +15728,7 @@ __metadata: languageName: node linkType: hard -"@react-hookz/web@npm:^24.0.0, @react-hookz/web@npm:^24.0.4": +"@react-hookz/web@npm:^24.0.0": version: 24.0.4 resolution: "@react-hookz/web@npm:24.0.4" dependencies: