kibana/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts
2020-11-04 11:27:52 +01:00

476 lines
14 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { getSuggestions } from './suggestion_helpers';
import { createMockVisualization, createMockDatasource, DatasourceMock } from '../mocks';
import { TableSuggestion, DatasourceSuggestion } from '../../types';
import { PaletteOutput } from 'src/plugins/charts/public';
const generateSuggestion = (state = {}, layerId: string = 'first'): DatasourceSuggestion => ({
state,
table: {
columns: [],
isMultiRow: false,
layerId,
changeType: 'unchanged',
},
keptLayerIds: [layerId],
});
let datasourceMap: Record<string, DatasourceMock>;
let datasourceStates: Record<
string,
{
isLoading: boolean;
state: unknown;
}
>;
beforeEach(() => {
datasourceMap = {
mock: createMockDatasource('a'),
};
datasourceStates = {
mock: {
isLoading: false,
state: {},
},
};
});
describe('suggestion helpers', () => {
it('should return suggestions array', () => {
const mockVisualization = createMockVisualization();
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(),
]);
const suggestedState = {};
const suggestions = getSuggestions({
visualizationMap: {
vis1: {
...mockVisualization,
getSuggestions: () => [
{
score: 0.5,
title: 'Test',
state: suggestedState,
previewIcon: 'empty',
},
],
},
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(suggestions).toHaveLength(1);
expect(suggestions[0].visualizationState).toBe(suggestedState);
});
it('should concatenate suggestions from all visualizations', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(),
]);
const suggestions = getSuggestions({
visualizationMap: {
vis1: {
...mockVisualization1,
getSuggestions: () => [
{
score: 0.5,
title: 'Test',
state: {},
previewIcon: 'empty',
},
{
score: 0.5,
title: 'Test2',
state: {},
previewIcon: 'empty',
},
],
},
vis2: {
...mockVisualization2,
getSuggestions: () => [
{
score: 0.5,
title: 'Test3',
state: {},
previewIcon: 'empty',
},
],
},
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(suggestions).toHaveLength(3);
});
it('should call getDatasourceSuggestionsForField when a field is passed', () => {
datasourceMap.mock.getDatasourceSuggestionsForField.mockReturnValue([generateSuggestion()]);
const droppedField = {};
getSuggestions({
visualizationMap: {
vis1: createMockVisualization(),
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
field: droppedField,
});
expect(datasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith(
datasourceStates.mock.state,
droppedField
);
});
it('should call getDatasourceSuggestionsForField from all datasources with a state', () => {
const multiDatasourceStates = {
mock: {
isLoading: false,
state: {},
},
mock2: {
isLoading: false,
state: {},
},
};
const multiDatasourceMap = {
mock: createMockDatasource('a'),
mock2: createMockDatasource('a'),
mock3: createMockDatasource('a'),
};
const droppedField = {};
getSuggestions({
visualizationMap: {
vis1: createMockVisualization(),
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap: multiDatasourceMap,
datasourceStates: multiDatasourceStates,
field: droppedField,
});
expect(multiDatasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith(
multiDatasourceStates.mock.state,
droppedField
);
expect(multiDatasourceMap.mock2.getDatasourceSuggestionsForField).toHaveBeenCalledWith(
multiDatasourceStates.mock2.state,
droppedField
);
expect(multiDatasourceMap.mock3.getDatasourceSuggestionsForField).not.toHaveBeenCalled();
});
it('should call getDatasourceSuggestionsForVisualizeField when a visualizeTriggerField is passed', () => {
datasourceMap.mock.getDatasourceSuggestionsForVisualizeField.mockReturnValue([
generateSuggestion(),
]);
getSuggestions({
visualizationMap: {
vis1: createMockVisualization(),
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
visualizeTriggerFieldContext: {
indexPatternId: '1',
fieldName: 'test',
},
});
expect(datasourceMap.mock.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith(
datasourceStates.mock.state,
'1',
'test'
);
});
it('should call getDatasourceSuggestionsForVisualizeField from all datasources with a state', () => {
const multiDatasourceStates = {
mock: {
isLoading: false,
state: {},
},
mock2: {
isLoading: false,
state: {},
},
};
const multiDatasourceMap = {
mock: createMockDatasource('a'),
mock2: createMockDatasource('a'),
mock3: createMockDatasource('a'),
};
const visualizeTriggerField = {
indexPatternId: '1',
fieldName: 'test',
};
getSuggestions({
visualizationMap: {
vis1: createMockVisualization(),
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap: multiDatasourceMap,
datasourceStates: multiDatasourceStates,
visualizeTriggerFieldContext: visualizeTriggerField,
});
expect(multiDatasourceMap.mock.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith(
multiDatasourceStates.mock.state,
'1',
'test'
);
expect(multiDatasourceMap.mock2.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith(
multiDatasourceStates.mock2.state,
'1',
'test'
);
expect(
multiDatasourceMap.mock3.getDatasourceSuggestionsForVisualizeField
).not.toHaveBeenCalled();
});
it('should rank the visualizations by score', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(),
]);
const suggestions = getSuggestions({
visualizationMap: {
vis1: {
...mockVisualization1,
getSuggestions: () => [
{
score: 0.2,
title: 'Test',
state: {},
previewIcon: 'empty',
},
{
score: 0.8,
title: 'Test2',
state: {},
previewIcon: 'empty',
},
],
},
vis2: {
...mockVisualization2,
getSuggestions: () => [
{
score: 0.6,
title: 'Test3',
state: {},
previewIcon: 'empty',
},
],
},
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(suggestions[0].score).toBe(0.8);
expect(suggestions[1].score).toBe(0.6);
expect(suggestions[2].score).toBe(0.2);
});
it('should call all suggestion getters with all available data tables', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
const table1: TableSuggestion = {
columns: [],
isMultiRow: true,
layerId: 'first',
changeType: 'unchanged',
};
const table2: TableSuggestion = {
columns: [],
isMultiRow: true,
layerId: 'first',
changeType: 'unchanged',
};
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
{ state: {}, table: table1, keptLayerIds: ['first'] },
{ state: {}, table: table2, keptLayerIds: ['first'] },
]);
getSuggestions({
visualizationMap: {
vis1: mockVisualization1,
vis2: mockVisualization2,
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(mockVisualization1.getSuggestions.mock.calls[0][0].table).toEqual(table1);
expect(mockVisualization1.getSuggestions.mock.calls[1][0].table).toEqual(table2);
expect(mockVisualization2.getSuggestions.mock.calls[0][0].table).toEqual(table1);
expect(mockVisualization2.getSuggestions.mock.calls[1][0].table).toEqual(table2);
});
it('should map the suggestion ids back to the correct datasource ids and states', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
const tableState1 = {};
const tableState2 = {};
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(tableState1),
generateSuggestion(tableState2),
]);
const vis1Suggestions = jest.fn();
vis1Suggestions.mockReturnValueOnce([
{
score: 0.3,
title: 'Test',
state: {},
previewIcon: 'empty',
},
]);
vis1Suggestions.mockReturnValueOnce([
{
score: 0.2,
title: 'Test2',
state: {},
previewIcon: 'empty',
},
]);
const vis2Suggestions = jest.fn();
vis2Suggestions.mockReturnValueOnce([]);
vis2Suggestions.mockReturnValueOnce([
{
score: 0.1,
title: 'Test3',
state: {},
previewIcon: 'empty',
},
]);
const suggestions = getSuggestions({
visualizationMap: {
vis1: {
...mockVisualization1,
getSuggestions: vis1Suggestions,
},
vis2: {
...mockVisualization2,
getSuggestions: vis2Suggestions,
},
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(suggestions[0].datasourceState).toBe(tableState1);
expect(suggestions[0].datasourceId).toBe('mock');
expect(suggestions[1].datasourceState).toBe(tableState2);
expect(suggestions[1].datasourceId).toBe('mock');
expect(suggestions[2].datasourceState).toBe(tableState2);
expect(suggestions[2].datasourceId).toBe('mock');
});
it('should pass the state of the currently active visualization to getSuggestions', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
const currentState = {};
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(0),
generateSuggestion(1),
]);
getSuggestions({
visualizationMap: {
vis1: mockVisualization1,
vis2: mockVisualization2,
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(mockVisualization1.getSuggestions).toHaveBeenCalledWith(
expect.objectContaining({
state: currentState,
})
);
expect(mockVisualization2.getSuggestions).not.toHaveBeenCalledWith(
expect.objectContaining({
state: currentState,
})
);
});
it('should pass passed in main palette if specified', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
const mainPalette: PaletteOutput = { type: 'palette', name: 'mock' };
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(0),
generateSuggestion(1),
]);
getSuggestions({
visualizationMap: {
vis1: mockVisualization1,
vis2: mockVisualization2,
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
mainPalette,
});
expect(mockVisualization1.getSuggestions).toHaveBeenCalledWith(
expect.objectContaining({
mainPalette,
})
);
expect(mockVisualization2.getSuggestions).toHaveBeenCalledWith(
expect.objectContaining({
mainPalette,
})
);
});
it('should query active visualization for main palette if not specified', () => {
const mockVisualization1 = createMockVisualization();
const mockVisualization2 = createMockVisualization();
const mainPalette: PaletteOutput = { type: 'palette', name: 'mock' };
mockVisualization1.getMainPalette = jest.fn(() => mainPalette);
datasourceMap.mock.getDatasourceSuggestionsFromCurrentState.mockReturnValue([
generateSuggestion(0),
generateSuggestion(1),
]);
getSuggestions({
visualizationMap: {
vis1: mockVisualization1,
vis2: mockVisualization2,
},
activeVisualizationId: 'vis1',
visualizationState: {},
datasourceMap,
datasourceStates,
});
expect(mockVisualization1.getMainPalette).toHaveBeenCalledWith({});
expect(mockVisualization2.getSuggestions).toHaveBeenCalledWith(
expect.objectContaining({
mainPalette,
})
);
});
});