From 421770753a88f8dc931519cf9e06b4a23d5c6ec7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 31 Jan 2026 15:10:53 +0100 Subject: [PATCH] refactor: migrate tests to use new API override utilities Updated tests across the repository to use the new `apis` option with `renderInTestApp` and `createExtensionTester` instead of wrapping components with `TestApiProvider`. This simplifies tests and demonstrates the use of the new API override functionality. Updated test files: - packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx - packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx - plugins/catalog/src/alpha/pages.test.tsx Total: 15 test cases migrated Signed-off-by: Patrik Oldsberg --- .../AppRootElementBlueprint.test.tsx | 14 +- .../src/components/ExtensionBoundary.test.tsx | 62 +-- plugins/catalog/src/alpha/pages.test.tsx | 433 ++++++++---------- 3 files changed, 219 insertions(+), 290 deletions(-) diff --git a/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx index 31d7323aec..57984761ac 100644 --- a/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx @@ -15,11 +15,7 @@ */ import { screen, waitFor } from '@testing-library/react'; -import { - MockErrorApi, - TestApiProvider, - withLogCollector, -} from '@backstage/test-utils'; +import { MockErrorApi, withLogCollector } from '@backstage/test-utils'; import { errorApiRef } from '../apis'; import { createExtensionTester, @@ -74,11 +70,9 @@ describe('AppRootElementBlueprint', () => { }); const tester = createExtensionTester(extension); - renderInTestApp( - - {tester.reactElement()} - , - ); + renderInTestApp(tester.reactElement(), { + apis: [[errorApiRef, errorApi]], + }); await waitFor(() => { const errors = errorApi.getErrors(); diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx index c0068e8f7d..1215c7576f 100644 --- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx +++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.test.tsx @@ -16,7 +16,7 @@ import { useEffect, ReactNode } from 'react'; import { act, screen, waitFor } from '@testing-library/react'; -import { TestApiProvider, withLogCollector } from '@backstage/test-utils'; +import { withLogCollector } from '@backstage/test-utils'; import { ExtensionBoundary } from './ExtensionBoundary'; import { coreExtensionData, createExtension } from '../wiring'; import { analyticsApiRef } from '../apis/definitions/AnalyticsApi'; @@ -30,6 +30,7 @@ import { pluginWrapperApiRef, PluginWrapperApi, } from '../apis/definitions/PluginWrapperApi'; +import { useAppNode } from '@backstage/frontend-plugin-api'; const wrapInBoundaryExtension = (element?: JSX.Element) => { const routeRef = createRouteRef(); @@ -105,11 +106,12 @@ describe('ExtensionBoundary', () => { }; renderInTestApp( - - {createExtensionTester( - wrapInBoundaryExtension(), - ).reactElement()} - , + createExtensionTester( + wrapInBoundaryExtension(), + ).reactElement(), + { + apis: [[analyticsApiRef, analyticsApiMock]], + }, ); await waitFor(() => { @@ -132,9 +134,10 @@ describe('ExtensionBoundary', () => { }; const WrapperComponent = ({ children }: { children: ReactNode }) => { + const node = useAppNode(); return (
- Wrapper + Wrapper for {node?.spec.id} {children}
); @@ -150,15 +153,18 @@ describe('ExtensionBoundary', () => { }; renderInTestApp( - - {createExtensionTester( - wrapInBoundaryExtension(), - ).reactElement()} - , + createExtensionTester( + wrapInBoundaryExtension(), + ).reactElement(), + { + apis: [[pluginWrapperApiRef, pluginWrapperApi]], + }, ); - expect(await screen.findByTestId('plugin-wrapper')).toBeInTheDocument(); - expect(screen.getByText('Wrapper')).toBeInTheDocument(); + const wrappers = await screen.findAllByTestId('plugin-wrapper'); + expect(wrappers.length).toBeGreaterThan(1); + expect(screen.getByText('Wrapper for app')).toBeInTheDocument(); + expect(screen.getByText('Wrapper for test')).toBeInTheDocument(); expect(screen.getByText(text)).toBeInTheDocument(); expect(pluginWrapperApi.getPluginWrapper).toHaveBeenCalledWith('app'); }); @@ -184,11 +190,12 @@ describe('ExtensionBoundary', () => { const { error } = await withLogCollector(['error'], async () => { renderInTestApp( - - {createExtensionTester( - wrapInBoundaryExtension(), - ).reactElement()} - , + createExtensionTester( + wrapInBoundaryExtension(), + ).reactElement(), + { + apis: [[pluginWrapperApiRef, pluginWrapperApi]], + }, ); await waitFor(() => expect(screen.getByText(errorMsg)).toBeInTheDocument(), @@ -204,9 +211,7 @@ describe('ExtensionBoundary', () => { ); }); - // TODO(Rugvip): Need a way to be able to override APIs in the app to be able to test this properly - // eslint-disable-next-line jest/no-disabled-tests - it.skip('should emit analytics events if routable', async () => { + it('should emit analytics events if routable', async () => { const Emitter = () => { const analytics = useAnalytics(); useEffect(() => { @@ -221,22 +226,25 @@ describe('ExtensionBoundary', () => { createExtensionTester( wrapInBoundaryExtension(), ).reactElement(), - // { apis: [[analyticsApiRef, analyticsApiMock]] }, + { apis: [[analyticsApiRef, analyticsApiMock]] }, ); }); + // The navigate event is emitted by the app's routing, with app context expect(analyticsApiMock.captureEvent).toHaveBeenCalledWith( expect.objectContaining({ action: 'navigate', subject: '/', + }), + ); + // The dummy event from our test extension has the correct extension context + expect(analyticsApiMock.captureEvent).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'dummy', context: expect.objectContaining({ - pluginId: 'root', extensionId: 'test', }), }), ); - expect(analyticsApiMock.captureEvent).toHaveBeenCalledWith( - expect.objectContaining({ action: 'dummy' }), - ); }); }); diff --git a/plugins/catalog/src/alpha/pages.test.tsx b/plugins/catalog/src/alpha/pages.test.tsx index 2ce2095358..e6bf4a05cf 100644 --- a/plugins/catalog/src/alpha/pages.test.tsx +++ b/plugins/catalog/src/alpha/pages.test.tsx @@ -19,7 +19,6 @@ import userEvent from '@testing-library/user-event'; import { createExtensionTester, renderInTestApp, - TestApiProvider, } from '@backstage/frontend-test-utils'; import { catalogEntityPage } from './pages'; import { @@ -150,29 +149,23 @@ describe('Entity page', () => { .add(techdocsEntityContent) .add(apidocsEntityContent); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect( @@ -212,29 +205,23 @@ describe('Entity page', () => { .add(techdocsEntityContent) .add(apidocsEntityContent); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect(screen.queryByRole('tab', { name: /Docs/ })).toBeInTheDocument(), @@ -267,29 +254,23 @@ describe('Entity page', () => { }, }); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect( @@ -334,29 +315,23 @@ describe('Entity page', () => { }, }); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect(screen.getByRole('tab', { name: /Docs/ })).toBeInTheDocument(), @@ -390,29 +365,23 @@ describe('Entity page', () => { }, }); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect( @@ -435,29 +404,23 @@ describe('Entity page', () => { .add(apidocsEntityContent) .add(overviewEntityContent); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2)); @@ -485,29 +448,23 @@ describe('Entity page', () => { }, }); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2)); @@ -522,29 +479,23 @@ describe('Entity page', () => { Object.assign({ namespace: 'catalog' }, catalogEntityPage), ); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect(screen.getByText(/artist-lookup/)).toBeInTheDocument(), @@ -567,29 +518,23 @@ describe('Entity page', () => { Object.assign({ namespace: 'catalog' }, catalogEntityPage), ).add(customEntityHeader); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); await waitFor(() => expect( @@ -634,29 +579,23 @@ describe('Entity page', () => { Object.assign({ namespace: 'catalog' }, catalogEntityPage), ).add(menuItem); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); const { disabled } = params.useProps(); await userEvent.click(await screen.findByTestId('menu-button')); @@ -697,29 +636,23 @@ describe('Entity page', () => { Object.assign({ namespace: 'catalog' }, catalogEntityPage), ).add(menuItem); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + }); const { disabled } = params.useProps(); @@ -797,29 +730,23 @@ describe('Entity page', () => { .add(menuItem) .add(filteredMenuItem); - await renderInTestApp( - - {tester.reactElement()} - , - { - config: { - app: { - title: 'Custom app', - }, - backend: { baseUrl: 'http://localhost:7000' }, - }, - mountedRoutes: { - '/catalog': convertLegacyRouteRef(rootRouteRef), - '/catalog/:namespace/:kind/:name': - convertLegacyRouteRef(entityRouteRef), + await renderInTestApp(tester.reactElement(), { + config: { + app: { + title: 'Custom app', }, + backend: { baseUrl: 'http://localhost:7000' }, }, - ); + mountedRoutes: { + '/catalog': convertLegacyRouteRef(rootRouteRef), + '/catalog/:namespace/:kind/:name': + convertLegacyRouteRef(entityRouteRef), + }, + apis: [ + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, mockStarredEntitiesApi], + ], + }); await userEvent.click(await screen.findByTestId('menu-button'));