1import { DataQuery, DefaultTimeZone, EventBusExtended, serializeStateToUrlParam, toUtc } from '@grafana/data';
2import { ExploreId, StoreState, ThunkDispatch } from 'app/types';
3import { refreshExplore } from './explorePane';
4import { setDataSourceSrv } from '@grafana/runtime';
5import { configureStore } from '../../../store/configureStore';
6import { of } from 'rxjs';
7
8jest.mock('../../dashboard/services/TimeSrv', () => ({
9  getTimeSrv: jest.fn().mockReturnValue({
10    init: jest.fn(),
11  }),
12}));
13
14const t = toUtc();
15const testRange = {
16  from: t,
17  to: t,
18  raw: {
19    from: t,
20    to: t,
21  },
22};
23
24const defaultInitialState = {
25  user: {
26    orgId: '1',
27    timeZone: DefaultTimeZone,
28  },
29  explore: {
30    [ExploreId.left]: {
31      initialized: true,
32      containerWidth: 1920,
33      eventBridge: {} as EventBusExtended,
34      queries: [] as DataQuery[],
35      range: testRange,
36      refreshInterval: {
37        label: 'Off',
38        value: 0,
39      },
40      cache: [],
41    },
42  },
43};
44
45function setupStore(state?: any) {
46  return configureStore({
47    ...defaultInitialState,
48    explore: {
49      [ExploreId.left]: {
50        ...defaultInitialState.explore[ExploreId.left],
51        ...(state || {}),
52      },
53    },
54  } as any);
55}
56
57function setup(state?: any) {
58  const datasources: Record<string, any> = {
59    newDs: {
60      testDatasource: jest.fn(),
61      init: jest.fn(),
62      query: jest.fn(),
63      name: 'newDs',
64      meta: { id: 'newDs' },
65      getRef: () => ({ uid: 'newDs' }),
66    },
67    someDs: {
68      testDatasource: jest.fn(),
69      init: jest.fn(),
70      query: jest.fn(),
71      name: 'someDs',
72      meta: { id: 'someDs' },
73      getRef: () => ({ uid: 'someDs' }),
74    },
75  };
76
77  setDataSourceSrv({
78    getList() {
79      return Object.values(datasources).map((d) => ({ name: d.name }));
80    },
81    getInstanceSettings(name: string) {
82      return { name, getRef: () => ({ uid: name }) };
83    },
84    get(name?: string) {
85      return Promise.resolve(
86        name
87          ? datasources[name]
88          : {
89              testDatasource: jest.fn(),
90              init: jest.fn(),
91              name: 'default',
92            }
93      );
94    },
95  } as any);
96
97  const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = setupStore({
98    datasourceInstance: datasources.someDs,
99    ...(state || {}),
100  });
101
102  return {
103    dispatch,
104    getState,
105    datasources,
106  };
107}
108
109describe('refreshExplore', () => {
110  it('should change data source when datasource in url changes', async () => {
111    const { dispatch, getState } = setup();
112    await dispatch(
113      refreshExplore(ExploreId.left, serializeStateToUrlParam({ datasource: 'newDs', queries: [], range: testRange }))
114    );
115    expect(getState().explore[ExploreId.left].datasourceInstance?.name).toBe('newDs');
116  });
117
118  it('should change and run new queries from the URL', async () => {
119    const { dispatch, getState, datasources } = setup();
120    datasources.someDs.query.mockReturnValueOnce(of({}));
121    await dispatch(
122      refreshExplore(
123        ExploreId.left,
124        serializeStateToUrlParam({ datasource: 'someDs', queries: [{ expr: 'count()', refId: 'A' }], range: testRange })
125      )
126    );
127    // same
128    const state = getState().explore[ExploreId.left];
129    expect(state.datasourceInstance?.name).toBe('someDs');
130    expect(state.queries.length).toBe(1);
131    expect(state.queries).toMatchObject([{ expr: 'count()' }]);
132    expect(datasources.someDs.query).toHaveBeenCalledTimes(1);
133  });
134
135  it('should not do anything if pane is not initialized', async () => {
136    const { dispatch, getState } = setup({
137      initialized: false,
138    });
139    const state = getState();
140    await dispatch(
141      refreshExplore(
142        ExploreId.left,
143        serializeStateToUrlParam({ datasource: 'newDs', queries: [{ expr: 'count()', refId: 'A' }], range: testRange })
144      )
145    );
146
147    expect(state).toEqual(getState());
148  });
149});
150