[Ingest pipelines] Clean up component integration tests (#78838)

This commit is contained in:
Alison Goryachev 2020-10-05 10:52:08 -04:00 committed by GitHub
parent 59e4e06316
commit 18a67b68b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 173 additions and 213 deletions

View file

@ -3,38 +3,42 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { act } from 'react-dom/test-utils';
import { TestBed } from '../../../../../test_utils';
export const getFormActions = (testBed: TestBed) => {
const { find, form } = testBed;
const { find, form, component } = testBed;
// User actions
const clickSubmitButton = () => {
find('submitButton').simulate('click');
const clickSubmitButton = async () => {
await act(async () => {
find('submitButton').simulate('click');
});
component.update();
};
const clickAddDocumentsButton = () => {
find('addDocumentsButton').simulate('click');
};
const clickShowRequestLink = async () => {
await act(async () => {
find('showRequestLink').simulate('click');
});
const clickShowRequestLink = () => {
find('showRequestLink').simulate('click');
component.update();
};
const toggleVersionSwitch = () => {
form.toggleEuiSwitch('versionToggle');
};
act(() => {
form.toggleEuiSwitch('versionToggle');
});
const toggleOnFailureSwitch = () => {
form.toggleEuiSwitch('onFailureToggle');
component.update();
};
return {
clickSubmitButton,
clickShowRequestLink,
toggleVersionSwitch,
toggleOnFailureSwitch,
clickAddDocumentsButton,
};
};

View file

@ -11,7 +11,6 @@ import {
TestBed,
TestBedConfig,
findTestSubject,
nextTick,
} from '../../../../../test_utils';
import { PipelinesList } from '../../../public/application/sections/pipelines_list';
import { WithAppDependencies } from './setup_environment';
@ -32,13 +31,17 @@ export type PipelineListTestBed = TestBed<PipelineListTestSubjects> & {
};
const createActions = (testBed: TestBed) => {
const { find } = testBed;
/**
* User Actions
*/
const clickReloadButton = () => {
find('reloadButton').simulate('click');
const clickReloadButton = async () => {
const { component, find } = testBed;
await act(async () => {
find('reloadButton').simulate('click');
});
component.update();
};
const clickPipelineAt = async (index: number) => {
@ -49,16 +52,19 @@ const createActions = (testBed: TestBed) => {
await act(async () => {
const { href } = pipelineLink.props();
router.navigateTo(href!);
await nextTick();
component.update();
});
component.update();
};
const clickActionMenu = (pipelineName: string) => {
const { component } = testBed;
// When a table has > 2 actions, EUI displays an overflow menu with an id "<pipeline_name>-actions"
component.find(`div[id="${pipelineName}-actions"] button`).simulate('click');
act(() => {
// When a table has > 2 actions, EUI displays an overflow menu with an id "<pipeline_name>-actions"
component.find(`div[id="${pipelineName}-actions"] button`).simulate('click');
});
component.update();
};
const clickPipelineAction = (pipelineName: string, action: 'edit' | 'clone' | 'delete') => {
@ -67,7 +73,11 @@ const createActions = (testBed: TestBed) => {
clickActionMenu(pipelineName);
component.find('.euiContextMenuItem').at(actions.indexOf(action)).simulate('click');
act(() => {
component.find('.euiContextMenuItem').at(actions.indexOf(action)).simulate('click');
});
component.update();
};
return {

View file

@ -4,20 +4,20 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import { LocationDescriptorObject } from 'history';
import { HttpSetup } from 'kibana/public';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';
import {
notificationServiceMock,
fatalErrorsServiceMock,
docLinksServiceMock,
injectedMetadataServiceMock,
scopedHistoryMock,
} from '../../../../../../src/core/public/mocks';
import { usageCollectionPluginMock } from '../../../../../../src/plugins/usage_collection/public/mocks';
import { HttpService } from '../../../../../../src/core/public/http';
import {
breadcrumbService,
documentationService,
@ -27,10 +27,7 @@ import {
import { init as initHttpRequests } from './http_requests';
const httpServiceSetupMock = new HttpService().setup({
injectedMetadata: injectedMetadataServiceMock.createSetupContract(),
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
});
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
const history = scopedHistoryMock.create();
history.createHref.mockImplementation((location: LocationDescriptorObject) => {
@ -53,7 +50,7 @@ const appServices = {
export const setupEnvironment = () => {
uiMetricService.setup(usageCollectionPluginMock.createSetupContract());
apiService.setup(httpServiceSetupMock, uiMetricService);
apiService.setup((mockHttpClient as unknown) as HttpSetup, uiMetricService);
documentationService.setup(docLinksServiceMock.createStartContract());
breadcrumbService.setup(() => {});

View file

@ -28,8 +28,7 @@ jest.mock('@elastic/eui', () => {
};
});
// FLAKY: https://github.com/elastic/kibana/issues/66856
describe.skip('<PipelinesClone />', () => {
describe('<PipelinesClone />', () => {
let testBed: PipelinesCloneTestBed;
const { server, httpRequestsMockHelpers } = setupEnvironment();
@ -38,13 +37,14 @@ describe.skip('<PipelinesClone />', () => {
server.restore();
});
beforeEach(async () => {
httpRequestsMockHelpers.setLoadPipelineResponse(PIPELINE_TO_CLONE);
httpRequestsMockHelpers.setLoadPipelineResponse(PIPELINE_TO_CLONE);
beforeEach(async () => {
await act(async () => {
testBed = await setup();
await testBed.waitFor('pipelineForm');
});
testBed.component.update();
});
test('should render the correct page header', () => {
@ -61,12 +61,9 @@ describe.skip('<PipelinesClone />', () => {
describe('form submission', () => {
it('should send the correct payload', async () => {
const { actions, waitFor } = testBed;
const { actions } = testBed;
await act(async () => {
actions.clickSubmitButton();
await waitFor('pipelineForm', 0);
});
await actions.clickSubmitButton();
const latestRequest = server.requests[server.requests.length - 1];
@ -75,7 +72,7 @@ describe.skip('<PipelinesClone />', () => {
name: `${PIPELINE_TO_CLONE.name}-copy`,
};
expect(JSON.parse(latestRequest.requestBody)).toEqual(expected);
expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
});
});
});

View file

@ -6,7 +6,7 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
import { setupEnvironment, pageHelpers } from './helpers';
import { PipelinesCreateTestBed } from './helpers/pipelines_create.helpers';
import { nestedProcessorsErrorFixture } from './fixtures';
@ -43,8 +43,9 @@ describe('<PipelinesCreate />', () => {
beforeEach(async () => {
await act(async () => {
testBed = await setup();
await testBed.waitFor('pipelineForm');
});
testBed.component.update();
});
test('should render the correct page header', () => {
@ -60,28 +61,20 @@ describe('<PipelinesCreate />', () => {
});
test('should toggle the version field', async () => {
const { actions, component, exists } = testBed;
const { actions, exists } = testBed;
// Version field should be hidden by default
expect(exists('versionField')).toBe(false);
await act(async () => {
actions.toggleVersionSwitch();
await nextTick();
component.update();
});
actions.toggleVersionSwitch();
expect(exists('versionField')).toBe(true);
});
test('should show the request flyout', async () => {
const { actions, component, find, exists } = testBed;
const { actions, find, exists } = testBed;
await act(async () => {
actions.clickShowRequestLink();
await nextTick();
component.update();
});
await actions.clickShowRequestLink();
// Verify request flyout opens
expect(exists('requestFlyout')).toBe(true);
@ -92,23 +85,18 @@ describe('<PipelinesCreate />', () => {
test('should prevent form submission if required fields are missing', async () => {
const { form, actions, component, find } = testBed;
await act(async () => {
actions.clickSubmitButton();
await nextTick();
component.update();
});
await actions.clickSubmitButton();
expect(form.getErrorsMessages()).toEqual(['Name is required.']);
expect(find('submitButton').props().disabled).toEqual(true);
// Add required fields and verify button is enabled again
form.setInputValue('nameField.input', 'my_pipeline');
await act(async () => {
await nextTick();
component.update();
// Add required fields and verify button is enabled again
form.setInputValue('nameField.input', 'my_pipeline');
});
component.update();
expect(find('submitButton').props().disabled).toEqual(false);
});
});
@ -117,23 +105,27 @@ describe('<PipelinesCreate />', () => {
beforeEach(async () => {
await act(async () => {
testBed = await setup();
const { waitFor, form } = testBed;
await waitFor('pipelineForm');
form.setInputValue('nameField.input', 'my_pipeline');
form.setInputValue('descriptionField.input', 'pipeline description');
});
testBed.component.update();
await act(async () => {
testBed.form.setInputValue('nameField.input', 'my_pipeline');
});
testBed.component.update();
await act(async () => {
testBed.form.setInputValue('descriptionField.input', 'pipeline description');
});
testBed.component.update();
});
test('should send the correct payload', async () => {
const { actions, waitFor } = testBed;
const { actions } = testBed;
await act(async () => {
actions.clickSubmitButton();
await waitFor('pipelineForm', 0);
});
await actions.clickSubmitButton();
const latestRequest = server.requests[server.requests.length - 1];
@ -143,11 +135,11 @@ describe('<PipelinesCreate />', () => {
processors: [],
};
expect(JSON.parse(latestRequest.requestBody)).toEqual(expected);
expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
});
test('should surface API errors from the request', async () => {
const { actions, find, exists, waitFor } = testBed;
const { actions, find, exists } = testBed;
const error = {
status: 409,
@ -157,29 +149,29 @@ describe('<PipelinesCreate />', () => {
httpRequestsMockHelpers.setCreatePipelineResponse(undefined, { body: error });
await act(async () => {
actions.clickSubmitButton();
await waitFor('savePipelineError');
});
await actions.clickSubmitButton();
expect(exists('savePipelineError')).toBe(true);
expect(find('savePipelineError').text()).toContain(error.message);
});
test('displays nested pipeline errors as a flat list', async () => {
const { actions, find, exists, waitFor } = testBed;
const { actions, find, exists, component } = testBed;
httpRequestsMockHelpers.setCreatePipelineResponse(undefined, {
body: nestedProcessorsErrorFixture,
});
await act(async () => {
actions.clickSubmitButton();
await waitFor('savePipelineError');
});
await actions.clickSubmitButton();
expect(exists('savePipelineError')).toBe(true);
expect(exists('savePipelineError.showErrorsButton')).toBe(true);
find('savePipelineError.showErrorsButton').simulate('click');
await act(async () => {
find('savePipelineError.showErrorsButton').simulate('click');
});
component.update();
expect(exists('savePipelineError.hideErrorsButton')).toBe(true);
expect(exists('savePipelineError.showErrorsButton')).toBe(false);
expect(find('savePipelineError').find('li').length).toBe(8);

View file

@ -37,13 +37,14 @@ describe('<PipelinesEdit />', () => {
server.restore();
});
beforeEach(async () => {
httpRequestsMockHelpers.setLoadPipelineResponse(PIPELINE_TO_EDIT);
httpRequestsMockHelpers.setLoadPipelineResponse(PIPELINE_TO_EDIT);
beforeEach(async () => {
await act(async () => {
testBed = await setup();
await testBed.waitFor('pipelineForm');
});
testBed.component.update();
});
test('should render the correct page header', () => {
@ -68,15 +69,12 @@ describe('<PipelinesEdit />', () => {
describe('form submission', () => {
it('should send the correct payload with changed values', async () => {
const UPDATED_DESCRIPTION = 'updated pipeline description';
const { actions, form, waitFor } = testBed;
const { actions, form } = testBed;
// Make change to description field
form.setInputValue('descriptionField.input', UPDATED_DESCRIPTION);
await act(async () => {
actions.clickSubmitButton();
await waitFor('pipelineForm', 0);
});
await actions.clickSubmitButton();
const latestRequest = server.requests[server.requests.length - 1];
@ -87,7 +85,7 @@ describe('<PipelinesEdit />', () => {
description: UPDATED_DESCRIPTION,
};
expect(JSON.parse(latestRequest.requestBody)).toEqual(expected);
expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected);
});
});
});

View file

@ -8,7 +8,7 @@ import { act } from 'react-dom/test-utils';
import { API_BASE_PATH } from '../../common/constants';
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
import { setupEnvironment, pageHelpers } from './helpers';
import { PipelineListTestBed } from './helpers/pipelines_list.helpers';
const { setup } = pageHelpers.pipelinesList;
@ -22,6 +22,14 @@ describe('<PipelinesList />', () => {
});
describe('With pipelines', () => {
beforeEach(async () => {
await act(async () => {
testBed = await setup();
});
testBed.component.update();
});
const pipeline1 = {
name: 'test_pipeline1',
description: 'test_pipeline1 description',
@ -38,16 +46,6 @@ describe('<PipelinesList />', () => {
httpRequestsMockHelpers.setLoadPipelinesResponse(pipelines);
beforeEach(async () => {
testBed = await setup();
await act(async () => {
const { waitFor } = testBed;
await waitFor('pipelinesTable');
});
});
test('should render the list view', async () => {
const { exists, find, table } = testBed;
@ -72,14 +70,10 @@ describe('<PipelinesList />', () => {
});
test('should reload the pipeline data', async () => {
const { component, actions } = testBed;
const { actions } = testBed;
const totalRequests = server.requests.length;
await act(async () => {
actions.clickReloadButton();
await nextTick(100);
component.update();
});
await actions.clickReloadButton();
expect(server.requests.length).toBe(totalRequests + 1);
expect(server.requests[server.requests.length - 1].url).toBe(API_BASE_PATH);
@ -118,33 +112,27 @@ describe('<PipelinesList />', () => {
await act(async () => {
confirmButton!.click();
await nextTick();
component.update();
});
const latestRequest = server.requests[server.requests.length - 1];
component.update();
expect(latestRequest.method).toBe('DELETE');
expect(latestRequest.url).toBe(`${API_BASE_PATH}/${pipelineName}`);
expect(latestRequest.status).toEqual(200);
const deleteRequest = server.requests[server.requests.length - 2];
expect(deleteRequest.method).toBe('DELETE');
expect(deleteRequest.url).toBe(`${API_BASE_PATH}/${pipelineName}`);
expect(deleteRequest.status).toEqual(200);
});
});
describe('No pipelines', () => {
beforeEach(async () => {
test('should display an empty prompt', async () => {
httpRequestsMockHelpers.setLoadPipelinesResponse([]);
testBed = await setup();
await act(async () => {
const { waitFor } = testBed;
await waitFor('emptyList');
testBed = await setup();
});
});
test('should display an empty prompt', async () => {
const { exists, find } = testBed;
const { exists, component, find } = testBed;
component.update();
expect(exists('sectionLoading')).toBe(false);
expect(exists('emptyList')).toBe(true);
@ -162,13 +150,11 @@ describe('<PipelinesList />', () => {
httpRequestsMockHelpers.setLoadPipelinesResponse(undefined, { body: error });
testBed = await setup();
await act(async () => {
const { waitFor } = testBed;
await waitFor('pipelineLoadError');
testBed = await setup();
});
testBed.component.update();
});
test('should render an error message if error fetching pipelines', async () => {

View file

@ -6,19 +6,9 @@
import { act } from 'react-dom/test-utils';
import React from 'react';
import { notificationServiceMock, scopedHistoryMock } from 'src/core/public/mocks';
import { LocationDescriptorObject } from 'history';
import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
import { registerTestBed, TestBed } from '../../../../../../../test_utils';
import { ProcessorsEditorContextProvider, Props, PipelineProcessorsEditor } from '../';
import {
breadcrumbService,
uiMetricService,
documentationService,
apiService,
} from '../../../services';
import { Props } from '../';
import { ProcessorsEditorWithDeps } from './processors_editor';
jest.mock('@elastic/eui', () => {
const original = jest.requireActual('@elastic/eui');
@ -67,28 +57,8 @@ jest.mock('react-virtualized', () => {
};
});
const history = scopedHistoryMock.create();
history.createHref.mockImplementation((location: LocationDescriptorObject) => {
return `${location.pathname}?${location.search}`;
});
const appServices = {
breadcrumbs: breadcrumbService,
metric: uiMetricService,
documentation: documentationService,
api: apiService,
notifications: notificationServiceMock.createSetupContract(),
history,
};
const testBedSetup = registerTestBed<TestSubject>(
(props: Props) => (
<KibanaContextProvider services={appServices}>
<ProcessorsEditorContextProvider {...props}>
<PipelineProcessorsEditor onLoadJson={jest.fn()} />
</ProcessorsEditorContextProvider>
</KibanaContextProvider>
),
(props: Props) => <ProcessorsEditorWithDeps {...props} />,
{
doMountAsync: false,
}

View file

@ -0,0 +1,43 @@
/*
* 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 React from 'react';
import { notificationServiceMock, scopedHistoryMock } from 'src/core/public/mocks';
import { LocationDescriptorObject } from 'history';
import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
import { ProcessorsEditorContextProvider, Props, PipelineProcessorsEditor } from '../';
import {
breadcrumbService,
uiMetricService,
documentationService,
apiService,
} from '../../../services';
const history = scopedHistoryMock.create();
history.createHref.mockImplementation((location: LocationDescriptorObject) => {
return `${location.pathname}?${location.search}`;
});
const appServices = {
breadcrumbs: breadcrumbService,
metric: uiMetricService,
documentation: documentationService,
api: apiService,
notifications: notificationServiceMock.createSetupContract(),
history,
};
export const ProcessorsEditorWithDeps: React.FunctionComponent<Props> = (props) => {
return (
<KibanaContextProvider services={appServices}>
<ProcessorsEditorContextProvider {...props}>
<PipelineProcessorsEditor onLoadJson={jest.fn()} />
</ProcessorsEditorContextProvider>
</KibanaContextProvider>
);
};

View file

@ -8,26 +8,15 @@ import React from 'react';
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import { notificationServiceMock, scopedHistoryMock } from 'src/core/public/mocks';
import { LocationDescriptorObject } from 'history';
import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
/* eslint-disable @kbn/eslint/no-restricted-paths */
import { usageCollectionPluginMock } from 'src/plugins/usage_collection/public/mocks';
import { registerTestBed, TestBed } from '../../../../../../../test_utils';
import { stubWebWorker } from '../../../../../../../test_utils/stub_web_worker';
import {
breadcrumbService,
uiMetricService,
documentationService,
apiService,
} from '../../../services';
import { ProcessorsEditorContextProvider, Props, PipelineProcessorsEditor } from '../';
import { uiMetricService, apiService } from '../../../services';
import { Props } from '../';
import { initHttpRequests } from './http_requests.helpers';
import { ProcessorsEditorWithDeps } from './processors_editor';
stubWebWorker();
@ -75,34 +64,8 @@ jest.mock('react-virtualized', () => {
};
});
const history = scopedHistoryMock.create();
history.createHref.mockImplementation((location: LocationDescriptorObject) => {
return `${location.pathname}?${location.search}`;
});
const appServices = {
breadcrumbs: breadcrumbService,
metric: uiMetricService,
documentation: documentationService,
api: apiService,
notifications: notificationServiceMock.createSetupContract(),
history,
uiSettings: {},
urlGenerators: {
getUrlGenerator: jest.fn().mockReturnValue({
createUrl: jest.fn(),
}),
},
};
const testBedSetup = registerTestBed<TestSubject>(
(props: Props) => (
<KibanaContextProvider services={appServices}>
<ProcessorsEditorContextProvider {...props}>
<PipelineProcessorsEditor onLoadJson={jest.fn()} />
</ProcessorsEditorContextProvider>
</KibanaContextProvider>
),
(props: Props) => <ProcessorsEditorWithDeps {...props} />,
{
doMountAsync: false,
}