Commit 85c4311c by Hugo Häggmark Committed by GitHub

e2eTests: Adds cleanup of created datasource and dashboard (#20244)

* e2eTests: Adds cleanup of created datasource and dashboard

* Chore: Fixes Prettier error

* Tests: Updates snapshots
parent f2415a31
......@@ -63,7 +63,7 @@
</div>
</div>
<div class="gf-form-button-row">
<button class="btn btn-danger" ng-click="ctrl.deleteDashboard()" ng-show="ctrl.canDelete">
<button class="btn btn-danger" ng-click="ctrl.deleteDashboard()" ng-show="ctrl.canDelete" aria-label="Dashboard settings page delete dashboard button">
Delete Dashboard
</button>
</div>
......
......@@ -19,7 +19,7 @@ export class DataSourcesListItem extends PureComponent<Props> {
<img src={dataSource.typeLogoUrl} alt={dataSource.name} />
</figure>
<div className="card-item-details">
<div className="card-item-name">
<div className="card-item-name" aria-label={`Data source list item for ${dataSource.name}`}>
{dataSource.name}
{dataSource.isDefault && <span className="btn btn-secondary btn-small card-item-label">default</span>}
</div>
......
......@@ -32,6 +32,7 @@ exports[`Render should render component 1`] = `
className="card-item-details"
>
<div
aria-label="Data source list item for gdev-cloudwatch"
className="card-item-name"
>
gdev-cloudwatch
......
......@@ -10,7 +10,7 @@ export interface Props {
const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange, onNameChange }) => {
return (
<div className="gf-form-group">
<div className="gf-form-group" aria-label="Datasource settings page basic settings">
<div className="gf-form-inline">
<div className="gf-form max-width-30" style={{ marginRight: '3px' }}>
<FormLabel
......@@ -28,11 +28,17 @@ const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange,
placeholder="Name"
onChange={event => onNameChange(event.target.value)}
required
aria-label="Datasource settings page name input field"
/>
</div>
{/*
//@ts-ignore */}
<Switch label="Default" checked={isDefault} onChange={event => onDefaultChange(event.target.checked)} />
<Switch
label="Default"
checked={isDefault}
onChange={event => {
// @ts-ignore
onDefaultChange(event.target.checked);
}}
/>
</div>
</div>
);
......
......@@ -27,7 +27,13 @@ const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit, onTest }) => {
Test
</button>
)}
<button type="submit" className="btn btn-danger" disabled={isReadOnly} onClick={onDelete}>
<button
type="submit"
className="btn btn-danger"
disabled={isReadOnly}
onClick={onDelete}
aria-label="Delete button"
>
Delete
</button>
<a className="btn btn-inverse" href={`${config.appSubUrl}/datasources`}>
......
......@@ -3,36 +3,31 @@ import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import isString from 'lodash/isString';
// Components
import Page from 'app/core/components/Page/Page';
import { PluginSettings, GenericDataSourcePlugin } from './PluginSettings';
import { GenericDataSourcePlugin, PluginSettings } from './PluginSettings';
import BasicSettings from './BasicSettings';
import ButtonRow from './ButtonRow';
// Services & Utils
import appEvents from 'app/core/app_events';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
// Actions & selectors
import { getDataSource, getDataSourceMeta } from '../state/selectors';
import {
dataSourceLoaded,
deleteDataSource,
loadDataSource,
setDataSourceName,
setIsDefault,
updateDataSource,
dataSourceLoaded,
} from '../state/actions';
import { getNavModel } from 'app/core/selectors/navModel';
import { getRouteParamsId } from 'app/core/selectors/location';
// Types
import { StoreState, CoreEvents } from 'app/types/';
import { CoreEvents, StoreState } from 'app/types/';
import { UrlQueryMap } from '@grafana/runtime';
import { DataSourceSettings, DataSourcePluginMeta } from '@grafana/data';
import { NavModel } from '@grafana/data';
import { DataSourcePluginMeta, DataSourceSettings, NavModel } from '@grafana/data';
import { getDataSourceLoadingNav } from '../state/navModel';
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader';
......
......@@ -2,6 +2,7 @@
exports[`Render should render component 1`] = `
<div
aria-label="Datasource settings page basic settings"
className="gf-form-group"
>
<div
......@@ -21,6 +22,7 @@ exports[`Render should render component 1`] = `
Name
</Component>
<Input
aria-label="Datasource settings page name input field"
className="gf-form-input max-width-23"
onChange={[Function]}
placeholder="Name"
......
......@@ -12,6 +12,7 @@ exports[`Render should render component 1`] = `
Test
</button>
<button
aria-label="Delete button"
className="btn btn-danger"
disabled={true}
onClick={[MockFunction]}
......@@ -42,6 +43,7 @@ exports[`Render should render with buttons enabled 1`] = `
Save & Test
</button>
<button
aria-label="Delete button"
className="btn btn-danger"
disabled={false}
onClick={[MockFunction]}
......
......@@ -26,7 +26,7 @@
<div class="confirm-modal-buttons">
<button ng-show="onAltAction" type="button" class="btn btn-primary" ng-click="dismiss();onAltAction();">{{altActionText}}</button>
<button ng-show="onConfirm" type="button" class="btn btn-danger" ng-click="onConfirm();dismiss();" ng-disabled="!confirmTextValid" give-focus="true">{{yesText}}</button>
<button ng-show="onConfirm" type="button" class="btn btn-danger" ng-click="onConfirm();dismiss();" ng-disabled="!confirmTextValid" give-focus="true" aria-label="Confirm Modal Danger Button">{{yesText}}</button>
<button type="button" class="btn btn-inverse" ng-click="dismiss()">{{noText}}</button>
</div>
</div>
......
import { ClickablePageObject, ClickablePageObjectType, Selector, TestPage } from '@grafana/toolkit/src/e2e';
export interface DashboardPage {
settings: ClickablePageObjectType;
}
export const dashboardPage = new TestPage<DashboardPage>({
pageObjects: {
settings: new ClickablePageObject(Selector.fromAriaLabel('Dashboard settings navbar button')),
},
});
import { ClickablePageObject, ClickablePageObjectType, Selector, TestPage } from '@grafana/toolkit/src/e2e';
export interface DashboardSettingsPage {
deleteDashBoard: ClickablePageObjectType;
}
export const dashboardSettingsPage = new TestPage<DashboardSettingsPage>({
pageObjects: {
deleteDashBoard: new ClickablePageObject(Selector.fromAriaLabel('Dashboard settings page delete dashboard button')),
},
});
import { TestPage } from '@grafana/toolkit/src/e2e';
import { ClickablePageObject, ClickablePageObjectType, Selector, TestPage } from '@grafana/toolkit/src/e2e';
export interface DataSourcesPage {}
export interface DataSourcesPage {
testData: ClickablePageObjectType;
}
export const dataSourcesPage = new TestPage<DataSourcesPage>({
export const dataSourcesPageFactory = (testDataSourceName: string) =>
new TestPage<DataSourcesPage>({
url: '/datasources',
pageObjects: {},
});
pageObjects: {
testData: new ClickablePageObject(Selector.fromAriaLabel(`Data source list item for ${testDataSourceName}`)),
},
});
import {
TestPage,
ClickablePageObjectType,
PageObjectType,
ClickablePageObject,
ClickablePageObjectType,
InputPageObject,
InputPageObjectType,
PageObject,
PageObjectType,
Selector,
TestPage,
} from '@grafana/toolkit/src/e2e';
export interface EditDataSourcePage {
name: InputPageObjectType;
default: ClickablePageObjectType;
delete: ClickablePageObjectType;
saveAndTest: ClickablePageObjectType;
alert: PageObjectType;
alertMessage: PageObjectType;
......@@ -15,6 +20,11 @@ export interface EditDataSourcePage {
export const editDataSourcePage = new TestPage<EditDataSourcePage>({
pageObjects: {
name: new InputPageObject(Selector.fromAriaLabel('Datasource settings page name input field')),
default: new ClickablePageObject(
Selector.fromSelector('[aria-label="Datasource settings page basic settings"] .gf-form-switch')
),
delete: new ClickablePageObject(Selector.fromAriaLabel('Delete button')),
saveAndTest: new ClickablePageObject(Selector.fromAriaLabel('Save and Test button')),
alert: new PageObject(Selector.fromAriaLabel('Datasource settings page Alert')),
alertMessage: new PageObject(Selector.fromAriaLabel('Datasource settings page Alert message')),
......
import { ClickablePageObject, ClickablePageObjectType, PageObject, Selector, TestPage } from '@grafana/toolkit/src/e2e';
export interface ConfirmModal {
delete: ClickablePageObjectType;
success: PageObject;
}
export const confirmModal = new TestPage<ConfirmModal>({
pageObjects: {
delete: new ClickablePageObject(Selector.fromAriaLabel('Confirm Modal Danger Button')),
success: new PageObject(Selector.fromSelector('.alert-success')),
},
});
import { Browser, Page, Target } from 'puppeteer-core';
import { e2eScenario, constants, takeScreenShot, compareScreenShots } from '@grafana/toolkit/src/e2e';
import { compareScreenShots, constants, e2eScenario, takeScreenShot } from '@grafana/toolkit/src/e2e';
import { addDataSourcePage } from 'e2e-test/pages/datasources/addDataSourcePage';
import { editDataSourcePage } from 'e2e-test/pages/datasources/editDataSourcePage';
import { dataSourcesPage } from 'e2e-test/pages/datasources/dataSources';
import { dataSourcesPageFactory } from 'e2e-test/pages/datasources/dataSources';
import { createDashboardPage } from 'e2e-test/pages/dashboards/createDashboardPage';
import { saveDashboardModal } from 'e2e-test/pages/dashboards/saveDashboardModal';
import { dashboardsPageFactory } from 'e2e-test/pages/dashboards/dashboardsPage';
import { panel } from 'e2e-test/pages/panels/panel';
import { editPanelPage } from 'e2e-test/pages/panels/editPanel';
import { sharePanelModal } from 'e2e-test/pages/panels/sharePanelModal';
import { confirmModal } from '../pages/modals/confirmModal';
import { dashboardPage } from '../pages/dashboards/dashboardPage';
import { dashboardSettingsPage } from '../pages/dashboards/dashboardSettingsPage';
e2eScenario(
'Login scenario, create test data source, dashboard, panel, and export scenario',
'should pass',
async (browser: Browser, page: Page) => {
const addTestDataSourceAndVerify = async (page: Page) => {
// Add TestData DB
const testDataSourceName = `TestData-${new Date().getTime()}`;
await addDataSourcePage.init(page);
await addDataSourcePage.navigateTo();
await addDataSourcePage.pageObjects.testDataDB.exists();
......@@ -23,6 +24,8 @@ e2eScenario(
await editDataSourcePage.init(page);
await editDataSourcePage.waitForNavigation();
await editDataSourcePage.pageObjects.name.enter(testDataSourceName);
await editDataSourcePage.pageObjects.default.click();
await editDataSourcePage.pageObjects.saveAndTest.click();
await editDataSourcePage.pageObjects.alert.exists();
await editDataSourcePage.pageObjects.alertMessage.containsText('Data source is working');
......@@ -32,11 +35,17 @@ e2eScenario(
const expectedUrl = url.substring(1, url.length - 1);
const selector = `a[href="${expectedUrl}"]`;
const dataSourcesPage = dataSourcesPageFactory(testDataSourceName);
await dataSourcesPage.init(page);
await dataSourcesPage.navigateTo();
await dataSourcesPage.expectSelector({ selector });
return testDataSourceName;
};
const addDashboardAndSetupTestDataGraph = async (page: Page) => {
// Create a new Dashboard
const dashboardTitle = `Dashboard-${new Date().getTime()}`;
await createDashboardPage.init(page);
await createDashboardPage.navigateTo();
await createDashboardPage.pageObjects.addQuery.click();
......@@ -52,11 +61,14 @@ e2eScenario(
// Confirm save modal
await saveDashboardModal.init(page);
await saveDashboardModal.expectSelector({ selector: 'save-dashboard-as-modal' });
const dashboardTitle = new Date().toISOString();
await saveDashboardModal.pageObjects.name.enter(dashboardTitle);
await saveDashboardModal.pageObjects.save.click();
await saveDashboardModal.pageObjects.success.exists();
return dashboardTitle;
};
const clickOnSharePanelImageLinkAndCompareImages = async (browser: Browser, page: Page, dashboardTitle: string) => {
// Share the dashboard
const dashboardsPage = dashboardsPageFactory(dashboardTitle);
await dashboardsPage.init(page);
......@@ -75,10 +87,56 @@ e2eScenario(
const newTarget: Target = (await targetPromise) as Target;
expect(newTarget.url()).toContain(`${constants.baseUrl}/render/d-solo`);
// Take snapshot of page
// Take snapshot of page only when running on CircleCI
if (process.env.CIRCLE_SHA1) {
const newPage = await newTarget.page();
const fileName = 'smoke-test-scenario';
await takeScreenShot(newPage, fileName);
await compareScreenShots(fileName);
}
};
const cleanUpTestDataSource = async (page: Page, testDataSourceName: string) => {
const dataSourcesPage = dataSourcesPageFactory(testDataSourceName);
await dataSourcesPage.init(page);
await dataSourcesPage.navigateTo();
await dataSourcesPage.pageObjects.testData.click();
await editDataSourcePage.init(page);
await editDataSourcePage.pageObjects.delete.exists();
await editDataSourcePage.pageObjects.delete.click();
await confirmModal.init(page);
await confirmModal.pageObjects.delete.click();
await confirmModal.pageObjects.success.exists();
};
const cleanDashboard = async (page: Page, dashboardTitle: string) => {
const dashboardsPage = dashboardsPageFactory(dashboardTitle);
await dashboardsPage.init(page);
await dashboardsPage.navigateTo();
await dashboardsPage.pageObjects.dashboard.exists();
await dashboardsPage.pageObjects.dashboard.click();
await dashboardPage.init(page);
await dashboardPage.pageObjects.settings.click();
await dashboardSettingsPage.init(page);
await dashboardSettingsPage.pageObjects.deleteDashBoard.click();
await confirmModal.init(page);
await confirmModal.pageObjects.delete.click();
await confirmModal.pageObjects.success.exists();
};
e2eScenario(
'Login scenario, create test data source, dashboard, panel, and export scenario',
'should pass',
async (browser: Browser, page: Page) => {
const testDataSourceName = await addTestDataSourceAndVerify(page);
const dashboardTitle = await addDashboardAndSetupTestDataGraph(page);
await clickOnSharePanelImageLinkAndCompareImages(browser, page, dashboardTitle);
await cleanUpTestDataSource(page, testDataSourceName);
await cleanDashboard(page, dashboardTitle);
}
);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment