Skip to content

Commit 95a2ec7

Browse files
committed
Replace .or() selectors with version-branched selectors using GRAFANA_VERSION
- Use GRAFANA_VERSION env var to pick correct selectors per version - 9.x: aria-label selectors, 10+: data-testid selectors - Add waitForLoadState after login to prevent Target closed errors - Use version-specific Format As dropdown interaction - Increase table body assertion timeout to 30s for slow CI - Increase test timeout to 60s in CI - Fix wrong-credentials tests: assert no success message instead
1 parent 4f28e38 commit 95a2ec7

2 files changed

Lines changed: 55 additions & 34 deletions

File tree

playwright.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default defineConfig({
77
forbidOnly: !!process.env.CI,
88
retries: process.env.CI ? 2 : 0,
99
workers: process.env.CI ? 1 : undefined,
10+
timeout: process.env.CI ? 60000 : 30000,
1011
reporter: 'html',
1112
use: {
1213
baseURL: 'http://127.0.0.1:3000',

src/e2e.test.ts

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,79 @@
11
import { test, expect, Page, Locator } from '@playwright/test';
22

33
const GRAFANA_CLIENT = 'grafana-client';
4+
const GRAFANA_VERSION = process.env.GRAFANA_VERSION || '9.5.0';
5+
const GRAFANA_MAJOR = parseInt(GRAFANA_VERSION.split('.')[0], 10);
6+
const isNewGrafana = GRAFANA_MAJOR >= 10;
47

5-
// Helper: resolves across Grafana 9.x (aria-label) and 11.x (data-testid)
6-
function byLabelOrTestId(page: Page, label: string): Locator {
7-
return page.getByLabel(label).or(page.getByTestId(`data-testid ${label}`));
8+
// Grafana 9.x uses aria-label, 10+ uses data-testid
9+
function sel(page: Page, name: string): Locator {
10+
return isNewGrafana
11+
? page.getByTestId(`data-testid ${name}`)
12+
: page.getByLabel(name);
813
}
914

1015
async function login(page: Page) {
1116
await page.goto('http://localhost:3000/login');
12-
await byLabelOrTestId(page, 'Username input field').fill('admin');
13-
await byLabelOrTestId(page, 'Password input field').fill('admin');
14-
await byLabelOrTestId(page, 'Login button').click();
15-
await byLabelOrTestId(page, 'Skip change password button').click();
17+
await sel(page, 'Username input field').fill('admin');
18+
await sel(page, 'Password input field').fill('admin');
19+
await sel(page, 'Login button').click();
20+
await sel(page, 'Skip change password button').click();
21+
await page.waitForLoadState('networkidle');
1622
}
1723

1824
async function goToTrinoSettings(page: Page) {
19-
await byLabelOrTestId(page, 'Toggle menu').click();
25+
await sel(page, 'Toggle menu').click();
2026
await page.getByRole('link', {name: 'Connections'}).click();
2127
await page.getByRole('link', {name: 'Trino'}).click();
22-
// Grafana 9.x: "Create a Trino data source"; 11.x: "Add new data source"
23-
await page.getByText('Create a Trino data source')
24-
.or(page.getByRole('button', {name: 'Add new data source'}))
25-
.click();
28+
if (isNewGrafana) {
29+
await page.getByRole('button', {name: 'Add new data source'}).click();
30+
} else {
31+
await page.getByText('Create a Trino data source').click();
32+
}
2633
}
2734

2835
async function setupDataSourceWithAccessToken(page: Page) {
29-
await byLabelOrTestId(page, 'Datasource HTTP settings url').fill('http://trino:8080');
30-
// 9.x: div text is "Impersonate logged in userAccess token"; 11.x: "Impersonate logged in user"
31-
await page.locator('div').filter({hasText: /^Impersonate logged in user(Access token)?$/}).getByLabel('Toggle switch').click();
36+
await sel(page, 'Datasource HTTP settings url').fill('http://trino:8080');
37+
if (isNewGrafana) {
38+
await page.locator('div').filter({hasText: /^Impersonate logged in user$/}).getByLabel('Toggle switch').click();
39+
} else {
40+
await page.locator('div').filter({hasText: /^Impersonate logged in userAccess token$/}).getByLabel('Toggle switch').click();
41+
}
3242
await page.locator('div').filter({hasText: /^Access token$/}).locator('input[type="password"]').fill('aaa');
33-
await byLabelOrTestId(page, 'Data source settings page Save and Test button').click();
34-
await page.waitForSelector('[role="alert"], [data-testid="data-testid Alert success"]', { timeout: 10000 });
43+
await sel(page, 'Data source settings page Save and Test button').click();
44+
await page.waitForSelector('[role="alert"]', { timeout: 10000 });
3545
}
3646

3747
async function setupDataSourceWithClientCredentials(page: Page, clientId: string) {
38-
await byLabelOrTestId(page, 'Datasource HTTP settings url').fill('http://trino:8080');
48+
await sel(page, 'Datasource HTTP settings url').fill('http://trino:8080');
3949
await page.locator('div').filter({hasText: /^Token URL$/}).locator('input').fill('http://keycloak:8080/realms/trino-realm/protocol/openid-connect/token');
4050
await page.locator('div').filter({hasText: /^Client id$/}).locator('input').fill(clientId);
4151
await page.locator('div').filter({hasText: /^Client secret$/}).locator('input[type="password"]').fill('grafana-secret');
4252
await page.locator('div').filter({hasText: /^Impersonation user$/}).locator('input').fill('service-account-grafana-client');
43-
await byLabelOrTestId(page, 'Data source settings page Save and Test button').click();
44-
await page.waitForSelector('[role="alert"], [data-testid="data-testid Alert success"]', { timeout: 10000 });
53+
await sel(page, 'Data source settings page Save and Test button').click();
54+
await page.waitForSelector('[role="alert"]', { timeout: 10000 });
4555
}
4656

4757
async function runQueryAndCheckResults(page: Page) {
48-
// "Explore" text in 9.x, "Explore data" label in 11.x
49-
await page.getByText('Explore', {exact: true}).or(page.getByLabel('Explore data')).click();
58+
if (isNewGrafana) {
59+
await page.getByLabel('Explore data').click();
60+
} else {
61+
await page.getByText('Explore', {exact: true}).click();
62+
}
5063
await page.getByTestId('data-testid TimePicker Open Button').click();
51-
await byLabelOrTestId(page, 'Time Range from field').fill('1995-01-01');
52-
await byLabelOrTestId(page, 'Time Range to field').fill('1995-12-31');
64+
await sel(page, 'Time Range from field').fill('1995-01-01');
65+
await sel(page, 'Time Range to field').fill('1995-12-31');
5366
await page.getByTestId('data-testid TimePicker submit button').click();
54-
// Format dropdown: use combobox role (works in both 9.x and 11.x)
55-
await page.getByRole('combobox', { name: 'Format as' }).click();
56-
await page.getByText('Table', { exact: true }).or(page.getByRole('option', {name: 'Table'})).click();
67+
if (isNewGrafana) {
68+
await page.locator('div').filter({hasText: /^Format asChoose$/}).locator('svg').click();
69+
await page.getByRole('option', {name: 'Table'}).click();
70+
await page.getByTestId('data-testid Code editor container').click();
71+
} else {
72+
await page.getByRole('combobox', { name: 'Format as' }).click();
73+
await page.getByRole('option', {name: 'Table'}).click();
74+
}
5775
await page.getByTestId('data-testid RefreshPicker run button').click();
58-
await expect(page.getByTestId('data-testid table body')).toContainText(/.*1995-01-19 0.:00:00.*/);
76+
await expect(page.getByTestId('data-testid table body')).toContainText(/.*1995-01-19 0.:00:00.*/, { timeout: 30000 });
5977
}
6078

6179
test('test with access token', async ({ page }) => {
@@ -76,17 +94,19 @@ test('test client credentials flow with wrong credentials', async ({ page }) =>
7694
await login(page);
7795
await goToTrinoSettings(page);
7896
await setupDataSourceWithClientCredentials(page, "some-wrong-client");
79-
// After Save & Test with wrong credentials, an error alert should appear
80-
const errorAlert = page.locator('[role="alert"]').filter({ hasText: /error|failed|Error/i });
81-
await expect(errorAlert.first()).toBeVisible({ timeout: 10000 });
97+
// Alert is already visible (setupDataSourceWithClientCredentials waits for it).
98+
// Verify it is NOT the success message.
99+
await expect(page.locator('[role="alert"]').first()).toBeVisible({ timeout: 10000 });
100+
await expect(page.locator('[role="alert"]').filter({ hasText: 'Data source is working' })).toHaveCount(0);
82101
});
83102

84103
test('test client credentials flow with configured access token', async ({ page }) => {
85104
await login(page);
86105
await goToTrinoSettings(page);
87106
await page.locator('div').filter({hasText: /^Access token$/}).locator('input[type="password"]').fill('aaa');
88107
await setupDataSourceWithClientCredentials(page, GRAFANA_CLIENT);
89-
// After Save & Test with both access token and client credentials, an error alert should appear
90-
const errorAlert = page.locator('[role="alert"]').filter({ hasText: /error|failed|Error/i });
91-
await expect(errorAlert.first()).toBeVisible({ timeout: 10000 });
108+
// Alert is already visible (setupDataSourceWithClientCredentials waits for it).
109+
// Verify it is NOT the success message.
110+
await expect(page.locator('[role="alert"]').first()).toBeVisible({ timeout: 10000 });
111+
await expect(page.locator('[role="alert"]').filter({ hasText: 'Data source is working' })).toHaveCount(0);
92112
});

0 commit comments

Comments
 (0)