mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
@grafana/e2e: improvements (#25497)
* Minor changes * Use UI for removing dashboards and datasources … with an optional “quick” mode that instead does so via a request * Improved URL helpers * Simplified test teardown * Added support for multiple tests ... instead of being forced to cram everything into a single test because the session was cleared
This commit is contained in:
parent
034abaa73a
commit
4c8ad8d031
@ -15,6 +15,7 @@ module.exports = async baseConfig => {
|
||||
// @todo: https://github.com/cypress-io/cypress/issues/6406
|
||||
const jsonReporter = require.resolve('@mochajs/json-file-reporter');
|
||||
|
||||
// @todo `baseUrl: env.CYPRESS_BASEURL`
|
||||
const projectConfig = {
|
||||
fixturesFolder: `${CWD}/cypress/fixtures`,
|
||||
integrationFolder: `${CWD}/cypress/integration`,
|
||||
|
@ -26,10 +26,18 @@ export const addPanel = (config?: Partial<AddPanelConfig>): any =>
|
||||
|
||||
const { dashboardUid, dataSourceName, panelTitle, queriesForm, visualizationName } = fullConfig;
|
||||
|
||||
e2e.flows.openDashboard(dashboardUid);
|
||||
e2e.pages.Dashboard.visit(dashboardUid);
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
||||
e2e.pages.AddDashboard.addNewPanel().click();
|
||||
|
||||
e2e().server();
|
||||
|
||||
// @todo alias '/**/*.js*' as '@pluginModule' when possible: https://github.com/cypress-io/cypress/issues/1296
|
||||
|
||||
e2e()
|
||||
.route('POST', '/api/ds/query')
|
||||
.as('chartData');
|
||||
|
||||
e2e()
|
||||
.get('.ds-picker')
|
||||
.click()
|
||||
@ -58,11 +66,6 @@ export const addPanel = (config?: Partial<AddPanelConfig>): any =>
|
||||
.click();
|
||||
closeOptionsGroup('type');
|
||||
|
||||
e2e().server();
|
||||
e2e()
|
||||
.route('POST', '/api/ds/query')
|
||||
.as('chartData');
|
||||
|
||||
queriesForm(fullConfig);
|
||||
|
||||
e2e().wait('@chartData');
|
||||
|
@ -2,37 +2,21 @@ import { e2e } from '../index';
|
||||
import { fromBaseUrl } from '../support/url';
|
||||
|
||||
export interface DeleteDashboardConfig {
|
||||
quick?: boolean;
|
||||
title: string;
|
||||
uid: string;
|
||||
}
|
||||
|
||||
export const deleteDashboard = ({ title, uid }: DeleteDashboardConfig) => {
|
||||
export const deleteDashboard = ({ quick = false, title, uid }: DeleteDashboardConfig) => {
|
||||
e2e().logToConsole('Deleting dashboard with uid:', uid);
|
||||
|
||||
// Avoid dashboard page errors
|
||||
e2e.pages.Home.visit();
|
||||
e2e().request('DELETE', fromBaseUrl(`/api/dashboards/uid/${uid}`));
|
||||
if (quick) {
|
||||
quickDelete(uid);
|
||||
} else {
|
||||
uiDelete(uid, title);
|
||||
}
|
||||
|
||||
/* https://github.com/cypress-io/cypress/issues/2831
|
||||
Flows.openDashboard(title);
|
||||
|
||||
Pages.Dashboard.settings().click();
|
||||
|
||||
Pages.DashboardSettings.deleteDashBoard().click();
|
||||
|
||||
Pages.ConfirmModal.delete().click();
|
||||
|
||||
Flows.assertSuccessNotification();
|
||||
|
||||
Pages.Dashboards.visit();
|
||||
Pages.Dashboards.dashboards().each(item => {
|
||||
const text = item.text();
|
||||
Cypress.log({ message: [text] });
|
||||
if (text && text.indexOf(title) !== -1) {
|
||||
expect(false).equals(true, `Dashboard ${title} was found although it was deleted.`);
|
||||
}
|
||||
});
|
||||
*/
|
||||
e2e().logToConsole('Deleted dashboard with uid:', uid);
|
||||
|
||||
e2e.getScenarioContext().then(({ addedDashboards }: any) => {
|
||||
e2e.setScenarioContext({
|
||||
@ -42,3 +26,26 @@ export const deleteDashboard = ({ title, uid }: DeleteDashboardConfig) => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const quickDelete = (uid: string) => {
|
||||
e2e().request('DELETE', fromBaseUrl(`/api/dashboards/uid/${uid}`));
|
||||
};
|
||||
|
||||
const uiDelete = (uid: string, title: string) => {
|
||||
e2e.pages.Dashboard.visit(uid);
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||
e2e.pages.Dashboard.Settings.General.deleteDashBoard().click();
|
||||
e2e.pages.ConfirmModal.delete().click();
|
||||
e2e.flows.assertSuccessNotification();
|
||||
|
||||
e2e.pages.Dashboards.visit();
|
||||
|
||||
// @todo replace `e2e.pages.Dashboards.dashboards` with this when argument is empty
|
||||
e2e()
|
||||
.get('[aria-label^="Dashboard search item "]')
|
||||
.each(item =>
|
||||
e2e()
|
||||
.wrap(item)
|
||||
.should('not.contain', title)
|
||||
);
|
||||
};
|
||||
|
@ -4,31 +4,19 @@ import { fromBaseUrl } from '../support/url';
|
||||
export interface DeleteDataSourceConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
quick?: boolean;
|
||||
}
|
||||
|
||||
export const deleteDataSource = ({ id, name }: DeleteDataSourceConfig) => {
|
||||
export const deleteDataSource = ({ id, name, quick = false }: DeleteDataSourceConfig) => {
|
||||
e2e().logToConsole('Deleting data source with name:', name);
|
||||
|
||||
// Avoid datasources page errors
|
||||
e2e.pages.Home.visit();
|
||||
e2e().request('DELETE', fromBaseUrl(`/api/datasources/name/${name}`));
|
||||
if (quick) {
|
||||
quickDelete(name);
|
||||
} else {
|
||||
uiDelete(name);
|
||||
}
|
||||
|
||||
/* https://github.com/cypress-io/cypress/issues/2831
|
||||
Pages.DataSources.visit();
|
||||
Pages.DataSources.dataSources(name).click();
|
||||
|
||||
Pages.DataSource.delete().click();
|
||||
|
||||
Pages.ConfirmModal.delete().click();
|
||||
|
||||
Pages.DataSources.visit();
|
||||
Pages.DataSources.dataSources().each(item => {
|
||||
const text = item.text();
|
||||
if (text && text.indexOf(name) !== -1) {
|
||||
expect(false).equals(true, `Data source ${name} was found although it was deleted.`);
|
||||
}
|
||||
});
|
||||
*/
|
||||
e2e().logToConsole('Deleted data source with name:', name);
|
||||
|
||||
e2e.getScenarioContext().then(({ addedDataSources }: any) => {
|
||||
e2e.setScenarioContext({
|
||||
@ -38,3 +26,25 @@ export const deleteDataSource = ({ id, name }: DeleteDataSourceConfig) => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const quickDelete = (name: string) => {
|
||||
e2e().request('DELETE', fromBaseUrl(`/api/datasources/name/${name}`));
|
||||
};
|
||||
|
||||
const uiDelete = (name: string) => {
|
||||
e2e.pages.DataSources.visit();
|
||||
e2e.pages.DataSources.dataSources(name).click();
|
||||
e2e.pages.DataSource.delete().click();
|
||||
e2e.pages.ConfirmModal.delete().click();
|
||||
|
||||
e2e.pages.DataSources.visit();
|
||||
|
||||
// @todo replace `e2e.pages.DataSources.dataSources` with this when argument is empty
|
||||
e2e()
|
||||
.get('[aria-label^="Data source list item "]')
|
||||
.each(item =>
|
||||
e2e()
|
||||
.wrap(item)
|
||||
.should('not.contain', name)
|
||||
);
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ import { login } from './login';
|
||||
import { openDashboard } from './openDashboard';
|
||||
import { saveDashboard } from './saveDashboard';
|
||||
import { openPanelMenuItem, PanelMenuItems } from './openPanelMenuItem';
|
||||
import { revertAllChanges } from './revertAllChanges';
|
||||
|
||||
export const Flows = {
|
||||
addDashboard,
|
||||
@ -21,4 +22,5 @@ export const Flows = {
|
||||
saveDashboard,
|
||||
openPanelMenuItem,
|
||||
PanelMenuItems,
|
||||
revertAllChanges,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { e2e } from '../index';
|
||||
|
||||
export const login = (username: string = 'admin', password: string = 'admin') => {
|
||||
e2e().logToConsole('Trying to login with username:', username);
|
||||
e2e().logToConsole('Logging in with username:', username);
|
||||
e2e.pages.Login.visit();
|
||||
e2e.pages.Login.username()
|
||||
.should('be.visible') // prevents flakiness
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { e2e } from '../index';
|
||||
|
||||
// @todo remove this, as it's a page change and not a flow
|
||||
export const openDashboard = (dashboardUid: string) => {
|
||||
e2e.pages.Dashboard.visit(dashboardUid);
|
||||
};
|
||||
|
8
packages/grafana-e2e/src/flows/revertAllChanges.ts
Normal file
8
packages/grafana-e2e/src/flows/revertAllChanges.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { e2e } from '../index';
|
||||
|
||||
export const revertAllChanges = () => {
|
||||
e2e.getScenarioContext().then(({ addedDashboards, addedDataSources }: any) => {
|
||||
addedDashboards.forEach((dashboard: any) => e2e.flows.deleteDashboard({ ...dashboard, quick: true }));
|
||||
addedDataSources.forEach((dataSource: any) => e2e.flows.deleteDataSource({ ...dataSource, quick: true }));
|
||||
});
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
import { e2e } from '../';
|
||||
import { Flows } from '../flows';
|
||||
import { getScenarioContext } from './scenarioContext';
|
||||
|
||||
export interface ScenarioArguments {
|
||||
describeName: string;
|
||||
@ -23,8 +22,11 @@ export const e2eScenario = ({
|
||||
if (skipScenario) {
|
||||
it.skip(itName, () => scenario());
|
||||
} else {
|
||||
before(() => Flows.login(e2e.env('USERNAME'), e2e.env('PASSWORD')));
|
||||
|
||||
beforeEach(() => {
|
||||
Flows.login(e2e.env('USERNAME'), e2e.env('PASSWORD'));
|
||||
Cypress.Cookies.preserveOnce('grafana_session');
|
||||
|
||||
if (addScenarioDataSource) {
|
||||
Flows.addDataSource();
|
||||
}
|
||||
@ -33,14 +35,13 @@ export const e2eScenario = ({
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getScenarioContext().then(({ addedDashboards, addedDataSources }: any) => {
|
||||
addedDashboards.forEach((dashboard: any) => Flows.deleteDashboard(dashboard));
|
||||
addedDataSources.forEach((dataSource: any) => Flows.deleteDataSource(dataSource));
|
||||
});
|
||||
});
|
||||
afterEach(() => Flows.revertAllChanges());
|
||||
after(() => e2e().clearCookies());
|
||||
|
||||
it(itName, () => scenario());
|
||||
|
||||
// @todo remove when possible: https://github.com/cypress-io/cypress/issues/2831
|
||||
it('temporary', () => {});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -2,13 +2,10 @@ import { e2e } from '../index';
|
||||
|
||||
const getBaseUrl = () => e2e.env('BASE_URL') || e2e.config().baseUrl || 'http://localhost:3000';
|
||||
|
||||
export const fromBaseUrl = (url = ''): string => {
|
||||
const strippedUrl = url.replace('^/', '');
|
||||
return `${getBaseUrl()}${strippedUrl}`;
|
||||
};
|
||||
export const fromBaseUrl = (url = '') => new URL(url, getBaseUrl()).href;
|
||||
|
||||
export const getDashboardUid = (url: string): string => {
|
||||
const matches = url.match(/\/d\/(.*)\//);
|
||||
const matches = new URL(url).pathname.match(/\/d\/([^/]+)/);
|
||||
if (!matches) {
|
||||
throw new Error(`Couldn't parse uid from ${url}`);
|
||||
} else {
|
||||
@ -17,7 +14,7 @@ export const getDashboardUid = (url: string): string => {
|
||||
};
|
||||
|
||||
export const getDataSourceId = (url: string): string => {
|
||||
const matches = url.match(/\/edit\/(.*)\//);
|
||||
const matches = new URL(url).pathname.match(/\/edit\/([^/]+)/);
|
||||
if (!matches) {
|
||||
throw new Error(`Couldn't parse id from ${url}`);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user