Hey there, I have an interesting issue I discovered recently using a technique that I don't see used too often.
Essentially, because functions in JS are also first class objects, they can given properties. I wrote a component which uses this to hold its default options, and was surprised when it broke during a test. I could have made the spy not call through, but in this particular case I wanted it to. Inside the code, it tried to reference a function which was now spied, and the property did not exist, giving an error.
My fix was to store the default options object in a local variable in the test before spying, and then re-adding it to the function (now a spy wrapping function) after. This worked fine.
Anyway, I was just thinking and it may (or may not) be desirable to have a way to cause a spy to iterate over the function its going to spy on's properties and copy them over to make cases like this easier. I could see it being a performance hit, so maybe it should be a flag that can be passed to the spy functions?
Just food for though! Here's a really contrived example, but should illustrate the issue (I know it will look like there's better ways to do it, esp. with the fake object, its just simplified for illustration):
it('wobbles', function() {
// Pretend this source code to be tested
var someObj = {
someFunc: function() {
return this.someFunc.stuff;
}
};
someObj.someFunc.stuff = 'wheee';
// Pretend this is the spec
expect( someObj.someFunc() ).toBe('wheee'); // This will pass
var stuffTemp = someObj.someFunc.stuff;
spyOn(someObj, 'someFunc' ).andCallThrough();
// someObj.someFunc.stuff = stuffTemp; // Try uncommenting this line and see the difference
expect( someObj.someFunc() ).toBe('wheee'); // This will fail unless previous line is uncommented
expect( someObj.someFunc ).toHaveBeenCalled(); // This will pass
});
So yeah, this may not be a good enough of a use case to justify handling it, but I thought I'd bring it up since it is perfectly valid JavaScript (even if the inner function has to be tightly coupled with its function name since they took away arguments.callee)