From 7bb76e0975b5553f3e727c19f3015a138b226f41 Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Fri, 4 Nov 2022 10:47:54 +0000 Subject: [PATCH] Azure Monitor: E2E Tests (#54619) * Update credentials form with data-testids and aria-labels * Update gitignore * Add example dashboard * Stub out E2E test for creating ds and importing dashboard * Add component selectors * Remove subscription check temporarily * Appropriately set disabled prop * Fix lint issues * Update to use selectors and wait on subscriptions request * Add test for metrics panel - Add required selectors for resource picker and metrics query editor * Add logs and ARG basic query scenarios - More selector updates * Add E2E test for template variables - Tests advanced resource picker - Adds required selectors * Remove log and add annotation e2e test * Update test * Prettier/betterer updates - Remove gitignore change * Lint issues * Update betterer results * Lint issue and remove unneeded import * Don't print certain commands * Avoiding flakiness - Ensure code editor has sufficient time to load in ARG test - Avoid flakiness around correct template variable being selected by typing in resource name * Remove be.visible requirement * Update test * Update selector name * Reuse datasource * Fix datasource reuse and combine query tests * Remove import dashboard step as unneeded * Review - Randomise datasource name - Skip annotations test - Remove unused example dashboard * Update to ensure e2e test works in CI * Update e2e test - Update environment variables (process is not available in cypress) - Add wait on resource picker searches to avoid flakiness - Update subscription and resource group names * Update CODEOWNERS * Parse credentials in CI from outputs file * Update outputs file path * Fix selector * Undo selector change * Update e2e tests - Set default subscription - Fix datasource selection in variable editor - Fix resource picker search flakiness - Set subscription in ARG query test - Fix resource group selection - Update resource group * Review * Review 2 --- .github/CODEOWNERS | 1 + e2e/cloud-plugins-suite/azure-monitor.spec.ts | 298 ++++++++++++++++++ .../grafana-e2e/src/flows/configurePanel.ts | 2 +- .../ArgQueryEditor/ArgQueryEditor.test.tsx | 21 +- .../ArgQueryEditor/ArgQueryEditor.tsx | 3 +- .../components/AzureCredentialsForm.tsx | 158 +++++----- .../LogsQueryEditor/FormatAsField.tsx | 3 +- .../MetricsQueryEditor/MetricNameField.tsx | 3 +- .../QueryEditor/QueryEditor.test.tsx | 4 +- .../components/QueryHeader.tsx | 3 +- .../ResourceField/ResourceField.tsx | 5 +- .../components/ResourcePicker/Advanced.tsx | 7 +- .../ResourcePicker/ResourcePicker.tsx | 7 +- .../components/ResourcePicker/Search.tsx | 3 + .../components/SubscriptionField.tsx | 5 +- .../VariableEditor/VariableEditor.tsx | 31 +- .../e2e/selectors.ts | 100 ++++++ 17 files changed, 561 insertions(+), 93 deletions(-) create mode 100644 e2e/cloud-plugins-suite/azure-monitor.spec.ts create mode 100644 public/app/plugins/datasource/grafana-azure-monitor-datasource/e2e/selectors.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 69fa184587b..78df7648155 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -118,6 +118,7 @@ go.sum @grafana/backend-platform /public/locales @grafana/user-essentials /public/app/core/internationalization @grafana/user-essentials /e2e @grafana/user-essentials +/e2e/cloud-plugins-suite @grafana/cloud-provider-plugins /packages @grafana/user-essentials @grafana/plugins-platform-frontend @grafana/grafana-bi-squad /packages/grafana-e2e-selectors @grafana/user-essentials /packages/grafana-e2e @grafana/user-essentials diff --git a/e2e/cloud-plugins-suite/azure-monitor.spec.ts b/e2e/cloud-plugins-suite/azure-monitor.spec.ts new file mode 100644 index 00000000000..db8fc29c235 --- /dev/null +++ b/e2e/cloud-plugins-suite/azure-monitor.spec.ts @@ -0,0 +1,298 @@ +import { load } from 'js-yaml'; +import { v4 as uuidv4 } from 'uuid'; + +import { e2e } from '@grafana/e2e'; + +import { selectors } from '../../public/app/plugins/datasource/grafana-azure-monitor-datasource/e2e/selectors'; +import { + AzureDataSourceJsonData, + AzureDataSourceSecureJsonData, + AzureQueryType, +} from '../../public/app/plugins/datasource/grafana-azure-monitor-datasource/types'; + +const provisioningPath = `../../provisioning/datasources/azmonitor-ds.yaml`; +const e2eSelectors = e2e.getSelectors(selectors.components); + +type AzureMonitorConfig = { + secureJsonData: AzureDataSourceSecureJsonData; + jsonData: AzureDataSourceJsonData; +}; + +type AzureMonitorProvision = { datasources: AzureMonitorConfig[] }; + +const dataSourceName = `Azure Monitor E2E Tests - ${uuidv4()}`; + +function provisionAzureMonitorDatasources(datasources: AzureMonitorProvision[]) { + const datasource = datasources[0].datasources[0]; + + e2e() + .intercept(/subscriptions/) + .as('subscriptions'); + + e2e.flows.addDataSource({ + type: 'Azure Monitor', + name: dataSourceName, + form: () => { + e2eSelectors.configEditor.azureCloud.input().find('input').type('Azure').type('{enter}'); + // We set the log value to false here to ensure that secrets aren't printed to logs + e2eSelectors.configEditor.tenantID.input().find('input').type(datasource.jsonData.tenantId, { log: false }); + e2eSelectors.configEditor.clientID.input().find('input').type(datasource.jsonData.clientId, { log: false }); + e2eSelectors.configEditor.clientSecret + .input() + .find('input') + .type(datasource.secureJsonData.clientSecret, { log: false }); + e2eSelectors.configEditor.loadSubscriptions.button().click().wait('@subscriptions').wait(500); + e2eSelectors.configEditor.defaultSubscription.input().find('input').type('datasources{enter}'); + }, + expectedAlertMessage: 'Successfully connected to all Azure Monitor endpoints', + }); +} + +const addAzureMonitorVariable = ( + name: string, + type: AzureQueryType, + isFirst: boolean, + options?: { subscription?: string; resourceGroup?: string; namespace?: string; resource?: string } +) => { + e2e.components.PageToolbar.item('Dashboard settings').click(); + e2e.components.Tab.title('Variables').click(); + if (isFirst) { + e2e.pages.Dashboard.Settings.Variables.List.addVariableCTAV2().click(); + } else { + e2e.pages.Dashboard.Settings.Variables.List.newButton().click(); + } + e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2().clear().type(name); + e2e.components.DataSourcePicker.inputV2().type(`${dataSourceName}{enter}`); + e2eSelectors.variableEditor.queryType + .input() + .find('input') + .type(`${type.replace('Azure', '').trim()}{enter}`); + switch (type) { + case AzureQueryType.ResourceGroupsQuery: + e2eSelectors.variableEditor.subscription.input().find('input').type(`${options?.subscription}{enter}`); + break; + case AzureQueryType.NamespacesQuery: + e2eSelectors.variableEditor.subscription.input().find('input').type(`${options?.subscription}{enter}`); + e2eSelectors.variableEditor.resourceGroup.input().find('input').type(`${options?.resourceGroup}{enter}`); + break; + case AzureQueryType.ResourceNamesQuery: + e2eSelectors.variableEditor.subscription.input().find('input').type(`${options?.subscription}{enter}`); + e2eSelectors.variableEditor.resourceGroup.input().find('input').type(`${options?.resourceGroup}{enter}`); + e2eSelectors.variableEditor.namespace.input().find('input').type(`${options?.namespace}{enter}`); + break; + case AzureQueryType.MetricNamesQuery: + e2eSelectors.variableEditor.subscription.input().find('input').type(`${options?.subscription}{enter}`); + e2eSelectors.variableEditor.resourceGroup.input().find('input').type(`${options?.resourceGroup}{enter}`); + e2eSelectors.variableEditor.namespace.input().find('input').type(`${options?.namespace}{enter}`); + e2eSelectors.variableEditor.resource.input().find('input').type(`${options?.resource}{enter}`); + break; + } + e2e.pages.Dashboard.Settings.Variables.Edit.General.submitButton().click(); + e2e.components.PageToolbar.item('Go Back').click(); +}; + +e2e.scenario({ + describeName: 'Add Azure Monitor datasource', + itName: 'fills out datasource connection configuration', + scenario: () => { + // This variable will be set in CI + const CI = e2e.env('CI'); + if (CI) { + e2e() + .readFile('../../outputs.json') + .then((outputs) => { + provisionAzureMonitorDatasources([ + { + datasources: [ + { + jsonData: { + cloudName: 'Azure', + tenantId: outputs.tenantId, + clientId: outputs.clientId, + }, + secureJsonData: { clientSecret: outputs.clientSecret }, + }, + ], + }, + ]); + }); + } else { + e2e() + .readFile(provisioningPath) + .then((azMonitorProvision: string) => { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const yaml = load(azMonitorProvision) as AzureMonitorProvision; + provisionAzureMonitorDatasources([yaml]); + }); + } + e2e.setScenarioContext({ addedDataSources: [] }); + }, +}); + +e2e.scenario({ + describeName: 'Create dashboard and add a panel for each query type', + itName: 'create dashboard, add panel for metrics query, log analytics query, and ARG query', + scenario: () => { + e2e.flows.addDashboard({ + timeRange: { + from: '2022-10-03 00:00:00', + to: '2022-10-03 23:59:59', + zone: 'Coordinated Universal Time', + }, + }); + e2e.flows.addPanel({ + dataSourceName, + visitDashboardAtStart: false, + queriesForm: () => { + e2eSelectors.queryEditor.resourcePicker.select.button().click(); + e2eSelectors.queryEditor.resourcePicker.search + .input() + .wait(100) + .type('azmonmetricstest') + .wait(500) + .type('{enter}'); + e2e().contains('azmonmetricstest').click(); + e2eSelectors.queryEditor.resourcePicker.apply.button().click(); + e2e().contains('microsoft.storage/storageaccounts'); + e2eSelectors.queryEditor.metricsQueryEditor.metricName.input().find('input').type('Used capacity{enter}'); + }, + }); + e2e.components.PanelEditor.applyButton().click(); + e2e.flows.addPanel({ + dataSourceName, + visitDashboardAtStart: false, + queriesForm: () => { + e2eSelectors.queryEditor.header.select().find('input').type('Logs{enter}'); + e2eSelectors.queryEditor.resourcePicker.select.button().click(); + e2eSelectors.queryEditor.resourcePicker.search + .input() + .wait(100) + .type('azmonlogstest') + .wait(500) + .type('{enter}'); + e2e().contains('azmonlogstest').click(); + e2eSelectors.queryEditor.resourcePicker.apply.button().click(); + e2e.components.CodeEditor.container().type('AzureDiagnostics'); + e2eSelectors.queryEditor.logsQueryEditor.formatSelection.input().type('Time series{enter}'); + }, + }); + e2e.components.PanelEditor.applyButton().click(); + e2e.flows.addPanel({ + dataSourceName, + visitDashboardAtStart: false, + queriesForm: () => { + e2eSelectors.queryEditor.header.select().find('input').type('Azure Resource Graph{enter}'); + e2e().wait(1000); // Need to wait for code editor to completely load + e2e().get('[aria-label="Remove Primary Subscription"]').click(); + e2eSelectors.queryEditor.argsQueryEditor.subscriptions.input().find('input').type('datasources{enter}'); + e2e.components.CodeEditor.container().type( + "Resources | where resourceGroup == 'cloud-plugins-e2e-test' | project name, resourceGroup" + ); + e2e.components.PanelEditor.toggleTableView().click({ force: true }); + }, + }); + }, +}); + +e2e.scenario({ + describeName: 'Create dashboard with template variables', + itName: 'creates a dashboard that includes a template variable', + scenario: () => { + e2e.flows.addDashboard({ + timeRange: { + from: '2022-10-03 00:00:00', + to: '2022-10-03 23:59:59', + zone: 'Coordinated Universal Time', + }, + }); + addAzureMonitorVariable('subscription', AzureQueryType.SubscriptionsQuery, true); + addAzureMonitorVariable('resourceGroups', AzureQueryType.ResourceGroupsQuery, false, { + subscription: '$subscription', + }); + addAzureMonitorVariable('namespaces', AzureQueryType.NamespacesQuery, false, { + subscription: '$subscription', + resourceGroup: '$resourceGroups', + }); + addAzureMonitorVariable('resource', AzureQueryType.ResourceNamesQuery, false, { + subscription: '$subscription', + resourceGroup: '$resourceGroups', + namespace: '$namespace', + }); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('subscription').click(); + e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('grafanalabs-datasources-dev').click(); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('resourceGroups').parent().find('button').click(); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('resourceGroups') + .parent() + .find('input') + .type('cloud-plugins-e2e-test{enter}'); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('namespaces').parent().find('button').click(); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('namespaces') + .parent() + .find('input') + .type('microsoft.storage/storageaccounts{enter}'); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('resource').parent().find('button').click(); + e2e.pages.Dashboard.SubMenu.submenuItemLabels('resource').parent().find('input').type('azmonmetricstest{enter}'); + e2e.flows.addPanel({ + dataSourceName, + visitDashboardAtStart: false, + queriesForm: () => { + e2eSelectors.queryEditor.resourcePicker.select.button().click(); + e2eSelectors.queryEditor.resourcePicker.advanced.collapse().click(); + e2eSelectors.queryEditor.resourcePicker.advanced.subscription.input().find('input').type('$subscription'); + e2eSelectors.queryEditor.resourcePicker.advanced.resourceGroup.input().find('input').type('$resourceGroups'); + e2eSelectors.queryEditor.resourcePicker.advanced.namespace.input().find('input').type('$namespaces'); + e2eSelectors.queryEditor.resourcePicker.advanced.resource.input().find('input').type('$resource'); + e2eSelectors.queryEditor.resourcePicker.apply.button().click(); + e2eSelectors.queryEditor.metricsQueryEditor.metricName.input().find('input').type('Transactions{enter}'); + }, + }); + }, +}); + +e2e.scenario({ + describeName: 'Create dashboard with annotation', + itName: 'creates a dashboard that includes an annotation', + scenario: () => { + e2e.flows.addDashboard({ + timeRange: { + from: '2022-10-03 00:00:00', + to: '2022-10-03 23:59:59', + zone: 'Coordinated Universal Time', + }, + }); + e2e.components.PageToolbar.item('Dashboard settings').click(); + e2e.components.Tab.title('Annotations').click(); + e2e.pages.Dashboard.Settings.Annotations.List.addAnnotationCTAV2().click(); + e2e.pages.Dashboard.Settings.Annotations.Settings.name().type('TestAnnotation'); + e2e.components.DataSourcePicker.inputV2().click().type(`${dataSourceName}{enter}`); + e2eSelectors.queryEditor.resourcePicker.select.button().click(); + e2eSelectors.queryEditor.resourcePicker.search.input().type('azmonmetricstest'); + e2e().contains('azmonmetricstest').click(); + e2eSelectors.queryEditor.resourcePicker.apply.button().click(); + e2e().contains('microsoft.storage/storageaccounts'); + e2eSelectors.queryEditor.metricsQueryEditor.metricName.input().find('input').type('Transactions{enter}'); + e2e().get('table').contains('text').parent().find('input').click().type('Transactions (number){enter}'); + e2e.components.PageToolbar.item('Go Back').click(); + e2e.flows.addPanel({ + dataSourceName, + visitDashboardAtStart: false, + queriesForm: () => { + e2eSelectors.queryEditor.resourcePicker.select.button().click(); + e2eSelectors.queryEditor.resourcePicker.search.input().type('azmonmetricstest'); + e2e().contains('azmonmetricstest').click(); + e2eSelectors.queryEditor.resourcePicker.apply.button().click(); + e2e().contains('microsoft.storage/storageaccounts'); + e2eSelectors.queryEditor.metricsQueryEditor.metricName.input().find('input').type('Used capacity{enter}'); + }, + }); + }, + skipScenario: true, +}); + +e2e.scenario({ + describeName: 'Remove datasource', + itName: 'remove azure monitor datasource', + scenario: () => { + e2e.flows.deleteDataSource({ name: dataSourceName, id: '', quick: true }); + }, +}); diff --git a/packages/grafana-e2e/src/flows/configurePanel.ts b/packages/grafana-e2e/src/flows/configurePanel.ts index 384bef3200c..d3aeb699629 100644 --- a/packages/grafana-e2e/src/flows/configurePanel.ts +++ b/packages/grafana-e2e/src/flows/configurePanel.ts @@ -148,7 +148,7 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC //e2e().wait('@chartData'); // Avoid annotations flakiness - e2e.components.RefreshPicker.runButtonV2().first().should('be.visible').click({ force: true }); + e2e.components.RefreshPicker.runButtonV2().first().click({ force: true }); e2e().wait('@chartData'); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.test.tsx index 838e9d5da1a..d9d223a69e9 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.test.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.test.tsx @@ -3,6 +3,7 @@ import React from 'react'; import createMockDatasource from '../../__mocks__/datasource'; import createMockQuery from '../../__mocks__/query'; +import { selectors } from '../../e2e/selectors'; import ArgQueryEditor from './ArgQueryEditor'; @@ -31,7 +32,9 @@ const defaultProps = { describe('ArgQueryEditor', () => { it('should render', async () => { render(); - expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.argsQueryEditor.container.input) + ).toBeInTheDocument(); }); it('should select a subscription from the fetched array', async () => { @@ -40,7 +43,9 @@ describe('ArgQueryEditor', () => { }); const onChange = jest.fn(); render(); - expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.argsQueryEditor.container.input) + ).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo'] })); }); @@ -50,7 +55,9 @@ describe('ArgQueryEditor', () => { subscriptions: ['bar'], }); render(); - expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.argsQueryEditor.container.input) + ).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['bar'] })); }); @@ -63,7 +70,9 @@ describe('ArgQueryEditor', () => { subscriptions: ['bar'], }); render(); - expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.argsQueryEditor.container.input) + ).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo'] })); expect(onChange).not.toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['bar'] })); }); @@ -77,7 +86,9 @@ describe('ArgQueryEditor', () => { subscriptions: ['foo', 'bar', 'foobar'], }); render(); - expect(await screen.findByTestId('azure-monitor-arg-query-editor-with-experimental-ui')).toBeInTheDocument(); + expect( + await screen.findByTestId(selectors.components.queryEditor.argsQueryEditor.container.input) + ).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo', 'bar'] })); expect(onChange).not.toHaveBeenCalledWith(expect.objectContaining({ subscriptions: ['foo', 'bar', 'foobar'] })); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx index 780e0de3753..79aaec260f1 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ArgQueryEditor/ArgQueryEditor.tsx @@ -4,6 +4,7 @@ import React, { useState, useMemo } from 'react'; import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental'; import Datasource from '../../datasource'; +import { selectors } from '../../e2e/selectors'; import { AzureMonitorErrorish, AzureMonitorOption, AzureMonitorQuery } from '../../types'; import SubscriptionField from '../SubscriptionField'; @@ -73,7 +74,7 @@ const ArgQueryEditor: React.FC = ({ }, [datasource]); return ( - + diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx index b5991492984..9bedcb7aa51 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx @@ -1,10 +1,12 @@ import React, { ChangeEvent, FunctionComponent, useEffect, useReducer, useState } from 'react'; import { SelectableValue } from '@grafana/data'; -import { InlineFormLabel, LegacyForms, Button, Select } from '@grafana/ui'; +import { InlineFormLabel, LegacyForms, Button, Select, InlineField } from '@grafana/ui'; import { isCredentialsComplete } from '../credentials'; +import { selectors } from '../e2e/selectors'; import { AzureAuthType, AzureCredentials } from '../types'; + const { Input } = LegacyForms; export interface Props { @@ -28,6 +30,8 @@ const authTypeOptions: Array> = [ }, ]; +const LABEL_WIDTH = 18; + export const AzureCredentialsForm: FunctionComponent = (props: Props) => { const { credentials, azureCloudOptions, onCredentialsChange, getSubscriptions, disabled } = props; const hasRequiredFields = isCredentialsComplete(credentials); @@ -153,68 +157,77 @@ export const AzureCredentialsForm: FunctionComponent = (props: Props) => return (
{props.managedIdentityEnabled && ( -
-
- - Authentication - - opt.value === credentials.authType)} + options={authTypeOptions} + onChange={onAuthTypeChange} + disabled={disabled} + /> + )} {credentials.authType === 'clientsecret' && ( <> {azureCloudOptions && ( -
-
- - Azure Cloud - - opt.value === credentials.azureCloud)} + options={azureCloudOptions} + onChange={onAzureCloudChange} + /> + )} -
-
- Directory (tenant) ID -
- -
+ +
+
-
-
-
- Application (client) ID -
- -
+ + +
+
-
+ {!disabled && (typeof credentials.clientSecret === 'symbol' ? (
@@ -231,27 +244,28 @@ export const AzureCredentialsForm: FunctionComponent = (props: Props) =>
) : ( -
-
- Client Secret -
- -
-
-
+ + + ))} )} {getSubscriptions && ( <>
-
+
Default Subscription
= ({ metricNames, query, variab const options = useMemo(() => [...metricNames, variableOptionGroup], [metricNames, variableOptionGroup]); return ( - + setInternalSelected(r)} /> - diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Search.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Search.tsx index fdb633fc7fc..f8621841c3c 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Search.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ResourcePicker/Search.tsx @@ -3,6 +3,8 @@ import React, { useEffect, useMemo, useState } from 'react'; import { Icon, Input } from '@grafana/ui'; +import { selectors } from '../../e2e/selectors'; + const Search = ({ searchFn }: { searchFn: (searchPhrase: string) => void }) => { const [searchFilter, setSearchFilter] = useState(''); @@ -25,6 +27,7 @@ const Search = ({ searchFn }: { searchFn: (searchPhrase: string) => void }) => { debouncedSearch(searchPhrase); }} placeholder="search for a resource" + data-testid={selectors.components.queryEditor.resourcePicker.search.input} /> ); }; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx index b93082020f2..cb349249883 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx @@ -3,6 +3,7 @@ import React, { useCallback, useMemo } from 'react'; import { SelectableValue } from '@grafana/data'; import { Select, MultiSelect } from '@grafana/ui'; +import { selectors } from '../e2e/selectors'; import { AzureMonitorQuery, AzureQueryEditorFieldProps, AzureMonitorOption, AzureQueryType } from '../types'; import { findOptions } from '../utils/common'; @@ -67,7 +68,7 @@ const SubscriptionField: React.FC = ({ const options = useMemo(() => [...subscriptions, variableOptionGroup], [subscriptions, variableOptionGroup]); return multiSelect ? ( - + = ({ /> ) : ( - + { )} {requireSubscription && ( - + { )} {(requireNamespace || hasNamespace) && ( - + } = { + components: components, +};