'use strict';

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

var _jestMatcherUtils = require('jest-matcher-utils');

var _chalk = _interopRequireDefault(require('chalk'));

var _prettyFormat = _interopRequireDefault(require('pretty-format'));

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

var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;

function _slicedToArray(arr, i) {
  return (
    _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
  );
}

function _nonIterableRest() {
  throw new TypeError('Invalid attempt to destructure non-iterable instance');
}

function _iterableToArrayLimit(arr, i) {
  var _arr = [];
  var _n = true;
  var _d = false;
  var _e = undefined;
  try {
    for (
      var _i = arr[Symbol.iterator](), _s;
      !(_n = (_s = _i.next()).done);
      _n = true
    ) {
      _arr.push(_s.value);
      if (i && _arr.length === i) break;
    }
  } catch (err) {
    _d = true;
    _e = err;
  } finally {
    try {
      if (!_n && _i['return'] != null) _i['return']();
    } finally {
      if (_d) throw _e;
    }
  }
  return _arr;
}

function _arrayWithHoles(arr) {
  if (Array.isArray(arr)) return arr;
}

const assertOperatorsMap = {
  '!=': 'notEqual',
  '!==': 'notStrictEqual',
  '==': 'equal',
  '===': 'strictEqual'
};
const humanReadableOperators = {
  deepEqual: 'to deeply equal',
  deepStrictEqual: 'to deeply and strictly equal',
  equal: 'to be equal',
  notDeepEqual: 'not to deeply equal',
  notDeepStrictEqual: 'not to deeply and strictly equal',
  notEqual: 'to not be equal',
  notStrictEqual: 'not be strictly equal',
  strictEqual: 'to strictly be equal'
};

const formatNodeAssertErrors = (event, state) => {
  switch (event.name) {
    case 'test_done': {
      event.test.errors = event.test.errors.map(errors => {
        let error;

        if (Array.isArray(errors)) {
          const _errors = _slicedToArray(errors, 2),
            originalError = _errors[0],
            asyncError = _errors[1];

          if (originalError == null) {
            error = asyncError;
          } else if (!originalError.stack) {
            error = asyncError;
            error.message = originalError.message
              ? originalError.message
              : `thrown: ${(0, _prettyFormat.default)(originalError, {
                  maxDepth: 3
                })}`;
          } else {
            error = originalError;
          }
        } else {
          error = errors;
        }

        return error.code === 'ERR_ASSERTION'
          ? {
              message: assertionErrorMessage(error, {
                expand: state.expand
              })
            }
          : errors;
      });
    }
  }
};

const getOperatorName = (operator, stack) => {
  if (typeof operator === 'string') {
    return assertOperatorsMap[operator] || operator;
  }

  if (stack.match('.doesNotThrow')) {
    return 'doesNotThrow';
  }

  if (stack.match('.throws')) {
    return 'throws';
  }

  return '';
};

const operatorMessage = operator => {
  const niceOperatorName = getOperatorName(operator, '');
  const humanReadableOperator = humanReadableOperators[niceOperatorName];
  return typeof operator === 'string'
    ? `${humanReadableOperator || niceOperatorName} to:\n`
    : '';
};

const assertThrowingMatcherHint = operatorName =>
  _chalk.default.dim('assert') +
  _chalk.default.dim('.' + operatorName + '(') +
  _chalk.default.red('function') +
  _chalk.default.dim(')');

const assertMatcherHint = (operator, operatorName) => {
  let message =
    _chalk.default.dim('assert') +
    _chalk.default.dim('.' + operatorName + '(') +
    _chalk.default.red('received') +
    _chalk.default.dim(', ') +
    _chalk.default.green('expected') +
    _chalk.default.dim(')');

  if (operator === '==') {
    message +=
      ' or ' +
      _chalk.default.dim('assert') +
      _chalk.default.dim('(') +
      _chalk.default.red('received') +
      _chalk.default.dim(') ');
  }

  return message;
};

function assertionErrorMessage(error, options) {
  const expected = error.expected,
    actual = error.actual,
    generatedMessage = error.generatedMessage,
    message = error.message,
    operator = error.operator,
    stack = error.stack;
  const diffString = (0, _jestMatcherUtils.diff)(expected, actual, options);
  const hasCustomMessage = !generatedMessage;
  const operatorName = getOperatorName(operator, stack);
  const trimmedStack = stack
    .replace(message, '')
    .replace(/AssertionError(.*)/g, '');

  if (operatorName === 'doesNotThrow') {
    return (
      assertThrowingMatcherHint(operatorName) +
      '\n\n' +
      _chalk.default.reset(`Expected the function not to throw an error.\n`) +
      _chalk.default.reset(`Instead, it threw:\n`) +
      `  ${(0, _jestMatcherUtils.printReceived)(actual)}` +
      _chalk.default.reset(
        hasCustomMessage ? '\n\nMessage:\n  ' + message : ''
      ) +
      trimmedStack
    );
  }

  if (operatorName === 'throws') {
    return (
      assertThrowingMatcherHint(operatorName) +
      '\n\n' +
      _chalk.default.reset(`Expected the function to throw an error.\n`) +
      _chalk.default.reset(`But it didn't throw anything.`) +
      _chalk.default.reset(
        hasCustomMessage ? '\n\nMessage:\n  ' + message : ''
      ) +
      trimmedStack
    );
  }

  return (
    assertMatcherHint(operator, operatorName) +
    '\n\n' +
    _chalk.default.reset(`Expected value ${operatorMessage(operator)}`) +
    `  ${(0, _jestMatcherUtils.printExpected)(expected)}\n` +
    _chalk.default.reset(`Received:\n`) +
    `  ${(0, _jestMatcherUtils.printReceived)(actual)}` +
    _chalk.default.reset(hasCustomMessage ? '\n\nMessage:\n  ' + message : '') +
    (diffString ? `\n\nDifference:\n\n${diffString}` : '') +
    trimmedStack
  );
}

var _default = formatNodeAssertErrors;
exports.default = _default;
