grafana/public/app/features/explore/state/actions.test.ts

417 lines
14 KiB
TypeScript
Raw Normal View History

import { PayloadAction } from '@reduxjs/toolkit';
import { DataQuery, DefaultTimeZone, LogsDedupStrategy, RawTimeRange, toUtc } from '@grafana/data';
import * as Actions from './actions';
import { changeDatasource, loadDatasource, navigateToExplore, refreshExplore } from './actions';
import { ExploreId, ExploreMode, ExploreUpdateState, ExploreUrlState } from 'app/types';
import { thunkTester } from 'test/core/thunk/thunkTester';
import {
initializeExploreAction,
InitializeExplorePayload,
loadDatasourcePendingAction,
loadDatasourceReadyAction,
setQueriesAction,
updateDatasourceInstanceAction,
updateUIStateAction,
} from './actionTypes';
import { Emitter } from 'app/core/core';
import { makeInitialUpdateState } from './reducers';
import { PanelModel } from 'app/features/dashboard/state';
import { updateLocation } from '../../../core/actions';
import { MockDataSourceApi } from '../../../../test/mocks/datasource_srv';
import * as DatasourceSrv from 'app/features/plugins/datasource_srv';
jest.mock('app/features/plugins/datasource_srv');
const getDatasourceSrvMock = (DatasourceSrv.getDatasourceSrv as any) as jest.Mock<DatasourceSrv.DatasourceSrv>;
beforeEach(() => {
getDatasourceSrvMock.mockClear();
getDatasourceSrvMock.mockImplementation(
() =>
({
getExternal: jest.fn().mockReturnValue([]),
get: jest.fn().mockReturnValue({
testDatasource: jest.fn(),
init: jest.fn(),
}),
} as any)
);
});
jest.mock('../../dashboard/services/TimeSrv', () => ({
getTimeSrv: jest.fn().mockReturnValue({
init: jest.fn(),
}),
}));
const t = toUtc();
const testRange = {
from: t,
to: t,
raw: {
from: t,
to: t,
},
};
jest.mock('app/core/utils/explore', () => ({
...jest.requireActual('app/core/utils/explore'),
getTimeRangeFromUrl: (range: RawTimeRange) => testRange,
}));
const setup = (updateOverides?: Partial<ExploreUpdateState>) => {
const exploreId = ExploreId.left;
const containerWidth = 1920;
const eventBridge = {} as Emitter;
const ui = { dedupStrategy: LogsDedupStrategy.none, showingGraph: false, showingLogs: false, showingTable: false };
const timeZone = DefaultTimeZone;
const range = testRange;
Explore & Dashboard: New Refresh picker (#16505) * Added RefreshButton * Added RefreshSelect * Added RefreshSelectButton * Added RefreshPicker * Removed the magic string Paused * Minor style changes and using Off instead of Pause * Added HeadlessSelect * Added HeadlessSelect story * Added SelectButton * Removed RefreshSelectButton * Added TimePicker and moved ClickOutsideWrapper to ui/components * Added TimePickerPopOver * Added react-calendar * Missed yarn lock file * Added inputs to popover * Added TimePicker and RefreshPicker to DashNav * Moved TimePicker and RefreshPicker to app/core * Added react-calendar to app and removed from ui/components * Fixed PopOver onClick * Moved everything back to ui components because of typings problems * Exporing RefreshPicker and TimePicker * Added Apply and inputs * Added typings * Added TimePickerInput and logic * Fixed parsing of string to Moments * Fixed range string * Styling and connecting the calendars and inputs * Changed Calendar styling * Added backward forward and zoom * Fixed responsive styles * Moved TimePicker and RefreshPicker into app core * Renamed menuIsOpen to isOpen * Changed from className={} to className="" * Moved Popover to TimePickerOptionGroup * Renamed all PopOver to Popover * Renamed popOver to popover and some minor refactorings * Renamed files with git mv * Added ButtonSelect and refactored RefreshPicker * Refactored TimePicker to use new ButtonSelect * Removed HeadlessSelect as suggested * fix: Fix typings and misc errors after rebase * wip: Enable time picker on dashboard and add tooltip * Merge branch 'master' into hugoh/new-timepicker-and-unified-component # Conflicts: # packages/grafana-ui/package.json # packages/grafana-ui/src/components/Input/Input.test.tsx # packages/grafana-ui/src/components/Input/Input.tsx # packages/grafana-ui/src/utils/validate.ts # public/app/features/dashboard/panel_editor/QueryOptions.tsx # yarn.lock * fix: Snapshot update * Move TimePicker default options into the TimePicker as statics, pass the tooltipContent down the line when wanted and wrap the button in a tooltip element * fix: Override internal state prop if we provide one in a prop * Updated snapshots * Let dashnav control refreshPicker state * feat: Add a stringToMs function * wip: RefreshPicker * wip: Move RefreshPicker to @grafana/ui * wip: Move TimePicker to @grafana/ui * wip: Remove comments * wip: Add refreshPicker to explore * wip: Use default intervals if the prop is missing * wip: Nicer way of setting defaults * fix: Control the select component * wip: Add onMoveForward/onMoveBack * Remove code related to the new time picker and refresh picker from dashnav * Fix: Typings after merge * chore: Minor fix after merge * chore: Remove _.map usage * chore: Moved refresh-picker logic out of the refresh picker since it will work a little differently in explore and dashboards until we have replaced the TimeSrv * feat: Add an Interval component to @grafana/ui * chore: Remove intervalId from redux state and move setInterval logic from ExploreToolbar to its own Interval component * feat: Add refreshInterval to Explore's URL state * feat: Pick up refreshInterval from url on page load * fix: Set default refreshInterval when no value can be retained from URL * fix: Update test initial state with refreshInterval * fix: Handle URLs before RefreshPicker * fix: Move RefreshInterval to url position 3 since the segments can take multiple positions * fix: A better way of detecting urls without RefreshInterval in Explore * chore: Some Explore typings * fix: Attach refresh picker to interval picker * chore: Sass fix for refresh button border radius * fix: Remove refreshInterval from URL * fix: Intervals now start when previous interval is finished * fix: Use clearTimeout instead of clearInterval * fix: Make sure there's a delay set before adding a timeout when we have slow explore queries * wip: Add refresh picker to dashboard * feat: Add util for removing keys with empty values * feat: RefreshPicker in dashboards and tmp rem out old RefreshPicker * fix: Remove the jumpy:ness in the refreshpicker * Changed placement and made it hide when your in dashboard settings * chore: Move logic related to refresh picker out of DashNav to its own component * feat: Add tooltip to refreshpicker * fix: Fix bug with refreshpicker not updating when setting to 'off' * fix: Make it possible to override refresh intervals using the dashboard intervals * chore: Change name of Interval to SetInterval to align with ecmascripts naming since its basically the same but declarative and async * fix: Use default intervals when auto refresh is empty in dashboard settings * fix: Hide time/interval picker when hidden is true on the model, such as on the home dashboard * fix: Interval picker will have to handle location changes since timeSrv wont * RefreshPicker: Refactoring refresh picker * RefreshPicker: minor refactoring
2019-04-16 02:15:23 -05:00
const urlState: ExploreUrlState = {
datasource: 'some-datasource',
queries: [],
range: range.raw,
mode: ExploreMode.Metrics,
Explore & Dashboard: New Refresh picker (#16505) * Added RefreshButton * Added RefreshSelect * Added RefreshSelectButton * Added RefreshPicker * Removed the magic string Paused * Minor style changes and using Off instead of Pause * Added HeadlessSelect * Added HeadlessSelect story * Added SelectButton * Removed RefreshSelectButton * Added TimePicker and moved ClickOutsideWrapper to ui/components * Added TimePickerPopOver * Added react-calendar * Missed yarn lock file * Added inputs to popover * Added TimePicker and RefreshPicker to DashNav * Moved TimePicker and RefreshPicker to app/core * Added react-calendar to app and removed from ui/components * Fixed PopOver onClick * Moved everything back to ui components because of typings problems * Exporing RefreshPicker and TimePicker * Added Apply and inputs * Added typings * Added TimePickerInput and logic * Fixed parsing of string to Moments * Fixed range string * Styling and connecting the calendars and inputs * Changed Calendar styling * Added backward forward and zoom * Fixed responsive styles * Moved TimePicker and RefreshPicker into app core * Renamed menuIsOpen to isOpen * Changed from className={} to className="" * Moved Popover to TimePickerOptionGroup * Renamed all PopOver to Popover * Renamed popOver to popover and some minor refactorings * Renamed files with git mv * Added ButtonSelect and refactored RefreshPicker * Refactored TimePicker to use new ButtonSelect * Removed HeadlessSelect as suggested * fix: Fix typings and misc errors after rebase * wip: Enable time picker on dashboard and add tooltip * Merge branch 'master' into hugoh/new-timepicker-and-unified-component # Conflicts: # packages/grafana-ui/package.json # packages/grafana-ui/src/components/Input/Input.test.tsx # packages/grafana-ui/src/components/Input/Input.tsx # packages/grafana-ui/src/utils/validate.ts # public/app/features/dashboard/panel_editor/QueryOptions.tsx # yarn.lock * fix: Snapshot update * Move TimePicker default options into the TimePicker as statics, pass the tooltipContent down the line when wanted and wrap the button in a tooltip element * fix: Override internal state prop if we provide one in a prop * Updated snapshots * Let dashnav control refreshPicker state * feat: Add a stringToMs function * wip: RefreshPicker * wip: Move RefreshPicker to @grafana/ui * wip: Move TimePicker to @grafana/ui * wip: Remove comments * wip: Add refreshPicker to explore * wip: Use default intervals if the prop is missing * wip: Nicer way of setting defaults * fix: Control the select component * wip: Add onMoveForward/onMoveBack * Remove code related to the new time picker and refresh picker from dashnav * Fix: Typings after merge * chore: Minor fix after merge * chore: Remove _.map usage * chore: Moved refresh-picker logic out of the refresh picker since it will work a little differently in explore and dashboards until we have replaced the TimeSrv * feat: Add an Interval component to @grafana/ui * chore: Remove intervalId from redux state and move setInterval logic from ExploreToolbar to its own Interval component * feat: Add refreshInterval to Explore's URL state * feat: Pick up refreshInterval from url on page load * fix: Set default refreshInterval when no value can be retained from URL * fix: Update test initial state with refreshInterval * fix: Handle URLs before RefreshPicker * fix: Move RefreshInterval to url position 3 since the segments can take multiple positions * fix: A better way of detecting urls without RefreshInterval in Explore * chore: Some Explore typings * fix: Attach refresh picker to interval picker * chore: Sass fix for refresh button border radius * fix: Remove refreshInterval from URL * fix: Intervals now start when previous interval is finished * fix: Use clearTimeout instead of clearInterval * fix: Make sure there's a delay set before adding a timeout when we have slow explore queries * wip: Add refresh picker to dashboard * feat: Add util for removing keys with empty values * feat: RefreshPicker in dashboards and tmp rem out old RefreshPicker * fix: Remove the jumpy:ness in the refreshpicker * Changed placement and made it hide when your in dashboard settings * chore: Move logic related to refresh picker out of DashNav to its own component * feat: Add tooltip to refreshpicker * fix: Fix bug with refreshpicker not updating when setting to 'off' * fix: Make it possible to override refresh intervals using the dashboard intervals * chore: Change name of Interval to SetInterval to align with ecmascripts naming since its basically the same but declarative and async * fix: Use default intervals when auto refresh is empty in dashboard settings * fix: Hide time/interval picker when hidden is true on the model, such as on the home dashboard * fix: Interval picker will have to handle location changes since timeSrv wont * RefreshPicker: Refactoring refresh picker * RefreshPicker: minor refactoring
2019-04-16 02:15:23 -05:00
ui,
};
const updateDefaults = makeInitialUpdateState();
const update = { ...updateDefaults, ...updateOverides };
const initialState = {
user: {
orgId: '1',
timeZone,
},
explore: {
[exploreId]: {
initialized: true,
urlState,
containerWidth,
eventBridge,
update,
datasourceInstance: { name: 'some-datasource' },
queries: [] as DataQuery[],
range,
ui,
Explore & Dashboard: New Refresh picker (#16505) * Added RefreshButton * Added RefreshSelect * Added RefreshSelectButton * Added RefreshPicker * Removed the magic string Paused * Minor style changes and using Off instead of Pause * Added HeadlessSelect * Added HeadlessSelect story * Added SelectButton * Removed RefreshSelectButton * Added TimePicker and moved ClickOutsideWrapper to ui/components * Added TimePickerPopOver * Added react-calendar * Missed yarn lock file * Added inputs to popover * Added TimePicker and RefreshPicker to DashNav * Moved TimePicker and RefreshPicker to app/core * Added react-calendar to app and removed from ui/components * Fixed PopOver onClick * Moved everything back to ui components because of typings problems * Exporing RefreshPicker and TimePicker * Added Apply and inputs * Added typings * Added TimePickerInput and logic * Fixed parsing of string to Moments * Fixed range string * Styling and connecting the calendars and inputs * Changed Calendar styling * Added backward forward and zoom * Fixed responsive styles * Moved TimePicker and RefreshPicker into app core * Renamed menuIsOpen to isOpen * Changed from className={} to className="" * Moved Popover to TimePickerOptionGroup * Renamed all PopOver to Popover * Renamed popOver to popover and some minor refactorings * Renamed files with git mv * Added ButtonSelect and refactored RefreshPicker * Refactored TimePicker to use new ButtonSelect * Removed HeadlessSelect as suggested * fix: Fix typings and misc errors after rebase * wip: Enable time picker on dashboard and add tooltip * Merge branch 'master' into hugoh/new-timepicker-and-unified-component # Conflicts: # packages/grafana-ui/package.json # packages/grafana-ui/src/components/Input/Input.test.tsx # packages/grafana-ui/src/components/Input/Input.tsx # packages/grafana-ui/src/utils/validate.ts # public/app/features/dashboard/panel_editor/QueryOptions.tsx # yarn.lock * fix: Snapshot update * Move TimePicker default options into the TimePicker as statics, pass the tooltipContent down the line when wanted and wrap the button in a tooltip element * fix: Override internal state prop if we provide one in a prop * Updated snapshots * Let dashnav control refreshPicker state * feat: Add a stringToMs function * wip: RefreshPicker * wip: Move RefreshPicker to @grafana/ui * wip: Move TimePicker to @grafana/ui * wip: Remove comments * wip: Add refreshPicker to explore * wip: Use default intervals if the prop is missing * wip: Nicer way of setting defaults * fix: Control the select component * wip: Add onMoveForward/onMoveBack * Remove code related to the new time picker and refresh picker from dashnav * Fix: Typings after merge * chore: Minor fix after merge * chore: Remove _.map usage * chore: Moved refresh-picker logic out of the refresh picker since it will work a little differently in explore and dashboards until we have replaced the TimeSrv * feat: Add an Interval component to @grafana/ui * chore: Remove intervalId from redux state and move setInterval logic from ExploreToolbar to its own Interval component * feat: Add refreshInterval to Explore's URL state * feat: Pick up refreshInterval from url on page load * fix: Set default refreshInterval when no value can be retained from URL * fix: Update test initial state with refreshInterval * fix: Handle URLs before RefreshPicker * fix: Move RefreshInterval to url position 3 since the segments can take multiple positions * fix: A better way of detecting urls without RefreshInterval in Explore * chore: Some Explore typings * fix: Attach refresh picker to interval picker * chore: Sass fix for refresh button border radius * fix: Remove refreshInterval from URL * fix: Intervals now start when previous interval is finished * fix: Use clearTimeout instead of clearInterval * fix: Make sure there's a delay set before adding a timeout when we have slow explore queries * wip: Add refresh picker to dashboard * feat: Add util for removing keys with empty values * feat: RefreshPicker in dashboards and tmp rem out old RefreshPicker * fix: Remove the jumpy:ness in the refreshpicker * Changed placement and made it hide when your in dashboard settings * chore: Move logic related to refresh picker out of DashNav to its own component * feat: Add tooltip to refreshpicker * fix: Fix bug with refreshpicker not updating when setting to 'off' * fix: Make it possible to override refresh intervals using the dashboard intervals * chore: Change name of Interval to SetInterval to align with ecmascripts naming since its basically the same but declarative and async * fix: Use default intervals when auto refresh is empty in dashboard settings * fix: Hide time/interval picker when hidden is true on the model, such as on the home dashboard * fix: Interval picker will have to handle location changes since timeSrv wont * RefreshPicker: Refactoring refresh picker * RefreshPicker: minor refactoring
2019-04-16 02:15:23 -05:00
refreshInterval: {
label: 'Off',
value: 0,
},
},
},
};
return {
initialState,
exploreId,
range,
ui,
containerWidth,
eventBridge,
};
};
describe('refreshExplore', () => {
describe('when explore is initialized', () => {
describe('and update datasource is set', () => {
it('then it should dispatch initializeExplore', async () => {
const { exploreId, ui, initialState, containerWidth, eventBridge } = setup({ datasource: true });
const dispatchedActions = await thunkTester(initialState)
.givenThunk(refreshExplore)
.whenThunkIsDispatched(exploreId);
const initializeExplore = dispatchedActions[1] as PayloadAction<InitializeExplorePayload>;
const { type, payload } = initializeExplore;
expect(type).toEqual(initializeExploreAction.type);
expect(payload.containerWidth).toEqual(containerWidth);
expect(payload.eventBridge).toEqual(eventBridge);
expect(payload.queries.length).toBe(1); // Queries have generated keys hard to expect on
expect(payload.range.from).toEqual(testRange.from);
expect(payload.range.to).toEqual(testRange.to);
expect(payload.range.raw.from).toEqual(testRange.raw.from);
expect(payload.range.raw.to).toEqual(testRange.raw.to);
expect(payload.ui).toEqual(ui);
});
});
describe('and update ui is set', () => {
it('then it should dispatch updateUIStateAction', async () => {
const { exploreId, initialState, ui } = setup({ ui: true });
const dispatchedActions = await thunkTester(initialState)
.givenThunk(refreshExplore)
.whenThunkIsDispatched(exploreId);
expect(dispatchedActions[0].type).toEqual(updateUIStateAction.type);
expect(dispatchedActions[0].payload).toEqual({ ...ui, exploreId });
});
});
describe('and update queries is set', () => {
it('then it should dispatch setQueriesAction', async () => {
const { exploreId, initialState } = setup({ queries: true });
const dispatchedActions = await thunkTester(initialState)
.givenThunk(refreshExplore)
.whenThunkIsDispatched(exploreId);
expect(dispatchedActions[0].type).toEqual(setQueriesAction.type);
expect(dispatchedActions[0].payload).toEqual({ exploreId, queries: [] });
});
});
});
describe('when update is not initialized', () => {
it('then it should not dispatch any actions', async () => {
const exploreId = ExploreId.left;
const initialState = { explore: { [exploreId]: { initialized: false } } };
const dispatchedActions = await thunkTester(initialState)
.givenThunk(refreshExplore)
.whenThunkIsDispatched(exploreId);
expect(dispatchedActions).toEqual([]);
});
});
});
describe('changing datasource', () => {
it('should switch to logs mode when changing from prometheus to loki', async () => {
const lokiMock = {
testDatasource: () => Promise.resolve({ status: 'success' }),
name: 'Loki',
init: jest.fn(),
meta: { id: 'some id', name: 'Loki' },
};
getDatasourceSrvMock.mockImplementation(
() =>
({
getExternal: jest.fn().mockReturnValue([]),
get: jest.fn().mockReturnValue(lokiMock),
} as any)
);
const exploreId = ExploreId.left;
const name = 'Prometheus';
const mockPromDatasourceInstance = {
testDatasource: () => Promise.resolve({ status: 'success' }),
name,
init: jest.fn(),
meta: { id: 'some id', name },
};
const initialState = {
explore: {
[exploreId]: {
requestedDatasourceName: 'Loki',
datasourceInstance: mockPromDatasourceInstance,
},
},
user: {
orgId: 1,
},
};
jest.spyOn(Actions, 'importQueries').mockImplementationOnce(() => jest.fn);
jest.spyOn(Actions, 'loadDatasource').mockImplementationOnce(() => jest.fn);
jest.spyOn(Actions, 'runQueries').mockImplementationOnce(() => jest.fn);
const dispatchedActions = await thunkTester(initialState)
.givenThunk(changeDatasource)
.whenThunkIsDispatched(exploreId, name);
expect(dispatchedActions).toEqual([
updateDatasourceInstanceAction({
exploreId,
datasourceInstance: lokiMock as any,
version: undefined,
mode: ExploreMode.Logs,
}),
]);
});
});
describe('loading datasource', () => {
describe('when loadDatasource thunk is dispatched', () => {
describe('and all goes fine', () => {
it('then it should dispatch correct actions', async () => {
const exploreId = ExploreId.left;
const name = 'some-datasource';
const initialState = { explore: { [exploreId]: { requestedDatasourceName: name } } };
const mockDatasourceInstance = {
testDatasource: () => {
return Promise.resolve({ status: 'success' });
},
name,
init: jest.fn(),
meta: { id: 'some id' },
};
const dispatchedActions = await thunkTester(initialState)
.givenThunk(loadDatasource)
.whenThunkIsDispatched(exploreId, mockDatasourceInstance);
expect(dispatchedActions).toEqual([
loadDatasourcePendingAction({
exploreId,
requestedDatasourceName: mockDatasourceInstance.name,
}),
loadDatasourceReadyAction({ exploreId, history: [] }),
]);
});
});
describe('and user changes datasource during load', () => {
it('then it should dispatch correct actions', async () => {
const exploreId = ExploreId.left;
const name = 'some-datasource';
const initialState = { explore: { [exploreId]: { requestedDatasourceName: 'some-other-datasource' } } };
const mockDatasourceInstance = {
testDatasource: () => {
return Promise.resolve({ status: 'success' });
},
name,
init: jest.fn(),
meta: { id: 'some id' },
};
const dispatchedActions = await thunkTester(initialState)
.givenThunk(loadDatasource)
.whenThunkIsDispatched(exploreId, mockDatasourceInstance);
expect(dispatchedActions).toEqual([
loadDatasourcePendingAction({
exploreId,
requestedDatasourceName: mockDatasourceInstance.name,
}),
]);
});
});
});
});
const getNavigateToExploreContext = async (openInNewWindow: (url: string) => void = undefined) => {
const url = 'http://www.someurl.com';
const panel: Partial<PanelModel> = {
datasource: 'mocked datasource',
targets: [{ refId: 'A' }],
};
const datasource = new MockDataSourceApi(panel.datasource);
const get = jest.fn().mockResolvedValue(datasource);
const getDataSourceSrv = jest.fn().mockReturnValue({ get });
const getTimeSrv = jest.fn();
const getExploreUrl = jest.fn().mockResolvedValue(url);
const dispatchedActions = await thunkTester({})
.givenThunk(navigateToExplore)
.whenThunkIsDispatched(panel, { getDataSourceSrv, getTimeSrv, getExploreUrl, openInNewWindow });
return {
url,
panel,
datasource,
get,
getDataSourceSrv,
getTimeSrv,
getExploreUrl,
dispatchedActions,
};
};
describe('navigateToExplore', () => {
describe('when navigateToExplore thunk is dispatched', () => {
describe('and openInNewWindow is undefined', () => {
const openInNewWindow: (url: string) => void = undefined;
it('then it should dispatch correct actions', async () => {
const { dispatchedActions, url } = await getNavigateToExploreContext(openInNewWindow);
expect(dispatchedActions).toEqual([updateLocation({ path: url, query: {} })]);
});
it('then getDataSourceSrv should have been once', async () => {
const { getDataSourceSrv } = await getNavigateToExploreContext(openInNewWindow);
expect(getDataSourceSrv).toHaveBeenCalledTimes(1);
});
it('then getDataSourceSrv.get should have been called with correct arguments', async () => {
const { get, panel } = await getNavigateToExploreContext(openInNewWindow);
expect(get).toHaveBeenCalledTimes(1);
expect(get).toHaveBeenCalledWith(panel.datasource);
});
it('then getTimeSrv should have been called once', async () => {
const { getTimeSrv } = await getNavigateToExploreContext(openInNewWindow);
expect(getTimeSrv).toHaveBeenCalledTimes(1);
});
it('then getExploreUrl should have been called with correct arguments', async () => {
const { getExploreUrl, panel, datasource, getDataSourceSrv, getTimeSrv } = await getNavigateToExploreContext(
openInNewWindow
);
expect(getExploreUrl).toHaveBeenCalledTimes(1);
expect(getExploreUrl).toHaveBeenCalledWith({
panel,
panelTargets: panel.targets,
panelDatasource: datasource,
datasourceSrv: getDataSourceSrv(),
timeSrv: getTimeSrv(),
});
});
});
describe('and openInNewWindow is defined', () => {
const openInNewWindow: (url: string) => void = jest.fn();
it('then it should dispatch no actions', async () => {
const { dispatchedActions } = await getNavigateToExploreContext(openInNewWindow);
expect(dispatchedActions).toEqual([]);
});
it('then getDataSourceSrv should have been once', async () => {
const { getDataSourceSrv } = await getNavigateToExploreContext(openInNewWindow);
expect(getDataSourceSrv).toHaveBeenCalledTimes(1);
});
it('then getDataSourceSrv.get should have been called with correct arguments', async () => {
const { get, panel } = await getNavigateToExploreContext(openInNewWindow);
expect(get).toHaveBeenCalledTimes(1);
expect(get).toHaveBeenCalledWith(panel.datasource);
});
it('then getTimeSrv should have been called once', async () => {
const { getTimeSrv } = await getNavigateToExploreContext(openInNewWindow);
expect(getTimeSrv).toHaveBeenCalledTimes(1);
});
it('then getExploreUrl should have been called with correct arguments', async () => {
const { getExploreUrl, panel, datasource, getDataSourceSrv, getTimeSrv } = await getNavigateToExploreContext(
openInNewWindow
);
expect(getExploreUrl).toHaveBeenCalledTimes(1);
expect(getExploreUrl).toHaveBeenCalledWith({
panel,
panelTargets: panel.targets,
panelDatasource: datasource,
datasourceSrv: getDataSourceSrv(),
timeSrv: getTimeSrv(),
});
});
it('then openInNewWindow should have been called with correct arguments', async () => {
const openInNewWindowFunc = jest.fn();
const { url } = await getNavigateToExploreContext(openInNewWindowFunc);
expect(openInNewWindowFunc).toHaveBeenCalledTimes(1);
expect(openInNewWindowFunc).toHaveBeenCalledWith(url);
});
});
});
});