@grafana/plugin-e2e 3.5.1 → 3.6.0-canary.2586.24779924064.0

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.
package/dist/index.d.ts CHANGED
@@ -193,6 +193,10 @@ declare class Panel extends GrafanaPage {
193
193
  clickOnMenuItem(item: string, options?: {
194
194
  parentItem?: string;
195
195
  }): Promise<void>;
196
+ /**
197
+ * Scrolls the panel into the viewport, triggering its query if not yet started.
198
+ */
199
+ scrollIntoView(): Promise<void>;
196
200
  /**
197
201
  * Returns the locator for the panel error (if any)
198
202
  */
@@ -342,11 +346,31 @@ declare class DashboardPage extends GrafanaPage {
342
346
  readonly dashboard?: DashboardPageArgs | undefined;
343
347
  dataSourcePicker: any;
344
348
  timeRange: TimeRange;
349
+ private pendingQueryCount;
350
+ private hasSeenQuery;
345
351
  constructor(ctx: PluginTestCtx, dashboard?: DashboardPageArgs | undefined);
346
352
  /**
347
353
  * Navigates to the dashboard page. If a dashboard uid was not provided, it's assumed that it's a new dashboard.
348
354
  */
349
355
  goto(options?: NavigateOptions): Promise<void>;
356
+ /**
357
+ * Scrolls each panel container into view so that below-fold panels have their queries triggered.
358
+ * Targets .react-grid-item containers (always in the DOM, even before VizPanel renders) rather
359
+ * than panel title/content elements which only exist after lazy rendering. Playwright's native
360
+ * scrollIntoViewIfNeeded finds the correct scroll container automatically across Grafana versions.
361
+ */
362
+ private scrollToRevealAllPanels;
363
+ /**
364
+ * Waits until all initiated panel queries have received responses.
365
+ *
366
+ * By default only waits for queries already triggered (panels in the viewport at navigation
367
+ * time or explicitly scrolled into view). Pass `scrollAll: true` to first scroll the full
368
+ * dashboard so that below-fold panels are also triggered before waiting.
369
+ */
370
+ waitForPanelsQueriesToComplete({ timeout, scrollAll, }?: {
371
+ timeout?: number;
372
+ scrollAll?: boolean;
373
+ }): Promise<void>;
350
374
  /**
351
375
  * Navigates to the panel edit page for the given panel id
352
376
  *
@@ -1384,6 +1408,10 @@ declare const expect: _playwright_test.Expect<{
1384
1408
  toHaveChecked: typeof toHaveChecked;
1385
1409
  toHaveColor: typeof toHaveColor;
1386
1410
  toHaveNoA11yViolations: typeof toHaveNoA11yViolations;
1411
+ toHavePanelErrors: (dashboard: DashboardPage, expectedCount?: number) => Promise<{
1412
+ pass: boolean;
1413
+ message: () => string;
1414
+ }>;
1387
1415
  }>;
1388
1416
 
1389
1417
  declare global {
@@ -1456,6 +1484,12 @@ declare global {
1456
1484
  * You can use this in conjunction with the .toHaveNoA11yViolations matcher to assert that there are no accessibility violations on the page.
1457
1485
  */
1458
1486
  toHaveNoA11yViolations(results: AxeResults, options?: A11yViolationsOptions): Promise<R>;
1487
+ /**
1488
+ * Asserts that a dashboard has panel errors. Omit `count` to assert at least one error.
1489
+ * Pass `count` to assert exactly that many panels with errors.
1490
+ * Use `.not.toHavePanelErrors()` to assert no panel errors.
1491
+ */
1492
+ toHavePanelErrors(this: Matchers<unknown, DashboardPage>, count?: number): Promise<R>;
1459
1493
  }
1460
1494
  }
1461
1495
  }
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ var toBeChecked = require('./matchers/toBeChecked.js');
42
42
  var toHaveNoA11yViolations = require('./matchers/toHaveNoA11yViolations.js');
43
43
  var toHaveChecked = require('./matchers/toHaveChecked.js');
44
44
  var toHaveColor = require('./matchers/toHaveColor.js');
45
+ var toHavePanelErrors = require('./matchers/toHavePanelErrors.js');
45
46
  var DataSourcePicker = require('./models/components/DataSourcePicker.js');
46
47
  var Panel = require('./models/components/Panel.js');
47
48
  var TimeRange = require('./models/components/TimeRange.js');
@@ -104,7 +105,8 @@ const expect = test$1.expect.extend({
104
105
  toBeChecked: toBeChecked.toBeChecked,
105
106
  toHaveChecked: toHaveChecked.toHaveChecked,
106
107
  toHaveColor: toHaveColor.toHaveColor,
107
- toHaveNoA11yViolations: toHaveNoA11yViolations.toHaveNoA11yViolations
108
+ toHaveNoA11yViolations: toHaveNoA11yViolations.toHaveNoA11yViolations,
109
+ toHavePanelErrors: toHavePanelErrors.toHavePanelErrors
108
110
  });
109
111
 
110
112
  Object.defineProperty(exports, "selectors", {
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const toHavePanelErrors = async (dashboard, expectedCount) => {
4
+ const errorLocator = dashboard.getByGrafanaSelector(dashboard.ctx.selectors.components.Panels.Panel.status("error"));
5
+ const count = await errorLocator.count();
6
+ const pass = expectedCount === void 0 ? count >= 1 : count === expectedCount;
7
+ return {
8
+ pass,
9
+ message: () => expectedCount === void 0 ? `Expected at least 1 panel with errors but found ${count}` : `Expected exactly ${expectedCount} panel error(s) but found ${count}`
10
+ };
11
+ };
12
+
13
+ exports.toHavePanelErrors = toHavePanelErrors;
@@ -75,6 +75,12 @@ class Panel extends GrafanaPage.GrafanaPage {
75
75
  options?.parentItem && await parentMenuItem.hover();
76
76
  await menuItem.click();
77
77
  }
78
+ /**
79
+ * Scrolls the panel into the viewport, triggering its query if not yet started.
80
+ */
81
+ async scrollIntoView() {
82
+ await this.locator.scrollIntoViewIfNeeded();
83
+ }
78
84
  /**
79
85
  * Returns the locator for the panel error (if any)
80
86
  */
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var semver = require('semver');
4
+ var test = require('@playwright/test');
4
5
  var DataSourcePicker = require('../components/DataSourcePicker.js');
5
6
  var GrafanaPage = require('./GrafanaPage.js');
6
7
  var PanelEditPage = require('./PanelEditPage.js');
@@ -38,6 +39,8 @@ class DashboardPage extends GrafanaPage.GrafanaPage {
38
39
  this.dashboard = dashboard;
39
40
  __publicField(this, "dataSourcePicker");
40
41
  __publicField(this, "timeRange");
42
+ __publicField(this, "pendingQueryCount", 0);
43
+ __publicField(this, "hasSeenQuery", false);
41
44
  this.dataSourcePicker = new DataSourcePicker.DataSourcePicker(ctx);
42
45
  this.timeRange = new TimeRange.TimeRange(ctx);
43
46
  }
@@ -45,6 +48,17 @@ class DashboardPage extends GrafanaPage.GrafanaPage {
45
48
  * Navigates to the dashboard page. If a dashboard uid was not provided, it's assumed that it's a new dashboard.
46
49
  */
47
50
  async goto(options = {}) {
51
+ this.ctx.page.on("request", (req) => {
52
+ if (req.url().includes(this.ctx.selectors.apis.DataSource.query)) {
53
+ this.pendingQueryCount++;
54
+ this.hasSeenQuery = true;
55
+ }
56
+ });
57
+ this.ctx.page.on("response", (res) => {
58
+ if (res.url().includes(this.ctx.selectors.apis.DataSource.query)) {
59
+ this.pendingQueryCount = Math.max(0, this.pendingQueryCount - 1);
60
+ }
61
+ });
48
62
  let url = this.dashboard?.uid ? this.ctx.selectors.pages.Dashboard.url(this.dashboard.uid) : this.ctx.selectors.pages.AddDashboard.url;
49
63
  if (this.dashboard?.timeRange) {
50
64
  options.queryParams = options?.queryParams ?? new URLSearchParams();
@@ -53,6 +67,39 @@ class DashboardPage extends GrafanaPage.GrafanaPage {
53
67
  }
54
68
  return super.navigate(url, options);
55
69
  }
70
+ /**
71
+ * Scrolls each panel container into view so that below-fold panels have their queries triggered.
72
+ * Targets .react-grid-item containers (always in the DOM, even before VizPanel renders) rather
73
+ * than panel title/content elements which only exist after lazy rendering. Playwright's native
74
+ * scrollIntoViewIfNeeded finds the correct scroll container automatically across Grafana versions.
75
+ */
76
+ async scrollToRevealAllPanels() {
77
+ const containers = this.ctx.page.locator(".react-grid-item");
78
+ const count = await containers.count();
79
+ for (let i = 0; i < count; i++) {
80
+ await containers.nth(i).scrollIntoViewIfNeeded();
81
+ await this.ctx.page.waitForTimeout(500);
82
+ }
83
+ }
84
+ /**
85
+ * Waits until all initiated panel queries have received responses.
86
+ *
87
+ * By default only waits for queries already triggered (panels in the viewport at navigation
88
+ * time or explicitly scrolled into view). Pass `scrollAll: true` to first scroll the full
89
+ * dashboard so that below-fold panels are also triggered before waiting.
90
+ */
91
+ async waitForPanelsQueriesToComplete({
92
+ timeout = 3e4,
93
+ scrollAll = false
94
+ } = {}) {
95
+ await test.expect.poll(() => this.hasSeenQuery, { timeout: 2e3 }).toBe(true).catch(() => {
96
+ });
97
+ await test.expect.poll(() => this.pendingQueryCount === 0, { timeout }).toBe(true);
98
+ if (scrollAll) {
99
+ await this.scrollToRevealAllPanels();
100
+ await test.expect.poll(() => this.pendingQueryCount === 0, { timeout }).toBe(true);
101
+ }
102
+ }
56
103
  /**
57
104
  * Navigates to the panel edit page for the given panel id
58
105
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/plugin-e2e",
3
- "version": "3.5.1",
3
+ "version": "3.6.0-canary.2586.24779924064.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -54,5 +54,5 @@
54
54
  "uuid": "^13.0.0",
55
55
  "yaml": "^2.3.4"
56
56
  },
57
- "gitHead": "bbe7431074aa667f5da9880f76fba803ba1b3f73"
57
+ "gitHead": "032d8634c8d6292b61e0cb3f0bb45c2d9bc71926"
58
58
  }