grafana/public/app/features/explore/AddToDashboard/addToDashboard.test.ts
Torkel Ödegaard 7181efd1cf
Explore: Allow users to save Explore queries to dashboards (#47083)
* Select: Expose AsyncSelectProps interface

* DashboardPicker: Add a generic DashboardPicker component

* Dashboard Service: improve types

* Explore: allow saving explore state in a new panel in an existing dashboard

* Handle saving provisioned dashboards error

* Improve test coverage

* simplify test setup

* Strip base path from url when redirecting to a dashboard

* Keep existing variables when saving to an existing dashboard

* group assertions in test

* SearchCard: handle undefined in meta.updated

* Change required error message

* Add to dashboard alternative

* Add to existing is working

* Add to dashboard form

* remove default add-panel when creating a dashboard from explore

* types cleanup

* remove unneeded BE change

* simplify selector

* Add explore2Dashboard feature toggle

* add tests

* Small refactor & add tests

* small DashboardPicker improvements

* use partial from lodash

* Better error handling

* improve tests & disable button when there are no queries

* rename addPanelToDashboard function

* remove localStorage item if opening tab fails

* UI touchups & tracking

* Fix tests & remove close reporting

* remove echologger debug

* fix adding a panel to an existing dashboard

* Enable explore2Dashboard by default and add docs

* Ensure each panel in dashboards has a valid ID

* force CI restart

Co-authored-by: Elfo404 <me@giordanoricci.com>
2022-04-12 13:26:07 +02:00

147 lines
5.1 KiB
TypeScript

import { DataQuery, MutableDataFrame } from '@grafana/data';
import { ExplorePanelData } from 'app/types';
import { createEmptyQueryResponse } from '../state/utils';
import { setDashboardInLocalStorage } from './addToDashboard';
import * as api from 'app/features/dashboard/state/initDashboard';
import { backendSrv } from 'app/core/services/backend_srv';
describe('addPanelToDashboard', () => {
let spy: jest.SpyInstance;
beforeAll(() => {
spy = jest.spyOn(api, 'setDashboardToFetchFromLocalStorage');
});
afterEach(() => {
jest.resetAllMocks();
});
it('Correct datasource ref is used', async () => {
await setDashboardInLocalStorage({
queries: [],
queryResponse: createEmptyQueryResponse(),
datasource: { type: 'loki', uid: 'someUid' },
});
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
dashboard: expect.objectContaining({
panels: expect.arrayContaining([expect.objectContaining({ datasource: { type: 'loki', uid: 'someUid' } })]),
}),
})
);
});
it('All queries are correctly passed through', async () => {
const queries: DataQuery[] = [{ refId: 'A' }, { refId: 'B', hide: true }];
await setDashboardInLocalStorage({
queries,
queryResponse: createEmptyQueryResponse(),
});
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
dashboard: expect.objectContaining({
panels: expect.arrayContaining([expect.objectContaining({ targets: expect.arrayContaining(queries) })]),
}),
})
);
});
it('Previous panels should not be removed', async () => {
const queries: DataQuery[] = [{ refId: 'A' }];
const existingPanel = { prop: 'this should be kept' };
jest.spyOn(backendSrv, 'getDashboardByUid').mockResolvedValue({
dashboard: {
templating: { list: [] },
title: 'Previous panels should not be removed',
uid: 'someUid',
panels: [existingPanel],
},
meta: {},
});
await setDashboardInLocalStorage({
queries,
queryResponse: createEmptyQueryResponse(),
dashboardUid: 'someUid',
datasource: { type: '' },
});
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
dashboard: expect.objectContaining({
panels: expect.arrayContaining([
expect.objectContaining({ targets: expect.arrayContaining(queries) }),
existingPanel,
]),
}),
})
);
});
describe('Setting visualization type', () => {
describe('Defaults to table', () => {
const cases: Array<[string, DataQuery[], ExplorePanelData]> = [
['If response is empty', [{ refId: 'A' }], createEmptyQueryResponse()],
['If no query is active', [{ refId: 'A', hide: true }], createEmptyQueryResponse()],
[
'If no query is active, even when there is a response from a previous execution',
[{ refId: 'A', hide: true }],
{ ...createEmptyQueryResponse(), logsFrames: [new MutableDataFrame({ refId: 'A', fields: [] })] },
],
[
// trace view is not supported in dashboards, we expect to fallback to table panel
'If there are trace frames',
[{ refId: 'A' }],
{ ...createEmptyQueryResponse(), traceFrames: [new MutableDataFrame({ refId: 'A', fields: [] })] },
],
];
it.each(cases)('%s', async (_, queries, queryResponse) => {
await setDashboardInLocalStorage({ queries, queryResponse });
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
dashboard: expect.objectContaining({
panels: expect.arrayContaining([expect.objectContaining({ type: 'table' })]),
}),
})
);
});
});
describe('Correctly set visualization based on response', () => {
type TestArgs = {
framesType: string;
expectedPanel: string;
};
// Note: traceFrames test is "duplicated" in "Defaults to table" tests.
// This is intentional as a way to enforce explicit tests for that case whenever in the future we'll
// add support for creating traceview panels
it.each`
framesType | expectedPanel
${'logsFrames'} | ${'logs'}
${'graphFrames'} | ${'timeseries'}
${'nodeGraphFrames'} | ${'nodeGraph'}
${'traceFrames'} | ${'table'}
`(
'Sets visualization to $expectedPanel if there are $frameType frames',
async ({ framesType, expectedPanel }: TestArgs) => {
const queries = [{ refId: 'A' }];
const queryResponse: ExplorePanelData = {
...createEmptyQueryResponse(),
[framesType]: [new MutableDataFrame({ refId: 'A', fields: [] })],
};
await setDashboardInLocalStorage({ queries, queryResponse });
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
dashboard: expect.objectContaining({
panels: expect.arrayContaining([expect.objectContaining({ type: expectedPanel })]),
}),
})
);
}
);
});
});
});