Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
alerting
/
unified
/
components
/
rule-editor
/
File Content:
AnnotationsStep.test.tsx
import { findByRole, findByText, findByTitle, getByTestId, queryByText, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { setupServer } from 'msw/node'; import React from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { TestProvider } from 'test/helpers/TestProvider'; import { byRole, byTestId } from 'testing-library-selector'; import 'core-js/stable/structured-clone'; import { setBackendSrv } from '@grafana/runtime'; import { backendSrv } from 'app/core/services/backend_srv'; import { DashboardSearchItemType } from '../../../../search/types'; import { mockDashboardApi } from '../../mockApi'; import { mockDashboardDto, mockDashboardSearchItem, mockStore } from '../../mocks'; import { RuleFormValues } from '../../types/rule-form'; import { Annotation } from '../../utils/constants'; import { getDefaultFormValues } from '../../utils/rule-form'; import 'whatwg-fetch'; import AnnotationsStep from './AnnotationsStep'; // To get anything displayed inside the Autosize component we need to mock it // Ref https://github.com/bvaughn/react-window/issues/454#issuecomment-646031139 jest.mock( 'react-virtualized-auto-sizer', () => ({ children }: { children: ({ height, width }: { height: number; width: number }) => JSX.Element }) => children({ height: 500, width: 330 }) ); const ui = { setDashboardButton: byRole('button', { name: 'Link dashboard and panel' }), annotationKeys: byTestId('annotation-key-', { exact: false }), annotationValues: byTestId('annotation-value-', { exact: false }), dashboardAnnotation: byTestId('dashboard-annotation'), panelAnnotation: byTestId('panel-annotation'), dashboardPicker: { dialog: byRole('dialog'), heading: byRole('heading', { name: 'Select dashboard and panel' }), confirmButton: byRole('button', { name: 'Confirm' }), }, } as const; const server = setupServer(); beforeAll(() => { setBackendSrv(backendSrv); server.listen({ onUnhandledRequest: 'error' }); }); beforeEach(() => { server.resetHandlers(); }); afterAll(() => { server.close(); }); function FormWrapper({ formValues }: { formValues?: Partial<RuleFormValues> }) { const store = mockStore(() => null); const formApi = useForm<RuleFormValues>({ defaultValues: { ...getDefaultFormValues(), ...formValues } }); return ( <TestProvider store={store}> <FormProvider {...formApi}> <AnnotationsStep /> </FormProvider> </TestProvider> ); } describe('AnnotationsField', function () { it('should display default list of annotations', function () { render(<FormWrapper />); const annotationElements = ui.annotationKeys.getAll(); expect(annotationElements).toHaveLength(3); expect(annotationElements[0]).toHaveTextContent('Summary'); expect(annotationElements[1]).toHaveTextContent('Description'); expect(annotationElements[2]).toHaveTextContent('Runbook URL'); }); describe('Dashboard and panel picker', function () { it('should display dashboard and panel selector when select button clicked', async function () { mockDashboardApi(server).search([]); const user = userEvent.setup(); render(<FormWrapper />); await user.click(ui.setDashboardButton.get()); expect(ui.dashboardPicker.dialog.get()).toBeInTheDocument(); expect(ui.dashboardPicker.heading.get()).toBeInTheDocument(); }); it('should enable Confirm button only when dashboard and panel selected', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'First panel', type: 'timeseries' }, { id: 2, title: 'Second panel', type: 'timeseries' }, ], }) ); const user = userEvent.setup(); render(<FormWrapper />); await user.click(ui.setDashboardButton.get()); expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled(); await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard')); expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled(); await user.click(await findByText(ui.dashboardPicker.dialog.get(), 'First panel')); expect(ui.dashboardPicker.confirmButton.get()).toBeEnabled(); }); it('should add selected dashboard and panel as annotations', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'First panel', type: 'graph' }, { id: 2, title: 'Second panel', type: 'graph' }, ], }) ); const user = userEvent.setup(); render(<FormWrapper formValues={{ annotations: [] }} />); await user.click(ui.setDashboardButton.get()); await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard')); await user.click(await findByText(ui.dashboardPicker.dialog.get(), 'Second panel')); await user.click(ui.dashboardPicker.confirmButton.get()); const annotationValueElements = ui.annotationValues.getAll(); expect(ui.dashboardPicker.dialog.query()).not.toBeInTheDocument(); expect(annotationValueElements).toHaveLength(2); expect(annotationValueElements[0]).toHaveTextContent('dash-test-uid'); expect(annotationValueElements[1]).toHaveTextContent('2'); }); it('should not show rows as panels', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'Row panel', type: 'row' }, { id: 2, title: 'First panel', type: 'timeseries' }, ], }) ); const user = userEvent.setup(); render(<FormWrapper />); await user.click(ui.setDashboardButton.get()); expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled(); await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard')); expect(await findByText(ui.dashboardPicker.dialog.get(), 'First panel')).toBeInTheDocument(); expect(await queryByText(ui.dashboardPicker.dialog.get(), 'Row panel')).not.toBeInTheDocument(); }); it('should show panels within collapsed rows', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'First panel', type: 'timeseries' }, { id: 2, title: 'Row panel', collapsed: true, type: 'row', panels: [{ id: 3, title: 'Panel within collapsed row', type: 'timeseries' }], }, ], }) ); const user = userEvent.setup(); render(<FormWrapper />); await user.click(ui.setDashboardButton.get()); expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled(); await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard')); expect(await findByText(ui.dashboardPicker.dialog.get(), 'First panel')).toBeInTheDocument(); expect(await queryByText(ui.dashboardPicker.dialog.get(), 'Row panel')).not.toBeInTheDocument(); expect(await findByText(ui.dashboardPicker.dialog.get(), 'Panel within collapsed row')).toBeInTheDocument(); }); // this test _should_ work in theory but something is stopping the 'onClick' function on the dashboard item // to trigger "handleDashboardChange" – skipping it for now but has been manually tested. it.skip('should update existing dashboard and panel identifies', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), mockDashboardSearchItem({ title: 'My other dashboard', uid: 'dash-other-uid', type: DashboardSearchItemType.DashDB, }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'First panel', type: 'timeseries' }, { id: 2, title: 'Second panel', type: 'timeseries' }, ], }) ); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My other dashboard', uid: 'dash-other-uid', panels: [{ id: 3, title: 'Third panel', type: 'timeseries' }], }) ); const user = userEvent.setup(); render( <FormWrapper formValues={{ annotations: [ { key: Annotation.dashboardUID, value: 'dash-test-uid' }, { key: Annotation.panelID, value: '1' }, ], }} /> ); let annotationValueElements = ui.annotationValues.getAll(); expect(annotationValueElements[0]).toHaveTextContent('dash-test-uid'); expect(annotationValueElements[1]).toHaveTextContent('1'); const { confirmButton, dialog } = ui.dashboardPicker; await user.click(ui.setDashboardButton.get()); await user.click(await findByRole(dialog.get(), 'button', { name: /My other dashboard/ })); await user.click(await findByRole(dialog.get(), 'button', { name: /Third panel/ })); await user.click(confirmButton.get()); expect(ui.dashboardPicker.dialog.query()).not.toBeInTheDocument(); const annotationKeyElements = ui.annotationKeys.getAll(); annotationValueElements = ui.annotationValues.getAll(); expect(annotationKeyElements).toHaveLength(2); expect(annotationValueElements).toHaveLength(2); expect(annotationKeyElements[0]).toHaveTextContent('Dashboard UID'); expect(annotationValueElements[0]).toHaveTextContent('dash-other-uid'); expect(annotationKeyElements[1]).toHaveTextContent('Panel ID'); expect(annotationValueElements[1]).toHaveTextContent('3'); }); }); it('should render warning icon for panels of type other than graph and timeseries', async function () { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [ { id: 1, title: 'First panel', type: 'bar' }, { id: 2, title: 'Second panel', type: 'graph' }, { type: 'timeseries' }, // Panels might NOT have id and title fields ], }) ); const user = userEvent.setup(); render(<FormWrapper formValues={{ annotations: [] }} />); const { dialog } = ui.dashboardPicker; await user.click(ui.setDashboardButton.get()); await user.click(await findByTitle(dialog.get(), 'My dashboard')); const warnedPanel = await findByRole(dialog.get(), 'button', { name: /First panel/ }); expect(getByTestId(warnedPanel, 'warning-icon')).toBeInTheDocument(); }); it('should render when panels do not contain certain fields', async () => { mockDashboardApi(server).search([ mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }), ]); mockDashboardApi(server).dashboard( mockDashboardDto({ title: 'My dashboard', uid: 'dash-test-uid', panels: [{ type: 'row' }, { type: 'timeseries' }, { id: 4, type: 'graph' }, { title: 'Graph', type: 'graph' }], }) ); render( <FormWrapper formValues={{ annotations: [ { key: Annotation.dashboardUID, value: 'dash-test-uid' }, { key: Annotation.panelID, value: '1' }, ], }} /> ); expect(await ui.dashboardAnnotation.find()).toBeInTheDocument(); expect(ui.dashboardAnnotation.get()).toHaveTextContent('My dashboard'); expect(ui.panelAnnotation.query()).not.toBeInTheDocument(); }); });
Submit
FILE
FOLDER
INFO
Name
Size
Permission
Action
__snapshots__
---
0755
alert-rule-form
---
0755
notificaton-preview
---
0755
query-and-alert-condition
---
0755
rule-types
---
0755
AlertRuleNameInput.tsx
1548 bytes
0644
AnnotationHeaderField.tsx
2118 bytes
0644
AnnotationKeyInput.tsx
1011 bytes
0644
AnnotationsStep.test.tsx
12955 bytes
0644
AnnotationsStep.tsx
9351 bytes
0644
CloudAlertPreview.tsx
2447 bytes
0644
CloudEvaluationBehavior.tsx
2339 bytes
0644
CloudRulesSourcePicker.tsx
1232 bytes
0644
CustomAnnotationHeaderField.tsx
978 bytes
0644
DashboardAnnotationField.tsx
2211 bytes
0644
DashboardPicker.test.tsx
2359 bytes
0644
DashboardPicker.tsx
11583 bytes
0644
ExpressionEditor.tsx
4464 bytes
0644
ExpressionsEditor.tsx
2456 bytes
0644
FolderAndGroup.tsx
15170 bytes
0644
GrafanaAlertStatePicker.tsx
1246 bytes
0644
GrafanaEvaluationBehavior.tsx
11886 bytes
0644
GrafanaRuleInspector.tsx
0 bytes
0644
GroupAndNamespaceFields.tsx
3633 bytes
0644
LabelsField.test.tsx
5489 bytes
0644
LabelsField.tsx
11099 bytes
0644
NeedHelpInfo.tsx
1656 bytes
0644
NotificationsStep.tsx
9351 bytes
0644
PreviewRule.tsx
3862 bytes
0644
PreviewRuleResult.tsx
2519 bytes
0644
QueryEditor.tsx
1317 bytes
0644
QueryOptions.tsx
2986 bytes
0644
QueryRows.tsx
10036 bytes
0644
QueryWrapper.tsx
8477 bytes
0644
RecordingRuleEditor.tsx
3160 bytes
0644
RecordingRulesNameSpaceAndGroupStep.tsx
743 bytes
0644
RuleEditorSection.tsx
1387 bytes
0644
RuleFolderPicker.tsx
2311 bytes
0644
RuleInspector.tsx
4989 bytes
0644
SelectWIthAdd.tsx
2207 bytes
0644
VizWrapper.tsx
2873 bytes
0644
dag.test.ts
3645 bytes
0644
dag.ts
3498 bytes
0644
preview.test.ts
5286 bytes
0644
preview.ts
1541 bytes
0644
useDashboardQuery.ts
1014 bytes
0644
util.test.ts
12574 bytes
0644
util.ts
11522 bytes
0644
N4ST4R_ID | Naxtarrr