node-bluebird/test/mocha/long_stack_traces.js

538 lines
17 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var assert = require("assert");
var testUtils = require("./helpers/util.js");
var assertLongTrace = require("./helpers/assert_long_trace.js");
var nodeVersion = typeof process !== "undefined" &&
typeof process.version === "string"
? process.version.replace(/[^0-9.]/g, "").split(".").map(Number)
: [-1, -1, -1];
// Node's V8 captureStackTrace is completely broken - it returns different
// results on different runs and sometimes causes this test to fail
if (!Promise.hasLongStackTraces() || testUtils.isOldNode) return;
describe(".then as context", function() {
it("1 level", function() {
return Promise.resolve().then(function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("1 level using promise reject with no stack", function() {
return Promise.resolve().then(function() {
var e;
try {throw new Error()} catch (err){e = err;}
e.stack;
delete e.stack;
return Promise.reject(e);
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1, 1]);
});
});
it("4 levels using promise reject", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
var e;
try {throw new Error()} catch (err){e = err;}
return Promise.reject(e);
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("Circular 1 level", function() {
var i = 0;
return (function circle() {
if (i++ > 5) throw new Error()
return Promise.resolve().then(circle);
})().then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("Circular 4 levels", function() {
var i = 0;
return (function circle() {
if (i++ > 5) throw new Error()
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(circle);
});
});
});
})().then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("followers unaffected", function() {
return Promise.resolve().then(function() {
return new Promise(function(res) {
res(Promise.delay(13).then(function() {
return new Promise(function(res) {
res(Promise.delay(13).then(function() {
throw new Error();
}));
});
}));
}).then(assert.fail, function(e) {
assertLongTrace(e, 5 + 1, [1, 1, 1, 1, 1]);
throw new Error();
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 2 + 1, [1, 1]);
});
});
it("3 distinct episodes of circularity with unique frames in between", function() {
var i = 0;
var j = 0;
var k = 0;
function circle1() {
if (i++ > 5) return u1_1();
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(circle1);
});
});
});
}
function circle2() {
if (j++ > 5) return u2_1();
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(circle2);
});
});
});
}
function circle3() {
if (k++ > 5) return u3_1();
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(circle3);
});
});
});
}
function u1_1() {
return Promise.resolve().then(u1_2);
}
function u1_2() {
return Promise.resolve().then(circle2);
}
function u2_1() {
return Promise.resolve().then(u2_2);
}
function u2_2() {
return Promise.resolve().then(circle3);
}
function u3_1() {
return Promise.resolve().then(u3_2);
}
function u3_2() {
return Promise.resolve().then(function() {
throw new Error("The error");
});
}
return circle1().then(assert.fail, function(e) {
assertLongTrace(e,
1 + 1 + 1 + 1,
[
1, 1, 2, 1, 1,
1, 1, 2, 1, 1,
1, 1, 2, 1, 1
]);
});
});
});
describe(".spread as context", function() {
it("1 level", function() {
return Promise.resolve([]).spread(function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.resolve([]).spread(function() {
return Promise.resolve([]).spread(function() {
return Promise.resolve([]).spread(function() {
return Promise.resolve([]).spread(function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe("constructor as context", function() {
it("0 level", function() {
return new Promise(function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1, []);
});
});
it("1 level", function() {
return new Promise(function(res) {
res(new Promise(function() {
throw new Error();
}))
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [2]);
});
});
it("0 level, no stack property", function() {
return new Promise(function(_ ,rej) {
var e = new Error();
e.stack;
delete e.stack;
rej(e);
}).then(assert.fail, function(e) {
assertLongTrace(e, 1, [1]);
});
});
it("1 level, no stack property", function() {
return new Promise(function(res) {
res(new Promise(function(_, rej) {
var e = new Error();
e.stack;
delete e.stack;
rej(e);
}))
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1, 1]);
});
});
it("4 levels", function() {
return new Promise(function(res) {
res(new Promise(function(res) {
res(new Promise(function(res) {
res(new Promise(function(res) {
res(new Promise(function(res) {
throw new Error();
}));
}));
}));
}));
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [2, 1, 1, 1]);
});
});
});
describe(".join as context", function() {
it("0 level", function() {
var err;
try {throw new Error(); } catch(e) {err = e;};
return Promise.join(1, 2, Promise.reject(err), function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 0 + 1, []);
});
});
it("1 level", function() {
return Promise.join(1, 2, 3, function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.join(1, 2, 3, function() {
return Promise.join(1, 2, 3, function() {
return Promise.join(1, 2, 3, function() {
return Promise.join(1, 2, 3, function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe(".map as context", function() {
it("1 level", function() {
return Promise.map([1,2,3], function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.map([1,2,3], function() {
return Promise.map([1,2,3], function() {
return Promise.map([1,2,3], function() {
return Promise.map([1,2,3], function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe(".reduce as context", function() {
it("1 level", function() {
return Promise.reduce([1,2,3], function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.reduce([1,2,3], function() {
return Promise.reduce([1,2,3], function() {
return Promise.reduce([1,2,3], function() {
return Promise.reduce([1,2,3], function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe(".method as context", function() {
it("1 level", function() {
return Promise.method(function() {
throw new Error();
})().then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
var second = Promise.method(function() {
return third();
});
var third = Promise.method(function() {
return fourth();
});
var fourth = Promise.method(function() {
throw new Error();
});
return Promise.method(function() {
return second();
})().then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [[1,2], 1, 1, 1]);
});
});
});
describe(".try as context", function() {
it("1 level", function() {
return Promise.attempt(function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.attempt(function() {
return Promise.attempt(function() {
return Promise.attempt(function() {
return Promise.attempt(function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe(".using as context", function() {
it("0 level", function() {
var err;
try {throw new Error(); } catch(e) {err = e};
return Promise.using(1, 2, Promise.reject(err), function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 0 + 1, []);
});
});
it("1 level", function() {
return Promise.using(1, 2, 3, function() {
throw new Error();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels", function() {
return Promise.using(1, 2, 3, function() {
return Promise.using(1, 2, 3, function() {
return Promise.using(1, 2, 3, function() {
return Promise.using(1, 2, 3, function() {
throw new Error();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});
describe("Long stack traces from thenable rejections", function() {
var es5 = (function(){"use strict"; return this})() === undefined;
// Todo, for 100% coverage thenables should be tested with every
// feature, not just then
var syncRej = function() {
return {
then: function(_, rej) {
rej(new Error());
}
};
};
var asyncRej = function() {
return {
then: function(_, rej) {
setTimeout(function() {
rej(new Error());
}, 1);
}
};
};
var throwRej = function() {
return {
then: function(_, rej) {
throw(new Error());
}
};
};
var thenGetRej = function() {
var ret = {};
Object.defineProperty(ret, "then", {
get: function() {
throw new Error()
}
});
return ret;
};
it("1 level sync reject", function() {
return Promise.resolve().then(function() {
return syncRej();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1+1, [1]);
});
});
it("4 levels sync reject", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return syncRej();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("1 level async reject", function() {
return Promise.resolve().then(function() {
return asyncRej();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels async reject", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return asyncRej();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("1 level throw", function() {
return Promise.resolve().then(function() {
return throwRej();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels throw", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return throwRej();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
it("1 level getter throw", function() {
return Promise.resolve().then(function() {
return thenGetRej();
}).then(assert.fail, function(e) {
assertLongTrace(e, 1 + 1, [1]);
});
});
it("4 levels getter throw", function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return Promise.resolve().then(function() {
return thenGetRej();
});
});
});
}).then(assert.fail, function(e) {
assertLongTrace(e, 4 + 1, [1, 1, 1, 1]);
});
});
});