Merge branch 'main' of https://github.com/nitobuendia/jasmine
* Adds toHaveSpyInteractions matcher * Merges #1959 from @nitobuenida * Fixes #1568
This commit is contained in:
@@ -152,6 +152,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
|
||||
'toHaveBeenCalledTimes',
|
||||
'toHaveBeenCalledWith',
|
||||
'toHaveClass',
|
||||
'toHaveSpyInteractions',
|
||||
'toMatch',
|
||||
'toThrow',
|
||||
'toThrowError',
|
||||
@@ -6930,6 +6931,81 @@ getJasmineRequireObj().toHaveSize = function(j$) {
|
||||
return toHaveSize;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().toHaveSpyInteractions = function(j$) {
|
||||
var getErrorMsg = j$.formatErrorMsg(
|
||||
'<toHaveSpyInteractions>',
|
||||
'expect(<spyObj>).toHaveSpyInteractions()'
|
||||
);
|
||||
|
||||
/**
|
||||
* {@link expect} the actual (a {@link SpyObj}) spies to have been called.
|
||||
* @function
|
||||
* @name matchers#toHaveSpyInteractions
|
||||
* @example
|
||||
* expect(mySpyObj).toHaveSpyInteractions();
|
||||
* expect(mySpyObj).not.toHaveSpyInteractions();
|
||||
*/
|
||||
function toHaveSpyInteractions(matchersUtil) {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
var result = {};
|
||||
|
||||
if (!j$.isObject_(actual)) {
|
||||
throw new Error(
|
||||
getErrorMsg('Expected a spy object, but got ' + typeof actual + '.')
|
||||
);
|
||||
}
|
||||
|
||||
if (arguments.length > 1) {
|
||||
throw new Error(getErrorMsg('Does not take arguments'));
|
||||
}
|
||||
|
||||
result.pass = false;
|
||||
let hasSpy = false;
|
||||
const calledSpies = [];
|
||||
for (const spy of Object.values(actual)) {
|
||||
if (!j$.isSpy(spy)) continue;
|
||||
hasSpy = true;
|
||||
|
||||
if (spy.calls.any()) {
|
||||
result.pass = true;
|
||||
calledSpies.push([spy.and.identity, spy.calls.count()]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSpy) {
|
||||
throw new Error(
|
||||
getErrorMsg(
|
||||
'Expected a spy object with spies, but object has no spies.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let resultMessage;
|
||||
if (result.pass) {
|
||||
resultMessage =
|
||||
'Expected spy object spies not to have been called, ' +
|
||||
'but the following spies were called: ';
|
||||
resultMessage += calledSpies
|
||||
.map(([spyName, spyCount]) => {
|
||||
return `${spyName} called ${spyCount} time(s)`;
|
||||
})
|
||||
.join(', ');
|
||||
} else {
|
||||
resultMessage =
|
||||
'Expected spy object spies to have been called, ' +
|
||||
'but no spies were called.';
|
||||
}
|
||||
result.message = resultMessage;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return toHaveSpyInteractions;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().toMatch = function(j$) {
|
||||
var getErrorMsg = j$.formatErrorMsg(
|
||||
'<toMatch>',
|
||||
|
||||
22
spec/core/integration/MatchersSpec.js
Normal file → Executable file
22
spec/core/integration/MatchersSpec.js
Normal file → Executable file
@@ -625,6 +625,28 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('toHaveSpyInteractions', function() {
|
||||
let spyObj;
|
||||
beforeEach(function() {
|
||||
spyObj = env.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
spyObj.otherMethod = function() {};
|
||||
});
|
||||
|
||||
verifyPasses(function(env) {
|
||||
spyObj.spyA();
|
||||
env.expect(spyObj).toHaveSpyInteractions();
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
env.expect(spyObj).toHaveSpyInteractions();
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
spyObj.otherMethod();
|
||||
env.expect(spyObj).toHaveSpyInteractions();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toMatch', function() {
|
||||
verifyPasses(function(env) {
|
||||
env.expect('foo').toMatch(/oo$/);
|
||||
|
||||
115
spec/core/matchers/toHaveSpyInteractionsSpec.js
Executable file
115
spec/core/matchers/toHaveSpyInteractionsSpec.js
Executable file
@@ -0,0 +1,115 @@
|
||||
describe('toHaveSpyInteractions', function() {
|
||||
it('passes when there are spy interactions', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
|
||||
spyObj.spyA();
|
||||
|
||||
let result = matcher.compare(spyObj);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it('passes when there are multiple spy interactions', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
|
||||
spyObj.spyA();
|
||||
spyObj.spyB();
|
||||
spyObj.spyA();
|
||||
|
||||
let result = matcher.compare(spyObj);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it('fails when there are no spy interactions', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
|
||||
let result = matcher.compare(spyObj);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toContain(
|
||||
'Expected spy object spies to have been called'
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the right message is negated', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
|
||||
spyObj.spyA();
|
||||
|
||||
let result = matcher.compare(spyObj);
|
||||
expect(result.pass).toBe(true);
|
||||
expect(result.message).toContain(
|
||||
// Will be shown only on negate.
|
||||
'Expected spy object spies not to have been called'
|
||||
);
|
||||
});
|
||||
|
||||
it('fails when only non-observed spy object interactions are interacted', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
spyObj.otherMethod = function() {};
|
||||
|
||||
spyObj.otherMethod();
|
||||
|
||||
let result = matcher.compare(spyObj);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toContain(
|
||||
'Expected spy object spies to have been called'
|
||||
);
|
||||
});
|
||||
|
||||
it(`throws an error if a non-object is passed`, function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(true);
|
||||
}).toThrowError(Error, /Expected a spy object, but got/);
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(123);
|
||||
}).toThrowError(Error, /Expected a spy object, but got/);
|
||||
|
||||
expect(function() {
|
||||
matcher.compare('string');
|
||||
}).toThrowError(Error, /Expected a spy object, but got/);
|
||||
});
|
||||
|
||||
it('throws an error if arguments are passed', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
let spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['spyA', 'spyB']);
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(spyObj, 'an argument');
|
||||
}).toThrowError(Error, /Does not take arguments/);
|
||||
});
|
||||
|
||||
it('throws an error if the spy object has no spies', function() {
|
||||
let matcher = jasmineUnderTest.matchers.toHaveSpyInteractions();
|
||||
const spyObj = jasmineUnderTest
|
||||
.getEnv()
|
||||
.createSpyObj('NewClass', ['notSpy']);
|
||||
// Removing spy since spy objects cannot be created without spies.
|
||||
spyObj.notSpy = function() {};
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(spyObj);
|
||||
}).toThrowError(
|
||||
Error,
|
||||
/Expected a spy object with spies, but object has no spies/
|
||||
);
|
||||
});
|
||||
});
|
||||
1
src/core/matchers/requireMatchers.js
Normal file → Executable file
1
src/core/matchers/requireMatchers.js
Normal file → Executable file
@@ -27,6 +27,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
|
||||
'toHaveBeenCalledTimes',
|
||||
'toHaveBeenCalledWith',
|
||||
'toHaveClass',
|
||||
'toHaveSpyInteractions',
|
||||
'toMatch',
|
||||
'toThrow',
|
||||
'toThrowError',
|
||||
|
||||
74
src/core/matchers/toHaveSpyInteractions.js
Executable file
74
src/core/matchers/toHaveSpyInteractions.js
Executable file
@@ -0,0 +1,74 @@
|
||||
getJasmineRequireObj().toHaveSpyInteractions = function(j$) {
|
||||
var getErrorMsg = j$.formatErrorMsg(
|
||||
'<toHaveSpyInteractions>',
|
||||
'expect(<spyObj>).toHaveSpyInteractions()'
|
||||
);
|
||||
|
||||
/**
|
||||
* {@link expect} the actual (a {@link SpyObj}) spies to have been called.
|
||||
* @function
|
||||
* @name matchers#toHaveSpyInteractions
|
||||
* @example
|
||||
* expect(mySpyObj).toHaveSpyInteractions();
|
||||
* expect(mySpyObj).not.toHaveSpyInteractions();
|
||||
*/
|
||||
function toHaveSpyInteractions(matchersUtil) {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
var result = {};
|
||||
|
||||
if (!j$.isObject_(actual)) {
|
||||
throw new Error(
|
||||
getErrorMsg('Expected a spy object, but got ' + typeof actual + '.')
|
||||
);
|
||||
}
|
||||
|
||||
if (arguments.length > 1) {
|
||||
throw new Error(getErrorMsg('Does not take arguments'));
|
||||
}
|
||||
|
||||
result.pass = false;
|
||||
let hasSpy = false;
|
||||
const calledSpies = [];
|
||||
for (const spy of Object.values(actual)) {
|
||||
if (!j$.isSpy(spy)) continue;
|
||||
hasSpy = true;
|
||||
|
||||
if (spy.calls.any()) {
|
||||
result.pass = true;
|
||||
calledSpies.push([spy.and.identity, spy.calls.count()]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSpy) {
|
||||
throw new Error(
|
||||
getErrorMsg(
|
||||
'Expected a spy object with spies, but object has no spies.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let resultMessage;
|
||||
if (result.pass) {
|
||||
resultMessage =
|
||||
'Expected spy object spies not to have been called, ' +
|
||||
'but the following spies were called: ';
|
||||
resultMessage += calledSpies
|
||||
.map(([spyName, spyCount]) => {
|
||||
return `${spyName} called ${spyCount} time(s)`;
|
||||
})
|
||||
.join(', ');
|
||||
} else {
|
||||
resultMessage =
|
||||
'Expected spy object spies to have been called, ' +
|
||||
'but no spies were called.';
|
||||
}
|
||||
result.message = resultMessage;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return toHaveSpyInteractions;
|
||||
};
|
||||
Reference in New Issue
Block a user