Use custom equality testers in Spy#withArgs

Fixes #1836.
This commit is contained in:
Steve Gravrock
2021-11-15 18:30:43 -08:00
parent 8e74529631
commit 2a049015b0
6 changed files with 152 additions and 61 deletions

View File

@@ -1490,12 +1490,18 @@ getJasmineRequireObj().Env = function(j$) {
};
var makeMatchersUtil = function() {
var customEqualityTesters =
runnableResources[currentRunnable().id].customEqualityTesters;
return new j$.MatchersUtil({
customTesters: customEqualityTesters,
pp: makePrettyPrinter()
});
const cr = currentRunnable();
if (cr) {
const customEqualityTesters =
runnableResources[cr.id].customEqualityTesters;
return new j$.MatchersUtil({
customTesters: customEqualityTesters,
pp: makePrettyPrinter()
});
} else {
return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ });
}
};
var expectationFactory = function(actual, spec) {
@@ -2026,7 +2032,8 @@ getJasmineRequireObj().Env = function(j$) {
}
return undefined;
}
},
makeMatchersUtil
);
var spyRegistry = new j$.SpyRegistry({
@@ -8647,11 +8654,6 @@ getJasmineRequireObj().Spy = function(j$) {
};
})();
var matchersUtil = new j$.MatchersUtil({
customTesters: [],
pp: j$.makePrettyPrinter()
});
/**
* @classdesc _Note:_ Do not construct this directly. Use {@link spyOn},
* {@link spyOnProperty}, {@link jasmine.createSpy}, or
@@ -8659,19 +8661,24 @@ getJasmineRequireObj().Spy = function(j$) {
* @class Spy
* @hideconstructor
*/
function Spy(name, originalFn, customStrategies, defaultStrategyFn) {
function Spy(name, matchersUtil, optionals) {
const { originalFn, customStrategies, defaultStrategyFn } = optionals || {};
var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
wrapper = makeFunc(numArgs, function(context, args, invokeNew) {
return spy(context, args, invokeNew);
}),
strategyDispatcher = new SpyStrategyDispatcher({
name: name,
fn: originalFn,
getSpy: function() {
return wrapper;
strategyDispatcher = new SpyStrategyDispatcher(
{
name: name,
fn: originalFn,
getSpy: function() {
return wrapper;
},
customStrategies: customStrategies
},
customStrategies: customStrategies
}),
matchersUtil
),
callTracker = new j$.CallTracker(),
spy = function(context, args, invokeNew) {
/**
@@ -8783,11 +8790,11 @@ getJasmineRequireObj().Spy = function(j$) {
return wrapper;
}
function SpyStrategyDispatcher(strategyArgs) {
function SpyStrategyDispatcher(strategyArgs, matchersUtil) {
var baseStrategy = new j$.SpyStrategy(strategyArgs);
var argsStrategies = new StrategyDict(function() {
return new j$.SpyStrategy(strategyArgs);
});
}, matchersUtil);
this.and = baseStrategy;
@@ -8816,9 +8823,10 @@ getJasmineRequireObj().Spy = function(j$) {
};
}
function StrategyDict(strategyFactory) {
function StrategyDict(strategyFactory, matchersUtil) {
this.strategies = [];
this.strategyFactory = strategyFactory;
this.matchersUtil = matchersUtil;
}
StrategyDict.prototype.any = function() {
@@ -8843,7 +8851,7 @@ getJasmineRequireObj().Spy = function(j$) {
var i;
for (i = 0; i < this.strategies.length; i++) {
if (matchersUtil.equals(args, this.strategies[i].args)) {
if (this.matchersUtil.equals(args, this.strategies[i].args)) {
return this.strategies[i].strategy;
}
}
@@ -8853,16 +8861,19 @@ getJasmineRequireObj().Spy = function(j$) {
};
getJasmineRequireObj().SpyFactory = function(j$) {
function SpyFactory(getCustomStrategies, getDefaultStrategyFn) {
function SpyFactory(
getCustomStrategies,
getDefaultStrategyFn,
getMatchersUtil
) {
var self = this;
this.createSpy = function(name, originalFn) {
return j$.Spy(
name,
return j$.Spy(name, getMatchersUtil(), {
originalFn,
getCustomStrategies(),
getDefaultStrategyFn()
);
customStrategies: getCustomStrategies(),
defaultStrategyFn: getDefaultStrategyFn()
});
};
this.createSpyObj = function(baseName, methodNames, propertyNames) {

View File

@@ -231,7 +231,7 @@ describe('Spies', function() {
expect(spy('baz', 'grault', 'waldo')).toEqual(42);
});
it('uses custom equality testers when selecting a strategy', function() {
it('uses asymmetric equality testers when selecting a strategy', function() {
var spy = env.createSpy('foo');
spy.and.returnValue(42);
spy.withArgs(jasmineUnderTest.any(String)).and.returnValue(-1);
@@ -240,6 +240,23 @@ describe('Spies', function() {
expect(spy({})).toEqual(42);
});
it('uses the provided matchersUtil selecting a strategy', function() {
const matchersUtil = new jasmineUnderTest.MatchersUtil({
customTesters: [
function(a, b) {
if ((a === 'bar' && b === 'baz') || (a === 'baz' && b === 'bar')) {
return true;
}
}
]
});
const spy = new jasmineUnderTest.Spy('aSpy', matchersUtil);
spy.and.returnValue('default strategy return value');
spy.withArgs('bar').and.returnValue('custom strategy return value');
expect(spy('foo')).toEqual('default strategy return value');
expect(spy('baz')).toEqual('custom strategy return value');
});
it('can reconfigure an argument-specific strategy', function() {
var spy = env.createSpy('foo');
spy.withArgs('foo').and.returnValue(42);

View File

@@ -3413,4 +3413,56 @@ describe('Env integration', function() {
done();
});
});
it('uses custom equality testers in Spy#withArgs', async function() {
env.it('a spec', function() {
const createSpySpy = env.createSpy('via createSpy');
const spiedOn = { foo: function() {} };
env.spyOn(spiedOn, 'foo');
const spyObj = env.createSpyObj('spyObj', ['foo']);
const spiedOnAllFuncs = { foo: function() {} };
env.spyOnAllFunctions(spiedOnAllFuncs);
for (spy of [
createSpySpy,
spiedOn.foo,
spyObj.foo,
spiedOnAllFuncs.foo
]) {
spy.and.returnValue('default strategy');
spy.withArgs(42).and.returnValue('custom strategy');
}
env.addCustomEqualityTester(function(a, b) {
if ((a === 'x' && b === 42) || (a === 42 && b === 'x')) {
return true;
}
});
env
.expect(createSpySpy('x'))
.withContext('createSpy')
.toEqual('custom strategy');
env
.expect(spiedOn.foo('x'))
.withContext('spyOn')
.toEqual('custom strategy');
env
.expect(spyObj.foo('x'))
.withContext('createSpyObj')
.toEqual('custom strategy');
env
.expect(spiedOnAllFuncs.foo('x'))
.withContext('spyOnAllFunctions')
.toEqual('custom strategy');
});
let failedExpectations;
env.addReporter({
specDone: r => (failedExpectations = r.failedExpectations)
});
await env.execute();
expect(failedExpectations).toEqual([]);
});
});

View File

@@ -327,12 +327,18 @@ getJasmineRequireObj().Env = function(j$) {
};
var makeMatchersUtil = function() {
var customEqualityTesters =
runnableResources[currentRunnable().id].customEqualityTesters;
return new j$.MatchersUtil({
customTesters: customEqualityTesters,
pp: makePrettyPrinter()
});
const cr = currentRunnable();
if (cr) {
const customEqualityTesters =
runnableResources[cr.id].customEqualityTesters;
return new j$.MatchersUtil({
customTesters: customEqualityTesters,
pp: makePrettyPrinter()
});
} else {
return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ });
}
};
var expectationFactory = function(actual, spec) {
@@ -863,7 +869,8 @@ getJasmineRequireObj().Env = function(j$) {
}
return undefined;
}
},
makeMatchersUtil
);
var spyRegistry = new j$.SpyRegistry({

View File

@@ -7,11 +7,6 @@ getJasmineRequireObj().Spy = function(j$) {
};
})();
var matchersUtil = new j$.MatchersUtil({
customTesters: [],
pp: j$.makePrettyPrinter()
});
/**
* @classdesc _Note:_ Do not construct this directly. Use {@link spyOn},
* {@link spyOnProperty}, {@link jasmine.createSpy}, or
@@ -19,19 +14,24 @@ getJasmineRequireObj().Spy = function(j$) {
* @class Spy
* @hideconstructor
*/
function Spy(name, originalFn, customStrategies, defaultStrategyFn) {
function Spy(name, matchersUtil, optionals) {
const { originalFn, customStrategies, defaultStrategyFn } = optionals || {};
var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
wrapper = makeFunc(numArgs, function(context, args, invokeNew) {
return spy(context, args, invokeNew);
}),
strategyDispatcher = new SpyStrategyDispatcher({
name: name,
fn: originalFn,
getSpy: function() {
return wrapper;
strategyDispatcher = new SpyStrategyDispatcher(
{
name: name,
fn: originalFn,
getSpy: function() {
return wrapper;
},
customStrategies: customStrategies
},
customStrategies: customStrategies
}),
matchersUtil
),
callTracker = new j$.CallTracker(),
spy = function(context, args, invokeNew) {
/**
@@ -143,11 +143,11 @@ getJasmineRequireObj().Spy = function(j$) {
return wrapper;
}
function SpyStrategyDispatcher(strategyArgs) {
function SpyStrategyDispatcher(strategyArgs, matchersUtil) {
var baseStrategy = new j$.SpyStrategy(strategyArgs);
var argsStrategies = new StrategyDict(function() {
return new j$.SpyStrategy(strategyArgs);
});
}, matchersUtil);
this.and = baseStrategy;
@@ -176,9 +176,10 @@ getJasmineRequireObj().Spy = function(j$) {
};
}
function StrategyDict(strategyFactory) {
function StrategyDict(strategyFactory, matchersUtil) {
this.strategies = [];
this.strategyFactory = strategyFactory;
this.matchersUtil = matchersUtil;
}
StrategyDict.prototype.any = function() {
@@ -203,7 +204,7 @@ getJasmineRequireObj().Spy = function(j$) {
var i;
for (i = 0; i < this.strategies.length; i++) {
if (matchersUtil.equals(args, this.strategies[i].args)) {
if (this.matchersUtil.equals(args, this.strategies[i].args)) {
return this.strategies[i].strategy;
}
}

View File

@@ -1,14 +1,17 @@
getJasmineRequireObj().SpyFactory = function(j$) {
function SpyFactory(getCustomStrategies, getDefaultStrategyFn) {
function SpyFactory(
getCustomStrategies,
getDefaultStrategyFn,
getMatchersUtil
) {
var self = this;
this.createSpy = function(name, originalFn) {
return j$.Spy(
name,
return j$.Spy(name, getMatchersUtil(), {
originalFn,
getCustomStrategies(),
getDefaultStrategyFn()
);
customStrategies: getCustomStrategies(),
defaultStrategyFn: getDefaultStrategyFn()
});
};
this.createSpyObj = function(baseName, methodNames, propertyNames) {