diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 426f63b4..9db769db 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -2803,7 +2803,7 @@ getJasmineRequireObj().CallTracker = function(j$) { this.track = function(context) { if (opts.cloneArgs) { - context.args = j$.util.cloneArgs(context.args); + context.args = opts.argsCloner(context.args); } calls.push(context); }; @@ -2911,13 +2911,15 @@ getJasmineRequireObj().CallTracker = function(j$) { }; /** - * Set this spy to do a shallow clone of arguments passed to each invocation. + * Set this spy to do a clone of arguments passed to each invocation. * @name Spy#calls#saveArgumentsByValue * @since 2.5.0 + * @param {Function} [argsCloner] A function to use to clone the arguments. Defaults to a shallow cloning function. * @function */ - this.saveArgumentsByValue = function() { + this.saveArgumentsByValue = function(argsCloner = j$.util.cloneArgs) { opts.cloneArgs = true; + opts.argsCloner = argsCloner; }; this.unverifiedCount = function() { diff --git a/spec/core/CallTrackerSpec.js b/spec/core/CallTrackerSpec.js index da5cecc7..55541b72 100644 --- a/spec/core/CallTrackerSpec.js +++ b/spec/core/CallTrackerSpec.js @@ -134,6 +134,42 @@ describe('CallTracker', function() { expect(callTracker.mostRecent().args[1]).toEqual(arrayArg); }); + it('allows object arguments to be deep cloned', function() { + const callTracker = new jasmineUnderTest.CallTracker(); + callTracker.saveArgumentsByValue(args => JSON.parse(JSON.stringify(args))); + + const objectArg = { foo: { bar: { baz: ['qux'] } } }, + arrayArg = ['foo', 'bar']; + + callTracker.track({ + object: {}, + args: [objectArg, arrayArg, false, undefined, null, NaN, '', 0, 1.0] + }); + + objectArg.foo.bar.baz.push('quux'); + + expect(callTracker.mostRecent().args[0]).not.toBe(objectArg); + expect(callTracker.mostRecent().args[0]).not.toEqual(objectArg); + expect(callTracker.mostRecent().args[0]).toEqual({ + foo: { bar: { baz: ['qux'] } } + }); + expect(callTracker.mostRecent().args[1]).not.toBe(arrayArg); + expect(callTracker.mostRecent().args[1]).toEqual(arrayArg); + }); + + it('can take any function to transform arguments when saving by value', function() { + const callTracker = new jasmineUnderTest.CallTracker(); + callTracker.saveArgumentsByValue(JSON.stringify); + + const objectArg = { foo: { bar: { baz: ['qux'] } } }, + arrayArg = ['foo', 'bar'], + args = [objectArg, arrayArg, false, undefined, null, NaN, '', 0, 1.0]; + + callTracker.track({ object: {}, args }); + + expect(callTracker.mostRecent().args).toEqual(JSON.stringify(args)); + }); + it('saves primitive arguments by value', function() { const callTracker = new jasmineUnderTest.CallTracker(), args = [undefined, null, false, '', /\s/, 0, 1.2, NaN]; diff --git a/src/core/CallTracker.js b/src/core/CallTracker.js index d123aed5..ac5f0763 100644 --- a/src/core/CallTracker.js +++ b/src/core/CallTracker.js @@ -9,7 +9,7 @@ getJasmineRequireObj().CallTracker = function(j$) { this.track = function(context) { if (opts.cloneArgs) { - context.args = j$.util.cloneArgs(context.args); + context.args = opts.argsCloner(context.args); } calls.push(context); }; @@ -117,13 +117,15 @@ getJasmineRequireObj().CallTracker = function(j$) { }; /** - * Set this spy to do a shallow clone of arguments passed to each invocation. + * Set this spy to do a clone of arguments passed to each invocation. * @name Spy#calls#saveArgumentsByValue * @since 2.5.0 + * @param {Function} [argsCloner] A function to use to clone the arguments. Defaults to a shallow cloning function. * @function */ - this.saveArgumentsByValue = function() { + this.saveArgumentsByValue = function(argsCloner = j$.util.cloneArgs) { opts.cloneArgs = true; + opts.argsCloner = argsCloner; }; this.unverifiedCount = function() {