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 <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-01-31 15:10:53 +01:00
parent 22864b75a9
commit 421770753a
3 changed files with 219 additions and 290 deletions
@@ -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(
<TestApiProvider apis={[[errorApiRef, errorApi]]}>
{tester.reactElement()}
</TestApiProvider>,
);
renderInTestApp(tester.reactElement(), {
apis: [[errorApiRef, errorApi]],
});
await waitFor(() => {
const errors = errorApi.getErrors();
@@ -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(
<TestApiProvider apis={[[analyticsApiRef, analyticsApiMock]]}>
{createExtensionTester(
wrapInBoundaryExtension(<AnalyticsComponent />),
).reactElement()}
</TestApiProvider>,
createExtensionTester(
wrapInBoundaryExtension(<AnalyticsComponent />),
).reactElement(),
{
apis: [[analyticsApiRef, analyticsApiMock]],
},
);
await waitFor(() => {
@@ -132,9 +134,10 @@ describe('ExtensionBoundary', () => {
};
const WrapperComponent = ({ children }: { children: ReactNode }) => {
const node = useAppNode();
return (
<div data-testid="plugin-wrapper">
<span>Wrapper</span>
<span>Wrapper for {node?.spec.id}</span>
{children}
</div>
);
@@ -150,15 +153,18 @@ describe('ExtensionBoundary', () => {
};
renderInTestApp(
<TestApiProvider apis={[[pluginWrapperApiRef, pluginWrapperApi]]}>
{createExtensionTester(
wrapInBoundaryExtension(<TextComponent />),
).reactElement()}
</TestApiProvider>,
createExtensionTester(
wrapInBoundaryExtension(<TextComponent />),
).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(
<TestApiProvider apis={[[pluginWrapperApiRef, pluginWrapperApi]]}>
{createExtensionTester(
wrapInBoundaryExtension(<TextComponent />),
).reactElement()}
</TestApiProvider>,
createExtensionTester(
wrapInBoundaryExtension(<TextComponent />),
).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(<Emitter />),
).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' }),
);
});
});
+180 -253
View File
@@ -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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockCatalogApi],
[starredEntitiesApiRef, mockStarredEntitiesApi],
]}
>
{tester.reactElement()}
</TestApiProvider>,
{
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'));