From 3d0a617718d72aefa4f3e14bd021794dc4ba2bb6 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Fri, 6 Mar 2026 10:48:54 +0100 Subject: [PATCH 01/11] add tests --- CLAUDE.md | 1 + docker-compose.yaml | 3 + package.json | 2 +- src/views/QueryEditor.tsx | 5 - src/views/QueryEditorPullRequests.tsx | 2 + tests/AGENTS.md | 190 ++++++++++++++++++++++++++ tests/DashboardPanels.spec.ts | 40 ++++++ tests/QueryEditor.spec.ts | 72 ++++++---- tests/QueryEditorPanels.spec.ts | 52 +++++++ tests/variableEditor.spec.ts | 40 ++++++ yarn.lock | 20 +-- 11 files changed, 387 insertions(+), 40 deletions(-) create mode 100644 CLAUDE.md create mode 100644 tests/AGENTS.md create mode 100644 tests/DashboardPanels.spec.ts create mode 100644 tests/QueryEditorPanels.spec.ts create mode 100644 tests/variableEditor.spec.ts diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..68c9e1d4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@test/AGENTS.md diff --git a/docker-compose.yaml b/docker-compose.yaml index b8927c88..84e3946d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,3 +3,6 @@ services: extends: file: .config/docker-compose-base.yaml service: grafana + environment: + GITHUB_TOKEN: ${GITHUB_TOKEN} + GITHUB_URL: ${GITHUB_URL:-} diff --git a/package.json b/package.json index 29f68345..3f262c58 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@changesets/cli": "2.29.8", "@grafana/e2e-selectors": "12.4.0", "@grafana/eslint-config": "9.0.0", - "@grafana/plugin-e2e": "3.4.0", + "@grafana/plugin-e2e": "3.4.2", "@grafana/plugin-meta-extractor": "0.12.2", "@grafana/tsconfig": "2.0.1", "@openfeature/web-sdk": "1.7.3", diff --git a/src/views/QueryEditor.tsx b/src/views/QueryEditor.tsx index 2bc064d1..e4beb069 100644 --- a/src/views/QueryEditor.tsx +++ b/src/views/QueryEditor.tsx @@ -3,7 +3,6 @@ import { QueryEditorProps, SelectableValue } from '@grafana/data'; import { Select, InlineField } from '@grafana/ui'; import { GitHubDataSource } from '../DataSource'; -import { isValid } from '../validation'; import { components } from '../components/selectors'; import QueryEditorRepository from './QueryEditorRepository'; @@ -138,10 +137,6 @@ const QueryEditor = (props: Props) => { const onChange = useCallback( (value: GitHubQuery) => { props.onChange(value); - - if (isValid(value)) { - props.onRunQuery(); - } }, [props] ); diff --git a/src/views/QueryEditorPullRequests.tsx b/src/views/QueryEditorPullRequests.tsx index b2a161c7..fcf588f4 100644 --- a/src/views/QueryEditorPullRequests.tsx +++ b/src/views/QueryEditorPullRequests.tsx @@ -3,6 +3,7 @@ import { Input, Select, InlineField } from '@grafana/ui'; import { SelectableValue } from '@grafana/data'; import { RightColumnWidth, LeftColumnWidth } from './QueryEditor'; import { PullRequestTimeField } from '../constants'; +import { components } from '../components/selectors'; import type { PullRequestsOptions } from '../types/query'; interface Props extends PullRequestsOptions { @@ -42,6 +43,7 @@ const QueryEditorPullRequests = (props: Props) => { interactive={true} > setQuery(el.currentTarget.value)} diff --git a/tests/AGENTS.md b/tests/AGENTS.md new file mode 100644 index 00000000..7cd2e917 --- /dev/null +++ b/tests/AGENTS.md @@ -0,0 +1,190 @@ +# E2E testing a Grafana plugin + +This plugin uses `@grafana/plugin-e2e` and Playwright for end-to-end testing. + +- Always import `test` and `expect` from `@grafana/plugin-e2e`, not from `@playwright/test`. +- Always use `@grafana/plugin-e2e` fixtures and page models instead of raw Playwright navigation. They handle Grafana version differences automatically. +- Place test files in `tests/` as `*.spec.ts`. +- Each test must be independent and assume fresh state. +- If tests fail against newer Grafana versions, update `@grafana/plugin-e2e` first. It evolves alongside Grafana core to handle selector and API changes. + +## Selecting elements + +### Grafana selectors + +- Use Grafana e2e-selectors whenever possible. Always get them from the `selectors` fixture provided by `@grafana/plugin-e2e` - never import from `@grafana/e2e-selectors` directly. The fixture resolves the correct selectors for the Grafana version under test. +- Always use the `getByGrafanaSelector` method (exposed by all plugin-e2e page models) to resolve selectors to Playwright locators. It handles the `aria-label` vs `data-testid` difference across Grafana versions automatically. + ```typescript + panelEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); + ``` + +### Scoping locators + +Scope locators to the narrowest context possible. + +```typescript +// bad - matches any "URL" text on the page +page.getByText('URL').click(); +// good - scoped to the plugin's wrapper +page.getByTestId('plugin-url-wrapper').getByText('URL').click(); +``` + +### Form elements + +The `InlineField` and `Field` components can be used interchangeably in the examples below. + +**Input** - use `getByRole('textbox', { name: '