diff --git a/docusaurus/docs/e2e-test-a-plugin/feature-toggles.md b/docusaurus/docs/e2e-test-a-plugin/feature-toggles.md index 542c81a6a..6d1ecf793 100644 --- a/docusaurus/docs/e2e-test-a-plugin/feature-toggles.md +++ b/docusaurus/docs/e2e-test-a-plugin/feature-toggles.md @@ -78,7 +78,7 @@ test('valid credentials should return a 200 status code', async ({ isFeatureToggleEnabled, }) => { const configPage = await createDataSourceConfigPage({ type: 'grafana-snowflake-datasource' }); - await configPage.getByTestIdOrAriaLabel('Data source connection URL').fill('http://localhost:9090'); + await configPage.getByGrafanaSelector('Data source connection URL').fill('http://localhost:9090'); const isSecureSocksDSProxyEnabled = await isFeatureToggleEnabled('secureSocksDSProxyEnabled'); if (isSecureSocksDSProxyEnabled) { page.getByLabel('Enabled').check(); diff --git a/docusaurus/docs/e2e-test-a-plugin/selecting-ui-elements.md b/docusaurus/docs/e2e-test-a-plugin/selecting-ui-elements.md index 11dae4af0..0bb93726b 100644 --- a/docusaurus/docs/e2e-test-a-plugin/selecting-ui-elements.md +++ b/docusaurus/docs/e2e-test-a-plugin/selecting-ui-elements.md @@ -24,10 +24,10 @@ Selecting Grafana UI elements can be challenging because the selector may be def ## Playwright locator for Grafana UI elements -All [pages](https://github.com/grafana/plugin-tools/tree/main/packages/plugin-e2e/src/models/pages) defined by `@grafana/plugin-e2e` expose a `getByTestIdOrAriaLabel` method. This method returns a Playwright [locator](https://playwright.dev/docs/locators) that resolves to one or more elements, using the appropriate HTML attribute as defined on the element. Whenever you want to resolve a Playwright locator based on a [grafana/e2e-selectors](https://github.com/grafana/grafana/tree/main/packages/grafana-e2e-selectors), you should always use this method. +All [pages](https://github.com/grafana/plugin-tools/tree/main/packages/plugin-e2e/src/models/pages) defined by `@grafana/plugin-e2e` expose a `getByGrafanaSelector` method. This method returns a Playwright [locator](https://playwright.dev/docs/locators) that resolves to one or more elements, using the appropriate HTML attribute as defined on the element. Whenever you want to resolve a Playwright locator based on a [grafana/e2e-selectors](https://github.com/grafana/grafana/tree/main/packages/grafana-e2e-selectors), you should always use this method. ```ts -panelEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); +panelEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); ``` ## The selectors fixture @@ -41,16 +41,14 @@ import { test, expect } from '@grafana/plugin-e2e'; test('annotation query should be OK when query is valid', async ({ annotationEditPage, page, selectors }) => { await annotationEditPage.datasource.set('E2E Test Data Source'); - await annotationEditPage - .getByTestIdOrAriaLabel(selectors.components.CodeEditor.container) - .fill('SELECT * FROM users'); + await annotationEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).fill('SELECT * FROM users'); await expect(annotationEditPage.runQuery()).toBeOK(); }); ``` ## Interact with UI elements defined in the plugin code -As stated above, you should always use the `getByTestIdOrAriaLabel` method when the UI element you want to interact with has an associated end-to-end selector. However, many Grafana UI elements don't have end-to-end selectors. If that's the case, we recommended following Grafana's best practices for [testing](https://github.com/grafana/grafana/blob/401265522e584e4e71a1d92d5af311564b1ec33e/contribute/style-guides/testing.md) and the [testing with accessibility in mind](https://github.com/grafana/grafana/blob/401265522e584e4e71a1d92d5af311564b1ec33e/contribute/style-guides/accessibility.md#writing-tests-with-accessibility-in-mind) guide when composing your UI and writing tests. +As stated above, you should always use the `getByGrafanaSelector` method when the UI element you want to interact with has an associated end-to-end selector. However, many Grafana UI elements don't have end-to-end selectors. If that's the case, we recommended following Grafana's best practices for [testing](https://github.com/grafana/grafana/blob/401265522e584e4e71a1d92d5af311564b1ec33e/contribute/style-guides/testing.md) and the [testing with accessibility in mind](https://github.com/grafana/grafana/blob/401265522e584e4e71a1d92d5af311564b1ec33e/contribute/style-guides/accessibility.md#writing-tests-with-accessibility-in-mind) guide when composing your UI and writing tests. ### Scope locators @@ -105,7 +103,7 @@ test('testing select component', async ({ page, selectors }) => { const configPage = await createDataSourceConfigPage({ type: 'test-datasource' }); await page.getByRole('combobox', { name: 'Auth type' }).click(); const option = selectors.components.Select.option; - await expect(configPage.getByTestIdOrAriaLabel(option)).toHaveText(['val1', 'val2']); + await expect(configPage.getByGrafanaSelector(option)).toHaveText(['val1', 'val2']); }); ``` diff --git a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/annotation-queries.md b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/annotation-queries.md index 79e0b7d7f..3a9f056d9 100644 --- a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/annotation-queries.md +++ b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/annotation-queries.md @@ -45,7 +45,7 @@ test('should run successfully and display a success alert box when query is vali const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' }); await annotationEditPage.datasource.set(ds.name); await page.waitForFunction(() => window.monaco); - await annotationEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await annotationEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText(`select time as time, humidity as text from dataset where $__timeFilter(time) and humidity > 95`); @@ -71,7 +71,7 @@ test('should fail and display an error alert box when time field is missing in t const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' }); await annotationEditPage.datasource.set(ds.name); await page.waitForFunction(() => window.monaco); - await annotationEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await annotationEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText(`select humidity as text from dataset where humidity > 95`); diff --git a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/custom-variable-editor.md b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/custom-variable-editor.md index 766cb6b69..6cbfb83b0 100644 --- a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/custom-variable-editor.md +++ b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/custom-variable-editor.md @@ -30,7 +30,7 @@ test('should display Dimensions field only if ListByDimensions is selected', asy const ds = await readProvisionedDataSource({ fileName: 'datasources.yaml' }); await variableEditPage.setVariableType('Query'); await variableEditPage.datasource.set(ds.name); - const dimensionField = variableEditPage.getByTestIdOrAriaLabel('Dimensions'); + const dimensionField = variableEditPage.getByGrafanaSelector('Dimensions'); await expect(dimensionField).not.toBeVisible(); await variableEditPage.getByLabel('Query type').fill('ListByDimensions'); await page.keyboard.press('Enter'); @@ -61,7 +61,7 @@ test('custom variable query runner should return data when query is valid', asyn await variableEditPage.setVariableType('Query'); await variableEditPage.datasource.set(ds.name); const codeEditorSelector = selectors.components.CodeEditor.container; - await variableEditPage.getByTestIdOrAriaLabel(codeEditorSelector).click(); + await variableEditPage.getByGrafanaSelector(codeEditorSelector).click(); await page.keyboard.insertText('select distinct(environment) from dataset'); const queryDataRequest = variableEditPage.waitForQueryDataRequest(); await variableEditPage.runQuery(); diff --git a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/query-editor.md b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/query-editor.md index 302ecb76b..4bc99555f 100644 --- a/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/query-editor.md +++ b/docusaurus/docs/e2e-test-a-plugin/test-a-data-source-plugin/query-editor.md @@ -31,7 +31,7 @@ test('should filter out govcloud regions', async ({ panelEditPage, selectors, re await panelEditPage.datasource.set(ds.name); await panelEditPage.mockResourceResponse('regions', regionsMock); await panelEditPage.getQueryEditorRow('A').getByText('Regions').click(); - await expect(panelEditPage.getByTestIdOrAriaLabel(selectors.components.Select.option)).toHaveText(expectedRegions); + await expect(panelEditPage.getByGrafanaSelector(selectors.components.Select.option)).toHaveText(expectedRegions); }); ``` diff --git a/packages/plugin-e2e/CONTRIBUTING.md b/packages/plugin-e2e/CONTRIBUTING.md index 523e92dcb..f0a1db8c7 100644 --- a/packages/plugin-e2e/CONTRIBUTING.md +++ b/packages/plugin-e2e/CONTRIBUTING.md @@ -111,10 +111,10 @@ If for example the UI for adding a panel to a dashboard is being changed complet if (gte(this.ctx.grafanaVersion, '10.4.0')) { // logic that ensures adding new panels work in Grafana versions greater than or equals to 10.4.0 } else if (gte(this.ctx.grafanaVersion, '10.0.0')) { - await this.getByTestIdOrAriaLabel(components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle)).click(); - await this.getByTestIdOrAriaLabel(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click(); + await this.getByGrafanaSelector(components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle)).click(); + await this.getByGrafanaSelector(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click(); } else { - await this.getByTestIdOrAriaLabel(pages.AddDashboard.addNewPanel).click(); + await this.getByGrafanaSelector(pages.AddDashboard.addNewPanel).click(); } ``` diff --git a/packages/plugin-e2e/src/index.ts b/packages/plugin-e2e/src/index.ts index d5868987b..5dfe56cf0 100644 --- a/packages/plugin-e2e/src/index.ts +++ b/packages/plugin-e2e/src/index.ts @@ -89,7 +89,7 @@ export const expect = baseExpect.extend({ /** Register a custom selector engine that resolves locators for Grafana E2E selectors * - * The same functionality is available in the {@link GrafanaPage.getByTestIdOrAriaLabel} method. However, + * The same functionality is available in the {@link GrafanaPage.getByGrafanaSelector} method. However, * by registering the selector engine, one can resolve locators by Grafana E2E selectors also within a locator. * * Example: diff --git a/packages/plugin-e2e/src/matchers/toDisplayPreviews.ts b/packages/plugin-e2e/src/matchers/toDisplayPreviews.ts index 5bb794358..b615d7b61 100644 --- a/packages/plugin-e2e/src/matchers/toDisplayPreviews.ts +++ b/packages/plugin-e2e/src/matchers/toDisplayPreviews.ts @@ -14,7 +14,7 @@ export const toDisplayPreviews = async ( try { await expect( - variableEditPage.getByTestIdOrAriaLabel( + variableEditPage.getByGrafanaSelector( variableEditPage.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption ) ).toContainText(previewTexts, options); diff --git a/packages/plugin-e2e/src/matchers/toHaveAlert.ts b/packages/plugin-e2e/src/matchers/toHaveAlert.ts index 622ca6ab9..c1bfe8b3b 100644 --- a/packages/plugin-e2e/src/matchers/toHaveAlert.ts +++ b/packages/plugin-e2e/src/matchers/toHaveAlert.ts @@ -10,7 +10,7 @@ export const toHaveAlert = async (grafanaPage: GrafanaPage, severity: AlertVaria try { const filteredAlerts = grafanaPage - .getByTestIdOrAriaLabel(grafanaPage.ctx.selectors.components.Alert.alertV2(severity)) + .getByGrafanaSelector(grafanaPage.ctx.selectors.components.Alert.alertV2(severity)) .filter({ hasText: options?.hasText, hasNotText: options?.hasNotText, diff --git a/packages/plugin-e2e/src/models/components/DataSourcePicker.ts b/packages/plugin-e2e/src/models/components/DataSourcePicker.ts index 5af2bcc8f..be101df1b 100644 --- a/packages/plugin-e2e/src/models/components/DataSourcePicker.ts +++ b/packages/plugin-e2e/src/models/components/DataSourcePicker.ts @@ -10,7 +10,7 @@ export class DataSourcePicker extends GrafanaPage { * Sets the data source picker to the provided name */ async set(name: string) { - await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.DataSourcePicker.container) + await this.getByGrafanaSelector(this.ctx.selectors.components.DataSourcePicker.container) .locator('input') .fill(name); diff --git a/packages/plugin-e2e/src/models/components/Panel.ts b/packages/plugin-e2e/src/models/components/Panel.ts index 6c8e63b7e..c00066a4f 100644 --- a/packages/plugin-e2e/src/models/components/Panel.ts +++ b/packages/plugin-e2e/src/models/components/Panel.ts @@ -43,7 +43,7 @@ export class Panel extends GrafanaPage { selector = this.ctx.selectors.components.Panels.Panel.headerCornerInfo(ERROR_STATUS); } - return this.getByTestIdOrAriaLabel(selector, { + return this.getByGrafanaSelector(selector, { root: this.locator, }); } diff --git a/packages/plugin-e2e/src/models/components/TimeRange.ts b/packages/plugin-e2e/src/models/components/TimeRange.ts index 75b76fb7a..ae58f8844 100644 --- a/packages/plugin-e2e/src/models/components/TimeRange.ts +++ b/packages/plugin-e2e/src/models/components/TimeRange.ts @@ -13,7 +13,7 @@ export class TimeRange extends GrafanaPage { async set({ from, to, zone }: TimeRangeArgs) { const { TimeZonePicker, TimePicker } = this.ctx.selectors.components; try { - await this.getByTestIdOrAriaLabel(TimePicker.openButton).click(); + await this.getByGrafanaSelector(TimePicker.openButton).click(); } catch (e) { // seems like in older versions of Grafana the time picker markup is rendered twice await this.ctx.page.locator('[aria-controls="TimePickerContent"]').last().click(); @@ -21,19 +21,19 @@ export class TimeRange extends GrafanaPage { if (zone) { const changeTimeSettingsButton = semver.gte(this.ctx.grafanaVersion, '11.0.0') - ? this.getByTestIdOrAriaLabel(TimeZonePicker.changeTimeSettingsButton) + ? this.getByGrafanaSelector(TimeZonePicker.changeTimeSettingsButton) : this.ctx.page.getByRole('button', { name: 'Change time settings' }); await changeTimeSettingsButton.click(); - await this.getByTestIdOrAriaLabel(TimeZonePicker.containerV2).fill(zone); + await this.getByGrafanaSelector(TimeZonePicker.containerV2).fill(zone); } - await this.getByTestIdOrAriaLabel(TimePicker.absoluteTimeRangeTitle).click(); - const fromField = await this.getByTestIdOrAriaLabel(TimePicker.fromField); + await this.getByGrafanaSelector(TimePicker.absoluteTimeRangeTitle).click(); + const fromField = await this.getByGrafanaSelector(TimePicker.fromField); await fromField.clear(); await fromField.fill(from); - const toField = await this.getByTestIdOrAriaLabel(TimePicker.toField); + const toField = await this.getByGrafanaSelector(TimePicker.toField); await toField.clear(); await toField.fill(to); - await this.getByTestIdOrAriaLabel(TimePicker.applyTimeRange).click(); + await this.getByGrafanaSelector(TimePicker.applyTimeRange).click(); } } diff --git a/packages/plugin-e2e/src/models/pages/AnnotationEditPage.ts b/packages/plugin-e2e/src/models/pages/AnnotationEditPage.ts index fc1669edc..239ae1633 100644 --- a/packages/plugin-e2e/src/models/pages/AnnotationEditPage.ts +++ b/packages/plugin-e2e/src/models/pages/AnnotationEditPage.ts @@ -33,7 +33,7 @@ export class AnnotationEditPage extends GrafanaPage { ); const testButton = semver.gte(this.ctx.grafanaVersion, '11.0.0') - ? this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Annotations.editor.testButton) + ? this.getByGrafanaSelector(this.ctx.selectors.components.Annotations.editor.testButton) : this.ctx.page.getByRole('button', { name: 'TEST' }); await testButton.click(); return responsePromise; diff --git a/packages/plugin-e2e/src/models/pages/AnnotationPage.ts b/packages/plugin-e2e/src/models/pages/AnnotationPage.ts index dcf4668d9..ac5c9e7e2 100644 --- a/packages/plugin-e2e/src/models/pages/AnnotationPage.ts +++ b/packages/plugin-e2e/src/models/pages/AnnotationPage.ts @@ -29,14 +29,14 @@ export class AnnotationPage extends GrafanaPage { if (!this.dashboard?.uid) { //the dashboard doesn't have any annotations yet (except for the built-in one) if (semver.gte(this.ctx.grafanaVersion, '8.3.0')) { - await this.getByTestIdOrAriaLabel(addAnnotationCTAV2).click(); + await this.getByGrafanaSelector(addAnnotationCTAV2).click(); } else { - await this.getByTestIdOrAriaLabel(addAnnotationCTA).click(); + await this.getByGrafanaSelector(addAnnotationCTA).click(); } } else { //the dashboard already has annotations const newQueryButton = semver.gte(this.ctx.grafanaVersion, '11.0.0') - ? this.getByTestIdOrAriaLabel(addAnnotationCTAV2) + ? this.getByGrafanaSelector(addAnnotationCTAV2) : this.ctx.page.getByRole('button', { name: 'New query' }); await newQueryButton.click(); } diff --git a/packages/plugin-e2e/src/models/pages/DashboardPage.ts b/packages/plugin-e2e/src/models/pages/DashboardPage.ts index 84166b78f..55f233830 100644 --- a/packages/plugin-e2e/src/models/pages/DashboardPage.ts +++ b/packages/plugin-e2e/src/models/pages/DashboardPage.ts @@ -53,7 +53,7 @@ export class DashboardPage extends GrafanaPage { * await expect(panel.fieldNames).toContainText(['time', 'temperature']); */ getPanelByTitle(title: string): Panel { - let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(title), { + let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(title), { startsWith: true, }); // in older versions, the panel selector is added to a child element, so we need to go up two levels to get the wrapper @@ -81,12 +81,12 @@ export class DashboardPage extends GrafanaPage { async addPanel(): Promise { const { components, pages } = this.ctx.selectors; if (semver.gte(this.ctx.grafanaVersion, '10.0.0')) { - await this.getByTestIdOrAriaLabel( + await this.getByGrafanaSelector( components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle) ).click(); - await this.getByTestIdOrAriaLabel(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click(); + await this.getByGrafanaSelector(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click(); } else { - await this.getByTestIdOrAriaLabel(pages.AddDashboard.addNewPanel).click(); + await this.getByGrafanaSelector(pages.AddDashboard.addNewPanel).click(); } const panelId = await this.ctx.page.evaluate(() => { diff --git a/packages/plugin-e2e/src/models/pages/DataSourceConfigPage.ts b/packages/plugin-e2e/src/models/pages/DataSourceConfigPage.ts index 96127bcb0..e10bc185e 100644 --- a/packages/plugin-e2e/src/models/pages/DataSourceConfigPage.ts +++ b/packages/plugin-e2e/src/models/pages/DataSourceConfigPage.ts @@ -45,7 +45,7 @@ export class DataSourceConfigPage extends GrafanaPage { ); const healthPath = options?.path ?? health(this.datasource.uid, this.datasource.id.toString()); const healthResponsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes(healthPath)); - await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.DataSource.saveAndTest).click(); + await this.getByGrafanaSelector(this.ctx.selectors.pages.DataSource.saveAndTest).click(); return saveResponsePromise.then(() => healthResponsePromise); } } diff --git a/packages/plugin-e2e/src/models/pages/ExplorePage.ts b/packages/plugin-e2e/src/models/pages/ExplorePage.ts index e8b2f763c..73c74100a 100644 --- a/packages/plugin-e2e/src/models/pages/ExplorePage.ts +++ b/packages/plugin-e2e/src/models/pages/ExplorePage.ts @@ -32,7 +32,7 @@ export class ExplorePage extends GrafanaPage { private getPanelLocators(suffix: string, text: string) { const page = this.ctx.page; - let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(suffix), { + let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(suffix), { startsWith: true, }); @@ -57,8 +57,8 @@ export class ExplorePage extends GrafanaPage { * Returns the locator for the query editor row with the given refId */ getQueryEditorRow(refId: string): Locator { - return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRows.rows).filter({ - has: this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRow.title(refId)), + return this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRows.rows).filter({ + has: this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRow.title(refId)), }); } @@ -72,13 +72,13 @@ export class ExplorePage extends GrafanaPage { options ); try { - await this.getByTestIdOrAriaLabel(components.RefreshPicker.runButtonV2).click({ + await this.getByGrafanaSelector(components.RefreshPicker.runButtonV2).click({ timeout: 1000, }); } catch (_) { // handle the case when the run button is hidden behind the "Show more items" button - await this.getByTestIdOrAriaLabel(components.PageToolbar.item(components.PageToolbar.shotMoreItems)).click(); - await this.getByTestIdOrAriaLabel(components.RefreshPicker.runButtonV2).last().click(); + await this.getByGrafanaSelector(components.PageToolbar.item(components.PageToolbar.shotMoreItems)).click(); + await this.getByGrafanaSelector(components.RefreshPicker.runButtonV2).last().click(); } return responsePromise; } diff --git a/packages/plugin-e2e/src/models/pages/GrafanaPage.ts b/packages/plugin-e2e/src/models/pages/GrafanaPage.ts index a9875a7c5..283f4bf4e 100644 --- a/packages/plugin-e2e/src/models/pages/GrafanaPage.ts +++ b/packages/plugin-e2e/src/models/pages/GrafanaPage.ts @@ -1,5 +1,5 @@ import { Locator, Request, Response } from '@playwright/test'; -import { GetByTestIdOrAriaLabelOptions, NavigateOptions, PluginTestCtx } from '../../types'; +import { getByGrafanaSelectorOptions, NavigateOptions, PluginTestCtx } from '../../types'; /** * Base class for all Grafana pages. @@ -20,11 +20,10 @@ export abstract class GrafanaPage { } /** - * Get a locator for a Grafana element by data-testid or aria-label - * @param selector the data-testid or aria-label of the element - * @param root optional root locator to search within. If no locator is provided, the page will be used + * Get a locator based on a Grafana E2E selector. A grafana E2E selector is defined in @grafana/e2e-selectors or in plugin-e2e/src/e2e-selectors. + * An E2E selector is a string that identifies a specific element in the Grafana UI. The element referencing the E2E selector use the data-testid or aria-label attribute. */ - getByTestIdOrAriaLabel(selector: string, options?: GetByTestIdOrAriaLabelOptions): Locator { + getByGrafanaSelector(selector: string, options?: getByGrafanaSelectorOptions): Locator { const startsWith = options?.startsWith ? '^' : ''; if (selector.startsWith('data-testid')) { return (options?.root || this.ctx.page).locator(`[data-testid${startsWith}="${selector}"]`); diff --git a/packages/plugin-e2e/src/models/pages/PanelEditPage.ts b/packages/plugin-e2e/src/models/pages/PanelEditPage.ts index a1325ac54..bc5460b1b 100644 --- a/packages/plugin-e2e/src/models/pages/PanelEditPage.ts +++ b/packages/plugin-e2e/src/models/pages/PanelEditPage.ts @@ -21,7 +21,7 @@ export class PanelEditPage extends GrafanaPage { private getPanelLocator() { // only one panel is allowed in the panel edit page, so we don't need to use panel title to locate it - const locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(''), { + const locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(''), { startsWith: true, }); // in older versions, the panel selector is added to a child element, so we need to go up two levels to get the wrapper @@ -48,7 +48,7 @@ export class PanelEditPage extends GrafanaPage { async toggleTableView() { await radioButtonSetChecked(this.ctx.page, 'Table view', true); - let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.toggleTableViewPanel('')); + let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.toggleTableViewPanel('')); if (semver.lt(this.ctx.grafanaVersion, '10.4.0')) { locator = this.ctx.page.getByRole('table'); } @@ -59,7 +59,7 @@ export class PanelEditPage extends GrafanaPage { await radioButtonSetChecked(this.ctx.page, 'Table view', false); this.panel = new Panel( this.ctx, - this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(''), { startsWith: true }) + this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(''), { startsWith: true }) ); } @@ -72,8 +72,8 @@ export class PanelEditPage extends GrafanaPage { await this.collapseSection(OptionsGroup.groupTitle); const vizInput = semver.gte(this.ctx.grafanaVersion, '11.0.0') - ? this.getByTestIdOrAriaLabel(PanelEditor.OptionsPane.fieldInput(TITLE)) - : this.getByTestIdOrAriaLabel(OptionsGroup.group(OptionsGroup.groupTitle)).locator('input').first(); + ? this.getByGrafanaSelector(PanelEditor.OptionsPane.fieldInput(TITLE)) + : this.getByGrafanaSelector(OptionsGroup.group(OptionsGroup.groupTitle)).locator('input').first(); await vizInput.fill(titleText); await this.ctx.page.keyboard.press('Tab'); } @@ -83,15 +83,15 @@ export class PanelEditPage extends GrafanaPage { */ async setVisualization(visualization: Visualization) { // toggle options pane if panel edit is not visible - const showPanelEditElement = this.getByTestIdOrAriaLabel('Show options pane'); + const showPanelEditElement = this.getByGrafanaSelector('Show options pane'); const showPanelEditElementCount = await showPanelEditElement.count(); if (showPanelEditElementCount > 0) { await showPanelEditElement.click(); } - await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker).click(); - await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PluginVisualization.item(visualization)).click(); + await this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker).click(); + await this.getByGrafanaSelector(this.ctx.selectors.components.PluginVisualization.item(visualization)).click(); await expect( - this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker), + this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker), `Could not set visualization to ${visualization}. Ensure the panel is installed.` ).toHaveText(visualization); } @@ -100,9 +100,9 @@ export class PanelEditPage extends GrafanaPage { * Expands the section for the given category name. If the section is already expanded, this method does nothing. */ async collapseSection(categoryName: string) { - const section = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.OptionsGroup.group(categoryName)); + const section = this.getByGrafanaSelector(this.ctx.selectors.components.OptionsGroup.group(categoryName)); await expect(section, `Could not find any section for category: ${categoryName}`).toBeVisible(); - const sectionToggle = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.OptionsGroup.toggle(categoryName)); + const sectionToggle = this.getByGrafanaSelector(this.ctx.selectors.components.OptionsGroup.toggle(categoryName)); const expandedAttr = (await sectionToggle.getAttribute('aria-expanded')) ?? ''; if (/false/.test(expandedAttr)) { await section.click(); @@ -113,7 +113,7 @@ export class PanelEditPage extends GrafanaPage { * Returns the name of the visualization currently selected in the panel editor */ getVisualizationName(): Locator { - return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker); + return this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker); } /** @@ -127,8 +127,8 @@ export class PanelEditPage extends GrafanaPage { * Returns the locator for the query editor row with the given refId */ getQueryEditorRow(refId: string): Locator { - return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRows.rows).filter({ - has: this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRow.title(refId)), + return this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRows.rows).filter({ + has: this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRow.title(refId)), }); } @@ -152,7 +152,7 @@ export class PanelEditPage extends GrafanaPage { ); // in older versions of grafana, the refresh button is rendered twice. this is a workaround to click the correct one - const refreshPanelButton = this.getByTestIdOrAriaLabel( + const refreshPanelButton = this.getByGrafanaSelector( this.ctx.selectors.components.PanelEditor.General.content ).locator(`selector=${this.ctx.selectors.components.RefreshPicker.runButtonV2}`); diff --git a/packages/plugin-e2e/src/models/pages/VariableEditPage.ts b/packages/plugin-e2e/src/models/pages/VariableEditPage.ts index 0e99b4e6e..bad6c4c4d 100644 --- a/packages/plugin-e2e/src/models/pages/VariableEditPage.ts +++ b/packages/plugin-e2e/src/models/pages/VariableEditPage.ts @@ -30,14 +30,14 @@ export class VariableEditPage extends GrafanaPage { * Sets the type of variable in the 'Variable type' dropdown to the given type */ async setVariableType(type: VariableType) { - await this.getByTestIdOrAriaLabel( + await this.getByGrafanaSelector( this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2 ) .locator('input') .fill(type); await this.ctx.page.keyboard.press('ArrowDown'); await this.ctx.page.keyboard.press('Enter'); - await this.getByTestIdOrAriaLabel( + await this.getByGrafanaSelector( this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2 ).scrollIntoViewIfNeeded(); } @@ -52,7 +52,7 @@ export class VariableEditPage extends GrafanaPage { async runQuery() { // in 9.2.0, the submit button got a new purpose. it no longer submits the form, but instead runs the query if (gte(this.ctx.grafanaVersion, '9.2.0')) { - await this.getByTestIdOrAriaLabel( + await this.getByGrafanaSelector( this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton ).click(); } else { diff --git a/packages/plugin-e2e/src/models/pages/VariablePage.ts b/packages/plugin-e2e/src/models/pages/VariablePage.ts index 58a5b8d23..b02a936a9 100644 --- a/packages/plugin-e2e/src/models/pages/VariablePage.ts +++ b/packages/plugin-e2e/src/models/pages/VariablePage.ts @@ -27,9 +27,9 @@ export class VariablePage extends GrafanaPage { this.ctx.selectors.pages.Dashboard.Settings.Variables.List; if (!this.dashboard?.uid) { - await this.getByTestIdOrAriaLabel(addVariableCTAV2(addVariableCTAV2Item)).click(); + await this.getByGrafanaSelector(addVariableCTAV2(addVariableCTAV2Item)).click(); } else { - await this.getByTestIdOrAriaLabel(newButton).click(); + await this.getByGrafanaSelector(newButton).click(); } const editIndex = await this.ctx.page.evaluate(() => { diff --git a/packages/plugin-e2e/src/types.ts b/packages/plugin-e2e/src/types.ts index d72267ca2..6f37ffffc 100644 --- a/packages/plugin-e2e/src/types.ts +++ b/packages/plugin-e2e/src/types.ts @@ -479,7 +479,7 @@ export type AppPageNavigateOptions = NavigateOptions & { path?: string; }; -export type GetByTestIdOrAriaLabelOptions = { +export type getByGrafanaSelectorOptions = { /** *Optional root locator to search within. If no locator is provided, the page will be used */ diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationEditor.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationEditor.spec.ts index 7e462ab73..321a35432 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationEditor.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationEditor.spec.ts @@ -10,7 +10,7 @@ test('should load resources and display them as options when clicking on an inpu const ds = await readProvisionedDataSource({ fileName: 'redshift.yaml' }); await annotationEditPage.datasource.set(ds.name); await page.getByLabel('Schema').click(); - await expect(annotationEditPage.getByTestIdOrAriaLabel('Select option')).toContainText(REDSHIFT_SCHEMAS); + await expect(annotationEditPage.getByGrafanaSelector('Select option')).toContainText(REDSHIFT_SCHEMAS); }); test('should be able to add a new annotation when there annotations already exist', async ({ diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationQueryRunner.integration.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationQueryRunner.integration.spec.ts index 66d896b7e..9bff8e068 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationQueryRunner.integration.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/annotations/annotationQueryRunner.integration.spec.ts @@ -13,7 +13,7 @@ test('should run successfully if valid Redshift query was provided', async ({ const ds = await readProvisionedDataSource({ fileName: 'redshift.yaml' }); await annotationEditPage.datasource.set(ds.name); await page.waitForFunction(() => (window as any).monaco); - await annotationEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await annotationEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText('SELECT starttime, eventname FROM event ORDER BY eventname ASC LIMIT 5 '); await expect(annotationEditPage.runQuery()).toBeOK(); await expect(page.getByText('.38 Special')).toBeTruthy(); diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.async.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.async.spec.ts index c63d225e7..3a7f69208 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.async.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.async.spec.ts @@ -27,7 +27,7 @@ test('async query data handler should return a `finished` status', async ({ await panelEditPage.datasource.set(ds.name); await panelEditPage.timeRange.set({ from: '2020-01-31', to: '2020-02-20' }); await page.waitForFunction(() => (window as any).monaco); - await panelEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await panelEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText('select * from long_format_example limit 100'); await expect( panelEditPage.refreshPanel({ diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.sync.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.sync.spec.ts index 806bb28bb..ee70feef1 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.sync.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/feature-toggles/queryEditor.sync.spec.ts @@ -12,7 +12,7 @@ test('standard query data handler should only be called once', async ({ await panelEditPage.datasource.set(ds.name); await panelEditPage.timeRange.set({ from: '2020-01-31', to: '2020-02-20' }); await page.waitForFunction(() => (window as any).monaco); - await panelEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await panelEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText('select * from long_format_example limit 100'); let calledTimes = 0; diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableEditor.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableEditor.spec.ts index d6cae2675..4de13c4a5 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableEditor.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableEditor.spec.ts @@ -12,8 +12,8 @@ test('should load resources and display them as options when clicking on an inpu await variableEditPage.setVariableType('Query'); await variableEditPage.datasource.set(ds.name); await page.getByLabel('Schema').click(); - await expect(variableEditPage.getByTestIdOrAriaLabel('Select option')).toContainText(REDSHIFT_SCHEMAS); + await expect(variableEditPage.getByGrafanaSelector('Select option')).toContainText(REDSHIFT_SCHEMAS); await page.keyboard.press('Enter'); await page.getByLabel('Table').click(); - await expect(variableEditPage.getByTestIdOrAriaLabel('Select option')).toContainText(REDSHIFT_TABLES); + await expect(variableEditPage.getByGrafanaSelector('Select option')).toContainText(REDSHIFT_TABLES); }); diff --git a/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableQueryRunner.integration.spec.ts b/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableQueryRunner.integration.spec.ts index f3f53eafb..1c09cc1a7 100644 --- a/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableQueryRunner.integration.spec.ts +++ b/packages/plugin-e2e/tests/as-admin-user/datasource/variables/customVariableQueryRunner.integration.spec.ts @@ -10,7 +10,7 @@ test('custom variable editor query runner should return data when query is valid await variableEditPage.setVariableType('Query'); await variableEditPage.datasource.set(ds.name); await page.waitForFunction(() => (window as any).monaco); - await variableEditPage.getByTestIdOrAriaLabel(selectors.components.CodeEditor.container).click(); + await variableEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); await page.keyboard.insertText('select distinct(environment) from long_format_example'); const queryDataRequest = variableEditPage.waitForQueryDataRequest(); await variableEditPage.runQuery();