"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSpyMiddleware = void 0; /* * 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. */ /** * Utilities for testing Redux middleware */ /** * Creates a new instance of middleware action helpers * Note: in most cases (testing concern specific middleware) this function should be given * the state type definition, else, the global state will be used. * * @example * // Use in Policy List middleware testing * const middlewareSpyUtils = createSpyMiddleware(); * store = createStore( * policyListReducer, * applyMiddleware( * policyListMiddlewareFactory(fakeCoreStart, depsStart), * middlewareSpyUtils.actionSpyMiddleware * ) * ); * // Reference `dispatchSpy` ONLY after creating the store that includes `actionSpyMiddleware` * const { waitForAction, dispatchSpy } = middlewareSpyUtils; * // * // later in test * // * it('...', async () => { * //... * await waitForAction('serverReturnedPolicyListData'); * // do assertions * // or check how action was called * expect(dispatchSpy.calls.length).toBe(2) * }); */ const createSpyMiddleware = () => { const watchers = new Set(); let spyDispatch; return { waitForAction: async (actionType, options = {}) => { // Error is defined here so that we get a better stack trace that points to the test from where it was used const err = new Error(`Timeout! Action '${actionType}' was not dispatched within the allocated time`); return new Promise((resolve, reject) => { const watch = action => { if (action.type === actionType) { if (options.validate && !options.validate(action)) { return; } watchers.delete(watch); clearTimeout(timeout); resolve(action); } }; // We timeout before jest's default 5s, so that a better error stack is returned const timeout = setTimeout(() => { watchers.delete(watch); reject(err); // TODO: is there a way we can grab the current timeout value from jest? // For now, this is using the default value (5000ms) - 500. }, 4500); watchers.add(watch); }); }, get dispatchSpy() { if (!spyDispatch) { throw new Error('Spy Middleware has not been initialized. Access this property only after using `actionSpyMiddleware` in a redux store'); } return spyDispatch.mock; }, actionSpyMiddleware: () => { return next => { spyDispatch = jest.fn(action => { next(action); // loop through the list of watcher (if any) and call them with this action for (const watch of watchers) { watch(action); } return action; }); return spyDispatch; }; } }; }; exports.createSpyMiddleware = createSpyMiddleware;