Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack trace for throws(new Error(...)) starts at constructor invocation #1507

Closed
noisecapella opened this issue Aug 2, 2017 · 4 comments
Closed

Comments

@noisecapella
Copy link
Contributor

When I pass an error object to stub.throws(...) I noticed that it shows the stack trace of the constructor in mocha and Chrome, not sure yet about Firefox. It would be nice to have the stack trace start from the point that the exception is thrown so I could identify what pieces of code interacted with the stubbed function. I was going to file a PR to attach a new stack trace to the exception but I noticed that there's a comment warning against interacting with the stack trace here. Can someone give me guidance on whether replacing the stack trace is desirable, or if there's a workaround from the end user's perspective I should use instead? Thanks

@mantoni
Copy link
Member

mantoni commented Aug 2, 2017

Stack traces look very different depending on the environment. The way I did it for Mochify was to remove lines with paths containing specific module names (see here: https://github.com/mantoni/mochify.js/blob/master/lib/trace.js). However, this is only possible on node or if something like Browserify is used with sourcemaps. So this solution doesn't work if scripts are pulled into a browser directly. TBH I think this is out of scope for Sinon itself. Instead, you could try to write a test report processor that filters the output of your test runner to remove Sinon internal trace lines.

@noisecapella
Copy link
Contributor Author

Sorry if I was confusing. The issue isn't that I want to filter out pieces of the stack trace, it's that I want the stack trace to start from the point where the exception is thrown, rather than the point the exception object was created. I wrote this test which I put in stub-test.js to show the behavior:

    it.only("replaces the stack trace", function () {
        var stub = createStub.create();
        stub.throws(new Error("not implemented"));

        let g = () => {
            stub();
        }

        try {
            g()
        } catch (e) {
            console.log(e.stack)
        }
    });

The output is:

Error: not implemented
    at Context.<anonymous> (/home/george/Projects/sinon/test/stub-test.js:527:25)
    at callFn (/home/george/Projects/sinon/node_modules/mocha/lib/runnable.js:348:21)
    at Test.Runnable.run (/home/george/Projects/sinon/node_modules/mocha/lib/runnable.js:340:7)
    at Runner.runTest (/home/george/Projects/sinon/node_modules/mocha/lib/runner.js:443:10)
    ... more lines below

The top line is the point where the Error object is created. If I edit spy.js like this:

    if (exception !== undefined) {
        exception.stack = new Error().stack;  // replace exception stack here
        throw exception;
    }

And rerun the unit test, the output becomes:

Error
    at Function.invoke (/home/george/Projects/sinon/lib/sinon/spy.js:228:31)
    at proxy (/home/george/Projects/sinon/lib/sinon/spy.js:86:22)
    at g (/home/george/Projects/sinon/test/stub-test.js:530:17)
    at Context.<anonymous> (/home/george/Projects/sinon/test/stub-test.js:534:17)
    at callFn (/home/george/Projects/sinon/node_modules/mocha/lib/runnable.js:348:21)
    at Test.Runnable.run (/home/george/Projects/sinon/node_modules/mocha/lib/runnable.js:340:7)
    at Runner.runTest (/home/george/Projects/sinon/node_modules/mocha/lib/runner.js:443:10)
    ... more lines below

The g function is now listed in the stack trace, which is desirable for debugging

@mantoni
Copy link
Member

mantoni commented Aug 3, 2017

Aaah, ok. Now I get it. There is a way to create the error using the type of the error as a string, like this:

var stub = sinon.stub().throws('Error')

Unfortunately this has the same behavior because the error object is constructed immediately. I was thinking it should be possible to construct the error object lazily when the stub is invoked. This way the error object has a stack showing the actual call path.

If you'd like to look into this, have a look at the default behaviors.

@noisecapella
Copy link
Contributor Author

Yes that seems like a good solution to me. I'll work on a PR for throws(...) taking a function as an argument to instantiate the error object. Thanks for your help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants