e2e: adds panel editor tests for test data queries (#23996)

This commit is contained in:
Hugo Häggmark
2020-04-30 09:26:59 +02:00
committed by GitHub
parent efeb4c1341
commit 55ac97dccc
9 changed files with 181 additions and 11 deletions

View File

@ -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();
};

View File

@ -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',

View File

@ -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<QueryOperationActionProps> = ({ icon
disabled={!!disabled}
onClick={onClick}
surface="header"
aria-label={`${title} query operation action`}
aria-label={selectors.components.QueryEditorRow.actionButton(title)}
/>
);
};

View File

@ -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';

View File

@ -198,7 +198,11 @@ export class QueryInspector extends PureComponent<Props, State> {
</p>
</div>
<div className={styles.toolbar}>
<Button icon="sync" onClick={this.onIssueNewQuery}>
<Button
icon="sync"
onClick={this.onIssueNewQuery}
aria-label={selectors.components.PanelInspector.Query.refreshButton}
>
Refresh
</Button>

View File

@ -271,7 +271,12 @@ export class QueriesTab extends PureComponent<Props, State> {
return (
<HorizontalGroup spacing="md" align="flex-start">
{showAddButton && (
<Button icon="plus" onClick={this.onAddQueryClick} variant="secondary">
<Button
icon="plus"
onClick={this.onAddQueryClick}
variant="secondary"
aria-label={selectors.components.QueryTab.addQuery}
>
Query
</Button>
)}

View File

@ -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<Props, State> {
const editor = this.renderPluginEditor();
return (
<QueryOperationRow title={this.renderTitle} actions={this.renderActions} onOpen={this.onOpen}>
<div className={rowClasses}>
<ErrorBoundaryAlert>{editor}</ErrorBoundaryAlert>
</div>
</QueryOperationRow>
<div aria-label={selectors.components.QueryEditorRows.rows}>
<QueryOperationRow title={this.renderTitle} actions={this.renderActions} onOpen={this.onOpen}>
<div className={rowClasses}>
<ErrorBoundaryAlert>{editor}</ErrorBoundaryAlert>
</div>
</QueryOperationRow>
</div>
);
}
}

View File

@ -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<QueryEditorRowTitleProps> = ({
const styles = getQueryEditorRowTitleStyles(theme);
return (
<HorizontalGroup align="center">
<div className={styles.refId}>
<div className={styles.refId} aria-label={selectors.components.QueryEditorRow.title(query.refId)}>
<span>{query.refId}</span>
{inMixedMode && <em className={styles.contextInfo}> ({datasource.name})</em>}
{disabled && <em className={styles.contextInfo}> Disabled</em>}