Skip to content

Commit

Permalink
fix: Incorrect function name prepended to error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
dhoulb committed Dec 16, 2018
1 parent b946d60 commit 55dce4f
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 30 deletions.
4 changes: 2 additions & 2 deletions lib/errors/ValueError.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class ValueError extends TypeError {
super("******");

// Pin down the cause of the error.
// This looks through the Error.stack and finds where e.g. check() or args() was actually called.
const frame = stackTrigger(this.stack, "blork$");
// This looks through the Error.stack and finds where e.g. check() was actually called.
const frame = stackTrigger(this.stack, ["check()"]);

// If there was an error causing function prepend it to the message.
// e.g. "name" → "MyClass.myFunc(): name"
Expand Down
10 changes: 5 additions & 5 deletions lib/helpers/stackTrigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ const destack = require("./destack");
* We also prepend the function/method this to error messages, so rather than error message being "Must be string" it is "MyClass.myFunc(): Must be string"
*
* @param {string} stack A stack string as generated by `new Error()` — unfortunately different browsers use different formats.
* @param {string} needle The needle to look for in function names that indicates the triggering error of the stack. Has to be something unique like "blorker$"
* @returns {array} An array like `[functionName, file, line]` that represents the file/line/call that caused this error, or undefined if it can't be found.
* @param {string[]} ignore Functions to ignore at the top of the stack. The first frame of the stack with a named function not in this list is the 'trigger'. Functions need to be formatted with a pair of parens like `myFunc()`
* @returns {Array} An array like `[functionName, file, line]` that represents the file/line/call that caused this error, or undefined if it can't be found.
*
* @internal
*/
function stackTrigger(stack, needle) {
function stackTrigger(stack, ignore) {
// Parse the stack into its constituent rows.
const frames = destack(stack);
if (frames.length) {
Expand All @@ -27,8 +27,8 @@ function stackTrigger(stack, needle) {

// Loop through the frames.
for (let i = 0; i < frames.length; i++) {
// Does the function name include needle
if (frames[i].function.indexOf(needle) >= 0) {
// Is the function named needle?
if (ignore.indexOf(frames[i].function) >= 0) {
// Return the next named function.
returnNextNamed = true;
} else if (returnNextNamed && frames[i].function) {
Expand Down
34 changes: 11 additions & 23 deletions test/helpers/stackTrigger.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ describe("stackTrigger()", () => {
// Full stack from a random Blork error.
const stack = [
"ValueError: Must be finite string (received 123)",
" at throwError (classes/Blorker.js:41:83)",
" at runChecker (classes/Blorker.js:21:77)",
" at Blorker._check (classes/Blorker.js:261:109)",
" at blorker$check (classes/Blorker.js:118:31)",
" at check (classes/Blorker.js:118:31)",
" at MyClass.name (MyClass.js:8:4)",
" at myFunc (helpers/myFunc.js:129:432)"
];

// Get the stackTrigger stack frame from the frames.
const c = stackTrigger(stack.join("\n"), "blorker$");
const c = stackTrigger(stack.join("\n"), ["check()"]);
expect(c.function).toBe("MyClass.name()");
expect(c.file).toBe("MyClass.js");
expect(c.line).toBe(8);
Expand All @@ -34,10 +31,7 @@ describe("stackTrigger()", () => {
// Full stack from a random Blork error.
const stack = [
"ValueError: Must be finite string (received 123)",
" at throwError (classes/Blorker.js:41:83)",
" at runChecker (classes/Blorker.js:21:77)",
" at Blorker._check (classes/Blorker.js:261:109)",
" at blorker$check (classes/Blorker.js:118:31)",
" at check (classes/Blorker.js:118:31)",
" at <anonymous>:1:3", // Anonymous.
" at <anonymous>:1", // Anonymous.
" at <anonymous>", // Anonymous.
Expand All @@ -46,7 +40,7 @@ describe("stackTrigger()", () => {
];

// Get the stackTrigger stack frame from the frames.
const c = stackTrigger(stack.join("\n"), "blorker$");
const c = stackTrigger(stack.join("\n"), ["check()"]);
expect(c.function).toBe("MyClass.name()");
expect(c.file).toBe("MyClass.js");
expect(c.line).toBe(8);
Expand All @@ -60,7 +54,7 @@ describe("stackTrigger()", () => {
].join("\n")
);
});
test("First frame is returned if no Blorker call is in the stack", () => {
test("First frame if no ignore functions are found in stack", () => {
// Full stack from a random Blork error.
const stack = [
"Error",
Expand All @@ -75,8 +69,8 @@ describe("stackTrigger()", () => {
];

// Get the stackTrigger stack frame from the frames.
const c = stackTrigger(stack.join("\n"), "blorker$");
expect(c.function).toBe("Object.test()");
const c = stackTrigger(stack.join("\n"), ["notInStack()"]);
expect(c.function).toBe("test()");
expect(c.file).toBe("functions/stackTrigger.test.js");
expect(c.line).toBe(8);
expect(c.column).toBe(4);
Expand All @@ -88,16 +82,13 @@ describe("stackTrigger()", () => {
test("Correct frame is returned", () => {
// Full stack from a random Blork error.
const stack = [
"throwError@classes/Blorker.js:41:83",
"runChecker@classes/Blorker.js:21:77",
"Blorker._check@classes/Blorker.js:261:109",
"blorker$check@classes/Blorker.js:118:31",
"check@classes/Blorker.js:118:31",
"MyClass.name@MyClass.js:8:4",
"myFunc@helpers/myFunc.js:129:432"
];

// Get the stackTrigger stack frame from the frames.
const c = stackTrigger(stack.join("\n"), "blorker$");
const c = stackTrigger(stack.join("\n"), ["check()"]);
expect(c.function).toBe("MyClass.name()");
expect(c.file).toBe("MyClass.js");
expect(c.line).toBe(8);
Expand All @@ -108,18 +99,15 @@ describe("stackTrigger()", () => {
test("Anonymous functions are skipped over", () => {
// Full stack from a random Blork error.
const stack = [
"throwError@classes/Blorker.js:41:83",
"runChecker@classes/Blorker.js:21:77",
"Blorker._check@classes/Blorker.js:261:109",
"blorker$check@classes/Blorker.js:118:31",
"check@classes/Blorker.js:118:31",
"@file:///C:/example.html:16:13", // Anonymous.
"@debugger eval code:21:9", // Anonymous.
"MyClass.name@MyClass.js:8:4",
"myFunc@helpers/myFunc.js:129:432"
];

// Get the stackTrigger stack frame from the frames.
const c = stackTrigger(stack.join("\n"), "blorker$");
const c = stackTrigger(stack.join("\n"), ["check()"]);
expect(c.function).toBe("MyClass.name()");
expect(c.file).toBe("MyClass.js");
expect(c.line).toBe(8);
Expand Down

0 comments on commit 55dce4f

Please sign in to comment.