Skip to main content

**注意:新的前台系统处于alpha阶段,只有少数插件支持。

测试前端插件

注意:新的前台系统还处于 alpha 阶段,某些插件尚未完全实施。

用于测试前端功能和组件的实用程序可在@backstage/frontend-test-utils.

测试 React 组件

一个组件可用于多个扩展,而且应独立于扩展环境进行测试。

使用renderInTestApp帮助程序在 Backstage 测试程序中渲染指定组件:

import React from 'react';
import { screen } from '@testing-library/react';
import { renderInTestApp } from '@backstage/frontend-test-utils';
import { EntityDetails } from './plugin';

describe('Entity details component', () => {
it('should render the entity name and owner', async () => {
await renderInTestApp(<EntityDetails owner="tools" name="test" />);

await expect(
screen.findByText('The entity "test" is owned by "tools"'),
).resolves.toBeInTheDocument();
});
});

嘲笑实用 API您可以使用TestApiProvider来覆盖单个应用程序接口的实现。 在下面的代码段中,我们将组件封装在一个TestApiProvider以模拟目录客户端 API:

import React from 'react';
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();
});
});

测试扩展

为便于测试前端扩展,可使用@backstage/frontend-test-utils软件包提供了一个测试器类,它可以启动整个前端工具包,并提供大量默认功能。 然后,您可以为扩展提供重载,以便在测试运行时调整其行为。

测试人员还可以接受许多功能(前端扩展和重写)。 以下是这些功能如何发挥作用的一些例子:

单一扩展

要隔离测试扩展,只需将其传递到测试器工厂,然后在返回的实例上调用 render 方法即可:

import { screen } from '@testing-library/react';
import { createExtensionTester } from '@backstage/frontend-test-utils';
import { indexPageExtension } from './plugin';

describe('Index page', () => {
it('should render a the index page', () => {
createExtensionTester(indexPageExtension).render();

expect(screen.getByText('Index Page')).toBeInTheDocument();
});
});

扩展预设

有些扩展依赖于其他扩展的存在,例如链接到其他页面的页面。 在这种情况下,您可以在测试中要呈现的功能预设中添加多个扩展,如下所示:

import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createExtensionTester } from '@backstage/frontend-test-utils';
import { indexPageExtension, detailsPageExtension } from './plugin';

describe('Index page', async () => {
it('should link to the details page', () => {
createExtensionTester(indexPageExtension)
// Adding more extensions to the preset being tested
.add(detailsPageExtension)
.render();

await expect(screen.findByText('Index Page')).toBeInTheDocument();

await userEvent.click(screen.getByRole('link', { name: 'See details' }));

await expect(
screen.findByText('Details Page'),
).resolves.toBeInTheDocument();
});
});

模拟 apis

如果您的扩展需要实现默认情况下没有连接的 API,则必须在测试功能预设中添加重载:

import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createApiFactory } from '@backestage/core-plugin-api';
import {
createExtensionOverrides,
configApiRef,
analyticsApiRef,
} from '@backstage/frontend-plugin-api';
import {
createExtensionTester,
MockConfigApi,
MockAnalyticsApi,
} from '@backstage/frontend-test-utils';
import { indexPageExtension } from './plugin';

describe('Index page', () => {
it('should capture click events in analytics', async () => {
// Mocking the analytics api implementation
const analyticsApiMock = new MockAnalyticsApi();

const analyticsApiOverride = createApiExtension({
factory: createApiFactory({
api: analyticsApiRef,
factory: () => analyticsApiMock,
}),
});

createExtensionTester(indexPageExtension)
// Overriding the analytics api extension
.add(analyticsApiOverride)
.render();

await userEvent.click(
await screen.findByRole('link', { name: 'See details' }),
);

expect(analyticsApiMock.getEvents()[0]).toMatchObject({
action: 'click',
subject: 'See details',
});
});
});

设置配置

如果扩展可以进行配置,则可以通过传递配置值来测试这一功能,具体如下:

import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createExtensionTester } from '@backstage/frontend-test-utils';
import { indexPageExtension, detailsPageExtension } from './plugin';

describe('Index page', () => {
it('should accepts a custom title via config', async () => {
createExtensionTester(indexPageExtension, {
// Configuration specific of index page
config: { title: 'Custom index' },
})
.add(detailsExtensionPage, {
// Configuration specific of details page
config: { title: 'Custom details' },
})
.render({
// Configuration specific of the instance
config: {
app: {
title: 'Custom app',
},
},
});

await expect(
screen.findByRole('heading', { name: 'Custom app' }),
).resolves.toBeInTheDocument();

await expect(
screen.findByRole('heading', { name: 'Custom index' }),
).resolves.toBeInTheDocument();

await userEvent.click(screen.getByRole('link', { name: 'See details' }));

await expect(
screen.findByText('Custom details'),
).resolves.toBeInTheDocument();
});
});

这就是测试功能的全部内容!

Missing something?

如果您认为文档中还需要涵盖其他内容,或者您认为测试工具中还没有涵盖其他内容,请在 Backstage 软件仓库中创建一个问题。 我们也随时欢迎您的贡献!