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.