@grafana/plugin-e2e 0.25.1 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,7 @@ export type APIs = {
11
11
  query: string;
12
12
  health: (uid: string, id: string) => string;
13
13
  datasourceByUID: (uid: string) => string;
14
- proxy: (uid: string) => string;
14
+ proxy: (uid: string, id: string) => string;
15
15
  };
16
16
  Dashboard: {
17
17
  delete: (uid: string) => string;
@@ -175,10 +175,12 @@ export type Pages = {
175
175
  newButton: string;
176
176
  addVariableCTAV2: (variableName: string) => string;
177
177
  addVariableCTAV2Item: string;
178
+ table: string;
178
179
  };
179
180
  Edit: {
180
181
  url: (dashboardUid: string, editIndex: string) => string;
181
182
  General: {
183
+ selectionOptionsIncludeAllSwitch: string;
182
184
  generalTypeSelectV2: string;
183
185
  previewOfValuesOption: string;
184
186
  submitButton: string;
@@ -21,7 +21,8 @@ export declare const versionedAPIs: {
21
21
  "8.0.0": (uid: string) => string;
22
22
  };
23
23
  proxy: {
24
- "8.0.0": (uid: string) => string;
24
+ '9.4.0': (uid: string, _: string) => string;
25
+ "8.0.0": (_: string, id: string) => string;
25
26
  };
26
27
  };
27
28
  Dashboard: {
@@ -25,7 +25,8 @@ exports.versionedAPIs = {
25
25
  [constants_1.MIN_GRAFANA_VERSION]: (uid) => `/api/datasources/uid/${uid}`,
26
26
  },
27
27
  proxy: {
28
- [constants_1.MIN_GRAFANA_VERSION]: (uid) => `api/datasources/proxy/uid/${uid}`,
28
+ '9.4.0': (uid, _) => `api/datasources/proxy/uid/${uid}`,
29
+ [constants_1.MIN_GRAFANA_VERSION]: (_, id) => `/api/datasources/proxy/${id}`,
29
30
  },
30
31
  },
31
32
  Dashboard: {
@@ -112,6 +112,9 @@ export declare const versionedPages: {
112
112
  '10.4.0': string;
113
113
  "8.0.0": string;
114
114
  };
115
+ selectionOptionsIncludeAllSwitch: {
116
+ "8.0.0": string;
117
+ };
115
118
  };
116
119
  };
117
120
  };
@@ -118,6 +118,9 @@ exports.versionedPages = {
118
118
  '10.4.0': 'data-testid Variable editor Run Query button',
119
119
  [constants_1.MIN_GRAFANA_VERSION]: 'Variable editor Submit button',
120
120
  },
121
+ selectionOptionsIncludeAllSwitch: {
122
+ [constants_1.MIN_GRAFANA_VERSION]: 'Variable editor Form IncludeAll switch',
123
+ },
121
124
  },
122
125
  },
123
126
  },
package/dist/index.js CHANGED
@@ -110,7 +110,7 @@ exports.expect = test_1.expect.extend({
110
110
  });
111
111
  /** Register a custom selector engine that resolves locators for Grafana E2E selectors
112
112
  *
113
- * The same functionality is available in the {@link GrafanaPage.getByTestIdOrAriaLabel} method. However,
113
+ * The same functionality is available in the {@link GrafanaPage.getByGrafanaSelector} method. However,
114
114
  * by registering the selector engine, one can resolve locators by Grafana E2E selectors also within a locator.
115
115
  *
116
116
  * Example:
@@ -8,7 +8,7 @@ const toDisplayPreviews = async (variableEditPage, previewTexts, options) => {
8
8
  let actual;
9
9
  let message = `To find preview of values: ${previewTexts.join(', ')}}`;
10
10
  try {
11
- await (0, test_1.expect)(variableEditPage.getByTestIdOrAriaLabel(variableEditPage.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption)).toContainText(previewTexts, options);
11
+ await (0, test_1.expect)(variableEditPage.getByGrafanaSelector(variableEditPage.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption)).toContainText(previewTexts, options);
12
12
  return {
13
13
  pass: true,
14
14
  actual: false,
@@ -8,7 +8,7 @@ const toHaveAlert = async (grafanaPage, severity, options) => {
8
8
  let message = `An alert of variant ${severity} to be displayed on the page`;
9
9
  try {
10
10
  const filteredAlerts = grafanaPage
11
- .getByTestIdOrAriaLabel(grafanaPage.ctx.selectors.components.Alert.alertV2(severity))
11
+ .getByGrafanaSelector(grafanaPage.ctx.selectors.components.Alert.alertV2(severity))
12
12
  .filter({
13
13
  hasText: options?.hasText,
14
14
  hasNotText: options?.hasNotText,
@@ -10,7 +10,7 @@ class DataSourcePicker extends GrafanaPage_1.GrafanaPage {
10
10
  * Sets the data source picker to the provided name
11
11
  */
12
12
  async set(name) {
13
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.DataSourcePicker.container)
13
+ await this.getByGrafanaSelector(this.ctx.selectors.components.DataSourcePicker.container)
14
14
  .locator('input')
15
15
  .fill(name);
16
16
  // this is a hack to get the selection to work in 10.ish versions of Grafana.
@@ -64,7 +64,7 @@ class Panel extends GrafanaPage_1.GrafanaPage {
64
64
  if (semver.lte(this.ctx.grafanaVersion, '9.4.3')) {
65
65
  selector = this.ctx.selectors.components.Panels.Panel.headerCornerInfo(ERROR_STATUS);
66
66
  }
67
- return this.getByTestIdOrAriaLabel(selector, {
67
+ return this.getByGrafanaSelector(selector, {
68
68
  root: this.locator,
69
69
  });
70
70
  }
@@ -36,7 +36,7 @@ class TimeRange extends GrafanaPage_1.GrafanaPage {
36
36
  async set({ from, to, zone }) {
37
37
  const { TimeZonePicker, TimePicker } = this.ctx.selectors.components;
38
38
  try {
39
- await this.getByTestIdOrAriaLabel(TimePicker.openButton).click();
39
+ await this.getByGrafanaSelector(TimePicker.openButton).click();
40
40
  }
41
41
  catch (e) {
42
42
  // seems like in older versions of Grafana the time picker markup is rendered twice
@@ -44,19 +44,19 @@ class TimeRange extends GrafanaPage_1.GrafanaPage {
44
44
  }
45
45
  if (zone) {
46
46
  const changeTimeSettingsButton = semver.gte(this.ctx.grafanaVersion, '11.0.0')
47
- ? this.getByTestIdOrAriaLabel(TimeZonePicker.changeTimeSettingsButton)
47
+ ? this.getByGrafanaSelector(TimeZonePicker.changeTimeSettingsButton)
48
48
  : this.ctx.page.getByRole('button', { name: 'Change time settings' });
49
49
  await changeTimeSettingsButton.click();
50
- await this.getByTestIdOrAriaLabel(TimeZonePicker.containerV2).fill(zone);
50
+ await this.getByGrafanaSelector(TimeZonePicker.containerV2).fill(zone);
51
51
  }
52
- await this.getByTestIdOrAriaLabel(TimePicker.absoluteTimeRangeTitle).click();
53
- const fromField = await this.getByTestIdOrAriaLabel(TimePicker.fromField);
52
+ await this.getByGrafanaSelector(TimePicker.absoluteTimeRangeTitle).click();
53
+ const fromField = await this.getByGrafanaSelector(TimePicker.fromField);
54
54
  await fromField.clear();
55
55
  await fromField.fill(from);
56
- const toField = await this.getByTestIdOrAriaLabel(TimePicker.toField);
56
+ const toField = await this.getByGrafanaSelector(TimePicker.toField);
57
57
  await toField.clear();
58
58
  await toField.fill(to);
59
- await this.getByTestIdOrAriaLabel(TimePicker.applyTimeRange).click();
59
+ await this.getByGrafanaSelector(TimePicker.applyTimeRange).click();
60
60
  }
61
61
  }
62
62
  exports.TimeRange = TimeRange;
@@ -45,7 +45,14 @@ class AnnotationEditPage extends GrafanaPage_1.GrafanaPage {
45
45
  const url = this.args.dashboard?.uid
46
46
  ? Dashboard.Settings.Annotations.Edit.url(this.args.dashboard.uid, this.args.id)
47
47
  : AddDashboard.Settings.Annotations.Edit.url(this.args.id);
48
- return super.navigate(url, options);
48
+ await super.navigate(url, options);
49
+ // In versions before 9.2.0, the annotation index is not part of the URL so there's no way to navigate to it directly.
50
+ // Instead, we have to click the nth row in the variable list to navigate to the edit page for a given annotation index.
51
+ if (semver.lt(this.ctx.grafanaVersion, '9.2.0') && this.args.id) {
52
+ const list = this.ctx.page.locator('tbody tr');
53
+ const variables = await list.all();
54
+ await variables[Number(this.args.id)].click();
55
+ }
49
56
  }
50
57
  /**
51
58
  * Executes the annotation query defined in the annotation page and returns the response promise
@@ -54,7 +61,7 @@ class AnnotationEditPage extends GrafanaPage_1.GrafanaPage {
54
61
  async runQuery(options) {
55
62
  const responsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes(this.ctx.selectors.apis.DataSource.query), options);
56
63
  const testButton = semver.gte(this.ctx.grafanaVersion, '11.0.0')
57
- ? this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Annotations.editor.testButton)
64
+ ? this.getByGrafanaSelector(this.ctx.selectors.components.Annotations.editor.testButton)
58
65
  : this.ctx.page.getByRole('button', { name: 'TEST' });
59
66
  await testButton.click();
60
67
  return responsePromise;
@@ -53,16 +53,16 @@ class AnnotationPage extends GrafanaPage_1.GrafanaPage {
53
53
  if (!this.dashboard?.uid) {
54
54
  //the dashboard doesn't have any annotations yet (except for the built-in one)
55
55
  if (semver.gte(this.ctx.grafanaVersion, '8.3.0')) {
56
- await this.getByTestIdOrAriaLabel(addAnnotationCTAV2).click();
56
+ await this.getByGrafanaSelector(addAnnotationCTAV2).click();
57
57
  }
58
58
  else {
59
- await this.getByTestIdOrAriaLabel(addAnnotationCTA).click();
59
+ await this.getByGrafanaSelector(addAnnotationCTA).click();
60
60
  }
61
61
  }
62
62
  else {
63
63
  //the dashboard already has annotations
64
64
  const newQueryButton = semver.gte(this.ctx.grafanaVersion, '11.0.0')
65
- ? this.getByTestIdOrAriaLabel(addAnnotationCTAV2)
65
+ ? this.getByGrafanaSelector(addAnnotationCTAV2)
66
66
  : this.ctx.page.getByRole('button', { name: 'New query' });
67
67
  await newQueryButton.click();
68
68
  }
@@ -75,7 +75,7 @@ class DashboardPage extends GrafanaPage_1.GrafanaPage {
75
75
  * await expect(panel.fieldNames).toContainText(['time', 'temperature']);
76
76
  */
77
77
  getPanelByTitle(title) {
78
- let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(title), {
78
+ let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(title), {
79
79
  startsWith: true,
80
80
  });
81
81
  // in older versions, the panel selector is added to a child element, so we need to go up two levels to get the wrapper
@@ -101,11 +101,11 @@ class DashboardPage extends GrafanaPage_1.GrafanaPage {
101
101
  async addPanel() {
102
102
  const { components, pages } = this.ctx.selectors;
103
103
  if (semver.gte(this.ctx.grafanaVersion, '10.0.0')) {
104
- await this.getByTestIdOrAriaLabel(components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle)).click();
105
- await this.getByTestIdOrAriaLabel(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click();
104
+ await this.getByGrafanaSelector(components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle)).click();
105
+ await this.getByGrafanaSelector(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click();
106
106
  }
107
107
  else {
108
- await this.getByTestIdOrAriaLabel(pages.AddDashboard.addNewPanel).click();
108
+ await this.getByGrafanaSelector(pages.AddDashboard.addNewPanel).click();
109
109
  }
110
110
  const panelId = await this.ctx.page.evaluate(() => {
111
111
  const urlParams = new URLSearchParams(window.location.search);
@@ -39,7 +39,7 @@ class DataSourceConfigPage extends GrafanaPage_1.GrafanaPage {
39
39
  const saveResponsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes(datasourceByUID(this.datasource.uid)));
40
40
  const healthPath = options?.path ?? health(this.datasource.uid, this.datasource.id.toString());
41
41
  const healthResponsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes(healthPath));
42
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.DataSource.saveAndTest).click();
42
+ await this.getByGrafanaSelector(this.ctx.selectors.pages.DataSource.saveAndTest).click();
43
43
  return saveResponsePromise.then(() => healthResponsePromise);
44
44
  }
45
45
  }
@@ -1,7 +1,30 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.ExplorePage = void 0;
4
- const semver = require('semver');
27
+ const semver = __importStar(require("semver"));
5
28
  const DataSourcePicker_1 = require("../components/DataSourcePicker");
6
29
  const GrafanaPage_1 = require("./GrafanaPage");
7
30
  const TimeRange_1 = require("../components/TimeRange");
@@ -26,7 +49,7 @@ class ExplorePage extends GrafanaPage_1.GrafanaPage {
26
49
  }
27
50
  getPanelLocators(suffix, text) {
28
51
  const page = this.ctx.page;
29
- let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(suffix), {
52
+ let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(suffix), {
30
53
  startsWith: true,
31
54
  });
32
55
  // having to use these selectors is unfortunate, but the Explore page did not use data-testid on the panels before Grafana 10.
@@ -48,8 +71,8 @@ class ExplorePage extends GrafanaPage_1.GrafanaPage {
48
71
  * Returns the locator for the query editor row with the given refId
49
72
  */
50
73
  getQueryEditorRow(refId) {
51
- return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRows.rows).filter({
52
- has: this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRow.title(refId)),
74
+ return this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRows.rows).filter({
75
+ has: this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRow.title(refId)),
53
76
  });
54
77
  }
55
78
  /**
@@ -59,14 +82,14 @@ class ExplorePage extends GrafanaPage_1.GrafanaPage {
59
82
  const components = this.ctx.selectors.components;
60
83
  const responsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes(this.ctx.selectors.apis.DataSource.query), options);
61
84
  try {
62
- await this.getByTestIdOrAriaLabel(components.RefreshPicker.runButtonV2).click({
85
+ await this.getByGrafanaSelector(components.RefreshPicker.runButtonV2).click({
63
86
  timeout: 1000,
64
87
  });
65
88
  }
66
89
  catch (_) {
67
90
  // handle the case when the run button is hidden behind the "Show more items" button
68
- await this.getByTestIdOrAriaLabel(components.PageToolbar.item(components.PageToolbar.shotMoreItems)).click();
69
- await this.getByTestIdOrAriaLabel(components.RefreshPicker.runButtonV2).last().click();
91
+ await this.getByGrafanaSelector(components.PageToolbar.item(components.PageToolbar.shotMoreItems)).click();
92
+ await this.getByGrafanaSelector(components.RefreshPicker.runButtonV2).last().click();
70
93
  }
71
94
  return responsePromise;
72
95
  }
@@ -1,5 +1,5 @@
1
1
  import { Locator, Request, Response } from '@playwright/test';
2
- import { GetByTestIdOrAriaLabelOptions, NavigateOptions, PluginTestCtx } from '../../types';
2
+ import { getByGrafanaSelectorOptions, NavigateOptions, PluginTestCtx } from '../../types';
3
3
  /**
4
4
  * Base class for all Grafana pages.
5
5
  *
@@ -10,11 +10,10 @@ export declare abstract class GrafanaPage {
10
10
  constructor(ctx: PluginTestCtx);
11
11
  protected navigate(url: string, options?: NavigateOptions): Promise<void>;
12
12
  /**
13
- * Get a locator for a Grafana element by data-testid or aria-label
14
- * @param selector the data-testid or aria-label of the element
15
- * @param root optional root locator to search within. If no locator is provided, the page will be used
13
+ * 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.
14
+ * 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.
16
15
  */
17
- getByTestIdOrAriaLabel(selector: string, options?: GetByTestIdOrAriaLabelOptions): Locator;
16
+ getByGrafanaSelector(selector: string, options?: getByGrafanaSelectorOptions): Locator;
18
17
  /**
19
18
  * Mocks the response of the datasource query call
20
19
  * @param json the json response to return
@@ -21,11 +21,10 @@ class GrafanaPage {
21
21
  });
22
22
  }
23
23
  /**
24
- * Get a locator for a Grafana element by data-testid or aria-label
25
- * @param selector the data-testid or aria-label of the element
26
- * @param root optional root locator to search within. If no locator is provided, the page will be used
24
+ * 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.
25
+ * 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.
27
26
  */
28
- getByTestIdOrAriaLabel(selector, options) {
27
+ getByGrafanaSelector(selector, options) {
29
28
  const startsWith = options?.startsWith ? '^' : '';
30
29
  if (selector.startsWith('data-testid')) {
31
30
  return (options?.root || this.ctx.page).locator(`[data-testid${startsWith}="${selector}"]`);
@@ -47,7 +47,7 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
47
47
  }
48
48
  getPanelLocator() {
49
49
  // only one panel is allowed in the panel edit page, so we don't need to use panel title to locate it
50
- const locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(''), {
50
+ const locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(''), {
51
51
  startsWith: true,
52
52
  });
53
53
  // in older versions, the panel selector is added to a child element, so we need to go up two levels to get the wrapper
@@ -70,7 +70,7 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
70
70
  }
71
71
  async toggleTableView() {
72
72
  await (0, utils_1.radioButtonSetChecked)(this.ctx.page, 'Table view', true);
73
- let locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.toggleTableViewPanel(''));
73
+ let locator = this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.toggleTableViewPanel(''));
74
74
  if (semver.lt(this.ctx.grafanaVersion, '10.4.0')) {
75
75
  locator = this.ctx.page.getByRole('table');
76
76
  }
@@ -78,7 +78,7 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
78
78
  }
79
79
  async untoggleTableView() {
80
80
  await (0, utils_1.radioButtonSetChecked)(this.ctx.page, 'Table view', false);
81
- this.panel = new Panel_1.Panel(this.ctx, this.getByTestIdOrAriaLabel(this.ctx.selectors.components.Panels.Panel.title(''), { startsWith: true }));
81
+ this.panel = new Panel_1.Panel(this.ctx, this.getByGrafanaSelector(this.ctx.selectors.components.Panels.Panel.title(''), { startsWith: true }));
82
82
  }
83
83
  /**
84
84
  * Sets the title of the panel. This method will open the panel options, set the title and close the panel options.
@@ -88,8 +88,8 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
88
88
  const { OptionsGroup, PanelEditor } = this.ctx.selectors.components;
89
89
  await this.collapseSection(OptionsGroup.groupTitle);
90
90
  const vizInput = semver.gte(this.ctx.grafanaVersion, '11.0.0')
91
- ? this.getByTestIdOrAriaLabel(PanelEditor.OptionsPane.fieldInput(TITLE))
92
- : this.getByTestIdOrAriaLabel(OptionsGroup.group(OptionsGroup.groupTitle)).locator('input').first();
91
+ ? this.getByGrafanaSelector(PanelEditor.OptionsPane.fieldInput(TITLE))
92
+ : this.getByGrafanaSelector(OptionsGroup.group(OptionsGroup.groupTitle)).locator('input').first();
93
93
  await vizInput.fill(titleText);
94
94
  await this.ctx.page.keyboard.press('Tab');
95
95
  }
@@ -98,22 +98,22 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
98
98
  */
99
99
  async setVisualization(visualization) {
100
100
  // toggle options pane if panel edit is not visible
101
- const showPanelEditElement = this.getByTestIdOrAriaLabel('Show options pane');
101
+ const showPanelEditElement = this.getByGrafanaSelector('Show options pane');
102
102
  const showPanelEditElementCount = await showPanelEditElement.count();
103
103
  if (showPanelEditElementCount > 0) {
104
104
  await showPanelEditElement.click();
105
105
  }
106
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker).click();
107
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PluginVisualization.item(visualization)).click();
108
- await (0, test_1.expect)(this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker), `Could not set visualization to ${visualization}. Ensure the panel is installed.`).toHaveText(visualization);
106
+ await this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker).click();
107
+ await this.getByGrafanaSelector(this.ctx.selectors.components.PluginVisualization.item(visualization)).click();
108
+ await (0, test_1.expect)(this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker), `Could not set visualization to ${visualization}. Ensure the panel is installed.`).toHaveText(visualization);
109
109
  }
110
110
  /**
111
111
  * Expands the section for the given category name. If the section is already expanded, this method does nothing.
112
112
  */
113
113
  async collapseSection(categoryName) {
114
- const section = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.OptionsGroup.group(categoryName));
114
+ const section = this.getByGrafanaSelector(this.ctx.selectors.components.OptionsGroup.group(categoryName));
115
115
  await (0, test_1.expect)(section, `Could not find any section for category: ${categoryName}`).toBeVisible();
116
- const sectionToggle = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.OptionsGroup.toggle(categoryName));
116
+ const sectionToggle = this.getByGrafanaSelector(this.ctx.selectors.components.OptionsGroup.toggle(categoryName));
117
117
  const expandedAttr = (await sectionToggle.getAttribute('aria-expanded')) ?? '';
118
118
  if (/false/.test(expandedAttr)) {
119
119
  await section.click();
@@ -123,7 +123,7 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
123
123
  * Returns the name of the visualization currently selected in the panel editor
124
124
  */
125
125
  getVisualizationName() {
126
- return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.toggleVizPicker);
126
+ return this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.toggleVizPicker);
127
127
  }
128
128
  /**
129
129
  * Clicks the "Apply" button in the panel editor
@@ -135,8 +135,8 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
135
135
  * Returns the locator for the query editor row with the given refId
136
136
  */
137
137
  getQueryEditorRow(refId) {
138
- return this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRows.rows).filter({
139
- has: this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRow.title(refId)),
138
+ return this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRows.rows).filter({
139
+ has: this.getByGrafanaSelector(this.ctx.selectors.components.QueryEditorRow.title(refId)),
140
140
  });
141
141
  }
142
142
  /**
@@ -155,7 +155,7 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
155
155
  const defaultPredicate = (resp) => resp.url().includes(this.ctx.selectors.apis.DataSource.query);
156
156
  const responsePromise = this.ctx.page.waitForResponse(options?.waitForResponsePredicateCallback ?? defaultPredicate, options);
157
157
  // in older versions of grafana, the refresh button is rendered twice. this is a workaround to click the correct one
158
- const refreshPanelButton = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PanelEditor.General.content).locator(`selector=${this.ctx.selectors.components.RefreshPicker.runButtonV2}`);
158
+ const refreshPanelButton = this.getByGrafanaSelector(this.ctx.selectors.components.PanelEditor.General.content).locator(`selector=${this.ctx.selectors.components.RefreshPicker.runButtonV2}`);
159
159
  await refreshPanelButton.click();
160
160
  return responsePromise;
161
161
  }
@@ -1,7 +1,30 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.VariableEditPage = void 0;
4
- const gte = require('semver/functions/gte');
27
+ const semver = __importStar(require("semver"));
5
28
  const DataSourcePicker_1 = require("../components/DataSourcePicker");
6
29
  const GrafanaPage_1 = require("./GrafanaPage");
7
30
  class VariableEditPage extends GrafanaPage_1.GrafanaPage {
@@ -23,17 +46,24 @@ class VariableEditPage extends GrafanaPage_1.GrafanaPage {
23
46
  ? Dashboard.Settings.Variables.Edit.url(this.args.dashboard.uid, this.args.id)
24
47
  : AddDashboard.Settings.Variables.Edit.url(this.args.id);
25
48
  await super.navigate(url, options);
49
+ // In versions before 9.2.0, the variable index is not part of the URL so there's no way to navigate to it directly.
50
+ // Instead, we have to click the nth row in the variable list to navigate to the edit page for a given variable index.
51
+ if (semver.lt(this.ctx.grafanaVersion, '9.2.0') && this.args.id) {
52
+ const list = this.getByGrafanaSelector(this.ctx.selectors.pages.Dashboard.Settings.Variables.List.table).locator('tbody tr');
53
+ const variables = await list.all();
54
+ await variables[Number(this.args.id)].click();
55
+ }
26
56
  }
27
57
  /**
28
58
  * Sets the type of variable in the 'Variable type' dropdown to the given type
29
59
  */
30
60
  async setVariableType(type) {
31
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2)
61
+ await this.getByGrafanaSelector(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2)
32
62
  .locator('input')
33
63
  .fill(type);
34
64
  await this.ctx.page.keyboard.press('ArrowDown');
35
65
  await this.ctx.page.keyboard.press('Enter');
36
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2).scrollIntoViewIfNeeded();
66
+ await this.getByGrafanaSelector(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2).scrollIntoViewIfNeeded();
37
67
  }
38
68
  /**
39
69
  * Triggers the variable query to run. Note that unlike {@link PanelEditPage.refreshPanel}, this method doesn't
@@ -44,12 +74,16 @@ class VariableEditPage extends GrafanaPage_1.GrafanaPage {
44
74
  */
45
75
  async runQuery() {
46
76
  // in 9.2.0, the submit button got a new purpose. it no longer submits the form, but instead runs the query
47
- if (gte(this.ctx.grafanaVersion, '9.2.0')) {
48
- await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton).click();
77
+ if (semver.gte(this.ctx.grafanaVersion, '9.2.0')) {
78
+ await this.getByGrafanaSelector(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton).click();
49
79
  }
50
80
  else {
51
- // in 9.1.3, the submit button submits the form
52
- await this.ctx.page.keyboard.press('Tab');
81
+ // in version before 9.2.0, there's no submit button, so instead we click the "Include all" button to trigger the query
82
+ const queryDataRequest = this.waitForQueryDataRequest();
83
+ const includeAllSwitch = this.getByGrafanaSelector(this.ctx.selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch).locator('..');
84
+ await includeAllSwitch.click();
85
+ await queryDataRequest;
86
+ await includeAllSwitch.click();
53
87
  }
54
88
  }
55
89
  }
@@ -27,10 +27,10 @@ class VariablePage extends GrafanaPage_1.GrafanaPage {
27
27
  async clickAddNew() {
28
28
  const { addVariableCTAV2, addVariableCTAV2Item, newButton } = this.ctx.selectors.pages.Dashboard.Settings.Variables.List;
29
29
  if (!this.dashboard?.uid) {
30
- await this.getByTestIdOrAriaLabel(addVariableCTAV2(addVariableCTAV2Item)).click();
30
+ await this.getByGrafanaSelector(addVariableCTAV2(addVariableCTAV2Item)).click();
31
31
  }
32
32
  else {
33
- await this.getByTestIdOrAriaLabel(newButton).click();
33
+ await this.getByGrafanaSelector(newButton).click();
34
34
  }
35
35
  const editIndex = await this.ctx.page.evaluate(() => {
36
36
  const urlParams = new URLSearchParams(window.location.search);
package/dist/types.d.ts CHANGED
@@ -418,7 +418,7 @@ export type NavigateOptions = {
418
418
  export type AppPageNavigateOptions = NavigateOptions & {
419
419
  path?: string;
420
420
  };
421
- export type GetByTestIdOrAriaLabelOptions = {
421
+ export type getByGrafanaSelectorOptions = {
422
422
  /**
423
423
  *Optional root locator to search within. If no locator is provided, the page will be used
424
424
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/plugin-e2e",
3
- "version": "0.25.1",
3
+ "version": "0.26.1",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -55,5 +55,5 @@
55
55
  "start": "cls || clear"
56
56
  }
57
57
  },
58
- "gitHead": "47290fa2f4c959794e3146240552b01905fbe7dd"
58
+ "gitHead": "e6b578f7f1dbd3d405ac150e71b625ed3db5c82b"
59
59
  }