为什么Mocha/Chai不将babel自定义错误与常规自定义错误一样对待?

Why don't Mocha/Chai treat babel custom errors the same as regular custom errors?

本文关键字:自定义 错误 一样 Mocha Chai 不将 为什么 babel 常规      更新时间:2023-09-26

这适用于摩卡/Chai:

describe('Chai throw() with old-style custom errors', ()=> {
  // old way
  function ES5Error(message = 'todo', value) {
    this.name = 'ES5Error';
    this.message = message;
  }
  ES5Error.prototype = new Error();
  it('catches ES5Errors', ()=> {
    var err = new ES5Error('This is a bad function.');
    var fn = function () { throw err; }
    expect(fn).to.throw(ES5Error);
    expect(fn).to.throw(Error);
    expect(fn).to.throw(/bad function/);
    expect(fn).to.not.throw('good function');
    expect(fn).to.throw(ES5Error, /bad function/);
    expect(fn).to.throw(err);
  });
});

而基于类的方法没有:

describe('Chai throw() with new-style custom errors', ()=> {
  // New way
  class ExtendError extends Error {
    constructor(message = 'todo', value) {
      super(message);
      this.name = 'ExtendError';
      this.message = message;
    }
  }
  it('catches ExtendError', ()=> {
    var err = new ExtendError('This is a bad function.');
    var fn = function () { throw err; }
    expect(fn).to.throw(ExtendError);
    expect(fn).to.throw(Error);
    expect(fn).to.throw(/bad function/);
    expect(fn).to.not.throw('good function');
    expect(fn).to.throw(ExtendError, /bad function/);
    expect(fn).to.throw(err);
  });
});

我也在这里实现了相关的SO答案。虽然很有趣,但它仍然不适用于摩卡throws()。我基本上很高兴使用ES5风格错误,但我只是不确定实际问题是什么。当我为ExtendError编译代码时,我不能立即看到任何会绊倒expect子句的东西:

'use strict';
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var ExtendError = function (_Error) {
  _inherits(ExtendError, _Error);
  function ExtendError() {
    var message = arguments.length <= 0 || arguments[0] === undefined ? 'todo' : arguments[0];
    var value = arguments[1];
    _classCallCheck(this, ExtendError);
    var _this = _possibleConstructorReturn(this, _Error.call(this, message));
    _this.name = 'ExtendError';
    _this.message = message;
    return _this;
  }
  return ExtendError;
}(Error);

摩卡/Chai的问题是什么?

问题不在Chai。如果你用ES6实现err instanceof ExtendError,你会得到false !

你运行的ExtendError的ES5和ES6实现实际上是不同的。

  • 在ES5端,调用Error,但对返回值不做任何操作。

  • 在ES6端,super(...)调用被转换为

    var _this = _possibleConstructorReturn(this, _Error.call(this, message));`
    

    ,然后_this代替原来ES6代码中的thisError的返回值是在ES6代码中使用的,这是一切都变得糟糕的地方,因为你从构造函数返回的对象是Error对象,而不是ExtendError对象。

我将继续使用ES5语法从Error派生。我尝试了一些方法来保持ES6的语法,但最终它们都是混合的,或者做了非常糟糕的事情。我想到的最不令人反感的方法是:

class ExtendError {
    constructor(message = 'todo', value) {
        Error.call(this, message);
        this.name = 'ExtendError';
        this.message = message;
    }
}
ExtendError.prototype = Object.create(Error.prototype);
ExtendError.prototype.constructor = ExtendError;

它没有充分利用ES6 class糖…