Skip to main content
Version: Next

Testing with Utility APIs

When testing frontend components and extensions, you often need to provide mock implementations of the utility APIs they depend on. The @backstage/frontend-test-utils package provides the mockApis namespace with ready-made mocks for all core utility APIs.

The mockApis namespace​

The mockApis namespace is the main entry point for creating mock utility API instances in tests. It provides two usage patterns for each API:

Fake instances​

Call the API function directly to create a fake instance with simplified but functional behavior. These are useful when your test needs the API to actually work, not just be stubbed.

import { mockApis } from '@backstage/frontend-test-utils';

const configApi = mockApis.config({ data: { app: { title: 'Test' } } });
configApi.getString('app.title'); // 'Test'

const alertApi = mockApis.alert();
alertApi.post({ message: 'hello' });
expect(alertApi.getAlerts()).toHaveLength(1);

Jest mocks​

Call .mock() to get an instance where every method is a jest.fn(). You can optionally provide partial implementations. This is useful when you want to assert that specific methods were called.

import { mockApis } from '@backstage/frontend-test-utils';
import { AuthorizeResult } from '@backstage/plugin-permission-common';

const permissionApi = mockApis.permission.mock({
authorize: async () => ({ result: AuthorizeResult.ALLOW }),
});

// ... exercise the component ...

expect(permissionApi.authorize).toHaveBeenCalledTimes(1);

Providing mock APIs in tests​

With renderInTestApp​

import { screen } from '@testing-library/react';
import { renderInTestApp, mockApis } from '@backstage/frontend-test-utils';

await renderInTestApp(<MyComponent />, {
apis: [
mockApis.identity({ userEntityRef: 'user:default/guest' }),
mockApis.config({ data: { app: { title: 'Test App' } } }),
],
});

You can also use the [apiRef, implementation] tuple syntax to provide any API implementation, including ones that aren't from mockApis:

import { myCustomApiRef } from '../apis';

const myCustomApiInstance = {
// ...
};

await renderInTestApp(<MyComponent />, {
apis: [
mockApis.identity({ userEntityRef: 'user:default/guest' }),
[myCustomApiRef, myCustomApiInstance],
],
});

With renderTestApp​

The same apis option is available on renderTestApp, which is commonly used when testing extensions or entity pages:

import { renderTestApp, mockApis } from '@backstage/frontend-test-utils';
import { createTestEntityPage } from '@backstage/plugin-catalog-react/testUtils';

renderTestApp({
extensions: [createTestEntityPage({ entity }), myEntityCard],
apis: [mockApis.permission()],
});

With TestApiProvider​

For standalone rendering scenarios where you're not using renderInTestApp, the TestApiProvider component accepts the same apis format:

import { render } from '@testing-library/react';
import { TestApiProvider, mockApis } from '@backstage/frontend-test-utils';

render(
<TestApiProvider
apis={[
mockApis.identity({ userEntityRef: 'user:default/guest' }),
mockApis.alert(),
]}
>
<MyComponent />
</TestApiProvider>,
);

Plugin-specific test mocks​

Plugins can provide their own mock APIs that follow the same pattern. For example, @backstage/plugin-catalog-react provides catalogApiMock in its /testUtils entry point:

import { renderTestApp } from '@backstage/frontend-test-utils';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';

renderTestApp({
extensions: [myExtension],
apis: [catalogApiMock({ entities: [entity] })],
});

Creating your own mock APIs​

If you maintain a plugin that exposes a utility API, you can provide mock utilities that follow the same function + .mock() pattern as the built-in mockApis.

Use attachMockApiFactory for fake instances with real behavior, and createApiMock for the jest-mocked .mock() variant where all methods are jest.fn(). The full pattern looks like this:

import {
attachMockApiFactory,
createApiMock,
type ApiMock,
} from '@backstage/frontend-test-utils';
import { myApiRef, type MyApi } from '@internal/plugin-example-react';

// Fake instance with real behavior
export function myApiMock(options?: { greeting?: string }) {
return attachMockApiFactory(myApiRef, {
greet: async () => options?.greeting ?? 'Hello!',
});
}

// Jest mock variant where all methods are jest.fn()
export namespace myApiMock {
export const mock = createApiMock(myApiRef, () => ({
greet: jest.fn(),
}));
}

Consumers can then use it just like the core mocks:

// Fake with real behavior
await renderInTestApp(<MyComponent />, {
apis: [myApiMock({ greeting: 'Hi there!' })],
});

// Jest mock for assertions
const api = myApiMock.mock({
greet: async () => 'mocked',
});

await renderInTestApp(<MyComponent />, {
apis: [api],
});

expect(api.greet).toHaveBeenCalledTimes(1);

Available mock APIs​

The table below lists all core APIs available through the mockApis namespace.

APIFake instanceNotes
mockApis.alert()MockAlertApiCollects alerts; has getAlerts(), clearAlerts(), waitForAlert()
mockApis.analytics()MockAnalyticsApiCollects events; has getEvents()
mockApis.config({ data })MockConfigApiReads from a plain JSON object
mockApis.discovery({ baseUrl })InlineReturns ${baseUrl}/api/${pluginId}, defaults to http://example.com
mockApis.error(options?)MockErrorApiCollects errors; has getErrors(), waitForError()
mockApis.featureFlags(options?)MockFeatureFlagsApiIn-memory flag state; has getState(), setState(), clearState()
mockApis.fetch(options?)MockFetchApiWraps native fetch; supports identity injection and plugin protocol
mockApis.identity(options?)InlineConfigurable user ref, ownership, token, profile
mockApis.permission(options?)MockPermissionApiDefaults to ALLOW; accepts a handler function
mockApis.storage({ data })MockStorageApiIn-memory storage with bucket support
mockApis.translation()MockTranslationApiPassthrough returning default messages from translation refs

Each of these also has a .mock() variant that returns jest mocks, as described above.