E2E: Remove cypress dashboards-suite (#109038)

* add equivalent dashboard-time-zone test

* remove cypress dashboards-suite

* modify tests to work with schema-v2 + update workflow to run playwright instead

* fix package.json

* update CODEOWNERS

* fix start-server to include ARCH
This commit is contained in:
Ashley Harrison
2025-08-05 10:09:49 +01:00
committed by GitHub
parent db2ba4f7e2
commit 6408e3acaa
70 changed files with 464 additions and 3001 deletions
@@ -9,13 +9,13 @@ const NUM_NESTED_DASHBOARDS = 60;
test.use({
featureToggles: {
tableNextGen: true,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
// TODO change this test so it doesn't conflict with the existing dashboard browse test
// probably needs a separate user
test.describe.skip(
test.describe.fixme(
'Dashboard browse (nested)',
{
tag: ['@dashboards'],
@@ -107,7 +107,7 @@ test.describe.skip(
await expect(page.getByText('Nested folder 00')).toBeVisible();
// Get the table body container for scrolling
const tableBody = page.getByRole('grid');
const tableBody = page.getByTestId(selectors.pages.BrowseDashboards.table.body).locator('> div');
// Scroll the page and check visibility of next set of items
await tableBody.evaluate((el) => el.scrollTo(0, 2100));
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
import testDashboard from '../dashboards/TestDashboard.json';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Dashboard browse',
{
@@ -7,6 +7,7 @@ test.use({
scenes: true,
newDashboardSharingComponent: true,
sharingDashboardImage: true, // Enable the export image feature
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -1,5 +1,11 @@
import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Export as JSON',
{
@@ -1,5 +1,11 @@
import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Dashboard keybindings',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
import testDashboard from '../dashboards/DataLinkWithoutSlugTest.json';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Dashboard with data links that have no slug',
{
@@ -5,6 +5,7 @@ import testDashboard from '../dashboards/DashboardLiveTest.json';
test.use({
featureToggles: {
tableNextGen: true,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -3,6 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
newDashboardSharingComponent: false,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -3,6 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
newDashboardSharingComponent: false,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -4,6 +4,7 @@ test.use({
featureToggles: {
scenes: true,
newDashboardSharingComponent: true,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -4,6 +4,7 @@ test.use({
featureToggles: {
scenes: true,
newDashboardSharingComponent: true,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -6,6 +6,7 @@ test.use({
featureToggles: {
scenes: true,
newDashboardSharingComponent: true,
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -4,6 +4,9 @@ const DASHBOARD_UID = 'HYaGDGIMk';
test.use({
timezoneId: 'Pacific/Easter',
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
@@ -0,0 +1,289 @@
import { addDays, addHours, differenceInCalendarDays, differenceInMinutes, isBefore, parseISO, toDate } from 'date-fns';
import { Page } from 'playwright-core';
import { test, expect, DashboardPage, E2ESelectorGroups } from '@grafana/plugin-e2e';
const TIMEZONE_DASHBOARD_UID = 'd41dbaa2-a39e-4536-ab2b-caca52f1a9c8';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Dashboard time zone support',
{
tag: ['@dashboards'],
},
() => {
test('Tests dashboard time zone scenarios', async ({ page, gotoDashboardPage, selectors }) => {
const dashboardPage = await gotoDashboardPage({ uid: TIMEZONE_DASHBOARD_UID });
const fromTimeZone = 'UTC';
const toTimeZone = 'America/Chicago';
const offset = offsetBetweenTimeZones(toTimeZone, fromTimeZone);
// Enter edit mode
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
// Open dashboard settings
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.settingsButton).click();
// Change timezone to UTC
await page.getByTestId(selectors.components.TimeZonePicker.containerV2).click();
await page.getByRole('option', { name: 'Coordinated Universal Time ' }).click();
// Close settings and refresh
await dashboardPage
.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton)
.click();
await dashboardPage.getByGrafanaSelector(selectors.components.RefreshPicker.runButtonV2).click();
const panelsToCheck = ['Panel in timezone'];
const timesInUtc: Record<string, string> = {};
// Verify all panels are visible
for (const title of panelsToCheck) {
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(title))).toBeVisible();
const timeCell = dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title(title))
.getByRole('row')
.nth(1)
.getByRole('cell')
.first();
const time = await timeCell.textContent();
if (time) {
timesInUtc[title] = time;
}
}
// Open dashboard settings
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.settingsButton).click();
// Change timezone to America/Chicago
await page.getByTestId(selectors.components.TimeZonePicker.containerV2).click();
await page.getByRole('option', { name: toTimeZone }).click();
// Close settings and refresh
await dashboardPage
.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton)
.click();
await dashboardPage.getByGrafanaSelector(selectors.components.RefreshPicker.runButtonV2).click();
// Verify panels are still visible after timezone change
for (const title of panelsToCheck) {
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(title))).toBeVisible();
const timeCell = dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title(title))
.getByRole('row')
.nth(1)
.getByRole('cell')
.first();
await expect(async () => {
const inUtc = timesInUtc[title];
const inTz = await timeCell.textContent();
expect(inTz).not.toBeNull();
if (inTz) {
const isCorrect = isTimeCorrect(inUtc, inTz, offset);
expect(isCorrect).toEqual(true);
}
}).toPass();
}
});
test('Tests relative timezone support and overrides', async ({ page, gotoDashboardPage, selectors }) => {
// Open dashboard
const dashboardPage = await gotoDashboardPage({
uid: TIMEZONE_DASHBOARD_UID,
});
// Switch to Browser timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now-6h',
to: 'now',
zone: 'Browser',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Today so far, still in Browser timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now/d',
to: 'now',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel in timezone'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Test UTC timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now-6h',
to: 'now',
zone: 'Coordinated Universal Time',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Today so far, still in UTC timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now/d',
to: 'now',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel in timezone'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Test Tokyo timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now-6h',
to: 'now',
zone: 'Asia/Tokyo',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Today so far, still in Tokyo timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now/d',
to: 'now',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel in timezone'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Test LA timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now-6h',
to: 'now',
zone: 'America/Los Angeles',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
// Today so far, still in LA timezone
await setTimeRange(page, dashboardPage, selectors, {
from: 'now/d',
to: 'now',
});
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel with relative time override'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
await expect(
dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel in timezone'))
.locator('[role="row"]')
.filter({ hasText: '00:00:00' })
).toBeVisible();
});
}
);
// Helper function to set time range with optional timezone
async function setTimeRange(
page: Page,
dashboardPage: DashboardPage,
selectors: E2ESelectorGroups,
options: { from: string; to: string; zone?: string }
) {
await dashboardPage.getByGrafanaSelector(selectors.components.TimePicker.openButton).click();
await dashboardPage.getByGrafanaSelector(selectors.components.TimePicker.fromField).fill(options.from);
await dashboardPage.getByGrafanaSelector(selectors.components.TimePicker.toField).fill(options.to);
if (options.zone) {
await page.getByRole('button', { name: 'Change time settings' }).click();
await page.getByTestId(selectors.components.TimeZonePicker.containerV2).click();
await page.getByRole('option', { name: options.zone }).click();
}
await dashboardPage.getByGrafanaSelector(selectors.components.TimePicker.applyTimeRange).click();
}
const isTimeCorrect = (inUtc: string, inTz: string, offset: number): boolean => {
if (inUtc === inTz) {
// we need to catch issues when timezone isn't changed for some reason like https://github.com/grafana/grafana/issues/35504
return false;
}
const utcDate = toDate(parseISO(inUtc));
const utcDateWithOffset = addHours(toDate(parseISO(inUtc)), offset);
const dayDifference = differenceInCalendarDays(utcDate, utcDateWithOffset); // if the utcDate +/- offset is the day before/after then we need to adjust reference
const dayOffset = isBefore(utcDateWithOffset, utcDate) ? dayDifference * -1 : dayDifference;
const tzDate = addDays(toDate(parseISO(inTz)), dayOffset); // adjust tzDate with any dayOffset
const diff = Math.abs(differenceInMinutes(utcDate, tzDate)); // use Math.abs if tzDate is in future
return diff <= Math.abs(offset * 60);
};
const offsetBetweenTimeZones = (timeZone1: string, timeZone2: string, when: Date = new Date()): number => {
const t1 = convertDateToAnotherTimeZone(when, timeZone1);
const t2 = convertDateToAnotherTimeZone(when, timeZone2);
return (t1.getTime() - t2.getTime()) / (1000 * 60 * 60);
};
const convertDateToAnotherTimeZone = (date: Date, timeZone: string): Date => {
const dateString = date.toLocaleString('en-US', {
timeZone: timeZone,
});
return new Date(dateString);
};
@@ -15,6 +15,9 @@ test.use({
cookies: [],
origins: [],
},
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
@@ -1,5 +1,11 @@
import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Embedded dashboard',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'edediimbjhdz4b/a-tall-dashboard';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Dashboards',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
import testDashboard from '../dashboards/TestDashboard.json';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Import Dashboards Test',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Load options from Url',
{
@@ -3,6 +3,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
const DASHBOARD_NAME = 'Test variable output';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Constant',
{
@@ -50,6 +50,12 @@ async function assertPreviewValues(
}
}
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Custom',
{
@@ -3,6 +3,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
const DASHBOARD_NAME = 'Test variable output';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Datasource',
{
@@ -16,6 +16,12 @@ async function assertPreviewValues(
}
}
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Interval',
{
@@ -3,6 +3,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables';
const DASHBOARD_NAME = 'Templating - Nested Template Variables';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Query - Add variable',
{
@@ -3,6 +3,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
const DASHBOARD_NAME = 'Test variable output';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Text box',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'WVpf2jp7z/repeating-a-panel-horizontally';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Repeating a panel horizontally',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'OY8Ghjt7k/repeating-a-panel-vertically';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Repeating a panel vertically',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = 'dtpl2Ctnk/repeating-an-empty-row';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Repeating empty rows',
{
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Variables - Set options from ui',
{
@@ -5,6 +5,7 @@ const DASHBOARD_UID = 'ZqZnVvFZz';
test.use({
featureToggles: {
newDashboardSharingComponent: false, // Use legacy sharing component for this test
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
@@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const DASHBOARD_UID = 'yBCC3aKGk';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'Templating dashboard links and variables',
{
@@ -4,6 +4,12 @@ import { test, expect, E2ESelectorGroups, DashboardPage } from '@grafana/plugin-
const PAGE_UNDER_TEST = 'AejrN1AMz';
test.use({
featureToggles: {
kubernetesDashboards: process.env.KUBERNETES_DASHBOARDS === 'true',
},
});
test.describe(
'TextBox - load options scenarios',
{