Skip to content

Commit

Permalink
Plugin E2E: Replace magic strings with selectors (#597)
Browse files Browse the repository at this point in the history
  • Loading branch information
sunker authored Dec 15, 2023
1 parent 0e0555a commit 9f5ff89
Show file tree
Hide file tree
Showing 16 changed files with 137 additions and 55 deletions.
28 changes: 26 additions & 2 deletions packages/plugin-e2e/src/e2e-selectors/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ export type E2ESelectors = {

export type APIs = {
DataSource: {
resource: string;
healthCheck: string;
resourcePattern: string;
resourceUIDPattern: string;
queryPattern: string;
query: string;
health: (uid: string, id: string) => string;
delete: (uid: string) => string;
};
Dashboard: {
delete: (uid: string) => string;
};
};

Expand Down Expand Up @@ -237,8 +244,10 @@ export type Components = {
};
PageToolbar: {
item: (tooltip: string) => string;
shotMoreItems: string;
container: string;
itemButton: (title: string) => string;
itemButtonTitle: string;
};
QueryEditorToolbarItem: {};
BackButton: {
Expand Down Expand Up @@ -406,6 +415,20 @@ export type Pages = {
addNewPanel: string;
addNewRow: string;
addNewPanelLibrary: string;
itemButtonAddViz: string;
Settings: {
Annotations: {
List: {
url: string;
};
Edit: {
url: (annotationIndex: string) => string;
};
};
Variables: {
url: string;
};
};
};
Dashboard: {
url: (uid: string) => string;
Expand Down Expand Up @@ -467,6 +490,7 @@ export type Pages = {
tableRowDuplicateButtons: (variableName: string) => string;
tableRowRemoveButtons: (variableName: string) => string;
addVariableCTAV2: (variableName: string) => string;
addVariableCTAV2Item: string;
};
Edit: {
General: {
Expand Down
23 changes: 19 additions & 4 deletions packages/plugin-e2e/src/e2e-selectors/versioned/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@ import { MIN_GRAFANA_VERSION } from './constants';

export const versionedAPIs = {
DataSource: {
resource: {
resourcePattern: {
[MIN_GRAFANA_VERSION]: '/api/datasources/*/resources',
},
resourceUIDPattern: {
'9.4.4': '/api/datasources/uid/*/resources',
[MIN_GRAFANA_VERSION]: '/api/datasources/*/resources',
},
query: {
queryPattern: {
[MIN_GRAFANA_VERSION]: '*/**/api/ds/query*',
},
healthCheck: {
[MIN_GRAFANA_VERSION]: 'api/datasources/uid/*/health',
query: {
[MIN_GRAFANA_VERSION]: '/api/ds/query',
},
health: {
['9.5.0']: (uid: string, _: string) => `/api/datasources/uid/${uid}/health`,
[MIN_GRAFANA_VERSION]: (_: string, id: string) => `/api/datasources/${id}/health`,
},
delete: {
[MIN_GRAFANA_VERSION]: (uid: string) => `/api/datasources/uid/${uid}`,
},
},
Dashboard: {
delete: {
[MIN_GRAFANA_VERSION]: (uid: string) => `/api/datasources/uid/${uid}`,
},
},
};
12 changes: 11 additions & 1 deletion packages/plugin-e2e/src/e2e-selectors/versioned/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ export const versionedComponents = {
menu: (title: string) => `data-testid Panel menu ${title}`,
containerByTitle: (title: string) => `${title} panel`,
headerCornerInfo: (mode: string) => `Panel header ${mode}`,
status: (status: string) => `data-testid Panel status ${status}`,
status: {
['10.2.0']: (status: string) => `data-testid Panel status ${status}`,
[MIN_GRAFANA_VERSION]: (_: string) => 'Panel status',
},
loadingBar: () => `Panel loading bar`,
HoverWidget: {
container: 'data-testid hover-header-container',
Expand Down Expand Up @@ -275,7 +278,14 @@ export const versionedComponents = {
PageToolbar: {
container: () => '.page-toolbar',
item: (tooltip: string) => `${tooltip}`,
shotMoreItems: {
[MIN_GRAFANA_VERSION]: 'Show more items',
},
itemButton: (title: string) => `data-testid ${title}`,
itemButtonTitle: {
'10.1.0': 'Add button',
[MIN_GRAFANA_VERSION]: 'Add panel button',
},
},
QueryEditorToolbarItem: {
button: (title: string) => `QueryEditor toolbar item button ${title}`,
Expand Down
19 changes: 19 additions & 0 deletions packages/plugin-e2e/src/e2e-selectors/versioned/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ export const versionedPages = {
addNewPanel: 'Add new panel',
addNewRow: 'Add new row',
addNewPanelLibrary: 'Add new panel from panel library',
itemButtonAddViz: {
[MIN_GRAFANA_VERSION]: 'Add new visualization menu item',
},
Settings: {
Annotations: {
List: {
url: '/dashboard/new?orgId=1&editview=annotations',
},
Edit: {
url: (annotationIndex: string) => `/dashboard/new?editview=annotations&editIndex=${annotationIndex}`,
},
},
Variables: {
url: '/dashboard/new?orgId=1&editview=templating',
},
},
},
Dashboard: {
url: (uid: string) => `/d/${uid}`,
Expand Down Expand Up @@ -124,6 +140,9 @@ export const versionedPages = {
tableRowDuplicateButtons: (variableName: string) => `Variable editor Table Duplicate button ${variableName}`,
tableRowRemoveButtons: (variableName: string) => `Variable editor Table Remove button ${variableName}`,
addVariableCTAV2: (name: string) => `data-testid Call to action button ${name}`,
addVariableCTAV2Item: {
[MIN_GRAFANA_VERSION]: 'Add variable',
},
},
Edit: {
General: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const createDataSourceViaAPI = async (
const text = await createDsReq.text();
const status = await createDsReq.status();
if (status === 200) {
console.log('Data source created: ', name);
return createDsReq.json().then((r) => r.datasource);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const createDataSourceConfigPage: CreateDataSourceConfigPageFixture = async (
await use(async (args) => {
deleteDataSource = args.deleteDataSourceAfterTest ?? true;
const datasource = await createDataSourceViaAPI(request, args);
datasourceConfigPage = new DataSourceConfigPage({ page, selectors, grafanaVersion, request }, datasource.uid);
datasourceConfigPage = new DataSourceConfigPage({ page, selectors, grafanaVersion, request }, datasource);
await datasourceConfigPage.goto();
return datasourceConfigPage;
});
Expand Down
5 changes: 4 additions & 1 deletion packages/plugin-e2e/src/models/AnnotationEditPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export class AnnotationEditPage extends GrafanaPage {
* @param options - Optional. RequestOptions to pass to waitForResponse
*/
async runQuery(options?: RequestOptions) {
const responsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes('/query'), options);
const responsePromise = this.ctx.page.waitForResponse(
(resp) => resp.url().includes(this.ctx.selectors.apis.DataSource.query),
options
);
//TODO: add new selector and use it in grafana/ui
await this.ctx.page.getByRole('button', { name: 'TEST' }).click();
return responsePromise;
Expand Down
10 changes: 8 additions & 2 deletions packages/plugin-e2e/src/models/AnnotationPage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as semver from 'semver';
import { PluginTestCtx } from '../types';
import { AnnotationEditPage } from './AnnotationEditPage';
import { GrafanaPage } from './GrafanaPage';
Expand All @@ -8,14 +9,19 @@ export class AnnotationPage extends GrafanaPage {
}

async goto() {
await this.ctx.page.goto('/dashboard/new?orgId=1&editview=annotations', {
await this.ctx.page.goto(this.ctx.selectors.pages.AddDashboard.Settings.Annotations.List.url, {
waitUntil: 'networkidle',
});
}

async clickAddNew() {
const { Dashboard } = this.ctx.selectors.pages;
this.getByTestIdOrAriaLabel(Dashboard.Settings.Annotations.List.addAnnotationCTAV2).click();

if (semver.gte(this.ctx.grafanaVersion, '8.3.0')) {
await this.getByTestIdOrAriaLabel(Dashboard.Settings.Annotations.List.addAnnotationCTAV2).click();
} else {
await this.getByTestIdOrAriaLabel(Dashboard.Settings.Annotations.List.addAnnotationCTA).click();
}
return new AnnotationEditPage(this.ctx);
}
}
11 changes: 5 additions & 6 deletions packages/plugin-e2e/src/models/DashboardPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,21 @@ export class DashboardPage extends GrafanaPage {
}

async addPanel(): Promise<PanelEditPage> {
const { components, pages } = this.ctx.selectors;
if (gte(this.ctx.grafanaVersion, '10.0.0')) {
//TODO: add new selector and use it in grafana/ui
const title = gte(this.ctx.grafanaVersion, '10.1.0') ? 'Add button' : 'Add panel button';
await this.getByTestIdOrAriaLabel(this.ctx.selectors.components.PageToolbar.itemButton(title)).click();
await this.getByTestIdOrAriaLabel(
this.ctx.selectors.pages.AddDashboard.itemButton('Add new visualization menu item')
components.PageToolbar.itemButton(components.PageToolbar.itemButtonTitle)
).click();
await this.getByTestIdOrAriaLabel(pages.AddDashboard.itemButton(pages.AddDashboard.itemButtonAddViz)).click();
} else {
await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.AddDashboard.addNewPanel).click();
await this.getByTestIdOrAriaLabel(pages.AddDashboard.addNewPanel).click();
}

return new PanelEditPage(this.ctx);
}

async deleteDashboard() {
await this.ctx.request.delete(`/api/datasources/uid/${this.dashboardUid}`);
await this.ctx.request.delete(this.ctx.selectors.apis.Dashboard.delete(this.dashboardUid));
}

async refreshDashboard() {
Expand Down
19 changes: 13 additions & 6 deletions packages/plugin-e2e/src/models/DataSourceConfigPage.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { PluginTestCtx } from '../types';
import { DataSource, PluginTestCtx } from '../types';
import { GrafanaPage } from './GrafanaPage';

export class DataSourceConfigPage extends GrafanaPage {
constructor(ctx: PluginTestCtx, private uid: string) {
constructor(ctx: PluginTestCtx, private datasource: DataSource) {
super(ctx);
}

async deleteDataSource() {
await this.ctx.request.delete(`/api/datasources/uid/${this.uid}`);
await this.ctx.request.delete(this.ctx.selectors.apis.DataSource.delete(this.datasource.uid));
}

async goto() {
await this.ctx.page.goto(this.ctx.selectors.pages.EditDataSource.url(this.uid), {
await this.ctx.page.goto(this.ctx.selectors.pages.EditDataSource.url(this.datasource.uid), {
waitUntil: 'load',
});
}
Expand All @@ -22,13 +22,20 @@ export class DataSourceConfigPage extends GrafanaPage {
* @param status the HTTP status code to return. Defaults to 200
*/
async mockHealthCheckResponse<T = any>(json: T, status = 200) {
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.healthCheck}`, async (route) => {
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.health}`, async (route) => {
await route.fulfill({ json, status });
});
}

async saveAndTest() {
const responsePromise = this.ctx.page.waitForResponse((resp) =>
resp
.url()
.includes(
this.ctx.selectors.apis.DataSource.health(this.datasource.uid ?? '', this.datasource.id.toString() ?? '')
)
);
await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.DataSource.saveAndTest).click();
return this.ctx.page.waitForResponse((resp) => resp.url().includes('/health'));
return responsePromise;
}
}
14 changes: 7 additions & 7 deletions packages/plugin-e2e/src/models/ExplorePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { DataSourcePicker } from './DataSourcePicker';
import { GrafanaPage } from './GrafanaPage';
import { TimeRange } from './TimeRange';

const SHOW_MORE_ITEMS = 'Show more items';

export class ExplorePage extends GrafanaPage {
datasource: DataSourcePicker;
timeRange: any;
Expand All @@ -20,24 +18,26 @@ export class ExplorePage extends GrafanaPage {
}

async getQueryEditorRow(refId: string): Promise<Locator> {
//TODO: add new selector and use it in grafana/ui
const locator = this.ctx.page.locator('[aria-label="Query editor row"]').filter({
has: this.ctx.page.locator(`[aria-label="Query editor row title ${refId}"]`),
const locator = this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRows.rows).filter({
has: this.getByTestIdOrAriaLabel(this.ctx.selectors.components.QueryEditorRow.title(refId)),
});
await expect(locator).toBeVisible();
return locator;
}

async runQuery(options?: RequestOptions) {
const components = this.ctx.selectors.components;
const responsePromise = this.ctx.page.waitForResponse((resp) => resp.url().includes('/api/ds/query'), options);
const responsePromise = this.ctx.page.waitForResponse(
(resp) => resp.url().includes(this.ctx.selectors.apis.DataSource.query),
options
);
try {
await this.getByTestIdOrAriaLabel(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(SHOW_MORE_ITEMS)).click();
await this.getByTestIdOrAriaLabel(components.PageToolbar.item(components.PageToolbar.shotMoreItems)).click();
await this.getByTestIdOrAriaLabel(components.RefreshPicker.runButtonV2).last().click();
}
return responsePromise;
Expand Down
8 changes: 4 additions & 4 deletions packages/plugin-e2e/src/models/GrafanaPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export abstract class GrafanaPage {
* @param status the HTTP status code to return. Defaults to 200
*/
async mockQueryDataResponse<T = any>(json: T, status = 200) {
await this.ctx.page.route('*/**/api/ds/query*', async (route) => {
await this.ctx.page.route(this.ctx.selectors.apis.DataSource.queryPattern, async (route) => {
await route.fulfill({ json, status });
});
}
Expand All @@ -50,11 +50,11 @@ export abstract class GrafanaPage {
* @param status the HTTP status code to return. Defaults to 200
*/
async mockResourceResponse<T = any>(path: string, json: T, status = 200) {
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.resource}/${path}`, async (route) => {
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.resourceUIDPattern}/${path}`, async (route) => {
await route.fulfill({ json, status });
});
// some data sources use the backendSrv directly, and then the path may be different
await this.ctx.page.route(`/api/datasources/*/resources/${path}`, async (route) => {
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.resourcePattern}/${path}`, async (route) => {
await route.fulfill({ json, status });
});
}
Expand All @@ -66,7 +66,7 @@ export abstract class GrafanaPage {
*/
async waitForQueryDataRequest(cb?: (request: Request) => boolean | Promise<boolean>) {
return this.ctx.page.waitForRequest((request) => {
if (request.url().includes('api/ds/query') && request.method() === 'POST') {
if (request.url().includes(this.ctx.selectors.apis.DataSource.query) && request.method() === 'POST') {
return cb ? cb(request) : true;
}
return false;
Expand Down
Loading

0 comments on commit 9f5ff89

Please sign in to comment.