From 223924a7a1eff78ad57a575fc98c163664a44f7a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 21 Sep 2019 11:37:16 -0700 Subject: [PATCH 1/3] Fixed matchersUtil.contains test to fail correctly --- spec/core/matchers/matchersUtilSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 9dd42ce5..570f8f20 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -164,7 +164,7 @@ describe("matchersUtil", function() { expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true); }); - + it("passes for equivalent Promises (GitHub issue #1314)", function() { if (typeof Promise === 'undefined') { return; } @@ -620,7 +620,7 @@ describe("matchersUtil", function() { it("uses custom equality testers if passed in and actual is an Array", function() { var customTester = function(a, b) {return true;}; - expect(jasmineUnderTest.matchersUtil.contains([1, 2], 2, [customTester])).toBe(true); + expect(jasmineUnderTest.matchersUtil.contains([1, 2], 3, [customTester])).toBe(true); }); it("fails when actual is undefined", function() { From 795a80ec6663c496699e7f31bc70f13c13b5a256 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 22 Sep 2019 12:07:23 -0700 Subject: [PATCH 2/3] Added integration tests for asymmetric equality testers --- .../AsymmetricEqualityTestersSpec.js | 222 ++++++++++++++++++ spec/core/integration/MatchersSpec.js | 27 ++- spec/helpers/checkForMap.js | 6 +- spec/helpers/checkForSet.js | 6 +- 4 files changed, 249 insertions(+), 12 deletions(-) create mode 100644 spec/core/integration/AsymmetricEqualityTestersSpec.js diff --git a/spec/core/integration/AsymmetricEqualityTestersSpec.js b/spec/core/integration/AsymmetricEqualityTestersSpec.js new file mode 100644 index 00000000..1ccf2801 --- /dev/null +++ b/spec/core/integration/AsymmetricEqualityTestersSpec.js @@ -0,0 +1,222 @@ +describe('Asymmetric equality testers (Integration)', function () { + function verifyPasses(expectations, setup) { + it('passes', function (done) { + var env = new jasmineUnderTest.Env(); + env.it('a spec', function () { + expectations(env); + }); + + var specExpectations = function (result) { + expect(result.status).toEqual('passed'); + expect(result.passedExpectations.length) + .withContext('Number of passed expectations') + .toEqual(1); + expect(result.failedExpectations.length) + .withContext('Number of failed expectations') + .toEqual(0); + expect(result.failedExpectations[0] && result.failedExpectations[0].message) + .withContext('Failure message') + .toBeUndefined(); + }; + + env.addReporter({specDone: specExpectations, jasmineDone: done}); + env.execute(); + }); + } + + function verifyFails(expectations) { + it('fails', function (done) { + var env = new jasmineUnderTest.Env(); + env.it('a spec', function () { + expectations(env); + }); + + var specExpectations = function (result) { + expect(result.status).toEqual('failed'); + expect(result.failedExpectations.length) + .withContext('Number of failed expectations') + .toEqual(1); + expect(result.failedExpectations[0].message) + .withContext('Failed with a thrown error rather than a matcher failure') + .not.toMatch(/^Error: /); + expect(result.failedExpectations[0].matcherName).withContext('Matcher name') + .not.toEqual(''); + }; + + env.addReporter({specDone: specExpectations, jasmineDone: done}); + env.execute(); + }); + } + + describe('any', function () { + verifyPasses(function (env) { + env.expect(5).toEqual(jasmineUnderTest.any(Number)); + }); + + verifyFails(function (env) { + env.expect("five").toEqual(jasmineUnderTest.any(Number)); + }); + }); + + describe('anything', function () { + verifyPasses(function (env) { + env.expect('').toEqual(jasmineUnderTest.anything()); + }); + + verifyFails(function (env) { + env.expect(null).toEqual(jasmineUnderTest.anything()); + }); + }); + + describe('arrayContaining', function () { + verifyPasses(function (env) { + env.addCustomEqualityTester(function (a, b) { + return a.toString() === b.toString(); + }); + env.expect([1, 2, 3]).toEqual(jasmineUnderTest.arrayContaining(["2"])); + }); + + verifyFails(function (env) { + env.expect(null).toEqual(jasmineUnderTest.arrayContaining([2])); + }); + }); + + describe('arrayWithExactContents', function () { + verifyPasses(function (env) { + env.addCustomEqualityTester(function (a, b) { + return a.toString() === b.toString(); + }); + env.expect([1, 2]).toEqual(jasmineUnderTest.arrayWithExactContents(["2", "1"])); + }); + + verifyFails(function (env) { + env.expect([]).toEqual(jasmineUnderTest.arrayWithExactContents([2])); + }); + }); + + describe('empty', function () { + verifyPasses(function (env) { + env.expect([]).toEqual(jasmineUnderTest.empty()); + }); + + verifyFails(function (env) { + env.expect([1]).toEqual(jasmineUnderTest.empty()); + }); + }); + + describe('falsy', function () { + verifyPasses(function (env) { + env.expect(false).toEqual(jasmineUnderTest.falsy()); + }); + + verifyFails(function (env) { + env.expect(true).toEqual(jasmineUnderTest.falsy()); + }); + }); + + describe('mapContaining', function () { + if (jasmine.getEnv().hasFunctioningMaps()) { + verifyPasses(function (env) { + var actual = new Map(); + actual.set('a', "2"); + var expected = new Map(); + expected.set('a', 2); + + env.addCustomEqualityTester(function (a, b) { + return a.toString() === b.toString(); + }); + + env.expect(actual).toEqual(jasmineUnderTest.mapContaining(expected)); + }); + } else { + it('passes', function() { + jasmine.getEnv().pending('Browser has incomplete or missing support for Maps'); + }); + } + + if (jasmine.getEnv().hasFunctioningMaps()) { + verifyFails(function (env) { + env.expect('something').toEqual(jasmineUnderTest.mapContaining(new Map())); + }); + } else { + it('fails', function() { + jasmine.getEnv().pending('Browser has incomplete or missing support for Maps'); + }); + } + }); + + describe('notEmpty', function () { + verifyPasses(function (env) { + env.expect([1]).toEqual(jasmineUnderTest.notEmpty()); + }); + + verifyFails(function (env) { + env.expect([]).toEqual(jasmineUnderTest.notEmpty()); + }); + }); + + describe('objectContaining', function () { + verifyPasses(function (env) { + env.addCustomEqualityTester(function (a, b) { + return a.toString() === b.toString(); + }); + + env.expect({a: 1, b: 2}).toEqual(jasmineUnderTest.objectContaining({a: "1"})); + }); + + verifyFails(function (env) { + env.expect({}).toEqual(jasmineUnderTest.objectContaining({a: "1"})); + }); + }); + + describe('setContaining', function () { + if (jasmine.getEnv().hasFunctioningSets()) { + verifyPasses(function (env) { + var actual = new Set(); + actual.add("1"); + var expected = new Set(); + actual.add(1); + + env.addCustomEqualityTester(function (a, b) { + return a.toString() === b.toString(); + }); + + env.expect(actual).toEqual(jasmineUnderTest.setContaining(expected)); + }); + } else { + it('pases', function() { + jasmine.getEnv().pending('Browser has incomplete or missing support for Sets'); + }); + } + + if (jasmine.getEnv().hasFunctioningSets()) { + verifyFails(function (env) { + env.expect('something').toEqual(jasmineUnderTest.setContaining(new Set())); + }); + } else { + it('fails', function() { + jasmine.getEnv().pending('Browser has incomplete or missing support for Sets'); + }); + } + }); + + describe('stringMatching', function () { + verifyPasses(function (env) { + env.expect('foo').toEqual(jasmineUnderTest.stringMatching(/o/)); + }); + + verifyFails(function (env) { + env.expect('bar').toEqual(jasmineUnderTest.stringMatching(/o/)); + }); + }); + + describe('truthy', function () { + verifyPasses(function (env) { + env.expect(true).toEqual(jasmineUnderTest.truthy()); + }); + + verifyFails(function (env) { + env.expect(false).toEqual(jasmineUnderTest.truthy()); + }); + }); +}); diff --git a/spec/core/integration/MatchersSpec.js b/spec/core/integration/MatchersSpec.js index f75aae28..6f81ea04 100644 --- a/spec/core/integration/MatchersSpec.js +++ b/spec/core/integration/MatchersSpec.js @@ -261,7 +261,10 @@ describe('Matchers (Integration)', function() { describe('toBeResolvedTo', function() { verifyPassesAsync(function(env) { - return env.expectAsync(Promise.resolve('foo')).toBeResolvedTo('foo'); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); + return env.expectAsync(Promise.resolve('5')).toBeResolvedTo(5); }); verifyFailsAsync(function(env) { @@ -281,7 +284,10 @@ describe('Matchers (Integration)', function() { describe('toBeRejectedWith', function() { verifyPassesAsync(function(env) { - return env.expectAsync(Promise.reject('nope')).toBeRejectedWith('nope'); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); + return env.expectAsync(Promise.reject('5')).toBeRejectedWith(5); }); verifyFailsAsync(function(env) { @@ -331,7 +337,10 @@ describe('Matchers (Integration)', function() { describe('toContain', function() { verifyPasses(function(env) { - env.expect('foobar').toContain('oo'); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); + env.expect(['1', '2', '3']).toContain(2); }); verifyFails(function(env) { @@ -341,7 +350,10 @@ describe('Matchers (Integration)', function() { describe('toEqual', function() { verifyPasses(function(env) { - env.expect('a').toEqual('a'); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); + env.expect(5).toEqual('5'); }); verifyFails(function(env) { @@ -394,8 +406,11 @@ describe('Matchers (Integration)', function() { describe('toHaveBeenCalledWith', function() { verifyPasses(function(env) { var spy = env.createSpy(); - spy('foo'); - env.expect(spy).toHaveBeenCalledWith('foo'); + spy('5'); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); + env.expect(spy).toHaveBeenCalledWith(5); }); verifyFails(function(env) { diff --git a/spec/helpers/checkForMap.js b/spec/helpers/checkForMap.js index 64e32cdc..46e346a8 100644 --- a/spec/helpers/checkForMap.js +++ b/spec/helpers/checkForMap.js @@ -1,5 +1,5 @@ (function(env) { - function hasFunctioningMaps() { + env.hasFunctioningMaps = function() { if (typeof Map === 'undefined') { return false; } @@ -36,10 +36,10 @@ } catch (e) { return false; } - } + }; env.requireFunctioningMaps = function() { - if (!hasFunctioningMaps()) { + if (!env.hasFunctioningMaps()) { env.pending('Browser has incomplete or missing support for Maps'); } }; diff --git a/spec/helpers/checkForSet.js b/spec/helpers/checkForSet.js index 1be8de45..dacb06aa 100644 --- a/spec/helpers/checkForSet.js +++ b/spec/helpers/checkForSet.js @@ -1,5 +1,5 @@ (function(env) { - function hasFunctioningSets() { + env.hasFunctioningSets = function() { if (typeof Set === 'undefined') { return false; } @@ -40,10 +40,10 @@ } catch (e) { return false; } - } + }; env.requireFunctioningSets = function() { - if (!hasFunctioningSets()) { + if (!env.hasFunctioningSets()) { env.pending('Browser has incomplete or missing support for Sets'); } }; From a00f995c681a693c8117ce4ece96f186892a8d59 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 21 Sep 2019 14:18:32 -0700 Subject: [PATCH 3/3] Added integration tests for existing matcher interfaces --- .../integration/CustomAsyncMatchersSpec.js | 36 +++++++++++++++++ spec/core/integration/CustomMatchersSpec.js | 40 +++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/spec/core/integration/CustomAsyncMatchersSpec.js b/spec/core/integration/CustomAsyncMatchersSpec.js index 0849e42a..51ddef34 100644 --- a/spec/core/integration/CustomAsyncMatchersSpec.js +++ b/spec/core/integration/CustomAsyncMatchersSpec.js @@ -75,4 +75,40 @@ describe('Custom Async Matchers (Integration)', function() { env.addReporter({ specDone: specExpectations, jasmineDone: done }); env.execute(); }); + + // TODO: remove this in the next major release. + it("passes the jasmine utility and current equality testers to the matcher factory", function(done) { + jasmine.getEnv().requirePromises(); + + var matcherFactory = function () { + return { + compare: function () { + return Promise.resolve({pass: true}); + } + }; + }, + matcherFactorySpy = jasmine.createSpy("matcherFactorySpy").and.callFake(matcherFactory), + customEqualityFn = function () { + return true; + }; + + env.it("spec with expectation", function() { + env.addCustomEqualityTester(customEqualityFn); + env.addAsyncMatchers({ + toBeReal: matcherFactorySpy + }); + + return env.expectAsync(true).toBeReal(); + }); + + var specExpectations = function() { + expect(matcherFactorySpy).toHaveBeenCalledWith( + jasmine.any(jasmineUnderTest.MatchersUtil), + [customEqualityFn] + ); + }; + + env.addReporter({ specDone: specExpectations, jasmineDone: done }); + env.execute(); + }); }); diff --git a/spec/core/integration/CustomMatchersSpec.js b/spec/core/integration/CustomMatchersSpec.js index 17e66354..4bb0c352 100644 --- a/spec/core/integration/CustomMatchersSpec.js +++ b/spec/core/integration/CustomMatchersSpec.js @@ -81,6 +81,34 @@ describe("Custom Matchers (Integration)", function() { env.execute(); }); + it("supports asymmetric equality testers that take a list of custom equality testers", function(done) { + // TODO: remove this in the next major release. + env.it("spec using custom asymmetric equality tester", function() { + var customEqualityFn = function(a, b) { + if (a === 2 && b === "two") { + return true; + } + }; + var arrayWithFirstElement = function(sample) { + return { + asymmetricMatch: function (actual, customEqualityTesters) { + return jasmineUnderTest.matchersUtil.equals(sample, actual[0], customEqualityTesters); + } + }; + }; + + env.addCustomEqualityTester(customEqualityFn); + env.expect(["two"]).toEqual(arrayWithFirstElement(2)); + }); + + var specExpectations = function(result) { + expect(result.status).toEqual('passed'); + }; + + env.addReporter({ specDone: specExpectations, jasmineDone: done }); + env.execute(); + }); + it("displays an appropriate failure message if a custom equality matcher fails", function(done) { env.it("spec using custom equality matcher", function() { var customEqualityFn = function(a, b) { @@ -175,23 +203,27 @@ describe("Custom Matchers (Integration)", function() { env.execute(); }); - it("passes the jasmine utility and current equality matchers to the expectation factory", function(done) { + // TODO: remove this in the next major release. + it("passes the jasmine utility and current equality testers to the matcher factory", function(done) { var matcherFactory = function() { return { compare: function() { return {pass: true}; }}; }, - argumentSpy = jasmine.createSpy("argument spy").and.returnValue(matcherFactory), + matcherFactorySpy = jasmine.createSpy("matcherFactorySpy").and.callFake(matcherFactory), customEqualityFn = function() { return true; }; env.it("spec with expectation", function() { env.addCustomEqualityTester(customEqualityFn); env.addMatchers({ - toBeReal: argumentSpy + toBeReal: matcherFactorySpy }); env.expect(true).toBeReal(); }); var specExpectations = function() { - expect(argumentSpy).toHaveBeenCalledWith(jasmineUnderTest.matchersUtil, [customEqualityFn]); + expect(matcherFactorySpy).toHaveBeenCalledWith( + jasmine.any(jasmineUnderTest.MatchersUtil), + [customEqualityFn] + ); }; env.addReporter({ specDone: specExpectations, jasmineDone: done });