Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

fix(ngMock window.inject): Remove Error 'stack' property changes #5047

Closed
wants to merge 1 commit into from

Conversation

wizardwerdna
Copy link
Contributor

Recent browsers, particularly PhantomJS 1.9.2 and Safari 7.0
treat the stack property as non-configurable and unwritable.

Because window.inject captures the stack at the time of the inject,
and attempts to insert it into a captured throw from the injected
function by modifying e.stack, a meaningless error message and
stack is thrown instead.

This commit inserts two tests exposing the problem, and implements
a solution passing those tests. The solution provides an object that
mimics the old Error object, with the additional stack information, where
possible (Error is not standardized on stack, line and file information), and
then captures the toString function from the Error object prototype.

An exception is IE8 or less, which fails to yield meaningful messages
under both the status quo and this instant commit. Accordingly, the test
memorializes the current IE8 behavior as a passing example.

modified: src/ngMock/angular-mocks.js
modified: test/ngMock/angular-mocksSpec.js

Recent browsers, particularly PhantomJS 1.9.2 and Safari 7.0
treat the stack property as non-configurable and unwritable.

Because window.inject captures the stack at the time of the inject,
and attempts to insert it into a captured throw from the injected
function by modifying e.stack, a meaningless error message and
stack is thrown instead.

This commit inserts two tests exposing the problem, and implements
a proposed solution that builds a new error-like object that mimicks
the old Error object, but with the additional stack information, and
captures the toString function from the Error object prototype.  This
appears to work for the browsers suppoerted here.

An exception is IE8 or less, which fails to yield meaningful messages
under both the status quo and after this commit.  Accordingly, the test
memorializes the current behavior without throwing an error for IE8
and earlier.

modified:   src/ngMock/angular-mocks.js
modified:   test/ngMock/angular-mocksSpec.js
@petebacondarwin
Copy link
Member

Hi @wizardwerdna - have you signed the CLA recently or in the past?

@wizardwerdna
Copy link
Contributor Author

I went ahead and re-signed the CLA. You should be good to go.

@alekstorm
Copy link

+1, this is hurting us quite badly. Please merge ASAP.

@mattdanskey
Copy link

+1. Ran into this issue with PhantomJS and got
TypeError: Attempted to assign to readonly property.
After commenting out line 2107 in v1.2.1, the message became a much more helpful,
Error: [$injector:unpr] Unknown provider: base64Provider <- base64 <- authenticator

@wizardwerdna
Copy link
Contributor Author

Indeed, to those of us who do test-first development, the quality of error
messages in jasmine are essential to efficient development. Remember, we
can't write a line of production code until we get a failing test. When
many of our non-matcher messaes are all "Attempted to assign to readonly
property," it puts a huge crimp in our work, particularly at the outset
when most messages are non-matcher errors.

@trashhalo
Copy link

This bug was a pretty big headache for my team. If anyone is interested it cleanly cherry picks onto the the 1.2.0 tag.

Build with the change from this pull request: https://gist.github.com/trashhalo/7660093
Diff between my gist and cdn code: http://www.diffnow.com/?report=xw0vo

@Kazark
Copy link

Kazark commented Dec 5, 2013

+1 this bit me too

@fidian
Copy link
Contributor

fidian commented Dec 6, 2013

I was about to submit a pull request for this exact same issue. +1 for me and my team. As it is, I will be manually applying the patch as the official packages don't have this extremely useful fix. I look forward to seeing this in 1.2.4.

@booleanbetrayal
Copy link
Contributor

+1 ... very annoying problem to have.

@sulmanen
Copy link

sulmanen commented Dec 9, 2013

didn't find in 1.2.4, patched manually. works. thnx!

@laurelnaiad
Copy link

+1 for merging pre-1.2.5

@pmccaughtry
Copy link

I am seeing this in 1.2.5. Is anyone else and if so, is there a solution?

Thank you

@laurelnaiad
Copy link

Look at the pull request and patch manually. Just a few lines of code.

@pmccaughtry
Copy link

Thank you stu-salsbury. Worked perfectly.

@laurelnaiad
Copy link

Np @pmccaughtry. You reminded me I forgot to re-patch after updating to 1.2.5. Core team is there anything preventing this from being merged? If so can you let us know. Maybe someone wil beable to pitch in!

@laurelnaiad
Copy link

Just thought of something.. I'm on the road so can't test this.. I don't think I saw the problem after updating to 1.2.5. I wonder if its because I added es5shim on my unit tests in order to get chai expect to work?

@munsellj
Copy link

+1. Encountered same issue writing unit tests (Grunt, Karma, Jasmine) and running them in PhantomJS using Angular v1.2.5. Running in Chrome produces the correct error stack trace for a failed test.

aughr added a commit to newrelic/bower-angular-mocks that referenced this pull request Dec 19, 2013
@jimmykane
Copy link

Still here on safari latest and angular 1.2.5

@wizardwerdna
Copy link
Contributor Author

@jimmykane This solution is targeted for a merge, but apparently isn't a strong priority at the moment. In the meanwhile, you can readily use patched versions of angular-mocks from a number of reputable sources, such as new relic and others, or manually implement it yourself.

@vojtajina
Copy link
Contributor

Guys sorry for delays... It's merged as 7e91645.
I changed the tests a bit - we don't need to test the stupid IE8 behavior.

@markscholtz
Copy link

This seems to break Jasmine 2.x's toThrowError() function. The original exception is no longer thrown and the new error object does not inherit from Error.

Given a Jasmine expectation that looks like:

expect(myObject.throwMyExpectedError()).toThrowError(MyExpectedError);

Where the implementation of throwMyExpectedError throws an exception inheriting from Error, I see something along these lines from my Jasmine test output:

...
Expected function to throw an Error, but it threw ({ message: 'my error message', name: 'MyExpectedError', stack: 'the augmented call stack ...'}).

That's a bit of a hand-wavy example. I can try and provide more information and perhaps write a test to prove this, but I wanted to raise it first to see if anyone had any thoughts.

@petebacondarwin
Copy link
Member

@markscholtz - if you feel we have an outstanding issue can you please create a new issue for it and reference this one?

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

Successfully merging this pull request may close these issues.

None yet