Commit fb3bec05 by Steven Vachon Committed by GitHub

@grafana/e2e: improvements (#25708)

* Set time range when opening a dashboard

* Set UTC timezone when creating a dashboard

* Added flow for selecting options in custom select fields

* Fix flaky test
parent 5d7cd2e9
......@@ -7,9 +7,7 @@ export const smokeTestScenario = {
addScenarioDashBoard: true,
skipScenario: false,
scenario: () => {
e2e.getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
e2e.flows.openDashboard(lastAddedDashboardUid);
});
e2e.flows.openDashboard();
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
e2e.pages.AddDashboard.addNewPanel().click();
......
......@@ -8,7 +8,7 @@ e2e.scenario({
skipScenario: false,
scenario: () => {
// open Panel Tests - Bar Gauge
e2e.flows.openDashboard('O6f11TZWk');
e2e.flows.openDashboard({ uid: 'O6f11TZWk' });
e2e()
.get('#panel-6 .bar-gauge__value')
......
......@@ -7,7 +7,7 @@ e2e.scenario({
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.openDashboard('5SdHCasdf');
e2e.flows.openDashboard({ uid: '5SdHCasdf' });
const fromTimeZone = 'Coordinated Universal Time';
const toTimeZone = 'America/Chicago';
......
......@@ -10,7 +10,7 @@ e2e.scenario({
skipScenario: false,
scenario: () => {
const viewPortWidth = e2e.config().viewportWidth;
e2e.flows.openDashboard('5SdHCadmz');
e2e.flows.openDashboard({ uid: '5SdHCadmz' });
// testing opening inspect drawer directly by clicking on Inspect in header menu
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Inspect, PANEL_UNDER_TEST);
......
......@@ -9,7 +9,7 @@ e2e.scenario({
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.openDashboard('5SdHCadmz');
e2e.flows.openDashboard({ uid: '5SdHCadmz' });
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST);
......
......@@ -10,7 +10,7 @@ e2e.scenario({
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.openDashboard('5SdHCadmz');
e2e.flows.openDashboard({ uid: '5SdHCadmz' });
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST);
......@@ -96,6 +96,10 @@ e2e.scenario({
e2e().wait('@apiPostQuery');
// Avoid flaky tests
// Maybe the virtual dom performs optimzations such as node position swapping, meaning 1 becomes 0 and it gets that element before the change because and never finds title 'A'
e2e().wait(250);
// Check the order of the rows after change
e2e.components.QueryEditorRows.rows()
.eq(0)
......
......@@ -9,7 +9,7 @@ e2e.scenario({
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.openDashboard('5SdHCadmz');
e2e.flows.openDashboard({ uid: '5SdHCadmz' });
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST);
......
......@@ -35,7 +35,7 @@ describe.skip('Variables', () => {
}
e2e.getScenarioContext().then(({ lastAddedDashboardUid, lastAddedDataSource }: any) => {
e2e.flows.openDashboard(lastAddedDashboardUid);
e2e.flows.openDashboard({ uid: lastAddedDashboardUid });
lastUid = lastAddedDashboardUid;
lastData = lastAddedDataSource;
});
......
......@@ -7,7 +7,7 @@ e2e.scenario({
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.openDashboard('5SdHCadmz');
e2e.flows.openDashboard({ uid: '5SdHCadmz' });
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
e2e.components.FolderPicker.container()
......
......@@ -52,6 +52,7 @@ export const Pages = {
sectionItems: (item: string) => `Dashboard settings section item ${item}`,
saveDashBoard: 'Dashboard settings aside actions Save button',
saveAsDashBoard: 'Dashboard settings aside actions Save As button',
timezone: 'Time zone picker select container',
title: 'Dashboard settings page title',
},
Variables: {
......
import { DeleteDashboardConfig } from './deleteDashboard';
import { e2e } from '../index';
import { getDashboardUid } from '../support/url';
import { selectOption } from './selectOption';
export interface AddDashboardConfig {
timezone: string;
title: string;
}
// @todo this actually returns type `Cypress.Chainable`
export const addDashboard = (config?: Partial<AddDashboardConfig>): any => {
const fullConfig = {
timezone: 'Coordinated Universal Time',
title: `e2e-${Date.now()}`,
...config,
} as AddDashboardConfig;
const { title } = fullConfig;
const { timezone, title } = fullConfig;
e2e().logToConsole('Adding dashboard with title:', title);
e2e.pages.AddDashboard.visit();
e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
selectOption(e2e.pages.Dashboard.Settings.General.timezone(), timezone);
e2e.pages.Dashboard.Settings.General.saveDashBoard().click();
e2e.pages.SaveDashboardAsModal.newName()
.clear()
......
import { e2e } from '../index';
import { getLocalStorage, requireLocalStorage } from '../support/localStorage';
import { getScenarioContext } from '../support/scenarioContext';
import { selectOption } from './selectOption';
export interface AddPanelConfig {
dashboardUid: string;
......@@ -26,7 +27,7 @@ export const addPanel = (config?: Partial<AddPanelConfig>): any =>
const { dashboardUid, dataSourceName, panelTitle, queriesForm, visualizationName } = fullConfig;
e2e.pages.Dashboard.visit(dashboardUid);
e2e.flows.openDashboard({ uid: dashboardUid });
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
e2e.pages.AddDashboard.addNewPanel().click();
......@@ -38,18 +39,7 @@ export const addPanel = (config?: Partial<AddPanelConfig>): any =>
.route('POST', '/api/ds/query')
.as('chartData');
e2e.components.DataSourcePicker.container().within(() => {
e2e()
.get('[class$="-input-suffix"]')
.click();
e2e.components.Select.option()
.filter(`:contains("${dataSourceName}")`)
.scrollIntoView()
.click();
e2e()
.root()
.scrollIntoView();
});
selectOption(e2e.components.DataSourcePicker.container(), dataSourceName);
// @todo instead wait for '@pluginModule'
e2e().wait(2000);
......
......@@ -9,6 +9,7 @@ import { openDashboard } from './openDashboard';
import { saveDashboard } from './saveDashboard';
import { openPanelMenuItem, PanelMenuItems } from './openPanelMenuItem';
import { revertAllChanges } from './revertAllChanges';
import { selectOption } from './selectOption';
export const Flows = {
addDashboard,
......@@ -23,4 +24,5 @@ export const Flows = {
openPanelMenuItem,
PanelMenuItems,
revertAllChanges,
selectOption,
};
import { e2e } from '../index';
import { getScenarioContext } from '../support/scenarioContext';
// @todo remove this, as it's a page change and not a flow
export const openDashboard = (dashboardUid: string) => {
e2e.pages.Dashboard.visit(dashboardUid);
};
export interface OpenDashboardConfig {
uid: string;
timeRange: {
from: string;
to: string;
};
}
export const openDashboard = (config?: Partial<OpenDashboardConfig>) =>
getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
const fullConfig = {
timeRange: {
from: '2020-01-01 00:00:00',
to: '2020-01-01 01:00:00',
},
uid: lastAddedDashboardUid,
...config,
} as OpenDashboardConfig;
const { timeRange, uid } = fullConfig;
e2e.pages.Dashboard.visit(uid);
e2e.pages.Dashboard.Toolbar.navBar().within(() => {
e2e()
.get('[aria-label="TimePicker Open Button"]')
.click();
e2e()
.get('[aria-label="TimePicker absolute time range"]')
.click();
e2e()
.get('[aria-label="TimePicker from field"]')
.clear()
.type(timeRange.from);
e2e()
.get('[aria-label="TimePicker to field"]')
.clear()
.type(timeRange.to);
e2e()
.get('[aria-label="TimePicker submit button"]')
.click();
});
// @todo remove `wrap` when possible
return e2e().wrap({ config: fullConfig });
});
import { e2e } from '../index';
// @todo this actually returns type `Cypress.Chainable`
export const selectOption = (select: any, optionText: string): any =>
select.within(() => {
e2e()
.get('[class$="-input-suffix"]')
.click();
e2e.components.Select.option()
.filter(`:contains("${optionText}")`)
.scrollIntoView()
.click();
e2e()
.root()
.scrollIntoView();
});
......@@ -200,7 +200,11 @@ const NarrowScreenForm: React.FC<FormProps> = props => {
return (
<>
<div className={styles.header} onClick={() => setCollapsed(!collapsed)}>
<div
aria-label="TimePicker absolute time range"
className={styles.header}
onClick={() => setCollapsed(!collapsed)}
>
<TimePickerTitle>Absolute time range</TimePickerTitle>
{<Icon name={collapsed ? 'angle-up' : 'angle-down'} />}
</div>
......@@ -239,7 +243,7 @@ const FullScreenForm: React.FC<FormProps> = props => {
return (
<>
<div className={styles.container}>
<div className={styles.title}>
<div aria-label="TimePicker absolute time range" className={styles.title}>
<TimePickerTitle>Absolute time range</TimePickerTitle>
</div>
<TimeRangeForm value={props.value} timeZone={props.timeZone} onApply={props.onChange} isFullscreen={true} />
......
......@@ -84,6 +84,7 @@ export const TimeRangeForm: React.FC<Props> = props => {
onFocus={onFocus}
onChange={event => setFrom(eventToState(event, false, timeZone))}
addonAfter={icon}
aria-label="TimePicker from field"
value={from.value}
/>
</Field>
......@@ -93,10 +94,13 @@ export const TimeRangeForm: React.FC<Props> = props => {
onFocus={onFocus}
onChange={event => setTo(eventToState(event, true, timeZone))}
addonAfter={icon}
aria-label="TimePicker to field"
value={to.value}
/>
</Field>
<Button onClick={onApply}>Apply time range</Button>
<Button aria-label="TimePicker submit button" onClick={onApply}>
Apply time range
</Button>
<TimePickerCalendar
isFullscreen={isFullscreen}
......
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