mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Expressions: Add tests for the QueryEditorRows and QueryGroup components (#63394)
* add QueryGroup onAddQueryClick and onExpressionClick tests * add test's for the query group component - new query/expression should be expanded - adds query/expression onclick * add open data source help modal test * add disabled expression test * add query editor rows test * rm unused attributes, rm renderScenario required override
This commit is contained in:
parent
33277fccde
commit
5ec8e370f7
2
.yarn/sdks/integrations.yml
vendored
2
.yarn/sdks/integrations.yml
vendored
@ -2,5 +2,5 @@
|
|||||||
# Manual changes might be lost!
|
# Manual changes might be lost!
|
||||||
|
|
||||||
integrations:
|
integrations:
|
||||||
- vim
|
|
||||||
- vscode
|
- vscode
|
||||||
|
- vim
|
||||||
|
@ -490,7 +490,7 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
|||||||
const DatasourceCheatsheet = datasource.components?.QueryEditorHelp;
|
const DatasourceCheatsheet = datasource.components?.QueryEditorHelp;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div aria-label={selectors.components.QueryEditorRows.rows}>
|
<div data-testid="query-editor-row" aria-label={selectors.components.QueryEditorRows.rows}>
|
||||||
<QueryOperationRow
|
<QueryOperationRow
|
||||||
id={this.id}
|
id={this.id}
|
||||||
draggable={true}
|
draggable={true}
|
||||||
|
156
public/app/features/query/components/QueryEditorRows.test.tsx
Normal file
156
public/app/features/query/components/QueryEditorRows.test.tsx
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import { fireEvent, queryByLabelText, render, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { type DataQuery } from '@grafana/schema';
|
||||||
|
import { mockDataSource } from 'app/features/alerting/unified/mocks';
|
||||||
|
import { DataSourceType } from 'app/features/alerting/unified/utils/datasource';
|
||||||
|
import createMockPanelData from 'app/plugins/datasource/azuremonitor/__mocks__/panelData';
|
||||||
|
|
||||||
|
import { QueryEditorRows, Props } from './QueryEditorRows';
|
||||||
|
|
||||||
|
const mockDS = mockDataSource({
|
||||||
|
name: 'CloudManager',
|
||||||
|
type: DataSourceType.Alertmanager,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockVariable = mockDataSource({
|
||||||
|
name: '${dsVariable}',
|
||||||
|
type: 'datasource',
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
|
||||||
|
return {
|
||||||
|
getDataSourceSrv: () => ({
|
||||||
|
get: () => Promise.resolve({ ...mockDS, getRef: () => {} }),
|
||||||
|
getList: ({ variables }: { variables: boolean }) => (variables ? [mockDS, mockVariable] : [mockDS]),
|
||||||
|
getInstanceSettings: () => ({
|
||||||
|
...mockDS,
|
||||||
|
meta: {
|
||||||
|
...mockDS.meta,
|
||||||
|
alerting: true,
|
||||||
|
mixed: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const props: Props = {
|
||||||
|
queries: [
|
||||||
|
{
|
||||||
|
datasource: mockDS,
|
||||||
|
refId: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
datasource: mockDS,
|
||||||
|
refId: 'B',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dsSettings: mockDataSource(),
|
||||||
|
onQueriesChange: function (queries: DataQuery[]): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
onAddQuery: function (query: DataQuery): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
onRunQueries: function (): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
data: createMockPanelData(),
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
|
||||||
|
return {
|
||||||
|
getDataSourceSrv: () => ({
|
||||||
|
get: () => Promise.resolve(mockDS),
|
||||||
|
getList: ({ variables }: { variables: boolean }) => (variables ? [mockDS, mockVariable] : [mockDS]),
|
||||||
|
getInstanceSettings: () => mockDS,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('QueryEditorRows', () => {
|
||||||
|
it('Should render queries', async () => {
|
||||||
|
const {
|
||||||
|
renderResult: { rerender },
|
||||||
|
} = renderScenario();
|
||||||
|
expect((await screen.findByTestId('query-editor-rows')).children.length).toBe(2);
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<QueryEditorRows
|
||||||
|
{...props}
|
||||||
|
queries={[
|
||||||
|
{
|
||||||
|
datasource: mockDS,
|
||||||
|
refId: 'A',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect((await screen.findByTestId('query-editor-rows')).children.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to expand and collapse queries', async () => {
|
||||||
|
renderScenario();
|
||||||
|
const queryEditorRows = await screen.findAllByTestId('query-editor-row');
|
||||||
|
|
||||||
|
for (const childQuery of queryEditorRows) {
|
||||||
|
const toggleExpandButton = queryByLabelText(childQuery, 'toggle collapse and expand query row') as HTMLElement;
|
||||||
|
|
||||||
|
expect(toggleExpandButton).toBeInTheDocument();
|
||||||
|
expect(toggleExpandButton.getAttribute('aria-expanded')).toBe('true');
|
||||||
|
|
||||||
|
fireEvent.click(toggleExpandButton);
|
||||||
|
|
||||||
|
expect(toggleExpandButton.getAttribute('aria-expanded')).toBe('false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to duplicate queries', async () => {
|
||||||
|
const onAddQuery = jest.fn();
|
||||||
|
const onQueryCopied = jest.fn();
|
||||||
|
|
||||||
|
renderScenario({ onAddQuery, onQueryCopied });
|
||||||
|
const queryEditorRows = await screen.findAllByTestId('query-editor-row');
|
||||||
|
queryEditorRows.map(async (childQuery) => {
|
||||||
|
const duplicateQueryButton = queryByLabelText(
|
||||||
|
childQuery,
|
||||||
|
'Duplicate query query operation action'
|
||||||
|
) as HTMLElement;
|
||||||
|
|
||||||
|
expect(duplicateQueryButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(duplicateQueryButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(onAddQuery).toHaveBeenCalledTimes(queryEditorRows.length);
|
||||||
|
expect(onQueryCopied).toHaveBeenCalledTimes(queryEditorRows.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to delete queries', async () => {
|
||||||
|
const onQueriesChange = jest.fn();
|
||||||
|
const onQueryRemoved = jest.fn();
|
||||||
|
renderScenario({ onQueriesChange, onQueryRemoved });
|
||||||
|
|
||||||
|
const queryEditorRows = await screen.findAllByTestId('query-editor-row');
|
||||||
|
queryEditorRows.map(async (childQuery) => {
|
||||||
|
const deleteQueryButton = queryByLabelText(childQuery, 'Remove query query operation action') as HTMLElement;
|
||||||
|
|
||||||
|
expect(deleteQueryButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(deleteQueryButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(onQueriesChange).toHaveBeenCalledTimes(queryEditorRows.length);
|
||||||
|
expect(onQueryRemoved).toHaveBeenCalledTimes(queryEditorRows.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderScenario(overrides?: Partial<Props>) {
|
||||||
|
Object.assign(props, overrides);
|
||||||
|
|
||||||
|
return {
|
||||||
|
renderResult: render(<QueryEditorRows {...props} />),
|
||||||
|
};
|
||||||
|
}
|
@ -14,7 +14,7 @@ import { getDataSourceSrv, reportInteraction } from '@grafana/runtime';
|
|||||||
|
|
||||||
import { QueryEditorRow } from './QueryEditorRow';
|
import { QueryEditorRow } from './QueryEditorRow';
|
||||||
|
|
||||||
interface Props {
|
export interface Props {
|
||||||
// The query configuration
|
// The query configuration
|
||||||
queries: DataQuery[];
|
queries: DataQuery[];
|
||||||
dsSettings: DataSourceInstanceSettings;
|
dsSettings: DataSourceInstanceSettings;
|
||||||
@ -151,7 +151,7 @@ export class QueryEditorRows extends PureComponent<Props> {
|
|||||||
<Droppable droppableId="transformations-list" direction="vertical">
|
<Droppable droppableId="transformations-list" direction="vertical">
|
||||||
{(provided) => {
|
{(provided) => {
|
||||||
return (
|
return (
|
||||||
<div ref={provided.innerRef} {...provided.droppableProps}>
|
<div data-testid="query-editor-rows" ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
{queries.map((query, index) => {
|
{queries.map((query, index) => {
|
||||||
const dataSourceSettings = getDataSourceSettings(query, dsSettings);
|
const dataSourceSettings = getDataSourceSettings(query, dsSettings);
|
||||||
const onChangeDataSourceSettings = dsSettings.meta.mixed
|
const onChangeDataSourceSettings = dsSettings.meta.mixed
|
||||||
|
149
public/app/features/query/components/QueryGroup.test.tsx
Normal file
149
public/app/features/query/components/QueryGroup.test.tsx
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import { act, render, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import config from 'app/core/config';
|
||||||
|
import { mockDataSource } from 'app/features/alerting/unified/mocks';
|
||||||
|
import { DataSourceType } from 'app/features/alerting/unified/utils/datasource';
|
||||||
|
|
||||||
|
import { PanelQueryRunner } from '../state/PanelQueryRunner';
|
||||||
|
|
||||||
|
import { Props, QueryGroup } from './QueryGroup';
|
||||||
|
|
||||||
|
const mockDS = mockDataSource({
|
||||||
|
name: 'CloudManager',
|
||||||
|
type: DataSourceType.Alertmanager,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockVariable = mockDataSource({
|
||||||
|
name: '${dsVariable}',
|
||||||
|
type: 'datasource',
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
|
||||||
|
return {
|
||||||
|
getDataSourceSrv: () => ({
|
||||||
|
get: () => Promise.resolve({ ...mockDS, getRef: () => {} }),
|
||||||
|
getList: ({ variables }: { variables: boolean }) => (variables ? [mockDS, mockVariable] : [mockDS]),
|
||||||
|
getInstanceSettings: () => ({
|
||||||
|
...mockDS,
|
||||||
|
meta: {
|
||||||
|
...mockDS.meta,
|
||||||
|
alerting: true,
|
||||||
|
mixed: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('QueryGroup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
config.expressionsEnabled = true;
|
||||||
|
});
|
||||||
|
it('Should add expression on click', async () => {
|
||||||
|
renderScenario({});
|
||||||
|
|
||||||
|
const addExpressionButton = await screen.findByTestId('query-tab-add-expression');
|
||||||
|
const queryRowsContainer = await screen.findByTestId('query-editor-rows');
|
||||||
|
expect(queryRowsContainer.children.length).toBe(2);
|
||||||
|
|
||||||
|
await addExpressionButton.click();
|
||||||
|
expect(queryRowsContainer.children.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should add query on click', async () => {
|
||||||
|
renderScenario({});
|
||||||
|
|
||||||
|
const addQueryButton = await screen.findByTestId('query-tab-add-query');
|
||||||
|
const queryRowsContainer = await screen.findByTestId('query-editor-rows');
|
||||||
|
expect(queryRowsContainer.children.length).toBe(2);
|
||||||
|
|
||||||
|
await addQueryButton.click();
|
||||||
|
|
||||||
|
expect(queryRowsContainer.children.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('New expression should be expanded', async () => {
|
||||||
|
renderScenario({});
|
||||||
|
|
||||||
|
const addExpressionButton = await screen.findByTestId('query-tab-add-expression');
|
||||||
|
const queryRowsContainer = await screen.findByTestId('query-editor-rows');
|
||||||
|
await addExpressionButton.click();
|
||||||
|
|
||||||
|
const lastQueryEditorRow = (await screen.findAllByTestId('query-editor-row')).at(-1);
|
||||||
|
const lastEditorToggleRow = (await screen.findAllByLabelText('toggle collapse and expand query row')).at(-1);
|
||||||
|
|
||||||
|
expect(lastEditorToggleRow?.getAttribute('aria-expanded')).toBe('true');
|
||||||
|
expect(lastQueryEditorRow?.firstElementChild?.children.length).toBe(2);
|
||||||
|
expect(queryRowsContainer.children.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('New query should be expanded', async () => {
|
||||||
|
renderScenario({});
|
||||||
|
|
||||||
|
const addQueryButton = await screen.findByTestId('query-tab-add-query');
|
||||||
|
const queryRowsContainer = await screen.findByTestId('query-editor-rows');
|
||||||
|
await addQueryButton.click();
|
||||||
|
|
||||||
|
const lastQueryEditorRow = (await screen.findAllByTestId('query-editor-row')).at(-1);
|
||||||
|
const lastEditorToggleRow = (await screen.findAllByLabelText('toggle collapse and expand query row')).at(-1);
|
||||||
|
|
||||||
|
expect(lastEditorToggleRow?.getAttribute('aria-expanded')).toBe('true');
|
||||||
|
expect(lastQueryEditorRow?.firstElementChild?.children.length).toBe(2);
|
||||||
|
expect(queryRowsContainer.children.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should open data source help modal', async () => {
|
||||||
|
renderScenario({});
|
||||||
|
|
||||||
|
const openHelpButton = await screen.findByTestId('query-tab-help-button');
|
||||||
|
await act(async () => {
|
||||||
|
await openHelpButton.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
const helpModal = await screen.findByRole('dialog');
|
||||||
|
expect(helpModal).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not show add expression button when expressions are disabled', async () => {
|
||||||
|
config.expressionsEnabled = false;
|
||||||
|
renderScenario({});
|
||||||
|
const addExpressionButton = screen.queryByTestId('query-tab-add-expression');
|
||||||
|
expect(addExpressionButton).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderScenario(overrides: Partial<Props>) {
|
||||||
|
const props: Props = {
|
||||||
|
onOptionsChange: jest.fn(),
|
||||||
|
queryRunner: new PanelQueryRunner({
|
||||||
|
getDataSupport: jest.fn(),
|
||||||
|
getFieldOverrideOptions: jest.fn(),
|
||||||
|
getTransformations: jest.fn(),
|
||||||
|
}),
|
||||||
|
options: {
|
||||||
|
queries: [
|
||||||
|
{
|
||||||
|
datasource: mockDS,
|
||||||
|
refId: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
datasource: mockDS,
|
||||||
|
refId: 'B',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dataSource: mockDS,
|
||||||
|
},
|
||||||
|
onRunQueries: function (): void {
|
||||||
|
throw new Error('Function not implemented.');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(props, overrides);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props,
|
||||||
|
renderResult: render(<QueryGroup {...props} />),
|
||||||
|
};
|
||||||
|
}
|
@ -32,7 +32,7 @@ import { QueryEditorRows } from './QueryEditorRows';
|
|||||||
import { QueryGroupOptionsEditor } from './QueryGroupOptions';
|
import { QueryGroupOptionsEditor } from './QueryGroupOptions';
|
||||||
import { SavedQueryPicker } from './SavedQueryPicker';
|
import { SavedQueryPicker } from './SavedQueryPicker';
|
||||||
|
|
||||||
interface Props {
|
export interface Props {
|
||||||
queryRunner: PanelQueryRunner;
|
queryRunner: PanelQueryRunner;
|
||||||
options: QueryGroupOptions;
|
options: QueryGroupOptions;
|
||||||
onOpenQueryInspector?: () => void;
|
onOpenQueryInspector?: () => void;
|
||||||
@ -94,6 +94,7 @@ export class QueryGroup extends PureComponent<Props, State> {
|
|||||||
try {
|
try {
|
||||||
const ds = await this.dataSourceSrv.get(options.dataSource);
|
const ds = await this.dataSourceSrv.get(options.dataSource);
|
||||||
const dsSettings = this.dataSourceSrv.getInstanceSettings(options.dataSource);
|
const dsSettings = this.dataSourceSrv.getInstanceSettings(options.dataSource);
|
||||||
|
|
||||||
const defaultDataSource = await this.dataSourceSrv.get();
|
const defaultDataSource = await this.dataSourceSrv.get();
|
||||||
const datasource = ds.getRef();
|
const datasource = ds.getRef();
|
||||||
const queries = options.queries.map((q) => ({
|
const queries = options.queries.map((q) => ({
|
||||||
@ -290,6 +291,7 @@ export class QueryGroup extends PureComponent<Props, State> {
|
|||||||
icon="question-circle"
|
icon="question-circle"
|
||||||
title="Open data source help"
|
title="Open data source help"
|
||||||
onClick={this.onOpenHelp}
|
onClick={this.onOpenHelp}
|
||||||
|
data-testid="query-tab-help-button"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.dataSourceRowItemOptions}>
|
<div className={styles.dataSourceRowItemOptions}>
|
||||||
@ -375,7 +377,6 @@ export class QueryGroup extends PureComponent<Props, State> {
|
|||||||
renderQueries(dsSettings: DataSourceInstanceSettings) {
|
renderQueries(dsSettings: DataSourceInstanceSettings) {
|
||||||
const { onRunQueries } = this.props;
|
const { onRunQueries } = this.props;
|
||||||
const { data, queries } = this.state;
|
const { data, queries } = this.state;
|
||||||
|
|
||||||
if (isSharedDashboardQuery(dsSettings.name)) {
|
if (isSharedDashboardQuery(dsSettings.name)) {
|
||||||
return (
|
return (
|
||||||
<DashboardQueryEditor
|
<DashboardQueryEditor
|
||||||
@ -429,6 +430,7 @@ export class QueryGroup extends PureComponent<Props, State> {
|
|||||||
onClick={this.onAddQueryClick}
|
onClick={this.onAddQueryClick}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
aria-label={selectors.components.QueryTab.addQuery}
|
aria-label={selectors.components.QueryTab.addQuery}
|
||||||
|
data-testid="query-tab-add-query"
|
||||||
>
|
>
|
||||||
Query
|
Query
|
||||||
</Button>
|
</Button>
|
||||||
@ -439,6 +441,7 @@ export class QueryGroup extends PureComponent<Props, State> {
|
|||||||
onClick={this.onAddExpressionClick}
|
onClick={this.onAddExpressionClick}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className={styles.expressionButton}
|
className={styles.expressionButton}
|
||||||
|
data-testid="query-tab-add-expression"
|
||||||
>
|
>
|
||||||
<span>Expression </span>
|
<span>Expression </span>
|
||||||
</Button>
|
</Button>
|
||||||
|
Loading…
Reference in New Issue
Block a user