'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});
exports.unhandledRejectionHandler = void 0;
var _utils = require('./utils');
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
var Promise =
  globalThis[Symbol.for('jest-native-promise')] || globalThis.Promise;
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
// Global values can be overwritten by mocks or tests. We'll capture
// the original values in the variables before we require any files.
const {setTimeout} = globalThis;
const untilNextEventLoopTurn = async () => {
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
};
const unhandledRejectionHandler = runtime => {
  return async (event, state) => {
    if (event.name === 'hook_start') {
      runtime.enterTestCode();
    } else if (event.name === 'hook_success' || event.name === 'hook_failure') {
      runtime.leaveTestCode();

      // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events
      await untilNextEventLoopTurn();
      const {test, describeBlock, hook} = event;
      const {asyncError, type} = hook;
      if (type === 'beforeAll') {
        (0, _utils.invariant)(describeBlock, 'always present for `*All` hooks');
        for (const error of state.unhandledRejectionErrorByPromise.values()) {
          (0, _utils.addErrorToEachTestUnderDescribe)(
            describeBlock,
            error,
            asyncError
          );
        }
      } else if (type === 'afterAll') {
        // Attaching `afterAll` errors to each test makes execution flow
        // too complicated, so we'll consider them to be global.
        for (const error of state.unhandledRejectionErrorByPromise.values()) {
          state.unhandledErrors.push([error, asyncError]);
        }
      } else {
        (0, _utils.invariant)(test, 'always present for `*Each` hooks');
        for (const error of test.unhandledRejectionErrorByPromise.values()) {
          test.errors.push([error, asyncError]);
        }
      }
    } else if (event.name === 'test_fn_start') {
      runtime.enterTestCode();
    } else if (
      event.name === 'test_fn_success' ||
      event.name === 'test_fn_failure'
    ) {
      runtime.leaveTestCode();

      // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events
      await untilNextEventLoopTurn();
      const {test} = event;
      (0, _utils.invariant)(test, 'always present for `*Each` hooks');
      for (const error of test.unhandledRejectionErrorByPromise.values()) {
        test.errors.push([error, event.test.asyncError]);
      }
    } else if (event.name === 'teardown') {
      // We need to give event loop the time to actually execute `rejectionHandled`, `uncaughtException` or `unhandledRejection` events
      await untilNextEventLoopTurn();
      state.unhandledErrors.push(
        ...state.unhandledRejectionErrorByPromise.values()
      );
    }
  };
};
exports.unhandledRejectionHandler = unhandledRejectionHandler;
