Add custom async matchers

This commit is contained in:
Tony Brix
2019-07-08 15:13:06 -05:00
committed by Steve Gravrock
parent 008b80adc5
commit f77ee32c56
18 changed files with 876 additions and 49 deletions
+608 -12
View File
@@ -16,16 +16,6 @@ describe('AsyncExpectation', function() {
'expectAsync is unavailable because the environment does not support promises.'
);
});
it('throws an Error if the argument is not a promise', function() {
jasmine.getEnv().requirePromises();
function f() {
jasmineUnderTest.Expectation.asyncFactory({ actual: 'not a promise' });
}
expect(f).toThrowError(
'Expected expectAsync to be called with a promise.'
);
});
});
describe('#not', function() {
@@ -45,7 +35,7 @@ describe('AsyncExpectation', function() {
false,
jasmine.objectContaining({
passed: false,
message: 'Expected a promise not to be resolved.'
message: 'Expected [object Promise] not to be resolved.'
})
);
});
@@ -203,7 +193,8 @@ describe('AsyncExpectation', function() {
expect(addExpectationResult).toHaveBeenCalledWith(
false,
jasmine.objectContaining({
message: 'Some context: Expected a promise not to be resolved.'
message:
'Some context: Expected [object Promise] not to be resolved.'
})
);
});
@@ -235,6 +226,611 @@ describe('AsyncExpectation', function() {
});
});
describe('async matchers', function() {
it('makes custom matchers available to this expectation', function() {
var asyncMatchers = {
toFoo: function() {},
toBar: function() {}
},
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: asyncMatchers
});
expect(expectation.toFoo).toBeDefined();
expect(expectation.toBar).toBeDefined();
});
it("wraps matchers's compare functions, passing in matcher dependencies", function() {
jasmine.getEnv().requirePromises();
var fakeCompare = function() {
return Promise.resolve({ pass: true });
},
matcherFactory = jasmine
.createSpy('matcher')
.and.returnValue({ compare: fakeCompare }),
matchers = {
toFoo: matcherFactory
},
util = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
customEqualityTesters = ['a'],
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
util: util,
customAsyncMatchers: matchers,
customEqualityTesters: customEqualityTesters,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(matcherFactory).toHaveBeenCalledWith(
util,
customEqualityTesters
);
});
});
it("wraps matchers's compare functions, passing the actual and expected", function() {
jasmine.getEnv().requirePromises();
var fakeCompare = jasmine
.createSpy('fake-compare')
.and.returnValue(Promise.resolve({ pass: true })),
matchers = {
toFoo: function() {
return {
compare: fakeCompare
};
}
},
util = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation;
expectation = jasmineUnderTest.Expectation.asyncFactory({
util: util,
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(fakeCompare).toHaveBeenCalledWith('an actual', 'hello');
});
});
it('reports a passing result to the spec when the comparison passes', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: true });
}
};
}
},
util = {
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
util: util,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toFoo',
passed: true,
message: '',
error: undefined,
expected: 'hello',
actual: 'an actual',
errorForStack: errorWithStack
});
});
});
it('reports a failing result to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: false });
}
};
}
},
util = {
buildFailureMessage: function() {
return '';
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
util: util,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: '',
error: undefined,
errorForStack: errorWithStack
});
});
});
it('reports a failing result and a custom fail message to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: false,
message: 'I am a custom message'
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: false,
message: function() {
return 'I am a custom message';
}
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it('reports a passing result to the spec when the comparison fails for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: false });
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toFoo',
passed: true,
message: '',
error: undefined,
expected: 'hello',
actual: actual,
errorForStack: errorWithStack
});
});
});
it('reports a failing result to the spec when the comparison passes for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: true });
}
};
}
},
util = {
buildFailureMessage: function() {
return 'default message';
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
util: util,
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: actual,
message: 'default message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: true,
message: 'I am a custom message'
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: actual,
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: true });
},
negativeCompare: function() {
return Promise.resolve({ pass: true });
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toFoo',
passed: true,
expected: 'hello',
actual: actual,
message: '',
error: undefined,
errorForStack: errorWithStack
});
});
});
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({ pass: true });
},
negativeCompare: function() {
return Promise.resolve({
pass: false,
message: "I'm a custom message"
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = 'an actual',
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
customAsyncMatchers: matchers,
actual: 'an actual',
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: actual,
message: "I'm a custom message",
error: undefined,
errorForStack: errorWithStack
});
});
});
it('reports errorWithStack when a custom error message is returned', function() {
jasmine.getEnv().requirePromises();
var customError = new Error('I am a custom error');
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: false,
message: 'I am a custom message',
error: customError
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
});
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it("reports a custom message to the spec when a 'not' comparison fails", function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: true,
message: 'I am a custom message'
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
it("reports a custom message func to the spec when a 'not' comparison fails", function() {
jasmine.getEnv().requirePromises();
var matchers = {
toFoo: function() {
return {
compare: function() {
return Promise.resolve({
pass: true,
message: function() {
return 'I am a custom message';
}
});
}
};
}
},
addExpectationResult = jasmine.createSpy('addExpectationResult'),
errorWithStack = new Error('errorWithStack'),
expectation;
spyOn(jasmineUnderTest.util, 'errorWithStack').and.returnValue(
errorWithStack
);
expectation = jasmineUnderTest.Expectation.asyncFactory({
actual: 'an actual',
customAsyncMatchers: matchers,
addExpectationResult: addExpectationResult
}).not;
return expectation.toFoo('hello').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toFoo',
passed: false,
expected: 'hello',
actual: 'an actual',
message: 'I am a custom message',
error: undefined,
errorForStack: errorWithStack
});
});
});
});
function dummyPromise() {
return new Promise(function(resolve, reject) {});
}
@@ -0,0 +1,78 @@
describe('Custom Async Matchers (Integration)', function() {
var env;
beforeEach(function() {
env = new jasmineUnderTest.Env();
env.configure({random: false});
});
it('passes the spec if the custom async matcher passes', function(done) {
jasmine.getEnv().requirePromises();
env.it('spec using custom async matcher', function() {
env.addAsyncMatchers({
toBeReal: function() {
return { compare: function() { return Promise.resolve({ pass: true }); } };
}
});
return env.expectAsync(true).toBeReal();
});
var specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it('uses the negative compare function for a negative comparison, if provided', function(done) {
jasmine.getEnv().requirePromises();
env.it('spec with custom negative comparison matcher', function() {
env.addAsyncMatchers({
toBeReal: function() {
return {
compare: function() { return Promise.resolve({ pass: true }); },
negativeCompare: function() { return Promise.resolve({ pass: true }); }
};
}
});
return env.expectAsync(true).not.toBeReal();
});
var specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it('generates messages with the same rules as built in matchers absent a custom message', function(done) {
jasmine.getEnv().requirePromises();
env.it('spec with an expectation', function() {
env.addAsyncMatchers({
toBeReal: function() {
return {
compare: function() {
return Promise.resolve({ pass: false });
}
};
}
});
return env.expectAsync('a').toBeReal();
});
var specExpectations = function(result) {
expect(result.failedExpectations[0].message).toEqual("Expected 'a' to be real.");
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
});
+3 -3
View File
@@ -2432,20 +2432,20 @@ describe("Env integration", function() {
suiteDone: suiteDone,
jasmineDone: function(result) {
expect(result.failedExpectations).toEqual([jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
message: 'Expected [object Promise] to be rejected.'
})]);
expect(specDone).toHaveBeenCalledWith(jasmine.objectContaining({
description: 'has an async failure',
failedExpectations: [jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
message: 'Expected [object Promise] to be rejected.'
})]
}));
expect(suiteDone).toHaveBeenCalledWith(jasmine.objectContaining({
description: 'a suite',
failedExpectations: [jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
message: 'Expected [object Promise] to be rejected.'
})]
}));
@@ -20,4 +20,17 @@ describe('toBeRejected', function() {
expect(result).toEqual(jasmine.objectContaining({pass: false}));
});
});
it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejected(jasmineUnderTest.matchersUtil),
actual = 'not a promise';
function f() {
return matcher.compare(actual);
}
expect(f).toThrowError(
'Expected toBeRejected to be called on a promise.'
);
});
});
@@ -138,4 +138,17 @@ describe('#toBeRejectedWithError', function () {
}));
});
});
it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWithError(jasmineUnderTest.matchersUtil),
actual = 'not a promise';
function f() {
return matcher.compare(actual);
}
expect(f).toThrowError(
'Expected toBeRejectedWithError to be called on a promise.'
);
});
});
@@ -60,4 +60,17 @@ describe('#toBeRejectedWith', function () {
expect(result).toEqual(jasmine.objectContaining({pass: true}));
});
});
it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(jasmineUnderTest.matchersUtil),
actual = 'not a promise';
function f() {
return matcher.compare(actual);
}
expect(f).toThrowError(
'Expected toBeRejectedWith to be called on a promise.'
);
});
});
@@ -20,4 +20,17 @@ describe('toBeResolved', function() {
expect(result).toEqual(jasmine.objectContaining({pass: false}));
});
});
it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeResolved(jasmineUnderTest.matchersUtil),
actual = 'not a promise';
function f() {
return matcher.compare(actual);
}
expect(f).toThrowError(
'Expected toBeResolved to be called on a promise.'
);
});
});
@@ -63,4 +63,17 @@ describe('#toBeResolvedTo', function() {
expect(result).toEqual(jasmine.objectContaining({pass: true}));
});
});
it('fails if actual is not a promise', function() {
var matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(jasmineUnderTest.matchersUtil),
actual = 'not a promise';
function f() {
return matcher.compare(actual);
}
expect(f).toThrowError(
'Expected toBeResolvedTo to be called on a promise.'
);
});
});