Тестирование promise с помощью mocha

В своём «домашнем» проекте для тестирования кода я использую фреймворк mocha. В тестах все утверждения проверяются библиотекой should.js, которая выбрасывает соответствующие исключения, отлавливаемые mocha.

При тестировании promise-объектов возникла проблема из-за того, что все исключения, выброшенные внутри резолвера, автоматически отлавливаются этим объектом. В результате тесты падают по таймауту без дополнительных разъяснений.

describe("Listener", function () {
    it("should reject data", function (done) {
        var connection = new MockStream();
        var promise = listener(connection);
        connection.write("foo bar baz");
        connection.end();

        promise.then(
            function (obj) {
                done(new Error("unexpected fulfill"));
            },
            function (obj) {
                obj.should.be.a("object").and
                  .have.property("valid", false);
                done();
            }
        );

    });
});

В данном тесте я ожидаю, что promise будет отклонён с объектом, в качестве параметра, имеющим поле valid равное значению false. Если утверждение не будет соответствовать действительности, то тест не завершится естественным образом (т.е. вызов done(), который идет за утверждением, не будет выполнен).

Благо, каждый вызов метода then() возвращает другой promise-объект. Он выполняет или отклоняется так же как и его «предок», но в параметры колбеков будут передаваться совершенно другие значения. Этим можно воспользоваться для корректного завершения теста.

describe("Listener", function () {
    it("should reject data", function (done) {
        var connection = new MockStream();
        var promise = listener(connection);
        connection.write("foo bar baz");
        connection.end();

        promise.then(
            function (obj) {
                // throw new Error("unexpected fulfill");
                return new Error("unexpected fulfill");
            },
            function (obj) {
                obj.should.be.a("object").and
                  .have.property("result", false);
            }
        ).then(done, done);

    });
});

При любом изменении состояния исходного promise-объекта будет вызываться done(). Отличаться будет только параметр, с которым он будет вызван:

  • объект ошибки в случае неверного состояния или выбрасывания исключения;
  • undefined при удачном завершении теста.

Именно такие значения параметра определяют состояние теста в mocha.