Domains not properly catching errors while testing nodeJS in mocha

前端 未结 2 898
暗喜
暗喜 2021-01-01 05:21

When running tests that utilize domains for error handling, Mocha still appears to be throwing an error even if a domain handler inside a library should have caught the erro

2条回答
  •  暗喜
    暗喜 (楼主)
    2021-01-01 05:45

    nodejs domains do definitely catch synchronous errors

    See this simple test case

    var domain = require("domain");
    var d = domain.create();
    
    d.on("error", function() {
        console.log("domain caught");
    });
    
    
    d.run(function() {
        throw new Error("foo");
    });
    
    
    // result: domain caught
    

    EDIT: Since writing this answer I have written a blog post describing what is going on with domains and try catch and whether you can use domains as a wholesale replacement for try catch. It summarises most of what has been discussed here.

    http://www.lighthouselogic.com/node-domains-as-a-replacement-for-try-catch/

    ORIGINAL ANSWER:

    Actually there is a problem with Mocha.

    I wrote the following test function:

    function error(callback){
         var d = domain.create().on('error', function(err){
            console.log("Caught Error in Domain Handler")
            return callback(err);
        });
        d.enter();
        throw new Error("TestError");
        d.exit();
    }
    

    Then I wrote a simple test without mocha:

    error(function(err){
        if(err)
        {
            console.log("Error was returned");
        }else
        {
            console.log("Error was not returned")
        }
    })
    

    The output I received was:

    Caught Error in Domain Handler
    Error was returned
    

    When I tested using Mocha:

    describe('Domain Tests', function(){
        it('Should return an error when testing', function(done){
            error(function(err){
                if(err)
                {
                    console.log("Error was returned");
                }else
                {
                    console.log("Error was not returned")
                }
                return done();
            })
        });
    });
    

    I received the following output:

    ․
    
      0 passing (4ms)
      1 failing
    
      1) Domain Tests Should return an error when testing:
         Error: TestError
          at error (/Users/bensudbury/Documents/node_projects/testMochaDomains/test.js:9:11)
          at Context. (/Users/bensudbury/Documents/node_projects/testMochaDomains/testMocha.js:6:3)
          at Test.Runnable.run (/usr/local/share/npm/lib/node_modules/mocha/lib/runnable.js:194:15)
          at Runner.runTest (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:358:10)
          at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:404:12
          at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:284:14)
          at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:293:7
          at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:237:23)
          at Object._onImmediate (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:261:5)
          at processImmediate [as _immediateCallback] (timers.js:330:15)
    

    As you can see: the domain error handler was short circuited.

    This problem seems to be related to the following issues:

    https://github.com/visionmedia/mocha/issues/513

    While the Node issue has been closed, the issue in mocha is still open.

    The workaround that was suggested at: https://gist.github.com/mcollina/4443963 didn't resolve the issue in this case.

    I dug through the code of Mocha and found that the problem occurs because mocha wraps the tests in a try catch block. This means that the exception is caught and never sent to the uncaughtException or _fatalException handler depending upon the version of node that you are using.

    Your workaround is good, but nodejs domains do definitely catch synchronous errors so I wouldn't change your code but instead change your test. Your new test should look like:

    describe("test", function() {
        it("should succeed", function(done) {
            process.nextTick(function(){
                var foo = require("./foo.js");
                foo(function() {
                    console.log("done");
                    done();
                });
            })      
        });
    });
    

    I haven't tested this code, but similar code for my example works properly:

    it('Should return an error when testing', function(done){   
        process.nextTick(function(){
            error(function(err){
                if(err)
                {
                    console.log("Error was returned");
                }else
                {
                    console.log("Error was not returned")
                }
                return done();
            });
        })
    });
    

    I have added a comment to the end of the issue in Mocha to see if it can be resolved:

    https://github.com/visionmedia/mocha/issues/513

提交回复
热议问题