Chai: ожидая ошибки или не зависит от параметра

Я пытаюсь сделать текст функции, которая обрабатывает ошибки таким образом, что, если это допустимая ошибка, она бросается, но если это не так, то ничего не выбрасывается. Проблема в том, что я не могу настроить параметр при использовании:

expect(handleError).to.throw(Error);

Идеальным было бы использовать:

expect(handleError(validError)).to.throw(Error);

Есть ли способ достичь этой функциональности?

код функции:

function handleError (err) {
    if (err !== true) {
        switch (err) {
            case xxx:
            ...
        }
        throw "stop js execution";
    else {}
}

И код теста (не работает по назначению):

it("should stop Javascript execution if the parameter isnt \"true\"", function() {
    expect(handleError).to.be.a("function");
    expect(handleError(true)).to.not.throw(Error);
    expect(handleError("anything else")).to.throw(Error);
});

Ответ 1

Проблема в том, что вы вызываете handleError, а затем передаете ожидаемый результат. Если handleError бросает, тогда ожидание никогда не будет вызвано.

Вам нужно отложить вызов handleError до тех пор, пока не будет вызван ожидаемый вызов, чтобы ожидание могло видеть, что происходит при вызове функции. К счастью, это то, чего ожидают:

expect(function () { handleError(true); }).to.not.throw();
expect(function () { handleError("anything else") }).to.throw("stop js execution");

Если вы прочитали документацию для броска, вы увидите, что связанный с ней ожидаемый результат должен быть передан функцией.

Ответ 2

Сегодня я столкнулся с этой проблемой и выбрал другое решение, не упомянутое здесь: приложение с частичной функцией, использующее bind():

expect(handleError.bind(null, true)).to.not.throw();
expect(handleError.bind(null, "anything else")).to.throw("stop js execution");

Это может быть кратким, используя простой старый JavaScript, не требуя дополнительных функций, и вы даже можете указать значение this, если ваша функция будет зависеть от него.

Ответ 3

Обертка вызова функции в Лямбде, как рекомендовал Дэвид Норман, безусловно, является одним из хороших способов решения этой проблемы.

Вы можете добавить это в свои утилиты тестирования, хотя, если вы ищете более читаемое решение. Эта функция обертывает вашу функцию в объекте с помощью метода withArgs, который позволяет вам писать тот же оператор более читабельным способом. В идеале это будет встроено в Чай.

var calling = function(func) {
  return {
    withArgs: function(/* arg1, arg2, ... */) {
      var args = Array.prototype.slice.call(arguments);
      return function() {
        func.apply(null, args);
      };
    }
  };
};

Затем используйте его как:

expect(calling(handleError).withArgs(true)).to.not.throw();        
expect(calling(handleError).withArgs("anything else")).to.throw("stop js execution");

Он читается как английский!

Ответ 4

Я использую ES2015 с предустановкой babel stage-2, и если вы это сделаете, вы также можете использовать это.

Я принял решение @StephenM347 и немного изменил его, чтобы быть короче, еще более читаемым IMHO:

let expectCalling = func => ({ withArgs: (...args) => expect(() => func(...args)) });

Использование:

expectCalling(handleError).withArgs(true).to.not.throw();        
expectCalling(handleError).withArgs("anything else").to.throw("stop js execution");

Примечание: если вы хотите использовать одно и то же использование (и придерживайтесь использования expect() как есть):

    let calling = func => ({ withArgs: (...args) => () => func(...args) });