add-e2e-selectors
Add reliable @grafana/e2e-selectors to interactive elements and key containers in the Grafana frontend. Use when adding e2e selectors, data-testid attributes,…
Write unit and E2E tests for Grafana visualization panels and viz utilities to the conventions this repo expects. Use when adding, backfilling, or reviewing tests for panels (barchart, timeseries, table, xychart, heatmap, canvas, etc.), grafana-ui viz components (Table, uPlot,
$ npx -y skills add grafana/grafana --skill panel-testing-strategy --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/panel-testing-strategyContext preview
The summary Claude sees to decide when to auto-load this skill.
Write unit and E2E tests for Grafana visualization panels and viz utilities to the conventions this repo expects. Use when adding, backfilling, or reviewing tests for panels (barchart, timeseries, table, xychart, heatmap, canvas, etc.), grafana-ui viz components (Table, uPlot,
name: panel-testing-strategy description: Write unit and E2E tests for Grafana visualization panels and viz utilities to the conventions this repo expects. Use when adding, backfilling, or reviewing tests for panels (barchart, timeseries, table, xychart, heatmap, canvas, etc.), grafana-ui viz components (Table, uPlot, VizLegend, VizTooltip), or grafana-data viz utils; when a panel test only asserts "it rendered" or "it's defined"; when reviewing AI-generated panel tests for slop; or when a canvas/rendering test is flaky.
This skill builds on **`frontend-testing-strategy`** — read that first for the general principles every Grafana frontend test is held to (the inverted testing diamond, asserting real behavior instead of existence, avoiding AI slop, verifying a test reaches its target branch, generic anti-flake rules, and the SDLC-phase gating). This skill covers what's specific to visualization code on top of that: data-frame/panel-prop builders, the canvas draw-call snapshot harness, panel accessibility and interaction-snapshot E2E, and canvas/uPlot-specific anti-flake rules. The visualization codeowner paths are opted into the gating `check-frontend-test-coverage.yml` check, so coverage that drops fails CI.
Build data frames with the `@grafana/data` builders — **pick one and don't mix** `toDataFrame` and `createDataFrame` in the same file:
import { createDataFrame, toDataFrame, arrayToDataFrame, FieldType, LoadingState } from '@grafana/data';Use a **single canonical builder per file** with a `Partial<>` overrides object, rather than bespoke frames per test:
function makeFrame(overrides: Partial<Options> = {}) {
/* … */
}To render a panel component, use the shared panel-props builder instead of hand-rolling props:
import { getPanelProps } from '../test-utils'; // public/app/plugins/panel/test-utils.ts
render(<BarChartPanel {...getPanelProps(defaultOptions, { fieldConfig })} />);> **Gotcha — field config.** A panel unit test must call `applyFieldOverrides` itself with a > `createFieldConfigRegistry`; the panel framework normally does this, so without it your > custom `fieldConfig.custom` never reaches the render and every case looks identical.
> **Gotcha — type inference.** If you're testing `guessFieldTypes` (or any inference), feed > **untyped** raw fields (`as unknown as DataFrameDTO`). `createDataFrame` pre-sets `type`, so > the function under test becomes a no-op and the test gives false confidence.
Panels that draw to canvas (timeseries, heatmap, xychart, timeline, piechart, sparkline) are tested by **capturing the ctx draw-call stream**, not by pixel-diffing. Follow the established harness:
// In the harness (public/app/plugins/panel/timeseries/TimeSeriesPanel.canvasTestUtils.tsx):
import {
applyDefaultUPlotAxisMeasureTextMock,
installCanvasPath2DShim,
removeCanvasTransforms,
} from '@grafana/test-utils/canvas';
// In each *.canvas.test.tsx, mock grafana-ui's text measurement so layout is deterministic:
jest.mock('@grafana/ui/src/utils/measureText', () =>
require('@grafana/test-utils/canvas').createGrafanaUiMeasureTextJestMock(() =>
require('./TimeSeriesPanel.canvasTestUtils').getUPlotInstance()
)
);`*.axisPlacement.…`, `*.axisRange.…` — each a focused `it.each` of cases.
timestamps (`Date.UTC(...)`, `timeZone: 'utc'`), and wait for the renderer to be ready before asserting — `await waitFor(() => expect(uPlotInstance?.status).toBe(1))` (a `waitFor` callback must **throw** to retry, so it needs `expect`, not a bare boolean).
The DataViz strategy is **unit-first**. Reserve Playwright for cross-component interaction and per-panel smoke coverage. When you do write E2E:
`data-testid` into the JSX, then query it (use the `add-e2e-selectors` skill).
in unit `screen.getByTestId(selectors.components...)`.
import { test, expect } from '@grafana/plugin-e2e';
test.describe('Panels test: BarChart render', { tag: ['@panels', '@barchart'] }, () => {
test('renders without error', async ({ gotoDashboardPage, selectors }) => {
const page = await gotoDashboardPage({ uid: DASHBOARD_UID }); // provisioned devenv dashboard
await expect(page.getByGrafanaSelector(selectors.components.Panels.Panel.headerCornerInfo('error'))).toBeHidden();
});
});**Every panel must have an E2E accessibility test.** Use the `scanForA11yViolations` fixture and the `toHaveNoA11yViolations()` matcher, in a `describe`/test tagged `@a11y`. Load the panel, wait for it to actually render (assert the panel title and the chart element are visible — an empty panel trivially passes), then scan:
test.describe('a11y', { tag: ['@a11y'] }, () => {
test('run a11y report', async ({ gotoDashboardPage, scanForA11yViolations, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: DASHBOARD_UID,
queryParams: new URLSearchParams({ viewPanel: 'panel-4' }),
});
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('…'))).toBeVisible();
await expect(page.locator('.uplot')).toBeVisible(); // panel has drawn
const report = await scanForA11yViolations({
options: { runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
Repo: grafana/grafana
Add reliable @grafana/e2e-selectors to interactive elements and key containers in the Grafana frontend. Use when adding e2e selectors, data-testid attributes,…
Write unit and E2E tests for Grafana frontend code (React/TypeScript, any package or feature area) to the conventions this repo expects. Use when adding,…