docs: update to prefer new apis option and use mockApis
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -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(<MyComponent />, {
|
||||
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.
|
||||
|
||||
@@ -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<typeof catalogApiRef.T>;
|
||||
|
||||
const entityRef = stringifyEntityRef({
|
||||
kind: 'Component',
|
||||
namespace: 'default',
|
||||
name: 'test',
|
||||
});
|
||||
|
||||
await renderInTestApp(
|
||||
<TestApiProvider apis={[[catalogApiRef, catalogApiMock]]}>
|
||||
<EntityDetails entityRef={entityRef} />
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
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<typeof catalogApiRef.T>;
|
||||
|
||||
const entityRef = stringifyEntityRef({
|
||||
kind: 'Component',
|
||||
namespace: 'default',
|
||||
name: 'test',
|
||||
});
|
||||
|
||||
await renderInTestApp(<EntityDetails entityRef={entityRef} />, {
|
||||
apis: [[catalogApiRef, catalogApiMock]],
|
||||
describe('MyEntitiesList', () => {
|
||||
it('should render entities owned by the current user', async () => {
|
||||
await renderInTestApp(<MyEntitiesList />, {
|
||||
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();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -83,15 +83,16 @@ export type TestAppOptions<TApiPairs extends any[] = any[]> = {
|
||||
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(<MyComponent />, {
|
||||
* apis: [
|
||||
* [errorApiRef, mockErrorApi],
|
||||
* [analyticsApiRef, mockAnalyticsApi],
|
||||
* ]
|
||||
* apis: [[identityApiRef, mockApis.identity({ userEntityRef: 'user:default/guest' })]],
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user