From 6440ca434d0bf41b687bd49145c9fb480f17eb6d Mon Sep 17 00:00:00 2001 From: Chives Date: Sat, 29 Feb 2020 04:30:03 -0500 Subject: [PATCH 01/14] Add trailing newlines to example code --- lib/jasmine-core/example/src/Player.js | 2 +- lib/jasmine-core/example/src/Song.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/example/src/Player.js b/lib/jasmine-core/example/src/Player.js index fcce8268..11851966 100644 --- a/lib/jasmine-core/example/src/Player.js +++ b/lib/jasmine-core/example/src/Player.js @@ -19,4 +19,4 @@ Player.prototype.resume = function() { Player.prototype.makeFavorite = function() { this.currentlyPlayingSong.persistFavoriteStatus(true); -}; \ No newline at end of file +}; diff --git a/lib/jasmine-core/example/src/Song.js b/lib/jasmine-core/example/src/Song.js index a8a3f2dd..02527cb1 100644 --- a/lib/jasmine-core/example/src/Song.js +++ b/lib/jasmine-core/example/src/Song.js @@ -4,4 +4,4 @@ function Song() { Song.prototype.persistFavoriteStatus = function(value) { // something complicated throw new Error("not yet implemented"); -}; \ No newline at end of file +}; From 66fe69a149e89456700ae2c1a71623b1fd24a1ad Mon Sep 17 00:00:00 2001 From: Chives Date: Mon, 16 Mar 2020 03:15:58 -0400 Subject: [PATCH 02/14] Add test for resolveTo/rejectWith with empty parameters --- spec/core/SpyStrategySpec.js | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/spec/core/SpyStrategySpec.js b/spec/core/SpyStrategySpec.js index e861dc8b..5e454b64 100644 --- a/spec/core/SpyStrategySpec.js +++ b/spec/core/SpyStrategySpec.js @@ -140,6 +140,28 @@ describe('SpyStrategy', function() { .catch(done.fail); }); + it('allows an empty resolved promise to be returned', function(done) { + jasmine.getEnv().requirePromises(); + + var originalFn = jasmine.createSpy('original'), + getPromise = function() { + return Promise; + }, + spyStrategy = new jasmineUnderTest.SpyStrategy({ + fn: originalFn, + getPromise: getPromise + }); + + spyStrategy.resolveTo(); + spyStrategy + .exec() + .then(function(returnValue) { + expect(returnValue).toBe(); + done(); + }) + .catch(done.fail); + }); + it('fails if promises are not available', function() { var originalFn = jasmine.createSpy('original'), spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); @@ -176,6 +198,29 @@ describe('SpyStrategy', function() { .catch(done.fail); }); + it('allows an empty rejected promise to be returned', function(done) { + jasmine.getEnv().requirePromises(); + + var originalFn = jasmine.createSpy('original'), + getPromise = function() { + return Promise; + }, + spyStrategy = new jasmineUnderTest.SpyStrategy({ + fn: originalFn, + getPromise: getPromise + }); + + spyStrategy.rejectWith(); + spyStrategy + .exec() + .then(done.fail) + .catch(function(error) { + expect(error).toBe(); + done(); + }) + .catch(done.fail); + }); + it('allows a non-Error to be rejected', function(done) { jasmine.getEnv().requirePromises(); From c521b4d47c1931f53051f38285a2e8c614e455ab Mon Sep 17 00:00:00 2001 From: Francois Wauquier Date: Fri, 28 Feb 2020 18:18:14 +0100 Subject: [PATCH 03/14] toHaveSize --- lib/jasmine-core/jasmine.js | 154 +++++++++++++------------- package.json | 2 +- spec/core/integration/MatchersSpec.js | 73 +++++++++++- spec/core/matchers/toHaveSizeSpec.js | 21 ++++ src/core/matchers/requireMatchers.js | 1 + src/core/matchers/toHaveSize.js | 79 +++++++++++++ 6 files changed, 250 insertions(+), 80 deletions(-) create mode 100644 spec/core/matchers/toHaveSizeSpec.js create mode 100644 src/core/matchers/toHaveSize.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 0e6c91d4..4c17bf3c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -290,9 +290,9 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return typeof jasmineGlobal.Node !== 'undefined' ? obj instanceof jasmineGlobal.Node : obj !== null && - typeof obj === 'object' && - typeof obj.nodeType === 'number' && - typeof obj.nodeName === 'string'; + typeof obj === 'object' && + typeof obj.nodeType === 'number' && + typeof obj.nodeName === 'string'; // return obj.nodeType > 0; }; @@ -763,7 +763,7 @@ getJasmineRequireObj().Spec = function(j$) { onComplete: function() { onComplete( self.result.status === 'failed' && - new j$.StopExecutionError('spec failed') + new j$.StopExecutionError('spec failed') ); }, userContext: this.userContext() @@ -828,8 +828,8 @@ getJasmineRequireObj().Spec = function(j$) { this.result.failedExpectations.length > 0 || (failSpecWithNoExpectations && this.result.failedExpectations.length + - this.result.passedExpectations.length === - 0) + this.result.passedExpectations.length === + 0) ) { return 'failed'; } @@ -1170,7 +1170,7 @@ getJasmineRequireObj().Env = function(j$) { } runnableResources[ currentRunnable().id - ].defaultStrategyFn = defaultStrategyFn; + ].defaultStrategyFn = defaultStrategyFn; }; this.addSpyStrategy = function(name, fn) { @@ -2565,7 +2565,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) { for (var property in this.sample) { if (!hasProperty(other, property) || - !matchersUtil.equals(this.sample[property], other[property])) { + !matchersUtil.equals(this.sample[property], other[property])) { return false; } } @@ -3373,7 +3373,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { // scheduled in a funcToRun from forcing an extra iteration currentTime !== endTime && scheduledLookup[0] <= endTime - ); + ); // ran out of functions to call, but still time left on the clock if (currentTime !== endTime) { @@ -4108,24 +4108,24 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) { return actualPromise.then( function() { - return { - pass: false, - message: prefix(false) + ' but it was resolved.' - }; - }, - function(actualValue) { - if (matchersUtil.equals(actualValue, expectedValue)) { - return { - pass: true, - message: prefix(true) + '.' - }; - } else { return { pass: false, - message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' + message: prefix(false) + ' but it was resolved.' }; + }, + function(actualValue) { + if (matchersUtil.equals(actualValue, expectedValue)) { + return { + pass: true, + message: prefix(true) + '.' + }; + } else { + return { + pass: false, + message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' + }; + } } - } ); } }; @@ -4494,9 +4494,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { MatchersUtil.prototype.asymmetricMatch_ = function(a, b, aStack, bStack, customTesters, diffBuilder) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), - asymmetricB = j$.isAsymmetricEqualityTester_(b), - shim, - result; + asymmetricB = j$.isAsymmetricEqualityTester_(b), + shim, + result; if (asymmetricA === asymmetricB) { return undefined; @@ -4731,7 +4731,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // otherwise explicitly look up the mapKey in the other Map since we want keys with unique // obj identity (that are otherwise equal) to not match. if (j$.isAsymmetricEqualityTester_(mapKey) || j$.isAsymmetricEqualityTester_(cmpKey) && - this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { + this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { mapValueB = b.get(cmpKey); } else { mapValueB = b.get(mapKey); @@ -4800,9 +4800,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // or `Array`s from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && - isFunction(aCtor) && isFunction(bCtor) && - a instanceof aCtor && b instanceof bCtor && - !(aCtor instanceof aCtor && bCtor instanceof bCtor)) { + isFunction(aCtor) && isFunction(bCtor) && + a instanceof aCtor && b instanceof bCtor && + !(aCtor instanceof aCtor && bCtor instanceof bCtor)) { diffBuilder.recordMismatch(constructorsAreDifferentFormatter.bind(null, this.pp)); return false; @@ -4849,13 +4849,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) { function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { - var keys = []; - for (var key in o) { - if (j$.util.has(o, key)) { - keys.push(key); - } + var keys = []; + for (var key in o) { + if (j$.util.has(o, key)) { + keys.push(key); } - return keys; + } + return keys; })(obj); if (!isArray) { @@ -4863,7 +4863,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } if (allKeys.length === 0) { - return allKeys; + return allKeys; } var extraKeys = []; @@ -4882,10 +4882,10 @@ getJasmineRequireObj().MatchersUtil = function(j$) { function objectKeysAreDifferentFormatter(pp, actual, expected, path) { var missingProperties = j$.util.objectDifference(expected, actual), - extraProperties = j$.util.objectDifference(actual, expected), - missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), - extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), - messages = []; + extraProperties = j$.util.objectDifference(actual, expected), + missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), + extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), + messages = []; if (!path.depth()) { path = 'object'; @@ -5302,15 +5302,15 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) { return { compare: function(actual, expected) { var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : matchersUtil.pp(actual), - expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), - expectedMatcher, - pass; + expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), + expectedMatcher, + pass; try { - expectedMatcher = new j$.Any(expected); - pass = expectedMatcher.asymmetricMatch(actual); + expectedMatcher = new j$.Any(expected); + pass = expectedMatcher.asymmetricMatch(actual); } catch (error) { - throw new Error(usageError('Expected value is not a constructor function')); + throw new Error(usageError('Expected value is not a constructor function')); } if (pass) { @@ -5805,7 +5805,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { }); var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) { - var diffBuilder = new j$.DiffBuilder(); + var diffBuilder = new j$.DiffBuilder(); matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); return 'Call ' + callIx + ':\n' + diffBuilder.getMessage().replace(/^/mg, ' '); @@ -6050,7 +6050,7 @@ getJasmineRequireObj().toThrowError = function(j$) { function thrownDescription(thrown) { var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception', - thrownMessage = ''; + thrownMessage = ''; if (expected) { thrownMessage = ' with message ' + matchersUtil.pp(thrown.message); @@ -6157,10 +6157,10 @@ getJasmineRequireObj().toThrowMatching = function(j$) { if (predicate(thrown)) { return pass('Expected function not to throw an exception matching a predicate.'); } else { - return fail(function() { - return 'Expected function to throw an exception matching a predicate, ' + - 'but it threw ' + thrownDescription(thrown) + '.'; - }); + return fail(function() { + return 'Expected function to throw an exception matching a predicate, ' + + 'but it threw ' + thrownDescription(thrown) + '.'; + }); } } }; @@ -6378,8 +6378,8 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { } else if (j$.util.arrayContains(this.seen, value)) { this.emitScalar( '' + (j$.isArray_(value) ? 'Array' : 'Object') + + '>' ); } else if (j$.isArray_(value) || j$.isA_('Object', value)) { this.seen.push(value); @@ -6648,14 +6648,14 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { - var keys = []; - for (var key in o) { - if (j$.util.has(o, key)) { - keys.push(key); - } + var keys = []; + for (var key in o) { + if (j$.util.has(o, key)) { + keys.push(key); } - return keys; - })(obj); + } + return keys; + })(obj); if (!isArray) { return allKeys; @@ -6841,11 +6841,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { timeoutId = self.setTimeout(function() { var error = new Error( 'Timeout - Async function did not complete within ' + - timeoutInterval + - 'ms ' + - (queueableFn.timeout - ? '(custom timeout)' - : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') + timeoutInterval + + 'ms ' + + (queueableFn.timeout + ? '(custom timeout)' + : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') ); onException(error); next(); @@ -7563,10 +7563,10 @@ getJasmineRequireObj().Spy = function(j$) { if (argsStrategies.any() && !baseStrategy.isConfigured()) { throw new Error( "Spy '" + - strategyArgs.name + - "' received a call with arguments " + - j$.pp(Array.prototype.slice.call(args)) + - ' but all configured strategies specify other arguments.' + strategyArgs.name + + "' received a call with arguments " + + j$.pp(Array.prototype.slice.call(args)) + + ' but all configured strategies specify other arguments.' ); } else { strategy = baseStrategy; @@ -7789,8 +7789,8 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error( getErrorMsg( 'spyOn could not find an object to spy upon for ' + - propertyName + - '' + propertyName + + '' ) ); } @@ -7815,9 +7815,9 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error( getErrorMsg( 'Property ' + - propertyName + - ' does not have access type ' + - accessType + propertyName + + ' does not have access type ' + + accessType ) ); } @@ -7948,7 +7948,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) { if (!Promise) { throw new Error( name + - ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' + ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' ); } diff --git a/package.json b/package.json index bc602f6f..8db8eace 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "3.5.0", + "version": "3.5.1", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/spec/core/integration/MatchersSpec.js b/spec/core/integration/MatchersSpec.js index 7f19a95c..ec3404ff 100644 --- a/spec/core/integration/MatchersSpec.js +++ b/spec/core/integration/MatchersSpec.js @@ -47,6 +47,9 @@ describe('Matchers (Integration)', function() { expect(result.failedExpectations[0].message) .withContext('Failed with a thrown error rather than a matcher failure') .not.toMatch(/^Error: /); + expect(result.failedExpectations[0].message) + .withContext('Failed with a thrown type error rather than a matcher failure') + .not.toMatch(/^TypeError: /); expect(result.failedExpectations[0].matcherName).withContext('Matcher name') .not.toEqual(''); }; @@ -477,9 +480,9 @@ describe('Matchers (Integration)', function() { verifyFailsWithCustomObjectFormatters({ formatter: function(val) { if (val === 5) { - return "five" + return 'five'; } else if (val === 4) { - return "four" + return 'four'; } }, expectations: function(env) { @@ -489,6 +492,72 @@ describe('Matchers (Integration)', function() { }); }); + describe('toHaveSize', function() { + verifyPasses(function(env) { + env.expect(['a','b']).toHaveSize(2); + }); + verifyFails(function(env) { + env.expect(['a','b']).toHaveSize(1); + }); + + verifyPasses(function(env) { + env.expect({a: 1, b: 2}).toHaveSize(2); + }); + verifyFails(function(env) { + env.expect({a: 1, b: 2}).toHaveSize(1); + }); + + verifyPasses(function(env) { + env.expect({a: 1, b: 2, length: 5}).toHaveSize(5); + }); + verifyFails(function(env) { + env.expect({a: 1, b: 2, length: 5}).toHaveSize(1); + }); + + verifyPasses(function(env) { + env.expect('ab').toHaveSize(2); + }); + verifyFails(function(env) { + env.expect('ab').toHaveSize(1); + }); + + verifyPasses(function(env) { + var map = new Map(); + map.set('a',1); + map.set('b',2); + env.expect(map).toHaveSize(2); + }); + verifyFails(function(env) { + var map = new Map(); + map.set('a',1); + map.set('b',2); + env.expect(map).toHaveSize(1); + }); + + verifyPasses(function(env) { + var set = new Set(); + set.add('a'); + set.add('b'); + env.expect(set).toHaveSize(2); + }); + verifyFails(function(env) { + var set = new Set(); + set.add('a'); + set.add('b'); + env.expect(set).toHaveSize(1); + }); + + verifyFails(function(env) { + env.expect(new WeakSet()).toHaveSize(1); + }); + verifyFails(function(env) { + env.expect(new WeakMap()).toHaveSize(1); + }); + verifyFails(function(env) { + env.expect(new DataView(new ArrayBuffer(128))).toHaveSize(1); + }); + }); + describe('toHaveBeenCalled', function() { verifyPasses(function(env) { var spy = env.createSpy('spy'); diff --git a/spec/core/matchers/toHaveSizeSpec.js b/spec/core/matchers/toHaveSizeSpec.js new file mode 100644 index 00000000..08045432 --- /dev/null +++ b/spec/core/matchers/toHaveSizeSpec.js @@ -0,0 +1,21 @@ +describe('toHaveSize', function() { + 'use strict'; + + it('delegates to equals function', function() { + var matchersUtil = { + equals: jasmine.createSpy('delegated-equals').and.returnValue(true), + buildFailureMessage: function() { + return 'does not matter'; + }, + DiffBuilder: new jasmineUnderTest.DiffBuilder() + }, + matcher = jasmineUnderTest.matchers.toHaveSize(matchersUtil), + result; + + result = matcher.compare([1], 1); + + expect(matchersUtil.equals).toHaveBeenCalledWith(1, 1, jasmine.anything(), jasmine.anything()); + expect(result.pass).toBe(true); + }); + +}); diff --git a/src/core/matchers/requireMatchers.js b/src/core/matchers/requireMatchers.js index e8b1fd58..e0b256e5 100644 --- a/src/core/matchers/requireMatchers.js +++ b/src/core/matchers/requireMatchers.js @@ -20,6 +20,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) { 'toBeUndefined', 'toContain', 'toEqual', + 'toHaveSize', 'toHaveBeenCalled', 'toHaveBeenCalledBefore', 'toHaveBeenCalledTimes', diff --git a/src/core/matchers/toHaveSize.js b/src/core/matchers/toHaveSize.js new file mode 100644 index 00000000..b4ea9c55 --- /dev/null +++ b/src/core/matchers/toHaveSize.js @@ -0,0 +1,79 @@ +getJasmineRequireObj().toHaveSize = function(j$) { + /** + * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size. + * @function + * @name matchers#toHaveSize + * @since 3.5.1 + * @param {Object} expected - Expected size + * @example + * array = [1,2]; + * expect(array).toHaveSize(2); + */ + function toHaveSize(matchersUtil) { + return { + compare: function(actual, expected) { + var result = { + pass: false + }, + simpleEqualityTesters = [function(a, b) { + return a === b; + }], + diffBuilder = j$.DiffBuilder(); + + // Avoid misleading collections size matching + if (actual instanceof WeakSet + || actual instanceof WeakMap + || actual instanceof DataView) { + result.message = 'Cannot get size of ' + actual + '.'; + return result; + } + + // Ref https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects + if (Array.isArray(actual) || isArrayLike(actual)) + result.pass = matchersUtil.equals(actual.length, expected, simpleEqualityTesters, diffBuilder); + else if ( actual instanceof String || typeof actual === 'string') + result.pass = matchersUtil.equals(actual.length, expected, simpleEqualityTesters, diffBuilder); + else if (actual instanceof Set || actual instanceof Map) + result.pass = matchersUtil.equals(actual.size, expected, simpleEqualityTesters, diffBuilder); + // instanceof Object + else + result.pass = matchersUtil.equals(Object.keys(actual).length, expected, simpleEqualityTesters, diffBuilder); + + if(!result.pass) + result.message = diffBuilder.getMessage() ; + return result; + } + }; + } + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * From lodash + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * _.isArrayLike([1, 2, 3]); + * // => true + * _.isArrayLike(document.body.children); + * // => true + * _.isArrayLike('abc'); + * // => true + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + var MAX_SAFE_INTEGER = 9007199254740991; + function isLength(value) { + return (typeof value == 'number') && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + var functionTags = ['[object Function]','[object GeneratorFunction]','[object AsyncFunction]','[object Proxy]']; + function isFunction(functionToCheck) { + return functionToCheck && functionTags.indexOf( Object.prototype.toString.call(functionToCheck) ) != -1; + } + + return toHaveSize; +}; From ec3ebcb7bb2c8612e2b18662a0582859439ac56d Mon Sep 17 00:00:00 2001 From: Gregg Van Hove Date: Wed, 18 Mar 2020 08:12:40 -0700 Subject: [PATCH 04/14] Clean up toHaveSize --- lib/jasmine-core/jasmine.js | 200 ++++++++++++++++---------- spec/core/integration/MatchersSpec.js | 58 +------- spec/core/matchers/toHaveSizeSpec.js | 140 ++++++++++++++++-- src/core/matchers/toHaveSize.js | 63 ++------ 4 files changed, 263 insertions(+), 198 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 4c17bf3c..824036b1 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -144,6 +144,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) { 'toBeUndefined', 'toContain', 'toEqual', + 'toHaveSize', 'toHaveBeenCalled', 'toHaveBeenCalledBefore', 'toHaveBeenCalledTimes', @@ -290,9 +291,9 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return typeof jasmineGlobal.Node !== 'undefined' ? obj instanceof jasmineGlobal.Node : obj !== null && - typeof obj === 'object' && - typeof obj.nodeType === 'number' && - typeof obj.nodeName === 'string'; + typeof obj === 'object' && + typeof obj.nodeType === 'number' && + typeof obj.nodeName === 'string'; // return obj.nodeType > 0; }; @@ -763,7 +764,7 @@ getJasmineRequireObj().Spec = function(j$) { onComplete: function() { onComplete( self.result.status === 'failed' && - new j$.StopExecutionError('spec failed') + new j$.StopExecutionError('spec failed') ); }, userContext: this.userContext() @@ -828,8 +829,8 @@ getJasmineRequireObj().Spec = function(j$) { this.result.failedExpectations.length > 0 || (failSpecWithNoExpectations && this.result.failedExpectations.length + - this.result.passedExpectations.length === - 0) + this.result.passedExpectations.length === + 0) ) { return 'failed'; } @@ -1170,7 +1171,7 @@ getJasmineRequireObj().Env = function(j$) { } runnableResources[ currentRunnable().id - ].defaultStrategyFn = defaultStrategyFn; + ].defaultStrategyFn = defaultStrategyFn; }; this.addSpyStrategy = function(name, fn) { @@ -2565,7 +2566,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) { for (var property in this.sample) { if (!hasProperty(other, property) || - !matchersUtil.equals(this.sample[property], other[property])) { + !matchersUtil.equals(this.sample[property], other[property])) { return false; } } @@ -3373,7 +3374,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { // scheduled in a funcToRun from forcing an extra iteration currentTime !== endTime && scheduledLookup[0] <= endTime - ); + ); // ran out of functions to call, but still time left on the clock if (currentTime !== endTime) { @@ -4108,24 +4109,24 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) { return actualPromise.then( function() { + return { + pass: false, + message: prefix(false) + ' but it was resolved.' + }; + }, + function(actualValue) { + if (matchersUtil.equals(actualValue, expectedValue)) { + return { + pass: true, + message: prefix(true) + '.' + }; + } else { return { pass: false, - message: prefix(false) + ' but it was resolved.' + message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' }; - }, - function(actualValue) { - if (matchersUtil.equals(actualValue, expectedValue)) { - return { - pass: true, - message: prefix(true) + '.' - }; - } else { - return { - pass: false, - message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.' - }; - } } + } ); } }; @@ -4494,9 +4495,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { MatchersUtil.prototype.asymmetricMatch_ = function(a, b, aStack, bStack, customTesters, diffBuilder) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), - asymmetricB = j$.isAsymmetricEqualityTester_(b), - shim, - result; + asymmetricB = j$.isAsymmetricEqualityTester_(b), + shim, + result; if (asymmetricA === asymmetricB) { return undefined; @@ -4731,7 +4732,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // otherwise explicitly look up the mapKey in the other Map since we want keys with unique // obj identity (that are otherwise equal) to not match. if (j$.isAsymmetricEqualityTester_(mapKey) || j$.isAsymmetricEqualityTester_(cmpKey) && - this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { + this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) { mapValueB = b.get(cmpKey); } else { mapValueB = b.get(mapKey); @@ -4800,9 +4801,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // or `Array`s from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && - isFunction(aCtor) && isFunction(bCtor) && - a instanceof aCtor && b instanceof bCtor && - !(aCtor instanceof aCtor && bCtor instanceof bCtor)) { + isFunction(aCtor) && isFunction(bCtor) && + a instanceof aCtor && b instanceof bCtor && + !(aCtor instanceof aCtor && bCtor instanceof bCtor)) { diffBuilder.recordMismatch(constructorsAreDifferentFormatter.bind(null, this.pp)); return false; @@ -4849,13 +4850,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) { function keys(obj, isArray) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { - var keys = []; - for (var key in o) { - if (j$.util.has(o, key)) { - keys.push(key); + var keys = []; + for (var key in o) { + if (j$.util.has(o, key)) { + keys.push(key); + } } - } - return keys; + return keys; })(obj); if (!isArray) { @@ -4863,7 +4864,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } if (allKeys.length === 0) { - return allKeys; + return allKeys; } var extraKeys = []; @@ -4882,10 +4883,10 @@ getJasmineRequireObj().MatchersUtil = function(j$) { function objectKeysAreDifferentFormatter(pp, actual, expected, path) { var missingProperties = j$.util.objectDifference(expected, actual), - extraProperties = j$.util.objectDifference(actual, expected), - missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), - extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), - messages = []; + extraProperties = j$.util.objectDifference(actual, expected), + missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties), + extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties), + messages = []; if (!path.depth()) { path = 'object'; @@ -5302,15 +5303,15 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) { return { compare: function(actual, expected) { var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : matchersUtil.pp(actual), - expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), - expectedMatcher, - pass; + expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected), + expectedMatcher, + pass; try { - expectedMatcher = new j$.Any(expected); - pass = expectedMatcher.asymmetricMatch(actual); + expectedMatcher = new j$.Any(expected); + pass = expectedMatcher.asymmetricMatch(actual); } catch (error) { - throw new Error(usageError('Expected value is not a constructor function')); + throw new Error(usageError('Expected value is not a constructor function')); } if (pass) { @@ -5805,7 +5806,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { }); var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) { - var diffBuilder = new j$.DiffBuilder(); + var diffBuilder = new j$.DiffBuilder(); matchersUtil.equals(argsForCall, expectedArgs, diffBuilder); return 'Call ' + callIx + ':\n' + diffBuilder.getMessage().replace(/^/mg, ' '); @@ -5862,6 +5863,49 @@ getJasmineRequireObj().toHaveClass = function(j$) { return toHaveClass; }; +getJasmineRequireObj().toHaveSize = function(j$) { + /** + * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size. + * @function + * @name matchers#toHaveSize + * @since 3.5.1 + * @param {Object} expected - Expected size + * @example + * array = [1,2]; + * expect(array).toHaveSize(2); + */ + function toHaveSize() { + return { + compare: function(actual, expected) { + var result = { + pass: false + }; + + if (actual instanceof WeakSet || actual instanceof WeakMap || actual instanceof DataView) { + throw new Error('Cannot get size of ' + actual + '.'); + } + + if (actual instanceof Set || actual instanceof Map) { + result.pass = actual.size === expected; + } else if (isLength(actual.length)) { + result.pass = actual.length === expected; + } else { + result.pass = Object.keys(actual).length === expected; + } + + return result; + } + }; + } + + var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; + function isLength(value) { + return (typeof value == 'number') && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER; + } + + return toHaveSize; +}; + getJasmineRequireObj().toMatch = function(j$) { var getErrorMsg = j$.formatErrorMsg('', 'expect().toMatch( || )'); @@ -6050,7 +6094,7 @@ getJasmineRequireObj().toThrowError = function(j$) { function thrownDescription(thrown) { var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception', - thrownMessage = ''; + thrownMessage = ''; if (expected) { thrownMessage = ' with message ' + matchersUtil.pp(thrown.message); @@ -6157,10 +6201,10 @@ getJasmineRequireObj().toThrowMatching = function(j$) { if (predicate(thrown)) { return pass('Expected function not to throw an exception matching a predicate.'); } else { - return fail(function() { - return 'Expected function to throw an exception matching a predicate, ' + - 'but it threw ' + thrownDescription(thrown) + '.'; - }); + return fail(function() { + return 'Expected function to throw an exception matching a predicate, ' + + 'but it threw ' + thrownDescription(thrown) + '.'; + }); } } }; @@ -6378,8 +6422,8 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { } else if (j$.util.arrayContains(this.seen, value)) { this.emitScalar( '' + (j$.isArray_(value) ? 'Array' : 'Object') + + '>' ); } else if (j$.isArray_(value) || j$.isA_('Object', value)) { this.seen.push(value); @@ -6648,14 +6692,14 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) { var allKeys = Object.keys ? Object.keys(obj) : (function(o) { - var keys = []; - for (var key in o) { - if (j$.util.has(o, key)) { - keys.push(key); + var keys = []; + for (var key in o) { + if (j$.util.has(o, key)) { + keys.push(key); + } } - } - return keys; - })(obj); + return keys; + })(obj); if (!isArray) { return allKeys; @@ -6841,11 +6885,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { timeoutId = self.setTimeout(function() { var error = new Error( 'Timeout - Async function did not complete within ' + - timeoutInterval + - 'ms ' + - (queueableFn.timeout - ? '(custom timeout)' - : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') + timeoutInterval + + 'ms ' + + (queueableFn.timeout + ? '(custom timeout)' + : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)') ); onException(error); next(); @@ -7563,10 +7607,10 @@ getJasmineRequireObj().Spy = function(j$) { if (argsStrategies.any() && !baseStrategy.isConfigured()) { throw new Error( "Spy '" + - strategyArgs.name + - "' received a call with arguments " + - j$.pp(Array.prototype.slice.call(args)) + - ' but all configured strategies specify other arguments.' + strategyArgs.name + + "' received a call with arguments " + + j$.pp(Array.prototype.slice.call(args)) + + ' but all configured strategies specify other arguments.' ); } else { strategy = baseStrategy; @@ -7789,8 +7833,8 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error( getErrorMsg( 'spyOn could not find an object to spy upon for ' + - propertyName + - '' + propertyName + + '' ) ); } @@ -7815,9 +7859,9 @@ getJasmineRequireObj().SpyRegistry = function(j$) { throw new Error( getErrorMsg( 'Property ' + - propertyName + - ' does not have access type ' + - accessType + propertyName + + ' does not have access type ' + + accessType ) ); } @@ -7948,7 +7992,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) { if (!Promise) { throw new Error( name + - ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' + ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' ); } @@ -8724,5 +8768,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '3.5.0'; + return '3.5.1'; }; diff --git a/spec/core/integration/MatchersSpec.js b/spec/core/integration/MatchersSpec.js index ec3404ff..c1d2dd09 100644 --- a/spec/core/integration/MatchersSpec.js +++ b/spec/core/integration/MatchersSpec.js @@ -496,66 +496,10 @@ describe('Matchers (Integration)', function() { verifyPasses(function(env) { env.expect(['a','b']).toHaveSize(2); }); + verifyFails(function(env) { env.expect(['a','b']).toHaveSize(1); }); - - verifyPasses(function(env) { - env.expect({a: 1, b: 2}).toHaveSize(2); - }); - verifyFails(function(env) { - env.expect({a: 1, b: 2}).toHaveSize(1); - }); - - verifyPasses(function(env) { - env.expect({a: 1, b: 2, length: 5}).toHaveSize(5); - }); - verifyFails(function(env) { - env.expect({a: 1, b: 2, length: 5}).toHaveSize(1); - }); - - verifyPasses(function(env) { - env.expect('ab').toHaveSize(2); - }); - verifyFails(function(env) { - env.expect('ab').toHaveSize(1); - }); - - verifyPasses(function(env) { - var map = new Map(); - map.set('a',1); - map.set('b',2); - env.expect(map).toHaveSize(2); - }); - verifyFails(function(env) { - var map = new Map(); - map.set('a',1); - map.set('b',2); - env.expect(map).toHaveSize(1); - }); - - verifyPasses(function(env) { - var set = new Set(); - set.add('a'); - set.add('b'); - env.expect(set).toHaveSize(2); - }); - verifyFails(function(env) { - var set = new Set(); - set.add('a'); - set.add('b'); - env.expect(set).toHaveSize(1); - }); - - verifyFails(function(env) { - env.expect(new WeakSet()).toHaveSize(1); - }); - verifyFails(function(env) { - env.expect(new WeakMap()).toHaveSize(1); - }); - verifyFails(function(env) { - env.expect(new DataView(new ArrayBuffer(128))).toHaveSize(1); - }); }); describe('toHaveBeenCalled', function() { diff --git a/spec/core/matchers/toHaveSizeSpec.js b/spec/core/matchers/toHaveSizeSpec.js index 08045432..a1b4cccb 100644 --- a/spec/core/matchers/toHaveSizeSpec.js +++ b/spec/core/matchers/toHaveSizeSpec.js @@ -1,21 +1,135 @@ describe('toHaveSize', function() { 'use strict'; - it('delegates to equals function', function() { - var matchersUtil = { - equals: jasmine.createSpy('delegated-equals').and.returnValue(true), - buildFailureMessage: function() { - return 'does not matter'; - }, - DiffBuilder: new jasmineUnderTest.DiffBuilder() - }, - matcher = jasmineUnderTest.matchers.toHaveSize(matchersUtil), - result; + it('passes for an array whose length matches', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare([1, 2], 2); - result = matcher.compare([1], 1); - - expect(matchersUtil.equals).toHaveBeenCalledWith(1, 1, jasmine.anything(), jasmine.anything()); expect(result.pass).toBe(true); }); + it('fails for an array whose length does not match', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare([1, 2, 3], 2); + + expect(result.pass).toBe(false); + }); + + it('passes for an object with the proper number of keys', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare({a: 1, b: 2}, 2); + + expect(result.pass).toBe(true); + }); + + it('fails for an object with a different number of keys', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare({a: 1, b: 2}, 1); + + expect(result.pass).toBe(false); + }); + + it('passes for an object with an explicit `length` property that matches', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare({a: 1, b: 2, length: 5}, 5); + + expect(result.pass).toBe(true); + }); + + it('fails for an object with an explicit `length` property that does not match', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare({a: 1, b: 2, length: 5}, 1); + + expect(result.pass).toBe(false); + }); + + it('passes for a string whose length matches', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare('ab', 2); + + expect(result.pass).toBe(true); + }); + + it('fails for a string whose length does not match', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare('abc', 2); + + expect(result.pass).toBe(false); + }); + + it('passes for a Map whose length matches', function() { + jasmine.getEnv().requireFunctioningMaps(); + + var map = new Map(); + map.set('a',1); + map.set('b',2); + + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare(map, 2); + + expect(result.pass).toBe(true); + }); + + it('fails for a Map whose length does not match', function() { + jasmine.getEnv().requireFunctioningMaps(); + + var map = new Map(); + map.set('a',1); + map.set('b',2); + + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare(map, 1); + + expect(result.pass).toBe(false); + }); + + it('passes for a Set whose length matches', function() { + jasmine.getEnv().requireFunctioningSets(); + + var set = new Set(); + set.add('a'); + set.add('b'); + + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare(set, 2); + + expect(result.pass).toBe(true); + }); + + it('fails for a Set whose length does not match', function() { + jasmine.getEnv().requireFunctioningSets(); + + var set = new Set(); + set.add('a'); + set.add('b'); + + var matcher = jasmineUnderTest.matchers.toHaveSize(), + result = matcher.compare(set, 1); + + expect(result.pass).toBe(false); + }); + + it('throws an error for WeakSet', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(); + + expect(function() { + matcher.compare(new WeakSet(), 2); + }).toThrowError('Cannot get size of [object WeakSet].'); + }); + + it('throws an error for WeakMap', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(); + + expect(function() { + matcher.compare(new WeakMap(), 2); + }).toThrowError('Cannot get size of [object WeakMap].'); + }); + + it('throws an error for DataView', function() { + var matcher = jasmineUnderTest.matchers.toHaveSize(); + + expect(function() { + matcher.compare(new DataView(new ArrayBuffer(128)), 2); + }).toThrowError('Cannot get size of [object DataView].'); + }); }); diff --git a/src/core/matchers/toHaveSize.js b/src/core/matchers/toHaveSize.js index b4ea9c55..ae344ca9 100644 --- a/src/core/matchers/toHaveSize.js +++ b/src/core/matchers/toHaveSize.js @@ -9,70 +9,33 @@ getJasmineRequireObj().toHaveSize = function(j$) { * array = [1,2]; * expect(array).toHaveSize(2); */ - function toHaveSize(matchersUtil) { + function toHaveSize() { return { compare: function(actual, expected) { var result = { pass: false - }, - simpleEqualityTesters = [function(a, b) { - return a === b; - }], - diffBuilder = j$.DiffBuilder(); + }; - // Avoid misleading collections size matching - if (actual instanceof WeakSet - || actual instanceof WeakMap - || actual instanceof DataView) { - result.message = 'Cannot get size of ' + actual + '.'; - return result; + if (actual instanceof WeakSet || actual instanceof WeakMap || actual instanceof DataView) { + throw new Error('Cannot get size of ' + actual + '.'); } - // Ref https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects - if (Array.isArray(actual) || isArrayLike(actual)) - result.pass = matchersUtil.equals(actual.length, expected, simpleEqualityTesters, diffBuilder); - else if ( actual instanceof String || typeof actual === 'string') - result.pass = matchersUtil.equals(actual.length, expected, simpleEqualityTesters, diffBuilder); - else if (actual instanceof Set || actual instanceof Map) - result.pass = matchersUtil.equals(actual.size, expected, simpleEqualityTesters, diffBuilder); - // instanceof Object - else - result.pass = matchersUtil.equals(Object.keys(actual).length, expected, simpleEqualityTesters, diffBuilder); + if (actual instanceof Set || actual instanceof Map) { + result.pass = actual.size === expected; + } else if (isLength(actual.length)) { + result.pass = actual.length === expected; + } else { + result.pass = Object.keys(actual).length === expected; + } - if(!result.pass) - result.message = diffBuilder.getMessage() ; return result; } }; } - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * From lodash - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * _.isArrayLike([1, 2, 3]); - * // => true - * _.isArrayLike(document.body.children); - * // => true - * _.isArrayLike('abc'); - * // => true - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - var MAX_SAFE_INTEGER = 9007199254740991; + var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; function isLength(value) { - return (typeof value == 'number') && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - var functionTags = ['[object Function]','[object GeneratorFunction]','[object AsyncFunction]','[object Proxy]']; - function isFunction(functionToCheck) { - return functionToCheck && functionTags.indexOf( Object.prototype.toString.call(functionToCheck) ) != -1; + return (typeof value == 'number') && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER; } return toHaveSize; From 79d55216fcf17f17a6e05e32a5564a03508705bf Mon Sep 17 00:00:00 2001 From: Gregg Van Hove Date: Wed, 18 Mar 2020 08:57:44 -0700 Subject: [PATCH 05/14] Use internal type checks instead of `instanceof` to support browsers that don't include the types --- lib/jasmine-core/jasmine.js | 2 +- src/core/matchers/toHaveSize.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 824036b1..5f9e531e 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -5881,7 +5881,7 @@ getJasmineRequireObj().toHaveSize = function(j$) { pass: false }; - if (actual instanceof WeakSet || actual instanceof WeakMap || actual instanceof DataView) { + if (j$.isA_('WeakSet', actual) || j$.isA_('WeakMap', actual) || j$.isA_('DataView', actual)) { throw new Error('Cannot get size of ' + actual + '.'); } diff --git a/src/core/matchers/toHaveSize.js b/src/core/matchers/toHaveSize.js index ae344ca9..c0e84cb3 100644 --- a/src/core/matchers/toHaveSize.js +++ b/src/core/matchers/toHaveSize.js @@ -16,7 +16,7 @@ getJasmineRequireObj().toHaveSize = function(j$) { pass: false }; - if (actual instanceof WeakSet || actual instanceof WeakMap || actual instanceof DataView) { + if (j$.isA_('WeakSet', actual) || j$.isA_('WeakMap', actual) || j$.isA_('DataView', actual)) { throw new Error('Cannot get size of ' + actual + '.'); } From 9a7dfb15d2a52a80930445091e6ecba49a894f82 Mon Sep 17 00:00:00 2001 From: Alex Parloti Date: Thu, 2 Apr 2020 21:01:56 +0200 Subject: [PATCH 06/14] fix #26 fix #26 Returning false will cause 'zone.js' to invoke e.preventDefault(), preventing the page from reloading. --- src/html/HtmlReporter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 1c6478cf..24d3a404 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -321,9 +321,11 @@ jasmineRequire.HtmlReporter = function(j$) { find('.jasmine-failures-menu').onclick = function() { setMenuModeTo('jasmine-failure-list'); + return false; }; find('.jasmine-spec-list-menu').onclick = function() { setMenuModeTo('jasmine-spec-list'); + return false; }; setMenuModeTo('jasmine-failure-list'); From 6b213a958d0edb187e255286dead7828b7752d05 Mon Sep 17 00:00:00 2001 From: DCtheTall Date: Thu, 9 Apr 2020 15:13:33 -0400 Subject: [PATCH 07/14] Add expectAsync().toBePending() --- spec/core/matchers/async/toBePendingSpec.js | 51 +++++++++++++++++++++ src/core/matchers/async/toBePending.js | 25 ++++++++++ src/core/matchers/requireAsyncMatchers.js | 1 + 3 files changed, 77 insertions(+) create mode 100644 spec/core/matchers/async/toBePendingSpec.js create mode 100644 src/core/matchers/async/toBePending.js diff --git a/spec/core/matchers/async/toBePendingSpec.js b/spec/core/matchers/async/toBePendingSpec.js new file mode 100644 index 00000000..5aa4f428 --- /dev/null +++ b/spec/core/matchers/async/toBePendingSpec.js @@ -0,0 +1,51 @@ +describe('toBePending', function() { + it('passes if the actual promise is pending', function() { + jasmine.getEnv().requirePromises(); + + var matchersUtil = new jasmineUnderTest.MatchersUtil(), + matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), + actual = new Promise(function() {}); + + return matcher.compare(actual).then(function(result) { + expect(result).toEqual(jasmine.objectContaining({pass: true})); + }); + }); + + it('fails if the actual promise is resolved', function() { + jasmine.getEnv().requirePromises(); + + var matchersUtil = new jasmineUnderTest.MatchersUtil(), + matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), + actual = Promise.resolve(); + + return matcher.compare(actual).then(function(result) { + expect(result).toEqual(jasmine.objectContaining({pass: false})); + }); + }); + + it('fails if the actual promise is rejected', function() { + jasmine.getEnv().requirePromises(); + + var matchersUtil = new jasmineUnderTest.MatchersUtil(), + matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), + actual = Promise.reject(new Error('promise was rejected')); + + return matcher.compare(actual).then(function(result) { + expect(result).toEqual(jasmine.objectContaining({pass: false})); + }); + }); + + it('fails if actual is not a promise', function() { + var matchersUtil = new jasmineUnderTest.MatchersUtil(), + matcher = jasmineUnderTest.asyncMatchers.toBePending(matchersUtil), + actual = 'not a promise'; + + function f() { + return matcher.compare(actual); + } + + expect(f).toThrowError( + 'Expected toBePending to be called on a promise.' + ); + }); +}); \ No newline at end of file diff --git a/src/core/matchers/async/toBePending.js b/src/core/matchers/async/toBePending.js new file mode 100644 index 00000000..31059084 --- /dev/null +++ b/src/core/matchers/async/toBePending.js @@ -0,0 +1,25 @@ +getJasmineRequireObj().toBePending = function(j$) { + /** + * Expect a promise to be pending, ie. the promise is neither resolved nor rejected. + * @function + * @async + * @name async-matchers#toBePending + * @since 3.5.1 (should this be the next version or the version when it was added?) + * @example + * await expectAsync(aPromise).toBePending(); + */ + return function toBePending() { + return { + compare: function(actual) { + if (!j$.isPromiseLike(actual)) { + throw new Error('Expected toBePending to be called on a promise.'); + } + var want = {}; + return Promise.race([actual, Promise.resolve(want)]).then( + function(got) { return {pass: want === got}; }, + function() { return {pass: false}; } + ); + } + }; + }; +}; \ No newline at end of file diff --git a/src/core/matchers/requireAsyncMatchers.js b/src/core/matchers/requireAsyncMatchers.js index faa91c02..abe9b8ef 100644 --- a/src/core/matchers/requireAsyncMatchers.js +++ b/src/core/matchers/requireAsyncMatchers.js @@ -1,5 +1,6 @@ getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) { var availableMatchers = [ + 'toBePending', 'toBeResolved', 'toBeRejected', 'toBeResolvedTo', From 76a99aef86ff1bf029851b56194cd16cb7facc2c Mon Sep 17 00:00:00 2001 From: DCtheTall Date: Thu, 9 Apr 2020 15:19:47 -0400 Subject: [PATCH 08/14] add missing trailing newline --- src/core/matchers/async/toBePending.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/matchers/async/toBePending.js b/src/core/matchers/async/toBePending.js index 31059084..7ea12df9 100644 --- a/src/core/matchers/async/toBePending.js +++ b/src/core/matchers/async/toBePending.js @@ -22,4 +22,4 @@ getJasmineRequireObj().toBePending = function(j$) { } }; }; -}; \ No newline at end of file +}; From 08779f2657cbd088b8b37e3c17e9363ac8406c46 Mon Sep 17 00:00:00 2001 From: DCtheTall Date: Thu, 9 Apr 2020 15:20:23 -0400 Subject: [PATCH 09/14] add missing trailing newline --- spec/core/matchers/async/toBePendingSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/core/matchers/async/toBePendingSpec.js b/spec/core/matchers/async/toBePendingSpec.js index 5aa4f428..318e22b7 100644 --- a/spec/core/matchers/async/toBePendingSpec.js +++ b/spec/core/matchers/async/toBePendingSpec.js @@ -48,4 +48,4 @@ describe('toBePending', function() { 'Expected toBePending to be called on a promise.' ); }); -}); \ No newline at end of file +}); From 78c3a007ad8cb29834b1ed957599804272a6b578 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Apr 2020 12:08:49 -0700 Subject: [PATCH 10/14] Fixed test failure in Firefox 74 --- spec/html/PrettyPrintHtmlSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/html/PrettyPrintHtmlSpec.js b/spec/html/PrettyPrintHtmlSpec.js index fd364d9e..738753ba 100644 --- a/spec/html/PrettyPrintHtmlSpec.js +++ b/spec/html/PrettyPrintHtmlSpec.js @@ -31,7 +31,7 @@ describe('PrettyPrinter (HTML Dependent)', function() { } // Different versions of FF produce different error messages. expect(pp(err)).toMatch( - /Not enough arguments|CustomEvent requires at least 1 argument, but only 0 were passed/ + /Not enough arguments|CustomEvent.*only 0.*passed/ ); } }); From 8991b1bba39b5b7e89fc5eeb07ae271a684cb1a4 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 12 Apr 2020 13:43:44 -0700 Subject: [PATCH 11/14] Fixed toHaveSize matcher on IE 10 & 11 --- lib/jasmine-core/jasmine.js | 22 ++++++++++++++++++++-- spec/core/baseSpec.js | 11 +++++++++++ spec/core/matchers/toHaveSizeSpec.js | 6 ++++-- spec/helpers/checkForMap.js | 6 ++++++ spec/helpers/checkForSet.js | 6 ++++++ src/core/base.js | 18 ++++++++++++++++++ src/core/matchers/toHaveSize.js | 4 ++-- 7 files changed, 67 insertions(+), 6 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 9f4413c3..1701fd73 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -314,6 +314,24 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { obj.constructor === jasmineGlobal.Set ); }; + + j$.isWeakMap = function(obj) { + return ( + obj !== null && + typeof obj !== 'undefined' && + typeof jasmineGlobal.WeakMap !== 'undefined' && + obj.constructor === jasmineGlobal.WeakMap + ); + }; + + j$.isDataView = function(obj) { + return ( + obj !== null && + typeof obj !== 'undefined' && + typeof jasmineGlobal.DataView !== 'undefined' && + obj.constructor === jasmineGlobal.DataView + ); + }; j$.isPromise = function(obj) { return ( @@ -5908,11 +5926,11 @@ getJasmineRequireObj().toHaveSize = function(j$) { pass: false }; - if (j$.isA_('WeakSet', actual) || j$.isA_('WeakMap', actual) || j$.isA_('DataView', actual)) { + if (j$.isA_('WeakSet', actual) || j$.isWeakMap(actual) || j$.isDataView(actual)) { throw new Error('Cannot get size of ' + actual + '.'); } - if (actual instanceof Set || actual instanceof Map) { + if (j$.isSet(actual) || j$.isMap(actual)) { result.pass = actual.size === expected; } else if (isLength(actual.length)) { result.pass = actual.length === expected; diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 4fce2254..b85721b9 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -51,4 +51,15 @@ describe('base helpers', function() { expect(jasmineUnderTest.isAsymmetricEqualityTester_(obj)).toBe(true); }); }); + + describe('isSet', function() { + it('returns true when the object is a Set', function() { + jasmine.getEnv().requireFunctioningSets(); + expect(jasmineUnderTest.isSet(new Set())).toBe(true); + }); + + it('returns false when the object is not a Set', function() { + expect(jasmineUnderTest.isSet({})).toBe(false); + }); + }); }); diff --git a/spec/core/matchers/toHaveSizeSpec.js b/spec/core/matchers/toHaveSizeSpec.js index a1b4cccb..a14a24e5 100644 --- a/spec/core/matchers/toHaveSizeSpec.js +++ b/spec/core/matchers/toHaveSizeSpec.js @@ -110,6 +110,7 @@ describe('toHaveSize', function() { }); it('throws an error for WeakSet', function() { + jasmine.getEnv().requireWeakSets(); var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { @@ -118,11 +119,12 @@ describe('toHaveSize', function() { }); it('throws an error for WeakMap', function() { + jasmine.getEnv().requireWeakMaps(); var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { matcher.compare(new WeakMap(), 2); - }).toThrowError('Cannot get size of [object WeakMap].'); + }).toThrowError(/Cannot get size of \[object (WeakMap|Object)\]\./); }); it('throws an error for DataView', function() { @@ -130,6 +132,6 @@ describe('toHaveSize', function() { expect(function() { matcher.compare(new DataView(new ArrayBuffer(128)), 2); - }).toThrowError('Cannot get size of [object DataView].'); + }).toThrowError(/Cannot get size of \[object (DataView|Object)\]\./); }); }); diff --git a/spec/helpers/checkForMap.js b/spec/helpers/checkForMap.js index 46e346a8..77fa1233 100644 --- a/spec/helpers/checkForMap.js +++ b/spec/helpers/checkForMap.js @@ -43,4 +43,10 @@ env.pending('Browser has incomplete or missing support for Maps'); } }; + + env.requireWeakMaps = function() { + if (typeof WeakMap === 'undefined') { + env.pending('Browser does not have support for WeakMap'); + } + }; })(jasmine.getEnv()); diff --git a/spec/helpers/checkForSet.js b/spec/helpers/checkForSet.js index dacb06aa..8656342d 100644 --- a/spec/helpers/checkForSet.js +++ b/spec/helpers/checkForSet.js @@ -47,4 +47,10 @@ env.pending('Browser has incomplete or missing support for Sets'); } }; + + env.requireWeakSets = function() { + if (typeof WeakSet === 'undefined') { + env.pending('Browser does not have support for WeakSet'); + } + }; })(jasmine.getEnv()); diff --git a/src/core/base.js b/src/core/base.js index e86a12c8..121ff614 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -148,6 +148,24 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { ); }; + j$.isWeakMap = function(obj) { + return ( + obj !== null && + typeof obj !== 'undefined' && + typeof jasmineGlobal.WeakMap !== 'undefined' && + obj.constructor === jasmineGlobal.WeakMap + ); + }; + + j$.isDataView = function(obj) { + return ( + obj !== null && + typeof obj !== 'undefined' && + typeof jasmineGlobal.DataView !== 'undefined' && + obj.constructor === jasmineGlobal.DataView + ); + }; + j$.isPromise = function(obj) { return ( typeof jasmineGlobal.Promise !== 'undefined' && diff --git a/src/core/matchers/toHaveSize.js b/src/core/matchers/toHaveSize.js index c0e84cb3..4f6ace0c 100644 --- a/src/core/matchers/toHaveSize.js +++ b/src/core/matchers/toHaveSize.js @@ -16,11 +16,11 @@ getJasmineRequireObj().toHaveSize = function(j$) { pass: false }; - if (j$.isA_('WeakSet', actual) || j$.isA_('WeakMap', actual) || j$.isA_('DataView', actual)) { + if (j$.isA_('WeakSet', actual) || j$.isWeakMap(actual) || j$.isDataView(actual)) { throw new Error('Cannot get size of ' + actual + '.'); } - if (actual instanceof Set || actual instanceof Map) { + if (j$.isSet(actual) || j$.isMap(actual)) { result.pass = actual.size === expected; } else if (isLength(actual.length)) { result.pass = actual.length === expected; From f90d9943fec94bd71b28509761f53d4ed537039d Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Tue, 29 Oct 2019 17:17:27 -0700 Subject: [PATCH 12/14] feat(env): setSpecProperty/setSuiteProperty(key, value) to attach data to tests Use setSpecProperty to attach key/value pairs to spec results that can be picked up in specialized jasmine reporters. Example use-cases include: * Tagging specs with URLs or string-tokens referencing test-plan docs. * Recording performance information for blocks of JS. Similarly setSuiteProperty attaches key/value pairs to suite results --- spec/core/SpecSpec.js | 20 ++++++++- spec/core/integration/EnvSpec.js | 71 ++++++++++++++++++++++++++++++++ src/core/Env.js | 18 ++++++++ src/core/Spec.js | 9 +++- src/core/Suite.js | 9 +++- 5 files changed, 124 insertions(+), 3 deletions(-) diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 38a8e780..fa530049 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -227,7 +227,8 @@ describe('Spec', function() { passedExpectations: [], deprecationWarnings: [], pendingReason: '', - duration: jasmine.any(Number) + duration: jasmine.any(Number), + properties: null }, 'things' ); @@ -299,6 +300,23 @@ describe('Spec', function() { expect(duration).toBe(77000); }); + it('should report properties set during the test', function() { + var done = jasmine.createSpy('done callback'), + spec = new jasmineUnderTest.Spec({ + queueableFn: { fn: jasmine.createSpy('spec body') }, + catchExceptions: function() { + return false; + }, + resultCallback: function() {}, + queueRunnerFactory: function(attrs) { + attrs.onComplete(); + } + }); + spec.setSpecProperty('a', 4); + spec.execute(done); + expect(spec.result.properties).toEqual({ a: 4 }); + }); + it('#status returns passing by default', function() { var spec = new jasmineUnderTest.Spec({ queueableFn: { fn: jasmine.createSpy('spec body') } diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 8c5c1941..247744d3 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -1971,6 +1971,77 @@ describe("Env integration", function() { env.execute(); }); + it('reports test properties on specs', function(done) { + var env = new jasmineUnderTest.Env(), + reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']); + + reporter.specDone.and.callFake(function(e) { + expect(e.properties).toEqual({a: 'Bee'}); + done(); + }); + + env.addReporter(reporter); + env.it('calls setSpecProperty', function() { + env.setSpecProperty('a', 'Bee') + }); + env.execute(); + }); + + it('throws an exception if you try to setSpecProperty outside of a spec', function (done) { + var env = new jasmineUnderTest.Env(), + exception; + + env.describe("a suite", function () { + try { + env.setSpecProperty('a prop', 'val'); + } catch(e) { + exception = e; + } + }); + + var assertions = function() { + expect(exception.message).toBe(`'setSpecProperty' was used when there was no current spec`); + done(); + }; + + env.addReporter({jasmineDone: assertions}); + + env.execute(); + }); + + it('reports test properties on suites', function(done) { + var env = new jasmineUnderTest.Env(), + reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']); + + reporter.suiteDone.and.callFake(function(e) { + expect(e.properties).toEqual({b: 'Sweet'}); + done(); + }); + + env.addReporter(reporter); + env.describe('calls setSuiteProperty', function() { + env.beforeEach(() => { + env.setSuiteProperty('b', 'Sweet'); + }); + env.it('a passing spec', () => { + expect.nothing(); + }); + }); + + env.execute(); + }); + + it('throws an exception if you try to setSuiteProperty outside of a suite', function (done) { + var env = new jasmineUnderTest.Env(); + + try { + env.setSuiteProperty('a', 'Bee'); + } catch(e) { + expect(e.message).toBe(`'setSuiteProperty' was used when there was no current suite`); + done(); + } + }); + it("should associate errors thrown from async code with the correct runnable", function(done) { var reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone','specDone']); diff --git a/src/core/Env.js b/src/core/Env.js index 47915c0a..1135aee7 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -1124,6 +1124,24 @@ getJasmineRequireObj().Env = function(j$) { return spec; }; + this.setSpecProperty = function(key, value) { + if (!currentRunnable() || currentRunnable() == currentSuite()) { + throw new Error( + "'setSpecProperty' was used when there was no current spec" + ); + } + currentRunnable().setSpecProperty(key, value); + }; + + this.setSuiteProperty = function(key, value) { + if (!currentSuite()) { + throw new Error( + "'setSuiteProperty' was used when there was no current suite" + ); + } + currentSuite().setSuiteProperty(key, value); + }; + this.expect = function(actual) { if (!currentRunnable()) { throw new Error( diff --git a/src/core/Spec.js b/src/core/Spec.js index db35de64..f369ac7a 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -48,6 +48,7 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @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 key-value pairs. */ this.result = { id: this.id, @@ -57,7 +58,8 @@ getJasmineRequireObj().Spec = function(j$) { passedExpectations: [], deprecationWarnings: [], pendingReason: '', - duration: null + duration: null, + properties: null }; } @@ -74,6 +76,11 @@ getJasmineRequireObj().Spec = function(j$) { } }; + Spec.prototype.setSpecProperty = function(key, value) { + this.result.properties = this.result.properties || {}; + this.result.properties[key] = value; + }; + Spec.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 4d33ceaa..5cbb9555 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -27,6 +27,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @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 key-value pairs. */ this.result = { id: this.id, @@ -34,10 +35,16 @@ getJasmineRequireObj().Suite = function(j$) { fullName: this.getFullName(), failedExpectations: [], deprecationWarnings: [], - duration: null + duration: null, + properties: null }; } + Suite.prototype.setSuiteProperty = function(key, value) { + this.result.properties = this.result.properties || {}; + this.result.properties[key] = value; + }; + Suite.prototype.expect = function(actual) { return this.expectationFactory(actual, this); }; From 8a731e17a7e4d97c73ba8428911c4f6d3a004c23 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 5 May 2020 17:58:16 -0700 Subject: [PATCH 13/14] Improved jsdocs for user-specified spec/suite properties --- lib/jasmine-core/jasmine.js | 20 ++++++++++++++++++-- src/core/Env.js | 16 ++++++++++++++++ src/core/Spec.js | 2 +- src/core/Suite.js | 2 +- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 63fa4b59..ace5df87 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -716,7 +716,7 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @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 key-value pairs. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} */ this.result = { id: this.id, @@ -2075,6 +2075,14 @@ getJasmineRequireObj().Env = function(j$) { return spec; }; + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SpecResult#properties} + * @name Env#setSpecProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ this.setSpecProperty = function(key, value) { if (!currentRunnable() || currentRunnable() == currentSuite()) { throw new Error( @@ -2084,6 +2092,14 @@ getJasmineRequireObj().Env = function(j$) { currentRunnable().setSpecProperty(key, value); }; + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SuiteResult#properties} + * @name Env#setSuiteProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ this.setSuiteProperty = function(key, value) { if (!currentSuite()) { throw new Error( @@ -8373,7 +8389,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @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 key-value pairs. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} */ this.result = { id: this.id, diff --git a/src/core/Env.js b/src/core/Env.js index 1135aee7..60025850 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -1124,6 +1124,14 @@ getJasmineRequireObj().Env = function(j$) { return spec; }; + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SpecResult#properties} + * @name Env#setSpecProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ this.setSpecProperty = function(key, value) { if (!currentRunnable() || currentRunnable() == currentSuite()) { throw new Error( @@ -1133,6 +1141,14 @@ getJasmineRequireObj().Env = function(j$) { currentRunnable().setSpecProperty(key, value); }; + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SuiteResult#properties} + * @name Env#setSuiteProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ this.setSuiteProperty = function(key, value) { if (!currentSuite()) { throw new Error( diff --git a/src/core/Spec.js b/src/core/Spec.js index f369ac7a..83d389d4 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -48,7 +48,7 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @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 key-value pairs. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty} */ this.result = { id: this.id, diff --git a/src/core/Suite.js b/src/core/Suite.js index 5cbb9555..e660d1f1 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -27,7 +27,7 @@ getJasmineRequireObj().Suite = function(j$) { * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @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 key-value pairs. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} */ this.result = { id: this.id, From 0cb304131f4e7f3816ecb1bfca98fbd571d4cb54 Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Tue, 26 May 2020 14:50:01 -0700 Subject: [PATCH 14/14] fix(env): expose setSpec/SuiteProperty on interface --- src/core/requireInterface.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/core/requireInterface.js b/src/core/requireInterface.js index 15a13cd1..adc503f8 100644 --- a/src/core/requireInterface.js +++ b/src/core/requireInterface.js @@ -168,6 +168,30 @@ getJasmineRequireObj().interface = function(jasmine, env) { return env.afterAll.apply(env, arguments); }, + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SpecResult#properties} + * @name Env#setSpecProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ + setSpecProperty: function(key, value) { + return env.setSpecProperty(key, value); + }, + + /** + * Sets a user-defined property that will be provided to reporters as part of {@link SuiteResult#properties} + * @name Env#setSuiteProperty + * @since 3.6.0 + * @function + * @param {String} key The name of the property + * @param {*} value The value of the property + */ + setSuiteProperty: function(key, value) { + return env.setSuiteProperty(key, value); + }, + /** * Create an expectation for a spec. * @name expect