Files
bun.sh/test/bun.js/capture-stack-trace.test.js
Dylan Conway 047a8d3f0d Error.captureStackTrace implementation (#1476)
* capture stack trace formatting, tests

* fix callsite methods, stack formatting or undefined

* isNative, tests for callsite methods

* Update src/bun.js/bindings/ZigGlobalObject.cpp

* Update src/bun.js/bindings/ZigGlobalObject.cpp

* template and macros for visitchildren

* static strings, handle infinity and clamp stacktracelimit

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2022-11-09 00:37:57 -08:00

304 lines
6.6 KiB
JavaScript

import { test, expect } from "bun:test";
test("capture stack trace", () => {
function f1() {
f2();
}
function f2() {
f3();
}
function f3() {
logErrorStackTrace();
}
function logErrorStackTrace() {
let error = {};
Error.captureStackTrace(error);
expect(error.stack !== undefined).toBe(true);
}
f1();
});
test("capture stack trace with message", () => {
function f1() {
f2();
}
function f2() {
f3();
}
function f3() {
logErrorStackTrace();
}
function logErrorStackTrace() {
let e1 = { message: "bad error!" };
Error.captureStackTrace(e1);
expect(e1.message === "bad error!").toBe(true);
let e2 = new Error("bad error!");
Error.captureStackTrace(e2);
expect(e2.message === "bad error!").toBe(true);
}
f1();
});
test("capture stack trace with constructor", () => {
class S {
constructor() {
captureStackTrace();
}
}
function captureStackTrace() {
let e1 = {};
Error.captureStackTrace(e1);
expect(e1.stack.split("\n")[2].includes("new S")).toBe(true);
}
let s = new S();
});
test("capture stack trace limit", () => {
function f1() {
f2();
}
function f2() {
f3();
}
function f3() {
f4();
}
function f4() {
f5();
}
function f5() {
f6();
}
function f6() {
f7();
}
function f7() {
f8();
}
function f8() {
f9();
}
function f9() {
f10();
}
function f10() {
captureStackTrace();
}
function captureStackTrace() {
let e1 = {};
Error.captureStackTrace(e1);
expect(e1.stack.split("\n").length).toBe(11);
let e2 = new Error();
Error.captureStackTrace(e2);
expect(e2.stack.split("\n").length).toBe(11);
let e3 = {};
Error.stackTraceLimit = 4;
Error.captureStackTrace(e3);
expect(e3.stack.split("\n").length).toBe(5);
let e4 = new Error();
Error.captureStackTrace(e4);
expect(e4.stack.split("\n").length).toBe(5);
let e5 = { stackTraceLimit: 2 };
Error.captureStackTrace(e5);
expect(e5.stack.split("\n").length).toBe(5);
let e6 = {};
Error.stackTraceLimit = Infinity;
Error.captureStackTrace(e6);
expect(e6.stack.split("\n").length).toBe(13);
}
f1();
});
test("prepare stack trace", () => {
function f1() {
f2();
}
function f2() {
let e = {};
let prevPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (e, stack) => {
return "custom stack trace";
};
Error.captureStackTrace(e);
expect(e.stack).toBe("custom stack trace");
Error.prepareStackTrace = prevPrepareStackTrace;
f3();
}
function f3() {
let e = { message: "bad error!" };
let prevPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (e, s) => {
expect(e.message === "bad error!").toBe(true);
expect(s.length).toBe(4);
};
Error.stackTraceLimit = 10;
Error.captureStackTrace(e);
expect(e.stack === undefined).toBe(true);
Error.prepareStackTrace = prevPrepareStackTrace;
}
f1();
});
test("capture stack trace second argument", () => {
function f0() {
let s = new S();
}
class S {
constructor() {
f1();
}
}
function f1() {
f2();
}
function f2() {
f3();
}
function f3() {
f4();
}
function f4() {
f5();
}
function f5() {
f6();
}
function f6() {
let e = { message: "bad error!" };
Error.captureStackTrace(e);
expect(e.stack.split("\n")[1].includes("at f6")).toBe(true);
expect(e.stack.split("\n")[2].includes("at f5")).toBe(true);
let e2 = {};
Error.captureStackTrace(e2, f3);
expect(e2.stack.split("\n")[1].includes("at f2")).toBe(true);
expect(e2.stack.split("\n")[2].includes("at f1")).toBe(true);
let e3 = {};
Error.captureStackTrace(e3, f9);
expect(e3.stack.split("\n").length).toBe(1);
let e4 = { message: "exclude constructor!" };
Error.captureStackTrace(e4, S.constructor);
expect(e4.stack.split("\n").length).toBe(1);
let e5 = { message: "actually exclude constructor!" };
Error.captureStackTrace(e5, S);
expect(e5.stack.split("\n")[1].includes("at f0")).toBe(true);
}
function f9() {
// nothing
}
f0();
});
test("capture stack trace edge cases", () => {
let e1 = {};
Error.captureStackTrace(e1, null);
expect(e1.stack !== undefined).toBe(true);
let e2 = {};
Error.captureStackTrace(e2, undefined);
expect(e2.stack !== undefined).toBe(true);
let e3 = {};
Error.captureStackTrace(e3, 1);
expect(e3.stack !== undefined).toBe(true);
let e4 = {};
Error.captureStackTrace(e4, "foo");
expect(e4.stack !== undefined).toBe(true);
let e5 = {};
Error.captureStackTrace(e5, {});
expect(e5.stack !== undefined).toBe(true);
expect(Error.captureStackTrace({})).toBe(undefined);
expect(Error.captureStackTrace({}, () => {})).toBe(undefined);
expect(Error.captureStackTrace({}, undefined)).toBe(undefined);
expect(Error.captureStackTrace({}, null)).toBe(undefined);
expect(Error.captureStackTrace({}, 1)).toBe(undefined);
expect(Error.captureStackTrace({}, "foo")).toBe(undefined);
expect(Error.captureStackTrace({}, {})).toBe(undefined);
expect(Error.captureStackTrace({}, [])).toBe(undefined);
expect(Error.captureStackTrace({}, true)).toBe(undefined);
});
test("prepare stack trace call sites", () => {
function f1() {
f2();
}
function f2() {
f3();
}
function f3() {
let e = { message: "bad error!" };
// let e = new Error("bad error!");
let prevPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (e, s) => {
expect(s[0].getThis !== undefined).toBe(true);
expect(s[0].getTypeName !== undefined).toBe(true);
expect(s[0].getFunction !== undefined).toBe(true);
expect(s[0].getFunctionName !== undefined).toBe(true);
expect(s[0].getMethodName !== undefined).toBe(true);
expect(s[0].getFileName !== undefined).toBe(true);
expect(s[0].getLineNumber !== undefined).toBe(true);
expect(s[0].getColumnNumber !== undefined).toBe(true);
expect(s[0].getEvalOrigin !== undefined).toBe(true);
expect(s[0].isToplevel !== undefined).toBe(true);
expect(s[0].isEval !== undefined).toBe(true);
expect(s[0].isNative !== undefined).toBe(true);
expect(s[0].isConstructor !== undefined).toBe(true);
expect(s[0].isAsync !== undefined).toBe(true);
expect(s[0].isPromiseAll !== undefined).toBe(true);
expect(s[0].getPromiseIndex !== undefined).toBe(true);
};
Error.captureStackTrace(e);
expect(e.stack === undefined).toBe(true);
Error.prepareStackTrace = prevPrepareStackTrace;
}
f1();
});