mocha icon indicating copy to clipboard operation
mocha copied to clipboard

🐛 Bug: Calling `done` with circular reference object results in type error converting JSON instead of correct failure message

Open hrdwdmrbl opened this issue 8 years ago • 1 comments
trafficstars

Just spent way too long getting this bug and not knowing why. After figuring it out, here's the simplest repro I could make

it('Mocha is confused', function(done) {
  new Promise(function(resolve, reject) {
    var a = {};
    a.b = a;
    resolve(a);
  }).then(done).catch(done);
});

Produces

  1) Mocha is confused

  0 passing (20ms)
  1 failing

  1)  Mocha is confused:
     TypeError: Converting circular structure to JSON
      at Object.stringify (native)

The problem here is that there isn't a stack-trace, so I start off with absolutely no idea how to solve the problem. I have no idea why Mocha wants to stringify what I give to the done function, but it does...

hrdwdmrbl avatar Nov 25 '16 20:11 hrdwdmrbl

done() is success (e.g. .then(function(){done()}), although if you're doing this you probably have a case for returning the promise instead of using done); done(<anything>) is failure, so it's trying to process the "failure" and is running into a circular reference in it. This could be simplified to:

it("circular done", function(done) {
  var x = {}
  x.y = x
  done(x)
})

We have another bug open, #2433, about circular errors or some such thing causing problems for the JSON reporter, but in this case the reporter doesn't seem to make a difference. This may also suggest an issue that some things are being done with the "failure" value before the point where Mocha is supposed to check that it's an Error (normally Mocha requires failures to be Errors and should give you a warning if you try to use something else, such as a raw string).

Notably, this does not happen if I throw or return a rejected promise instead of calling done:

it("circular throw", function() {
  var x = {}
  x.y = x
  throw x
})
it("circular promise", function() {
  var x = {}
  x.y = x
  return Promise.reject(x)
})

Error: the object { "y": [Circular] } was thrown, throw an Error :)

ScottFreeCode avatar Nov 25 '16 22:11 ScottFreeCode