Commit 841cffbe by Hugo Häggmark Committed by GitHub

e2e: Migrates query variable CRUD tests to new framework (#21146)

* Refactor: Adds params to visit

* Refactor: Restructures exported Pages somewhat

* Refactor: Moves more into new framework but holdup because of bugs in digest

* Refactor: Finish migrating templating e2e tests to new framework

* Refactor: Changes after merge with master

* Refactor: Removes weird change

* Refactor: Adds duplication test

* Refactor: Adds move down and move up variable asserts

* Refactor: Adds some test to value select dropdown
parent 331bc173
import { e2e } from '../index'; import { e2e } from '../index';
export const saveDashboard = () => { export const saveDashboard = () => {
e2e.pages.Dashboard.toolbarItems('Save dashboard').click(); e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
e2e.pages.SaveDashboardModal.save().click(); e2e.pages.SaveDashboardModal.save().click();
......
import { e2e } from '../index'; import { e2e } from '../index';
export const saveNewDashboard = () => { export const saveNewDashboard = () => {
e2e.pages.Dashboard.toolbarItems('Save dashboard').click(); e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
const dashboardTitle = `e2e-${new Date().getTime()}`; const dashboardTitle = `e2e-${new Date().getTime()}`;
e2e.pages.SaveDashboardAsModal.newName().clear(); e2e.pages.SaveDashboardAsModal.newName().clear();
......
...@@ -8,9 +8,9 @@ import { Pages } from './pages'; ...@@ -8,9 +8,9 @@ import { Pages } from './pages';
import { Flows } from './flows'; import { Flows } from './flows';
import { scenarioContext } from './support/scenarioContext'; import { scenarioContext } from './support/scenarioContext';
export type SelectorFunction = (text?: string) => Cypress.Chainable<any>; export type SelectorFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>;
export type SelectorObject<S> = { export type SelectorObject<S> = {
visit: (args?: string) => Cypress.Chainable<any>; visit: (args?: string) => Cypress.Chainable<Window>;
selectors: S; selectors: S;
}; };
......
...@@ -5,5 +5,6 @@ export const Dashboard = pageFactory({ ...@@ -5,5 +5,6 @@ export const Dashboard = pageFactory({
selectors: { selectors: {
toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`, toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`,
backArrow: 'Dashboard settings Go Back button', backArrow: 'Dashboard settings Go Back button',
navBar: () => '.navbar',
}, },
}); });
...@@ -4,7 +4,7 @@ export const DashboardSettings = pageFactory({ ...@@ -4,7 +4,7 @@ export const DashboardSettings = pageFactory({
url: '', url: '',
selectors: { selectors: {
deleteDashBoard: 'Dashboard settings page delete dashboard button', deleteDashBoard: 'Dashboard settings page delete dashboard button',
sectionItems: 'Dashboard settings section item', sectionItems: (item: string) => `Dashboard settings section item ${item}`,
saveDashBoard: 'Dashboard settings aside actions Save button', saveDashBoard: 'Dashboard settings aside actions Save button',
saveAsDashBoard: 'Dashboard settings aside actions Save As button', saveAsDashBoard: 'Dashboard settings aside actions Save As button',
}, },
......
...@@ -14,6 +14,7 @@ import { Graph } from './graph'; ...@@ -14,6 +14,7 @@ import { Graph } from './graph';
import { SaveDashboardModal } from './saveDashboardModal'; import { SaveDashboardModal } from './saveDashboardModal';
import { Panel } from './panel'; import { Panel } from './panel';
import { SharePanelModal } from './sharePanelModal'; import { SharePanelModal } from './sharePanelModal';
import { ConstantVariable, QueryVariable, VariableGeneral, Variables, VariablesSubMenu } from './variables';
export const Pages = { export const Pages = {
Login, Login,
...@@ -22,20 +23,34 @@ export const Pages = { ...@@ -22,20 +23,34 @@ export const Pages = {
AddDataSource, AddDataSource,
ConfirmModal, ConfirmModal,
AddDashboard, AddDashboard,
Dashboard, Dashboard: {
visit: (uid: string) => Dashboard.visit(uid),
Toolbar: Dashboard,
SubMenu: VariablesSubMenu,
Settings: {
General: DashboardSettings,
Variables: {
List: Variables,
Edit: {
General: VariableGeneral,
QueryVariable: QueryVariable,
ConstantVariable: ConstantVariable,
},
},
},
Panels: {
Panel,
EditPanel,
DataSource: {
TestData,
},
Visualization: {
Graph,
},
},
},
Dashboards, Dashboards,
SaveDashboardAsModal, SaveDashboardAsModal,
SaveDashboardModal, SaveDashboardModal,
DashboardSettings,
SharePanelModal, SharePanelModal,
Panels: {
Panel,
EditPanel,
DataSource: {
TestData,
},
Visualization: {
Graph,
},
},
}; };
import { pageFactory } from '../support';
export const Variables = pageFactory({
url: '',
selectors: {
addVariableCTA: 'Call to action button Add variable',
newButton: 'Variable editor New variable button',
table: 'Variable editor Table',
tableRowNameFields: (variableName: string) => `Variable editor Table Name field ${variableName}`,
tableRowDefinitionFields: (variableName: string) => `Variable editor Table Definition field ${variableName}`,
tableRowArrowUpButtons: (variableName: string) => `Variable editor Table ArrowUp button ${variableName}`,
tableRowArrowDownButtons: (variableName: string) => `Variable editor Table ArrowDown button ${variableName}`,
tableRowDuplicateButtons: (variableName: string) => `Variable editor Table Duplicate button ${variableName}`,
tableRowRemoveButtons: (variableName: string) => `Variable editor Table Remove button ${variableName}`,
},
});
export const VariablesSubMenu = pageFactory({
url: '',
selectors: {
submenuItem: 'Dashboard template variables submenu item',
submenuItemLabels: (item: string) => `Dashboard template variables submenu Label ${item}`,
submenuItemValueDropDownValueLinkTexts: (item: string) =>
`Dashboard template variables Variable Value DropDown value link text ${item}`,
submenuItemValueDropDownDropDown: 'Dashboard template variables Variable Value DropDown DropDown',
submenuItemValueDropDownOptionTexts: (item: string) =>
`Dashboard template variables Variable Value DropDown option text ${item}`,
},
});
export const VariableGeneral = pageFactory({
url: '',
selectors: {
headerLink: 'Variable editor Header link',
modeLabelNew: 'Variable editor Header mode New',
modeLabelEdit: 'Variable editor Header mode Edit',
generalNameInput: 'Variable editor Form Name field',
generalTypeSelect: 'Variable editor Form Type select',
generalLabelInput: 'Variable editor Form Label field',
generalHideSelect: 'Variable editor Form Hide select',
selectionOptionsMultiSwitch: 'Variable editor Form Multi switch',
selectionOptionsIncludeAllSwitch: 'Variable editor Form IncludeAll switch',
selectionOptionsCustomAllInput: 'Variable editor Form IncludeAll field',
previewOfValuesOption: 'Variable editor Preview of Values option',
addButton: 'Variable editor Add button',
updateButton: 'Variable editor Update button',
},
});
export const QueryVariable = pageFactory({
url: '',
selectors: {
queryOptionsDataSourceSelect: 'Variable editor Form Query DataSource select',
queryOptionsRefreshSelect: 'Variable editor Form Query Refresh select',
queryOptionsRegExInput: 'Variable editor Form Query RegEx field',
queryOptionsSortSelect: 'Variable editor Form Query Sort select',
queryOptionsQueryInput: 'Variable editor Form Default Variable Query Editor textarea',
valueGroupsTagsEnabledSwitch: 'Variable editor Form Query UseTags switch',
valueGroupsTagsTagsQueryInput: 'Variable editor Form Query TagsQuery field',
valueGroupsTagsTagsValuesQueryInput: 'Variable editor Form Query TagsValuesQuery field',
},
});
export const ConstantVariable = pageFactory({
url: '',
selectors: {
constantOptionsQueryInput: 'Variable editor Form Constant Query field',
},
});
...@@ -5,6 +5,7 @@ import filter from 'lodash/filter'; ...@@ -5,6 +5,7 @@ import filter from 'lodash/filter';
import find from 'lodash/find'; import find from 'lodash/find';
import indexOf from 'lodash/indexOf'; import indexOf from 'lodash/indexOf';
import map from 'lodash/map'; import map from 'lodash/map';
import { e2e } from '@grafana/e2e';
import coreModule from '../core_module'; import coreModule from '../core_module';
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl'; import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
...@@ -26,11 +27,13 @@ export class ValueSelectDropdownCtrl { ...@@ -26,11 +27,13 @@ export class ValueSelectDropdownCtrl {
onUpdated: any; onUpdated: any;
queryHasSearchFilter: boolean; queryHasSearchFilter: boolean;
debouncedQueryChanged: Function; debouncedQueryChanged: Function;
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
/** @ngInject */ /** @ngInject */
constructor(private $scope: IScope) { constructor(private $scope: IScope) {
this.queryHasSearchFilter = this.variable ? containsSearchFilter(this.variable.query) : false; this.queryHasSearchFilter = this.variable ? containsSearchFilter(this.variable.query) : false;
this.debouncedQueryChanged = debounce(this.queryChanged.bind(this), 200); this.debouncedQueryChanged = debounce(this.queryChanged.bind(this), 200);
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
} }
show() { show() {
......
...@@ -160,7 +160,7 @@ export class DashNav extends PureComponent<Props> { ...@@ -160,7 +160,7 @@ export class DashNav extends PureComponent<Props> {
<button <button
className="navbar-edit__back-btn" className="navbar-edit__back-btn"
onClick={this.onClose} onClick={this.onClose}
aria-label={e2e.pages.Dashboard.selectors.backArrow} aria-label={e2e.pages.Dashboard.Toolbar.selectors.backArrow}
> >
<i className="fa fa-arrow-left" /> <i className="fa fa-arrow-left" />
</button> </button>
......
...@@ -19,7 +19,7 @@ export const DashNavButton: FunctionComponent<Props> = ({ icon, tooltip, classSu ...@@ -19,7 +19,7 @@ export const DashNavButton: FunctionComponent<Props> = ({ icon, tooltip, classSu
<button <button
className={`btn navbar-button navbar-button--${classSuffix}`} className={`btn navbar-button navbar-button--${classSuffix}`}
onClick={onClick} onClick={onClick}
aria-label={e2e.pages.Dashboard.selectors.toolbarItems(tooltip)} aria-label={e2e.pages.Dashboard.Toolbar.selectors.toolbarItems(tooltip)}
> >
<i className={icon} /> <i className={icon} />
</button> </button>
......
...@@ -22,7 +22,7 @@ export class SettingsCtrl { ...@@ -22,7 +22,7 @@ export class SettingsCtrl {
canDelete: boolean; canDelete: boolean;
sections: any[]; sections: any[];
hasUnsavedFolderChange: boolean; hasUnsavedFolderChange: boolean;
selectors: typeof e2e.pages.DashboardSettings.selectors; selectors: typeof e2e.pages.Dashboard.Settings.General.selectors;
/** @ngInject */ /** @ngInject */
constructor( constructor(
...@@ -55,7 +55,7 @@ export class SettingsCtrl { ...@@ -55,7 +55,7 @@ export class SettingsCtrl {
this.$rootScope.onAppEvent(CoreEvents.routeUpdated, this.onRouteUpdated.bind(this), $scope); this.$rootScope.onAppEvent(CoreEvents.routeUpdated, this.onRouteUpdated.bind(this), $scope);
this.$rootScope.appEvent(CoreEvents.dashScroll, { animate: false, pos: 0 }); this.$rootScope.appEvent(CoreEvents.dashScroll, { animate: false, pos: 0 });
this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope); this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope);
this.selectors = e2e.pages.DashboardSettings.selectors; this.selectors = e2e.pages.Dashboard.Settings.General.selectors;
} }
buildSectionList() { buildSectionList() {
......
<aside class="dashboard-settings__aside"> <aside class="dashboard-settings__aside">
<a href="{{::section.url}}" class="dashboard-settings__nav-item" ng-class="{active: ctrl.viewId === section.id}" ng-repeat="section in ctrl.sections" aria-label={{ctrl.selectors.sectionItems}}> <a href="{{::section.url}}" class="dashboard-settings__nav-item" ng-class="{active: ctrl.viewId === section.id}" ng-repeat="section in ctrl.sections" aria-label={{ctrl.selectors.sectionItems(section.title)}}>
<i class="{{::section.icon}}"></i> <i class="{{::section.icon}}"></i>
{{::section.title}} {{::section.title}}
</a> </a>
......
import angular, { ILocationService } from 'angular'; import angular, { ILocationService } from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import { e2e } from '@grafana/e2e';
import { VariableSrv } from 'app/features/templating/all'; import { VariableSrv } from 'app/features/templating/all';
import { CoreEvents } from '../../../../types'; import { CoreEvents } from '../../../../types';
...@@ -8,6 +9,7 @@ export class SubMenuCtrl { ...@@ -8,6 +9,7 @@ export class SubMenuCtrl {
variables: any; variables: any;
dashboard: any; dashboard: any;
submenuEnabled: boolean; submenuEnabled: boolean;
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
/** @ngInject */ /** @ngInject */
constructor(private variableSrv: VariableSrv, private $location: ILocationService) { constructor(private variableSrv: VariableSrv, private $location: ILocationService) {
...@@ -17,6 +19,7 @@ export class SubMenuCtrl { ...@@ -17,6 +19,7 @@ export class SubMenuCtrl {
this.dashboard.events.on(CoreEvents.submenuVisibilityChanged, (enabled: boolean) => { this.dashboard.events.on(CoreEvents.submenuVisibilityChanged, (enabled: boolean) => {
this.submenuEnabled = enabled; this.submenuEnabled = enabled;
}); });
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
} }
annotationStateChanged() { annotationStateChanged() {
......
<div class="submenu-controls" ng-hide="ctrl.submenuEnabled === false"> <div class="submenu-controls" ng-hide="ctrl.submenuEnabled === false">
<div ng-repeat="variable in ctrl.variables" ng-hide="variable.hide === 2" class="submenu-item gf-form-inline"> <div
ng-repeat="variable in ctrl.variables"
ng-hide="variable.hide === 2"
class="submenu-item gf-form-inline"
aria-label="{{::ctrl.selectors.submenuItem}}"
>
<div class="gf-form"> <div class="gf-form">
<label <label
class="gf-form-label template-variable" class="gf-form-label template-variable"
ng-hide="variable.hide === 1" ng-hide="variable.hide === 1"
aria-label="Dashboard template variables submenu LabelName label" aria-label="{{ctrl.selectors.submenuItemLabels(variable.label || variable.name)}}"
>{{variable.label || variable.name}}</label> >{{variable.label || variable.name}}</label
<value-select-dropdown ng-if="variable.type !== 'adhoc' && variable.type !== 'textbox'" dashboard="ctrl.dashboard" variable="variable" on-updated="ctrl.variableUpdated(variable)"></value-select-dropdown> >
<input type="text" ng-if="variable.type === 'textbox'" ng-model="variable.query" class="gf-form-input width-12" ng-blur="variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);" ng-keydown="$event.keyCode === 13 && variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);" ></input> <value-select-dropdown
ng-if="variable.type !== 'adhoc' && variable.type !== 'textbox'"
dashboard="ctrl.dashboard"
variable="variable"
on-updated="ctrl.variableUpdated(variable)"
></value-select-dropdown>
<input
type="text"
ng-if="variable.type === 'textbox'"
ng-model="variable.query"
class="gf-form-input width-12"
ng-blur="variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);"
ng-keydown="$event.keyCode === 13 && variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);"
/>
</div> </div>
<ad-hoc-filters ng-if="variable.type === 'adhoc'" variable="variable" dashboard="ctrl.dashboard"></ad-hoc-filters> <ad-hoc-filters ng-if="variable.type === 'adhoc'" variable="variable" dashboard="ctrl.dashboard"></ad-hoc-filters>
</div> </div>
<div ng-if="ctrl.dashboard.annotations.list.length > 0"> <div ng-if="ctrl.dashboard.annotations.list.length > 0">
<div ng-repeat="annotation in ctrl.dashboard.annotations.list" ng-hide="annotation.hide" class="submenu-item" ng-class="{'annotation-disabled': !annotation.enable}"> <div
<gf-form-switch class="gf-form" label="{{annotation.name}}" checked="annotation.enable" on-change="ctrl.annotationStateChanged()"></gf-form-switch> ng-repeat="annotation in ctrl.dashboard.annotations.list"
ng-hide="annotation.hide"
class="submenu-item"
ng-class="{'annotation-disabled': !annotation.enable}"
>
<gf-form-switch
class="gf-form"
label="{{annotation.name}}"
checked="annotation.enable"
on-change="ctrl.annotationStateChanged()"
></gf-form-switch>
</div> </div>
</div> </div>
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow"></div>
</div>
<div ng-if="ctrl.dashboard.links.length > 0" > <div ng-if="ctrl.dashboard.links.length > 0">
<dash-links-container links="ctrl.dashboard.links" dashboard="ctrl.dashboard" class="gf-form-inline"></dash-links-container> <dash-links-container
links="ctrl.dashboard.links"
dashboard="ctrl.dashboard"
class="gf-form-inline"
></dash-links-container>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
......
...@@ -96,7 +96,7 @@ export class PanelHeader extends Component<Props, State> { ...@@ -96,7 +96,7 @@ export class PanelHeader extends Component<Props, State> {
className="panel-title-container" className="panel-title-container"
onClick={this.onMenuToggle} onClick={this.onMenuToggle}
onMouseDown={this.onMouseDown} onMouseDown={this.onMouseDown}
aria-label={e2e.pages.Panels.Panel.selectors.title(title)} aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.title(title)}
> >
<div className="panel-title"> <div className="panel-title">
<span className="icon-gf panel-alert-icon" /> <span className="icon-gf panel-alert-icon" />
......
...@@ -15,7 +15,10 @@ export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => { ...@@ -15,7 +15,10 @@ export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => {
<li className={isSubMenu ? 'dropdown-submenu' : null}> <li className={isSubMenu ? 'dropdown-submenu' : null}>
<a onClick={props.onClick}> <a onClick={props.onClick}>
{props.iconClassName && <i className={props.iconClassName} />} {props.iconClassName && <i className={props.iconClassName} />}
<span className="dropdown-item-text" aria-label={e2e.pages.Panels.Panel.selectors.headerItems(props.text)}> <span
className="dropdown-item-text"
aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.headerItems(props.text)}
>
{props.text} {props.text}
</span> </span>
{props.shortcut && <span className="dropdown-menu-item-shortcut">{props.shortcut}</span>} {props.shortcut && <span className="dropdown-menu-item-shortcut">{props.shortcut}</span>}
......
...@@ -131,7 +131,7 @@ function TabItem({ tab, activeTab, onClick }: TabItemParams) { ...@@ -131,7 +131,7 @@ function TabItem({ tab, activeTab, onClick }: TabItemParams) {
return ( return (
<div className="panel-editor-tabs__item" onClick={() => onClick(tab)}> <div className="panel-editor-tabs__item" onClick={() => onClick(tab)}>
<a className={tabClasses} aria-label={e2e.pages.Panels.EditPanel.selectors.tabItems(tab.text)}> <a className={tabClasses} aria-label={e2e.pages.Dashboard.Panels.EditPanel.selectors.tabItems(tab.text)}>
<Tooltip content={`${tab.text}`} placement="auto"> <Tooltip content={`${tab.text}`} placement="auto">
<i className={`gicon gicon-${tab.id}${activeTab === tab.id ? '-active' : ''}`} /> <i className={`gicon gicon-${tab.id}${activeTab === tab.id ? '-active' : ''}`} />
</Tooltip> </Tooltip>
......
...@@ -43,7 +43,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => { ...@@ -43,7 +43,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
const panelContent = elem.find('.panel-content'); const panelContent = elem.find('.panel-content');
const cornerInfoElem = elem.find('.panel-info-corner'); const cornerInfoElem = elem.find('.panel-info-corner');
const ctrl = scope.ctrl; const ctrl = scope.ctrl;
ctrl.selectors = e2e.pages.Panels.Panel.selectors; ctrl.selectors = e2e.pages.Dashboard.Panels.Panel.selectors;
let infoDrop: any; let infoDrop: any;
let panelScrollbar: any; let panelScrollbar: any;
......
...@@ -36,9 +36,9 @@ function renderMenuItem(item: AngularPanelMenuItem, ctrl: any) { ...@@ -36,9 +36,9 @@ function renderMenuItem(item: AngularPanelMenuItem, ctrl: any) {
} }
html += `><i class="${item.icon}"></i>`; html += `><i class="${item.icon}"></i>`;
html += `<span class="dropdown-item-text" aria-label="${e2e.pages.Panels.Panel.selectors.headerItems(item.text)}">${ html += `<span class="dropdown-item-text" aria-label="${e2e.pages.Dashboard.Panels.Panel.selectors.headerItems(
item.text item.text
}</span>`; )}">${item.text}</span>`;
if (item.shortcut) { if (item.shortcut) {
html += `<span class="dropdown-menu-item-shortcut">${item.shortcut}</span>`; html += `<span class="dropdown-menu-item-shortcut">${item.shortcut}</span>`;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { VariableQueryProps } from 'app/types/plugins'; import { VariableQueryProps } from 'app/types/plugins';
import { e2e } from '@grafana/e2e';
export default class DefaultVariableQueryEditor extends PureComponent<VariableQueryProps, any> { export default class DefaultVariableQueryEditor extends PureComponent<VariableQueryProps, any> {
constructor(props: VariableQueryProps) { constructor(props: VariableQueryProps) {
...@@ -37,7 +38,7 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu ...@@ -37,7 +38,7 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu
onBlur={this.onBlur} onBlur={this.onBlur}
placeholder="metric name or tags query" placeholder="metric name or tags query"
required required
aria-label="Variable editor Form Default Variable Query Editor textarea" aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsQueryInput}
/> />
</div> </div>
); );
......
import _ from 'lodash'; import _ from 'lodash';
import { AppEvents } from '@grafana/data';
import { e2e } from '@grafana/e2e';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import { variableTypes } from './variable'; import { variableTypes } from './variable';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
import DatasourceSrv from '../plugins/datasource_srv'; import DatasourceSrv from '../plugins/datasource_srv';
import { VariableSrv } from './all'; import { VariableSrv } from './all';
import { TemplateSrv } from './template_srv'; import { TemplateSrv } from './template_srv';
import { AppEvents } from '@grafana/data';
import { promiseToDigest } from '../../core/utils/promiseToDigest'; import { promiseToDigest } from '../../core/utils/promiseToDigest';
export class VariableEditorCtrl { export class VariableEditorCtrl {
...@@ -57,6 +59,13 @@ export class VariableEditorCtrl { ...@@ -57,6 +59,13 @@ export class VariableEditorCtrl {
{ value: 2, text: 'Variable' }, { value: 2, text: 'Variable' },
]; ];
$scope.selectors = {
...e2e.pages.Dashboard.Settings.Variables.List.selectors,
...e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors,
...e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors,
...e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.selectors,
};
$scope.init = () => { $scope.init = () => {
$scope.mode = 'list'; $scope.mode = 'list';
......
<div ng-controller="VariableEditorCtrl" ng-init="init()"> <div ng-controller="VariableEditorCtrl" ng-init="init()">
<div class="page-action-bar"> <div class="page-action-bar">
<h3 class="dashboard-settings__header"> <h3 class="dashboard-settings__header">
<a ng-click="setMode('list')" aria-label="Variable editor Header link">Variables</a> <a ng-click="setMode('list')" aria-label="{{::selectors.headerLink}}">Variables</a>
<span ng-show="mode === 'new'" <span ng-show="mode === 'new'"
><i class="fa fa-fw fa-chevron-right" aria-label="Variable editor Header mode New"></i> New</span ><i class="fa fa-fw fa-chevron-right" aria-label="{{::selectors.modeLabelNew}}"></i> New</span
> >
<span ng-show="mode === 'edit'" <span ng-show="mode === 'edit'"
><i class="fa fa-fw fa-chevron-right" aria-label="Variable editor Header mode Edit"></i> Edit</span ><i class="fa fa-fw fa-chevron-right" aria-label="{{::selectors.modeLabelEdit}}"></i> Edit</span
> >
</h3> </h3>
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
ng-click="setMode('new');" ng-click="setMode('new');"
ng-if="variables.length > 0" ng-if="variables.length > 0"
ng-hide="mode === 'edit' || mode === 'new'" ng-hide="mode === 'edit' || mode === 'new'"
aria-label="Variable editor New variable button" aria-label="{{::selectors.newButton}}"
> >
New New
</a> </a>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
</div> </div>
<div ng-if="variables.length"> <div ng-if="variables.length">
<table class="filter-table filter-table--hover" aria-label="Variable editor Table"> <table class="filter-table filter-table--hover" aria-label="{{::selectors.table}}">
<thead> <thead>
<tr> <tr>
<th>Variable</th> <th>Variable</th>
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<span <span
ng-click="edit(variable)" ng-click="edit(variable)"
class="pointer template-variable" class="pointer template-variable"
aria-label="Variable editor Table Name field" aria-label="{{::selectors.tableRowNameFields(variable.name)}}"
> >
${{ variable.name }} ${{ variable.name }}
</span> </span>
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
style="max-width: 200px;" style="max-width: 200px;"
ng-click="edit(variable)" ng-click="edit(variable)"
class="pointer max-width" class="pointer max-width"
aria-label="Variable editor Table Definition field" aria-label="{{::selectors.tableRowDefinitionFields(variable.name)}}"
> >
{{ variable.definition ? variable.definition : variable.query }} {{ variable.definition ? variable.definition : variable.query }}
</td> </td>
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
ng-click="_.move(variables,$index,$index-1)" ng-click="_.move(variables,$index,$index-1)"
ng-hide="$first" ng-hide="$first"
class="pointer fa fa-arrow-up" class="pointer fa fa-arrow-up"
aria-label="Variable editor Table ArrowUp button" aria-label="{{::selectors.tableRowArrowUpButtons(variable.name)}}"
></i> ></i>
</td> </td>
<td style="width: 1%"> <td style="width: 1%">
...@@ -76,14 +76,14 @@ ...@@ -76,14 +76,14 @@
ng-click="_.move(variables,$index,$index+1)" ng-click="_.move(variables,$index,$index+1)"
ng-hide="$last" ng-hide="$last"
class="pointer fa fa-arrow-down" class="pointer fa fa-arrow-down"
aria-label="Variable editor Table ArrowDown button" aria-label="{{::selectors.tableRowArrowDownButtons(variable.name)}}"
></i> ></i>
</td> </td>
<td style="width: 1%"> <td style="width: 1%">
<a <a
ng-click="duplicate(variable)" ng-click="duplicate(variable)"
class="btn btn-inverse btn-small" class="btn btn-inverse btn-small"
aria-label="Variable editor Table Duplicate button" aria-label="{{::selectors.tableRowDuplicateButtons(variable.name)}}"
> >
Duplicate Duplicate
</a> </a>
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<a <a
ng-click="removeVariable(variable)" ng-click="removeVariable(variable)"
class="btn btn-danger btn-small" class="btn btn-danger btn-small"
aria-label="Variable editor Table Remove button" aria-label="{{::selectors.tableRowRemoveButtons(variable.name)}}"
> >
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</a> </a>
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
ng-model="current.name" ng-model="current.name"
required required
ng-pattern="namePattern" ng-pattern="namePattern"
aria-label="Variable editor Form Name field" aria-label="{{::selectors.generalNameInput}}"
/> />
</div> </div>
<div class="gf-form max-width-19"> <div class="gf-form max-width-19">
...@@ -133,7 +133,7 @@ ...@@ -133,7 +133,7 @@
ng-model="current.type" ng-model="current.type"
ng-options="k as v.name for (k, v) in variableTypes" ng-options="k as v.name for (k, v) in variableTypes"
ng-change="typeChanged()" ng-change="typeChanged()"
aria-label="Variable editor Form Type select" aria-label="{{::selectors.generalTypeSelect}}"
></select> ></select>
</div> </div>
</div> </div>
...@@ -153,7 +153,7 @@ ...@@ -153,7 +153,7 @@
class="gf-form-input" class="gf-form-input"
ng-model="current.label" ng-model="current.label"
placeholder="optional display name" placeholder="optional display name"
aria-label="Variable editor Form Label field" aria-label="{{::selectors.generalLabelInput}}"
/> />
</div> </div>
<div class="gf-form max-width-19"> <div class="gf-form max-width-19">
...@@ -163,7 +163,7 @@ ...@@ -163,7 +163,7 @@
class="gf-form-input" class="gf-form-input"
ng-model="current.hide" ng-model="current.hide"
ng-options="f.value as f.text for f in hideOptions" ng-options="f.value as f.text for f in hideOptions"
aria-label="Variable editor Form Hide select" aria-label="{{::selectors.generalHideSelect}}"
></select> ></select>
</div> </div>
</div> </div>
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
ng-model="current.query" ng-model="current.query"
ng-blur="runQuery()" ng-blur="runQuery()"
placeholder="your metric prefix" placeholder="your metric prefix"
aria-label="Variable editor Form Constant Query field" aria-label="{{::selectors.constantOptionsQueryInput}}"
/> />
</div> </div>
</div> </div>
...@@ -288,7 +288,7 @@ ...@@ -288,7 +288,7 @@
ng-options="f.value as f.name for f in datasources" ng-options="f.value as f.name for f in datasources"
ng-change="datasourceChanged()" ng-change="datasourceChanged()"
required required
aria-label="Variable editor Form Query DataSource select" aria-label="{{::selectors.queryOptionsDataSourceSelect}}"
> >
<option value="" ng-if="false"></option> <option value="" ng-if="false"></option>
</select> </select>
...@@ -307,7 +307,7 @@ ...@@ -307,7 +307,7 @@
class="gf-form-input" class="gf-form-input"
ng-model="current.refresh" ng-model="current.refresh"
ng-options="f.value as f.text for f in refreshOptions" ng-options="f.value as f.text for f in refreshOptions"
aria-label="Variable editor Form Query Refresh select" aria-label="{{::selectors.queryOptionsRefreshSelect}}"
></select> ></select>
</div> </div>
</div> </div>
...@@ -331,7 +331,7 @@ ...@@ -331,7 +331,7 @@
placeholder="/.*-(.*)-.*/" placeholder="/.*-(.*)-.*/"
ng-model-onblur ng-model-onblur
ng-change="runQuery()" ng-change="runQuery()"
aria-label="Variable editor Form Query RegEx field" aria-label="{{::selectors.queryOptionsRegExInput}}"
/> />
</div> </div>
<div class="gf-form max-width-21"> <div class="gf-form max-width-21">
...@@ -347,7 +347,7 @@ ...@@ -347,7 +347,7 @@
ng-model="current.sort" ng-model="current.sort"
ng-options="f.value as f.text for f in sortOptions" ng-options="f.value as f.text for f in sortOptions"
ng-change="runQuery()" ng-change="runQuery()"
aria-label="Variable editor Form Query Sort select" aria-label="{{::selectors.queryOptionsSortSelect}}"
></select> ></select>
</div> </div>
</div> </div>
...@@ -420,7 +420,7 @@ ...@@ -420,7 +420,7 @@
tooltip="Enables multiple values to be selected at the same time" tooltip="Enables multiple values to be selected at the same time"
checked="current.multi" checked="current.multi"
on-change="runQuery()" on-change="runQuery()"
aria-label="Variable editor Form Multi switch" aria-label="{{::selectors.selectionOptionsMultiSwitch}}"
> >
</gf-form-switch> </gf-form-switch>
<gf-form-switch <gf-form-switch
...@@ -429,7 +429,7 @@ ...@@ -429,7 +429,7 @@
label-class="width-10" label-class="width-10"
checked="current.includeAll" checked="current.includeAll"
on-change="runQuery()" on-change="runQuery()"
aria-label="Variable editor Form IncludeAll switch" aria-label="{{::selectors.selectionOptionsIncludeAllSwitch}}"
> >
</gf-form-switch> </gf-form-switch>
</div> </div>
...@@ -440,7 +440,7 @@ ...@@ -440,7 +440,7 @@
class="gf-form-input max-width-15" class="gf-form-input max-width-15"
ng-model="current.allValue" ng-model="current.allValue"
placeholder="blank = auto" placeholder="blank = auto"
aria-label="Variable editor Form IncludeAll field" aria-label="{{::selectors.selectionOptionsCustomAllInput}}"
/> />
</div> </div>
</div> </div>
...@@ -453,7 +453,7 @@ ...@@ -453,7 +453,7 @@
label-class="width-10" label-class="width-10"
checked="current.useTags" checked="current.useTags"
on-change="runQuery()" on-change="runQuery()"
aria-label="Variable editor Form Query UseTags switch" aria-label="{{::selectors.valueGroupsTagsEnabledSwitch}}"
> >
</gf-form-switch> </gf-form-switch>
<div class="gf-form last" ng-if="current.useTags"> <div class="gf-form last" ng-if="current.useTags">
...@@ -464,7 +464,7 @@ ...@@ -464,7 +464,7 @@
ng-model="current.tagsQuery" ng-model="current.tagsQuery"
placeholder="metric name or tags query" placeholder="metric name or tags query"
ng-model-onblur ng-model-onblur
aria-label="Variable editor Form Query TagsQuery field" aria-label="{{::selectors.valueGroupsTagsTagsQueryInput}}"
/> />
</div> </div>
<div class="gf-form" ng-if="current.useTags"> <div class="gf-form" ng-if="current.useTags">
...@@ -475,7 +475,7 @@ ...@@ -475,7 +475,7 @@
ng-model="current.tagValuesQuery" ng-model="current.tagValuesQuery"
placeholder="apps.$tag.*" placeholder="apps.$tag.*"
ng-model-onblur ng-model-onblur
aria-label="Variable editor Form Query TagsValuesQuery field" aria-label="{{::selectors.valueGroupsTagsTagsValuesQueryInput}}"
/> />
</div> </div>
</div> </div>
...@@ -484,7 +484,7 @@ ...@@ -484,7 +484,7 @@
<h5>Preview of values</h5> <h5>Preview of values</h5>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit"> <div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit">
<span class="gf-form-label" aria-label="Variable editor Preview of Values option">{{ option.text }}</span> <span class="gf-form-label" aria-label="{{::selectors.previewOfValuesOption}}">{{ option.text }}</span>
</div> </div>
<div class="gf-form" ng-if="current.options.length > optionsLimit"> <div class="gf-form" ng-if="current.options.length > optionsLimit">
<a <a
...@@ -508,7 +508,7 @@ ...@@ -508,7 +508,7 @@
class="btn btn-primary" class="btn btn-primary"
ng-show="mode === 'edit'" ng-show="mode === 'edit'"
ng-click="update();" ng-click="update();"
aria-label="Variable editor Update button" aria-label="{{::selectors.updateButton}}"
> >
Update Update
</button> </button>
...@@ -517,7 +517,7 @@ ...@@ -517,7 +517,7 @@
class="btn btn-primary" class="btn btn-primary"
ng-show="mode === 'new'" ng-show="mode === 'new'"
ng-click="add();" ng-click="add();"
aria-label="Variable editor Add button" aria-label="{{::selectors.addButton}}"
> >
Add Add
</button> </button>
......
<div class="variable-link-wrapper"> <div class="variable-link-wrapper">
<a <a
ng-click="vm.show()" ng-click="vm.show()"
class="variable-value-link" class="variable-value-link"
aria-label="Dashboard template variables Variable Value DropDown value link" aria-label="{{vm.selectors.submenuItemValueDropDownValueLinkTexts(vm.linkText)}}"
> >
{{vm.linkText}} {{vm.linkText}}
<span ng-repeat="tag in vm.selectedTags" bs-tooltip='tag.valuesText' data-placement="bottom"> <span ng-repeat="tag in vm.selectedTags" bs-tooltip="tag.valuesText" data-placement="bottom">
<span class="label-tag"tag-color-from-name="tag.text"> <span class="label-tag" tag-color-from-name="tag.text">
&nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp; &nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp; {{tag.text}}
{{tag.text}} </span>
</span> </span>
</span> <i class="fa fa-caret-down" style="font-size:12px"></i>
<i class="fa fa-caret-down" style="font-size:12px"></i> </a>
</a>
<input type="text" class="gf-form-input" style="display: none" ng-keydown="vm.keyDown($event)" ng-model="vm.search.query" ng-change="vm.debouncedQueryChanged()" ></input> <input
type="text"
class="gf-form-input"
style="display: none"
ng-keydown="vm.keyDown($event)"
ng-model="vm.search.query"
ng-change="vm.debouncedQueryChanged()"
/>
<div <div
class="variable-value-dropdown" class="variable-value-dropdown"
ng-if="vm.dropdownVisible" ng-if="vm.dropdownVisible"
ng-class="{'multi': vm.variable.multi, 'single': !vm.variable.multi}" ng-class="{'multi': vm.variable.multi, 'single': !vm.variable.multi}"
aria-label="Dashboard template variables Variable Value DropDown DropDown" aria-label="{{::vm.selectors.submenuItemValueDropDownDropDown}}"
> >
<div class="variable-options-wrapper"> <div class="variable-options-wrapper">
<div class="variable-options-column"> <div class="variable-options-column">
<a <a
class="variable-options-column-header" class="variable-options-column-header"
ng-if="vm.variable.multi" ng-if="vm.variable.multi"
ng-class="{'many-selected': vm.selectedValues.length > 1}" ng-class="{'many-selected': vm.selectedValues.length > 1}"
bs-tooltip="'Clear selections'" bs-tooltip="'Clear selections'"
data-placement="top" data-placement="top"
ng-click="vm.clearSelections()" ng-click="vm.clearSelections()"
aria-label="Dashboard template variables Variable Value DropDown Selected link"
> >
<span class="variable-option-icon"></span> <span class="variable-option-icon"></span>
Selected ({{vm.selectedValues.length}}) Selected ({{vm.selectedValues.length}})
</a> </a>
<a <a
class="variable-option pointer" class="variable-option pointer"
ng-repeat="option in vm.search.options" ng-repeat="option in vm.search.options"
ng-class="{'selected': option.selected, 'highlighted': $index === vm.highlightIndex}" ng-class="{'selected': option.selected, 'highlighted': $index === vm.highlightIndex}"
ng-click="vm.selectValue(option, $event)" ng-click="vm.selectValue(option, $event)"
> >
<span class="variable-option-icon"></span> <span class="variable-option-icon"></span>
<span aria-label="Dashboard template variables Variable Value DropDown option text">{{option.text}}</span> <span aria-label="{{vm.selectors.submenuItemValueDropDownOptionTexts(option.text)}}">{{option.text}}</span>
</a> </a>
</div> </div>
<div class="variable-options-column" ng-if="vm.tags.length"> <div class="variable-options-column" ng-if="vm.tags.length">
<div class="variable-options-column-header text-center"> <div class="variable-options-column-header text-center">
Tags Tags
</div> </div>
<a class="variable-option-tag pointer" ng-repeat="tag in vm.tags" ng-click="vm.selectTag(tag, $event)" ng-class="{'selected': tag.selected}"> <a
<span class="fa fa-fw variable-option-icon"></span> class="variable-option-tag pointer"
<span class="label-tag" tag-color-from-name="tag.text">{{tag.text}}&nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp;</span> ng-repeat="tag in vm.tags"
</a> ng-click="vm.selectTag(tag, $event)"
</div> ng-class="{'selected': tag.selected}"
</div> >
</div> <span class="fa fa-fw variable-option-icon"></span>
<span class="label-tag" tag-color-from-name="tag.text"
>{{tag.text}}&nbsp;&nbsp;<i class="fa fa-tag"></i>&nbsp;</span
>
</a>
</div>
</div>
</div>
</div> </div>
...@@ -31,7 +31,7 @@ export class TestDataQueryCtrl extends QueryCtrl { ...@@ -31,7 +31,7 @@ export class TestDataQueryCtrl extends QueryCtrl {
selectedPoint: any; selectedPoint: any;
showLabels = false; showLabels = false;
selectors: typeof e2e.pages.Panels.DataSource.TestData.QueryTab.selectors; selectors: typeof e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors;
/** @ngInject */ /** @ngInject */
constructor($scope: any, $injector: any) { constructor($scope: any, $injector: any) {
...@@ -42,7 +42,7 @@ export class TestDataQueryCtrl extends QueryCtrl { ...@@ -42,7 +42,7 @@ export class TestDataQueryCtrl extends QueryCtrl {
this.newPointTime = dateTime(); this.newPointTime = dateTime();
this.selectedPoint = { text: 'Select point', value: null }; this.selectedPoint = { text: 'Select point', value: null };
this.showLabels = showLabelsFor.includes(this.target.scenarioId); this.showLabels = showLabelsFor.includes(this.target.scenarioId);
this.selectors = e2e.pages.Panels.DataSource.TestData.QueryTab.selectors; this.selectors = e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors;
} }
getPoints() { getPoints() {
......
...@@ -8,7 +8,7 @@ export class AxesEditorCtrl { ...@@ -8,7 +8,7 @@ export class AxesEditorCtrl {
xAxisModes: any; xAxisModes: any;
xAxisStatOptions: any; xAxisStatOptions: any;
xNameSegment: any; xNameSegment: any;
selectors: typeof e2e.pages.Panels.Visualization.Graph.VisualizationTab.selectors; selectors: typeof e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors;
/** @ngInject */ /** @ngInject */
constructor(private $scope: any) { constructor(private $scope: any) {
...@@ -45,7 +45,7 @@ export class AxesEditorCtrl { ...@@ -45,7 +45,7 @@ export class AxesEditorCtrl {
this.panel.xaxis.name = 'specify field'; this.panel.xaxis.name = 'specify field';
} }
} }
this.selectors = e2e.pages.Panels.Visualization.Graph.VisualizationTab.selectors; this.selectors = e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors;
} }
setUnitFormat(axis: { format: any }) { setUnitFormat(axis: { format: any }) {
......
...@@ -8,27 +8,25 @@ e2e.scenario({ ...@@ -8,27 +8,25 @@ e2e.scenario({
skipScenario: false, skipScenario: false,
scenario: () => { scenario: () => {
e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid')); e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid'));
e2e.pages.Dashboard.toolbarItems('Add panel') e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
.should('be.visible') // prevents flakiness
.click();
e2e.pages.AddDashboard.ctaButtons('Add Query').click(); e2e.pages.AddDashboard.ctaButtons('Add Query').click();
e2e.pages.Panels.EditPanel.tabItems('Queries').click(); e2e.pages.Dashboard.Panels.EditPanel.tabItems('Queries').click();
e2e.pages.Panels.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values'); e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values');
e2e.pages.Panels.EditPanel.tabItems('Visualization').click(); e2e.pages.Dashboard.Panels.EditPanel.tabItems('Visualization').click();
e2e.pages.Panels.Visualization.Graph.VisualizationTab.xAxisSection() e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.xAxisSection()
.contains('Show') .contains('Show')
.click(); .click();
e2e.flows.saveDashboard(); e2e.flows.saveDashboard();
e2e.pages.Dashboard.backArrow().click(); e2e.pages.Dashboard.Toolbar.backArrow().click();
e2e.pages.Panels.Panel.title('Panel Title').click(); e2e.pages.Dashboard.Panels.Panel.title('Panel Title').click();
e2e.pages.Panels.Panel.headerItems('Share').click(); e2e.pages.Dashboard.Panels.Panel.headerItems('Share').click();
e2e.pages.SharePanelModal.linkToRenderedImage().then(($a: any) => { e2e.pages.SharePanelModal.linkToRenderedImage().then(($a: any) => {
// extract the fully qualified href property // extract the fully qualified href property
......
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