D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
usr
/
share
/
grafana
/
public
/
app
/
plugins
/
datasource
/
cloudwatch
/
components
/
Filename :
QueryEditor.test.tsx
back
Copy
import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { QueryEditorProps } from '@grafana/data'; import { config } from '@grafana/runtime'; import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource'; import { validLogsQuery, validMetricQueryBuilderQuery, validMetricQueryCodeQuery, validMetricSearchBuilderQuery, validMetricSearchCodeQuery, } from '../__mocks__/queries'; import { CloudWatchDatasource } from '../datasource'; import { CloudWatchQuery, CloudWatchJsonData, MetricEditorMode, MetricQueryType } from '../types'; import { QueryEditor } from './QueryEditor'; // the following three fields are added to legacy queries in the dashboard migrator const migratedFields = { statistic: 'Average', metricEditorMode: MetricEditorMode.Builder, metricQueryType: MetricQueryType.Query, }; const props: QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> = { datasource: setupMockedDataSource().datasource, onRunQuery: jest.fn(), onChange: jest.fn(), query: {} as CloudWatchQuery, }; const FAKE_EDITOR_LABEL = 'FakeEditor'; jest.mock('./SQLCodeEditor', () => ({ SQLCodeEditor: ({ sql, onChange }: { sql: string; onChange: (val: string) => void }) => { return ( <> <label htmlFor="cloudwatch-fake-editor">{FAKE_EDITOR_LABEL}</label> <input id="cloudwatch-fake-editor" value={sql} onChange={(e) => onChange(e.currentTarget.value)}></input> </> ); }, })); export { SQLCodeEditor } from './SQLCodeEditor'; jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), config: { ...jest.requireActual('@grafana/runtime').config, featureToggles: { cloudWatchCrossAccountQuerying: true, }, }, })); describe('QueryEditor should render right editor', () => { describe('when using grafana 6.3.0 metric query', () => { it('should render the metrics query editor', async () => { const query = { ...migratedFields, dimensions: { InstanceId: 'i-123', }, expression: '', highResolution: false, id: '', metricName: 'CPUUtilization', namespace: 'AWS/EC2', period: '', refId: 'A', region: 'default', returnData: false, }; render(<QueryEditor {...props} query={query} />); expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); describe('when using grafana 7.0.0 style metrics query', () => { it('should render the metrics query editor', async () => { const query = { ...migratedFields, alias: '', apiMode: 'Metrics', dimensions: { InstanceId: 'i-123', }, expression: '', id: '', logGroupNames: [], matchExact: true, metricName: 'CPUUtilization', namespace: 'AWS/EC2', period: '', queryMode: 'Metrics', refId: 'A', region: 'ap-northeast-2', statistics: 'Average', } as CloudWatchQuery; render(<QueryEditor {...props} query={query} />); expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); describe('when using grafana 7.0.0 style logs query', () => { it('should render the logs query editor', async () => { const query = { ...migratedFields, alias: '', apiMode: 'Logs', dimensions: { InstanceId: 'i-123', }, expression: '', id: '', logGroupNames: [], matchExact: true, metricName: 'CPUUtilization', namespace: 'AWS/EC2', period: '', queryMode: 'Logs', refId: 'A', region: 'ap-northeast-2', statistic: 'Average', } as CloudWatchQuery; render(<QueryEditor {...props} query={query} />); expect(await screen.findByText('Select log groups')).toBeInTheDocument(); }); }); describe('when using grafana query from curated ec2 dashboard', () => { it('should render the metrics query editor', async () => { const query = { ...migratedFields, alias: 'Inbound', dimensions: { InstanceId: '*', }, expression: "SUM(REMOVE_EMPTY(SEARCH('{AWS/EC2,InstanceId} MetricName=\"NetworkIn\"', 'Sum', $period)))/$period", id: '', matchExact: true, metricName: 'NetworkOut', namespace: 'AWS/EC2', period: '$period', refId: 'B', region: '$region', statistic: 'Average', } as CloudWatchQuery; render(<QueryEditor {...props} query={query} />); expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); interface MonitoringBadgeScenario { name: string; query: CloudWatchQuery; toggle: boolean; } describe('monitoring badge', () => { let originalValue: boolean | undefined; let datasourceMock: ReturnType<typeof setupMockedDataSource>; beforeEach(() => { datasourceMock = setupMockedDataSource(); datasourceMock.datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(true); datasourceMock.datasource.resources.getMetrics = jest.fn().mockResolvedValue([]); datasourceMock.datasource.resources.getDimensionKeys = jest.fn().mockResolvedValue([]); originalValue = config.featureToggles.cloudWatchCrossAccountQuerying; }); afterEach(() => { config.featureToggles.cloudWatchCrossAccountQuerying = originalValue; }); describe('should be displayed when a monitoring account is returned and', () => { const cases: MonitoringBadgeScenario[] = [ { name: 'it is logs query and feature is enabled', query: validLogsQuery, toggle: true }, { name: 'it is metric search builder query and feature is enabled', query: validMetricSearchBuilderQuery, toggle: true, }, { name: 'it is metric search code query and feature is enabled', query: validMetricSearchCodeQuery, toggle: true, }, ]; test.each(cases)('$name', async ({ query, toggle }) => { config.featureToggles.cloudWatchCrossAccountQuerying = toggle; render(<QueryEditor {...props} datasource={datasourceMock.datasource} query={query} />); expect(await screen.findByText('Monitoring account')).toBeInTheDocument(); }); }); describe('should not be displayed when a monitoring account is returned and', () => { const cases: MonitoringBadgeScenario[] = [ { name: 'it is metric query builder query and toggle is enabled', query: validMetricQueryBuilderQuery, toggle: true, }, { name: 'it is metric query code query and toggle is not enabled', query: validMetricQueryCodeQuery, toggle: false, }, { name: 'it is logs query and feature is not enabled', query: validLogsQuery, toggle: false }, { name: 'it is metric search builder query and feature is not enabled', query: validMetricSearchBuilderQuery, toggle: false, }, { name: 'it is metric search code query and feature is not enabled', query: validMetricSearchCodeQuery, toggle: false, }, ]; test.each(cases)('$name', async ({ query, toggle }) => { config.featureToggles.cloudWatchCrossAccountQuerying = toggle; render(<QueryEditor {...props} datasource={datasourceMock.datasource} query={query} />); expect(await screen.findByText('Run queries')).toBeInTheDocument(); expect(screen.queryByText('Monitoring account')).toBeNull(); }); }); }); describe('QueryHeader', () => { it('should display metric actions in header when metric query is used', async () => { render(<QueryEditor {...props} query={validMetricQueryCodeQuery} />); expect(await screen.findByText('CloudWatch Metrics')).toBeInTheDocument(); expect(screen.getByLabelText(/Region.*/)).toBeInTheDocument(); expect(screen.getByLabelText('Builder')).toBeInTheDocument(); expect(screen.getByLabelText('Code')).toBeInTheDocument(); expect(screen.getByText('Metric Query')).toBeInTheDocument(); }); it('should display metric actions in header when metric query is used', async () => { render(<QueryEditor {...props} query={validLogsQuery} />); expect(await screen.findByText('CloudWatch Logs')).toBeInTheDocument(); expect(screen.getByLabelText(/Region.*/)).toBeInTheDocument(); expect(screen.queryByLabelText('Builder')).not.toBeInTheDocument(); expect(screen.queryByLabelText('Code')).not.toBeInTheDocument(); expect(screen.queryByText('Metric Query')).not.toBeInTheDocument(); }); }); describe('metrics editor should handle editor modes correctly', () => { it('when metric query type is metric search and editor mode is builder', async () => { render(<QueryEditor {...props} query={validMetricSearchBuilderQuery} />); expect(await screen.findByText('Metric Search')).toBeInTheDocument(); const radio = screen.getByLabelText('Builder'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric search and editor mode is raw', async () => { render(<QueryEditor {...props} query={validMetricSearchCodeQuery} />); expect(await screen.findByText('Metric Search')).toBeInTheDocument(); const radio = screen.getByLabelText('Code'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric query and editor mode is builder', async () => { render(<QueryEditor {...props} query={validMetricQueryBuilderQuery} />); expect(await screen.findByText('Metric Query')).toBeInTheDocument(); const radio = screen.getByLabelText('Builder'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric query and editor mode is raw', async () => { render(<QueryEditor {...props} query={validMetricQueryCodeQuery} />); expect(await screen.findByText('Metric Query')).toBeInTheDocument(); const radio = screen.getByLabelText('Code'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); }); describe('confirm modal', () => { it('should be shown when moving from code editor to builder when in sql mode', async () => { const sqlQuery = 'SELECT * FROM test'; render( <QueryEditor {...props} query={{ ...validMetricQueryCodeQuery, sqlExpression: sqlQuery }} onChange={jest.fn()} onRunQuery={jest.fn()} /> ); // the modal should not be shown unless the code editor is "dirty", so need to trigger a change const codeEditorElement = screen.getByLabelText(FAKE_EDITOR_LABEL); await userEvent.clear(codeEditorElement); await userEvent.type(codeEditorElement, 'select * from '); const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); await userEvent.click(builderElement); const modalTitleElem = screen.getByText('Are you sure?'); expect(modalTitleElem).toBeInTheDocument(); }); it('should not be shown when moving from builder to code when in sql mode', async () => { render( <QueryEditor {...props} query={validMetricQueryBuilderQuery} onChange={jest.fn()} onRunQuery={jest.fn()} /> ); const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); await userEvent.click(builderElement); expect(screen.queryByText('Are you sure?')).toBeNull(); }); it('should not be shown when moving from code to builder when in search mode', async () => { render(<QueryEditor {...props} query={validMetricSearchCodeQuery} onChange={jest.fn()} onRunQuery={jest.fn()} />); const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); await userEvent.click(builderElement); expect(screen.queryByText('Are you sure?')).toBeNull(); }); }); });