mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
@grafana/e2e: improvements (#27170)
* Minor changes * Changed default panel screenshot name * Removed default visualization type from `addPanel` config ... which, unless defined, will use the app's default (graph). This is the new approach for plugins which supports annotations. * Select timezone from dashboard toolbar instead of settings ... and refactored `setDashboardTimeRange` for reuse on other pages via a now more generalized `setTimeRange` * Added optional annotations to `addDashboard` config * Added `explore` flow … which reuses `configurePanel` which is very similar
This commit is contained in:
parent
46d7c3f814
commit
1a69bcfeff
@ -1,13 +1,19 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import { DashboardTimeRangeConfig, setDashboardTimeRange } from './setDashboardTimeRange';
|
|
||||||
import { DeleteDashboardConfig } from './deleteDashboard';
|
import { DeleteDashboardConfig } from './deleteDashboard';
|
||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
import { getDashboardUid } from '../support/url';
|
import { getDashboardUid } from '../support/url';
|
||||||
import { selectOption } from './selectOption';
|
import { setDashboardTimeRange, TimeRangeConfig } from './setDashboardTimeRange';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export interface AddAnnotationConfig {
|
||||||
|
dataSource: string;
|
||||||
|
name: string;
|
||||||
|
sources?: string;
|
||||||
|
tags?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AddDashboardConfig {
|
export interface AddDashboardConfig {
|
||||||
timeRange: DashboardTimeRangeConfig;
|
annotations: AddAnnotationConfig[];
|
||||||
timezone: string;
|
timeRange: TimeRangeConfig;
|
||||||
title: string;
|
title: string;
|
||||||
variables: Array<Partial<AddVariableConfig>>;
|
variables: Array<Partial<AddVariableConfig>>;
|
||||||
}
|
}
|
||||||
@ -15,7 +21,7 @@ export interface AddDashboardConfig {
|
|||||||
export interface AddVariableConfig {
|
export interface AddVariableConfig {
|
||||||
constantValue?: string;
|
constantValue?: string;
|
||||||
dataSource?: string;
|
dataSource?: string;
|
||||||
hide?: string;
|
hide: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
name: string;
|
name: string;
|
||||||
query?: string;
|
query?: string;
|
||||||
@ -27,40 +33,38 @@ export interface AddVariableConfig {
|
|||||||
// @todo this actually returns type `Cypress.Chainable`
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
export const addDashboard = (config?: Partial<AddDashboardConfig>): any => {
|
export const addDashboard = (config?: Partial<AddDashboardConfig>): any => {
|
||||||
const fullConfig = {
|
const fullConfig = {
|
||||||
timeRange: {
|
annotations: [],
|
||||||
from: '2020-01-01 00:00:00',
|
|
||||||
to: '2020-01-01 06:00:00',
|
|
||||||
},
|
|
||||||
timezone: 'Coordinated Universal Time',
|
|
||||||
title: `e2e-${uuidv4()}`,
|
title: `e2e-${uuidv4()}`,
|
||||||
variables: [],
|
variables: [],
|
||||||
...config,
|
...config,
|
||||||
|
timeRange: {
|
||||||
|
from: '2020-01-01 00:00:00',
|
||||||
|
to: '2020-01-01 06:00:00',
|
||||||
|
zone: 'Coordinated Universal Time',
|
||||||
|
...config?.timeRange,
|
||||||
|
},
|
||||||
} as AddDashboardConfig;
|
} as AddDashboardConfig;
|
||||||
|
|
||||||
const { timeRange, timezone, title, variables } = fullConfig;
|
const { annotations, timeRange, title, variables } = fullConfig;
|
||||||
|
|
||||||
e2e().logToConsole('Adding dashboard with title:', title);
|
e2e().logToConsole('Adding dashboard with title:', title);
|
||||||
|
|
||||||
e2e.pages.AddDashboard.visit();
|
e2e.pages.AddDashboard.visit();
|
||||||
|
|
||||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
if (annotations.length > 0 || variables.length > 0) {
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
// @todo use the time range picker's time zone control
|
addAnnotations(annotations);
|
||||||
selectOption(e2e.pages.Dashboard.Settings.General.timezone(), timezone);
|
addVariables(variables);
|
||||||
|
e2e.components.BackButton.backArrow().click();
|
||||||
addVariables(variables);
|
}
|
||||||
|
|
||||||
e2e.components.BackButton.backArrow().click();
|
|
||||||
|
|
||||||
setDashboardTimeRange(timeRange);
|
setDashboardTimeRange(timeRange);
|
||||||
|
|
||||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
|
||||||
|
|
||||||
e2e.pages.SaveDashboardAsModal.newName()
|
e2e.pages.SaveDashboardAsModal.newName()
|
||||||
.clear()
|
.clear()
|
||||||
.type(title);
|
.type(title);
|
||||||
e2e.pages.SaveDashboardAsModal.save().click();
|
e2e.pages.SaveDashboardAsModal.save().click();
|
||||||
|
|
||||||
e2e.flows.assertSuccessNotification();
|
e2e.flows.assertSuccessNotification();
|
||||||
|
|
||||||
e2e().logToConsole('Added dashboard with title:', title);
|
e2e().logToConsole('Added dashboard with title:', title);
|
||||||
@ -87,13 +91,74 @@ export const addDashboard = (config?: Partial<AddDashboardConfig>): any => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addAnnotation = (config: AddAnnotationConfig, isFirst: boolean) => {
|
||||||
|
if (isFirst) {
|
||||||
|
e2e.pages.Dashboard.Settings.Annotations.List.addAnnotationCTA().click();
|
||||||
|
} else {
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.btn', 'New')
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dataSource, name, sources, tags } = config;
|
||||||
|
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.gf-form', 'Data source')
|
||||||
|
.find('select')
|
||||||
|
.select(dataSource);
|
||||||
|
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.gf-form', 'Name')
|
||||||
|
.find('input')
|
||||||
|
.type(name);
|
||||||
|
|
||||||
|
if (sources) {
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.gf-form', 'Sources')
|
||||||
|
.find('input')
|
||||||
|
.type(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags) {
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.gf-form', 'Tags')
|
||||||
|
.find('input')
|
||||||
|
.type(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo add to e2e-selectors and `aria-label`
|
||||||
|
e2e()
|
||||||
|
.contains('.btn', 'Add')
|
||||||
|
.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
|
const addAnnotations = (configs: AddAnnotationConfig[]): any => {
|
||||||
|
if (configs.length > 0) {
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Annotations').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
return configs.map((config, i) => addAnnotation(config, i === 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VARIABLE_HIDE_LABEL = 'Label';
|
||||||
|
export const VARIABLE_HIDE_NOTHING = '';
|
||||||
|
export const VARIABLE_HIDE_VARIABLE = 'Variable';
|
||||||
|
|
||||||
export const VARIABLE_TYPE_AD_HOC_FILTERS = 'Ad hoc filters';
|
export const VARIABLE_TYPE_AD_HOC_FILTERS = 'Ad hoc filters';
|
||||||
export const VARIABLE_TYPE_CONSTANT = 'Constant';
|
export const VARIABLE_TYPE_CONSTANT = 'Constant';
|
||||||
export const VARIABLE_TYPE_DATASOURCE = 'Datasource';
|
export const VARIABLE_TYPE_DATASOURCE = 'Datasource';
|
||||||
export const VARIABLE_TYPE_QUERY = 'Query';
|
export const VARIABLE_TYPE_QUERY = 'Query';
|
||||||
|
|
||||||
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
const addVariable = (config: Partial<AddVariableConfig>, isFirst: boolean): any => {
|
const addVariable = (config: Partial<AddVariableConfig>, isFirst: boolean): any => {
|
||||||
const fullConfig = {
|
const fullConfig = {
|
||||||
|
hide: VARIABLE_HIDE_NOTHING,
|
||||||
type: VARIABLE_TYPE_QUERY,
|
type: VARIABLE_TYPE_QUERY,
|
||||||
...config,
|
...config,
|
||||||
} as AddVariableConfig;
|
} as AddVariableConfig;
|
||||||
@ -106,7 +171,13 @@ const addVariable = (config: Partial<AddVariableConfig>, isFirst: boolean): any
|
|||||||
|
|
||||||
const { constantValue, dataSource, hide, label, name, query, regex, type } = fullConfig;
|
const { constantValue, dataSource, hide, label, name, query, regex, type } = fullConfig;
|
||||||
|
|
||||||
if (hide) {
|
// This field is key to many reactive changes
|
||||||
|
if (type !== VARIABLE_TYPE_QUERY) {
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect().select(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid '', which is an accepted value
|
||||||
|
if (hide !== undefined) {
|
||||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().select(hide);
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().select(hide);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,10 +187,6 @@ const addVariable = (config: Partial<AddVariableConfig>, isFirst: boolean): any
|
|||||||
|
|
||||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().type(name);
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().type(name);
|
||||||
|
|
||||||
if (type !== VARIABLE_TYPE_QUERY) {
|
|
||||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect().select(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
dataSource &&
|
dataSource &&
|
||||||
(type === VARIABLE_TYPE_AD_HOC_FILTERS || type === VARIABLE_TYPE_DATASOURCE || type === VARIABLE_TYPE_QUERY)
|
(type === VARIABLE_TYPE_AD_HOC_FILTERS || type === VARIABLE_TYPE_DATASOURCE || type === VARIABLE_TYPE_QUERY)
|
||||||
@ -141,11 +208,26 @@ const addVariable = (config: Partial<AddVariableConfig>, isFirst: boolean): any
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid flakiness
|
||||||
|
e2e()
|
||||||
|
.focused()
|
||||||
|
.blur();
|
||||||
|
e2e()
|
||||||
|
.contains('.gf-form-group', 'Preview of values')
|
||||||
|
.within(() => {
|
||||||
|
if (type === VARIABLE_TYPE_CONSTANT) {
|
||||||
|
e2e()
|
||||||
|
.root()
|
||||||
|
.contains(constantValue as string);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.addButton().click();
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.addButton().click();
|
||||||
|
|
||||||
return fullConfig;
|
return fullConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
const addVariables = (configs: Array<Partial<AddVariableConfig>>): any => {
|
const addVariables = (configs: Array<Partial<AddVariableConfig>>): any => {
|
||||||
if (configs.length > 0) {
|
if (configs.length > 0) {
|
||||||
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import { DeleteDataSourceConfig } from './deleteDataSource';
|
import { DeleteDataSourceConfig } from './deleteDataSource';
|
||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
import { fromBaseUrl, getDataSourceId } from '../support/url';
|
import { fromBaseUrl, getDataSourceId } from '../support/url';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
export interface AddDataSourceConfig {
|
export interface AddDataSourceConfig {
|
||||||
basicAuth: boolean;
|
basicAuth: boolean;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import { configurePanel, ConfigurePanelConfig } from './configurePanel';
|
import { configurePanel, ConfigurePanelConfig } from './configurePanel';
|
||||||
import { getScenarioContext } from '../support/scenarioContext';
|
import { getScenarioContext } from '../support/scenarioContext';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
// @todo `Omit` 'isExplore'
|
||||||
export interface AddPanelConfig extends ConfigurePanelConfig {
|
export interface AddPanelConfig extends ConfigurePanelConfig {
|
||||||
dataSourceName: string;
|
dataSourceName: string;
|
||||||
queriesForm: (config: AddPanelConfig) => void;
|
queriesForm: (config: AddPanelConfig) => void;
|
||||||
panelTitle: string;
|
|
||||||
visualizationName: string;
|
visualizationName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,7 +17,6 @@ export const addPanel = (config?: Partial<AddPanelConfig>): any =>
|
|||||||
{
|
{
|
||||||
dataSourceName: lastAddedDataSource,
|
dataSourceName: lastAddedDataSource,
|
||||||
panelTitle: `e2e-${uuidv4()}`,
|
panelTitle: `e2e-${uuidv4()}`,
|
||||||
visualizationName: 'Table',
|
|
||||||
...config,
|
...config,
|
||||||
} as AddPanelConfig,
|
} as AddPanelConfig,
|
||||||
false
|
false
|
||||||
|
@ -2,6 +2,8 @@ import { e2e } from '../index';
|
|||||||
import { getLocalStorage, requireLocalStorage } from '../support/localStorage';
|
import { getLocalStorage, requireLocalStorage } from '../support/localStorage';
|
||||||
import { getScenarioContext } from '../support/scenarioContext';
|
import { getScenarioContext } from '../support/scenarioContext';
|
||||||
import { selectOption } from './selectOption';
|
import { selectOption } from './selectOption';
|
||||||
|
import { setDashboardTimeRange } from './setDashboardTimeRange';
|
||||||
|
import { setTimeRange, TimeRangeConfig } from './setTimeRange';
|
||||||
|
|
||||||
export interface ConfigurePanelConfig {
|
export interface ConfigurePanelConfig {
|
||||||
chartData: {
|
chartData: {
|
||||||
@ -10,17 +12,19 @@ export interface ConfigurePanelConfig {
|
|||||||
};
|
};
|
||||||
dashboardUid: string;
|
dashboardUid: string;
|
||||||
dataSourceName?: string;
|
dataSourceName?: string;
|
||||||
|
isExplore: boolean;
|
||||||
matchScreenshot: boolean;
|
matchScreenshot: boolean;
|
||||||
queriesForm?: (config: any) => void;
|
queriesForm?: (config: any) => void;
|
||||||
panelTitle: string;
|
panelTitle: string;
|
||||||
screenshotName: string;
|
screenshotName: string;
|
||||||
|
timeRange?: TimeRangeConfig;
|
||||||
visitDashboardAtStart: boolean; // @todo remove when possible
|
visitDashboardAtStart: boolean; // @todo remove when possible
|
||||||
visualizationName?: string;
|
visualizationName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo improve config input/output: https://stackoverflow.com/a/63507459/923745
|
// @todo improve config input/output: https://stackoverflow.com/a/63507459/923745
|
||||||
// @todo this actually returns type `Cypress.Chainable`
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: boolean): any =>
|
export const configurePanel = (config: Partial<ConfigurePanelConfig>, isEdit: boolean): any =>
|
||||||
getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
|
getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
|
||||||
const fullConfig = {
|
const fullConfig = {
|
||||||
chartData: {
|
chartData: {
|
||||||
@ -28,9 +32,10 @@ export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: bool
|
|||||||
route: '/api/ds/query',
|
route: '/api/ds/query',
|
||||||
},
|
},
|
||||||
dashboardUid: lastAddedDashboardUid,
|
dashboardUid: lastAddedDashboardUid,
|
||||||
|
isExplore: false,
|
||||||
matchScreenshot: false,
|
matchScreenshot: false,
|
||||||
saveDashboard: true,
|
saveDashboard: true,
|
||||||
screenshotName: 'chart',
|
screenshotName: 'panel-visualization',
|
||||||
visitDashboardAtStart: true,
|
visitDashboardAtStart: true,
|
||||||
...config,
|
...config,
|
||||||
} as ConfigurePanelConfig;
|
} as ConfigurePanelConfig;
|
||||||
@ -39,24 +44,38 @@ export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: bool
|
|||||||
chartData,
|
chartData,
|
||||||
dashboardUid,
|
dashboardUid,
|
||||||
dataSourceName,
|
dataSourceName,
|
||||||
|
isExplore,
|
||||||
matchScreenshot,
|
matchScreenshot,
|
||||||
panelTitle,
|
panelTitle,
|
||||||
queriesForm,
|
queriesForm,
|
||||||
screenshotName,
|
screenshotName,
|
||||||
|
timeRange,
|
||||||
visitDashboardAtStart,
|
visitDashboardAtStart,
|
||||||
visualizationName,
|
visualizationName,
|
||||||
} = fullConfig;
|
} = fullConfig;
|
||||||
|
|
||||||
if (visitDashboardAtStart) {
|
if (isExplore) {
|
||||||
e2e.flows.openDashboard({ uid: dashboardUid });
|
e2e.pages.Explore.visit();
|
||||||
|
} else {
|
||||||
|
if (visitDashboardAtStart) {
|
||||||
|
e2e.flows.openDashboard({ uid: dashboardUid });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEdit) {
|
||||||
|
e2e.components.Panels.Panel.title(panelTitle).click();
|
||||||
|
e2e.components.Panels.Panel.headerItems('Edit').click();
|
||||||
|
} else {
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
||||||
|
e2e.pages.AddDashboard.addNewPanel().click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edit) {
|
if (timeRange) {
|
||||||
e2e.components.Panels.Panel.title(panelTitle).click();
|
if (isExplore) {
|
||||||
e2e.components.Panels.Panel.headerItems('Edit').click();
|
e2e.pages.Explore.Toolbar.navBar().within(() => setTimeRange(timeRange));
|
||||||
} else {
|
} else {
|
||||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
setDashboardTimeRange(timeRange);
|
||||||
e2e.pages.AddDashboard.addNewPanel().click();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e2e().server();
|
e2e().server();
|
||||||
@ -76,39 +95,46 @@ export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: bool
|
|||||||
|
|
||||||
e2e().wait('@chartData');
|
e2e().wait('@chartData');
|
||||||
|
|
||||||
// `panelTitle` is needed to edit the panel, and unlikely to have its value changed at that point
|
if (!isExplore) {
|
||||||
const changeTitle = panelTitle && !edit;
|
// `panelTitle` is needed to edit the panel, and unlikely to have its value changed at that point
|
||||||
|
const changeTitle = panelTitle && !isEdit;
|
||||||
|
|
||||||
if (changeTitle || visualizationName) {
|
if (changeTitle || visualizationName) {
|
||||||
openOptions();
|
openOptions();
|
||||||
|
|
||||||
if (changeTitle) {
|
if (changeTitle) {
|
||||||
openOptionsGroup('settings');
|
openOptionsGroup('settings');
|
||||||
getOptionsGroup('settings')
|
getOptionsGroup('settings')
|
||||||
.find('[value="Panel Title"]')
|
.find('[value="Panel Title"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.clear()
|
.clear()
|
||||||
.type(panelTitle);
|
.type(panelTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visualizationName) {
|
||||||
|
openOptionsGroup('type');
|
||||||
|
e2e.components.PluginVisualization.item(visualizationName)
|
||||||
|
.scrollIntoView()
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consistently closed
|
||||||
closeOptionsGroup('settings');
|
closeOptionsGroup('settings');
|
||||||
}
|
|
||||||
|
|
||||||
if (visualizationName) {
|
|
||||||
openOptionsGroup('type');
|
|
||||||
e2e.components.PluginVisualization.item(visualizationName)
|
|
||||||
.scrollIntoView()
|
|
||||||
.click();
|
|
||||||
closeOptionsGroup('type');
|
closeOptionsGroup('type');
|
||||||
|
closeOptions();
|
||||||
|
} else {
|
||||||
|
// Consistently closed
|
||||||
|
closeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeOptions();
|
|
||||||
} else {
|
|
||||||
// Options are consistently closed
|
|
||||||
closeOptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queriesForm) {
|
if (queriesForm) {
|
||||||
queriesForm(fullConfig);
|
queriesForm(fullConfig);
|
||||||
e2e().wait('@chartData');
|
e2e().wait('@chartData');
|
||||||
|
|
||||||
|
// Wait for a possible complex visualization to render (or something related, as this isn't necessary on the dashboard page)
|
||||||
|
// Can't assert that its HTML changed because a new query could produce the same results
|
||||||
|
e2e().wait(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo enable when plugins have this implemented
|
// @todo enable when plugins have this implemented
|
||||||
@ -118,13 +144,20 @@ export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: bool
|
|||||||
//e2e.components.QueryEditorRow.actionButton('Disable/enable query').click();
|
//e2e.components.QueryEditorRow.actionButton('Disable/enable query').click();
|
||||||
//e2e().wait('@chartData');
|
//e2e().wait('@chartData');
|
||||||
|
|
||||||
e2e()
|
if (!isExplore) {
|
||||||
.get('button[title="Apply changes and go back to dashboard"]')
|
e2e()
|
||||||
.click();
|
.get('button[title="Apply changes and go back to dashboard"]')
|
||||||
|
.click();
|
||||||
|
e2e()
|
||||||
|
.url()
|
||||||
|
.should('include', `/d/${dashboardUid}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid annotations flakiness
|
||||||
e2e()
|
e2e()
|
||||||
.url()
|
.get('.refresh-picker-buttons .btn')
|
||||||
.should('include', `/d/${dashboardUid}`);
|
.first()
|
||||||
|
.click();
|
||||||
|
|
||||||
e2e().wait('@chartData');
|
e2e().wait('@chartData');
|
||||||
|
|
||||||
@ -132,9 +165,15 @@ export const configurePanel = (config: Partial<ConfigurePanelConfig>, edit: bool
|
|||||||
e2e().wait(500);
|
e2e().wait(500);
|
||||||
|
|
||||||
if (matchScreenshot) {
|
if (matchScreenshot) {
|
||||||
e2e.components.Panels.Panel.containerByTitle(panelTitle)
|
let visualization;
|
||||||
.find('.panel-content')
|
|
||||||
.screenshot(screenshotName);
|
if (isExplore) {
|
||||||
|
visualization = e2e.pages.Explore.General.graph();
|
||||||
|
} else {
|
||||||
|
visualization = e2e.components.Panels.Panel.containerByTitle(panelTitle).find('.panel-content');
|
||||||
|
}
|
||||||
|
|
||||||
|
visualization.scrollIntoView().screenshot(screenshotName);
|
||||||
e2e().compareScreenshots(screenshotName);
|
e2e().compareScreenshots(screenshotName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,3 +238,20 @@ const toggleOptionsGroup = (name: string) =>
|
|||||||
getOptionsGroup(name)
|
getOptionsGroup(name)
|
||||||
.find('.editor-options-group-toggle')
|
.find('.editor-options-group-toggle')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
export const VISUALIZATION_ALERT_LIST = 'Alert list';
|
||||||
|
export const VISUALIZATION_BAR_GAUGE = 'Bar gauge';
|
||||||
|
export const VISUALIZATION_CLOCK = 'Clock';
|
||||||
|
export const VISUALIZATION_DASHBOARD_LIST = 'Dashboard list';
|
||||||
|
export const VISUALIZATION_GAUGE = 'Gauge';
|
||||||
|
export const VISUALIZATION_GRAPH = 'Graph';
|
||||||
|
export const VISUALIZATION_HEAT_MAP = 'Heatmap';
|
||||||
|
export const VISUALIZATION_LOGS = 'Logs';
|
||||||
|
export const VISUALIZATION_NEWS = 'News';
|
||||||
|
export const VISUALIZATION_PIE_CHART = 'Pie Chart';
|
||||||
|
export const VISUALIZATION_PLUGIN_LIST = 'Plugin list';
|
||||||
|
export const VISUALIZATION_POLYSTAT = 'Polystat';
|
||||||
|
export const VISUALIZATION_STAT = 'Stat';
|
||||||
|
export const VISUALIZATION_TABLE = 'Table';
|
||||||
|
export const VISUALIZATION_TEXT = 'Text';
|
||||||
|
export const VISUALIZATION_WORLD_MAP = 'Worldmap Panel';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { configurePanel, ConfigurePanelConfig } from './configurePanel';
|
import { configurePanel, ConfigurePanelConfig } from './configurePanel';
|
||||||
|
|
||||||
|
// @todo `Omit` 'isExplore'
|
||||||
export interface EditPanelConfig extends ConfigurePanelConfig {
|
export interface EditPanelConfig extends ConfigurePanelConfig {
|
||||||
queriesForm?: (config: EditPanelConfig) => void;
|
queriesForm?: (config: EditPanelConfig) => void;
|
||||||
}
|
}
|
||||||
|
28
packages/grafana-e2e/src/flows/explore.ts
Normal file
28
packages/grafana-e2e/src/flows/explore.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { configurePanel, ConfigurePanelConfig } from './configurePanel';
|
||||||
|
import { getScenarioContext } from '../support/scenarioContext';
|
||||||
|
|
||||||
|
// @todo `Omit` 'dashboardUid' and 'panelTitle'
|
||||||
|
export interface ExploreConfig extends ConfigurePanelConfig {
|
||||||
|
queriesForm: (config: ExploreConfig) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo improve config input/output: https://stackoverflow.com/a/63507459/923745
|
||||||
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
|
export const explore = (config: Partial<ExploreConfig>): any =>
|
||||||
|
getScenarioContext().then(({ lastAddedDataSource }: any) =>
|
||||||
|
configurePanel(
|
||||||
|
{
|
||||||
|
dataSourceName: lastAddedDataSource,
|
||||||
|
isExplore: true,
|
||||||
|
screenshotName: 'explore-graph',
|
||||||
|
...config,
|
||||||
|
timeRange: {
|
||||||
|
from: '2020-01-01 00:00:00',
|
||||||
|
to: '2020-01-01 06:00:00',
|
||||||
|
zone: 'Coordinated Universal Time',
|
||||||
|
...config.timeRange,
|
||||||
|
},
|
||||||
|
} as ExploreConfig,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
@ -5,9 +5,29 @@ export * from './assertSuccessNotification';
|
|||||||
export * from './deleteDashboard';
|
export * from './deleteDashboard';
|
||||||
export * from './deleteDataSource';
|
export * from './deleteDataSource';
|
||||||
export * from './editPanel';
|
export * from './editPanel';
|
||||||
|
export * from './explore';
|
||||||
export * from './login';
|
export * from './login';
|
||||||
export * from './openDashboard';
|
export * from './openDashboard';
|
||||||
export * from './openPanelMenuItem';
|
export * from './openPanelMenuItem';
|
||||||
export * from './revertAllChanges';
|
export * from './revertAllChanges';
|
||||||
export * from './saveDashboard';
|
export * from './saveDashboard';
|
||||||
export * from './selectOption';
|
export * from './selectOption';
|
||||||
|
|
||||||
|
export {
|
||||||
|
VISUALIZATION_ALERT_LIST,
|
||||||
|
VISUALIZATION_BAR_GAUGE,
|
||||||
|
VISUALIZATION_CLOCK,
|
||||||
|
VISUALIZATION_DASHBOARD_LIST,
|
||||||
|
VISUALIZATION_GAUGE,
|
||||||
|
VISUALIZATION_GRAPH,
|
||||||
|
VISUALIZATION_HEAT_MAP,
|
||||||
|
VISUALIZATION_LOGS,
|
||||||
|
VISUALIZATION_NEWS,
|
||||||
|
VISUALIZATION_PIE_CHART,
|
||||||
|
VISUALIZATION_PLUGIN_LIST,
|
||||||
|
VISUALIZATION_POLYSTAT,
|
||||||
|
VISUALIZATION_STAT,
|
||||||
|
VISUALIZATION_TABLE,
|
||||||
|
VISUALIZATION_TEXT,
|
||||||
|
VISUALIZATION_WORLD_MAP,
|
||||||
|
} from './configurePanel';
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { DashboardTimeRangeConfig, setDashboardTimeRange } from './setDashboardTimeRange';
|
|
||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
import { getScenarioContext } from '../support/scenarioContext';
|
import { getScenarioContext } from '../support/scenarioContext';
|
||||||
|
import { setDashboardTimeRange, TimeRangeConfig } from './setDashboardTimeRange';
|
||||||
|
|
||||||
export interface OpenDashboardConfig {
|
export interface OpenDashboardConfig {
|
||||||
timeRange?: DashboardTimeRangeConfig;
|
timeRange?: TimeRangeConfig;
|
||||||
uid: string;
|
uid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
|
|
||||||
// @todo this actually returns type `Cypress.Chainable`
|
// @todo this actually returns type `Cypress.Chainable`
|
||||||
export const selectOption = (select: any, optionText: string): any =>
|
export const selectOption = (select: any, optionText: string, clickToOpen = true): any =>
|
||||||
select.within(() => {
|
select.within(() => {
|
||||||
e2e()
|
if (clickToOpen) {
|
||||||
.get('[class$="-input-suffix"]')
|
e2e()
|
||||||
.click();
|
.get('[class$="-input-suffix"]')
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
|
||||||
e2e.components.Select.option()
|
e2e.components.Select.option()
|
||||||
.filter(`:contains("${optionText}")`)
|
.filter(`:contains("${optionText}")`)
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
|
@ -1,27 +1,7 @@
|
|||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
|
import { setTimeRange, TimeRangeConfig } from './setTimeRange';
|
||||||
|
|
||||||
export interface DashboardTimeRangeConfig {
|
export { TimeRangeConfig };
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setDashboardTimeRange = ({ from, to }: DashboardTimeRangeConfig) =>
|
export const setDashboardTimeRange = (config: TimeRangeConfig) =>
|
||||||
e2e.pages.Dashboard.Toolbar.navBar().within(() => {
|
e2e.pages.Dashboard.Toolbar.navBar().within(() => setTimeRange(config));
|
||||||
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(from);
|
|
||||||
e2e()
|
|
||||||
.get('[aria-label="TimePicker to field"]')
|
|
||||||
.clear()
|
|
||||||
.type(to);
|
|
||||||
e2e()
|
|
||||||
.get('[aria-label="TimePicker submit button"]')
|
|
||||||
.click();
|
|
||||||
});
|
|
||||||
|
38
packages/grafana-e2e/src/flows/setTimeRange.ts
Normal file
38
packages/grafana-e2e/src/flows/setTimeRange.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { e2e } from '../index';
|
||||||
|
import { selectOption } from './selectOption';
|
||||||
|
|
||||||
|
export interface TimeRangeConfig {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
zone?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setTimeRange = ({ from, to, zone }: TimeRangeConfig) => {
|
||||||
|
e2e()
|
||||||
|
.get('[aria-label="TimePicker Open Button"]')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
if (zone) {
|
||||||
|
e2e()
|
||||||
|
.contains('button', 'Change time zone')
|
||||||
|
.click();
|
||||||
|
selectOption(e2e.components.TimeZonePicker.container(), zone, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For smaller screens
|
||||||
|
e2e()
|
||||||
|
.get('[aria-label="TimePicker absolute time range"]')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
e2e()
|
||||||
|
.get('[aria-label="TimePicker from field"]')
|
||||||
|
.clear()
|
||||||
|
.type(from);
|
||||||
|
e2e()
|
||||||
|
.get('[aria-label="TimePicker to field"]')
|
||||||
|
.clear()
|
||||||
|
.type(to);
|
||||||
|
e2e()
|
||||||
|
.get('[aria-label="TimePicker submit button"]')
|
||||||
|
.click();
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user