最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Catching out-of-scope errors with Mocha and Chai - Stack Overflow

programmeradmin0浏览0评论

I am modifying a node.js library to support true asynchronous operations.

I am having troubles with Mocha and Chai to make this (a similar) test pass.

it('should throw an error', function() {
    expect(function() {
        process.nextTick(function() {
            throw new Error('This is my error');
        });
    }).to.throw(Error);
});

The problem is - because of the nextTick - that the Error is thrown out of scope of it and besides the test failing, Mocha also outputs the below.

Uncaught Error: This is my error

What is the proper way to structure this test in order to make it succeed?

I am modifying a node.js library to support true asynchronous operations.

I am having troubles with Mocha and Chai to make this (a similar) test pass.

it('should throw an error', function() {
    expect(function() {
        process.nextTick(function() {
            throw new Error('This is my error');
        });
    }).to.throw(Error);
});

The problem is - because of the nextTick - that the Error is thrown out of scope of it and besides the test failing, Mocha also outputs the below.

Uncaught Error: This is my error

What is the proper way to structure this test in order to make it succeed?

Share Improve this question edited Nov 3, 2014 at 17:47 levi 25.2k18 gold badges63 silver badges76 bronze badges asked Nov 3, 2014 at 17:05 TrenskowTrenskow 3,7931 gold badge30 silver badges37 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

Hmm... in a full-fledged application what I'd do is probably use something like Sinon to check that the method that should throw an error has been called and is throwing.

In code where you cannot do this, then the following method would trap the exception:

var expect = require("chai").expect;
var domain = require("domain");

it('should throw an error', function(done) {
    var d = domain.create();
    d.on('error', function (err) {
        // Exit the current domain.
        d.exit();
        // We must execute this code at the next tick.
        process.nextTick(function () {
            console.log(err); // Just to show something on the console.
            expect(err instanceof Error).to.be.true;
            done();
        });
    });


    d.run(function () {
        process.nextTick(function() {
            throw new Error('This is my error');
        });
    });
});

This code creates a "domain" stored in d. A domain will emit error events on uncaught exceptions that happen in it so we run the test inside the domain (d.run(...)) we've created and wait for an exception to happen (d.on('error', ...). We check that it is an Error object. (In a real test, I'd also check the error message.) When we are finished we call done() to tell Mocha that the asynchronous test is over.

The handler for error events calls d.exit(). This is to make it so that Mocha can catch the error normally if the assertion (expect(err instanceof Error)...) turns out to fail. If we do not exit the domain, then the domain will trap the error. Also, the check itself must be performed on the next tick to be outside the d domain.

Is Using domain A Problem?

NO!

The documentation for domain es with some warnings about shutting down operations once an uncaught exception is caught when running an ongoing process, like a server. Then the thing to do is to clean what can be cleaned and exit as soon as possible. However, using domain in a test does not differ from what Mocha is already doing. The way Mocha catches unhandled exceptions in asynchronous code is by using process.on('uncaughtException'. Upon catching an unhandled exception Mocha marks the current test as failed and continues. Yet the documentation regarding uncaughtException says "Don't use it, use domains instead. If you do use it, restart your application after every unhandled exception!"

Ergo, anyone who has a problem with using domain should not be using Mocha in the first place.

You're trying to catch an exception on the incorrect function, the container for the function that throws. Also, because the function is wrapped in nextTick it is executed in a different stack and therefore the exception cannot be captured (this is simply a JS thing unfortunately).

Try this instead:

it ('should throw an error', function (done) {

  process.nextTick(function () {
    var myFn = function () { throw new Error() };

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

    // Tell mocha the test is plete 
    done();
  });
});

Update: There is no proper way to structure this test to make it pass as you cannot catch the exception in this scenario. Perhaps update your code to use callbacks to handle errors:

function doSomethingUnsafe() {

  try {
    // Run code here that may cause exceptions...
    callback(null, 'Woohoo! No errors!');
  } catch (e) {
    callback (e, null);
  }
}
发布评论

评论列表(0)

  1. 暂无评论