mirror of
https://github.com/grafana/grafana.git
synced 2025-08-06 03:19:30 +08:00
e2e: adds panel editor tests for test data queries (#23996)
This commit is contained in:
146
e2e/suite1/specs/panelEdit_queries.spec.ts
Normal file
146
e2e/suite1/specs/panelEdit_queries.spec.ts
Normal 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();
|
||||
};
|
@ -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',
|
||||
|
@ -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)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -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';
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
)}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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>}
|
||||
|
Reference in New Issue
Block a user