Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enterprise Search] Mocks/tests tech debt - avoid hungry mocking #101107

Merged
merged 9 commits into from
Jun 9, 2021
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ module.exports = {
{
// Source files only - allow `any` in test/mock files
files: ['x-pack/plugins/enterprise_search/**/*.{ts,tsx}'],
excludedFiles: ['x-pack/plugins/enterprise_search/**/*.{test,mock}.{ts,tsx}'],
excludedFiles: ['x-pack/plugins/enterprise_search/**/*.{test,mock,test_helper}.{ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export const mockFlashMessageHelpers = {
flashErrorToast: jest.fn(),
};

jest.mock('../shared/flash_messages', () => ({
...(jest.requireActual('../shared/flash_messages') as object),
jest.mock('../../shared/flash_messages', () => ({
...(jest.requireActual('../../shared/flash_messages') as object),
...mockFlashMessageHelpers,
FlashMessagesLogic: {
values: mockFlashMessagesValues,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

/**
* Combine all shared mock values/actions into a single obj
*
* NOTE: These variable names MUST start with 'mock*' in order for
* Jest to accept its use within a jest.mock()
*/
import { mockFlashMessagesValues, mockFlashMessagesActions } from './flash_messages_logic.mock';
import { mockHttpValues } from './http_logic.mock';
import { mockKibanaValues } from './kibana_logic.mock';
import { mockLicensingValues } from './licensing_logic.mock';
import { mockTelemetryActions } from './telemetry_logic.mock';

export const mockAllValues = {
...mockKibanaValues,
...mockLicensingValues,
...mockHttpValues,
...mockFlashMessagesValues,
};
export const mockAllActions = {
...mockTelemetryActions,
...mockFlashMessagesActions,
};

/**
* Import this file directly to mock useValues with a set of default values for all shared logic files.
* Example usage:
*
* import '../../../__mocks__/kea_logic'; // Must come before kea's import, adjust relative path as needed
*/
jest.mock('kea', () => ({
...(jest.requireActual('kea') as object),
useValues: jest.fn(() => ({ ...mockAllValues })),
useActions: jest.fn(() => ({ ...mockAllActions })),
}));

/**
* React component helpers
*
* Call this function to override a specific set of Kea values while retaining all other defaults
*
* Example usage:
*
* import { setMockValues } from '../../../__mocks__/kea_logic';
* import { SomeComponent } from './';
*
* it('some test', () => {
* setMockValues({ someValue: 'hello' });
* shallow(<SomeComponent />);
* });
*/
import { useValues, useActions } from 'kea';

export const setMockValues = (values: object) => {
(useValues as jest.Mock).mockImplementation(() => ({ ...mockAllValues, ...values }));
};
export const setMockActions = (actions: object) => {
(useActions as jest.Mock).mockImplementation(() => ({ ...mockAllActions, ...actions }));
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ export const mockHttpValues = {
readOnlyMode: false,
};

jest.mock('../shared/http', () => ({
jest.mock('../../shared/http', () => ({
HttpLogic: { values: mockHttpValues },
}));
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

export { mockHistory, mockLocation } from './react_router_history.mock';
export { mockKibanaValues } from './kibana_logic.mock';
export { mockLicensingValues } from './licensing_logic.mock';
export { mockHttpValues } from './http_logic.mock';
Expand All @@ -15,18 +14,6 @@ export {
mockFlashMessagesActions,
mockFlashMessageHelpers,
} from './flash_messages_logic.mock';
export {
mockAllValues,
mockAllActions,
setMockValues,
setMockActions,
LogicMounter,
} from './kea.mock';

export { mountAsync } from './mount_async.mock';
export { mountWithIntl } from './mount_with_i18n.mock';
export { shallowWithIntl } from './shallow_with_i18n.mock';
export { rerender } from './enzyme_rerender.mock';
// Note: shallow_useeffect must be imported directly as a file
export { mockAllValues, mockAllActions, setMockValues, setMockActions } from './hooks.mock';

export { expectedAsyncError } from './expected_async_error';
export { LogicMounter } from './logic_mounter.test_helper';
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* 2.0.
*/

import { mockHistory } from './react_router_history.mock';
import { chartPluginMock } from '../../../../../../../src/plugins/charts/public/mocks';

import { chartPluginMock } from '../../../../../../src/plugins/charts/public/mocks';
import { mockHistory } from '../react_router/state.mock';

export const mockKibanaValues = {
config: { host: 'http://localhost:3002' },
Expand All @@ -24,6 +24,6 @@ export const mockKibanaValues = {
renderHeaderActions: jest.fn(),
};

jest.mock('../shared/kibana', () => ({
jest.mock('../../shared/kibana', () => ({
KibanaLogic: { values: mockKibanaValues },
}));
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
* 2.0.
*/

import { licensingMock } from '../../../../licensing/public/mocks';
import { licensingMock } from '../../../../../licensing/public/mocks';

export const mockLicensingValues = {
license: licensingMock.createLicense(),
hasPlatinumLicense: false,
hasGoldLicense: false,
};

jest.mock('../shared/licensing', () => ({
jest.mock('../../shared/licensing', () => ({
LicensingLogic: { values: mockLicensingValues },
}));
Original file line number Diff line number Diff line change
Expand Up @@ -6,75 +6,14 @@
*/

/**
* Combine all shared mock values/actions into a single obj
*
* NOTE: These variable names MUST start with 'mock*' in order for
* Jest to accept its use within a jest.mock()
*/
import { mockFlashMessagesValues, mockFlashMessagesActions } from './flash_messages_logic.mock';
import { mockHttpValues } from './http_logic.mock';
import { mockKibanaValues } from './kibana_logic.mock';
import { mockLicensingValues } from './licensing_logic.mock';
import { mockTelemetryActions } from './telemetry_logic.mock';

export const mockAllValues = {
...mockKibanaValues,
...mockLicensingValues,
...mockHttpValues,
...mockFlashMessagesValues,
};
export const mockAllActions = {
...mockTelemetryActions,
...mockFlashMessagesActions,
};

/**
* Import this file directly to mock useValues with a set of default values for all shared logic files.
* Example usage:
*
* import '../../../__mocks__/kea'; // Must come before kea's import, adjust relative path as needed
*/
jest.mock('kea', () => ({
...(jest.requireActual('kea') as object),
useValues: jest.fn(() => ({ ...mockAllValues })),
useActions: jest.fn(() => ({ ...mockAllActions })),
}));

/**
* React component helpers
*
* Call this function to override a specific set of Kea values while retaining all other defaults
*
* Example usage:
*
* import { setMockValues } from '../../../__mocks__/kea.mock';
* import { SomeComponent } from './';
*
* it('some test', () => {
* setMockValues({ someValue: 'hello' });
* shallow(<SomeComponent />);
* });
*/
import { useValues, useActions } from 'kea';

export const setMockValues = (values: object) => {
(useValues as jest.Mock).mockImplementation(() => ({ ...mockAllValues, ...values }));
};
export const setMockActions = (actions: object) => {
(useActions as jest.Mock).mockImplementation(() => ({ ...mockAllActions, ...actions }));
};

/**
* Kea logic helpers
*
* Call this function to mount a logic file and optionally override default values.
* Automatically DRYs out a lot of cruft for us, such as resetting context, creating the
* nested defaults path obj (see https://kea.js.org/docs/api/context#resetcontext), and
* returning an unmount function
*
* Example usage:
*
* import { LogicMounter } from '../../../__mocks__/kea.mock';
* import { LogicMounter } from '../../../__mocks__/kea_logic';
* import { SomeLogic } from './';
*
* const { mount, unmount } = new LogicMounter(SomeLogic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const mockTelemetryActions = {
sendWorkplaceSearchTelemetry: jest.fn(),
};

jest.mock('../shared/telemetry', () => ({
...(jest.requireActual('../shared/telemetry') as object),
jest.mock('../../shared/telemetry', () => ({
...(jest.requireActual('../../shared/telemetry') as object),
TelemetryLogic: { actions: mockTelemetryActions },
}));
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,25 @@
* 2.0.
*/

/**
* NOTE: These variable names MUST start with 'mock*' in order for
* Jest to accept its use within a jest.mock()
*/
export const mockHistory = {
createHref: jest.fn(({ pathname }) => `/app/enterprise_search${pathname}`),
push: jest.fn(),
location: {
pathname: '/current-path',
},
listen: jest.fn(() => jest.fn()),
} as any;
export const mockLocation = {
key: 'someKey',
pathname: '/current-path',
search: '?query=something',
hash: '#hash',
state: {},
};
import { mockHistory, mockLocation } from './state.mock';

export const mockUseHistory = jest.fn(() => mockHistory);
export const mockUseLocation = jest.fn(() => mockLocation);
export const mockUseParams = jest.fn(() => ({}));
export const mockUseRouteMatch = jest.fn(() => true);

jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');
return {
...originalModule,
useHistory: jest.fn(() => mockHistory),
useLocation: jest.fn(() => mockLocation),
useParams: jest.fn(() => ({})),
useRouteMatch: jest.fn(() => null),
useHistory: mockUseHistory,
useLocation: mockUseLocation,
useParams: mockUseParams,
useRouteMatch: mockUseRouteMatch,
// Note: RR's generatePath() opinionatedly encodeURI()s paths (although this doesn't actually
// show up/affect the final browser URL). Since we already have a generateEncodedPath helper &
// RR is removing this behavior in history 5.0+, I'm mocking tests to remove the extra encoding
// for now to make reading generateEncodedPath URLs a little less of a pain
generatePath: jest.fn((path, params) => decodeURI(originalModule.generatePath(path, params))),
};
});

/**
* For example usage, @see public/applications/shared/react_router_helpers/eui_link.test.tsx
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

// State and hooks are stored in separate mock files for when a file needs to
// import a basic history mock without automatically jest.mock()ing all of React Router
export * from './state.mock';
export * from './hooks.mock';

// For example usage, @see public/applications/shared/react_router_helpers/eui_link.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

/**
* NOTE: These variable names MUST start with 'mock*' in order for
* Jest to accept its use within a jest.mock()
*/

export const mockHistory = {
createHref: jest.fn(({ pathname }) => `/app/enterprise_search${pathname}`),
push: jest.fn(),
location: {
pathname: '/current-path',
},
listen: jest.fn(() => jest.fn()),
} as any;

export const mockLocation = {
key: 'someKey',
pathname: '/current-path',
search: '?query=something',
hash: '#hash',
state: {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__';
import { LogicMounter } from '../__mocks__';
import { LogicMounter } from '../__mocks__/kea_logic';

import { AppLogic } from './app_logic';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
*/

import '../../../__mocks__/shallow_useeffect.mock';
import '../../../__mocks__/react_router_history.mock';
import { mockKibanaValues, setMockValues, setMockActions, rerender } from '../../../__mocks__';
import { mockKibanaValues, setMockValues, setMockActions } from '../../../__mocks__/kea_logic';
import { mockUseParams } from '../../../__mocks__/react_router';

import React from 'react';
import { useParams } from 'react-router-dom';

import { shallow } from 'enzyme';

import { FlashMessages } from '../../../shared/flash_messages';
import { Loading } from '../../../shared/loading';
import { rerender } from '../../../test_helpers';
import { LogRetentionCallout } from '../log_retention';

import { AnalyticsLayout } from './analytics_layout';
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('AnalyticsLayout', () => {

describe('data loading', () => {
it('loads query data for query details pages', () => {
(useParams as jest.Mock).mockReturnValueOnce({ query: 'test' });
mockUseParams.mockReturnValueOnce({ query: 'test' });
shallow(<AnalyticsLayout isQueryView title="" />);

expect(actions.loadQueryData).toHaveBeenCalledWith('test');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
mockKibanaValues,
mockHttpValues,
mockFlashMessageHelpers,
} from '../../../__mocks__';
} from '../../../__mocks__/kea_logic';

jest.mock('../engine', () => ({
EngineLogic: { values: { engineName: 'test-engine' } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { mockKibanaValues } from '../../../../__mocks__';
import { mockKibanaValues } from '../../../../__mocks__/kea_logic';

import React from 'react';

Expand Down
Loading