From 5a28b6b939d0504c0bbf18bb9cac61514d1c1b1b Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Tue, 24 Feb 2026 14:34:11 +0100 Subject: [PATCH 1/5] add e2e testing instructions for agents --- .../common/.config/AGENTS/e2e-testing.md | 194 ++++++++++++++++++ .../common/.config/AGENTS/instructions.md | 2 +- 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 packages/create-plugin/templates/common/.config/AGENTS/e2e-testing.md diff --git a/packages/create-plugin/templates/common/.config/AGENTS/e2e-testing.md b/packages/create-plugin/templates/common/.config/AGENTS/e2e-testing.md new file mode 100644 index 0000000000..37e494d0f4 --- /dev/null +++ b/packages/create-plugin/templates/common/.config/AGENTS/e2e-testing.md @@ -0,0 +1,194 @@ +# 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. + +## 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: '