diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d88c3948..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "pages"] - path = pages - url = https://github.com/pivotal/jasmine.git diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index d4badddb..401d5df6 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -60,7 +60,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Any = jRequire.Any(j$); j$.Anything = jRequire.Anything(j$); j$.CallTracker = jRequire.CallTracker(j$); - j$.MockDate = jRequire.MockDate(); + j$.MockDate = jRequire.MockDate(j$); j$.getClearStack = jRequire.clearStack(j$); j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); @@ -89,6 +89,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(); @@ -367,7 +368,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is an instance of the specified class/constructor. * @name jasmine.any * @since 1.3.0 @@ -379,7 +380,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is not `null` and not `undefined`. * @name jasmine.anything * @since 2.2.0 @@ -390,7 +391,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is `true` or anything truthy. * @name jasmine.truthy * @since 3.1.0 @@ -401,7 +402,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is `null`, `undefined`, `0`, `false` or anything falsey. * @name jasmine.falsy * @since 3.1.0 @@ -412,7 +413,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is empty. * @name jasmine.empty * @since 3.1.0 @@ -423,7 +424,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is not empty. * @name jasmine.notEmpty * @since 3.1.0 @@ -434,7 +435,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared contains at least the keys and values. * @name jasmine.objectContaining * @since 1.3.0 @@ -446,7 +447,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 matches the `RegExp` or `String`. * @name jasmine.stringMatching * @since 2.2.0 @@ -458,7 +459,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 + * @since 3.10.0 + * @function + * @param {String} expected + */ + j$.stringContaining = function(expected) { + return new j$.StringContaining(expected); + }; + + /** + * Get an {@link AsymmetricEqualityTester}, 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. * @name jasmine.arrayContaining * @since 2.2.0 @@ -470,7 +483,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 all of the elements in the sample in any order. * @name jasmine.arrayWithExactContents * @since 2.8.0 @@ -482,7 +495,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 every key/value pair in the sample passes the deep equality comparison * with at least one key/value pair in the actual value being compared * @name jasmine.mapContaining @@ -495,7 +508,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 every item in the sample passes the deep equality comparison * with at least one item in the actual value being compared * @name jasmine.setContaining @@ -659,11 +672,30 @@ getJasmineRequireObj().util = function(j$) { }; getJasmineRequireObj().Spec = function(j$) { + /** + * @interface Spec + * @see Configuration#specFilter + * @since 2.0.0 + */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; + /** + * The unique ID of this spec. + * @name Spec#id + * @readonly + * @type {string} + * @since 2.0.0 + */ this.id = attrs.id; + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + * @since 2.0.0 + */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -710,7 +742,8 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} - */ + * @since 2.0.0 +x */ this.result = { id: this.id, description: this.description, @@ -871,6 +904,13 @@ getJasmineRequireObj().Spec = function(j$) { return 'passed'; }; + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; @@ -1536,6 +1576,7 @@ getJasmineRequireObj().Env = function(j$) { * @function * @name Env#topSuite * @return {Suite} the root suite + * @since 2.0.0 */ this.topSuite = function() { return topSuite.metadata; @@ -1718,6 +1759,7 @@ getJasmineRequireObj().Env = function(j$) { * @typedef JasmineStartedInfo * @property {Int} totalSpecsDefined - The total number of specs defined in this suite. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. + * @since 2.0.0 */ reporter.jasmineStarted( { @@ -1756,6 +1798,7 @@ getJasmineRequireObj().Env = function(j$) { * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. + * @since 2.4.0 */ reporter.jasmineDone( { @@ -2726,6 +2769,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)) { @@ -2814,6 +2882,7 @@ getJasmineRequireObj().CallTracker = function(j$) { /** * Get the "this" object that was passed to a specific invocation of this spy. * @name Spy#calls#thisFor + * @since 3.8.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Object?} @@ -2975,6 +3044,7 @@ getJasmineRequireObj().Clock = function() { /** * @class Clock + * @since 1.3.0 * @classdesc Jasmine's mock clock is used when testing time dependent code.
* _Note:_ Do not construct this directly. You can get the current clock with * {@link jasmine.clock}. @@ -3701,6 +3771,7 @@ getJasmineRequireObj().Expectation = function(j$) { * Otherwise evaluate the matcher. * @member * @name async-matchers#already + * @since 3.8.0 * @type {async-matchers} * @example * await expectAsync(myPromise).already.toBeResolved(); @@ -5315,9 +5386,33 @@ getJasmineRequireObj().MatchersUtil = function(j$) { /** * @interface AsymmetricEqualityTester * @classdesc An asymmetric equality tester is an object that can match multiple - * objects. Examples include jasmine.any() and jasmine.stringMatching(). - * User-defined asymmetric equality testers can also be defined and used in - * expectations. + * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine + * includes a number of built-in asymmetric equality testers, such as + * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are + * also supported. + * + * Asymmetric equality testers work with any matcher, including user-defined + * custom matchers, that uses {@link MatchersUtil#equals} or + * {@link MatchersUtil#contains}. + * + * @example + * function numberDivisibleBy(divisor) { + * return { + * asymmetricMatch: function(n) { + * return typeof n === 'number' && n % divisor === 0; + * }, + * jasmineToString: function() { + * return ``; + * } + * }; + * } + * + * var actual = { + * n: 2, + * otherFields: "don't care" + * }; + * + * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)})); * @see custom_asymmetric_equality_testers * @since 2.0.0 */ @@ -6940,7 +7035,7 @@ getJasmineRequireObj().toThrowMatching = function(j$) { return toThrowMatching; }; -getJasmineRequireObj().MockDate = function() { +getJasmineRequireObj().MockDate = function(j$) { function MockDate(global) { var self = this; var currentTime = 0; @@ -6958,6 +7053,14 @@ getJasmineRequireObj().MockDate = function() { if (mockDate instanceof GlobalDate) { currentTime = mockDate.getTime(); } else { + if (!j$.util.isUndefined(mockDate)) { + j$.getEnv().deprecated( + 'The argument to jasmine.clock().mockDate(), if specified, ' + + 'should be a Date instance. Passing anything other than a Date ' + + 'will be treated as an error in a future release.' + ); + } + currentTime = new GlobalDate().getTime(); } @@ -9103,9 +9206,29 @@ getJasmineRequireObj().StackTrace = function(j$) { }; getJasmineRequireObj().Suite = function(j$) { + /** + * @interface Suite + * @see Env#topSuite + * @since 2.0.0 + */ function Suite(attrs) { + this.env = attrs.env; + /** + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} + * @since 2.0.0 + */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + * @since 2.0.0 + */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; @@ -9118,6 +9241,13 @@ getJasmineRequireObj().Suite = function(j$) { this.beforeAllFns = []; this.afterAllFns = []; this.timer = attrs.timer || new j$.Timer(); + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + * @since 2.0.0 + */ this.children = []; /** @@ -9130,6 +9260,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} + * @since 2.0.0 */ this.result = { id: this.id, @@ -9155,6 +9286,13 @@ getJasmineRequireObj().Suite = function(j$) { return this.asyncExpectationFactory(actual, this); }; + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ Suite.prototype.getFullName = function() { var fullName = []; for ( diff --git a/spec/core/ClockSpec.js b/spec/core/ClockSpec.js index 2aba566b..126fe8ca 100644 --- a/spec/core/ClockSpec.js +++ b/spec/core/ClockSpec.js @@ -950,6 +950,28 @@ describe('Clock (acceptance)', function() { expect(timeoutDate).toEqual(baseTime.getTime() + 150); }); + it('logs a deprecation when mockDate is called with a non-Date', function() { + var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), + global = { Date: Date }, + mockDate = new jasmineUnderTest.MockDate(global), + clock = new jasmineUnderTest.Clock( + { setTimeout: setTimeout }, + function() { + return delayedFunctionScheduler; + }, + mockDate + ), + env = jasmineUnderTest.getEnv(); + + spyOn(env, 'deprecated'); + clock.mockDate(12345); + expect(env.deprecated).toHaveBeenCalledWith( + 'The argument to jasmine.clock().mockDate(), if specified, should be ' + + 'a Date instance. Passing anything other than a Date will be ' + + 'treated as an error in a future release.' + ); + }); + it('mocks the Date object and updates the date per delayed function', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, 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 dff70d46..cf71329c 100644 --- a/spec/core/integration/AsymmetricEqualityTestersSpec.js +++ b/spec/core/integration/AsymmetricEqualityTestersSpec.js @@ -199,6 +199,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/CallTracker.js b/src/core/CallTracker.js index 128790fe..fa9ebeaa 100644 --- a/src/core/CallTracker.js +++ b/src/core/CallTracker.js @@ -52,6 +52,7 @@ getJasmineRequireObj().CallTracker = function(j$) { /** * Get the "this" object that was passed to a specific invocation of this spy. * @name Spy#calls#thisFor + * @since 3.8.0 * @function * @param {Integer} index The 0-based invocation index. * @return {Object?} diff --git a/src/core/Clock.js b/src/core/Clock.js index 30c1ca7a..1bb593e1 100644 --- a/src/core/Clock.js +++ b/src/core/Clock.js @@ -7,6 +7,7 @@ getJasmineRequireObj().Clock = function() { /** * @class Clock + * @since 1.3.0 * @classdesc Jasmine's mock clock is used when testing time dependent code.
* _Note:_ Do not construct this directly. You can get the current clock with * {@link jasmine.clock}. diff --git a/src/core/Env.js b/src/core/Env.js index be59c1e7..d1c92194 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -544,6 +544,7 @@ getJasmineRequireObj().Env = function(j$) { * @function * @name Env#topSuite * @return {Suite} the root suite + * @since 2.0.0 */ this.topSuite = function() { return topSuite.metadata; @@ -726,6 +727,7 @@ getJasmineRequireObj().Env = function(j$) { * @typedef JasmineStartedInfo * @property {Int} totalSpecsDefined - The total number of specs defined in this suite. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. + * @since 2.0.0 */ reporter.jasmineStarted( { @@ -764,6 +766,7 @@ getJasmineRequireObj().Env = function(j$) { * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. + * @since 2.4.0 */ reporter.jasmineDone( { diff --git a/src/core/Expectation.js b/src/core/Expectation.js index a92af848..4d34de0b 100644 --- a/src/core/Expectation.js +++ b/src/core/Expectation.js @@ -119,6 +119,7 @@ getJasmineRequireObj().Expectation = function(j$) { * Otherwise evaluate the matcher. * @member * @name async-matchers#already + * @since 3.8.0 * @type {async-matchers} * @example * await expectAsync(myPromise).already.toBeResolved(); diff --git a/src/core/MockDate.js b/src/core/MockDate.js index a0dd164c..e8738a44 100644 --- a/src/core/MockDate.js +++ b/src/core/MockDate.js @@ -1,4 +1,4 @@ -getJasmineRequireObj().MockDate = function() { +getJasmineRequireObj().MockDate = function(j$) { function MockDate(global) { var self = this; var currentTime = 0; @@ -16,6 +16,14 @@ getJasmineRequireObj().MockDate = function() { if (mockDate instanceof GlobalDate) { currentTime = mockDate.getTime(); } else { + if (!j$.util.isUndefined(mockDate)) { + j$.getEnv().deprecated( + 'The argument to jasmine.clock().mockDate(), if specified, ' + + 'should be a Date instance. Passing anything other than a Date ' + + 'will be treated as an error in a future release.' + ); + } + currentTime = new GlobalDate().getTime(); } diff --git a/src/core/Spec.js b/src/core/Spec.js index 8a0299cc..9c85902e 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -1,9 +1,28 @@ getJasmineRequireObj().Spec = function(j$) { + /** + * @interface Spec + * @see Configuration#specFilter + * @since 2.0.0 + */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; + /** + * The unique ID of this spec. + * @name Spec#id + * @readonly + * @type {string} + * @since 2.0.0 + */ this.id = attrs.id; + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + * @since 2.0.0 + */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -50,7 +69,8 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} - */ + * @since 2.0.0 +x */ this.result = { id: this.id, description: this.description, @@ -211,6 +231,13 @@ getJasmineRequireObj().Spec = function(j$) { return 'passed'; }; + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 7ed92190..bf182680 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,7 +1,27 @@ getJasmineRequireObj().Suite = function(j$) { + /** + * @interface Suite + * @see Env#topSuite + * @since 2.0.0 + */ function Suite(attrs) { + this.env = attrs.env; + /** + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} + * @since 2.0.0 + */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + * @since 2.0.0 + */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; @@ -14,6 +34,13 @@ getJasmineRequireObj().Suite = function(j$) { this.beforeAllFns = []; this.afterAllFns = []; this.timer = attrs.timer || new j$.Timer(); + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + * @since 2.0.0 + */ this.children = []; /** @@ -26,6 +53,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} + * @since 2.0.0 */ this.result = { id: this.id, @@ -51,6 +79,13 @@ getJasmineRequireObj().Suite = function(j$) { return this.asyncExpectationFactory(actual, this); }; + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ Suite.prototype.getFullName = function() { var fullName = []; for ( 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 983e1602..1e52ebc3 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -206,7 +206,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is an instance of the specified class/constructor. * @name jasmine.any * @since 1.3.0 @@ -218,7 +218,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is not `null` and not `undefined`. * @name jasmine.anything * @since 2.2.0 @@ -229,7 +229,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is `true` or anything truthy. * @name jasmine.truthy * @since 3.1.0 @@ -240,7 +240,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is `null`, `undefined`, `0`, `false` or anything falsey. * @name jasmine.falsy * @since 3.1.0 @@ -251,7 +251,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is empty. * @name jasmine.empty * @since 3.1.0 @@ -262,7 +262,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared is not empty. * @name jasmine.notEmpty * @since 3.1.0 @@ -273,7 +273,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 being compared contains at least the keys and values. * @name jasmine.objectContaining * @since 1.3.0 @@ -285,7 +285,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 matches the `RegExp` or `String`. * @name jasmine.stringMatching * @since 2.2.0 @@ -297,7 +297,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 + * @since 3.10.0 + * @function + * @param {String} expected + */ + j$.stringContaining = function(expected) { + return new j$.StringContaining(expected); + }; + + /** + * Get an {@link AsymmetricEqualityTester}, 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. * @name jasmine.arrayContaining * @since 2.2.0 @@ -309,7 +321,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 all of the elements in the sample in any order. * @name jasmine.arrayWithExactContents * @since 2.8.0 @@ -321,7 +333,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 every key/value pair in the sample passes the deep equality comparison * with at least one key/value pair in the actual value being compared * @name jasmine.mapContaining @@ -334,7 +346,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { }; /** - * 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}), + * Get an {@link AsymmetricEqualityTester}, 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 every item in the sample passes the deep equality comparison * with at least one item in the actual value being compared * @name jasmine.setContaining diff --git a/src/core/matchers/matchersUtil.js b/src/core/matchers/matchersUtil.js index 1650b64f..9c9a2c36 100644 --- a/src/core/matchers/matchersUtil.js +++ b/src/core/matchers/matchersUtil.js @@ -625,9 +625,33 @@ getJasmineRequireObj().MatchersUtil = function(j$) { /** * @interface AsymmetricEqualityTester * @classdesc An asymmetric equality tester is an object that can match multiple - * objects. Examples include jasmine.any() and jasmine.stringMatching(). - * User-defined asymmetric equality testers can also be defined and used in - * expectations. + * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine + * includes a number of built-in asymmetric equality testers, such as + * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are + * also supported. + * + * Asymmetric equality testers work with any matcher, including user-defined + * custom matchers, that uses {@link MatchersUtil#equals} or + * {@link MatchersUtil#contains}. + * + * @example + * function numberDivisibleBy(divisor) { + * return { + * asymmetricMatch: function(n) { + * return typeof n === 'number' && n % divisor === 0; + * }, + * jasmineToString: function() { + * return `
`; + * } + * }; + * } + * + * var actual = { + * n: 2, + * otherFields: "don't care" + * }; + * + * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)})); * @see custom_asymmetric_equality_testers * @since 2.0.0 */ diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 15094305..a185bd47 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -38,7 +38,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Any = jRequire.Any(j$); j$.Anything = jRequire.Anything(j$); j$.CallTracker = jRequire.CallTracker(j$); - j$.MockDate = jRequire.MockDate(); + j$.MockDate = jRequire.MockDate(j$); j$.getClearStack = jRequire.clearStack(j$); j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); @@ -67,6 +67,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();