diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
index 324b55b5e02..6c2c635bb1e 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
@@ -2,6 +2,8 @@ import React from 'react';
import { TextArea } from '@grafana/ui';
+import { selectors } from '../e2e/selectors';
+
export interface Props {
onChange: (query: string) => void;
onRunQuery: () => void;
@@ -17,7 +19,7 @@ export function MQLQueryEditor({ query, onChange, onRunQuery }: React.PropsWithC
};
return (
- <>
+
);
}
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
index 3b76b8f3fc9..79e81617e25 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
@@ -5,6 +5,7 @@ import { EditorField, EditorRow } from '@grafana/experimental';
import { TextArea, Input } from '@grafana/ui';
import CloudMonitoringDatasource from '../datasource';
+import { selectors } from '../e2e/selectors';
import { PromQLQuery } from '../types/query';
import { Project } from './Project';
@@ -41,7 +42,7 @@ export function PromQLQueryEditor({
}
return (
- <>
+
- >
+
);
}
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
index 4284d7ca58a..91380a13173 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
@@ -1,8 +1,10 @@
-import { render, waitFor } from '@testing-library/react';
+import { render, waitFor, screen } from '@testing-library/react';
import React from 'react';
+import { select } from 'react-select-event';
import { createMockDatasource } from '../__mocks__/cloudMonitoringDatasource';
import { createMockQuery } from '../__mocks__/cloudMonitoringQuery';
+import { selectors } from '../e2e/selectors';
import { QueryType } from '../types/query';
import { QueryEditor } from './QueryEditor';
@@ -30,9 +32,9 @@ describe('QueryEditor', () => {
const onChange = jest.fn();
datasource.migrateQuery = jest.fn().mockReturnValue(defaultProps.query);
- render();
+ render();
await waitFor(() => expect(datasource.migrateQuery).toHaveBeenCalledTimes(1));
- await waitFor(() => expect(onChange).toHaveBeenCalledTimes(1));
+ await waitFor(() => expect(onChange).toHaveBeenCalled());
await waitFor(() => expect(onChange).toHaveBeenCalledWith(defaultProps.query));
});
@@ -46,4 +48,93 @@ describe('QueryEditor', () => {
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ queryType: QueryType.TIME_SERIES_LIST }))
);
});
+
+ it('renders the visual metrics query editor when the query type is timeSeriesList', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = {
+ ...createMockQuery(),
+ queryType: QueryType.TIME_SERIES_LIST,
+ };
+
+ render( {}} onRunQuery={() => {}} />);
+ await waitFor(() =>
+ expect(
+ screen.getByTestId(selectors.components.queryEditor.visualMetricsQueryEditor.container.input)
+ ).toBeInTheDocument()
+ );
+ });
+ it('renders the visual metrics query editor when the query type is timeSeriesList', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = {
+ ...createMockQuery(),
+ queryType: QueryType.TIME_SERIES_LIST,
+ };
+
+ render( {}} onRunQuery={() => {}} />);
+ await waitFor(() =>
+ expect(
+ screen.getByTestId(selectors.components.queryEditor.visualMetricsQueryEditor.container.input)
+ ).toBeInTheDocument()
+ );
+ });
+ it('renders the mql metrics query editor when the query type is timeSeriesQuery', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = {
+ ...createMockQuery(),
+ queryType: QueryType.TIME_SERIES_QUERY,
+ };
+
+ render( {}} onRunQuery={() => {}} />);
+ await waitFor(() =>
+ expect(
+ screen.getByTestId(selectors.components.queryEditor.mqlMetricsQueryEditor.container.input)
+ ).toBeInTheDocument()
+ );
+ });
+
+ it('renders the SLO query editor when the query type is SLO', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = {
+ ...createMockQuery(),
+ queryType: QueryType.SLO,
+ };
+
+ render( {}} onRunQuery={() => {}} />);
+ await waitFor(() =>
+ expect(screen.getByTestId(selectors.components.queryEditor.sloQueryEditor.container.input)).toBeInTheDocument()
+ );
+ });
+
+ it('renders the PromQL query editor when the query type is PromQL', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = {
+ ...createMockQuery(),
+ queryType: QueryType.PROMQL,
+ };
+
+ render( {}} onRunQuery={() => {}} />);
+ await waitFor(() =>
+ expect(screen.getByTestId(selectors.components.queryEditor.promQlQueryEditor.container.input)).toBeInTheDocument()
+ );
+ });
+
+ it('changes the query type when selected', async () => {
+ const mockDatasource = createMockDatasource();
+ const mockQuery = createMockQuery();
+ const onChange = jest.fn();
+ render( {}} />);
+ await waitFor(() => expect(screen.getByTestId(selectors.components.queryEditor.container)).toBeInTheDocument());
+
+ const queryType = await screen.findByLabelText(/Query type/);
+
+ await waitFor(() => select(queryType, 'PromQL', { container: document.body }));
+
+ expect(onChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ refId: mockQuery.refId,
+ datasource: mockQuery.datasource,
+ queryType: QueryType.PROMQL,
+ })
+ );
+ });
});
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
index 0d1eec582c8..a6104921f34 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
@@ -1,11 +1,13 @@
+import deepEqual from 'fast-deep-equal';
import { isEqual } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { QueryEditorProps, getDefaultTimeRange, toOption } from '@grafana/data';
import { EditorRows } from '@grafana/experimental';
import { ConfirmModal } from '@grafana/ui';
import CloudMonitoringDatasource from '../datasource';
+import { selectors } from '../e2e/selectors';
import { CloudMonitoringQuery, PromQLQuery, QueryType, SLOQuery } from '../types/query';
import { CloudMonitoringOptions } from '../types/types';
@@ -19,24 +21,16 @@ import { MetricQueryEditor, SLOQueryEditor } from './';
export type Props = QueryEditorProps;
export const QueryEditor = (props: Props) => {
- const { datasource, query: oldQ, onRunQuery, onChange, range } = props;
+ const { datasource, query, onRunQuery, onChange, range } = props;
const [modalIsOpen, setModalIsOpen] = useState(false);
- const [migratedQuery, setMigratedQuery] = useState();
- const query = useMemo(() => {
- if (!migratedQuery) {
- const migratedQuery = datasource.migrateQuery(oldQ);
- setMigratedQuery(migratedQuery);
- // Update the query once the migrations have been completed.
- onChange({ ...migratedQuery });
- return migratedQuery;
- }
- if (migratedQuery) {
- return migratedQuery;
+ useEffect(() => {
+ const migrated = datasource.migrateQuery(query);
+ if (!deepEqual(migrated, query)) {
+ onChange({ ...migrated });
}
+ }, [query, datasource, onChange]);
- return oldQ;
- }, [oldQ, datasource, onChange, migratedQuery]);
const [currentQuery, setCurrentQuery] = useState(query);
const [queryHasBeenEdited, setQueryHasBeenEdited] = useState(false);
@@ -95,62 +89,64 @@ export const QueryEditor = (props: Props) => {
};
return (
-
- {
- setModalIsOpen(false);
- onChange(currentQuery);
- setQueryHasBeenEdited(false);
- }}
- confirmText="Confirm"
- onDismiss={() => {
- setModalIsOpen(false);
- setCurrentQuery(query);
- }}
- />
-
-
- {queryType === QueryType.PROMQL && (
-
+
+ {
+ setModalIsOpen(false);
+ onChange(currentQuery);
+ setQueryHasBeenEdited(false);
+ }}
+ confirmText="Confirm"
+ onDismiss={() => {
+ setModalIsOpen(false);
+ setCurrentQuery(query);
+ }}
/>
- )}
+
- {queryType !== QueryType.SLO && (
-
- )}
+ {queryType === QueryType.PROMQL && (
+
+ )}
- {queryType === QueryType.SLO && (
- onChange({ ...query, aliasBy })}
- />
- )}
-
+ {queryType !== QueryType.SLO && (
+
+ )}
+
+ {queryType === QueryType.SLO && (
+ onChange({ ...query, aliasBy })}
+ />
+ )}
+
+
);
};
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
index 04ab30b94fe..af753ae72df 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
@@ -5,6 +5,7 @@ import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental'
import { ALIGNMENT_PERIODS, SLO_BURN_RATE_SELECTOR_NAME } from '../constants';
import CloudMonitoringDatasource from '../datasource';
+import { selectors } from '../e2e/selectors';
import { alignmentPeriodLabel } from '../functions';
import { AlignmentTypes, SLOQuery } from '../types/query';
import { CustomMetaData } from '../types/types';
@@ -54,7 +55,7 @@ export function SLOQueryEditor({
}: React.PropsWithChildren) {
const alignmentLabel = useMemo(() => alignmentPeriodLabel(customMetaData, datasource), [customMetaData, datasource]);
return (
- <>
+
- >
+
);
}
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
index 4815ffa2949..a5d57040047 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
@@ -9,6 +9,7 @@ import { reportInteraction } from '@grafana/runtime';
import { getSelectStyles, Select, AsyncSelect, useStyles2, useTheme2 } from '@grafana/ui';
import CloudMonitoringDatasource from '../datasource';
+import { selectors } from '../e2e/selectors';
import { getAlignmentPickerData, getMetricType, setMetricType } from '../functions';
import { PreprocessorType, TimeSeriesList, MetricKind, ValueTypes } from '../types/query';
import { CustomMetaData, MetricDescriptor } from '../types/types';
@@ -223,7 +224,7 @@ export function Editor({
};
return (
- <>
+
>
- >
+
);
}
diff --git a/public/app/plugins/datasource/cloud-monitoring/e2e/selectors.ts b/public/app/plugins/datasource/cloud-monitoring/e2e/selectors.ts
new file mode 100644
index 00000000000..fd88d490408
--- /dev/null
+++ b/public/app/plugins/datasource/cloud-monitoring/e2e/selectors.ts
@@ -0,0 +1,30 @@
+import { E2ESelectors } from '@grafana/e2e-selectors';
+
+export const components = {
+ queryEditor: {
+ container: 'data-testid cloud-monitoring-query-editor',
+ header: {
+ select: 'data-testid cloud-monitoring-header',
+ },
+ visualMetricsQueryEditor: {
+ container: { input: 'data-testid cloud-monitoring-visual-metrics-query-editor' },
+ },
+ mqlMetricsQueryEditor: {
+ container: { input: 'data-testid cloud-monitoring-mql-query-editor' },
+ },
+ sloQueryEditor: {
+ container: {
+ input: 'data-testid cloud-monitoring-slo-query-editor',
+ },
+ },
+ promQlQueryEditor: {
+ container: {
+ input: 'data-testid cloud-monitoring-prom-ql-query-editor',
+ },
+ },
+ },
+};
+
+export const selectors: { components: E2ESelectors } = {
+ components: components,
+};