跳到主要内容

测试数据查询

简介

查询编辑器是数据源插件的核心部分,因为用户在这里编写用于获取数据的查询。你的数据源插件可以提供丰富的查询编辑器,允许针对不同 API 的各种查询类型。你的查询编辑器甚至可以具有可视化查询构建器、IntelliSense 和自动完成等功能。

测试查询编辑器是否加载

以下示例是一个简单的冒烟测试,用于验证数据源查询编辑器是否加载

queryEditor.spec.ts
import { test, expect } from '@grafana/plugin-e2e';

test('should render query editor', async ({ panelEditPage, readProvisionedDataSource }) => {
const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
await panelEditPage.datasource.set(ds.name);
await expect(panelEditPage.getQueryEditorRow('A').getByRole('textbox', { name: 'Query Text' })).toBeVisible();
});

隔离测试查询编辑器的各个部分

在以下示例中,查询编辑器通过向 /regions 发送请求来加载区域,并过滤掉包含 gov 的区域,然后将其填充到下拉菜单中。

<page>.mockResourceResponse 方法允许你模拟对数据源 资源 API 的请求的响应。为了测试过滤是否按预期工作,我们使用此方法模拟 /regions 响应,并断言当单击区域下拉菜单时,仅显示名称中不包含 -gov- 的区域。

queryEditor.spec.ts
test('should filter out govcloud regions', async ({ panelEditPage, selectors, readProvisionedDataSource }) => {
const regionsMock = ['us-gov-west-1', 'us-east-1', 'us-west-1', 'us-gov-east-1'];
const expectedRegions = ['us-east-1', 'us-west-1'];
const ds = await readProvisionedDataSource({ fileName: 'datasources.yaml' });
await panelEditPage.datasource.set(ds.name);
await panelEditPage.mockResourceResponse('regions', regionsMock);
await panelEditPage.getQueryEditorRow('A').getByText('Regions').click();
await expect(panelEditPage.getByGrafanaSelector(selectors.components.Select.option)).toHaveText(expectedRegions);
});

测试整个数据流

以下示例显示了一个集成测试,该测试测试插件的整个查询数据流。

警告

在端到端测试中点击第三方 API 可能很有用,但也可能存在安全隐患,并可能给你的 CI 管道引入不稳定性。你应该始终仔细考虑,并考虑使用模拟来代替。

queryEditor.spec.ts
test('data query should be successful when the query is valid', async ({
panelEditPage,
readProvisionedDataSource,
}) => {
const ds = await readProvisionedDataSource({ fileName: 'datasources.yaml' });
await panelEditPage.datasource.set(ds.name);
await panelEditPage.getQueryEditorRow('A').getByText('Query Text').fill('SELECT * FROM dataset');
await expect(panelEditPage.refreshPanel()).toBeOK();
});

进行面板数据断言

在许多情况下,仅断言数据查询响应为 OK 不足以说明你的数据源插件运行正常。你还必须对面板中显示的数据进行断言。

Grafana 附带了一组内置面板,并且在 Grafana 插件目录 中提供了各种社区面板。每个面板都可以不同地渲染数据,因此不可能提供一种一致的方式来断言所有面板上显示的数据。因此,我们建议你为此使用 Table 面板。

<page>.panel.data 属性返回一个 Playwright 定位器,该定位器解析一个或多个包含当前在 Table 面板中显示的值的元素。这意味着你可以使用任何自动重试的 匹配器,该匹配器接受定位器作为接收类型。

queryEditor.spec.ts
test('data query should return values 10 and 20', async ({ panelEditPage, readProvisionedDataSource }) => {
const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
await panelEditPage.datasource.set(ds.name);
await panelEditPage.setVisualization('Table');
await expect(panelEditPage.refreshPanel()).toBeOK();
await expect(panelEditPage.panel.data).toContainText(['10', '20']);
});

如果你想断言 Table 面板中显示的列标题,你可以使用 <page>.panel.fieldNames 属性。

queryEditor.spec.ts
test('data query should return headers  and 3', async ({ panelEditPage, readProvisionedDataSource }) => {
const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
await panelEditPage.datasource.set(ds.name);
await panelEditPage.setVisualization('Table');
await expect(panelEditPage.refreshPanel()).toBeOK();
await expect(panelEditPage.panel.fieldNames).toHaveText(['Stockholm', 'Vienna']);
});

在已配置的仪表板中测试查询

有时你可能想要打开已存在面板的面板编辑页面,并运行查询以确保一切按预期工作。

test('query in provisioned dashboard should return temp and humidity data', async ({
readProvisionedDashboard,
gotoPanelEditPage,
}) => {
const dashboard = await readProvisionedDashboard({ fileName: 'dashboard.json' });
const panelEditPage = await gotoPanelEditPage({ dashboard, id: '3' });
await expect(panelEditPage.refreshPanel()).toBeOK();
await expect(panel.fieldNames).toContainText(['temperature', 'humidity']);
await expect(panel.data).toContainText(['25', '10']);
});

你还可以打开已存在的仪表板,并验证表格面板是否已渲染你期望的数据。

test('getting panel by id', async ({ gotoDashboardPage, readProvisionedDashboard }) => {
const dashboard = await readProvisionedDashboard({ fileName: 'dashboard.json' });
const dashboardPage = await gotoDashboardPage(dashboard);
const panel1 = await dashboardPage.getPanelById('3');
await expect(panel1.data).toContainText(['25', '32', 'staging']);
const panel2 = await dashboardPage.getPanelByTitle('Basic table example');
await expect(dashboardPage.panel2.fieldNames).toContainText(['Tokyo', 'Berlin']);
});