Skip to content

Commit 599382b

Browse files
committed
test: 💍 add in-chart "Explore underlying data" unit tests
1 parent 406e02d commit 599382b

File tree

2 files changed

+275
-5
lines changed

2 files changed

+275
-5
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { ExploreDataChartAction } from './explore_data_chart_action';
8+
import { Params, PluginDeps } from './abstract_explore_data_action';
9+
import { coreMock } from '../../../../../../src/core/public/mocks';
10+
import { UrlGeneratorContract } from '../../../../../../src/plugins/share/public';
11+
import {
12+
EmbeddableStart,
13+
RangeSelectTriggerContext,
14+
ValueClickTriggerContext,
15+
ChartActionContext,
16+
} from '../../../../../../src/plugins/embeddable/public';
17+
import { i18n } from '@kbn/i18n';
18+
import {
19+
VisualizeEmbeddableContract,
20+
VISUALIZE_EMBEDDABLE_TYPE,
21+
} from '../../../../../../src/plugins/visualizations/public';
22+
import { ViewMode } from '../../../../../../src/plugins/embeddable/public';
23+
import { Filter, TimeRange } from '../../../../../../src/plugins/data/public';
24+
25+
const i18nTranslateSpy = (i18n.translate as unknown) as jest.SpyInstance;
26+
27+
jest.mock('@kbn/i18n', () => ({
28+
i18n: {
29+
translate: jest.fn((key, options) => options.defaultMessage),
30+
},
31+
}));
32+
33+
afterEach(() => {
34+
i18nTranslateSpy.mockClear();
35+
});
36+
37+
const setup = ({ useRangeEvent = false }: { useRangeEvent?: boolean } = {}) => {
38+
type UrlGenerator = UrlGeneratorContract<'DISCOVER_APP_URL_GENERATOR'>;
39+
40+
const core = coreMock.createStart();
41+
42+
const urlGenerator: UrlGenerator = ({
43+
createUrl: jest.fn(() => Promise.resolve('/xyz/app/discover/foo#bar')),
44+
} as unknown) as UrlGenerator;
45+
46+
const filtersAndTimeRangeFromContext = jest.fn((async () => ({
47+
filters: [],
48+
})) as EmbeddableStart['filtersAndTimeRangeFromContext']);
49+
50+
const plugins: PluginDeps = {
51+
discover: {
52+
urlGenerator,
53+
},
54+
embeddable: {
55+
filtersAndTimeRangeFromContext,
56+
},
57+
};
58+
59+
const params: Params = {
60+
start: () => ({
61+
plugins,
62+
self: {},
63+
core,
64+
}),
65+
};
66+
const action = new ExploreDataChartAction(params);
67+
68+
const input = {
69+
viewMode: ViewMode.VIEW,
70+
};
71+
72+
const output = {
73+
indexPatterns: [
74+
{
75+
id: 'index-ptr-foo',
76+
},
77+
],
78+
};
79+
80+
const embeddable: VisualizeEmbeddableContract = ({
81+
type: VISUALIZE_EMBEDDABLE_TYPE,
82+
getInput: () => input,
83+
getOutput: () => output,
84+
} as unknown) as VisualizeEmbeddableContract;
85+
86+
const data: ChartActionContext<typeof embeddable>['data'] = {
87+
...(useRangeEvent
88+
? ({ range: {} } as RangeSelectTriggerContext['data'])
89+
: ({ data: [] } as ValueClickTriggerContext['data'])),
90+
timeFieldName: 'order_date',
91+
};
92+
93+
const context = {
94+
embeddable,
95+
data,
96+
} as ChartActionContext<typeof embeddable>;
97+
98+
return { core, plugins, urlGenerator, params, action, input, output, embeddable, data, context };
99+
};
100+
101+
describe('"Explore underlying data" panel action', () => {
102+
test('action has Discover icon', () => {
103+
const { action, context } = setup();
104+
expect(action.getIconType(context)).toBe('discoverApp');
105+
});
106+
107+
test('title is "Explore underlying data"', () => {
108+
const { action, context } = setup();
109+
expect(action.getDisplayName(context)).toBe('Explore underlying data');
110+
});
111+
112+
test('translates title', () => {
113+
expect(i18nTranslateSpy).toHaveBeenCalledTimes(0);
114+
115+
const { action, context } = setup();
116+
action.getDisplayName(context);
117+
118+
expect(i18nTranslateSpy).toHaveBeenCalledTimes(1);
119+
expect(i18nTranslateSpy.mock.calls[0][0]).toBe(
120+
'xpack.discover.FlyoutCreateDrilldownAction.displayName'
121+
);
122+
});
123+
124+
describe('isCompatible()', () => {
125+
test('returns true when all conditions are met', async () => {
126+
const { action, context } = setup();
127+
128+
const isCompatible = await action.isCompatible(context);
129+
130+
expect(isCompatible).toBe(true);
131+
});
132+
133+
test('returns false when URL generator is not present', async () => {
134+
const { action, plugins, context } = setup();
135+
(plugins.discover as any).urlGenerator = undefined;
136+
137+
const isCompatible = await action.isCompatible(context);
138+
139+
expect(isCompatible).toBe(false);
140+
});
141+
142+
test('returns false if embeddable is not Visualize embeddable', async () => {
143+
const { action, embeddable, context } = setup();
144+
(embeddable as any).type = 'NOT_VISUALIZE_EMBEDDABLE';
145+
146+
const isCompatible = await action.isCompatible(context);
147+
148+
expect(isCompatible).toBe(false);
149+
});
150+
151+
test('returns false if embeddable does not have index patterns', async () => {
152+
const { action, output, context } = setup();
153+
delete output.indexPatterns;
154+
155+
const isCompatible = await action.isCompatible(context);
156+
157+
expect(isCompatible).toBe(false);
158+
});
159+
160+
test('returns false if embeddable index patterns are empty', async () => {
161+
const { action, output, context } = setup();
162+
output.indexPatterns = [];
163+
164+
const isCompatible = await action.isCompatible(context);
165+
166+
expect(isCompatible).toBe(false);
167+
});
168+
169+
test('returns false if dashboard is in edit mode', async () => {
170+
const { action, input, context } = setup();
171+
input.viewMode = ViewMode.EDIT;
172+
173+
const isCompatible = await action.isCompatible(context);
174+
175+
expect(isCompatible).toBe(false);
176+
});
177+
});
178+
179+
describe('getHref()', () => {
180+
test('returns URL path generated by URL generator', async () => {
181+
const { action, context } = setup();
182+
183+
const href = await action.getHref(context);
184+
185+
expect(href).toBe('/xyz/app/discover/foo#bar');
186+
});
187+
188+
test('calls URL generator with right arguments', async () => {
189+
const { action, urlGenerator, context } = setup();
190+
191+
expect(urlGenerator.createUrl).toHaveBeenCalledTimes(0);
192+
193+
await action.getHref(context);
194+
195+
expect(urlGenerator.createUrl).toHaveBeenCalledTimes(1);
196+
expect(urlGenerator.createUrl).toHaveBeenCalledWith({
197+
filters: [],
198+
indexPatternId: 'index-ptr-foo',
199+
timeRange: undefined,
200+
});
201+
});
202+
203+
test('applies chart event filters', async () => {
204+
const { action, context, urlGenerator, plugins } = setup();
205+
206+
((plugins.embeddable
207+
.filtersAndTimeRangeFromContext as unknown) as jest.SpyInstance).mockImplementation(() => {
208+
const filters: Filter[] = [
209+
{
210+
meta: {
211+
alias: 'alias',
212+
disabled: false,
213+
negate: false,
214+
},
215+
},
216+
];
217+
const timeRange: TimeRange = {
218+
from: 'from',
219+
to: 'to',
220+
};
221+
return { filters, timeRange };
222+
});
223+
224+
expect(plugins.embeddable.filtersAndTimeRangeFromContext).toHaveBeenCalledTimes(0);
225+
226+
await action.getHref(context);
227+
228+
expect(plugins.embeddable.filtersAndTimeRangeFromContext).toHaveBeenCalledTimes(1);
229+
expect(plugins.embeddable.filtersAndTimeRangeFromContext).toHaveBeenCalledWith(context);
230+
expect(urlGenerator.createUrl).toHaveBeenCalledWith({
231+
filters: [
232+
{
233+
meta: {
234+
alias: 'alias',
235+
disabled: false,
236+
negate: false,
237+
},
238+
},
239+
],
240+
indexPatternId: 'index-ptr-foo',
241+
timeRange: {
242+
from: 'from',
243+
to: 'to',
244+
},
245+
});
246+
});
247+
});
248+
249+
describe('execute()', () => {
250+
test('calls platform SPA navigation method', async () => {
251+
const { action, context, core } = setup();
252+
253+
expect(core.application.navigateToApp).toHaveBeenCalledTimes(0);
254+
255+
await action.execute(context);
256+
257+
expect(core.application.navigateToApp).toHaveBeenCalledTimes(1);
258+
});
259+
260+
test('calls platform SPA navigation method with right arguments', async () => {
261+
const { action, context, core } = setup();
262+
263+
await action.execute(context);
264+
265+
expect(core.application.navigateToApp).toHaveBeenCalledTimes(1);
266+
expect(core.application.navigateToApp.mock.calls[0]).toEqual([
267+
'discover',
268+
{
269+
path: '/foo#bar',
270+
},
271+
]);
272+
});
273+
});
274+
});

x-pack/plugins/discover_enhanced/public/actions/explore_data/explore_data_context_menu_action.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import {
8-
ExploreDataContextMenuAction,
9-
ACTION_EXPLORE_DATA,
10-
} from './explore_data_context_menu_action';
7+
import { ExploreDataContextMenuAction } from './explore_data_context_menu_action';
118
import { Params, PluginDeps } from './abstract_explore_data_action';
129
import { coreMock } from '../../../../../../src/core/public/mocks';
1310
import { UrlGeneratorContract } from '../../../../../../src/plugins/share/public';
@@ -37,7 +34,6 @@ const setup = () => {
3734
const core = coreMock.createStart();
3835

3936
const urlGenerator: UrlGenerator = ({
40-
id: ACTION_EXPLORE_DATA,
4137
createUrl: jest.fn(() => Promise.resolve('/xyz/app/discover/foo#bar')),
4238
} as unknown) as UrlGenerator;
4339

0 commit comments

Comments
 (0)