diff --git a/e2e/suite1/specs/panel-edit.spec.ts b/e2e/suite1/specs/panelEdit_base.spec.ts similarity index 100% rename from e2e/suite1/specs/panel-edit.spec.ts rename to e2e/suite1/specs/panelEdit_base.spec.ts diff --git a/e2e/suite1/specs/panelEdit_queries.spec.ts b/e2e/suite1/specs/panelEdit_queries.spec.ts new file mode 100644 index 00000000000..96f34c0bce0 --- /dev/null +++ b/e2e/suite1/specs/panelEdit_queries.spec.ts @@ -0,0 +1,146 @@ +import { e2e } from '@grafana/e2e'; +import { expect } from '../../../public/test/lib/common'; + +const PANEL_UNDER_TEST = 'Random walk series'; + +e2e.scenario({ + describeName: 'Panel edit tests - queries', + itName: 'Testes various Panel edit queries scenarios', + addScenarioDataSource: false, + addScenarioDashBoard: false, + skipScenario: false, + scenario: () => { + e2e.flows.openDashboard('5SdHCadmz'); + + e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST); + + // New panel editor opens when navigating from Panel menu + e2e.components.PanelEditor.General.content().should('be.visible'); + + // Queries tab is rendered and open by default + e2e.components.PanelEditor.DataPane.content().should('be.visible'); + + // We expect row with refId A to exist and be visible + e2e.components.QueryEditorRows.rows().within(rows => { + expect(rows.length).equals(1); + }); + + // Add query button should be visible and clicking on it should create a new row + e2e.components.QueryTab.addQuery() + .scrollIntoView() + .should('be.visible') + .click(); + + // We expect row with refId A and B to exist and be visible + e2e.components.QueryEditorRows.rows().within(rows => { + expect(rows.length).equals(2); + }); + + // Remove refId A + e2e.components.QueryEditorRow.actionButton('Remove query') + .eq(0) + .should('be.visible') + .click(); + + // We expect row with refId B to exist and be visible + e2e.components.QueryEditorRows.rows().within(rows => { + expect(rows.length).equals(1); + }); + + // Duplicate refId B + e2e.components.QueryEditorRow.actionButton('Duplicate query') + .eq(0) + .should('be.visible') + .click(); + + // We expect row with refId Band and A to exist and be visible + e2e.components.QueryEditorRows.rows().within(rows => { + expect(rows.length).equals(2); + }); + + // Change to CSV Metric Values scenario for A + e2e.components.DataSource.TestData.QueryTab.scenarioSelect() + .eq(1) + .select('CSV Metric Values'); + + // Change order or query rows + // Check the order of the rows before + e2e.components.QueryEditorRows.rows() + .eq(0) + .within(() => { + e2e.components.QueryEditorRow.title('B').should('be.visible'); + }); + + e2e.components.QueryEditorRows.rows() + .eq(1) + .within(() => { + e2e.components.QueryEditorRow.title('A').should('be.visible'); + }); + + // Change so A is first + e2e.components.QueryEditorRow.actionButton('Move query up') + .eq(1) + .click(); + + // Check the order of the rows after change + e2e.components.QueryEditorRows.rows() + .eq(0) + .within(() => { + e2e.components.QueryEditorRow.title('A').should('be.visible'); + }); + + e2e.components.QueryEditorRows.rows() + .eq(1) + .within(() => { + e2e.components.QueryEditorRow.title('B').should('be.visible'); + }); + + // Disable / enable row + expectInspectorResultAndClose(keys => { + const length = keys.length; + expect(keys[length - 2].innerText).equals('A:'); + expect(keys[length - 1].innerText).equals('B:'); + }); + + // Disable row with refId B + e2e.components.QueryEditorRow.actionButton('Disable/enable query') + .eq(1) + .should('be.visible') + .click(); + + expectInspectorResultAndClose(keys => { + const length = keys.length; + expect(keys[length - 1].innerText).equals('A:'); + }); + + // Enable row with refId B + e2e.components.QueryEditorRow.actionButton('Disable/enable query') + .eq(1) + .should('be.visible') + .click(); + + expectInspectorResultAndClose(keys => { + const length = keys.length; + expect(keys[length - 2].innerText).equals('A:'); + expect(keys[length - 1].innerText).equals('B:'); + }); + }, +}); + +const expectInspectorResultAndClose = (expectCallBack: (keys: any[]) => void) => { + e2e.components.QueryTab.queryInspectorButton() + .should('be.visible') + .click(); + + e2e.components.PanelInspector.Query.refreshButton() + .should('be.visible') + .click(); + + e2e.components.PanelInspector.Query.jsonObjectKeys() + .should('be.visible') + .within((keys: any) => expectCallBack(keys)); + + e2e.components.Drawer.General.close() + .should('be.visible') + .click(); +}; diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 781a809367e..54e55a4bd3e 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -67,6 +67,8 @@ export const Components = { }, Query: { content: 'Panel inspector Query content', + refreshButton: 'Panel inspector Query refresh button', + jsonObjectKeys: () => '.json-formatter-key', }, }, Tab: { @@ -76,6 +78,14 @@ export const Components = { QueryTab: { content: 'Query editor tab content', queryInspectorButton: 'Query inspector button', + addQuery: 'Query editor add query button', + }, + QueryEditorRows: { + rows: 'Query editor row', + }, + QueryEditorRow: { + actionButton: (title: string) => `${title} query operation action`, + title: (refId: string) => `Query editor row title ${refId}`, }, AlertTab: { content: 'Alert editor tab content', diff --git a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx index 20b016146f0..f109b3c0d7a 100644 --- a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx +++ b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx @@ -1,7 +1,8 @@ -import { IconName, IconButton, stylesFactory, useTheme } from '@grafana/ui'; +import { IconButton, IconName, stylesFactory, useTheme } from '@grafana/ui'; import React from 'react'; import { css } from 'emotion'; import { GrafanaTheme } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; interface QueryOperationActionProps { icon: IconName; @@ -27,7 +28,7 @@ export const QueryOperationAction: React.FC = ({ icon disabled={!!disabled} onClick={onClick} surface="header" - aria-label={`${title} query operation action`} + aria-label={selectors.components.QueryEditorRow.actionButton(title)} /> ); }; diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx index 09683f5135d..9123c31e243 100644 --- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx +++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { renderOrCallToRender, Icon, stylesFactory, useTheme, HorizontalGroup } from '@grafana/ui'; +import { HorizontalGroup, Icon, renderOrCallToRender, stylesFactory, useTheme } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; import { css } from 'emotion'; import { useUpdateEffect } from 'react-use'; diff --git a/public/app/features/dashboard/components/Inspector/QueryInspector.tsx b/public/app/features/dashboard/components/Inspector/QueryInspector.tsx index 9cf092babf2..b4050d66024 100644 --- a/public/app/features/dashboard/components/Inspector/QueryInspector.tsx +++ b/public/app/features/dashboard/components/Inspector/QueryInspector.tsx @@ -198,7 +198,11 @@ export class QueryInspector extends PureComponent {

- diff --git a/public/app/features/dashboard/panel_editor/QueriesTab.tsx b/public/app/features/dashboard/panel_editor/QueriesTab.tsx index bdcaa05cbd0..9aacaf6cfb6 100644 --- a/public/app/features/dashboard/panel_editor/QueriesTab.tsx +++ b/public/app/features/dashboard/panel_editor/QueriesTab.tsx @@ -271,7 +271,12 @@ export class QueriesTab extends PureComponent { return ( {showAddButton && ( - )} diff --git a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx index 55187db555d..480adee7323 100644 --- a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx +++ b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx @@ -24,6 +24,7 @@ import { QueryEditorRowTitle } from './QueryEditorRowTitle'; import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow'; import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction'; import { DashboardModel } from '../state/DashboardModel'; +import { selectors } from '@grafana/e2e-selectors'; interface Props { panel: PanelModel; @@ -282,11 +283,13 @@ export class QueryEditorRow extends PureComponent { const editor = this.renderPluginEditor(); return ( - -
- {editor} -
-
+
+ +
+ {editor} +
+
+
); } } diff --git a/public/app/features/dashboard/panel_editor/QueryEditorRowTitle.tsx b/public/app/features/dashboard/panel_editor/QueryEditorRowTitle.tsx index 9bf21f6ab58..515749c5fc8 100644 --- a/public/app/features/dashboard/panel_editor/QueryEditorRowTitle.tsx +++ b/public/app/features/dashboard/panel_editor/QueryEditorRowTitle.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { css } from 'emotion'; import { DataQuery, DataSourceApi, GrafanaTheme } from '@grafana/data'; import { HorizontalGroup, stylesFactory, useTheme } from '@grafana/ui'; +import { selectors } from '@grafana/e2e-selectors'; interface QueryEditorRowTitleProps { query: DataQuery; @@ -24,7 +25,7 @@ export const QueryEditorRowTitle: React.FC = ({ const styles = getQueryEditorRowTitleStyles(theme); return ( -
+
{query.refId} {inMixedMode && ({datasource.name})} {disabled && Disabled}