From 4d632de6c42b69ba67a1939357414c9cc3383a6b Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 6 Aug 2019 09:48:02 +0200 Subject: [PATCH] add tests for manual switch and remove dependency to automatic switch --- .../__mocks__/state_helpers.ts | 3 + .../indexpattern_plugin/datapanel.test.tsx | 384 +++++------------- .../indexpattern_plugin/layerpanel.test.tsx | 223 +++------- .../public/indexpattern_plugin/layerpanel.tsx | 2 +- 4 files changed, 166 insertions(+), 446 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__mocks__/state_helpers.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__mocks__/state_helpers.ts index 1df52a3fd80ead..48de1b3d8b4f90 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__mocks__/state_helpers.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/__mocks__/state_helpers.ts @@ -7,6 +7,7 @@ const actual = jest.requireActual('../state_helpers'); jest.spyOn(actual, 'changeColumn'); +jest.spyOn(actual, 'updateLayerIndexPattern'); export const { getColumnOrder, @@ -15,4 +16,6 @@ export const { updateColumnParam, sortByField, hasField, + updateLayerIndexPattern, + isLayerTransferable, } = actual; diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx index 950916bb789470..948d258c67fce7 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx @@ -193,313 +193,139 @@ const initialState: IndexPatternPrivateState = { }, }; describe('IndexPattern Data Panel', () => { - describe('index pattern switch', () => { - let defaultProps: DatasourceDataPanelProps; - - beforeEach(() => { - defaultProps = { - dragDropContext: createMockedDragDropContext(), - state: initialState, - setState: jest.fn(), - }; - }); - - function changeIndexPattern( - component: ShallowWrapper[0]>, - newIndexPattern: string - ) { - component.prop('setShowIndexPatternSwitcher')(true); - component.prop('onChangeIndexPattern')!(newIndexPattern); - } - - it('should not update the index pattern of the layer if there are incompatible fields', () => { - const instance = shallow(); - changeIndexPattern(instance, '3'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...initialState, - currentIndexPatternId: '3', - }); - }); - - it('should not update the index pattern of the layer if there are layers with from different index patterns', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - ...initialState.layers, - first: { - indexPatternId: '2', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'avg', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '3'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...state, - currentIndexPatternId: '3', - }); - }); - - it('should not update the index pattern of the layer if there are incompatible restrictions on the target index pattern', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - second: { - ...initialState.layers.second, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '2'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...state, - currentIndexPatternId: '2', - }); - }); - - it('should change the index pattern if there are less restrictions on the target index patterns', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - second: { - indexPatternId: '2', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'min', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '1'); - const newState = (defaultProps.setState as jest.Mock).mock - .calls[0][0] as IndexPatternPrivateState; - expect(newState.currentIndexPatternId).toEqual('1'); - expect(newState.layers.second.indexPatternId).toEqual('1'); - }); - - it('should change the index pattern if all layers are compatible', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - ...initialState.layers, - first: { - indexPatternId: '1', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'avg', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '3'); - const newState = (defaultProps.setState as jest.Mock).mock - .calls[0][0] as IndexPatternPrivateState; - expect(newState.currentIndexPatternId).toEqual('3'); - expect(newState.layers.first.indexPatternId).toEqual('3'); - expect(newState.layers.second.indexPatternId).toEqual('3'); - }); + let defaultProps: Parameters[0]; + + beforeEach(() => { + defaultProps = { + dragDropContext: createMockedDragDropContext(), + currentIndexPatternId: '1', + indexPatterns: initialState.indexPatterns, + showIndexPatternSwitcher: false, + setShowIndexPatternSwitcher: jest.fn(), + onChangeIndexPattern: jest.fn(), + }; }); - describe('field list', () => { - let defaultProps: Parameters[0]; + it('should render a warning if there are no index patterns', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="indexPattern-no-indexpatterns"]')).toHaveLength(1); + }); - beforeEach(() => { - defaultProps = { - dragDropContext: createMockedDragDropContext(), - currentIndexPatternId: '1', - indexPatterns: initialState.indexPatterns, - showIndexPatternSwitcher: false, - setShowIndexPatternSwitcher: jest.fn(), - onChangeIndexPattern: jest.fn(), - }; - }); + it('should call setState when the index pattern is switched', async () => { + const wrapper = shallow(); - it('should render a warning if there are no index patterns', () => { - const wrapper = shallow( - - ); - expect(wrapper.find('[data-test-subj="indexPattern-no-indexpatterns"]')).toHaveLength(1); - }); + wrapper.find('[data-test-subj="indexPattern-switch-link"]').simulate('click'); - it('should call setState when the index pattern is switched', async () => { - const wrapper = shallow(); + expect(defaultProps.setShowIndexPatternSwitcher).toHaveBeenCalledWith(true); - wrapper.find('[data-test-subj="indexPattern-switch-link"]').simulate('click'); + wrapper.setProps({ showIndexPatternSwitcher: true }); - expect(defaultProps.setShowIndexPatternSwitcher).toHaveBeenCalledWith(true); + const comboBox = wrapper.find(EuiComboBox); - wrapper.setProps({ showIndexPatternSwitcher: true }); + comboBox.prop('onChange')!([ + { + label: initialState.indexPatterns['2'].title, + value: '2', + }, + ]); - const comboBox = wrapper.find(EuiComboBox); + expect(defaultProps.onChangeIndexPattern).toHaveBeenCalledWith('2'); + }); - comboBox.prop('onChange')!([ - { - label: initialState.indexPatterns['2'].title, - value: '2', - }, - ]); + it('should list all supported fields in the pattern sorted alphabetically', async () => { + const wrapper = shallow(); - expect(defaultProps.onChangeIndexPattern).toHaveBeenCalledWith('2'); - }); + expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ + 'bytes', + 'memory', + 'source', + 'timestamp', + ]); + }); - it('should list all supported fields in the pattern sorted alphabetically', async () => { - const wrapper = shallow(); + it('should filter down by name', async () => { + const wrapper = shallow(); - expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ - 'bytes', - 'memory', - 'source', - 'timestamp', - ]); + act(() => { + wrapper.find(EuiFieldSearch).prop('onChange')!({ target: { value: 'mem' } } as ChangeEvent< + HTMLInputElement + >); }); - it('should filter down by name', async () => { - const wrapper = shallow(); + expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ + 'memory', + ]); + }); - act(() => { - wrapper.find(EuiFieldSearch).prop('onChange')!({ target: { value: 'mem' } } as ChangeEvent< - HTMLInputElement - >); - }); + it('should filter down by type', async () => { + const wrapper = shallow(); - expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ - 'memory', - ]); + act(() => { + (wrapper + .find(EuiContextMenuPanel) + .prop('items')! + .find( + item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' + )! as ReactElement).props.onClick(); }); - it('should filter down by type', async () => { - const wrapper = shallow(); + expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ + 'bytes', + 'memory', + ]); + }); - act(() => { - (wrapper - .find(EuiContextMenuPanel) - .prop('items')! - .find( - item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' - )! as ReactElement).props.onClick(); - }); + it('should toggle type if clicked again', async () => { + const wrapper = shallow(); - expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ - 'bytes', - 'memory', - ]); + act(() => { + (wrapper + .find(EuiContextMenuPanel) + .prop('items')! + .find( + item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' + )! as ReactElement).props.onClick(); }); - it('should toggle type if clicked again', async () => { - const wrapper = shallow(); - - act(() => { - (wrapper - .find(EuiContextMenuPanel) - .prop('items')! - .find( - item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' - )! as ReactElement).props.onClick(); - }); - - act(() => { - (wrapper - .find(EuiContextMenuPanel) - .prop('items')! - .find( - item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' - )! as ReactElement).props.onClick(); - }); - - expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ - 'bytes', - 'memory', - 'source', - 'timestamp', - ]); + act(() => { + (wrapper + .find(EuiContextMenuPanel) + .prop('items')! + .find( + item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' + )! as ReactElement).props.onClick(); }); - it('should filter down by type and by name', async () => { - const wrapper = shallow(); + expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ + 'bytes', + 'memory', + 'source', + 'timestamp', + ]); + }); - act(() => { - wrapper.find(EuiFieldSearch).prop('onChange')!({ target: { value: 'mem' } } as ChangeEvent< - HTMLInputElement - >); - }); + it('should filter down by type and by name', async () => { + const wrapper = shallow(); - act(() => { - (wrapper - .find(EuiContextMenuPanel) - .prop('items')! - .find( - item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' - )! as ReactElement).props.onClick(); - }); + act(() => { + wrapper.find(EuiFieldSearch).prop('onChange')!({ target: { value: 'mem' } } as ChangeEvent< + HTMLInputElement + >); + }); - expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ - 'memory', - ]); + act(() => { + (wrapper + .find(EuiContextMenuPanel) + .prop('items')! + .find( + item => (item as ReactElement).props['data-test-subj'] === 'typeFilter-number' + )! as ReactElement).props.onClick(); }); + + expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([ + 'memory', + ]); }); }); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.test.tsx index 5d2e80b3e4b28e..a25ff140b124d1 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.test.tsx @@ -14,8 +14,9 @@ import { FieldItem } from './field_item'; import { act } from 'react-dom/test-utils'; import { DatasourceDataPanelProps } from '..'; import { IndexPatternLayerPanelProps, LayerPanel } from './layerpanel'; +import { updateLayerIndexPattern } from './state_helpers'; -jest.mock('./loader'); +jest.mock('./state_helpers'); const initialState: IndexPatternPrivateState = { currentIndexPatternId: '1', @@ -151,7 +152,7 @@ const initialState: IndexPatternPrivateState = { searchable: true, }, { - name: 'bytes', + name: 'memory', type: 'number', aggregatable: true, searchable: true, @@ -167,181 +168,71 @@ const initialState: IndexPatternPrivateState = { }, }; describe('Layer Data Panel', () => { - let defaultProps: IndexPatternLayerPanelProps; + let defaultProps: IndexPatternLayerPanelProps; - beforeEach(() => { - defaultProps = { - layerId: 'first', - state: initialState, - setState: jest.fn(), - }; - }); + beforeEach(() => { + defaultProps = { + layerId: 'first', + state: initialState, + setState: jest.fn(), + }; + }); - // function changeIndexPattern( - // component: ShallowWrapper[0]>, - // newIndexPattern: I - // ) { - // component.find('[data-test-subj="layerIndexPatternLabel"]').first().simulate('click'); - // component.find('[data-test-subj="layerIndexPatternSwitcher"]').find(EuiComboBox).prop('onChange')!([{ label: '', value: initialState.indexPatterns['2']}]) - // } + it('should list all index patterns but the current one', () => { + const instance = shallow(); + act(() => { + instance + .find('[data-test-subj="layerIndexPatternLabel"]') + .first() + .simulate('click'); + }); - it('should list all index patterns but the current one', () => { - const instance = shallow(); - act(() => { - instance.find('[data-test-subj="layerIndexPatternLabel"]').first().simulate('click'); - }); + expect( + instance + .find(EuiComboBox) + .prop('options')! + .map(option => option.label) + ).toEqual(['my-fake-restricted-pattern', 'my-compatible-pattern']); + }); - expect(instance.find(EuiComboBox).prop('options')!.map(option => option.label)).toEqual(); - - changeIndexPattern(instance, '3'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...initialState, - currentIndexPatternId: '3', - }); + it('should indicate whether the switch can be made without lossing data', () => { + const instance = shallow(); + act(() => { + instance + .find('[data-test-subj="layerIndexPatternLabel"]') + .first() + .simulate('click'); }); - it('should not update the index pattern of the layer if there are layers with from different index patterns', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - ...initialState.layers, - first: { - indexPatternId: '2', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'avg', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '3'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...state, - currentIndexPatternId: '3', - }); - }); + expect( + instance + .find(EuiComboBox) + .prop('options')! + .map(option => (option.value as { isTransferable: boolean }).isTransferable) + ).toEqual([false, true]); + }); - it('should not update the index pattern of the layer if there are incompatible restrictions on the target index pattern', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - second: { - ...initialState.layers.second, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '2'); - expect(defaultProps.setState).toHaveBeenCalledWith({ - ...state, - currentIndexPatternId: '2', - }); + it('should switch using updateLayerIndexPattern', () => { + const instance = shallow(); + act(() => { + instance + .find('[data-test-subj="layerIndexPatternLabel"]') + .first() + .simulate('click'); }); - it('should change the index pattern if there are less restrictions on the target index patterns', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - second: { - indexPatternId: '2', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'min', - sourceField: 'bytes', - }, - }, - }, + act(() => { + instance.find(EuiComboBox).prop('onChange')!([ + { + label: 'my-compatible-pattern', + value: defaultProps.state.indexPatterns['3'], }, - }; - const instance = shallow(); - changeIndexPattern(instance, '1'); - const newState = (defaultProps.setState as jest.Mock).mock - .calls[0][0] as IndexPatternPrivateState; - expect(newState.currentIndexPatternId).toEqual('1'); - expect(newState.layers.second.indexPatternId).toEqual('1'); + ]); }); - it('should change the index pattern if all layers are compatible', () => { - const state: IndexPatternPrivateState = { - ...initialState, - layers: { - ...initialState.layers, - first: { - indexPatternId: '1', - columnOrder: ['col1', 'col2'], - columns: { - col1: { - label: 'My Op', - dataType: 'string', - isBucketed: true, - operationType: 'terms', - sourceField: 'source', - params: { - size: 5, - orderDirection: 'asc', - orderBy: { - type: 'alphabetical', - }, - }, - }, - col2: { - label: 'My Op', - dataType: 'number', - isBucketed: false, - operationType: 'avg', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const instance = shallow(); - changeIndexPattern(instance, '3'); - const newState = (defaultProps.setState as jest.Mock).mock - .calls[0][0] as IndexPatternPrivateState; - expect(newState.currentIndexPatternId).toEqual('3'); - expect(newState.layers.first.indexPatternId).toEqual('3'); - expect(newState.layers.second.indexPatternId).toEqual('3'); - }); + expect(updateLayerIndexPattern).toHaveBeenCalledWith( + defaultProps.state.layers.first, + defaultProps.state.indexPatterns['3'] + ); }); - }); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.tsx index 329e43001d76df..327e880128fb99 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/layerpanel.tsx @@ -35,7 +35,7 @@ export function LayerPanel({ state, setState, layerId }: IndexPatternLayerPanelP ...indexPattern, isTransferable: isLayerTransferable(state.layers[layerId], indexPattern), })), - [state.indexPatterns, layerId] + [state.indexPatterns, layerId, state.layers[layerId]] ); const currentIndexPatternId = state.layers[layerId].indexPatternId;