diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts index 4ebb9edd20c0e..0926c67544701 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts @@ -85,6 +85,7 @@ export const setMockActions = (actions: object) => { * }); */ import { resetContext, LogicWrapper } from 'kea'; +import { merge } from 'lodash'; type LogicFile = LogicWrapper; @@ -101,25 +102,82 @@ export class LogicMounter { if (!values || !Object.keys(values).length) { resetContext({}); } else { - let { path, key } = this.logicFile.inputs[0]; - - // For keyed logic files, both key and path should be functions - if (this.logicFile._isKeaWithKey) { - key = key(props); - path = path(key); - } - - // Generate the correct nested defaults obj based on the file path - // example path: ['x', 'y', 'z'] - // example defaults: { x: { y: { z: values } } } - const defaults = path.reduceRight( - (value: object, name: string) => ({ [name]: value }), - values - ); + const defaults: object = this.createDefaultValuesObject(values, props); resetContext({ defaults }); } }; + /** + * Based on the values passed into mount, turn them into properly nested objects that can + * be passed to kea's resetContext in order to set default values": + * + * ex. + * + * input: + * + * values: { + * schema: { foo: "text" }, + * engineName: "engine1" + * } + * + * output: + * + * { + * enterprise_search: { + * app_search: { + * schema_logic: { + * schema: { foo: "text" } + * }, + * engine_logic: { + * engineName: "engine1" + * } + * } + * } + * } + */ + private createDefaultValuesObject = (values: object, props?: object) => { + let { path, key } = this.logicFile.inputs[0]; + + // For keyed logic files, both key and path should be functions + if (this.logicFile._isKeaWithKey) { + key = key(props); + path = path(key); + } + + // TODO Deal with this if and when we get there. + if (this.logicFile.inputs[0].connect?.values.length > 2) { + throw Error( + "This connected logic has more than 2 values in 'connect', implement handler logic for this in kea.mock.ts" + ); + } + + // If a logic includes values from another logic via the "connect" property, we need to make sure they're nested + // correctly under the correct path. + // + // For example, if the current logic under test is SchemaLogic connects values from EngineLogic also, then we need + // to make sure that values from SchemaLogic get nested under enterprise_search.app_search.schema_logic, and values + // from EngineLogic get nested under enterprise_search.app_search.engine_logic + if (this.logicFile.inputs[0].connect?.values[0]) { + const connectedPath = this.logicFile.inputs[0].connect.values[0].inputs[0].path; + const connectedValueKeys = this.logicFile.inputs[0].connect.values[1]; + + const primaryValues: Record = {}; + const connectedValues: Record = {}; + + Object.entries(values).forEach(([k, v]) => { + if (connectedValueKeys.includes(k)) { + connectedValues[k] = v; + } else { + primaryValues[k] = v; + } + }); + + return merge(createDefaults(path, values), createDefaults(connectedPath, connectedValues)); + } else { + return createDefaults(path, values); + } + }; + // Automatically reset context & mount the logic file public mount = (values?: object, props?: object) => { this.resetContext(values, props); @@ -132,6 +190,48 @@ export class LogicMounter { // built logic instance with props, NOT the unmount fn }; + // Custom "jest-like" assertions + // ex. + // expectAction(() => { + // SomeLogic.actions.dataInitialized(); + // }).toChangeState({ + // from: { dataLoading: true }, + // to: { dataLoading: false }, + // }); + // + // For keyed logic: + // + // ex. + // expectAction((logic) => { + // logic.actions.dataInitialized(); + // }, PROPS).toChangeState({ + // from: { dataLoading: true }, + // to: { dataLoading: false }, + // }); + // + + public expectAction = (action: (logic: LogicFile) => void, props: object = {}) => { + return { + // Mount state with "from" values and test that the specified "to" values are present in + // the updated state, and that no other values have changed. + toChangeState: ({ from, to, ignore }: { from: object; to: object; ignore?: string[] }) => { + const logic = this.mount(from, props); + const originalValues = { + ...logic.values, + }; + action(logic); + expect(logic.values).toEqual({ + ...originalValues, + ...to, + ...(ignore || []).reduce((acc: Record, field: string) => { + acc[field] = expect.anything(); + return acc; + }, {}), + }); + }, + }; + }; + // Also add unmount as a class method that can be destructured on init without becoming stale later public unmount = () => { this.unmountFn(); @@ -162,3 +262,10 @@ export class LogicMounter { : listeners; // handles simpler logic files that just define listeners: { ... } }; } + +// Generate the correct nested defaults obj based on the file path +// example path: ['x', 'y', 'z'] +// example defaults: { x: { y: { z: values } } } +const createDefaults = (path: string[], values: object) => { + return path.reduceRight((value: object, name: string) => ({ [name]: value }), values); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows_logic.test.ts index 0e2d28a6fc3e1..79b1d6a1caba2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows_logic.test.ts @@ -7,12 +7,10 @@ import { LogicMounter } from '../../../__mocks__'; -import { Logic } from 'kea'; - import { MultiInputRowsLogic } from './multi_input_rows_logic'; describe('MultiInputRowsLogic', () => { - const { mount } = new LogicMounter(MultiInputRowsLogic); + const { mount, expectAction } = new LogicMounter(MultiInputRowsLogic); const MOCK_VALUES = ['a', 'b', 'c']; @@ -37,67 +35,70 @@ describe('MultiInputRowsLogic', () => { }); describe('actions', () => { - let logic: Logic; - - beforeEach(() => { - logic = mount({}, DEFAULT_PROPS); - }); - - afterEach(() => { - // Should not mutate the original array - expect(logic.values.values).not.toBe(MOCK_VALUES); // Would fail if we did not clone a new array - }); - describe('addValue', () => { it('appends an empty string to the values array & sets addedNewRow to true', () => { - logic.actions.addValue(); - - expect(logic.values).toEqual({ - ...DEFAULT_VALUES, - addedNewRow: true, - hasEmptyValues: true, - values: ['a', 'b', 'c', ''], + expectAction((logic) => { + logic.actions.addValue(); + }, DEFAULT_PROPS).toChangeState({ + from: { + addedNewRow: false, + hasEmptyValues: false, + values: ['a', 'b', 'c'], + }, + to: { + addedNewRow: true, + hasEmptyValues: true, + values: ['a', 'b', 'c', ''], + }, }); }); }); describe('deleteValue', () => { it('deletes the value at the specified array index', () => { - logic.actions.deleteValue(1); - - expect(logic.values).toEqual({ - ...DEFAULT_VALUES, - values: ['a', 'c'], + expectAction((logic) => { + logic.actions.deleteValue(1); + }, DEFAULT_PROPS).toChangeState({ + from: { + values: ['a', 'b', 'c'], + }, + to: { + values: ['a', 'c'], + }, }); }); }); describe('editValue', () => { it('edits the value at the specified array index', () => { - logic.actions.editValue(2, 'z'); - - expect(logic.values).toEqual({ - ...DEFAULT_VALUES, - values: ['a', 'b', 'z'], + expectAction((logic) => { + logic.actions.editValue(2, 'z'); + }, DEFAULT_PROPS).toChangeState({ + from: { + values: ['a', 'b', 'c'], + }, + to: { + values: ['a', 'b', 'z'], + }, }); }); }); - }); - describe('selectors', () => { - describe('hasEmptyValues', () => { - it('returns true if values has any empty strings', () => { - const logic = mount({}, { ...DEFAULT_PROPS, values: ['', '', ''] }); + describe('selectors', () => { + describe('hasEmptyValues', () => { + it('returns true if values has any empty strings', () => { + const logic = mount({}, { ...DEFAULT_PROPS, values: ['', '', ''] }); - expect(logic.values.hasEmptyValues).toEqual(true); + expect(logic.values.hasEmptyValues).toEqual(true); + }); }); - }); - describe('hasOnlyOneValue', () => { - it('returns true if values only has one item', () => { - const logic = mount({}, { ...DEFAULT_PROPS, values: ['test'] }); + describe('hasOnlyOneValue', () => { + it('returns true if values only has one item', () => { + const logic = mount({}, { ...DEFAULT_PROPS, values: ['test'] }); - expect(logic.values.hasOnlyOneValue).toEqual(true); + expect(logic.values.hasOnlyOneValue).toEqual(true); + }); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts index 6522d84aef156..469849116b19f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_logic.test.ts @@ -9,8 +9,6 @@ import { LogicMounter, mockFlashMessageHelpers, mockHttpValues } from '../../../ import { mockEngineValues } from '../../__mocks__'; -import { omit } from 'lodash'; - import { nextTick } from '@kbn/test/jest'; import { Schema, SchemaConflicts, SchemaType } from '../../../shared/schema/types'; @@ -32,7 +30,7 @@ const expectToHaveBeenCalledWithStrict = ( }; describe('ResultSettingsLogic', () => { - const { mount } = new LogicMounter(ResultSettingsLogic); + const { mount, expectAction } = new LogicMounter(ResultSettingsLogic); const DEFAULT_VALUES = { dataLoading: true, @@ -54,8 +52,7 @@ describe('ResultSettingsLogic', () => { queryPerformanceScore: 0, }; - // Values without selectors - const resultSettingLogicValues = () => omit(ResultSettingsLogic.values, Object.keys(SELECTORS)); + const SELECTOR_FIELDS = Object.keys(SELECTORS); beforeEach(() => { jest.clearAllMocks(); @@ -91,117 +88,112 @@ describe('ResultSettingsLogic', () => { }; it('will initialize all result field state within the UI, based on provided server data', () => { - mount({ - dataLoading: true, - saving: true, - }); - - ResultSettingsLogic.actions.initializeResultFields( - serverResultFields, - schema, - schemaConflicts - ); - - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - dataLoading: false, - saving: false, - // It converts the passed server result fields to a client results field and stores it - // as resultFields - resultFields: { - foo: { - raw: true, - rawSize: 5, - snippet: false, - snippetFallback: false, - }, - // Baz was not part of the original serverResultFields, it was injected based on the schema - baz: { - raw: false, - snippet: false, - snippetFallback: false, - }, - bar: { - raw: true, - rawSize: 5, - snippet: false, - snippetFallback: false, - }, - }, - // It also saves it as lastSavedResultFields - lastSavedResultFields: { - foo: { - raw: true, - rawSize: 5, - snippet: false, - snippetFallback: false, - }, - // Baz was not part of the original serverResultFields, it was injected based on the schema - baz: { - raw: false, - snippet: false, - snippetFallback: false, + expectAction(() => { + ResultSettingsLogic.actions.initializeResultFields( + serverResultFields, + schema, + schemaConflicts + ); + }).toChangeState({ + from: { + dataLoading: true, + saving: true, + }, + ignore: SELECTOR_FIELDS, + to: { + dataLoading: false, + saving: false, + // It converts the passed server result fields to a client results field and stores it + // as resultFields + resultFields: { + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: { + raw: false, + snippet: false, + snippetFallback: false, + }, + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, }, - bar: { - raw: true, - rawSize: 5, - snippet: false, - snippetFallback: false, + // It also saves it as lastSavedResultFields + lastSavedResultFields: { + foo: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, + // Baz was not part of the original serverResultFields, it was injected based on the schema + baz: { + raw: false, + snippet: false, + snippetFallback: false, + }, + bar: { + raw: true, + rawSize: 5, + snippet: false, + snippetFallback: false, + }, }, + // Stores the provided schema details + schema, + schemaConflicts, }, - // Stores the provided schema details - schema, - schemaConflicts, }); }); - - it('default schema conflicts data if none was provided', () => { - mount(); - - ResultSettingsLogic.actions.initializeResultFields(serverResultFields, schema); - - expect(ResultSettingsLogic.values.schemaConflicts).toEqual({}); - }); }); describe('clearAllFields', () => { it('should remove all settings that have been set for each field', () => { - mount({ - resultFields: { - quuz: { raw: false, snippet: false, snippetFallback: false }, - corge: { raw: true, snippet: false, snippetFallback: true }, + expectAction(() => { + ResultSettingsLogic.actions.clearAllFields(); + }).toChangeState({ + from: { + resultFields: { + quuz: { raw: false, snippet: false, snippetFallback: false }, + corge: { raw: true, snippet: false, snippetFallback: true }, + }, }, - }); - - ResultSettingsLogic.actions.clearAllFields(); - - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - resultFields: { - quuz: {}, - corge: {}, + to: { + resultFields: { + quuz: {}, + corge: {}, + }, }, + ignore: SELECTOR_FIELDS, }); }); }); describe('resetAllFields', () => { it('should reset all settings to their default values per field', () => { - mount({ - resultFields: { - quuz: { raw: true, snippet: true, snippetFallback: true }, - corge: { raw: true, snippet: true, snippetFallback: true }, + expectAction(() => { + ResultSettingsLogic.actions.resetAllFields(); + }).toChangeState({ + from: { + resultFields: { + quuz: { raw: true, snippet: true, snippetFallback: true }, + corge: { raw: true, snippet: true, snippetFallback: true }, + }, }, - }); - - ResultSettingsLogic.actions.resetAllFields(); - - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - resultFields: { - quuz: { raw: true, snippet: false, snippetFallback: false }, - corge: { raw: true, snippet: false, snippetFallback: false }, + to: { + resultFields: { + quuz: { raw: true, snippet: false, snippetFallback: false }, + corge: { raw: true, snippet: false, snippetFallback: false }, + }, }, + ignore: SELECTOR_FIELDS, }); }); }); @@ -215,52 +207,45 @@ describe('ResultSettingsLogic', () => { }; it('should update settings for an individual field', () => { - mount(initialValues); - - ResultSettingsLogic.actions.updateField('foo', { - raw: true, - snippet: false, - snippetFallback: false, - }); - - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - // the settings for foo are updated below for any *ResultFields state in which they appear - resultFields: { - foo: { raw: true, snippet: false, snippetFallback: false }, - bar: { raw: true, snippet: true, snippetFallback: true }, + expectAction(() => { + ResultSettingsLogic.actions.updateField('foo', { + raw: true, + snippet: false, + snippetFallback: false, + }); + }).toChangeState({ + from: initialValues, + to: { + resultFields: { + foo: { raw: true, snippet: false, snippetFallback: false }, + bar: { raw: true, snippet: true, snippetFallback: true }, + }, }, + ignore: SELECTOR_FIELDS, }); }); it('should do nothing if the specified field does not exist', () => { - mount(initialValues); - - ResultSettingsLogic.actions.updateField('baz', { - raw: false, - snippet: false, - snippetFallback: false, - }); - - // 'baz' does not exist in state, so nothing is updated - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - ...initialValues, + expectAction(() => { + ResultSettingsLogic.actions.updateField('baz', { + raw: false, + snippet: false, + snippetFallback: false, + }); + }).toChangeState({ + from: initialValues, + to: initialValues, }); }); }); describe('saving', () => { it('sets saving to true', () => { - mount({ - saving: false, - }); - - ResultSettingsLogic.actions.saving(); - - expect(resultSettingLogicValues()).toEqual({ - ...DEFAULT_VALUES, - saving: true, + expectAction(() => { + ResultSettingsLogic.actions.saving(); + }).toChangeState({ + from: { saving: false }, + to: { saving: true }, }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_logic.test.ts index 123f62af4eeba..f0da5c323e03b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/schema/schema_logic.test.ts @@ -10,12 +10,12 @@ import { mockEngineActions } from '../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; -import { SchemaType, Schema } from '../../../shared/schema/types'; +import { SchemaType } from '../../../shared/schema/types'; import { SchemaLogic } from './schema_logic'; describe('SchemaLogic', () => { - const { mount } = new LogicMounter(SchemaLogic); + const { mount, expectAction } = new LogicMounter(SchemaLogic); const { http } = mockHttpValues; const { flashAPIErrors, flashSuccessToast, setErrorMessage } = mockFlashMessageHelpers; @@ -49,16 +49,6 @@ describe('SchemaLogic', () => { isModalOpen: false, }; - /* - * Unfortunately, we can't mount({ schema: ... }) & have to use an action to set schema - * because of the separate connected logic file - our LogicMounter test helper sets context - * for only the currently tested file - */ - const mountAndSetSchema = ({ schema, ...values }: { schema: Schema; [key: string]: unknown }) => { - mount(values); - SchemaLogic.actions.setSchema(schema); - }; - beforeEach(() => { jest.clearAllMocks(); }); @@ -71,64 +61,63 @@ describe('SchemaLogic', () => { describe('actions', () => { describe('onSchemaLoad', () => { it('stores the API response in state and sets isUpdating & isModalOpen to false', () => { - mount({ isModalOpen: true }); - - SchemaLogic.actions.onSchemaLoad(MOCK_RESPONSE); - - expect(SchemaLogic.values).toEqual({ - ...DEFAULT_VALUES, - // SchemaBaseLogic - dataLoading: false, - schema: MOCK_RESPONSE.schema, - // SchemaLogic - isUpdating: false, - isModalOpen: false, - cachedSchema: MOCK_RESPONSE.schema, - hasSchema: true, - mostRecentIndexJob: MOCK_RESPONSE.mostRecentIndexJob, - unconfirmedFields: MOCK_RESPONSE.unconfirmedFields, - hasUnconfirmedFields: true, - hasNewUnsearchedFields: MOCK_RESPONSE.unsearchedUnconfirmedFields, + expectAction(() => { + SchemaLogic.actions.onSchemaLoad(MOCK_RESPONSE); + }).toChangeState({ + from: { isModalOpen: true }, + to: { + // SchemaBaseLogic + dataLoading: false, + schema: MOCK_RESPONSE.schema, + // SchemaLogic + isUpdating: false, + isModalOpen: false, + cachedSchema: MOCK_RESPONSE.schema, + hasSchema: true, + mostRecentIndexJob: MOCK_RESPONSE.mostRecentIndexJob, + unconfirmedFields: MOCK_RESPONSE.unconfirmedFields, + hasUnconfirmedFields: true, + hasNewUnsearchedFields: MOCK_RESPONSE.unsearchedUnconfirmedFields, + }, }); }); }); describe('onSchemaUpdateError', () => { it('sets isUpdating & isModalOpen to false', () => { - mount({ isUpdating: true, isModalOpen: true }); - - SchemaLogic.actions.onSchemaUpdateError(); - - expect(SchemaLogic.values).toEqual({ - ...DEFAULT_VALUES, - isUpdating: false, - isModalOpen: false, + expectAction(() => { + SchemaLogic.actions.onSchemaUpdateError(); + }).toChangeState({ + from: { + isUpdating: true, + isModalOpen: true, + }, + to: { + isUpdating: false, + isModalOpen: false, + }, }); }); }); describe('openModal', () => { it('sets isModalOpen to true', () => { - mount({ isModalOpen: false }); - - SchemaLogic.actions.openModal(); - - expect(SchemaLogic.values).toEqual({ - ...DEFAULT_VALUES, - isModalOpen: true, + expectAction(() => { + SchemaLogic.actions.openModal(); + }).toChangeState({ + from: { isModalOpen: false }, + to: { isModalOpen: true }, }); }); }); describe('closeModal', () => { it('sets isModalOpen to false', () => { - mount({ isModalOpen: true }); - - SchemaLogic.actions.closeModal(); - - expect(SchemaLogic.values).toEqual({ - ...DEFAULT_VALUES, - isModalOpen: false, + expectAction(() => { + SchemaLogic.actions.closeModal(); + }).toChangeState({ + from: { isModalOpen: true }, + to: { isModalOpen: false }, }); }); }); @@ -137,19 +126,19 @@ describe('SchemaLogic', () => { describe('selectors', () => { describe('hasSchema', () => { it('returns true when the schema obj has items', () => { - mountAndSetSchema({ schema: { test: SchemaType.Text } }); + mount({ schema: { test: SchemaType.Text } }); expect(SchemaLogic.values.hasSchema).toEqual(true); }); it('returns false when the schema obj is empty', () => { - mountAndSetSchema({ schema: {} }); + mount({ schema: {} }); expect(SchemaLogic.values.hasSchema).toEqual(false); }); }); describe('hasSchemaChanged', () => { it('returns true when the schema state is different from the cachedSchema state', () => { - mountAndSetSchema({ + mount({ schema: { test: SchemaType.Text }, cachedSchema: { test: SchemaType.Number }, }); @@ -158,11 +147,10 @@ describe('SchemaLogic', () => { }); it('returns false when the stored schema is the same as cachedSchema', () => { - mountAndSetSchema({ + mount({ schema: { test: SchemaType.Text }, cachedSchema: { test: SchemaType.Text }, }); - expect(SchemaLogic.values.hasSchemaChanged).toEqual(false); }); }); @@ -184,7 +172,7 @@ describe('SchemaLogic', () => { describe('addSchemaField', () => { describe('if the schema field already exists', () => { it('flashes an error and closes the modal', () => { - mountAndSetSchema({ schema: { existing_field: SchemaType.Text } }); + mount({ schema: { existing_field: SchemaType.Text } }); jest.spyOn(SchemaLogic.actions, 'closeModal'); SchemaLogic.actions.addSchemaField('existing_field', SchemaType.Text); @@ -214,7 +202,7 @@ describe('SchemaLogic', () => { describe('updateSchemaFieldType', () => { it("updates an existing schema key's field type value", async () => { - mountAndSetSchema({ schema: { existing_field: SchemaType.Text } }); + mount({ schema: { existing_field: SchemaType.Text } }); jest.spyOn(SchemaLogic.actions, 'setSchema'); SchemaLogic.actions.updateSchemaFieldType('existing_field', SchemaType.Geolocation); @@ -227,13 +215,11 @@ describe('SchemaLogic', () => { describe('updateSchema', () => { it('sets isUpdating to true', () => { - mount({ isUpdating: false }); - - SchemaLogic.actions.updateSchema(); - - expect(SchemaLogic.values).toEqual({ - ...DEFAULT_VALUES, - isUpdating: true, + expectAction(() => { + SchemaLogic.actions.updateSchema(); + }).toChangeState({ + from: { isUpdating: false }, + to: { isUpdating: true }, }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts index 2191c633131bb..9484a68e00803 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/search_ui/search_ui_logic.test.ts @@ -16,7 +16,7 @@ import { ActiveField } from './types'; import { SearchUILogic } from './'; describe('SearchUILogic', () => { - const { mount } = new LogicMounter(SearchUILogic); + const { mount, expectAction } = new LogicMounter(SearchUILogic); const { http } = mockHttpValues; const { flashAPIErrors } = mockFlashMessageHelpers; @@ -45,79 +45,80 @@ describe('SearchUILogic', () => { describe('actions', () => { describe('onFieldDataLoaded', () => { it('sets initial field values fetched from API call and sets dataLoading to false', () => { - mount({ - validFields: [], - validSortFields: [], - validFacetFields: [], - }); - - SearchUILogic.actions.onFieldDataLoaded({ - validFields: ['foo'], - validSortFields: ['bar'], - validFacetFields: ['baz'], - }); - - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - dataLoading: false, - validFields: ['foo'], - validSortFields: ['bar'], - validFacetFields: ['baz'], + expectAction(() => { + SearchUILogic.actions.onFieldDataLoaded({ + validFields: ['foo'], + validSortFields: ['bar'], + validFacetFields: ['baz'], + }); + }).toChangeState({ + from: { + dataLoading: true, + validFields: [], + validSortFields: [], + validFacetFields: [], + }, + to: { + dataLoading: false, + validFields: ['foo'], + validSortFields: ['bar'], + validFacetFields: ['baz'], + }, }); }); }); describe('onTitleFieldChange', () => { it('sets the titleField value', () => { - mount({ titleField: '' }); - SearchUILogic.actions.onTitleFieldChange('foo'); - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - titleField: 'foo', + expectAction(() => { + SearchUILogic.actions.onTitleFieldChange('foo'); + }).toChangeState({ + from: { titleField: '' }, + to: { titleField: 'foo' }, }); }); }); describe('onUrlFieldChange', () => { it('sets the urlField value', () => { - mount({ urlField: '' }); - SearchUILogic.actions.onUrlFieldChange('foo'); - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - urlField: 'foo', + expectAction(() => { + SearchUILogic.actions.onUrlFieldChange('foo'); + }).toChangeState({ + from: { urlField: '' }, + to: { urlField: 'foo' }, }); }); }); describe('onFacetFieldsChange', () => { it('sets the facetFields value', () => { - mount({ facetFields: [] }); - SearchUILogic.actions.onFacetFieldsChange(['foo']); - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - facetFields: ['foo'], + expectAction(() => { + SearchUILogic.actions.onFacetFieldsChange(['foo']); + }).toChangeState({ + from: { facetFields: [] }, + to: { facetFields: ['foo'] }, }); }); }); describe('onSortFieldsChange', () => { it('sets the sortFields value', () => { - mount({ sortFields: [] }); - SearchUILogic.actions.onSortFieldsChange(['foo']); - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - sortFields: ['foo'], + expectAction(() => { + SearchUILogic.actions.onSortFieldsChange(['foo']); + }).toChangeState({ + from: { sortFields: [] }, + to: { sortFields: ['foo'] }, }); }); }); describe('onActiveFieldChange', () => { it('sets the activeField value', () => { - mount({ activeField: '' }); - SearchUILogic.actions.onActiveFieldChange(ActiveField.Sort); - expect(SearchUILogic.values).toEqual({ - ...DEFAULT_VALUES, - activeField: ActiveField.Sort, + expectAction(() => { + SearchUILogic.actions.onActiveFieldChange(ActiveField.Sort); + }).toChangeState({ + from: { activeField: '' }, + to: { activeField: ActiveField.Sort }, }); }); });