diff --git a/packages/kbn-test/src/jest/utils/testbed/README.md b/packages/kbn-test/src/jest/utils/testbed/README.md index 5a05ba3750d3c..87cabd7ca4fa1 100644 --- a/packages/kbn-test/src/jest/utils/testbed/README.md +++ b/packages/kbn-test/src/jest/utils/testbed/README.md @@ -116,7 +116,7 @@ In order to prevent flakiness in component integration tests, please consider th }); ``` -- **Do not use** using `nextTick()`, `waitFor`, or `waitForFunc` helpers in tests. These helpers use `setTimeout` underneath and add latency in the tests, especially on CI where a timeout (even of a few ms) can trigger a timeout error. These helpers will eventually be deprecated once existing tests has been updated. +- **Do not use** using `nextTick()` helper in tests. This helper use `setTimeout` underneath and add latency in the tests, especially on CI where a timeout (even of a few ms) can trigger a timeout error. - **Do not declare** `component.update()` inside `act()`. Each `act()` call should contain a chunk of actions that updates the internal state(s). The `component.update()` that re-renders the internal DOM needs to be called outside, before asserting against the updated DOM. @@ -274,14 +274,11 @@ expect(tableCellsValues).toEqual([ An object with the following methods: -##### `setInputValue(input, value, isAsync)` +##### `setInputValue(input, value)` Set the value of a form input. The input can either be a test subject (a string) or an Enzyme react wrapper. If you specify a test subject, you can provide a nested path to access it by separating the parent and child with a dot (e.g. `myForm.followerIndexName`). -`isAsync`: flag that will return a Promise that resolves on the next "tick". This is useful if updating the input triggers -an async operation (like a HTTP request) and we need it to resolve so the DOM gets updated (default: `false`). - ```js await form.setInputValue('myInput', 'some value', true); ``` diff --git a/packages/kbn-test/src/jest/utils/testbed/testbed.ts b/packages/kbn-test/src/jest/utils/testbed/testbed.ts index 240ec25a9c296..b10f331da10d6 100644 --- a/packages/kbn-test/src/jest/utils/testbed/testbed.ts +++ b/packages/kbn-test/src/jest/utils/testbed/testbed.ts @@ -157,52 +157,17 @@ export function registerTestBed( }); }; - const waitForFn: TestBed['waitForFn'] = async (predicate, errMessage) => { - const triggeredAt = Date.now(); - - const MAX_WAIT_TIME = 30000; - const WAIT_INTERVAL = 50; - - const process = async (): Promise => { - const isOK = await predicate(); - - if (isOK) { - // Great! nothing else to do here. - return; - } - - const timeElapsed = Date.now() - triggeredAt; - if (timeElapsed > MAX_WAIT_TIME) { - throw new Error(errMessage); - } - - return new Promise((resolve) => setTimeout(resolve, WAIT_INTERVAL)).then(() => { - component.update(); - return process(); - }); - }; - - return process(); - }; - - const waitFor: TestBed['waitFor'] = (testSubject: T, count = 1) => { - return waitForFn( - () => Promise.resolve(exists(testSubject, count)), - `I waited patiently for the "${testSubject}" test subject to appear with no luck. It is nowhere to be found!` - ); - }; - /** * ---------------------------------------------------------------- * Forms * ---------------------------------------------------------------- */ - const setInputValue: TestBed['form']['setInputValue'] = ( - input, - value, - isAsync = false - ) => { + const setInputValue: TestBed['form']['setInputValue'] = function (input, value) { + if (arguments.length === 3) { + throw new Error(`Passing the "isAsync" arg is not supported anymore.`); + } + const formInput = typeof input === 'string' ? find(input) : input; if (!formInput.length) { @@ -210,11 +175,6 @@ export function registerTestBed( } formInput.simulate('change', { target: { value } }); component.update(); - - if (!isAsync) { - return; - } - return new Promise((resolve) => setTimeout(resolve)); }; const setSelectValue: TestBed['form']['setSelectValue'] = ( @@ -334,8 +294,6 @@ export function registerTestBed( exists, find, setProps, - waitFor, - waitForFn, table: { getMetaData, }, diff --git a/packages/kbn-test/src/jest/utils/testbed/types.ts b/packages/kbn-test/src/jest/utils/testbed/types.ts index 121b848e51b51..924eaa2f81b15 100644 --- a/packages/kbn-test/src/jest/utils/testbed/types.ts +++ b/packages/kbn-test/src/jest/utils/testbed/types.ts @@ -61,31 +61,14 @@ export interface TestBed { * @param updatedProps The updated prop object */ setProps: (updatedProps: any) => void; - /** - * Helper to wait until an element appears in the DOM as hooks updates cycles are tricky. - * Useful when loading a component that fetches a resource from the server - * and we need to wait for the data to be fetched (and bypass any "loading" state). - */ - waitFor: (testSubject: T, count?: number) => Promise; - waitForFn: (predicate: () => Promise, errMessage: string) => Promise; form: { /** * Set the value of a form text input. * - * In some cases, changing an input value triggers an HTTP request to validate - * the field. Even if we return immediately the response on the mock server we - * still need to wait until the next tick before the DOM updates. - * Setting isAsync to "true" takes care of that. - * * @param input The form input. Can either be a data-test-subj or a reactWrapper (can be a nested path. e.g. "myForm.myInput"). * @param value The value to set - * @param isAsync If set to true will return a Promise that resolves on the next "tick" */ - setInputValue: ( - input: T | ReactWrapper, - value: string, - isAsync?: boolean - ) => Promise | void; + setInputValue: (input: T | ReactWrapper, value: string) => void; /** * Set the value of a or a mocked * For the you need to mock it like this diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js index 700a8cb38a392..cf490f173bff0 100644 --- a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { act } from 'react-dom/test-utils'; import { API_BASE_PATH } from '../../../common/constants'; import { FollowerIndexForm } from '../../app/components/follower_index_form/follower_index_form'; @@ -98,18 +99,20 @@ describe('Edit follower index', () => { httpRequestsMockHelpers.setLoadRemoteClustersResponse(remoteClusters); httpRequestsMockHelpers.setGetFollowerIndexResponse(FOLLOWER_INDEX_EDIT); - testBed = await setup(); - await testBed.waitFor('followerIndexForm'); + await act(async () => { + testBed = await setup(); + }); + + testBed.component.update(); }); test('is consumed correctly', async () => { - const { actions, form, component, find, waitFor } = testBed; + const { actions, form, component, find } = testBed; form.setInputValue('maxRetryDelayInput', '10s'); actions.clickSaveForm(); component.update(); // The modal to confirm the update opens - await waitFor('confirmModalTitleText'); find('confirmModalConfirmButton').simulate('click'); await nextTick(); // Make sure the Request went through diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js index 9f2e44e64ca33..97602238dc5ee 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js @@ -114,7 +114,7 @@ export class JobCreateUi extends Component { startJobAfterCreation: false, }; - this.lastIndexPatternValidationTime = 0; + this.lastIndexPatternValidationIdx = 0; } componentDidMount() { @@ -159,7 +159,7 @@ export class JobCreateUi extends Component { requestIndexPatternValidation = debounce((resetDefaults = true) => { const indexPattern = this.getIndexPattern(); - const lastIndexPatternValidationTime = (this.lastIndexPatternValidationTime = Date.now()); + const lastIndexPatternValidationIdx = ++this.lastIndexPatternValidationIdx; validateIndexPattern(indexPattern) .then((response) => { // We don't need to do anything if this component has been unmounted. @@ -168,7 +168,7 @@ export class JobCreateUi extends Component { } // Only re-request if the index pattern changed. - if (lastIndexPatternValidationTime !== this.lastIndexPatternValidationTime) { + if (lastIndexPatternValidationIdx !== this.lastIndexPatternValidationIdx) { return; } @@ -291,7 +291,7 @@ export class JobCreateUi extends Component { } // Ignore all responses except that to the most recent request. - if (lastIndexPatternValidationTime !== this.lastIndexPatternValidationTime) { + if (lastIndexPatternValidationIdx !== this.lastIndexPatternValidationIdx) { return; } diff --git a/x-pack/plugins/rollup/public/test/client_integration/helpers/index.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/index.js index 191b44cd46d80..ef5a191b994c6 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/helpers/index.js +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/index.js @@ -5,13 +5,13 @@ * 2.0. */ +export { mockHttpRequest } from './setup_environment'; + import { setup as jobCreateSetup } from './job_create.helpers'; import { setup as jobListSetup } from './job_list.helpers'; import { setup as jobCloneSetup } from './job_clone.helpers'; -export { nextTick, getRandomString, findTestSubject } from '@kbn/test/jest'; - -export { mockHttpRequest } from './setup_environment'; +export { getRandomString, findTestSubject } from '@kbn/test/jest'; export { wrapComponent } from './setup_context'; diff --git a/x-pack/plugins/rollup/public/test/client_integration/helpers/jest.mocks.tsx b/x-pack/plugins/rollup/public/test/client_integration/helpers/jest.mocks.tsx new file mode 100644 index 0000000000000..5e5c8bb1f071d --- /dev/null +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/jest.mocks.tsx @@ -0,0 +1,20 @@ +/* + * 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. + */ + +jest.mock('lodash', () => ({ + ...jest.requireActual('lodash'), + debounce: (fn: () => unknown) => fn, +})); + +jest.mock('../../../crud_app/services/documentation_links', () => { + const coreMocks = jest.requireActual('../../../../../../../src/core/public/mocks'); + + return { + init: jest.fn(), + documentationLinks: coreMocks.docLinksServiceMock.createStartContract().links, + }; +}); diff --git a/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js index 9bbfb405bce22..36550d904fa39 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js @@ -5,6 +5,8 @@ * 2.0. */ +import { act } from 'react-dom/test-utils'; + import { registerTestBed } from '@kbn/test/jest'; import { rollupJobsStore } from '../../../crud_app/store'; import { JobCreate } from '../../../crud_app/sections'; @@ -22,7 +24,9 @@ export const setup = (props) => { // User actions const clickNextStep = () => { const button = testBed.find('rollupJobNextButton'); - button.simulate('click'); + act(() => { + button.simulate('click'); + }); component.update(); }; @@ -34,7 +38,9 @@ export const setup = (props) => { const clickSave = () => { const button = testBed.find('rollupJobSaveButton'); - button.simulate('click'); + act(() => { + button.simulate('click'); + }); component.update(); }; @@ -42,23 +48,33 @@ export const setup = (props) => { const fillFormFields = async (step) => { switch (step) { case 'logistics': - form.setInputValue('rollupJobName', JOB_TO_CREATE.id); - await form.setInputValue('rollupIndexPattern', JOB_TO_CREATE.indexPattern, true); - form.setInputValue('rollupIndexName', JOB_TO_CREATE.rollupIndex); + act(() => { + form.setInputValue('rollupJobName', JOB_TO_CREATE.id); + }); + act(() => { + form.setInputValue('rollupIndexPattern', JOB_TO_CREATE.indexPattern); + }); + act(() => { + form.setInputValue('rollupIndexName', JOB_TO_CREATE.rollupIndex); + }); break; case 'date-histogram': - form.setInputValue('rollupJobInterval', JOB_TO_CREATE.interval); + act(() => { + form.setInputValue('rollupJobInterval', JOB_TO_CREATE.interval); + }); break; default: return; } + + component.update(); }; // Navigation const goToStep = async (targetStep) => { const stepHandlers = { - 1: () => fillFormFields('logistics'), - 2: () => fillFormFields('date-histogram'), + 1: async () => await fillFormFields('logistics'), + 2: async () => await fillFormFields('date-histogram'), }; let currentStep = 1; diff --git a/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts b/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts index 805621257d73e..53e8630cfab8b 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import './jest.mocks'; interface RequestMocks { jobs?: object; diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js index 40c26baa76441..0b314d9174d0d 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js @@ -5,16 +5,13 @@ * 2.0. */ +import { mockHttpRequest, pageHelpers } from './helpers'; + +import { act } from 'react-dom/test-utils'; import { setHttp, init as initDocumentation } from '../../crud_app/services'; -import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); - const { setup } = pageHelpers.jobClone; const { jobs: [{ config: jobConfig }], @@ -29,11 +26,16 @@ describe('Cloning a rollup job through create job wizard', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { mockHttpRequest(startMock.http, { indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK }); @@ -149,9 +151,10 @@ describe('Cloning a rollup job through create job wizard', () => { // Changing the index pattern value after cloning a rollup job should update a number of values. // On each view of the set up wizard we check for the expected state after this change. - form.setInputValue('rollupIndexPattern', 'test'); - // Fires off a network request. - await nextTick(); + + await act(async () => { + form.setInputValue('rollupIndexPattern', 'test'); + }); const { groups: { date_histogram: dateHistogram }, diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js index 88c72140bcdda..dda79395dd4a7 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js @@ -5,17 +5,12 @@ * 2.0. */ -import moment from 'moment-timezone'; +import { mockHttpRequest, pageHelpers } from './helpers'; +import moment from 'moment-timezone'; import { setHttp, init as initDocumentation } from '../../crud_app/services'; -import { mockHttpRequest, pageHelpers } from './helpers'; import { docLinksServiceMock, coreMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); - const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 2: Date histogram', () => { @@ -28,10 +23,16 @@ describe('Create Rollup Job, step 2: Date histogram', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js index 7d9d714ba8d2d..50615ed00a680 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js @@ -5,14 +5,10 @@ * 2.0. */ -import { setHttp, init as initDocumentation } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; -import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); +import { setHttp, init as initDocumentation } from '../../crud_app/services'; +import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; const { setup } = pageHelpers.jobCreate; @@ -27,11 +23,16 @@ describe('Create Rollup Job, step 4: Histogram', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js index 792cb4434e551..667e3b569518a 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js @@ -5,15 +5,12 @@ * 2.0. */ -import { indexPatterns } from '../../../../../../src/plugins/data/public'; -import { setHttp, init as initDocumentation } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; -import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); +import { act } from 'react-dom/test-utils'; +import { indexPatterns } from '../../../../../../src/plugins/data/public'; +import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; +import { setHttp, init as initDocumentation } from '../../crud_app/services'; const { setup } = pageHelpers.jobCreate; @@ -26,11 +23,16 @@ describe('Create Rollup Job, step 1: Logistics', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); @@ -87,21 +89,27 @@ describe('Create Rollup Job, step 1: Logistics', () => { }); it('should not allow spaces', async () => { - await form.setInputValue('rollupIndexPattern', 'with space', true); + await act(async () => { + form.setInputValue('rollupIndexPattern', 'with space'); + }); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain('Remove the spaces from your index pattern.'); }); it('should not allow an unknown index pattern', async () => { mockHttpRequest(startMock.http, { indxPatternVldtResp: { doesMatchIndices: false } }); - await form.setInputValue('rollupIndexPattern', 'unknown', true); + await act(async () => { + form.setInputValue('rollupIndexPattern', 'unknown'); + }); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain("Index pattern doesn't match any indices."); }); it('should not allow an index pattern without time fields', async () => { mockHttpRequest(startMock.http, { indxPatternVldtResp: { dateFields: [] } }); - await form.setInputValue('rollupIndexPattern', 'abc', true); + await act(async () => { + form.setInputValue('rollupIndexPattern', 'abc'); + }); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain( 'Index pattern must match indices that contain time fields.' @@ -112,14 +120,21 @@ describe('Create Rollup Job, step 1: Logistics', () => { mockHttpRequest(startMock.http, { indxPatternVldtResp: { doesMatchRollupIndices: true }, }); - await form.setInputValue('rollupIndexPattern', 'abc', true); + await act(async () => { + form.setInputValue('rollupIndexPattern', 'abc'); + }); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain('Index pattern must not match rollup indices.'); }); it('should not be the same as the rollup index name', async () => { - await form.setInputValue('rollupIndexPattern', 'abc', true); - await form.setInputValue('rollupIndexName', 'abc', true); + await act(async () => { + form.setInputValue('rollupIndexPattern', 'abc'); + }); + + await act(async () => { + form.setInputValue('rollupIndexName', 'abc'); + }); actions.clickNextStep(); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js index 35861586b68f3..659bcbce1c8eb 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js @@ -5,14 +5,10 @@ * 2.0. */ -import { setHttp, init as initDocumentation } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; -import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); +import { setHttp, init as initDocumentation } from '../../crud_app/services'; +import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; const { setup } = pageHelpers.jobCreate; @@ -27,11 +23,16 @@ describe('Create Rollup Job, step 5: Metrics', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js index dd102ce88ae5b..bbd2e72c6eee1 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js @@ -6,15 +6,12 @@ */ import { pageHelpers, mockHttpRequest } from './helpers'; + +import { act } from 'react-dom/test-utils'; import { first } from 'lodash'; +import { coreMock } from '../../../../../../src/core/public/mocks'; import { setHttp } from '../../crud_app/services'; import { JOBS } from './helpers/constants'; -import { coreMock } from '../../../../../../src/core/public/mocks'; - -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); jest.mock('../../kibana_services', () => { const services = jest.requireActual('../../kibana_services'); @@ -26,9 +23,7 @@ jest.mock('../../kibana_services', () => { const { setup } = pageHelpers.jobCreate; -// FLAKY: https://github.com/elastic/kibana/issues/69783 -// FLAKY: https://github.com/elastic/kibana/issues/70043 -describe.skip('Create Rollup Job, step 6: Review', () => { +describe('Create Rollup Job, step 6: Review', () => { let find; let exists; let actions; @@ -37,16 +32,23 @@ describe.skip('Create Rollup Job, step 6: Review', () => { let table; let form; let startMock; + let component; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); - ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form } = setup()); + ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form, component } = + setup()); }); afterEach(() => { @@ -83,12 +85,18 @@ describe.skip('Create Rollup Job, step 6: Review', () => { describe('tabs', () => { const getTabsText = () => find('stepReviewTab').map((tab) => tab.text()); const selectFirstField = (step) => { - find('rollupJobShowFieldChooserButton').simulate('click'); + act(() => { + find('rollupJobShowFieldChooserButton').simulate('click'); + }); + component.update(); - // Select the first term field - table - .getMetaData(`rollupJob${step}FieldChooser-table`) - .rows[0].reactWrapper.simulate('click'); + act(() => { + // Select the first term field + table + .getMetaData(`rollupJob${step}FieldChooser-table`) + .rows[0].reactWrapper.simulate('click'); + }); + component.update(); }; it('should have a "Summary" & "Request" tabs to review the Job', async () => { @@ -105,6 +113,7 @@ describe.skip('Create Rollup Job, step 6: Review', () => { actions.clickNextStep(); // go to step 5 actions.clickNextStep(); // go to review + expect(exists('rollupJobCreateReviewTitle')); // Make sure we are on the review step expect(getTabsText()).toEqual(['Summary', 'Terms', 'Request']); }); @@ -153,9 +162,10 @@ describe.skip('Create Rollup Job, step 6: Review', () => { expect(startMock.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); - // Given the following anti-jitter sleep x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js - // we add a longer sleep here :( - await new Promise((res) => setTimeout(res, 750)); + + // There is a 500 timeout before receiving the response. + // To be investigated, this is the only app requiring a timeout to avoid a "weird flicker"; + jest.advanceTimersByTime(500); expect(startMock.http.put).toHaveBeenCalledWith(jobCreateApiPath, expect.anything()); // It has been called! expect(startMock.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // It has still not been called! @@ -170,18 +180,33 @@ describe.skip('Create Rollup Job, step 6: Review', () => { await goToStep(6); - find('rollupJobToggleJobStartAfterCreation').simulate('change', { - target: { checked: true }, + act(() => { + find('rollupJobToggleJobStartAfterCreation').simulate('change', { + target: { checked: true }, + }); }); + component.update(); expect(startMock.http.post).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); - // Given the following anti-jitter sleep x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js - // we add a longer sleep here :( - await new Promise((res) => setTimeout(res, 750)); - expect(startMock.http.post).toHaveBeenCalledWith(jobStartApiPath, expect.anything()); // It has been called! + // There is a 500 timeout before receiving the response. + // To be investigated, this is the only app requiring a timeout to avoid a "weird flicker"; + await act(async () => { + jest.advanceTimersByTime(500); + }); + + // We then have a createNoticeableDelay() that we need to account for. + act(() => { + jest.advanceTimersByTime(300); + }); + + expect(startMock.http.post).toHaveBeenCalledWith(jobStartApiPath, { + body: JSON.stringify({ + jobIds: ['test-job'], + }), + }); }); }); }); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js index d27eab75b7758..b84aad9bf9aa4 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js @@ -5,14 +5,10 @@ * 2.0. */ -import { setHttp, init as initDocumentation } from '../../crud_app/services'; import { pageHelpers, mockHttpRequest } from './helpers'; -import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); +import { setHttp, init as initDocumentation } from '../../crud_app/services'; +import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; const { setup } = pageHelpers.jobCreate; @@ -26,11 +22,16 @@ describe('Create Rollup Job, step 3: Terms', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(() => { // Set "default" mock responses by not providing any arguments mockHttpRequest(startMock.http); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js index 46ddfbcfc2de5..18ffce77b9656 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js @@ -5,8 +5,10 @@ * 2.0. */ +import { mockHttpRequest, pageHelpers } from './helpers'; + +import { act } from 'react-dom/test-utils'; import { getRouter, setHttp, init as initDocumentation } from '../../crud_app/services'; -import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOBS } from './helpers/constants'; import { coreMock, docLinksServiceMock } from '../../../../../../src/core/public/mocks'; @@ -36,17 +38,23 @@ describe('', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); initDocumentation(docLinksServiceMock.createStartContract()); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(async () => { mockHttpRequest(startMock.http, { jobs: JOBS }); - ({ component, exists, table } = setup()); + await act(async () => { + ({ component, exists, table } = setup()); + }); - await nextTick(); // We need to wait next tick for the mock server response to comes in component.update(); }); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js index 3987e18538e57..1e24a4f92666c 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js @@ -5,17 +5,14 @@ * 2.0. */ -import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; +import { mockHttpRequest, pageHelpers } from './helpers'; + +import { act } from 'react-dom/test-utils'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; import { getRouter } from '../../crud_app/services/routing'; import { setHttp } from '../../crud_app/services'; import { coreMock } from '../../../../../../src/core/public/mocks'; -jest.mock('lodash', () => ({ - ...jest.requireActual('lodash'), - debounce: (fn) => fn, -})); - jest.mock('../../kibana_services', () => { const services = jest.requireActual('../../kibana_services'); return { @@ -24,15 +21,6 @@ jest.mock('../../kibana_services', () => { }; }); -jest.mock('../../crud_app/services/documentation_links', () => { - const coreMocks = jest.requireActual('../../../../../../src/core/public/mocks'); - - return { - init: jest.fn(), - documentationLinks: coreMocks.docLinksServiceMock.createStartContract().links, - }; -}); - const { setup } = pageHelpers.jobList; describe('Smoke test cloning an existing rollup job from job list', () => { @@ -43,19 +31,25 @@ describe('Smoke test cloning an existing rollup job from job list', () => { let startMock; beforeAll(() => { + jest.useFakeTimers(); startMock = coreMock.createStart(); setHttp(startMock.http); }); + afterAll(() => { + jest.useRealTimers(); + }); + beforeEach(async () => { mockHttpRequest(startMock.http, { jobs: JOB_TO_CLONE, indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK, }); - ({ find, exists, table, component } = setup()); + await act(async () => { + ({ find, exists, table, component } = setup()); + }); - await nextTick(); // We need to wait next tick for the mock server response to comes in component.update(); });