From e3c9a59c6c29bac357dd22116dd8fcb491f9d468 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 22 Sep 2021 11:19:59 -0700 Subject: [PATCH] Added a stringContaining asymmetric equality tester * Fixes #1923. --- lib/jasmine-core/jasmine.js | 37 +++++++++++++++++++ .../StringContainingSpec.js | 27 ++++++++++++++ .../AsymmetricEqualityTestersSpec.js | 10 +++++ .../asymmetric_equality/StringContaining.js | 24 ++++++++++++ src/core/base.js | 11 ++++++ src/core/requireCore.js | 1 + 6 files changed, 110 insertions(+) create mode 100644 spec/core/asymmetric_equality/StringContainingSpec.js create mode 100644 src/core/asymmetric_equality/StringContaining.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 67ae3805..a4390730 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -96,6 +96,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); + j$.StringContaining = jRequire.StringContaining(j$); j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); @@ -487,6 +488,17 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return new j$.StringMatching(expected); }; + /** + * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), + * that will succeed if the actual value is a `String` that contains the specified `String`. + * @name jasmine.stringContaining + * @function + * @param {String} expected + */ + j$.stringContaining = function(expected) { + return new j$.StringContaining(expected); + }; + /** * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains at least the elements in the sample. @@ -2926,6 +2938,31 @@ getJasmineRequireObj().SetContaining = function(j$) { return SetContaining; }; +getJasmineRequireObj().StringContaining = function(j$) { + function StringContaining(expected) { + if (!j$.isString_(expected)) { + throw new Error('Expected is not a String'); + } + + this.expected = expected; + } + + StringContaining.prototype.asymmetricMatch = function(other) { + if (!j$.isString_(other)) { + // Arrays, etc. don't match no matter what their indexOf returns. + return false; + } + + return other.indexOf(this.expected) !== -1; + }; + + StringContaining.prototype.jasmineToString = function() { + return ''; + }; + + return StringContaining; +}; + getJasmineRequireObj().StringMatching = function(j$) { function StringMatching(expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { diff --git a/spec/core/asymmetric_equality/StringContainingSpec.js b/spec/core/asymmetric_equality/StringContainingSpec.js new file mode 100644 index 00000000..aef1f48e --- /dev/null +++ b/spec/core/asymmetric_equality/StringContainingSpec.js @@ -0,0 +1,27 @@ +describe('StringContaining', function() { + it('searches for a provided substring when the expected is a String', function() { + var matcher = new jasmineUnderTest.StringContaining('foo'); + + expect(matcher.asymmetricMatch('barfoobaz')).toBe(true); + expect(matcher.asymmetricMatch('barbaz')).toBe(false); + }); + + it('raises an Error when the expected is not a String', function() { + expect(function() { + new jasmineUnderTest.StringContaining(/foo/); + }).toThrowError(/not a String/); + }); + + it('fails when the actual is not a String', function() { + var matcher = new jasmineUnderTest.StringContaining('x'); + expect(matcher.asymmetricMatch(['x'])).toBe(false); + }); + + it("jasmineToString's itself", function() { + var matching = new jasmineUnderTest.StringContaining('foo'); + + expect(matching.jasmineToString()).toEqual( + '' + ); + }); +}); diff --git a/spec/core/integration/AsymmetricEqualityTestersSpec.js b/spec/core/integration/AsymmetricEqualityTestersSpec.js index 3d12f15d..7ab1c77f 100644 --- a/spec/core/integration/AsymmetricEqualityTestersSpec.js +++ b/spec/core/integration/AsymmetricEqualityTestersSpec.js @@ -231,6 +231,16 @@ describe('Asymmetric equality testers (Integration)', function() { }); }); + describe('stringContaining', function() { + verifyPasses(function(env) { + env.expect('foo').toEqual(jasmineUnderTest.stringContaining('o')); + }); + + verifyFails(function(env) { + env.expect('bar').toEqual(jasmineUnderTest.stringContaining('o')); + }); + }); + describe('truthy', function() { verifyPasses(function(env) { env.expect(true).toEqual(jasmineUnderTest.truthy()); diff --git a/src/core/asymmetric_equality/StringContaining.js b/src/core/asymmetric_equality/StringContaining.js new file mode 100644 index 00000000..16f0c4e6 --- /dev/null +++ b/src/core/asymmetric_equality/StringContaining.js @@ -0,0 +1,24 @@ +getJasmineRequireObj().StringContaining = function(j$) { + function StringContaining(expected) { + if (!j$.isString_(expected)) { + throw new Error('Expected is not a String'); + } + + this.expected = expected; + } + + StringContaining.prototype.asymmetricMatch = function(other) { + if (!j$.isString_(other)) { + // Arrays, etc. don't match no matter what their indexOf returns. + return false; + } + + return other.indexOf(this.expected) !== -1; + }; + + StringContaining.prototype.jasmineToString = function() { + return ''; + }; + + return StringContaining; +}; diff --git a/src/core/base.js b/src/core/base.js index 89cd2b6e..fefa0479 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -319,6 +319,17 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return new j$.StringMatching(expected); }; + /** + * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), + * that will succeed if the actual value is a `String` that contains the specified `String`. + * @name jasmine.stringContaining + * @function + * @param {String} expected + */ + j$.stringContaining = function(expected) { + return new j$.StringContaining(expected); + }; + /** * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}), * that will succeed if the actual value is an `Array` that contains at least the elements in the sample. diff --git a/src/core/requireCore.js b/src/core/requireCore.js index df7f2571..c4c41859 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -74,6 +74,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); + j$.StringContaining = jRequire.StringContaining(j$); j$.UserContext = jRequire.UserContext(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer();