diff --git a/.changeset/api-override-test-utils.md b/.changeset/api-override-test-utils.md
index a250dc7d15..f2c73db7f3 100644
--- a/.changeset/api-override-test-utils.md
+++ b/.changeset/api-override-test-utils.md
@@ -2,21 +2,29 @@
'@backstage/frontend-test-utils': patch
---
-Added support for API overrides in `createExtensionTester` and `renderInTestApp`. You can now pass an `apis` option to override specific APIs when testing extensions:
+Added an `apis` option to `createExtensionTester` and `renderInTestApp` to override APIs when testing extensions. Use the `mockApis` helpers to create mock implementations:
```typescript
+import { identityApiRef } from '@backstage/frontend-plugin-api';
+import { mockApis } from '@backstage/frontend-test-utils';
+
// Override APIs in createExtensionTester
const tester = createExtensionTester(myExtension, {
apis: [
- [errorApiRef, mockErrorApi],
- [analyticsApiRef, mockAnalyticsApi],
+ [
+ identityApiRef,
+ mockApis.identity({ userEntityRef: 'user:default/guest' }),
+ ],
],
});
// Override APIs in renderInTestApp
renderInTestApp(, {
- apis: [[errorApiRef, mockErrorApi]],
+ apis: [
+ [
+ identityApiRef,
+ mockApis.identity({ userEntityRef: 'user:default/guest' }),
+ ],
+ ],
});
```
-
-The package now also exports its own implementations of `TestApiProvider`, `TestApiRegistry`, and related types, rather than re-exporting them from `@backstage/test-utils`. This consolidates common types used internally by the test utilities.
diff --git a/docs/frontend-system/building-plugins/02-testing.md b/docs/frontend-system/building-plugins/02-testing.md
index adb0e0a45e..550434f373 100644
--- a/docs/frontend-system/building-plugins/02-testing.md
+++ b/docs/frontend-system/building-plugins/02-testing.md
@@ -31,89 +31,50 @@ describe('Entity details component', () => {
});
```
-To mock [Utility APIs](../architecture/33-utility-apis.md) that are used by your component you can use the `TestApiProvider` to override individual API implementations. In the snippet below, we wrap the component within a `TestApiProvider` in order to mock the catalog client API:
+To mock [Utility APIs](../architecture/33-utility-apis.md) that are used by your component, pass API overrides to `renderInTestApp` using the `apis` option. Mock helpers are available from `@backstage/frontend-test-utils` and plugin-specific test utilities:
```tsx
import { screen } from '@testing-library/react';
-import {
- renderInTestApp,
- TestApiProvider,
-} from '@backstage/frontend-test-utils';
-import { stringifyEntityRef } from '@backstage/catalog-model';
-import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react';
-import { EntityDetails } from './plugin';
-
-describe('Entity details component', () => {
- it('should render the entity name and owner', async () => {
- const catalogApiMock = {
- async getEntityFacets() {
- return {
- facets: {
- 'relations.ownedBy': [{ count: 1, value: 'group:default/tools' }],
- },
- },
- }
- } satisfies Partial;
-
- const entityRef = stringifyEntityRef({
- kind: 'Component',
- namespace: 'default',
- name: 'test',
- });
-
- await renderInTestApp(
-
-
- ,
- );
-
- await expect(
- screen.findByText('The entity "test" is owned by "tools"'),
- ).resolves.toBeInTheDocument();
- });
-});
-```
-
-This pattern also works for many other context providers. An important example is the `EntityProvider` from the `@backstage/plugin-catalog-react` package, which you can use to provide a mocked entity context to the component.
-
-Alternatively, you can pass API overrides directly to `renderInTestApp` using the `apis` option:
-
-```tsx
-import { screen } from '@testing-library/react';
-import { renderInTestApp } from '@backstage/frontend-test-utils';
+import { renderInTestApp, mockApis } from '@backstage/frontend-test-utils';
+import { identityApiRef } from '@backstage/frontend-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
-import { EntityDetails } from './plugin';
+import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
+import { MyEntitiesList } from './plugin';
-describe('Entity details component', () => {
- it('should render the entity name and owner', async () => {
- const catalogApiMock = {
- async getEntityFacets() {
- return {
- facets: {
- 'relations.ownedBy': [{ count: 1, value: 'group:default/tools' }],
- },
- },
- }
- } satisfies Partial;
-
- const entityRef = stringifyEntityRef({
- kind: 'Component',
- namespace: 'default',
- name: 'test',
- });
-
- await renderInTestApp(, {
- apis: [[catalogApiRef, catalogApiMock]],
+describe('MyEntitiesList', () => {
+ it('should render entities owned by the current user', async () => {
+ await renderInTestApp(, {
+ apis: [
+ [
+ identityApiRef,
+ mockApis.identity({ userEntityRef: 'user:default/guest' }),
+ ],
+ [
+ catalogApiRef,
+ catalogApiMock({
+ entities: [
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'Component',
+ metadata: { name: 'my-component' },
+ spec: { type: 'service', owner: 'user:default/guest' },
+ },
+ ],
+ }),
+ ],
+ ],
});
await expect(
- screen.findByText('The entity "test" is owned by "tools"'),
+ screen.findByText('my-component'),
).resolves.toBeInTheDocument();
});
});
```
-This approach provides the API overrides at the app level, which is useful when testing extensions that depend on APIs deep in the component tree.
+This approach provides the API overrides at the app level, which is useful when testing components that depend on APIs deep in the component tree.
+
+The `TestApiProvider` component is also available for standalone rendering scenarios where you're not using `renderInTestApp` or other test utilities. Context providers like `EntityProvider` from `@backstage/plugin-catalog-react` can also be used to provide a mocked entity context to the component.
## Testing extensions
@@ -141,26 +102,32 @@ describe('Index page', () => {
});
```
-This pattern also allows you to wrap the extension with context providers, such as the `TestApiProvider` that was introduced [above](#testing-react-components). Alternatively, you can provide API overrides directly to `createExtensionTester`:
+You can also provide API overrides directly to `createExtensionTester` using the `apis` option:
```tsx
import { screen } from '@testing-library/react';
-import { createExtensionTester } from '@backstage/frontend-test-utils';
-import { analyticsApiRef } from '@backstage/frontend-plugin-api';
+import {
+ createExtensionTester,
+ mockApis,
+ renderInTestApp,
+} from '@backstage/frontend-test-utils';
+import { identityApiRef } from '@backstage/frontend-plugin-api';
import { indexPageExtension } from './plugin';
describe('Index page', () => {
- it('should render and track analytics', async () => {
- const analyticsApiMock = { captureEvent: jest.fn() };
-
+ it('should render with a custom identity', async () => {
await renderInTestApp(
createExtensionTester(indexPageExtension, {
- apis: [[analyticsApiRef, analyticsApiMock]],
+ apis: [
+ [
+ identityApiRef,
+ mockApis.identity({ userEntityRef: 'user:default/guest' }),
+ ],
+ ],
}).reactElement(),
);
expect(screen.getByText('Index Page')).toBeInTheDocument();
- expect(analyticsApiMock.captureEvent).toHaveBeenCalled();
});
});
```
diff --git a/packages/frontend-test-utils/src/app/renderInTestApp.tsx b/packages/frontend-test-utils/src/app/renderInTestApp.tsx
index 8aa863512b..93094fb7e3 100644
--- a/packages/frontend-test-utils/src/app/renderInTestApp.tsx
+++ b/packages/frontend-test-utils/src/app/renderInTestApp.tsx
@@ -83,15 +83,16 @@ export type TestAppOptions = {
initialRouteEntries?: string[];
/**
- * API overrides to provide to the test app.
+ * API overrides to provide to the test app. Use `mockApis` helpers
+ * from `@backstage/frontend-test-utils` to create mock implementations.
*
* @example
* ```ts
+ * import { identityApiRef } from '@backstage/frontend-plugin-api';
+ * import { mockApis } from '@backstage/frontend-test-utils';
+ *
* renderInTestApp(, {
- * apis: [
- * [errorApiRef, mockErrorApi],
- * [analyticsApiRef, mockAnalyticsApi],
- * ]
+ * apis: [[identityApiRef, mockApis.identity({ userEntityRef: 'user:default/guest' })]],
* })
* ```
*/