'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});
exports.runAndTransformResultsToJestFormat = exports.initialize = void 0;

var _expect = require('expect');

var _jestMessageUtil = require('jest-message-util');

var _jestSnapshot = require('jest-snapshot');

var _throat = _interopRequireDefault(require('throat'));

var _state = require('../state');

var _utils = require('../utils');

var _run = _interopRequireDefault(require('../run'));

var _ = _interopRequireDefault(require('..'));

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : {default: obj};
}

var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
var Promise = global[Symbol.for('jest-native-promise')] || global.Promise;

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function() {
    var self = this,
      args = arguments;
    return new Promise(function(resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
      }
      _next(undefined);
    });
  };
}

const initialize = ({
  config,
  environment,
  getPrettier,
  getBabelTraverse,
  globalConfig,
  localRequire,
  parentProcess,
  testPath
}) => {
  if (globalConfig.testTimeout) {
    (0, _state.getState)().testTimeout = globalConfig.testTimeout;
  }

  const mutex = (0, _throat.default)(globalConfig.maxConcurrency);
  const nodeGlobal = global;
  Object.assign(nodeGlobal, _.default);
  nodeGlobal.xit = nodeGlobal.it.skip;
  nodeGlobal.xtest = nodeGlobal.it.skip;
  nodeGlobal.xdescribe = nodeGlobal.describe.skip;
  nodeGlobal.fit = nodeGlobal.it.only;
  nodeGlobal.fdescribe = nodeGlobal.describe.only;

  nodeGlobal.test.concurrent = (test => {
    const concurrent = (testName, testFn, timeout) => {
      // For concurrent tests we first run the function that returns promise, and then register a
      // nomral test that will be waiting on the returned promise (when we start the test, the promise
      // will already be in the process of execution).
      // Unfortunately at this stage there's no way to know if there are any `.only` tests in the suite
      // that will result in this test to be skipped, so we'll be executing the promise function anyway,
      // even if it ends up being skipped.
      const promise = mutex(() => testFn());
      nodeGlobal.test(testName, () => promise, timeout);
    };

    concurrent.only = (testName, testFn, timeout) => {
      const promise = mutex(() => testFn()); // eslint-disable-next-line jest/no-focused-tests

      test.only(testName, () => promise, timeout);
    };

    concurrent.skip = test.skip;
    return concurrent;
  })(nodeGlobal.test);

  (0, _state.addEventHandler)(eventHandler);

  if (environment.handleTestEvent) {
    (0, _state.addEventHandler)(environment.handleTestEvent.bind(environment));
  }

  (0, _state.dispatch)({
    name: 'setup',
    parentProcess,
    testNamePattern: globalConfig.testNamePattern
  });

  if (config.testLocationInResults) {
    (0, _state.dispatch)({
      name: 'include_test_location_in_result'
    });
  } // Jest tests snapshotSerializers in order preceding built-in serializers.
  // Therefore, add in reverse because the last added is the first tested.

  config.snapshotSerializers
    .concat()
    .reverse()
    .forEach(path => {
      (0, _jestSnapshot.addSerializer)(localRequire(path));
    });
  const expand = globalConfig.expand,
    updateSnapshot = globalConfig.updateSnapshot;
  const snapshotResolver = (0, _jestSnapshot.buildSnapshotResolver)(config);
  const snapshotPath = snapshotResolver.resolveSnapshotPath(testPath);
  const snapshotState = new _jestSnapshot.SnapshotState(snapshotPath, {
    expand,
    getBabelTraverse,
    getPrettier,
    updateSnapshot
  });
  (0, _expect.setState)({
    snapshotState,
    testPath
  });
  (0, _state.addEventHandler)(handleSnapshotStateAfterRetry(snapshotState)); // Return it back to the outer scope (test runner outside the VM).

  return {
    globals: _.default,
    snapshotState
  };
};

exports.initialize = initialize;

const runAndTransformResultsToJestFormat =
  /*#__PURE__*/
  (function() {
    var _ref = _asyncToGenerator(function*({config, globalConfig, testPath}) {
      const runResult = yield (0, _run.default)();
      let numFailingTests = 0;
      let numPassingTests = 0;
      let numPendingTests = 0;
      let numTodoTests = 0;
      const assertionResults = runResult.testResults.map(testResult => {
        let status;

        if (testResult.status === 'skip') {
          status = 'pending';
          numPendingTests += 1;
        } else if (testResult.status === 'todo') {
          status = 'todo';
          numTodoTests += 1;
        } else if (testResult.errors.length) {
          status = 'failed';
          numFailingTests += 1;
        } else {
          status = 'passed';
          numPassingTests += 1;
        }

        const ancestorTitles = testResult.testPath.filter(
          name => name !== _state.ROOT_DESCRIBE_BLOCK_NAME
        );
        const title = ancestorTitles.pop();
        return {
          ancestorTitles,
          duration: testResult.duration,
          failureMessages: testResult.errors,
          fullName: title
            ? ancestorTitles.concat(title).join(' ')
            : ancestorTitles.join(' '),
          invocations: testResult.invocations,
          location: testResult.location,
          numPassingAsserts: 0,
          status,
          title: testResult.testPath[testResult.testPath.length - 1]
        };
      });
      let failureMessage = (0, _jestMessageUtil.formatResultsErrors)(
        assertionResults,
        config,
        globalConfig,
        testPath
      );
      let testExecError;

      if (runResult.unhandledErrors.length) {
        testExecError = {
          message: '',
          stack: runResult.unhandledErrors.join('\n')
        };
        failureMessage =
          (failureMessage || '') +
          '\n\n' +
          runResult.unhandledErrors
            .map(err =>
              (0, _jestMessageUtil.formatExecError)(err, config, globalConfig)
            )
            .join('\n');
      }

      (0, _state.dispatch)({
        name: 'teardown'
      });
      return {
        console: undefined,
        displayName: config.displayName,
        failureMessage,
        leaks: false,
        // That's legacy code, just adding it so Flow is happy.
        numFailingTests,
        numPassingTests,
        numPendingTests,
        numTodoTests,
        openHandles: [],
        perfStats: {
          // populated outside
          end: 0,
          start: 0
        },
        skipped: false,
        snapshot: {
          added: 0,
          fileDeleted: false,
          matched: 0,
          unchecked: 0,
          uncheckedKeys: [],
          unmatched: 0,
          updated: 0
        },
        sourceMaps: {},
        testExecError,
        testFilePath: testPath,
        testResults: assertionResults
      };
    });

    return function runAndTransformResultsToJestFormat(_x) {
      return _ref.apply(this, arguments);
    };
  })();

exports.runAndTransformResultsToJestFormat = runAndTransformResultsToJestFormat;

const handleSnapshotStateAfterRetry = snapshotState => event => {
  switch (event.name) {
    case 'test_retry': {
      // Clear any snapshot data that occurred in previous test run
      snapshotState.clear();
    }
  }
};

const eventHandler = event => {
  switch (event.name) {
    case 'test_start': {
      (0, _expect.setState)({
        currentTestName: (0, _utils.getTestID)(event.test)
      });
      break;
    }

    case 'test_done': {
      _addSuppressedErrors(event.test);

      _addExpectedAssertionErrors(event.test);

      break;
    }
  }
};

const _addExpectedAssertionErrors = test => {
  const failures = (0, _expect.extractExpectedAssertionsErrors)();
  const errors = failures.map(failure => failure.error);
  test.errors = test.errors.concat(errors);
}; // Get suppressed errors from ``jest-matchers`` that weren't throw during
// test execution and add them to the test result, potentially failing
// a passing test.

const _addSuppressedErrors = test => {
  const _getState = (0, _expect.getState)(),
    suppressedErrors = _getState.suppressedErrors;

  (0, _expect.setState)({
    suppressedErrors: []
  });

  if (suppressedErrors.length) {
    test.errors = test.errors.concat(suppressedErrors);
  }
};
