From 2369c8dba765ac3e0b19c24e17d134775bf58585 Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Wed, 7 Aug 2019 17:44:57 -0700 Subject: [PATCH 01/71] fix(env): Throw if nested describe has no children. Users would like an error if it() is acciddently moved within a before/afterEach/All function. The it() function calls ensureIsNotNested to report such an error. But if the user has no other it() functions in the Suite, it() and thus ensureIsNotNested() is never called. Here we check nested Suites for children; if none are found we throw. --- spec/core/EnvSpec.js | 6 ++++++ spec/core/ExceptionsSpec.js | 4 +++- spec/core/integration/EnvSpec.js | 3 +++ src/core/Env.js | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 72c8d979..821a3b27 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -133,6 +133,12 @@ describe('Env', function() { 'describe expects a function argument; received [object Function]' ); }); + + it('throws an error when it has no children', function() { + expect(function() { + env.describe('done method', function() {}); + }).toThrowError('describe with no children (describe() or it())'); + }); }); describe('#it', function() { diff --git a/spec/core/ExceptionsSpec.js b/spec/core/ExceptionsSpec.js index 538c682d..6dd4611b 100644 --- a/spec/core/ExceptionsSpec.js +++ b/spec/core/ExceptionsSpec.js @@ -30,7 +30,9 @@ describe('Exceptions:', function() { }); it('should handle exceptions thrown directly in top-level describe blocks and continue', function(done) { - var secondDescribe = jasmine.createSpy('second describe'); + var secondDescribe = jasmine.createSpy('second describe').and.callFake(function() { + env.it('is a test', function() {}); + }); env.describe('a suite that throws an exception', function() { env.it('is a test that should pass', function() { this.expect(true).toEqual(true); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 9c827b24..041e738e 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -1881,6 +1881,7 @@ describe("Env integration", function() { } catch(e) { exception = e; } + env.it('has a test', () => {}); }); var assertions = function() { @@ -1904,6 +1905,7 @@ describe("Env integration", function() { } catch(e) { exception = e; } + env.it('has a test', () => {}); }); var assertions = function() { @@ -1927,6 +1929,7 @@ describe("Env integration", function() { } catch(e) { exception = e; } + env.it('has a test', () => {}); }); var assertions = function() { diff --git a/src/core/Env.js b/src/core/Env.js index 43e4a8e7..f8a38ff7 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -843,6 +843,9 @@ getJasmineRequireObj().Env = function(j$) { suite.pend(); } addSpecsToSuite(suite, specDefinitions); + if (suite.parentSuite && !suite.children.length) { + throw new Error('describe with no children (describe() or it())'); + } return suite; }; From 4b2a14f1f3ac3f83571200a8e185fd54c5fcadaf Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 12 Feb 2020 15:38:52 -0800 Subject: [PATCH 02/71] Removed deprecated custom matcher, matchersUtil, pp, etc interfaces --- lib/jasmine-core/jasmine.js | 297 +----------------- spec/core/ExpectationSpec.js | 37 --- ...ymmetricEqualityTesterArgCompatShimSpec.js | 197 ------------ .../integration/CustomAsyncMatchersSpec.js | 80 ----- spec/core/integration/CustomMatchersSpec.js | 116 ------- spec/core/matchers/matchersUtilSpec.js | 179 +---------- src/core/Env.js | 27 -- src/core/Expector.js | 10 +- .../asymmetricEqualityTesterArgCompatShim.js | 122 ------- src/core/matchers/matchersUtil.js | 106 +------ src/core/requireCore.js | 31 -- 11 files changed, 33 insertions(+), 1169 deletions(-) delete mode 100644 spec/core/asymmetricEqualityTesterArgCompatShimSpec.js delete mode 100644 src/core/asymmetricEqualityTesterArgCompatShim.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 8503208b..76f91002 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -72,40 +72,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Expectation = jRequire.Expectation(j$); j$.buildExpectationResult = jRequire.buildExpectationResult(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$); - j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim( - j$ - ); j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$); j$.basicPrettyPrinter_ = j$.makePrettyPrinter(); - Object.defineProperty(j$, 'pp', { - get: function() { - j$.getEnv().deprecatedOnceWithStack( - 'jasmine.pp is deprecated and will be removed in a future release. ' + - 'Use the pp method of the matchersUtil passed to the matcher factory ' + - "or the asymmetric equality tester's `asymmetricMatch` method " + - 'instead. See ' + - ' for details.' - ); - return j$.basicPrettyPrinter_; - } - }); j$.MatchersUtil = jRequire.MatchersUtil(j$); - var staticMatchersUtil = new j$.MatchersUtil({ - customTesters: [], - pp: j$.basicPrettyPrinter_ - }); - Object.defineProperty(j$, 'matchersUtil', { - get: function() { - j$.getEnv().deprecatedOnceWithStack( - 'jasmine.matchersUtil is deprecated and will be removed ' + - 'in a future release. Use the instance passed to the matcher factory or ' + - "the asymmetric equality tester's `asymmetricMatch` method instead. " + - 'See for details.' - ); - return staticMatchersUtil; - } - }); - j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); @@ -1304,17 +1273,6 @@ getJasmineRequireObj().Env = function(j$) { runnableResources[currentRunnable().id].customMatchers; for (var matcherName in matchersToAdd) { - if (matchersToAdd[matcherName].length > 1) { - self.deprecatedOnceWithStack( - 'The matcher factory for "' + - matcherName + - '" ' + - 'accepts custom equality testers, but this parameter will no longer be ' + - 'passed in a future release. ' + - 'See for details.' - ); - } - customMatchers[matcherName] = matchersToAdd[matcherName]; } }; @@ -1329,17 +1287,6 @@ getJasmineRequireObj().Env = function(j$) { runnableResources[currentRunnable().id].customAsyncMatchers; for (var matcherName in matchersToAdd) { - if (matchersToAdd[matcherName].length > 1) { - self.deprecatedOnceWithStack( - 'The matcher factory for "' + - matcherName + - '" ' + - 'accepts custom equality testers, but this parameter will no longer be ' + - 'passed in a future release. ' + - 'See for details.' - ); - } - customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; } }; @@ -1385,12 +1332,8 @@ getJasmineRequireObj().Env = function(j$) { }; var expectationFactory = function(actual, spec) { - var customEqualityTesters = - runnableResources[spec.id].customEqualityTesters; - return j$.Expectation.factory({ matchersUtil: makeMatchersUtil(), - customEqualityTesters: customEqualityTesters, customMatchers: runnableResources[spec.id].customMatchers, actual: actual, addExpectationResult: addExpectationResult @@ -1430,7 +1373,6 @@ getJasmineRequireObj().Env = function(j$) { var asyncExpectationFactory = function(actual, spec, runableType) { return j$.Expectation.asyncFactory({ matchersUtil: makeMatchersUtil(), - customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, actual: actual, addExpectationResult: addExpectationResult @@ -2932,129 +2874,6 @@ getJasmineRequireObj().Truthy = function(j$) { return Truthy; }; -getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) { - /* - Older versions of Jasmine passed an array of custom equality testers as the - second argument to each asymmetric equality tester's `asymmetricMatch` - method. Newer versions will pass a `MatchersUtil` instance. The - asymmetricEqualityTesterArgCompatShim allows for a graceful migration from - the old interface to the new by "being" both an array of custom equality - testers and a `MatchersUtil` at the same time. - - This code should be removed in the next major release. - */ - - var likelyArrayProps = [ - 'concat', - 'constructor', - 'copyWithin', - 'entries', - 'every', - 'fill', - 'filter', - 'find', - 'findIndex', - 'flat', - 'flatMap', - 'forEach', - 'includes', - 'indexOf', - 'join', - 'keys', - 'lastIndexOf', - 'length', - 'map', - 'pop', - 'push', - 'reduce', - 'reduceRight', - 'reverse', - 'shift', - 'slice', - 'some', - 'sort', - 'splice', - 'toLocaleString', - 'toSource', - 'toString', - 'unshift', - 'values' - ]; - - function asymmetricEqualityTesterArgCompatShim( - matchersUtil, - customEqualityTesters - ) { - var self = Object.create(matchersUtil); - - copyAndDeprecate(self, customEqualityTesters, 'length'); - - for (i = 0; i < customEqualityTesters.length; i++) { - copyAndDeprecate(self, customEqualityTesters, i); - } - - // Avoid copying array props if we've previously done so, - // to avoid triggering our own deprecation warnings. - if (!self.isAsymmetricEqualityTesterArgCompatShim_) { - copyAndDeprecateArrayMethods(self); - } - - self.isAsymmetricEqualityTesterArgCompatShim_ = true; - return self; - } - - function copyAndDeprecateArrayMethods(dest) { - var props = arrayProps(), - i, - k; - - for (i = 0; i < props.length; i++) { - k = props[i]; - - // Skip length (dealt with above), and anything that collides with - // MatchesUtil e.g. an Array.prototype.contains method added by user code - if (k !== 'length' && !dest[k]) { - copyAndDeprecate(dest, Array.prototype, k); - } - } - } - - function copyAndDeprecate(dest, src, propName) { - Object.defineProperty(dest, propName, { - get: function() { - j$.getEnv().deprecated( - 'The second argument to asymmetricMatch is now a ' + - 'MatchersUtil. Using it as an array of custom equality testers is ' + - 'deprecated and will stop working in a future release. ' + - 'See for details.' - ); - return src[propName]; - } - }); - } - - function arrayProps() { - var props, a, k; - - if (!Object.getOwnPropertyDescriptors) { - return likelyArrayProps.filter(function(k) { - return Array.prototype.hasOwnProperty(k); - }); - } - - props = Object.getOwnPropertyDescriptors(Array.prototype); // eslint-disable-line compat/compat - a = []; - - for (k in props) { - a.push(k); - } - - return a; - } - - return asymmetricEqualityTesterArgCompatShim; -}; - getJasmineRequireObj().CallTracker = function(j$) { /** * @namespace Spy#calls @@ -4128,7 +3947,6 @@ getJasmineRequireObj().Expector = function(j$) { this.matchersUtil = options.matchersUtil || { buildFailureMessage: function() {} }; - this.customEqualityTesters = options.customEqualityTesters || []; this.actual = options.actual; this.addExpectationResult = options.addExpectationResult || function() {}; this.filters = new j$.ExpectationFilterChain(); @@ -4145,14 +3963,7 @@ getJasmineRequireObj().Expector = function(j$) { this.args.unshift(this.actual); - // TODO: Remove support for passing customEqualityTesters in the next major release. - var matcher; - - if (matcherFactory.length >= 2) { - matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters); - } else { - matcher = matcherFactory(this.matchersUtil); - } + var matcher = matcherFactory(this.matchersUtil); var comparisonFunc = this.filters.selectComparisonFunc(matcher); return comparisonFunc || matcher.compare; @@ -4851,19 +4662,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @since 2.0.0 * @param {*} haystack The collection to search * @param {*} needle The value to search for - * @param [customTesters] An array of custom equality testers. Deprecated. - * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0. * @returns {boolean} True if `needle` was found in `haystack` */ - MatchersUtil.prototype.contains = function(haystack, needle, customTesters) { - if (customTesters) { - j$.getEnv().deprecatedOnceWithStack( - 'Passing custom equality testers ' + - 'to MatchersUtil#contains is deprecated. ' + - 'See for details.' - ); - } - + MatchersUtil.prototype.contains = function(haystack, needle) { if (j$.isSet(haystack)) { return haystack.has(needle); } @@ -4873,7 +4674,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { (!!haystack && !haystack.indexOf) ) { for (var i = 0; i < haystack.length; i++) { - if (this.equals(haystack[i], needle, customTesters)) { + if (this.equals(haystack[i], needle)) { return true; } } @@ -4917,19 +4718,11 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ) { if (j$.isFunction_(b.valuesForDiff_)) { var values = b.valuesForDiff_(a, this.pp); - this.eq_( - values.other, - values.self, - aStack, - bStack, - customTesters, - diffBuilder - ); + this.eq_(values.other, values.self, aStack, bStack, diffBuilder); } else { diffBuilder.recordMismatch(); } @@ -4940,22 +4733,18 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), asymmetricB = j$.isAsymmetricEqualityTester_(b), - shim, result; if (asymmetricA === asymmetricB) { return undefined; } - shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters); - if (asymmetricA) { - result = a.asymmetricMatch(b, shim); + result = a.asymmetricMatch(b, this); if (!result) { diffBuilder.recordMismatch(); } @@ -4963,9 +4752,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } if (asymmetricB) { - result = b.asymmetricMatch(a, shim); + result = b.asymmetricMatch(a, this); if (!result) { - this.asymmetricDiff_(a, b, aStack, bStack, customTesters, diffBuilder); + this.asymmetricDiff_(a, b, aStack, bStack, diffBuilder); } return result; } @@ -4978,58 +4767,18 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @since 2.0.0 * @param {*} a The first value to compare * @param {*} b The second value to compare - * @param [customTesters] An array of custom equality testers. Deprecated. - * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0. * @returns {boolean} True if the values are equal */ - MatchersUtil.prototype.equals = function( - a, - b, - customTestersOrDiffBuilder, - diffBuilderOrNothing - ) { - var customTesters, diffBuilder; - - if (isDiffBuilder(customTestersOrDiffBuilder)) { - diffBuilder = customTestersOrDiffBuilder; - } else { - if (customTestersOrDiffBuilder) { - j$.getEnv().deprecatedOnceWithStack( - 'Passing custom equality testers ' + - 'to MatchersUtil#equals is deprecated. ' + - 'See for details.' - ); - } - - if (diffBuilderOrNothing) { - j$.getEnv().deprecatedOnceWithStack( - 'Diff builder should be passed ' + - 'as the third argument to MatchersUtil#equals, not the fourth. ' + - 'See for details.' - ); - } - - customTesters = customTestersOrDiffBuilder; - diffBuilder = diffBuilderOrNothing; - } - - customTesters = customTesters || this.customTesters_; + MatchersUtil.prototype.equals = function(a, b, diffBuilder) { diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder.setRoots(a, b); - return this.eq_(a, b, [], [], customTesters, diffBuilder); + return this.eq_(a, b, [], [], diffBuilder); }; // Equality function lovingly adapted from isEqual in // [Underscore](http://underscorejs.org) - MatchersUtil.prototype.eq_ = function( - a, - b, - aStack, - bStack, - customTesters, - diffBuilder - ) { + MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, diffBuilder) { var result = true, self = this, i; @@ -5039,15 +4788,14 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ); if (!j$.util.isUndefined(asymmetricResult)) { return asymmetricResult; } - for (i = 0; i < customTesters.length; i++) { - var customTesterResult = customTesters[i](a, b); + for (i = 0; i < this.customTesters_.length; i++) { + var customTesterResult = this.customTesters_[i](a, b); if (!j$.util.isUndefined(customTesterResult)) { if (!customTesterResult) { diffBuilder.recordMismatch(); @@ -5123,7 +4871,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { new Uint8Array(b), // eslint-disable-line compat/compat aStack, bStack, - customTesters, diffBuilder ); // RegExps are compared by their source patterns and flags. @@ -5202,7 +4949,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { i < bLength ? b[i] : void 0, aStack, bStack, - customTesters, diffBuilder ) && result; } @@ -5247,14 +4993,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { if ( j$.isAsymmetricEqualityTester_(mapKey) || (j$.isAsymmetricEqualityTester_(cmpKey) && - this.eq_( - mapKey, - cmpKey, - aStack, - bStack, - customTesters, - j$.NullDiffBuilder() - )) + this.eq_(mapKey, cmpKey, aStack, bStack, j$.NullDiffBuilder())) ) { mapValueB = b.get(cmpKey); } else { @@ -5265,7 +5004,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { mapValueB, aStack, bStack, - customTesters, j$.NullDiffBuilder() ); } @@ -5316,7 +5054,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { otherValue, baseStack, otherStack, - customTesters, j$.NullDiffBuilder() ); if (!found && prevStackSize !== baseStack.length) { @@ -5381,9 +5118,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } diffBuilder.withPath(key, function() { - if ( - !self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder) - ) { + if (!self.eq_(a[key], b[key], aStack, bStack, diffBuilder)) { result = false; } }); @@ -5495,10 +5230,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { return formatted; } - function isDiffBuilder(obj) { - return obj && typeof obj.recordMismatch === 'function'; - } - return MatchersUtil; }; diff --git a/spec/core/ExpectationSpec.js b/spec/core/ExpectationSpec.js index f0cdfded..ce2b9ae9 100644 --- a/spec/core/ExpectationSpec.js +++ b/spec/core/ExpectationSpec.js @@ -55,43 +55,6 @@ describe('Expectation', function() { expect(matcherFactory).toHaveBeenCalledWith(matchersUtil); }); - // TODO: remove this in the next major release - it('passes custom equality testers when the matcher factory takes two arguments', function() { - var fakeCompare = function() { - return { pass: true }; - }, - matcherFactory = function(matchersUtil, customTesters) { - return { compare: fakeCompare }; - }, - matcherFactorySpy = jasmine - .createSpy('matcher', matcherFactory) - .and.callThrough(), - matchers = { - toFoo: matcherFactorySpy - }, - matchersUtil = { - buildFailureMessage: jasmine.createSpy('buildFailureMessage') - }, - customEqualityTesters = ['a'], - addExpectationResult = jasmine.createSpy('addExpectationResult'), - expectation; - - expectation = jasmineUnderTest.Expectation.factory({ - matchersUtil: matchersUtil, - customMatchers: matchers, - customEqualityTesters: customEqualityTesters, - actual: 'an actual', - addExpectationResult: addExpectationResult - }); - - expectation.toFoo('hello'); - - expect(matcherFactorySpy).toHaveBeenCalledWith( - matchersUtil, - customEqualityTesters - ); - }); - it("wraps matchers's compare functions, passing the actual and expected", function() { var fakeCompare = jasmine .createSpy('fake-compare') diff --git a/spec/core/asymmetricEqualityTesterArgCompatShimSpec.js b/spec/core/asymmetricEqualityTesterArgCompatShimSpec.js deleted file mode 100644 index 26bb90fd..00000000 --- a/spec/core/asymmetricEqualityTesterArgCompatShimSpec.js +++ /dev/null @@ -1,197 +0,0 @@ -describe('asymmetricEqualityTesterArgCompatShim', function() { - it('provides all the properties of the MatchersUtil', function() { - var matchersUtil = { - foo: function() {}, - bar: function() {} - }, - shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim( - matchersUtil, - [] - ); - - expect(shim.foo).toBe(matchersUtil.foo); - expect(shim.bar).toBe(matchersUtil.bar); - }); - - it('provides and deprecates all the properties of the customEqualityTesters', function() { - var customEqualityTesters = [function() {}, function() {}], - shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim( - {}, - customEqualityTesters - ), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'), - expectedMessage = - 'The second argument to asymmetricMatch is now a MatchersUtil. ' + - 'Using it as an array of custom equality testers is deprecated and will stop ' + - 'working in a future release. ' + - 'See for details.'; - - expect(shim.length).toBe(2); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - deprecated.calls.reset(); - - expect(shim[0]).toBe(customEqualityTesters[0]); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - deprecated.calls.reset(); - - expect(shim[1]).toBe(customEqualityTesters[1]); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - }); - - it('provides and deprecates all the properties of Array.prototype', function() { - var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'), - expectedMessage = - 'The second argument to asymmetricMatch is now a MatchersUtil. ' + - 'Using it as an array of custom equality testers is deprecated and will stop ' + - 'working in a future release. ' + - 'See for details.'; - - expect(shim.filter).toBe(Array.prototype.filter); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - deprecated.calls.reset(); - - expect(shim.forEach).toBe(Array.prototype.forEach); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - deprecated.calls.reset(); - - expect(shim.map).toBe(Array.prototype.map); - expect(deprecated).toHaveBeenCalledWith(expectedMessage); - deprecated.calls.reset(); - }); - - it('provides and deprecates properties of Array.prototype', function() { - var keys = [ - 'concat', - 'every', - 'filter', - 'forEach', - 'indexOf', - 'join', - 'lastIndexOf', - 'length', - 'map', - 'pop', - 'push', - 'reduce', - 'reduceRight', - 'reverse', - 'shift', - 'slice', - 'some', - 'sort', - 'splice', - 'unshift' - ], - optionalKeys = [ - 'copyWithin', - 'entries', - 'fill', - 'find', - 'findIndex', - 'flat', - 'flatMap', - 'includes', - 'keys', - 'values' - ], - shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'), - i, - k; - - // Properties that are present on all supported runtimes - for (i = 0; i < keys.length; i++) { - k = keys[i]; - expect(shim[k]) - .withContext(k) - .not.toBeUndefined(); - expect(shim[k]) - .withContext(k) - .toBe(Array.prototype[k]); - expect(deprecated).toHaveBeenCalled(); - deprecated.calls.reset(); - } - - // Properties that are present on only some supported runtimes - for (i = 0; i < optionalKeys.length; i++) { - k = optionalKeys[i]; - - if (shim[k] !== undefined) { - expect(shim[k]) - .withContext(k) - .toBe(Array.prototype[k]); - expect(deprecated) - .withContext(k) - .toHaveBeenCalled(); - deprecated.calls.reset(); - } - } - }); - - it('does not deprecate properties of Object.prototype', function() { - var shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim({}, []), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - expect(shim.hasOwnProperty).toBe(Object.prototype.hasOwnProperty); - expect(shim.isPrototypeOf).toBe(Object.prototype.isPrototypeOf); - - expect(deprecated).not.toHaveBeenCalled(); - }); - - describe('When Array.prototype additions collide with MatchersUtil methods', function() { - function keys() { - return [ - 'contains', - 'buildFailureMessage', - 'asymmetricDiff_', - 'asymmetricMatch_', - 'equals', - 'eq_' - ]; - } - - beforeEach(function() { - keys().forEach(function(k) { - expect(Array.prototype[k]) - .withContext('Array.prototype already had ' + k) - .toBeUndefined(); - Array.prototype[k] = function() {}; - }); - }); - - afterEach(function() { - keys().forEach(function(k) { - delete Array.prototype[k]; - }); - }); - - it('uses the MatchersUtil methods', function() { - var matchersUtil = new jasmineUnderTest.MatchersUtil({}), - shim = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim( - matchersUtil, - [] - ); - - keys().forEach(function(k) { - expect(shim[k]) - .withContext(k + ' was overwritten') - .toBe(jasmineUnderTest.MatchersUtil.prototype[k]); - }); - }); - }); - - describe('When the matchersUtil is already an asymmetricEqualityTesterArgCompatShim', function() { - it('does not trigger any deprecations', function() { - var shim1 = jasmineUnderTest.asymmetricEqualityTesterArgCompatShim( - {}, - [] - ); - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - jasmineUnderTest.asymmetricEqualityTesterArgCompatShim(shim1, []); - - expect(jasmineUnderTest.getEnv().deprecated).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/core/integration/CustomAsyncMatchersSpec.js b/spec/core/integration/CustomAsyncMatchersSpec.js index cb30216d..e015e2fc 100644 --- a/spec/core/integration/CustomAsyncMatchersSpec.js +++ b/spec/core/integration/CustomAsyncMatchersSpec.js @@ -124,48 +124,6 @@ describe('Custom Async Matchers (Integration)', function() { env.execute(null, done); }); - // TODO: remove this in the next major release. - describe('When a matcher factory takes at least two arguments', function() { - it('passes the jasmine utility and current equality testers to the matcher factory', function(done) { - jasmine.getEnv().requirePromises(); - - var matcherFactory = function(util, customTesters) { - return { - compare: function() { - return Promise.resolve({ pass: true }); - } - }; - }, - matcherFactorySpy = jasmine.createSpy( - 'matcherFactorySpy', - matcherFactory - ), - customEqualityFn = function() { - return true; - }; - - env.it('spec with expectation', function() { - env.addCustomEqualityTester(customEqualityFn); - env.addAsyncMatchers({ - toBeReal: matcherFactorySpy - }); - - return env.expectAsync(true).toBeReal(); - }); - - var specExpectations = function() { - expect(matcherFactorySpy).toHaveBeenCalledWith( - jasmine.any(jasmineUnderTest.MatchersUtil), - [customEqualityFn] - ); - }; - - spyOn(env, 'deprecated'); - env.addReporter({ specDone: specExpectations, jasmineDone: done }); - env.execute(); - }); - }); - it('provides custom equality testers to the matcher factory via matchersUtil', function(done) { jasmine.getEnv().requirePromises(); @@ -201,42 +159,4 @@ describe('Custom Async Matchers (Integration)', function() { env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); - - it('logs a deprecation once per matcher if the matcher factory takes two arguments', function(done) { - var matcherFactory = function(matchersUtil, customEqualityTesters) { - return { compare: function() {} }; - }; - - spyOn(env, 'deprecated'); - - env.beforeEach(function() { - env.addAsyncMatchers({ toBeFoo: matcherFactory }); - env.addAsyncMatchers({ toBeBar: matcherFactory }); - }); - - env.it('a spec', function() {}); - env.it('another spec', function() {}); - - function jasmineDone() { - expect(env.deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'The matcher factory for "toBeFoo" accepts custom equality testers, ' + - 'but this parameter will no longer be passed in a future release. ' + - 'See for details.' - ) - ); - expect(env.deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'The matcher factory for "toBeBar" accepts custom equality testers, ' + - 'but this parameter will no longer be passed in a future release. ' + - 'See for details.' - ) - ); - expect(env.deprecated).toHaveBeenCalledTimes(2); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(); - }); }); diff --git a/spec/core/integration/CustomMatchersSpec.js b/spec/core/integration/CustomMatchersSpec.js index 9b203072..5bd990f8 100644 --- a/spec/core/integration/CustomMatchersSpec.js +++ b/spec/core/integration/CustomMatchersSpec.js @@ -108,44 +108,7 @@ describe('Custom Matchers (Integration)', function() { env.execute(null, done); }); - it('supports asymmetric equality testers that take a list of custom equality testers', function(done) { - // TODO: remove this in the next major release. - spyOn(jasmineUnderTest, 'getEnv').and.returnValue(env); - spyOn(env, 'deprecated'); // suppress warnings - - env.it('spec using custom asymmetric equality tester', function() { - var customEqualityFn = function(a, b) { - if (a === 2 && b === 'two') { - return true; - } - }; - var arrayWithFirstElement = function(sample) { - return { - asymmetricMatch: function(actual, customEqualityTesters) { - return jasmineUnderTest.matchersUtil.equals( - sample, - actual[0], - customEqualityTesters - ); - } - }; - }; - - env.addCustomEqualityTester(customEqualityFn); - env.expect(['two']).toEqual(arrayWithFirstElement(2)); - }); - - var specExpectations = function(result) { - expect(result.status).toEqual('passed'); - }; - - env.addReporter({ specDone: specExpectations }); - env.execute(null, done); - }); - it('displays an appropriate failure message if a custom equality matcher fails', function(done) { - spyOn(env, 'deprecated'); - env.it('spec using custom equality matcher', function() { var customEqualityFn = function(a, b) { // "foo" is not equal to anything @@ -277,47 +240,6 @@ describe('Custom Matchers (Integration)', function() { env.execute(null, done); }); - // TODO: remove this in the next major release. - describe('When a matcher factory takes at least two arguments', function() { - it('passes the jasmine utility and current equality testers to the matcher factory', function(done) { - spyOn(env, 'deprecated'); - - var matcherFactory = function(util, customTesters) { - return { - compare: function() { - return { pass: true }; - } - }; - }, - matcherFactorySpy = jasmine.createSpy( - 'matcherFactorySpy', - matcherFactory - ), - customEqualityFn = function() { - return true; - }; - - env.it('spec with expectation', function() { - env.addCustomEqualityTester(customEqualityFn); - env.addMatchers({ - toBeReal: matcherFactorySpy - }); - - env.expect(true).toBeReal(); - }); - - var specExpectations = function() { - expect(matcherFactorySpy).toHaveBeenCalledWith( - jasmine.any(jasmineUnderTest.MatchersUtil), - [customEqualityFn] - ); - }; - - env.addReporter({ specDone: specExpectations, jasmineDone: done }); - env.execute(); - }); - }); - it('provides custom equality testers to the matcher factory via matchersUtil', function(done) { var matcherFactory = function(matchersUtil) { return { @@ -349,42 +271,4 @@ describe('Custom Matchers (Integration)', function() { env.addReporter({ specDone: specExpectations }); env.execute(null, done); }); - - it('logs a deprecation once per matcher if the matcher factory takes two arguments', function(done) { - var matcherFactory = function(matchersUtil, customEqualityTesters) { - return { compare: function() {} }; - }; - - spyOn(env, 'deprecated'); - - env.beforeEach(function() { - env.addMatchers({ toBeFoo: matcherFactory }); - env.addMatchers({ toBeBar: matcherFactory }); - }); - - env.it('a spec', function() {}); - env.it('another spec', function() {}); - - function jasmineDone() { - expect(env.deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'The matcher factory for "toBeFoo" accepts custom equality testers, ' + - 'but this parameter will no longer be passed in a future release. ' + - 'See for details.' - ) - ); - expect(env.deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'The matcher factory for "toBeBar" accepts custom equality testers, ' + - 'but this parameter will no longer be passed in a future release. ' + - 'See for details.' - ) - ); - expect(env.deprecated).toHaveBeenCalledTimes(2); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(); - }); }); diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index cb0ba44d..1be758d6 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -499,19 +499,7 @@ describe('matchersUtil', function() { ).toBe(true); }); - it('passes when a custom equality matcher passed to equals returns true', function() { - // TODO: remove this in the next major release. - var tester = function(a, b) { - return true; - }, - matchersUtil = new jasmineUnderTest.MatchersUtil(); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - - expect(matchersUtil.equals(1, 2, [tester])).toBe(true); - }); - - it('passes when a custom equality matcher passed to the constructor returns true', function() { + it('passes when a custom equality matcher returns true', function() { var tester = function(a, b) { return true; }, @@ -528,20 +516,7 @@ describe('matchersUtil', function() { expect(matchersUtil.equals({}, {})).toBe(true); }); - describe("when a custom equality matcher is passed to equals that returns 'undefined'", function() { - // TODO: remove this in the next major release. - var tester = function(a, b) { - return jasmine.undefined; - }; - - it('passes for two empty Objects', function() { - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - expect(matchersUtil.equals({}, {}, [tester])).toBe(true); - }); - }); - - describe("when a custom equality matcher is passed to the constructor that returns 'undefined'", function() { + describe("when a custom equality matcher returns 'undefined'", function() { var tester = function(a, b) { return jasmine.undefined; }; @@ -555,19 +530,7 @@ describe('matchersUtil', function() { }); }); - it('fails for equivalents when a custom equality matcher passed to equals returns false', function() { - // TODO: remove this in the next major release. - var tester = function(a, b) { - return false; - }, - matchersUtil = new jasmineUnderTest.MatchersUtil(); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - - expect(matchersUtil.equals(1, 1, [tester])).toBe(false); - }); - - it('fails for equivalents when a custom equality matcher passed to the constructor returns false', function() { + it('fails for equivalents when a custom equality matcher returns false', function() { var tester = function(a, b) { return false; }, @@ -579,29 +542,7 @@ describe('matchersUtil', function() { expect(matchersUtil.equals(1, 1)).toBe(false); }); - it('passes for an asymmetric equality tester that returns true when a custom equality tester passed to equals return false', function() { - // TODO: remove this in the next major release. - var asymmetricTester = { - asymmetricMatch: function(other) { - return true; - } - }, - symmetricTester = function(a, b) { - return false; - }, - matchersUtil = new jasmineUnderTest.MatchersUtil(); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - - expect( - matchersUtil.equals(asymmetricTester, true, [symmetricTester]) - ).toBe(true); - expect( - matchersUtil.equals(true, asymmetricTester, [symmetricTester]) - ).toBe(true); - }); - - it('passes for an asymmetric equality tester that returns true when a custom equality tester passed to the constructor return false', function() { + it('passes for an asymmetric equality tester that returns true when a custom equality tester return false', function() { var asymmetricTester = { asymmetricMatch: function(other) { return true; @@ -619,47 +560,6 @@ describe('matchersUtil', function() { expect(matchersUtil.equals(true, asymmetricTester)).toBe(true); }); - describe('The compatibility shim passed to asymmetric equality testers', function() { - describe('When equals is called with custom equality testers', function() { - it('is both a matchersUtil and the custom equality testers passed to equals', function() { - var asymmetricTester = jasmine.createSpyObj('tester', [ - 'asymmetricMatch' - ]), - symmetricTester = function() {}, - matchersUtil = new jasmineUnderTest.MatchersUtil(), - shim; - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - matchersUtil.equals(true, asymmetricTester, [symmetricTester]); - shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1]; - expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil)); - expect(shim.length).toEqual(1); - expect(shim[0]).toEqual(symmetricTester); - }); - }); - - describe('When equals is called with custom equality testers', function() { - it('is both a matchersUtil and the custom equality testers passed to the constructor', function() { - var asymmetricTester = jasmine.createSpyObj('tester', [ - 'asymmetricMatch' - ]), - symmetricTester = function() {}, - matchersUtil = new jasmineUnderTest.MatchersUtil({ - customTesters: [symmetricTester], - pp: function() {} - }), - shim; - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - matchersUtil.equals(true, asymmetricTester); - shim = asymmetricTester.asymmetricMatch.calls.argsFor(0)[1]; - expect(shim).toEqual(jasmine.any(jasmineUnderTest.MatchersUtil)); - expect(shim.length).toEqual(1); - expect(shim[0]).toEqual(symmetricTester); - }); - }); - }); - it('passes when an Any is compared to an Any that checks for the same type', function() { var any1 = new jasmineUnderTest.Any(Function), any2 = new jasmineUnderTest.Any(Function), @@ -1030,57 +930,6 @@ describe('matchersUtil', function() { }); }); - it('logs a deprecation warning when custom equality testers are passed', function() { - var matchersUtil = new jasmineUnderTest.MatchersUtil(), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - matchersUtil.equals(0, 0, []); - - expect(deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'Passing custom equality testers ' + - 'to MatchersUtil#equals is deprecated. ' + - 'See for details.' - ) - ); - }); - - it('logs a deprecation warning when a diffBuilder is provided as the fourth argument', function() { - var matchersUtil = new jasmineUnderTest.MatchersUtil(), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - matchersUtil.equals(0, 0, null, new jasmineUnderTest.NullDiffBuilder()); - - expect(deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'Diff builder should be passed as the ' + - 'third argument to MatchersUtil#equals, not the fourth. ' + - 'See for details.' - ) - ); - }); - - it('uses a diffBuilder if one is provided as the fourth argument', function() { - // TODO: remove this in the next major release. - var diffBuilder = new jasmineUnderTest.DiffBuilder(), - matchersUtil = new jasmineUnderTest.MatchersUtil(); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); // suppress warning - spyOn(diffBuilder, 'recordMismatch'); - spyOn(diffBuilder, 'withPath').and.callThrough(); - - matchersUtil.equals([1], [2], [], diffBuilder); - expect(diffBuilder.withPath).toHaveBeenCalledWith( - 'length', - jasmine.any(Function) - ); - expect(diffBuilder.withPath).toHaveBeenCalledWith( - 0, - jasmine.any(Function) - ); - expect(diffBuilder.recordMismatch).toHaveBeenCalledWith(); - }); - it('uses a diffBuilder if one is provided as the third argument', function() { var diffBuilder = new jasmineUnderTest.DiffBuilder(), matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -1130,25 +979,7 @@ describe('matchersUtil', function() { ).toBe(true); }); - it('uses custom equality testers if passed to contains and actual is an Array', function() { - // TODO: remove this in the next major release. - var customTester = function(a, b) { - return true; - }, - matchersUtil = new jasmineUnderTest.MatchersUtil(), - deprecated = spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - expect(matchersUtil.contains([1, 2], 3, [customTester])).toBe(true); - - expect(deprecated).toHaveBeenCalledWith( - jasmine.stringMatching( - 'Passing custom equality testers to MatchersUtil#contains is deprecated. ' + - 'See for details.' - ) - ); - }); - - it('uses custom equality testers if passed to the constructor and actual is an Array', function() { + it('uses custom equality testers if actual is an Array', function() { var customTester = function(a, b) { return true; }, diff --git a/src/core/Env.js b/src/core/Env.js index fed16dfc..b0193d15 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -302,17 +302,6 @@ getJasmineRequireObj().Env = function(j$) { runnableResources[currentRunnable().id].customMatchers; for (var matcherName in matchersToAdd) { - if (matchersToAdd[matcherName].length > 1) { - self.deprecatedOnceWithStack( - 'The matcher factory for "' + - matcherName + - '" ' + - 'accepts custom equality testers, but this parameter will no longer be ' + - 'passed in a future release. ' + - 'See for details.' - ); - } - customMatchers[matcherName] = matchersToAdd[matcherName]; } }; @@ -327,17 +316,6 @@ getJasmineRequireObj().Env = function(j$) { runnableResources[currentRunnable().id].customAsyncMatchers; for (var matcherName in matchersToAdd) { - if (matchersToAdd[matcherName].length > 1) { - self.deprecatedOnceWithStack( - 'The matcher factory for "' + - matcherName + - '" ' + - 'accepts custom equality testers, but this parameter will no longer be ' + - 'passed in a future release. ' + - 'See for details.' - ); - } - customAsyncMatchers[matcherName] = matchersToAdd[matcherName]; } }; @@ -383,12 +361,8 @@ getJasmineRequireObj().Env = function(j$) { }; var expectationFactory = function(actual, spec) { - var customEqualityTesters = - runnableResources[spec.id].customEqualityTesters; - return j$.Expectation.factory({ matchersUtil: makeMatchersUtil(), - customEqualityTesters: customEqualityTesters, customMatchers: runnableResources[spec.id].customMatchers, actual: actual, addExpectationResult: addExpectationResult @@ -428,7 +402,6 @@ getJasmineRequireObj().Env = function(j$) { var asyncExpectationFactory = function(actual, spec, runableType) { return j$.Expectation.asyncFactory({ matchersUtil: makeMatchersUtil(), - customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers, actual: actual, addExpectationResult: addExpectationResult diff --git a/src/core/Expector.js b/src/core/Expector.js index c4a560ca..df4878da 100644 --- a/src/core/Expector.js +++ b/src/core/Expector.js @@ -3,7 +3,6 @@ getJasmineRequireObj().Expector = function(j$) { this.matchersUtil = options.matchersUtil || { buildFailureMessage: function() {} }; - this.customEqualityTesters = options.customEqualityTesters || []; this.actual = options.actual; this.addExpectationResult = options.addExpectationResult || function() {}; this.filters = new j$.ExpectationFilterChain(); @@ -20,14 +19,7 @@ getJasmineRequireObj().Expector = function(j$) { this.args.unshift(this.actual); - // TODO: Remove support for passing customEqualityTesters in the next major release. - var matcher; - - if (matcherFactory.length >= 2) { - matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters); - } else { - matcher = matcherFactory(this.matchersUtil); - } + var matcher = matcherFactory(this.matchersUtil); var comparisonFunc = this.filters.selectComparisonFunc(matcher); return comparisonFunc || matcher.compare; diff --git a/src/core/asymmetricEqualityTesterArgCompatShim.js b/src/core/asymmetricEqualityTesterArgCompatShim.js deleted file mode 100644 index 7ba21831..00000000 --- a/src/core/asymmetricEqualityTesterArgCompatShim.js +++ /dev/null @@ -1,122 +0,0 @@ -getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) { - /* - Older versions of Jasmine passed an array of custom equality testers as the - second argument to each asymmetric equality tester's `asymmetricMatch` - method. Newer versions will pass a `MatchersUtil` instance. The - asymmetricEqualityTesterArgCompatShim allows for a graceful migration from - the old interface to the new by "being" both an array of custom equality - testers and a `MatchersUtil` at the same time. - - This code should be removed in the next major release. - */ - - var likelyArrayProps = [ - 'concat', - 'constructor', - 'copyWithin', - 'entries', - 'every', - 'fill', - 'filter', - 'find', - 'findIndex', - 'flat', - 'flatMap', - 'forEach', - 'includes', - 'indexOf', - 'join', - 'keys', - 'lastIndexOf', - 'length', - 'map', - 'pop', - 'push', - 'reduce', - 'reduceRight', - 'reverse', - 'shift', - 'slice', - 'some', - 'sort', - 'splice', - 'toLocaleString', - 'toSource', - 'toString', - 'unshift', - 'values' - ]; - - function asymmetricEqualityTesterArgCompatShim( - matchersUtil, - customEqualityTesters - ) { - var self = Object.create(matchersUtil); - - copyAndDeprecate(self, customEqualityTesters, 'length'); - - for (i = 0; i < customEqualityTesters.length; i++) { - copyAndDeprecate(self, customEqualityTesters, i); - } - - // Avoid copying array props if we've previously done so, - // to avoid triggering our own deprecation warnings. - if (!self.isAsymmetricEqualityTesterArgCompatShim_) { - copyAndDeprecateArrayMethods(self); - } - - self.isAsymmetricEqualityTesterArgCompatShim_ = true; - return self; - } - - function copyAndDeprecateArrayMethods(dest) { - var props = arrayProps(), - i, - k; - - for (i = 0; i < props.length; i++) { - k = props[i]; - - // Skip length (dealt with above), and anything that collides with - // MatchesUtil e.g. an Array.prototype.contains method added by user code - if (k !== 'length' && !dest[k]) { - copyAndDeprecate(dest, Array.prototype, k); - } - } - } - - function copyAndDeprecate(dest, src, propName) { - Object.defineProperty(dest, propName, { - get: function() { - j$.getEnv().deprecated( - 'The second argument to asymmetricMatch is now a ' + - 'MatchersUtil. Using it as an array of custom equality testers is ' + - 'deprecated and will stop working in a future release. ' + - 'See for details.' - ); - return src[propName]; - } - }); - } - - function arrayProps() { - var props, a, k; - - if (!Object.getOwnPropertyDescriptors) { - return likelyArrayProps.filter(function(k) { - return Array.prototype.hasOwnProperty(k); - }); - } - - props = Object.getOwnPropertyDescriptors(Array.prototype); // eslint-disable-line compat/compat - a = []; - - for (k in props) { - a.push(k); - } - - return a; - } - - return asymmetricEqualityTesterArgCompatShim; -}; diff --git a/src/core/matchers/matchersUtil.js b/src/core/matchers/matchersUtil.js index 9f488854..c2cf7c82 100644 --- a/src/core/matchers/matchersUtil.js +++ b/src/core/matchers/matchersUtil.js @@ -29,19 +29,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @since 2.0.0 * @param {*} haystack The collection to search * @param {*} needle The value to search for - * @param [customTesters] An array of custom equality testers. Deprecated. - * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0. * @returns {boolean} True if `needle` was found in `haystack` */ - MatchersUtil.prototype.contains = function(haystack, needle, customTesters) { - if (customTesters) { - j$.getEnv().deprecatedOnceWithStack( - 'Passing custom equality testers ' + - 'to MatchersUtil#contains is deprecated. ' + - 'See for details.' - ); - } - + MatchersUtil.prototype.contains = function(haystack, needle) { if (j$.isSet(haystack)) { return haystack.has(needle); } @@ -51,7 +41,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { (!!haystack && !haystack.indexOf) ) { for (var i = 0; i < haystack.length; i++) { - if (this.equals(haystack[i], needle, customTesters)) { + if (this.equals(haystack[i], needle)) { return true; } } @@ -95,19 +85,11 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ) { if (j$.isFunction_(b.valuesForDiff_)) { var values = b.valuesForDiff_(a, this.pp); - this.eq_( - values.other, - values.self, - aStack, - bStack, - customTesters, - diffBuilder - ); + this.eq_(values.other, values.self, aStack, bStack, diffBuilder); } else { diffBuilder.recordMismatch(); } @@ -118,22 +100,18 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ) { var asymmetricA = j$.isAsymmetricEqualityTester_(a), asymmetricB = j$.isAsymmetricEqualityTester_(b), - shim, result; if (asymmetricA === asymmetricB) { return undefined; } - shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters); - if (asymmetricA) { - result = a.asymmetricMatch(b, shim); + result = a.asymmetricMatch(b, this); if (!result) { diffBuilder.recordMismatch(); } @@ -141,9 +119,9 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } if (asymmetricB) { - result = b.asymmetricMatch(a, shim); + result = b.asymmetricMatch(a, this); if (!result) { - this.asymmetricDiff_(a, b, aStack, bStack, customTesters, diffBuilder); + this.asymmetricDiff_(a, b, aStack, bStack, diffBuilder); } return result; } @@ -156,58 +134,18 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @since 2.0.0 * @param {*} a The first value to compare * @param {*} b The second value to compare - * @param [customTesters] An array of custom equality testers. Deprecated. - * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0. * @returns {boolean} True if the values are equal */ - MatchersUtil.prototype.equals = function( - a, - b, - customTestersOrDiffBuilder, - diffBuilderOrNothing - ) { - var customTesters, diffBuilder; - - if (isDiffBuilder(customTestersOrDiffBuilder)) { - diffBuilder = customTestersOrDiffBuilder; - } else { - if (customTestersOrDiffBuilder) { - j$.getEnv().deprecatedOnceWithStack( - 'Passing custom equality testers ' + - 'to MatchersUtil#equals is deprecated. ' + - 'See for details.' - ); - } - - if (diffBuilderOrNothing) { - j$.getEnv().deprecatedOnceWithStack( - 'Diff builder should be passed ' + - 'as the third argument to MatchersUtil#equals, not the fourth. ' + - 'See for details.' - ); - } - - customTesters = customTestersOrDiffBuilder; - diffBuilder = diffBuilderOrNothing; - } - - customTesters = customTesters || this.customTesters_; + MatchersUtil.prototype.equals = function(a, b, diffBuilder) { diffBuilder = diffBuilder || j$.NullDiffBuilder(); diffBuilder.setRoots(a, b); - return this.eq_(a, b, [], [], customTesters, diffBuilder); + return this.eq_(a, b, [], [], diffBuilder); }; // Equality function lovingly adapted from isEqual in // [Underscore](http://underscorejs.org) - MatchersUtil.prototype.eq_ = function( - a, - b, - aStack, - bStack, - customTesters, - diffBuilder - ) { + MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, diffBuilder) { var result = true, self = this, i; @@ -217,15 +155,14 @@ getJasmineRequireObj().MatchersUtil = function(j$) { b, aStack, bStack, - customTesters, diffBuilder ); if (!j$.util.isUndefined(asymmetricResult)) { return asymmetricResult; } - for (i = 0; i < customTesters.length; i++) { - var customTesterResult = customTesters[i](a, b); + for (i = 0; i < this.customTesters_.length; i++) { + var customTesterResult = this.customTesters_[i](a, b); if (!j$.util.isUndefined(customTesterResult)) { if (!customTesterResult) { diffBuilder.recordMismatch(); @@ -301,7 +238,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { new Uint8Array(b), // eslint-disable-line compat/compat aStack, bStack, - customTesters, diffBuilder ); // RegExps are compared by their source patterns and flags. @@ -380,7 +316,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { i < bLength ? b[i] : void 0, aStack, bStack, - customTesters, diffBuilder ) && result; } @@ -425,14 +360,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { if ( j$.isAsymmetricEqualityTester_(mapKey) || (j$.isAsymmetricEqualityTester_(cmpKey) && - this.eq_( - mapKey, - cmpKey, - aStack, - bStack, - customTesters, - j$.NullDiffBuilder() - )) + this.eq_(mapKey, cmpKey, aStack, bStack, j$.NullDiffBuilder())) ) { mapValueB = b.get(cmpKey); } else { @@ -443,7 +371,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { mapValueB, aStack, bStack, - customTesters, j$.NullDiffBuilder() ); } @@ -494,7 +421,6 @@ getJasmineRequireObj().MatchersUtil = function(j$) { otherValue, baseStack, otherStack, - customTesters, j$.NullDiffBuilder() ); if (!found && prevStackSize !== baseStack.length) { @@ -559,9 +485,7 @@ getJasmineRequireObj().MatchersUtil = function(j$) { } diffBuilder.withPath(key, function() { - if ( - !self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder) - ) { + if (!self.eq_(a[key], b[key], aStack, bStack, diffBuilder)) { result = false; } }); @@ -673,9 +597,5 @@ getJasmineRequireObj().MatchersUtil = function(j$) { return formatted; } - function isDiffBuilder(obj) { - return obj && typeof obj.recordMismatch === 'function'; - } - return MatchersUtil; }; diff --git a/src/core/requireCore.js b/src/core/requireCore.js index d5ea06a6..aac94b87 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -50,40 +50,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Expectation = jRequire.Expectation(j$); j$.buildExpectationResult = jRequire.buildExpectationResult(j$); j$.JsApiReporter = jRequire.JsApiReporter(j$); - j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim( - j$ - ); j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$); j$.basicPrettyPrinter_ = j$.makePrettyPrinter(); - Object.defineProperty(j$, 'pp', { - get: function() { - j$.getEnv().deprecatedOnceWithStack( - 'jasmine.pp is deprecated and will be removed in a future release. ' + - 'Use the pp method of the matchersUtil passed to the matcher factory ' + - "or the asymmetric equality tester's `asymmetricMatch` method " + - 'instead. See ' + - ' for details.' - ); - return j$.basicPrettyPrinter_; - } - }); j$.MatchersUtil = jRequire.MatchersUtil(j$); - var staticMatchersUtil = new j$.MatchersUtil({ - customTesters: [], - pp: j$.basicPrettyPrinter_ - }); - Object.defineProperty(j$, 'matchersUtil', { - get: function() { - j$.getEnv().deprecatedOnceWithStack( - 'jasmine.matchersUtil is deprecated and will be removed ' + - 'in a future release. Use the instance passed to the matcher factory or ' + - "the asymmetric equality tester's `asymmetricMatch` method instead. " + - 'See for details.' - ); - return staticMatchersUtil; - } - }); - j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$); From 1e8619df8862a806d19b9be160617f04d11f2327 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 12 Feb 2020 15:59:38 -0800 Subject: [PATCH 03/71] Removed deprecated env methods --- lib/jasmine-core/jasmine.js | 119 --------------------- spec/core/integration/SpecRunningSpec.js | 129 ----------------------- src/core/Env.js | 119 --------------------- 3 files changed, 367 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 76f91002..3b644f9a 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1217,21 +1217,6 @@ getJasmineRequireObj().Env = function(j$) { return result; }; - Object.defineProperty(this, 'specFilter', { - get: function() { - self.deprecated( - 'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`' - ); - return config.specFilter; - }, - set: function(val) { - self.deprecated( - 'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`' - ); - config.specFilter = val; - } - }); - this.setDefaultSpyStrategy = function(defaultStrategyFn) { if (!currentRunnable()) { throw new Error( @@ -1468,110 +1453,6 @@ getJasmineRequireObj().Env = function(j$) { return buildExpectationResult(attrs); }; - /** - * Sets whether Jasmine should throw an Error when an expectation fails. - * This causes a spec to only have one expectation failure. - * @name Env#throwOnExpectationFailure - * @since 2.3.0 - * @function - * @param {Boolean} value Whether to throw when a expectation fails - * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure} - */ - this.throwOnExpectationFailure = function(value) { - this.deprecated( - 'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`' - ); - this.configure({ oneFailurePerSpec: !!value }); - }; - - this.throwingExpectationFailures = function() { - this.deprecated( - 'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`' - ); - return config.oneFailurePerSpec; - }; - - /** - * Set whether to stop suite execution when a spec fails - * @name Env#stopOnSpecFailure - * @since 2.7.0 - * @function - * @param {Boolean} value Whether to stop suite execution when a spec fails - * @deprecated Use the `failFast` option with {@link Env#configure} - */ - this.stopOnSpecFailure = function(value) { - this.deprecated( - 'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`' - ); - this.configure({ failFast: !!value }); - }; - - this.stoppingOnSpecFailure = function() { - this.deprecated( - 'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`' - ); - return config.failFast; - }; - - /** - * Set whether to randomize test execution order - * @name Env#randomizeTests - * @since 2.4.0 - * @function - * @param {Boolean} value Whether to randomize execution order - * @deprecated Use the `random` option with {@link Env#configure} - */ - this.randomizeTests = function(value) { - this.deprecated( - 'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`' - ); - config.random = !!value; - }; - - this.randomTests = function() { - this.deprecated( - 'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`' - ); - return config.random; - }; - - /** - * Set the random number seed for spec randomization - * @name Env#seed - * @since 2.4.0 - * @function - * @param {Number} value The seed value - * @deprecated Use the `seed` option with {@link Env#configure} - */ - this.seed = function(value) { - this.deprecated( - 'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`' - ); - if (value) { - config.seed = value; - } - return config.seed; - }; - - this.hidingDisabled = function(value) { - this.deprecated( - 'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`' - ); - return config.hideDisabled; - }; - - /** - * @name Env#hideDisabled - * @since 3.2.0 - * @function - */ - this.hideDisabled = function(value) { - this.deprecated( - 'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`' - ); - config.hideDisabled = !!value; - }; - this.deprecated = function(deprecation) { var runnable = currentRunnable() || topSuite; var context; diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index d6e26104..31cae08c 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -877,107 +877,6 @@ describe('spec running', function() { done(); }); }); - - it('skips to cleanup functions after an error with deprecations', function(done) { - var actions = []; - - spyOn(env, 'deprecated'); - - env.describe('Something', function() { - env.beforeEach(function() { - actions.push('outer beforeEach'); - throw new Error('error'); - }); - - env.afterEach(function() { - actions.push('outer afterEach'); - }); - - env.describe('Inner', function() { - env.beforeEach(function() { - actions.push('inner beforeEach'); - }); - - env.afterEach(function() { - actions.push('inner afterEach'); - }); - - env.it('does it', function() { - actions.push('inner it'); - }); - }); - }); - - env.throwOnExpectationFailure(true); - - env.execute(null, function() { - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); - expect(env.deprecated).toHaveBeenCalled(); - done(); - }); - }); - - it('skips to cleanup functions after done.fail is called with deprecations', function(done) { - var actions = []; - - spyOn(env, 'deprecated'); - - env.describe('Something', function() { - env.beforeEach(function(done) { - actions.push('beforeEach'); - done.fail('error'); - actions.push('after done.fail'); - }); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - env.throwOnExpectationFailure(true); - - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - expect(env.deprecated).toHaveBeenCalled(); - done(); - }); - }); - - it('skips to cleanup functions when an async function times out with deprecations', function(done) { - var actions = []; - - spyOn(env, 'deprecated'); - - env.describe('Something', function() { - env.beforeEach(function(innerDone) { - actions.push('beforeEach'); - }, 1); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - env.throwOnExpectationFailure(true); - - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - expect(env.deprecated).toHaveBeenCalled(); - done(); - }); - }); }); describe('when stopOnSpecFailure is on', function() { @@ -1004,33 +903,5 @@ describe('spec running', function() { done(); }); }); - - it('does not run further specs when one fails when configured with deprecated option', function(done) { - var actions = []; - - spyOn(env, 'deprecated'); - - env.describe('wrapper', function() { - env.it('fails', function() { - actions.push('fails'); - env.expect(1).toBe(2); - }); - }); - - env.describe('holder', function() { - env.it('does not run', function() { - actions.push('does not run'); - }); - }); - - env.configure({ random: false }); - env.stopOnSpecFailure(true); - - env.execute(null, function() { - expect(actions).toEqual(['fails']); - expect(env.deprecated).toHaveBeenCalled(); - done(); - }); - }); }); }); diff --git a/src/core/Env.js b/src/core/Env.js index b0193d15..138711e0 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -246,21 +246,6 @@ getJasmineRequireObj().Env = function(j$) { return result; }; - Object.defineProperty(this, 'specFilter', { - get: function() { - self.deprecated( - 'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`' - ); - return config.specFilter; - }, - set: function(val) { - self.deprecated( - 'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`' - ); - config.specFilter = val; - } - }); - this.setDefaultSpyStrategy = function(defaultStrategyFn) { if (!currentRunnable()) { throw new Error( @@ -497,110 +482,6 @@ getJasmineRequireObj().Env = function(j$) { return buildExpectationResult(attrs); }; - /** - * Sets whether Jasmine should throw an Error when an expectation fails. - * This causes a spec to only have one expectation failure. - * @name Env#throwOnExpectationFailure - * @since 2.3.0 - * @function - * @param {Boolean} value Whether to throw when a expectation fails - * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure} - */ - this.throwOnExpectationFailure = function(value) { - this.deprecated( - 'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`' - ); - this.configure({ oneFailurePerSpec: !!value }); - }; - - this.throwingExpectationFailures = function() { - this.deprecated( - 'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`' - ); - return config.oneFailurePerSpec; - }; - - /** - * Set whether to stop suite execution when a spec fails - * @name Env#stopOnSpecFailure - * @since 2.7.0 - * @function - * @param {Boolean} value Whether to stop suite execution when a spec fails - * @deprecated Use the `failFast` option with {@link Env#configure} - */ - this.stopOnSpecFailure = function(value) { - this.deprecated( - 'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`' - ); - this.configure({ failFast: !!value }); - }; - - this.stoppingOnSpecFailure = function() { - this.deprecated( - 'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`' - ); - return config.failFast; - }; - - /** - * Set whether to randomize test execution order - * @name Env#randomizeTests - * @since 2.4.0 - * @function - * @param {Boolean} value Whether to randomize execution order - * @deprecated Use the `random` option with {@link Env#configure} - */ - this.randomizeTests = function(value) { - this.deprecated( - 'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`' - ); - config.random = !!value; - }; - - this.randomTests = function() { - this.deprecated( - 'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`' - ); - return config.random; - }; - - /** - * Set the random number seed for spec randomization - * @name Env#seed - * @since 2.4.0 - * @function - * @param {Number} value The seed value - * @deprecated Use the `seed` option with {@link Env#configure} - */ - this.seed = function(value) { - this.deprecated( - 'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`' - ); - if (value) { - config.seed = value; - } - return config.seed; - }; - - this.hidingDisabled = function(value) { - this.deprecated( - 'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`' - ); - return config.hideDisabled; - }; - - /** - * @name Env#hideDisabled - * @since 3.2.0 - * @function - */ - this.hideDisabled = function(value) { - this.deprecated( - 'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`' - ); - config.hideDisabled = !!value; - }; - this.deprecated = function(deprecation) { var runnable = currentRunnable() || topSuite; var context; From 235efe52f1cfb3ab48622cadcc727e85b4f30e6e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 12 Feb 2020 16:55:40 -0800 Subject: [PATCH 04/71] Fixed test failure in IE --- spec/core/matchers/matchersUtilSpec.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 1be758d6..f06fe431 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -818,11 +818,16 @@ describe('matchersUtil', function() { Array.prototype, 'findIndex' ); - if (!findIndexDescriptor) { - return; - } beforeEach(function() { + if (!findIndexDescriptor) { + jasmine + .getEnv() + .pending( + 'Environment does not have a property descriptor for Array.prototype.findIndex' + ); + } + Object.defineProperty(Array.prototype, 'findIndex', { enumerable: true, value: function(predicate) { From c2b558a2daef3f947066ec0955d039c8e893411d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 17 Sep 2020 14:47:25 -0700 Subject: [PATCH 05/71] Fail specs that try to combine two forms of async --- lib/jasmine-core/jasmine.js | 8 +++----- spec/core/QueueRunnerSpec.js | 21 ++++++++++----------- src/core/QueueRunner.js | 8 +++----- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 3b644f9a..cfbd607d 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -7449,18 +7449,16 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (retval && j$.isFunction_(retval.then)) { // Issue a warning that matches the user's code if (j$.isAsyncFunction_(fn)) { - this.deprecated( + this.onException( 'An asynchronous before/it/after ' + 'function was defined with the async keyword but also took a ' + - 'done callback. This is not supported and will stop working in' + - ' the future. Either remove the done callback (recommended) or ' + + 'done callback. Either remove the done callback (recommended) or ' + 'remove the async keyword.' ); } else { - this.deprecated( + this.onException( 'An asynchronous before/it/after ' + 'function took a done callback but also returned a promise. ' + - 'This is not supported and will stop working in the future. ' + 'Either remove the done callback (recommended) or change the ' + 'function to not return a promise.' ); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 7333b02a..1aaba300 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -513,46 +513,45 @@ describe('QueueRunner', function() { expect(queueableFn2.fn).toHaveBeenCalled(); }); - it('issues a deprecation if the function also takes a parameter', function() { + it('issues an error if the function also takes a parameter', function() { var queueableFn = { fn: function(done) { return new StubPromise(); } }, - deprecated = jasmine.createSpy('deprecated'), + onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], - deprecated: deprecated + onException: onException }), env = jasmineUnderTest.getEnv(); queueRunner.execute(); - expect(deprecated).toHaveBeenCalledWith( + expect(onException).toHaveBeenCalledWith( 'An asynchronous ' + 'before/it/after function took a done callback but also returned a ' + - 'promise. This is not supported and will stop working in the future. ' + + 'promise. ' + 'Either remove the done callback (recommended) or change the function ' + 'to not return a promise.' ); }); - it('issues a more specific deprecation if the function is `async`', function() { + it('issues a more specific error if the function is `async`', function() { jasmine.getEnv().requireAsyncAwait(); eval('var fn = async function(done){};'); - var deprecated = jasmine.createSpy('deprecated'), + var onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [{ fn: fn }], - deprecated: deprecated + onException: onException }); queueRunner.execute(); - expect(deprecated).toHaveBeenCalledWith( + expect(onException).toHaveBeenCalledWith( 'An asynchronous ' + 'before/it/after function was defined with the async keyword but ' + - 'also took a done callback. This is not supported and will stop ' + - 'working in the future. Either remove the done callback ' + + 'also took a done callback. Either remove the done callback ' + '(recommended) or remove the async keyword.' ); }); diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index be9e7f62..b3458bab 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -218,18 +218,16 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (retval && j$.isFunction_(retval.then)) { // Issue a warning that matches the user's code if (j$.isAsyncFunction_(fn)) { - this.deprecated( + this.onException( 'An asynchronous before/it/after ' + 'function was defined with the async keyword but also took a ' + - 'done callback. This is not supported and will stop working in' + - ' the future. Either remove the done callback (recommended) or ' + + 'done callback. Either remove the done callback (recommended) or ' + 'remove the async keyword.' ); } else { - this.deprecated( + this.onException( 'An asynchronous before/it/after ' + 'function took a done callback but also returned a promise. ' + - 'This is not supported and will stop working in the future. ' + 'Either remove the done callback (recommended) or change the ' + 'function to not return a promise.' ); From c2a714f168ac9de4215e6e8cb90c19618eb5500e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 22 Apr 2021 19:16:06 -0700 Subject: [PATCH 06/71] Removed support for IE 10 and Safari 8 --- README.md | 4 +- lib/jasmine-core/jasmine.js | 6 +- package.json | 4 +- scripts/run-all-browsers | 2 - spec/core/PrettyPrintSpec.js | 12 +- spec/core/asymmetric_equality/AnySpec.js | 14 +-- spec/core/asymmetric_equality/AnythingSpec.js | 12 +- spec/core/asymmetric_equality/EmptySpec.js | 15 +-- .../asymmetric_equality/MapContainingSpec.js | 5 - spec/core/asymmetric_equality/NotEmptySpec.js | 15 +-- .../asymmetric_equality/SetContainingSpec.js | 5 - spec/core/baseSpec.js | 3 +- .../AsymmetricEqualityTestersSpec.js | 92 +++++----------- spec/core/matchers/matchersUtilSpec.js | 101 +++++++---------- spec/core/matchers/toEqualSpec.js | 104 ++++++------------ spec/core/matchers/toHaveSizeSpec.js | 11 +- spec/core/matchers/toThrowErrorSpec.js | 13 +-- spec/helpers/checkForArrayBuffer.js | 25 ----- spec/helpers/checkForMap.js | 45 -------- spec/helpers/checkForSet.js | 49 --------- spec/helpers/checkForTypedArrays.js | 24 ---- spec/support/jasmine-browser.js | 2 - spec/support/jasmine.json | 2 - src/core/base.js | 2 - src/core/matchers/matchersUtil.js | 4 +- 25 files changed, 139 insertions(+), 432 deletions(-) delete mode 100644 spec/helpers/checkForArrayBuffer.js delete mode 100644 spec/helpers/checkForTypedArrays.js diff --git a/README.md b/README.md index 177face0..8e5a9c3b 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed | Environment | Supported versions | |-------------------|--------------------| | Node | 10, 12, 14 | -| Safari | 8-14 | +| Safari | 9-14 | | Chrome | Evergreen | | Firefox | Evergreen, 68, 78 | | Edge | Evergreen | -| Internet Explorer | 10, 11 | +| Internet Explorer | 11 | For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work. diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index cfbd607d..7af9d344 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -298,7 +298,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map ); }; @@ -307,7 +306,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set ); }; @@ -4748,8 +4746,8 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // If we have an instance of ArrayBuffer the Uint8Array ctor // will be defined as well return self.eq_( - new Uint8Array(a), // eslint-disable-line compat/compat - new Uint8Array(b), // eslint-disable-line compat/compat + new Uint8Array(a), + new Uint8Array(b), aStack, bStack, diffBuilder diff --git a/package.json b/package.json index b90ced73..0521fae6 100644 --- a/package.json +++ b/package.json @@ -90,11 +90,11 @@ } }, "browserslist": [ - "Safari >= 8", + "Safari >= 9", "last 2 Chrome versions", "last 2 Firefox versions", "Firefox 68", "last 2 Edge versions", - "IE >= 10" + "IE >= 11" ] } diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index 331109cc..15cf4b7d 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -24,7 +24,6 @@ run_browser() { passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 run_browser "internet explorer" 11 -run_browser "internet explorer" 10 run_browser firefox latest run_browser firefox 78 run_browser firefox 68 @@ -34,7 +33,6 @@ run_browser safari 12 run_browser safari 11 run_browser safari 10 run_browser safari 9 -run_browser safari 8 run_browser MicrosoftEdge latest echo diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index de6a11d6..7d4bc6d5 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -18,8 +18,7 @@ describe('PrettyPrinter', function() { describe('stringify sets', function() { it('should stringify sets properly', function() { - jasmine.getEnv().requireFunctioningSets(); - var set = new Set(); // eslint-disable-line compat/compat + var set = new Set(); set.add(1); set.add(2); var pp = jasmineUnderTest.makePrettyPrinter(); @@ -27,12 +26,11 @@ describe('PrettyPrinter', function() { }); it('should truncate sets with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() { - jasmine.getEnv().requireFunctioningSets(); var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; - var set = new Set(); // eslint-disable-line compat/compat + var set = new Set(); set.add('a'); set.add('b'); set.add('c'); @@ -46,20 +44,18 @@ describe('PrettyPrinter', function() { describe('stringify maps', function() { it('should stringify maps properly', function() { - jasmine.getEnv().requireFunctioningMaps(); - var map = new Map(); // eslint-disable-line compat/compat + var map = new Map(); map.set(1, 2); var pp = jasmineUnderTest.makePrettyPrinter(); expect(pp(map)).toEqual('Map( [ 1, 2 ] )'); }); it('should truncate maps with more elements than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH', function() { - jasmine.getEnv().requireFunctioningMaps(); var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH; try { jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2; - var map = new Map(); // eslint-disable-line compat/compat + var map = new Map(); map.set('a', 1); map.set('b', 2); map.set('c', 3); diff --git a/spec/core/asymmetric_equality/AnySpec.js b/spec/core/asymmetric_equality/AnySpec.js index 0903cf84..5a8f6678 100644 --- a/spec/core/asymmetric_equality/AnySpec.js +++ b/spec/core/asymmetric_equality/AnySpec.js @@ -30,27 +30,21 @@ describe('Any', function() { }); it('matches a Map', function() { - jasmine.getEnv().requireFunctioningMaps(); - var any = new jasmineUnderTest.Any(Map); - expect(any.asymmetricMatch(new Map())).toBe(true); // eslint-disable-line compat/compat + expect(any.asymmetricMatch(new Map())).toBe(true); }); it('matches a Set', function() { - jasmine.getEnv().requireFunctioningSets(); - var any = new jasmineUnderTest.Any(Set); - expect(any.asymmetricMatch(new Set())).toBe(true); // eslint-disable-line compat/compat + expect(any.asymmetricMatch(new Set())).toBe(true); }); it('matches a TypedArray', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); + var any = new jasmineUnderTest.Any(Uint32Array); - var any = new jasmineUnderTest.Any(Uint32Array); // eslint-disable-line compat/compat - - expect(any.asymmetricMatch(new Uint32Array([]))).toBe(true); // eslint-disable-line compat/compat + expect(any.asymmetricMatch(new Uint32Array([]))).toBe(true); }); it('matches a Symbol', function() { diff --git a/spec/core/asymmetric_equality/AnythingSpec.js b/spec/core/asymmetric_equality/AnythingSpec.js index 61ac14e5..d72852f2 100644 --- a/spec/core/asymmetric_equality/AnythingSpec.js +++ b/spec/core/asymmetric_equality/AnythingSpec.js @@ -24,27 +24,21 @@ describe('Anything', function() { }); it('matches a Map', function() { - jasmine.getEnv().requireFunctioningMaps(); - var anything = new jasmineUnderTest.Anything(); - expect(anything.asymmetricMatch(new Map())).toBe(true); // eslint-disable-line compat/compat + expect(anything.asymmetricMatch(new Map())).toBe(true); }); it('matches a Set', function() { - jasmine.getEnv().requireFunctioningSets(); - var anything = new jasmineUnderTest.Anything(); - expect(anything.asymmetricMatch(new Set())).toBe(true); // eslint-disable-line compat/compat + expect(anything.asymmetricMatch(new Set())).toBe(true); }); it('matches a TypedArray', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); - var anything = new jasmineUnderTest.Anything(); - expect(anything.asymmetricMatch(new Uint32Array([]))).toBe(true); // eslint-disable-line compat/compat + expect(anything.asymmetricMatch(new Uint32Array([]))).toBe(true); }); it('matches a Symbol', function() { diff --git a/spec/core/asymmetric_equality/EmptySpec.js b/spec/core/asymmetric_equality/EmptySpec.js index 4ef48a86..a99f0458 100644 --- a/spec/core/asymmetric_equality/EmptySpec.js +++ b/spec/core/asymmetric_equality/EmptySpec.js @@ -22,30 +22,27 @@ describe('Empty', function() { }); it('matches an empty map', function() { - jasmine.getEnv().requireFunctioningMaps(); var empty = new jasmineUnderTest.Empty(); - var fullMap = new Map(); // eslint-disable-line compat/compat + var fullMap = new Map(); fullMap.set('thing', 2); - expect(empty.asymmetricMatch(new Map())).toBe(true); // eslint-disable-line compat/compat + expect(empty.asymmetricMatch(new Map())).toBe(true); expect(empty.asymmetricMatch(fullMap)).toBe(false); }); it('matches an empty set', function() { - jasmine.getEnv().requireFunctioningSets(); var empty = new jasmineUnderTest.Empty(); - var fullSet = new Set(); // eslint-disable-line compat/compat + var fullSet = new Set(); fullSet.add(3); - expect(empty.asymmetricMatch(new Set())).toBe(true); // eslint-disable-line compat/compat + expect(empty.asymmetricMatch(new Set())).toBe(true); expect(empty.asymmetricMatch(fullSet)).toBe(false); }); it('matches an empty typed array', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); var empty = new jasmineUnderTest.Empty(); - expect(empty.asymmetricMatch(new Int16Array())).toBe(true); // eslint-disable-line compat/compat - expect(empty.asymmetricMatch(new Int16Array([1, 2]))).toBe(false); // eslint-disable-line compat/compat + expect(empty.asymmetricMatch(new Int16Array())).toBe(true); + expect(empty.asymmetricMatch(new Int16Array([1, 2]))).toBe(false); }); }); diff --git a/spec/core/asymmetric_equality/MapContainingSpec.js b/spec/core/asymmetric_equality/MapContainingSpec.js index d55c450b..ed44f11b 100644 --- a/spec/core/asymmetric_equality/MapContainingSpec.js +++ b/spec/core/asymmetric_equality/MapContainingSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('MapContaining', function() { function MapI(iterable) { // for IE11 @@ -9,10 +8,6 @@ describe('MapContaining', function() { return map; } - beforeEach(function() { - jasmine.getEnv().requireFunctioningMaps(); - }); - it('matches any actual map to an empty map', function() { var actualMap = new MapI([['foo', 'bar']]); var containing = new jasmineUnderTest.MapContaining(new Map()); diff --git a/spec/core/asymmetric_equality/NotEmptySpec.js b/spec/core/asymmetric_equality/NotEmptySpec.js index fdb0a99e..52c4b692 100644 --- a/spec/core/asymmetric_equality/NotEmptySpec.js +++ b/spec/core/asymmetric_equality/NotEmptySpec.js @@ -22,32 +22,29 @@ describe('NotEmpty', function() { }); it('matches a non empty map', function() { - jasmine.getEnv().requireFunctioningMaps(); var notEmpty = new jasmineUnderTest.NotEmpty(); - var fullMap = new Map(); // eslint-disable-line compat/compat + var fullMap = new Map(); fullMap.set('one', 1); - var emptyMap = new Map(); // eslint-disable-line compat/compat + var emptyMap = new Map(); expect(notEmpty.asymmetricMatch(fullMap)).toBe(true); expect(notEmpty.asymmetricMatch(emptyMap)).toBe(false); }); it('matches a non empty set', function() { - jasmine.getEnv().requireFunctioningSets(); var notEmpty = new jasmineUnderTest.NotEmpty(); - var filledSet = new Set(); // eslint-disable-line compat/compat + var filledSet = new Set(); filledSet.add(1); - var emptySet = new Set(); // eslint-disable-line compat/compat + var emptySet = new Set(); expect(notEmpty.asymmetricMatch(filledSet)).toBe(true); expect(notEmpty.asymmetricMatch(emptySet)).toBe(false); }); it('matches a non empty typed array', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); var notEmpty = new jasmineUnderTest.NotEmpty(); - expect(notEmpty.asymmetricMatch(new Int16Array([1, 2, 3]))).toBe(true); // eslint-disable-line compat/compat - expect(notEmpty.asymmetricMatch(new Int16Array())).toBe(false); // eslint-disable-line compat/compat + expect(notEmpty.asymmetricMatch(new Int16Array([1, 2, 3]))).toBe(true); + expect(notEmpty.asymmetricMatch(new Int16Array())).toBe(false); }); }); diff --git a/spec/core/asymmetric_equality/SetContainingSpec.js b/spec/core/asymmetric_equality/SetContainingSpec.js index 37925c46..c986181f 100644 --- a/spec/core/asymmetric_equality/SetContainingSpec.js +++ b/spec/core/asymmetric_equality/SetContainingSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('SetContaining', function() { function SetI(iterable) { // for IE11 @@ -9,10 +8,6 @@ describe('SetContaining', function() { return set; } - beforeEach(function() { - jasmine.getEnv().requireFunctioningSets(); - }); - it('matches any actual set to an empty set', function() { var actualSet = new SetI(['foo', 'bar']); var containing = new jasmineUnderTest.SetContaining(new Set()); diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 99a0e668..3ce313cb 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -54,8 +54,7 @@ describe('base helpers', function() { describe('isSet', function() { it('returns true when the object is a Set', function() { - jasmine.getEnv().requireFunctioningSets(); - expect(jasmineUnderTest.isSet(new Set())).toBe(true); // eslint-disable-line compat/compat + expect(jasmineUnderTest.isSet(new Set())).toBe(true); }); it('returns false when the object is not a Set', function() { diff --git a/spec/core/integration/AsymmetricEqualityTestersSpec.js b/spec/core/integration/AsymmetricEqualityTestersSpec.js index 3d12f15d..dff70d46 100644 --- a/spec/core/integration/AsymmetricEqualityTestersSpec.js +++ b/spec/core/integration/AsymmetricEqualityTestersSpec.js @@ -122,40 +122,24 @@ describe('Asymmetric equality testers (Integration)', function() { }); describe('mapContaining', function() { - if (jasmine.getEnv().hasFunctioningMaps()) { - verifyPasses(function(env) { - var actual = new Map(); - actual.set('a', '2'); - var expected = new Map(); - expected.set('a', 2); + verifyPasses(function(env) { + var actual = new Map(); + actual.set('a', '2'); + var expected = new Map(); + expected.set('a', 2); - env.addCustomEqualityTester(function(a, b) { - return a.toString() === b.toString(); - }); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); - env.expect(actual).toEqual(jasmineUnderTest.mapContaining(expected)); - }); - } else { - it('passes', function() { - jasmine - .getEnv() - .pending('Browser has incomplete or missing support for Maps'); - }); - } + env.expect(actual).toEqual(jasmineUnderTest.mapContaining(expected)); + }); - if (jasmine.getEnv().hasFunctioningMaps()) { - verifyFails(function(env) { - env - .expect('something') - .toEqual(jasmineUnderTest.mapContaining(new Map())); - }); - } else { - it('fails', function() { - jasmine - .getEnv() - .pending('Browser has incomplete or missing support for Maps'); - }); - } + verifyFails(function(env) { + env + .expect('something') + .toEqual(jasmineUnderTest.mapContaining(new Map())); + }); }); describe('notEmpty', function() { @@ -185,40 +169,24 @@ describe('Asymmetric equality testers (Integration)', function() { }); describe('setContaining', function() { - if (jasmine.getEnv().hasFunctioningSets()) { - verifyPasses(function(env) { - var actual = new Set(); - actual.add('1'); - var expected = new Set(); - actual.add(1); + verifyPasses(function(env) { + var actual = new Set(); + actual.add('1'); + var expected = new Set(); + actual.add(1); - env.addCustomEqualityTester(function(a, b) { - return a.toString() === b.toString(); - }); + env.addCustomEqualityTester(function(a, b) { + return a.toString() === b.toString(); + }); - env.expect(actual).toEqual(jasmineUnderTest.setContaining(expected)); - }); - } else { - it('pases', function() { - jasmine - .getEnv() - .pending('Browser has incomplete or missing support for Sets'); - }); - } + env.expect(actual).toEqual(jasmineUnderTest.setContaining(expected)); + }); - if (jasmine.getEnv().hasFunctioningSets()) { - verifyFails(function(env) { - env - .expect('something') - .toEqual(jasmineUnderTest.setContaining(new Set())); - }); - } else { - it('fails', function() { - jasmine - .getEnv() - .pending('Browser has incomplete or missing support for Sets'); - }); - } + verifyFails(function(env) { + env + .expect('something') + .toEqual(jasmineUnderTest.setContaining(new Set())); + }); }); describe('stringMatching', function() { diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index f06fe431..20adb01e 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -439,13 +439,11 @@ describe('matchersUtil', function() { }); it('passes when MapContaining is used', function() { - jasmine.getEnv().requireFunctioningMaps(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var obj = new Map(); // eslint-disable-line compat/compat + var obj = new Map(); obj.set(1, 2); obj.set('foo', 'bar'); - var containing = new jasmineUnderTest.MapContaining(new Map()); // eslint-disable-line compat/compat + var containing = new jasmineUnderTest.MapContaining(new Map()); containing.sample.set('foo', 'bar'); expect(matchersUtil.equals(obj, containing)).toBe(true); @@ -453,13 +451,11 @@ describe('matchersUtil', function() { }); it('passes when SetContaining is used', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var obj = new Set(); // eslint-disable-line compat/compat + var obj = new Set(); obj.add(1); obj.add('foo'); - var containing = new jasmineUnderTest.SetContaining(new Set()); // eslint-disable-line compat/compat + var containing = new jasmineUnderTest.SetContaining(new Set()); containing.sample.add(1); expect(matchersUtil.equals(obj, containing)).toBe(true); @@ -591,19 +587,16 @@ describe('matchersUtil', function() { }); it('passes when comparing two empty sets', function() { - jasmine.getEnv().requireFunctioningSets(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - expect(matchersUtil.equals(new Set(), new Set())).toBe(true); // eslint-disable-line compat/compat + expect(matchersUtil.equals(new Set(), new Set())).toBe(true); }); it('passes when comparing identical sets', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add(6); setA.add(5); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add(6); setB.add(5); @@ -611,13 +604,11 @@ describe('matchersUtil', function() { }); it('passes when comparing identical sets with different insertion order and simple elements', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add(3); setA.add(6); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add(6); setB.add(3); @@ -625,26 +616,24 @@ describe('matchersUtil', function() { }); it('passes when comparing identical sets with different insertion order and complex elements 1', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA1 = new Set(); // eslint-disable-line compat/compat + var setA1 = new Set(); setA1.add(['a', 3]); setA1.add([6, 1]); - var setA2 = new Set(); // eslint-disable-line compat/compat + var setA2 = new Set(); setA1.add(['y', 3]); setA1.add([6, 1]); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add(setA1); setA.add(setA2); - var setB1 = new Set(); // eslint-disable-line compat/compat + var setB1 = new Set(); setB1.add([6, 1]); setB1.add(['a', 3]); - var setB2 = new Set(); // eslint-disable-line compat/compat + var setB2 = new Set(); setB1.add([6, 1]); setB1.add(['y', 3]); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add(setB1); setB.add(setB2); @@ -652,13 +641,11 @@ describe('matchersUtil', function() { }); it('passes when comparing identical sets with different insertion order and complex elements 2', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add([[1, 2], [3, 4]]); setA.add([[5, 6], [7, 8]]); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add([[5, 6], [7, 8]]); setB.add([[1, 2], [3, 4]]); @@ -666,13 +653,12 @@ describe('matchersUtil', function() { }); it('fails for sets with different elements', function() { - jasmine.getEnv().requireFunctioningSets(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add(6); setA.add(3); setA.add(5); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add(6); setB.add(4); setB.add(5); @@ -681,12 +667,11 @@ describe('matchersUtil', function() { }); it('fails for sets of different size', function() { - jasmine.getEnv().requireFunctioningSets(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var setA = new Set(); // eslint-disable-line compat/compat + var setA = new Set(); setA.add(6); setA.add(3); - var setB = new Set(); // eslint-disable-line compat/compat + var setB = new Set(); setB.add(6); setB.add(4); setB.add(5); @@ -695,40 +680,36 @@ describe('matchersUtil', function() { }); it('passes when comparing two empty maps', function() { - jasmine.getEnv().requireFunctioningMaps(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - expect(matchersUtil.equals(new Map(), new Map())).toBe(true); // eslint-disable-line compat/compat + expect(matchersUtil.equals(new Map(), new Map())).toBe(true); }); it('passes when comparing identical maps', function() { - jasmine.getEnv().requireFunctioningMaps(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var mapA = new Map(); // eslint-disable-line compat/compat + var mapA = new Map(); mapA.set(6, 5); - var mapB = new Map(); // eslint-disable-line compat/compat + var mapB = new Map(); mapB.set(6, 5); expect(matchersUtil.equals(mapA, mapB)).toBe(true); }); it('passes when comparing identical maps with different insertion order', function() { - jasmine.getEnv().requireFunctioningMaps(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var mapA = new Map(); // eslint-disable-line compat/compat + var mapA = new Map(); mapA.set('a', 3); mapA.set(6, 1); - var mapB = new Map(); // eslint-disable-line compat/compat + var mapB = new Map(); mapB.set(6, 1); mapB.set('a', 3); expect(matchersUtil.equals(mapA, mapB)).toBe(true); }); it('fails for maps with different elements', function() { - jasmine.getEnv().requireFunctioningMaps(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var mapA = new Map(); // eslint-disable-line compat/compat + var mapA = new Map(); mapA.set(6, 3); mapA.set(5, 1); - var mapB = new Map(); // eslint-disable-line compat/compat + var mapB = new Map(); mapB.set(6, 4); mapB.set(5, 1); @@ -736,11 +717,10 @@ describe('matchersUtil', function() { }); it('fails for maps of different size', function() { - jasmine.getEnv().requireFunctioningMaps(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var mapA = new Map(); // eslint-disable-line compat/compat + var mapA = new Map(); mapA.set(6, 3); - var mapB = new Map(); // eslint-disable-line compat/compat + var mapB = new Map(); mapB.set(6, 4); mapB.set(5, 1); expect(matchersUtil.equals(mapA, mapB)).toBe(false); @@ -795,19 +775,16 @@ describe('matchersUtil', function() { }); it('passes for ArrayBuffers with same length and content', function() { - jasmine.getEnv().requireFunctioningArrayBuffers(); - var buffer1 = new ArrayBuffer(4); // eslint-disable-line compat/compat - var buffer2 = new ArrayBuffer(4); // eslint-disable-line compat/compat + var buffer1 = new ArrayBuffer(4); + var buffer2 = new ArrayBuffer(4); var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(buffer1, buffer2)).toBe(true); }); it('fails for ArrayBuffers with same length but different content', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); - jasmine.getEnv().requireFunctioningArrayBuffers(); - var buffer1 = new ArrayBuffer(4); // eslint-disable-line compat/compat - var buffer2 = new ArrayBuffer(4); // eslint-disable-line compat/compat - var array1 = new Uint8Array(buffer1); // eslint-disable-line compat/compat + var buffer1 = new ArrayBuffer(4); + var buffer2 = new ArrayBuffer(4); + var array1 = new Uint8Array(buffer1); array1[0] = 1; var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(buffer1, buffer2)).toBe(false); @@ -1019,11 +996,9 @@ describe('matchersUtil', function() { }); it('passes for set members', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); var setItem = { foo: 'bar' }; - var set = new Set(); // eslint-disable-line compat/compat + var set = new Set(); set.add(setItem); expect(matchersUtil.contains(set, setItem)).toBe(true); @@ -1031,10 +1006,8 @@ describe('matchersUtil', function() { // documenting current behavior it('fails (!) for objects that equal to a set member', function() { - jasmine.getEnv().requireFunctioningSets(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); - var set = new Set(); // eslint-disable-line compat/compat + var set = new Set(); set.add({ foo: 'bar' }); expect(matchersUtil.contains(set, { foo: 'bar' })).toBe(false); diff --git a/spec/core/matchers/toEqualSpec.js b/spec/core/matchers/toEqualSpec.js index b2fb9f9c..fe10bab4 100644 --- a/spec/core/matchers/toEqualSpec.js +++ b/spec/core/matchers/toEqualSpec.js @@ -257,10 +257,8 @@ describe('toEqual', function() { }); it('reports mismatches between arrays of different types', function() { - jasmine.getEnv().requireFunctioningTypedArrays(); - - var actual = new Uint32Array([1, 2, 3]), // eslint-disable-line compat/compat - expected = new Uint16Array([1, 2, 3]), // eslint-disable-line compat/compat + var actual = new Uint32Array([1, 2, 3]), + expected = new Uint16Array([1, 2, 3]), message = 'Expected Uint32Array [ 1, 2, 3 ] to equal Uint16Array [ 1, 2, 3 ].'; @@ -462,11 +460,9 @@ describe('toEqual', function() { // == Sets == it('reports mismatches between Sets', function() { - jasmine.getEnv().requireFunctioningSets(); - - var actual = new Set(); // eslint-disable-line compat/compat + var actual = new Set(); actual.add(1); - var expected = new Set(); // eslint-disable-line compat/compat + var expected = new Set(); expected.add(2); var message = 'Expected Set( 1 ) to equal Set( 2 ).'; @@ -474,11 +470,9 @@ describe('toEqual', function() { }); it('reports deep mismatches within Sets', function() { - jasmine.getEnv().requireFunctioningSets(); - - var actual = new Set(); // eslint-disable-line compat/compat + var actual = new Set(); actual.add({ x: 1 }); - var expected = new Set(); // eslint-disable-line compat/compat + var expected = new Set(); expected.add({ x: 2 }); var message = 'Expected Set( Object({ x: 1 }) ) to equal Set( Object({ x: 2 }) ).'; @@ -487,11 +481,9 @@ describe('toEqual', function() { }); it('reports mismatches between Sets nested in objects', function() { - jasmine.getEnv().requireFunctioningSets(); - - var actualSet = new Set(); // eslint-disable-line compat/compat + var actualSet = new Set(); actualSet.add(1); - var expectedSet = new Set(); // eslint-disable-line compat/compat + var expectedSet = new Set(); expectedSet.add(2); var actual = { sets: [actualSet] }; @@ -502,12 +494,10 @@ describe('toEqual', function() { }); it('reports mismatches between Sets of different lengths', function() { - jasmine.getEnv().requireFunctioningSets(); - - var actual = new Set(); // eslint-disable-line compat/compat + var actual = new Set(); actual.add(1); actual.add(2); - var expected = new Set(); // eslint-disable-line compat/compat + var expected = new Set(); expected.add(2); var message = 'Expected Set( 1, 2 ) to equal Set( 2 ).'; @@ -515,13 +505,11 @@ describe('toEqual', function() { }); it('reports mismatches between Sets where actual is missing a value from expected', function() { - jasmine.getEnv().requireFunctioningSets(); - // Use 'duplicate' object in actual so sizes match - var actual = new Set(); // eslint-disable-line compat/compat + var actual = new Set(); actual.add({ x: 1 }); actual.add({ x: 1 }); - var expected = new Set(); // eslint-disable-line compat/compat + var expected = new Set(); expected.add({ x: 1 }); expected.add({ x: 2 }); var message = @@ -531,13 +519,11 @@ describe('toEqual', function() { }); it('reports mismatches between Sets where actual has a value missing from expected', function() { - jasmine.getEnv().requireFunctioningSets(); - // Use 'duplicate' object in expected so sizes match - var actual = new Set(); // eslint-disable-line compat/compat + var actual = new Set(); actual.add({ x: 1 }); actual.add({ x: 2 }); - var expected = new Set(); // eslint-disable-line compat/compat + var expected = new Set(); expected.add({ x: 1 }); expected.add({ x: 1 }); var message = @@ -549,23 +535,19 @@ describe('toEqual', function() { // == Maps == it('does not report mismatches between deep equal Maps', function() { - jasmine.getEnv().requireFunctioningMaps(); - // values are the same but with different object identity - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set('a', { x: 1 }); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set('a', { x: 1 }); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports deep mismatches within Maps', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set('a', { x: 1 }); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set('a', { x: 2 }); var message = "Expected Map( [ 'a', Object({ x: 1 }) ] ) to equal Map( [ 'a', Object({ x: 2 }) ] )."; @@ -574,11 +556,9 @@ describe('toEqual', function() { }); it('reports mismatches between Maps nested in objects', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = { Maps: [new Map()] }; // eslint-disable-line compat/compat + var actual = { Maps: [new Map()] }; actual.Maps[0].set('a', 1); - var expected = { Maps: [new Map()] }; // eslint-disable-line compat/compat + var expected = { Maps: [new Map()] }; expected.Maps[0].set('a', 2); var message = @@ -588,11 +568,9 @@ describe('toEqual', function() { }); it('reports mismatches between Maps of different lengths', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set('a', 1); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set('a', 2); expected.set('b', 1); var message = @@ -602,11 +580,9 @@ describe('toEqual', function() { }); it('reports mismatches between Maps with equal values but differing keys', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set('a', 1); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set('b', 1); var message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'b', 1 ] )."; @@ -614,22 +590,19 @@ describe('toEqual', function() { }); it('does not report mismatches between Maps with keys with same object identity', function() { - jasmine.getEnv().requireFunctioningMaps(); var key = { x: 1 }; - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set(key, 2); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set(key, 2); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports mismatches between Maps with identical keys with different object identity', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set({ x: 1 }, 2); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set({ x: 1 }, 2); var message = 'Expected Map( [ Object({ x: 1 }), 2 ] ) to equal Map( [ Object({ x: 1 }), 2 ] ).'; @@ -638,36 +611,32 @@ describe('toEqual', function() { }); it('does not report mismatches when comparing Map key to jasmine.anything()', function() { - jasmine.getEnv().requireFunctioningMaps(); - - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set('a', 1); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set(jasmineUnderTest.anything(), 1); expect(compareEquals(actual, expected).pass).toBe(true); }); it('does not report mismatches when comparing Maps with the same symbol keys', function() { - jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningSymbols(); var key = Symbol(); // eslint-disable-line compat/compat - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set(key, 1); - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set(key, 1); expect(compareEquals(actual, expected).pass).toBe(true); }); it('reports mismatches between Maps with different symbol keys', function() { - jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningSymbols(); - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set(Symbol(), 1); // eslint-disable-line compat/compat - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set(Symbol(), 1); // eslint-disable-line compat/compat var message = 'Expected Map( [ Symbol(), 1 ] ) to equal Map( [ Symbol(), 1 ] ).'; @@ -676,12 +645,11 @@ describe('toEqual', function() { }); it('does not report mismatches when comparing Map symbol key to jasmine.anything()', function() { - jasmine.getEnv().requireFunctioningMaps(); jasmine.getEnv().requireFunctioningSymbols(); - var actual = new Map(); // eslint-disable-line compat/compat + var actual = new Map(); actual.set(Symbol(), 1); // eslint-disable-line compat/compat - var expected = new Map(); // eslint-disable-line compat/compat + var expected = new Map(); expected.set(jasmineUnderTest.anything(), 1); expect(compareEquals(actual, expected).pass).toBe(true); diff --git a/spec/core/matchers/toHaveSizeSpec.js b/spec/core/matchers/toHaveSizeSpec.js index fc5baf91..c0f3344c 100644 --- a/spec/core/matchers/toHaveSizeSpec.js +++ b/spec/core/matchers/toHaveSizeSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('toHaveSize', function() { 'use strict'; @@ -59,8 +58,6 @@ describe('toHaveSize', function() { }); it('passes for a Map whose length matches', function() { - jasmine.getEnv().requireFunctioningMaps(); - var map = new Map(); map.set('a', 1); map.set('b', 2); @@ -72,8 +69,6 @@ describe('toHaveSize', function() { }); 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); @@ -85,8 +80,6 @@ describe('toHaveSize', function() { }); it('passes for a Set whose length matches', function() { - jasmine.getEnv().requireFunctioningSets(); - var set = new Set(); set.add('a'); set.add('b'); @@ -98,8 +91,6 @@ describe('toHaveSize', function() { }); it('fails for a Set whose length does not match', function() { - jasmine.getEnv().requireFunctioningSets(); - var set = new Set(); set.add('a'); set.add('b'); @@ -115,7 +106,7 @@ describe('toHaveSize', function() { var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { - matcher.compare(new WeakSet(), 2); + matcher.compare(new WeakSet(), 2); // eslint-disable-line compat/compat }).toThrowError('Cannot get size of [object WeakSet].'); }); diff --git a/spec/core/matchers/toThrowErrorSpec.js b/spec/core/matchers/toThrowErrorSpec.js index c8532276..6d76a1d1 100644 --- a/spec/core/matchers/toThrowErrorSpec.js +++ b/spec/core/matchers/toThrowErrorSpec.js @@ -92,16 +92,9 @@ describe('toThrowError', function() { iframe.src = 'about:blank'; var iframeDocument = iframe.contentWindow.document; - if (iframeDocument.body) { - iframeDocument.body.appendChild( - iframeDocument.createElement('script') - ).textContent = "function method() { throw new Error('foo'); }"; - } else { - // IE 10 and older - iframeDocument.write( - "" - ); - } + iframeDocument.body.appendChild( + iframeDocument.createElement('script') + ).textContent = "function method() { throw new Error('foo'); }"; var result = matcher.compare(iframe.contentWindow.method); expect(result.pass).toBe(true); diff --git a/spec/helpers/checkForArrayBuffer.js b/spec/helpers/checkForArrayBuffer.js deleted file mode 100644 index a04a94e9..00000000 --- a/spec/helpers/checkForArrayBuffer.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasFunctioningArrayBuffers() { - if (typeof ArrayBuffer === 'undefined') { - return false; - } - - try { - var buffer = new ArrayBuffer(2); - var view8bit = new Uint8Array(buffer); - var view16bit = new Uint16Array(buffer); - view16bit[0] = 0xabcd; - return view8bit[0] === 0xcd && view8bit[1] === 0xab; - } catch (e) { - return false; - } - } - - env.requireFunctioningArrayBuffers = function() { - env.requireFunctioningTypedArrays(); - if (!hasFunctioningArrayBuffers()) { - env.pending('Browser has incomplete or missing support for ArrayBuffer'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/checkForMap.js b/spec/helpers/checkForMap.js index b8bdacd3..87f66410 100644 --- a/spec/helpers/checkForMap.js +++ b/spec/helpers/checkForMap.js @@ -1,50 +1,5 @@ /* eslint-disable compat/compat */ (function(env) { - env.hasFunctioningMaps = function() { - if (typeof Map === 'undefined') { - return false; - } - - try { - var s = new Map(); - s.set('a', 1); - s.set('b', 2); - - if (s.size !== 2) { - return false; - } - if (s.has('a') !== true) { - return false; - } - - var iterations = 0; - var ifForEachWorking = true; - s.forEach(function(value, key, map) { - ifForEachWorking = ifForEachWorking && map === s; - if (key === 'a') { - ifForEachWorking = ifForEachWorking && value === 1; - } - iterations++; - }); - if (iterations !== 2) { - return false; - } - if (ifForEachWorking !== true) { - return false; - } - - return true; - } catch (e) { - return false; - } - }; - - env.requireFunctioningMaps = function() { - if (!env.hasFunctioningMaps()) { - 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'); diff --git a/spec/helpers/checkForSet.js b/spec/helpers/checkForSet.js index cae95db7..203befcc 100644 --- a/spec/helpers/checkForSet.js +++ b/spec/helpers/checkForSet.js @@ -1,54 +1,5 @@ /* eslint-disable compat/compat */ (function(env) { - env.hasFunctioningSets = function() { - if (typeof Set === 'undefined') { - return false; - } - - try { - var s = new Set(); - s.add(1); - s.add(2); - - if (s.size !== 2) { - return false; - } - if (s.has(1) !== true) { - return false; - } - - var iterations = 0; - var isForEachWorking = true; - s.forEach(function(value, key, set) { - isForEachWorking = isForEachWorking && set === s; - - if (iterations === 0) { - isForEachWorking = isForEachWorking && key === value && value === 1; - } else if (iterations === 1) { - isForEachWorking = isForEachWorking && key === value && value === 2; - } - - iterations++; - }); - if (iterations !== 2) { - return false; - } - if (isForEachWorking !== true) { - return false; - } - - return true; - } catch (e) { - return false; - } - }; - - env.requireFunctioningSets = function() { - if (!env.hasFunctioningSets()) { - 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'); diff --git a/spec/helpers/checkForTypedArrays.js b/spec/helpers/checkForTypedArrays.js deleted file mode 100644 index 6902120b..00000000 --- a/spec/helpers/checkForTypedArrays.js +++ /dev/null @@ -1,24 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasFunctioningTypedArrays() { - if (typeof Uint32Array === 'undefined') { - return false; - } - - try { - var a = new Uint32Array([1, 2, 3]); - if (a.length !== 3) { - return false; - } - return true; - } catch (e) { - return false; - } - } - - env.requireFunctioningTypedArrays = function() { - if (!hasFunctioningTypedArrays()) { - env.pending('Browser has incomplete or missing support for typed arrays'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/support/jasmine-browser.js b/spec/support/jasmine-browser.js index 486d4df6..cc7e378a 100644 --- a/spec/support/jasmine-browser.js +++ b/spec/support/jasmine-browser.js @@ -20,11 +20,9 @@ module.exports = { 'helpers/asyncAwait.js', 'helpers/generator.js', 'helpers/BrowserFlags.js', - 'helpers/checkForArrayBuffer.js', 'helpers/checkForMap.js', 'helpers/checkForSet.js', 'helpers/checkForSymbol.js', - 'helpers/checkForTypedArrays.js', 'helpers/checkForUrl.js', 'helpers/domHelpers.js', 'helpers/integrationMatchers.js', diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index 68878471..1a0ca3b2 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -7,11 +7,9 @@ "helpers": [ "helpers/asyncAwait.js", "helpers/generator.js", - "helpers/checkForArrayBuffer.js", "helpers/checkForMap.js", "helpers/checkForSet.js", "helpers/checkForSymbol.js", - "helpers/checkForTypedArrays.js", "helpers/checkForUrl.js", "helpers/domHelpers.js", "helpers/integrationMatchers.js", diff --git a/src/core/base.js b/src/core/base.js index 3c1da322..37707541 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -138,7 +138,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map ); }; @@ -147,7 +146,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set ); }; diff --git a/src/core/matchers/matchersUtil.js b/src/core/matchers/matchersUtil.js index c2cf7c82..f0e09575 100644 --- a/src/core/matchers/matchersUtil.js +++ b/src/core/matchers/matchersUtil.js @@ -234,8 +234,8 @@ getJasmineRequireObj().MatchersUtil = function(j$) { // If we have an instance of ArrayBuffer the Uint8Array ctor // will be defined as well return self.eq_( - new Uint8Array(a), // eslint-disable-line compat/compat - new Uint8Array(b), // eslint-disable-line compat/compat + new Uint8Array(a), + new Uint8Array(b), aStack, bStack, diffBuilder From e4e232864d3b4c99ec1a44c17c4387534cafa25f Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 21 May 2021 20:58:20 -0700 Subject: [PATCH 07/71] Don't expose Suite objects as `this` of describe functions This was a holdover from 1.x that should have been removed in 2.0, but was missed. Suite is meant to be private, and almost none of its methods can be safely called by user code. --- lib/jasmine-core/jasmine.js | 36 +------------------------------- spec/core/EnvSpec.js | 35 ++----------------------------- spec/helpers/checkForProxy.js | 17 --------------- spec/support/jasmine-browser.js | 1 - spec/support/jasmine.json | 1 - src/core/Env.js | 2 +- src/core/deprecatingThisProxy.js | 32 ---------------------------- src/core/requireCore.js | 1 - 8 files changed, 4 insertions(+), 121 deletions(-) delete mode 100644 spec/helpers/checkForProxy.js delete mode 100644 src/core/deprecatingThisProxy.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 25e70185..1e4c891c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -65,7 +65,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Env = jRequire.Env(j$); - j$.deprecatingThisProxy = jRequire.deprecatingThisProxy(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); @@ -1957,7 +1956,7 @@ getJasmineRequireObj().Env = function(j$) { var declarationError = null; try { - specDefinitions.call(j$.deprecatingThisProxy(suite, self)); + specDefinitions(); } catch (e) { declarationError = e; } @@ -3368,39 +3367,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { return DelayedFunctionScheduler; }; -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingThisProxy = function(j$) { - var msg = "Access to 'this' in describe functions is deprecated."; - - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(suite) { - return suite; - }; - } - - function DeprecatingThisProxyHandler(env) { - this._env = env; - } - - DeprecatingThisProxyHandler.prototype.get = function(target, prop, receiver) { - this._env.deprecated(msg); - return target[prop]; - }; - - DeprecatingThisProxyHandler.prototype.set = function(target, prop, value) { - this._env.deprecated(msg); - return (target[prop] = value); - }; - - return function(suite, env) { - return new Proxy(suite, new DeprecatingThisProxyHandler(env)); - }; -}; - getJasmineRequireObj().errors = function() { function ExpectationFailed() {} diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 12000f34..23c0d373 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -441,38 +441,7 @@ describe('Env', function() { }); }); - it("deprecates access to 'this' in describes", function() { - jasmine.getEnv().requireProxy(); - var msg = "Access to 'this' in describe functions is deprecated.", - ran = false; - spyOn(env, 'deprecated'); - - env.describe('a suite', function() { - expect(this.description).toEqual('a suite'); - expect(env.deprecated).toHaveBeenCalledWith(msg); - env.deprecated.calls.reset(); - - this.foo = 1; - expect(env.deprecated).toHaveBeenCalledWith(msg); - expect(this.foo).toEqual(1); - env.deprecated.calls.reset(); - - expect(this.getFullName()).toEqual('a suite'); - expect(env.deprecated).toHaveBeenCalledWith(msg); - env.deprecated.calls.reset(); - - env.it('has a spec'); - ran = true; - }); - - expect(ran).toBeTrue(); - }); - - // TODO: Remove this in the next major version. Suites were never meant to be - // exposed via describe 'this' in >= 2.0, and user code should not rely on it. - // This spec is just here to make sure we don't break user code that *does* - // rely on it in older browsers (without Proxy) while deprecating it. - it("sets 'this' to the Suite in describes", function() { + it("does not expose the suite as 'this'", function() { var suiteThis; spyOn(env, 'deprecated'); @@ -481,6 +450,6 @@ describe('Env', function() { env.it('has a spec'); }); - expect(suiteThis).toBeInstanceOf(jasmineUnderTest.Suite); + expect(suiteThis).not.toBeInstanceOf(jasmineUnderTest.Suite); }); }); diff --git a/spec/helpers/checkForProxy.js b/spec/helpers/checkForProxy.js deleted file mode 100644 index b4062d0b..00000000 --- a/spec/helpers/checkForProxy.js +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasProxyConstructor() { - try { - new Proxy({}, {}); - return true; - } catch (e) { - return false; - } - } - - env.requireProxy = function() { - if (!hasProxyConstructor()) { - env.pending('Environment does not support Proxy'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/support/jasmine-browser.js b/spec/support/jasmine-browser.js index 1fc16d01..9062bf8a 100644 --- a/spec/support/jasmine-browser.js +++ b/spec/support/jasmine-browser.js @@ -21,7 +21,6 @@ module.exports = { 'helpers/generator.js', 'helpers/BrowserFlags.js', 'helpers/checkForMap.js', - 'helpers/checkForProxy.js', 'helpers/checkForSet.js', 'helpers/checkForSymbol.js', 'helpers/checkForUrl.js', diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index d6369bf2..1a0ca3b2 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -8,7 +8,6 @@ "helpers/asyncAwait.js", "helpers/generator.js", "helpers/checkForMap.js", - "helpers/checkForProxy.js", "helpers/checkForSet.js", "helpers/checkForSymbol.js", "helpers/checkForUrl.js", diff --git a/src/core/Env.js b/src/core/Env.js index 813c4843..39c8cf81 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -987,7 +987,7 @@ getJasmineRequireObj().Env = function(j$) { var declarationError = null; try { - specDefinitions.call(j$.deprecatingThisProxy(suite, self)); + specDefinitions(); } catch (e) { declarationError = e; } diff --git a/src/core/deprecatingThisProxy.js b/src/core/deprecatingThisProxy.js deleted file mode 100644 index 6f924b18..00000000 --- a/src/core/deprecatingThisProxy.js +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingThisProxy = function(j$) { - var msg = "Access to 'this' in describe functions is deprecated."; - - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(suite) { - return suite; - }; - } - - function DeprecatingThisProxyHandler(env) { - this._env = env; - } - - DeprecatingThisProxyHandler.prototype.get = function(target, prop, receiver) { - this._env.deprecated(msg); - return target[prop]; - }; - - DeprecatingThisProxyHandler.prototype.set = function(target, prop, value) { - this._env.deprecated(msg); - return (target[prop] = value); - }; - - return function(suite, env) { - return new Proxy(suite, new DeprecatingThisProxyHandler(env)); - }; -}; diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 13cc6cc5..aac94b87 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -43,7 +43,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Env = jRequire.Env(j$); - j$.deprecatingThisProxy = jRequire.deprecatingThisProxy(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); From a0f6b77c3ed43400b748fc717e1490367fedcfb2 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 22 May 2021 17:33:46 -0700 Subject: [PATCH 08/71] Remove access to non-public Suite and Spec members via Env#topSuite --- lib/jasmine-core/jasmine.js | 286 +++++++----------------------- spec/core/EnvSpec.js | 93 +--------- spec/helpers/checkForProxy.js | 17 -- spec/support/jasmine-browser.js | 1 - spec/support/jasmine.json | 1 - src/core/Env.js | 2 +- src/core/Spec.js | 40 +++-- src/core/Suite.js | 72 +++++--- src/core/deprecatingSpecProxy.js | 70 -------- src/core/deprecatingSuiteProxy.js | 98 ---------- src/core/requireCore.js | 2 - 11 files changed, 142 insertions(+), 540 deletions(-) delete mode 100644 spec/helpers/checkForProxy.js delete mode 100644 src/core/deprecatingSpecProxy.js delete mode 100644 src/core/deprecatingSuiteProxy.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 75c578c5..8d5998a4 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -66,8 +66,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Deprecator = jRequire.Deprecator(j$); j$.Env = jRequire.Env(j$); - j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$); - j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); @@ -672,21 +670,11 @@ getJasmineRequireObj().util = function(j$) { }; getJasmineRequireObj().Spec = function(j$) { - /** - * @interface Spec - * @see Configuration#specFilter - */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; - /** - * The description passed to the {@link it} that created this spec. - * @name Spec#description - * @readonly - * @type {string} - */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -878,12 +866,6 @@ getJasmineRequireObj().Spec = function(j$) { return 'passed'; }; - /** - * The full description including all ancestors of this spec. - * @name Spec#getFullName - * @function - * @returns {string} - */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; @@ -916,6 +898,30 @@ getJasmineRequireObj().Spec = function(j$) { ); }; + /** + * @interface Spec + * @see Configuration#specFilter + */ + Spec.prototype.buildMetadata = function() { + return { + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + }; + return Spec; }; @@ -1526,7 +1532,7 @@ getJasmineRequireObj().Env = function(j$) { * @return {Suite} the root suite */ this.topSuite = function() { - return j$.deprecatingSuiteProxy(topSuite, null, this); + return topSuite.buildMetadata(null); }; /** @@ -3354,176 +3360,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { return DelayedFunctionScheduler; }; -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingSpecProxy = function(j$) { - function isMember(target, prop) { - return ( - Object.keys(target).indexOf(prop) !== -1 || - Object.keys(j$.Spec.prototype).indexOf(prop) !== -1 - ); - } - - function isAllowedMember(prop) { - return prop === 'description' || prop === 'getFullName'; - } - - function msg(member) { - var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1'); - return ( - 'Access to private Spec members (in this case `' + - memberName + - '`) via Env#topSuite is not supported and will break in ' + - 'a future release. See ' + - 'for correct usage.' - ); - } - - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(spec) { - return spec; - }; - } - - function DeprecatingSpecProxyHandler(env) { - this._env = env; - } - - DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) { - this._maybeDeprecate(target, prop); - - if (prop === 'getFullName') { - // getFullName calls a private method. Re-bind 'this' to avoid a bogus - // deprecation warning. - return target.getFullName.bind(target); - } else { - return target[prop]; - } - }; - - DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) { - this._maybeDeprecate(target, prop); - return (target[prop] = value); - }; - - DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function( - target, - prop - ) { - if (isMember(target, prop) && !isAllowedMember(prop)) { - this._env.deprecated(msg(prop)); - } - }; - - function deprecatingSpecProxy(spec, env) { - return new Proxy(spec, new DeprecatingSpecProxyHandler(env)); - } - - return deprecatingSpecProxy; -}; - -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingSuiteProxy = function(j$) { - var allowedMembers = [ - 'children', - 'description', - 'parentSuite', - 'getFullName' - ]; - - function isMember(target, prop) { - return ( - Object.keys(target).indexOf(prop) !== -1 || - Object.keys(j$.Suite.prototype).indexOf(prop) !== -1 - ); - } - - function isAllowedMember(prop) { - return allowedMembers.indexOf(prop) !== -1; - } - - function msg(member) { - var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1'); - return ( - 'Access to private Suite members (in this case `' + - memberName + - '`) via Env#topSuite is not supported and will break in ' + - 'a future release. See ' + - 'for correct usage.' - ); - } - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(suite) { - return suite; - }; - } - - function DeprecatingSuiteProxyHandler(parentSuite, env) { - this._parentSuite = parentSuite; - this._env = env; - } - - DeprecatingSuiteProxyHandler.prototype.get = function( - target, - prop, - receiver - ) { - if (prop === 'children') { - if (!this._children) { - this._children = target.children.map( - this._proxyForChild.bind(this, receiver) - ); - } - - return this._children; - } else if (prop === 'parentSuite') { - return this._parentSuite; - } else { - this._maybeDeprecate(target, prop); - return target[prop]; - } - }; - - DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) { - debugger; - this._maybeDeprecate(target, prop); - return (target[prop] = value); - }; - - DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function( - target, - prop - ) { - if (isMember(target, prop) && !isAllowedMember(prop)) { - this._env.deprecated(msg(prop)); - } - }; - - DeprecatingSuiteProxyHandler.prototype._proxyForChild = function( - ownProxy, - child - ) { - if (child.children) { - return deprecatingSuiteProxy(child, ownProxy, this._env); - } else { - return j$.deprecatingSpecProxy(child, this._env); - } - }; - - function deprecatingSuiteProxy(suite, parentSuite, env) { - return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env)); - } - - return deprecatingSuiteProxy; -}; - getJasmineRequireObj().Deprecator = function(j$) { function Deprecator(topSuite) { this.topSuite_ = topSuite; @@ -9088,26 +8924,10 @@ getJasmineRequireObj().StackTrace = function(j$) { }; getJasmineRequireObj().Suite = function(j$) { - /** - * @interface Suite - * @see Env#topSuite - */ function Suite(attrs) { this.env = attrs.env; this.id = attrs.id; - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ this.parentSuite = attrs.parentSuite; - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; @@ -9118,14 +8938,7 @@ getJasmineRequireObj().Suite = function(j$) { this.afterFns = []; this.beforeAllFns = []; this.afterAllFns = []; - this.timer = attrs.timer || new j$.Timer(); - - /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} - */ this.children = []; /** @@ -9163,12 +8976,6 @@ getJasmineRequireObj().Suite = function(j$) { return this.asyncExpectationFactory(actual, this); }; - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - */ Suite.prototype.getFullName = function() { var fullName = []; for ( @@ -9303,6 +9110,49 @@ getJasmineRequireObj().Suite = function(j$) { ); }; + Suite.prototype.buildMetadata = function(parentMetadata) { + /** + * @interface Suite + * @see Env#topSuite + */ + var result = { + /** + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} + */ + parentSuite: parentMetadata, + + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + */ + result.children = this.children.map(function(child) { + return child.buildMetadata(result); + }); + + return result; + }; + function isFailure(args) { return !args[0]; } diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 56412c7a..fde0767a 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -39,19 +39,25 @@ describe('Env', function() { }); suite = env.topSuite(); + expect(suite).not.toBeInstanceOf(jasmineUnderTest.Suite); expect(suite.description).toEqual('Jasmine__TopLevel__Suite'); expect(suite.getFullName()).toEqual(''); expect(suite.children.length).toEqual(2); + expect(suite.children[0]).not.toBeInstanceOf(jasmineUnderTest.Spec); expect(suite.children[0].description).toEqual('a top level spec'); expect(suite.children[0].getFullName()).toEqual('a top level spec'); expect(suite.children[0].children).toBeFalsy(); + expect(suite.children[1]).not.toBeInstanceOf(jasmineUnderTest.Suite); expect(suite.children[1].description).toEqual('a suite'); expect(suite.children[1].getFullName()).toEqual('a suite'); expect(suite.children[1].parentSuite).toBe(suite); expect(suite.children[1].children.length).toEqual(2); + expect(suite.children[1].children[0]).not.toBeInstanceOf( + jasmineUnderTest.Spec + ); expect(suite.children[1].children[0].description).toEqual('a spec'); expect(suite.children[1].children[0].getFullName()).toEqual( 'a suite a spec' @@ -75,93 +81,6 @@ describe('Env', function() { ); expect(suite.children[1].children[1].children[0].children).toBeFalsy(); }); - - it('does not deprecate access to public Suite and Spec members', function() { - jasmine.getEnv().requireProxy(); - var suite; - spyOn(env, 'deprecated'); - - env.it('a top level spec'); - env.describe('a suite', function() { - env.it('a spec'); - }); - - suite = env.topSuite(); - suite.description; - suite.getFullName(); - suite.children; - suite.parentSuite; - suite.children[0].description; - suite.children[0].getFullName(); - suite.children[0].children; - - suite.children[1].description; - suite.children[1].getFullName(); - suite.children[1].parentSuite; - suite.children[1].children; - - expect(env.deprecated).not.toHaveBeenCalled(); - }); - - it('deprecates access to internal Suite and Spec members', function() { - jasmine.getEnv().requireProxy(); - var topSuite, expectationFactory, spec; - - env.it('a top level spec'); - spyOn(env, 'deprecated'); - topSuite = env.topSuite(); - - topSuite.expectationFactory; - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Suite ' + - 'members (in this case `expectationFactory`) via Env#topSuite is ' + - 'not supported and will break in a future release. See ' + - ' for correct usage.' - ); - env.deprecated.calls.reset(); - - topSuite.expectationFactory = expectationFactory; - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Suite ' + - 'members (in this case `expectationFactory`) via Env#topSuite is ' + - 'not supported and will break in a future release. See ' + - ' for correct usage.' - ); - - topSuite.status(); - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Suite ' + - 'members (in this case `status`) via Env#topSuite is ' + - 'not supported and will break in a future release. See ' + - ' for correct usage.' - ); - - spec = topSuite.children[0]; - spec.pend(); - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Spec ' + - 'members (in this case `pend`) via Env#topSuite ' + - 'is not supported and will break in a future release. See ' + - ' for correct usage.' - ); - - expectationFactory = spec.expectationFactory; - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Spec ' + - 'members (in this case `expectationFactory`) via Env#topSuite ' + - 'is not supported and will break in a future release. See ' + - ' for correct usage.' - ); - env.deprecated.calls.reset(); - - spec.expectationFactory = expectationFactory; - expect(env.deprecated).toHaveBeenCalledWith( - 'Access to private Spec ' + - 'members (in this case `expectationFactory`) via Env#topSuite ' + - 'is not supported and will break in a future release. See ' + - ' for correct usage.' - ); - }); }); it('accepts its own current configureation', function() { diff --git a/spec/helpers/checkForProxy.js b/spec/helpers/checkForProxy.js deleted file mode 100644 index b4062d0b..00000000 --- a/spec/helpers/checkForProxy.js +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasProxyConstructor() { - try { - new Proxy({}, {}); - return true; - } catch (e) { - return false; - } - } - - env.requireProxy = function() { - if (!hasProxyConstructor()) { - env.pending('Environment does not support Proxy'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/support/jasmine-browser.js b/spec/support/jasmine-browser.js index 1fc16d01..9062bf8a 100644 --- a/spec/support/jasmine-browser.js +++ b/spec/support/jasmine-browser.js @@ -21,7 +21,6 @@ module.exports = { 'helpers/generator.js', 'helpers/BrowserFlags.js', 'helpers/checkForMap.js', - 'helpers/checkForProxy.js', 'helpers/checkForSet.js', 'helpers/checkForSymbol.js', 'helpers/checkForUrl.js', diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index d6369bf2..1a0ca3b2 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -8,7 +8,6 @@ "helpers/asyncAwait.js", "helpers/generator.js", "helpers/checkForMap.js", - "helpers/checkForProxy.js", "helpers/checkForSet.js", "helpers/checkForSymbol.js", "helpers/checkForUrl.js", diff --git a/src/core/Env.js b/src/core/Env.js index 3368de22..f106b426 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -554,7 +554,7 @@ getJasmineRequireObj().Env = function(j$) { * @return {Suite} the root suite */ this.topSuite = function() { - return j$.deprecatingSuiteProxy(topSuite, null, this); + return topSuite.buildMetadata(null); }; /** diff --git a/src/core/Spec.js b/src/core/Spec.js index 81d244dd..0382dd71 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -1,19 +1,9 @@ getJasmineRequireObj().Spec = function(j$) { - /** - * @interface Spec - * @see Configuration#specFilter - */ function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.resultCallback = attrs.resultCallback || function() {}; this.id = attrs.id; - /** - * The description passed to the {@link it} that created this spec. - * @name Spec#description - * @readonly - * @type {string} - */ this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = @@ -205,12 +195,6 @@ getJasmineRequireObj().Spec = function(j$) { return 'passed'; }; - /** - * The full description including all ancestors of this spec. - * @name Spec#getFullName - * @function - * @returns {string} - */ Spec.prototype.getFullName = function() { return this.getSpecName(this); }; @@ -243,6 +227,30 @@ getJasmineRequireObj().Spec = function(j$) { ); }; + /** + * @interface Spec + * @see Configuration#specFilter + */ + Spec.prototype.buildMetadata = function() { + return { + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + }; + return Spec; }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 5043017b..390a72eb 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,24 +1,8 @@ getJasmineRequireObj().Suite = function(j$) { - /** - * @interface Suite - * @see Env#topSuite - */ function Suite(attrs) { this.env = attrs.env; this.id = attrs.id; - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ this.parentSuite = attrs.parentSuite; - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - */ this.description = attrs.description; this.expectationFactory = attrs.expectationFactory; this.asyncExpectationFactory = attrs.asyncExpectationFactory; @@ -29,14 +13,7 @@ getJasmineRequireObj().Suite = function(j$) { this.afterFns = []; this.beforeAllFns = []; this.afterAllFns = []; - this.timer = attrs.timer || new j$.Timer(); - - /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} - */ this.children = []; /** @@ -74,12 +51,6 @@ getJasmineRequireObj().Suite = function(j$) { return this.asyncExpectationFactory(actual, this); }; - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - */ Suite.prototype.getFullName = function() { var fullName = []; for ( @@ -214,6 +185,49 @@ getJasmineRequireObj().Suite = function(j$) { ); }; + Suite.prototype.buildMetadata = function(parentMetadata) { + /** + * @interface Suite + * @see Env#topSuite + */ + var result = { + /** + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} + */ + parentSuite: parentMetadata, + + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + */ + result.children = this.children.map(function(child) { + return child.buildMetadata(result); + }); + + return result; + }; + function isFailure(args) { return !args[0]; } diff --git a/src/core/deprecatingSpecProxy.js b/src/core/deprecatingSpecProxy.js deleted file mode 100644 index c490705f..00000000 --- a/src/core/deprecatingSpecProxy.js +++ /dev/null @@ -1,70 +0,0 @@ -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingSpecProxy = function(j$) { - function isMember(target, prop) { - return ( - Object.keys(target).indexOf(prop) !== -1 || - Object.keys(j$.Spec.prototype).indexOf(prop) !== -1 - ); - } - - function isAllowedMember(prop) { - return prop === 'description' || prop === 'getFullName'; - } - - function msg(member) { - var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1'); - return ( - 'Access to private Spec members (in this case `' + - memberName + - '`) via Env#topSuite is not supported and will break in ' + - 'a future release. See ' + - 'for correct usage.' - ); - } - - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(spec) { - return spec; - }; - } - - function DeprecatingSpecProxyHandler(env) { - this._env = env; - } - - DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) { - this._maybeDeprecate(target, prop); - - if (prop === 'getFullName') { - // getFullName calls a private method. Re-bind 'this' to avoid a bogus - // deprecation warning. - return target.getFullName.bind(target); - } else { - return target[prop]; - } - }; - - DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) { - this._maybeDeprecate(target, prop); - return (target[prop] = value); - }; - - DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function( - target, - prop - ) { - if (isMember(target, prop) && !isAllowedMember(prop)) { - this._env.deprecated(msg(prop)); - } - }; - - function deprecatingSpecProxy(spec, env) { - return new Proxy(spec, new DeprecatingSpecProxyHandler(env)); - } - - return deprecatingSpecProxy; -}; diff --git a/src/core/deprecatingSuiteProxy.js b/src/core/deprecatingSuiteProxy.js deleted file mode 100644 index 11759374..00000000 --- a/src/core/deprecatingSuiteProxy.js +++ /dev/null @@ -1,98 +0,0 @@ -/* eslint-disable compat/compat */ -// TODO: Remove this in the next major release. -getJasmineRequireObj().deprecatingSuiteProxy = function(j$) { - var allowedMembers = [ - 'children', - 'description', - 'parentSuite', - 'getFullName' - ]; - - function isMember(target, prop) { - return ( - Object.keys(target).indexOf(prop) !== -1 || - Object.keys(j$.Suite.prototype).indexOf(prop) !== -1 - ); - } - - function isAllowedMember(prop) { - return allowedMembers.indexOf(prop) !== -1; - } - - function msg(member) { - var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1'); - return ( - 'Access to private Suite members (in this case `' + - memberName + - '`) via Env#topSuite is not supported and will break in ' + - 'a future release. See ' + - 'for correct usage.' - ); - } - try { - new Proxy({}, {}); - } catch (e) { - // Environment does not support Poxy. - return function(suite) { - return suite; - }; - } - - function DeprecatingSuiteProxyHandler(parentSuite, env) { - this._parentSuite = parentSuite; - this._env = env; - } - - DeprecatingSuiteProxyHandler.prototype.get = function( - target, - prop, - receiver - ) { - if (prop === 'children') { - if (!this._children) { - this._children = target.children.map( - this._proxyForChild.bind(this, receiver) - ); - } - - return this._children; - } else if (prop === 'parentSuite') { - return this._parentSuite; - } else { - this._maybeDeprecate(target, prop); - return target[prop]; - } - }; - - DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) { - debugger; - this._maybeDeprecate(target, prop); - return (target[prop] = value); - }; - - DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function( - target, - prop - ) { - if (isMember(target, prop) && !isAllowedMember(prop)) { - this._env.deprecated(msg(prop)); - } - }; - - DeprecatingSuiteProxyHandler.prototype._proxyForChild = function( - ownProxy, - child - ) { - if (child.children) { - return deprecatingSuiteProxy(child, ownProxy, this._env); - } else { - return j$.deprecatingSpecProxy(child, this._env); - } - }; - - function deprecatingSuiteProxy(suite, parentSuite, env) { - return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env)); - } - - return deprecatingSuiteProxy; -}; diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 2dd88c06..15094305 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -44,8 +44,6 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.Deprecator = jRequire.Deprecator(j$); j$.Env = jRequire.Env(j$); - j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$); - j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$); j$.StackTrace = jRequire.StackTrace(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExpectationFilterChain = jRequire.ExpectationFilterChain(); From 4edac7d3d182d70f8d42b3b87fbee072a68e492b Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 10 Jul 2021 09:21:41 -0700 Subject: [PATCH 09/71] Dropped Safari <13 from test matrix --- README.md | 5 ++--- scripts/run-all-browsers | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index caf68c70..69d32a8b 100644 --- a/README.md +++ b/README.md @@ -51,12 +51,11 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed | Environment | Supported versions | |-------------------|--------------------| -| Node | 10, 12, 14, 16 | -| Safari | 9-14 | +| Node | 12.17+, 14, 16 | +| Safari | 13-14 | | Chrome | Evergreen | | Firefox | Evergreen, 68, 78 | | Edge | Evergreen | -| Internet Explorer | 11 | For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work. diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index 768f0fd4..e8734441 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -30,7 +30,6 @@ run_browser firefox 78 run_browser firefox 68 run_browser safari 14 run_browser safari 13 -run_browser safari 9 run_browser MicrosoftEdge latest echo From e3999531745620f86c049af70f87e76c6009f6ae Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 17 Jul 2021 17:47:30 -0700 Subject: [PATCH 10/71] Removed obsolete timing function hacks from boot.js --- lib/jasmine-core/boot.js | 8 -------- lib/jasmine-core/boot/boot.js | 8 -------- 2 files changed, 16 deletions(-) diff --git a/lib/jasmine-core/boot.js b/lib/jasmine-core/boot.js index 9c9aee42..f03f8527 100644 --- a/lib/jasmine-core/boot.js +++ b/lib/jasmine-core/boot.js @@ -127,14 +127,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. env.configure(config); - /** - * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. - */ - window.setTimeout = window.setTimeout; - window.setInterval = window.setInterval; - window.clearTimeout = window.clearTimeout; - window.clearInterval = window.clearInterval; - /** * ## Execution * diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index e1e20f1c..ef2b8f7f 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -105,14 +105,6 @@ env.configure(config); - /** - * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. - */ - window.setTimeout = window.setTimeout; - window.setInterval = window.setInterval; - window.clearTimeout = window.clearTimeout; - window.clearInterval = window.clearInterval; - /** * ## Execution * From 623eecdcec08d8809537eae4f9989355057d4d62 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 22 Jul 2021 21:37:57 -0700 Subject: [PATCH 11/71] Removed json2.js Environments that don't provide a JSON parser are ancient history. --- lib/jasmine-core/json2.js | 489 ------------------------------ spec/npmPackage/npmPackageSpec.js | 3 +- 2 files changed, 1 insertion(+), 491 deletions(-) delete mode 100644 lib/jasmine-core/json2.js diff --git a/lib/jasmine-core/json2.js b/lib/jasmine-core/json2.js deleted file mode 100644 index deb88ec9..00000000 --- a/lib/jasmine-core/json2.js +++ /dev/null @@ -1,489 +0,0 @@ -/* - json2.js - 2014-02-04 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. - - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ - -/*jslint evil: true, regexp: true */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (typeof JSON !== 'object') { - JSON = {}; -} - -(function () { - 'use strict'; - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function () { - - return isFinite(this.valueOf()) - ? this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' - : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function () { - return this.valueOf(); - }; - } - - var cx, - escapable, - gap, - indent, - meta, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' - ? c - : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 - ? '[]' - : gap - ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' - : '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - if (typeof rep[i] === 'string') { - k = rep[i]; - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 - ? '{}' - : gap - ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' - : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }; - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/ - .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') - .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' - ? walk({'': j}, '') - : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/spec/npmPackage/npmPackageSpec.js b/spec/npmPackage/npmPackageSpec.js index ada121fa..1d909b72 100644 --- a/spec/npmPackage/npmPackageSpec.js +++ b/spec/npmPackage/npmPackageSpec.js @@ -55,8 +55,7 @@ describe('npm package', function() { it('has jsFiles', function() { expect(this.packagedCore.files.jsFiles).toEqual([ 'jasmine.js', - 'jasmine-html.js', - 'json2.js' + 'jasmine-html.js' ]); var packagedCore = this.packagedCore; From fe0a83ba87265ca2c6d26db129ccc98c35e15b5f Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 23 Jul 2021 19:48:53 -0700 Subject: [PATCH 12/71] Removed support for Internet Explorer --- .github/CONTRIBUTING.md | 19 +--- lib/jasmine-core/jasmine.js | 100 ++++-------------- package.json | 13 +-- scripts/run-all-browsers | 1 - spec/core/AsyncExpectationSpec.js | 58 ---------- spec/core/EnvSpec.js | 18 ++-- spec/core/MockDateSpec.js | 18 ---- spec/core/PrettyPrintSpec.js | 21 ++-- spec/core/QueueRunnerSpec.js | 1 - spec/core/SpecSpec.js | 4 - spec/core/SpySpec.js | 9 +- spec/core/SpyStrategySpec.js | 17 +-- spec/core/StackTraceSpec.js | 4 +- spec/core/UtilSpec.js | 3 +- spec/core/asymmetric_equality/AnySpec.js | 6 +- spec/core/asymmetric_equality/AnythingSpec.js | 4 +- .../asymmetric_equality/MapContainingSpec.js | 55 ++++------ .../asymmetric_equality/SetContainingSpec.js | 39 +++---- spec/core/baseSpec.js | 9 -- .../integration/CustomAsyncMatchersSpec.js | 11 -- spec/core/integration/EnvSpec.js | 21 +--- spec/core/integration/MatchersSpec.js | 51 ++------- spec/core/matchers/async/toBePendingSpec.js | 7 -- spec/core/matchers/async/toBeRejectedSpec.js | 5 - .../async/toBeRejectedWithErrorSpec.js | 23 ---- .../matchers/async/toBeRejectedWithSpec.js | 11 -- spec/core/matchers/async/toBeResolvedSpec.js | 5 - .../core/matchers/async/toBeResolvedToSpec.js | 11 -- spec/core/matchers/matchersUtilSpec.js | 35 +----- spec/core/matchers/toBeInstanceOfSpec.js | 2 - spec/core/matchers/toEqualSpec.js | 14 +-- spec/core/matchers/toHaveSizeSpec.js | 4 +- spec/helpers/asyncAwait.js | 26 ----- spec/helpers/checkForMap.js | 8 -- spec/helpers/checkForSet.js | 8 -- spec/helpers/checkForSymbol.js | 28 ----- spec/helpers/checkForUrl.js | 17 --- spec/helpers/generator.js | 22 ---- spec/helpers/promises.js | 7 -- spec/html/SpyRegistryHtmlSpec.js | 16 --- spec/support/jasmine-browser.js | 6 -- spec/support/jasmine.json | 7 -- src/core/Expectation.js | 7 -- src/core/MockDate.js | 6 +- src/core/StackTrace.js | 2 +- src/core/asymmetric_equality/MapContaining.js | 19 ++-- src/core/asymmetric_equality/SetContaining.js | 19 ++-- src/core/base.js | 29 +---- src/core/matchers/async/toBePending.js | 1 - src/core/matchers/toHaveSize.js | 2 +- src/core/util.js | 15 --- 51 files changed, 137 insertions(+), 707 deletions(-) delete mode 100644 spec/helpers/asyncAwait.js delete mode 100644 spec/helpers/checkForMap.js delete mode 100644 spec/helpers/checkForSet.js delete mode 100644 spec/helpers/checkForSymbol.js delete mode 100644 spec/helpers/checkForUrl.js delete mode 100644 spec/helpers/generator.js delete mode 100644 spec/helpers/promises.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3c8ecdbe..5f19cac4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -92,6 +92,7 @@ Or, How to make a successful pull request without test-driving it. * _Write code in the style of the rest of the repo_ - Jasmine should look like a cohesive whole. + * **Exception**: Prefer `const` or `let` over `var`. * _Ensure the *entire* test suite is green_ in all the big browsers, Node, and ESLint. Your contribution shouldn't break Jasmine for other users. @@ -100,27 +101,15 @@ Follow these tips and your pull request, patch, or suggestion is much more likel ### Running Specs Be sure to run the tests in at least one supported Node version and at least a -couple of supported browsers. It's also a good idea to run the tests in Internet -Explorer if you've touched code in `src/html`, if your change involves newer -JavaScript language/runtime features, or if you're unfamiliar with writing code -for older browsers. To run the tests in Node, simply use `npm test` as described -above. To run the tests in a browser, run `npm run serve` and then visit -`http://localhost:8888`. +couple of supported browsers. To run the tests in Node, simply use `npm test` +as described above. To run the tests in a browser, run `npm run serve` and then +visit `http://localhost:8888`. If you have the necessary Selenium drivers installed, you can also use Jasmine's CI tooling: $ JASMINE_BROWSER= node spec/support/ci.js -The easiest way to run the tests in **Internet Explorer** is to run a VM that has IE installed. It's easy to do this with VirtualBox. - -1. Download and install [VirtualBox](https://www.virtualbox.org/wiki/Downloads). -1. Download a VM image [from Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/). Select "VirtualBox" as the platform. -1. Unzip the downloaded archive. There should be an OVA file inside. -1. In VirtualBox, choose `File > Import Appliance` and select the OVA file. Accept the default settings in the dialog that appears. Now you have a Windows VM! -1. Run the VM and start IE. -1. With `npm run serve` running on your host machine, navigate to `http://:8888` in IE. - ## Before Committing or Submitting a Pull Request 1. Ensure all specs are green in browser *and* node. diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2a817cc1..6ad75fdc 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -267,25 +267,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { if (value instanceof Error) { return true; } - if ( - typeof window !== 'undefined' && - typeof window.trustedTypes !== 'undefined' - ) { - return ( - typeof value.stack === 'string' && typeof value.message === 'string' - ); - } - if (value && value.constructor && value.constructor.constructor) { - var valueGlobal = value.constructor.constructor('return this'); - if (j$.isFunction_(valueGlobal)) { - valueGlobal = valueGlobal(); - } - if (valueGlobal.Error && value instanceof valueGlobal.Error) { - return true; - } - } - return false; + return typeof value.stack === 'string' && typeof value.message === 'string'; }; j$.isAsymmetricEqualityTester_ = function(obj) { @@ -327,7 +310,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.WeakMap !== 'undefined' && obj.constructor === jasmineGlobal.WeakMap ); }; @@ -336,7 +318,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.URL !== 'undefined' && obj.constructor === jasmineGlobal.URL ); }; @@ -345,17 +326,12 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.DataView !== 'undefined' && obj.constructor === jasmineGlobal.DataView ); }; j$.isPromise = function(obj) { - return ( - typeof jasmineGlobal.Promise !== 'undefined' && - !!obj && - obj.constructor === jasmineGlobal.Promise - ); + return !!obj && obj.constructor === jasmineGlobal.Promise; }; j$.isPromiseLike = function(obj) { @@ -376,7 +352,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { j$.isPending_ = function(promise) { var sentinel = {}; - // eslint-disable-next-line compat/compat return Promise.race([promise, Promise.resolve(sentinel)]).then( function(result) { return result === sentinel; @@ -676,21 +651,6 @@ getJasmineRequireObj().util = function(j$) { StopIteration.prototype = Object.create(Error.prototype); StopIteration.prototype.constructor = StopIteration; - // useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them - util.forEachBreakable = function(iterable, iteratee) { - function breakLoop() { - throw new StopIteration(); - } - - try { - iterable.forEach(function(value, key) { - iteratee(breakLoop, value, key, iterable); - }); - } catch (error) { - if (!(error instanceof StopIteration)) throw error; - } - }; - return util; }; @@ -2559,27 +2519,26 @@ getJasmineRequireObj().MapContaining = function(j$) { MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isMap(other)) return false; - var hasAllMatches = true; - j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) { + for (const [key, value] of this.sample) { // for each key/value pair in `sample` // there should be at least one pair in `other` whose key and value both match var hasMatch = false; - j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) { + for (const [oKey, oValue] of other) { if ( matchersUtil.equals(oKey, key) && matchersUtil.equals(oValue, value) ) { hasMatch = true; - oBreakLoop(); + break; } - }); - if (!hasMatch) { - hasAllMatches = false; - breakLoop(); } - }); - return hasAllMatches; + if (!hasMatch) { + return false; + } + } + + return true; }; MapContaining.prototype.jasmineToString = function(pp) { @@ -2711,25 +2670,24 @@ getJasmineRequireObj().SetContaining = function(j$) { SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isSet(other)) return false; - var hasAllMatches = true; - j$.util.forEachBreakable(this.sample, function(breakLoop, item) { + for (const item of this.sample) { // for each item in `sample` there should be at least one matching item in `other` // (not using `matchersUtil.contains` because it compares set members by reference, // not by deep value equality) var hasMatch = false; - j$.util.forEachBreakable(other, function(oBreakLoop, oItem) { + for (const oItem of other) { if (matchersUtil.equals(oItem, item)) { hasMatch = true; - oBreakLoop(); + break; } - }); - if (!hasMatch) { - hasAllMatches = false; - breakLoop(); } - }); - return hasAllMatches; + if (!hasMatch) { + return false; + } + } + + return true; }; SetContaining.prototype.jasmineToString = function(pp) { @@ -3670,15 +3628,8 @@ getJasmineRequireObj().Expectation = function(j$) { * @namespace async-matchers */ function AsyncExpectation(options) { - var global = options.global || j$.getGlobal(); this.expector = new j$.Expector(options); - if (!global.Promise) { - throw new Error( - 'expectAsync is unavailable because the environment does not support promises.' - ); - } - var customAsyncMatchers = options.customAsyncMatchers || {}; for (var matcherName in customAsyncMatchers) { this[matcherName] = wrapAsyncCompare( @@ -4233,7 +4184,6 @@ getJasmineRequireObj().GlobalErrors = function(j$) { return GlobalErrors; }; -/* eslint-disable compat/compat */ getJasmineRequireObj().toBePending = function(j$) { /** * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected. @@ -6518,7 +6468,7 @@ getJasmineRequireObj().toHaveSize = function(j$) { }; } - var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; // eslint-disable-line compat/compat + var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; function isLength(value) { return ( typeof value == 'number' && @@ -7019,11 +6969,7 @@ getJasmineRequireObj().MockDate = function() { FakeDate.prototype = GlobalDate.prototype; FakeDate.now = function() { - if (GlobalDate.now) { - return currentTime; - } else { - throw new Error('Browser does not support Date.now()'); - } + return currentTime; }; FakeDate.toSource = GlobalDate.toSource; @@ -8970,7 +8916,7 @@ getJasmineRequireObj().StackTrace = function(j$) { } var framePatterns = [ - // PhantomJS on Linux, Node, Chrome, IE, Edge + // Node, Chrome, Edge // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)" // Note that the "function name" can include a surprisingly large set of // characters, including angle brackets and square brackets. diff --git a/package.json b/package.json index 4449c324..436593d2 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,10 @@ "extends": [ "plugin:compat/recommended" ], - "parserOptions": { - "ecmaVersion": 5 + "env": { + "browser": true, + "node": true, + "es2017": true }, "rules": { "quotes": [ @@ -94,11 +96,10 @@ } }, "browserslist": [ - "Safari >= 9", + "Safari >= 13", "last 2 Chrome versions", "last 2 Firefox versions", - "Firefox 68", - "last 2 Edge versions", - "IE >= 11" + "Firefox >= 68", + "last 2 Edge versions" ] } diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index e8734441..a240ab3a 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -23,7 +23,6 @@ run_browser() { passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 -run_browser "internet explorer" 11 run_browser chrome latest run_browser firefox latest run_browser firefox 78 diff --git a/spec/core/AsyncExpectationSpec.js b/spec/core/AsyncExpectationSpec.js index 338e0faf..60dc2f01 100644 --- a/spec/core/AsyncExpectationSpec.js +++ b/spec/core/AsyncExpectationSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('AsyncExpectation', function() { beforeEach(function() { jasmineUnderTest.Expectation.addAsyncCoreMatchers( @@ -6,23 +5,8 @@ describe('AsyncExpectation', function() { ); }); - describe('Factory', function() { - it('throws an Error if promises are not available', function() { - var thenable = { then: function() {} }, - options = { global: {}, actual: thenable }; - function f() { - jasmineUnderTest.Expectation.asyncFactory(options); - } - expect(f).toThrowError( - 'expectAsync is unavailable because the environment does not support promises.' - ); - }); - }); - describe('#not', function() { it('converts a pass to a fail', function() { - jasmine.getEnv().requirePromises(); - var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve(), pp = jasmineUnderTest.makePrettyPrinter(), @@ -44,8 +28,6 @@ describe('AsyncExpectation', function() { }); it('converts a fail to a pass', function() { - jasmine.getEnv().requirePromises(); - var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.reject(), expectation = jasmineUnderTest.Expectation.asyncFactory({ @@ -69,7 +51,6 @@ describe('AsyncExpectation', function() { }); it('propagates rejections from the comparison function', function() { - jasmine.getEnv().requirePromises(); var error = new Error('ExpectationSpec failure'); var addExpectationResult = jasmine.createSpy('addExpectationResult'), @@ -93,8 +74,6 @@ describe('AsyncExpectation', function() { describe('#withContext', function() { it('prepends the context to the generated failure message', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = { pp: function(val) { return val.toString(); @@ -122,8 +101,6 @@ describe('AsyncExpectation', function() { }); it('prepends the context to a custom failure message', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = { buildFailureMessage: function() { return 'failure message'; @@ -154,7 +131,6 @@ describe('AsyncExpectation', function() { it('prepends the context to a custom failure message from a function', function() { pending('should actually work, but no custom matchers for async yet'); - jasmine.getEnv().requirePromises(); var matchersUtil = { buildFailureMessage: function() { @@ -183,8 +159,6 @@ describe('AsyncExpectation', function() { }); it('works with #not', function() { - jasmine.getEnv().requirePromises(); - var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve(), pp = jasmineUnderTest.makePrettyPrinter(), @@ -209,8 +183,6 @@ describe('AsyncExpectation', function() { }); it('works with #not and a custom message', function() { - jasmine.getEnv().requirePromises(); - var addExpectationResult = jasmine.createSpy('addExpectationResult'), actual = Promise.resolve('a'), expectation = jasmineUnderTest.Expectation.asyncFactory({ @@ -238,8 +210,6 @@ describe('AsyncExpectation', function() { describe('async matchers', function() { it('makes custom matchers available to this expectation', function() { - jasmine.getEnv().requirePromises(); - var asyncMatchers = { toFoo: function() {}, toBar: function() {} @@ -255,8 +225,6 @@ describe('AsyncExpectation', function() { }); it("wraps matchers's compare functions, passing in matcher dependencies", function() { - jasmine.getEnv().requirePromises(); - var fakeCompare = function() { return Promise.resolve({ pass: true }); }, @@ -285,8 +253,6 @@ describe('AsyncExpectation', function() { }); it("wraps matchers's compare functions, passing the actual and expected", function() { - jasmine.getEnv().requirePromises(); - var fakeCompare = jasmine .createSpy('fake-compare') .and.returnValue(Promise.resolve({ pass: true })), @@ -316,8 +282,6 @@ describe('AsyncExpectation', function() { }); it('reports a passing result to the spec when the comparison passes', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -359,8 +323,6 @@ describe('AsyncExpectation', function() { }); it('reports a failing result to the spec when the comparison fails', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -404,8 +366,6 @@ describe('AsyncExpectation', function() { }); it('reports a failing result and a custom fail message to the spec when the comparison fails', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -446,8 +406,6 @@ describe('AsyncExpectation', function() { }); it('reports a failing result with a custom fail message function to the spec when the comparison fails', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -490,8 +448,6 @@ describe('AsyncExpectation', function() { }); it('reports a passing result to the spec when the comparison fails for a negative expectation', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -530,8 +486,6 @@ describe('AsyncExpectation', function() { }); it('reports a failing result to the spec when the comparison passes for a negative expectation', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -576,8 +530,6 @@ describe('AsyncExpectation', function() { }); it('reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation', function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -619,8 +571,6 @@ describe('AsyncExpectation', function() { }); it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -662,8 +612,6 @@ describe('AsyncExpectation', function() { }); it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -708,8 +656,6 @@ describe('AsyncExpectation', function() { }); it('reports errorWithStack when a custom error message is returned', function() { - jasmine.getEnv().requirePromises(); - var customError = new Error('I am a custom error'); var matchers = { toFoo: function() { @@ -752,8 +698,6 @@ describe('AsyncExpectation', function() { }); it("reports a custom message to the spec when a 'not' comparison fails", function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { @@ -794,8 +738,6 @@ describe('AsyncExpectation', function() { }); it("reports a custom message func to the spec when a 'not' comparison fails", function() { - jasmine.getEnv().requirePromises(); - var matchers = { toFoo: function() { return { diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index fde0767a..f9bf2911 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -223,9 +223,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.it('async', jasmine.getEnv().makeAsyncAwaitFunction()); + env.it('async', async function() {}); }).not.toThrow(); }); }); @@ -255,9 +254,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.xit('async', jasmine.getEnv().makeAsyncAwaitFunction()); + env.xit('async', async function() {}); }).not.toThrow(); }); }); @@ -282,9 +280,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction()); + env.beforeEach(async function() {}); }).not.toThrow(); }); }); @@ -299,9 +296,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction()); + env.beforeAll(async function() {}); }).not.toThrow(); }); }); @@ -316,9 +312,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction()); + env.afterEach(async function() {}); }).not.toThrow(); }); }); @@ -333,9 +328,8 @@ describe('Env', function() { }); it('accepts an async function', function() { - jasmine.getEnv().requireAsyncAwait(); expect(function() { - env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction()); + env.afterAll(async function() {}); }).not.toThrow(); }); }); diff --git a/spec/core/MockDateSpec.js b/spec/core/MockDateSpec.js index 6f6f88df..aaeece54 100644 --- a/spec/core/MockDateSpec.js +++ b/spec/core/MockDateSpec.js @@ -96,24 +96,6 @@ describe('FakeDate', function() { expect(fakeGlobal.Date.now()).toEqual(1000); }); - it("does not stub Date.now() if it doesn't already exist", function() { - var globalDate = jasmine.createSpy('global Date').and.callFake(function() { - return { - getTime: function() { - return 1000; - } - }; - }), - fakeGlobal = { Date: globalDate }, - mockDate = new jasmineUnderTest.MockDate(fakeGlobal); - - mockDate.install(); - - expect(fakeGlobal.Date.now).toThrowError( - 'Browser does not support Date.now()' - ); - }); - it('makes time passes using tick', function() { var globalDate = jasmine.createSpy('global Date').and.callFake(function() { return { diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index 7d4bc6d5..2fa0a74d 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -295,20 +295,15 @@ describe('PrettyPrinter', function() { it('should indicate getters on objects as such', function() { var pp = jasmineUnderTest.makePrettyPrinter(); - var sampleValue = { id: 1 }; - if (sampleValue.__defineGetter__) { - //not supported in IE! - sampleValue.__defineGetter__('calculatedValue', function() { + var sampleValue = { + id: 1, + get calculatedValue() { throw new Error("don't call me!"); - }); - } - if (sampleValue.__defineGetter__) { - expect(pp(sampleValue)).toEqual( - 'Object({ id: 1, calculatedValue: })' - ); - } else { - expect(pp(sampleValue)).toEqual('Object({ id: 1 })'); - } + } + }; + expect(pp(sampleValue)).toEqual( + 'Object({ id: 1, calculatedValue: })' + ); }); it('should not do HTML escaping of strings', function() { diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 1aaba300..8ed3a827 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -538,7 +538,6 @@ describe('QueueRunner', function() { }); it('issues a more specific error if the function is `async`', function() { - jasmine.getEnv().requireAsyncAwait(); eval('var fn = async function(done){};'); var onException = jasmine.createSpy('onException'), queueRunner = new jasmineUnderTest.QueueRunner({ diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index fa530049..ef2e1b22 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -61,10 +61,6 @@ describe('Spec', function() { spec.execute(); fakeQueueRunner.calls.mostRecent().args[0].queueableFns[0].fn(); - // TODO: due to some issue with the Pretty Printer, this line fails, but the other two pass. - // This means toHaveBeenCalledWith on IE8 will always be broken. - - // expect(startCallback).toHaveBeenCalledWith(spec); expect(startCallback).toHaveBeenCalled(); expect(startCallback.calls.first().object).toEqual(spec); }); diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 97fc9544..4614a396 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -31,12 +31,7 @@ describe('Spies', function() { var fn = function test() {}; var spy = env.createSpy(fn); - // IE doesn't do `.name` - if (fn.name === 'test') { - expect(spy.and.identity).toEqual('test'); - } else { - expect(spy.and.identity).toEqual('unknown'); - } + expect(spy.and.identity).toEqual('test'); }); it('warns the user that we intend to overwrite an existing property', function() { @@ -254,8 +249,6 @@ describe('Spies', function() { describe('any promise-based strategy', function() { it('works with global Promise library when available', function(done) { - jasmine.getEnv().requirePromises(); - var spy = env.createSpy('foo').and.resolveTo(42); spy() .then(function(result) { diff --git a/spec/core/SpyStrategySpec.js b/spec/core/SpyStrategySpec.js index b4beabc1..abd7eb39 100644 --- a/spec/core/SpyStrategySpec.js +++ b/spec/core/SpyStrategySpec.js @@ -108,7 +108,6 @@ describe('SpyStrategy', function() { }); it('allows a fake async function to be called instead', function(done) { - jasmine.getEnv().requireAsyncAwait(); var originalFn = jasmine.createSpy('original'), fakeFn = jasmine .createSpy('fake') @@ -131,8 +130,6 @@ describe('SpyStrategy', function() { describe('#resolveTo', function() { it('allows a resolved promise to be returned', function(done) { - jasmine.getEnv().requirePromises(); - var originalFn = jasmine.createSpy('original'), getPromise = function() { return Promise; @@ -153,8 +150,6 @@ describe('SpyStrategy', function() { }); it('allows an empty resolved promise to be returned', function(done) { - jasmine.getEnv().requirePromises(); - var originalFn = jasmine.createSpy('original'), getPromise = function() { return Promise; @@ -188,8 +183,6 @@ describe('SpyStrategy', function() { describe('#rejectWith', function() { it('allows a rejected promise to be returned', function(done) { - jasmine.getEnv().requirePromises(); - var originalFn = jasmine.createSpy('original'), getPromise = function() { return Promise; @@ -211,8 +204,6 @@ describe('SpyStrategy', function() { }); it('allows an empty rejected promise to be returned', function(done) { - jasmine.getEnv().requirePromises(); - var originalFn = jasmine.createSpy('original'), getPromise = function() { return Promise; @@ -234,8 +225,6 @@ describe('SpyStrategy', function() { }); it('allows a non-Error to be rejected', function(done) { - jasmine.getEnv().requirePromises(); - var originalFn = jasmine.createSpy('original'), getPromise = function() { return Promise; @@ -335,9 +324,9 @@ describe('SpyStrategy', function() { }); it('allows generator functions to be passed to callFake strategy', function() { - jasmine.getEnv().requireGeneratorFunctions(); - - var generator = jasmine.getEnv().makeGeneratorFunction('yield "ok";'), + var generator = function*() { + yield 'ok'; + }, spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: function() {} }); spyStrategy.callFake(generator); diff --git a/spec/core/StackTraceSpec.js b/spec/core/StackTraceSpec.js index d041c8e7..680a8ade 100644 --- a/spec/core/StackTraceSpec.js +++ b/spec/core/StackTraceSpec.js @@ -1,5 +1,5 @@ describe('StackTrace', function() { - it('understands Chrome/IE/Edge style traces', function() { + it('understands Chrome/Edge style traces', function() { var error = { message: 'nope', stack: @@ -30,7 +30,7 @@ describe('StackTrace', function() { ]); }); - it('understands Chrome/IE/Edge style traces with multiline messages', function() { + it('understands Chrome/Edge style traces with multiline messages', function() { var error = { message: 'line 1\nline 2', stack: diff --git a/spec/core/UtilSpec.js b/spec/core/UtilSpec.js index 8e05c6ab..f95d92fc 100644 --- a/spec/core/UtilSpec.js +++ b/spec/core/UtilSpec.js @@ -39,8 +39,7 @@ describe('jasmineUnderTest.util', function() { }; beforeEach(function() { - jasmine.getEnv().requirePromises(); - mockNativePromise = new Promise(function(res, rej) {}); // eslint-disable-line compat/compat + mockNativePromise = new Promise(function(res, rej) {}); mockPromiseLikeObject = new mockPromiseLike(); }); diff --git a/spec/core/asymmetric_equality/AnySpec.js b/spec/core/asymmetric_equality/AnySpec.js index 5a8f6678..7979dd7c 100644 --- a/spec/core/asymmetric_equality/AnySpec.js +++ b/spec/core/asymmetric_equality/AnySpec.js @@ -48,11 +48,9 @@ describe('Any', function() { }); it('matches a Symbol', function() { - jasmine.getEnv().requireFunctioningSymbols(); + var any = new jasmineUnderTest.Any(Symbol); - var any = new jasmineUnderTest.Any(Symbol); // eslint-disable-line compat/compat - - expect(any.asymmetricMatch(Symbol())).toBe(true); // eslint-disable-line compat/compat + expect(any.asymmetricMatch(Symbol())).toBe(true); }); it('matches another constructed object', function() { diff --git a/spec/core/asymmetric_equality/AnythingSpec.js b/spec/core/asymmetric_equality/AnythingSpec.js index d72852f2..e4a3df5f 100644 --- a/spec/core/asymmetric_equality/AnythingSpec.js +++ b/spec/core/asymmetric_equality/AnythingSpec.js @@ -42,11 +42,9 @@ describe('Anything', function() { }); it('matches a Symbol', function() { - jasmine.getEnv().requireFunctioningSymbols(); - var anything = new jasmineUnderTest.Anything(); - expect(anything.asymmetricMatch(Symbol())).toBe(true); // eslint-disable-line compat/compat + expect(anything.asymmetricMatch(Symbol())).toBe(true); }); it("doesn't match undefined", function() { diff --git a/spec/core/asymmetric_equality/MapContainingSpec.js b/spec/core/asymmetric_equality/MapContainingSpec.js index ed44f11b..dbee6bf5 100644 --- a/spec/core/asymmetric_equality/MapContainingSpec.js +++ b/spec/core/asymmetric_equality/MapContainingSpec.js @@ -1,28 +1,19 @@ describe('MapContaining', function() { - function MapI(iterable) { - // for IE11 - var map = new Map(); - iterable.forEach(function(kv) { - map.set(kv[0], kv[1]); - }); - return map; - } - it('matches any actual map to an empty map', function() { - var actualMap = new MapI([['foo', 'bar']]); + var actualMap = new Map([['foo', 'bar']]); var containing = new jasmineUnderTest.MapContaining(new Map()); expect(containing.asymmetricMatch(actualMap)).toBe(true); }); it('matches when all the key/value pairs in sample have matches in actual', function() { - var actualMap = new MapI([ + var actualMap = new Map([ ['foo', [1, 2, 3]], [{ foo: 'bar' }, 'baz'], ['other', 'any'] ]); - var containingMap = new MapI([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); + var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -30,12 +21,12 @@ describe('MapContaining', function() { }); it('does not match when a key is not in actual', function() { - var actualMap = new MapI([ + var actualMap = new Map([ ['foo', [1, 2, 3]], [{ foo: 'not a bar' }, 'baz'] ]); - var containingMap = new MapI([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); + var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2, 3]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -43,9 +34,9 @@ describe('MapContaining', function() { }); it('does not match when a value is not in actual', function() { - var actualMap = new MapI([['foo', [1, 2, 3]], [{ foo: 'bar' }, 'baz']]); + var actualMap = new Map([['foo', [1, 2, 3]], [{ foo: 'bar' }, 'baz']]); - var containingMap = new MapI([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2]]]); + var containingMap = new Map([[{ foo: 'bar' }, 'baz'], ['foo', [1, 2]]]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -53,13 +44,13 @@ describe('MapContaining', function() { }); it('matches when all the key/value pairs in sample have asymmetric matches in actual', function() { - var actualMap = new MapI([ + var actualMap = new Map([ ['foo1', 'not a bar'], ['foo2', 'bar'], ['baz', [1, 2, 3, 4]] ]); - var containingMap = new MapI([ + var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([2, 3])] ]); @@ -70,9 +61,9 @@ describe('MapContaining', function() { }); it('does not match when a key in sample has no asymmetric matches in actual', function() { - var actualMap = new MapI([['a-foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); + var actualMap = new Map([['a-foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); - var containingMap = new MapI([ + var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([2, 3])] ]); @@ -83,9 +74,9 @@ describe('MapContaining', function() { }); it('does not match when a value in sample has no asymmetric matches in actual', function() { - var actualMap = new MapI([['foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); + var actualMap = new Map([['foo1', 'bar'], ['baz', [1, 2, 3, 4]]]); - var containingMap = new MapI([ + var containingMap = new Map([ [jasmineUnderTest.stringMatching(/^foo\d/), 'bar'], ['baz', jasmineUnderTest.arrayContaining([4, 5])] ]); @@ -96,15 +87,15 @@ describe('MapContaining', function() { }); it('matches recursively', function() { - var actualMap = new MapI([ - ['foo', new MapI([['foo1', 1], ['foo2', 2]])], - [new MapI([[1, 'bar1'], [2, 'bar2']]), 'bar'], + var actualMap = new Map([ + ['foo', new Map([['foo1', 1], ['foo2', 2]])], + [new Map([[1, 'bar1'], [2, 'bar2']]), 'bar'], ['other', 'any'] ]); - var containingMap = new MapI([ - ['foo', new jasmineUnderTest.MapContaining(new MapI([['foo1', 1]]))], - [new jasmineUnderTest.MapContaining(new MapI([[2, 'bar2']])), 'bar'] + var containingMap = new Map([ + ['foo', new jasmineUnderTest.MapContaining(new Map([['foo1', 1]]))], + [new jasmineUnderTest.MapContaining(new Map([[2, 'bar2']])), 'bar'] ]); var containing = new jasmineUnderTest.MapContaining(containingMap); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -119,10 +110,8 @@ describe('MapContaining', function() { ? a < 0 && b < 0 : a === b; } - var actualMap = new MapI([['foo', -1]]); - var containing = new jasmineUnderTest.MapContaining( - new MapI([['foo', -2]]) - ); + var actualMap = new Map([['foo', -1]]); + var containing = new jasmineUnderTest.MapContaining(new Map([['foo', -2]])); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); @@ -131,7 +120,7 @@ describe('MapContaining', function() { }); it('does not match when actual is not a map', function() { - var containingMap = new MapI([['foo', 'bar']]); + var containingMap = new Map([['foo', 'bar']]); expect( new jasmineUnderTest.MapContaining(containingMap).asymmetricMatch('foo') ).toBe(false); diff --git a/spec/core/asymmetric_equality/SetContainingSpec.js b/spec/core/asymmetric_equality/SetContainingSpec.js index c986181f..6c2efc2b 100644 --- a/spec/core/asymmetric_equality/SetContainingSpec.js +++ b/spec/core/asymmetric_equality/SetContainingSpec.js @@ -1,24 +1,15 @@ describe('SetContaining', function() { - function SetI(iterable) { - // for IE11 - var set = new Set(); - iterable.forEach(function(v) { - set.add(v); - }); - return set; - } - it('matches any actual set to an empty set', function() { - var actualSet = new SetI(['foo', 'bar']); + var actualSet = new Set(['foo', 'bar']); var containing = new jasmineUnderTest.SetContaining(new Set()); expect(containing.asymmetricMatch(actualSet)).toBe(true); }); it('matches when all the values in sample have matches in actual', function() { - var actualSet = new SetI([{ foo: 'bar' }, 'baz', [1, 2, 3]]); + var actualSet = new Set([{ foo: 'bar' }, 'baz', [1, 2, 3]]); - var containingSet = new SetI([[1, 2, 3], { foo: 'bar' }]); + var containingSet = new Set([[1, 2, 3], { foo: 'bar' }]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -26,9 +17,9 @@ describe('SetContaining', function() { }); it('does not match when a value is not in actual', function() { - var actualSet = new SetI([{ foo: 'bar' }, 'baz', [1, 2, 3]]); + var actualSet = new Set([{ foo: 'bar' }, 'baz', [1, 2, 3]]); - var containingSet = new SetI([[1, 2], { foo: 'bar' }]); + var containingSet = new Set([[1, 2], { foo: 'bar' }]); var containing = new jasmineUnderTest.SetContaining(containingSet); var matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -36,9 +27,9 @@ describe('SetContaining', function() { }); it('matches when all the values in sample have asymmetric matches in actual', function() { - var actualSet = new SetI([[1, 2, 3, 4], 'other', 'foo1']); + var actualSet = new Set([[1, 2, 3, 4], 'other', 'foo1']); - var containingSet = new SetI([ + var containingSet = new Set([ jasmineUnderTest.stringMatching(/^foo\d/), jasmineUnderTest.arrayContaining([2, 3]) ]); @@ -49,9 +40,9 @@ describe('SetContaining', function() { }); it('does not match when a value in sample has no asymmetric matches in actual', function() { - var actualSet = new SetI(['a-foo1', [1, 2, 3, 4], 'other']); + var actualSet = new Set(['a-foo1', [1, 2, 3, 4], 'other']); - var containingSet = new SetI([ + var containingSet = new Set([ jasmine.stringMatching(/^foo\d/), jasmine.arrayContaining([2, 3]) ]); @@ -62,10 +53,10 @@ describe('SetContaining', function() { }); it('matches recursively', function() { - var actualSet = new SetI(['foo', new SetI([1, 'bar', 2]), 'other']); + var actualSet = new Set(['foo', new Set([1, 'bar', 2]), 'other']); - var containingSet = new SetI([ - new jasmineUnderTest.SetContaining(new SetI(['bar'])), + var containingSet = new Set([ + new jasmineUnderTest.SetContaining(new Set(['bar'])), 'foo' ]); var containing = new jasmineUnderTest.SetContaining(containingSet); @@ -81,8 +72,8 @@ describe('SetContaining', function() { ? a < 0 && b < 0 : a === b; } - var actualSet = new SetI(['foo', -1]); - var containing = new jasmineUnderTest.SetContaining(new SetI([-2, 'foo'])); + var actualSet = new Set(['foo', -1]); + var containing = new jasmineUnderTest.SetContaining(new Set([-2, 'foo'])); var matchersUtil = new jasmineUnderTest.MatchersUtil({ customTesters: [tester] }); @@ -91,7 +82,7 @@ describe('SetContaining', function() { }); it('does not match when actual is not a set', function() { - var containingSet = new SetI(['foo']); + var containingSet = new Set(['foo']); expect( new jasmineUnderTest.SetContaining(containingSet).asymmetricMatch('foo') ).toBe(false); diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 2409b075..91a73337 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -101,21 +101,16 @@ describe('base helpers', function() { describe('isURL', function() { it('returns true when the object is a URL', function() { - jasmine.getEnv().requireUrls(); - // eslint-disable-next-line compat/compat expect(jasmineUnderTest.isURL(new URL('http://localhost/'))).toBe(true); }); it('returns false when the object is not a URL', function() { - jasmine.getEnv().requireUrls(); expect(jasmineUnderTest.isURL({})).toBe(false); }); }); describe('isPending_', function() { it('returns a promise that resolves to true when the promise is pending', function() { - jasmine.getEnv().requirePromises(); - // eslint-disable-next-line compat/compat var promise = new Promise(function() {}); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( true @@ -123,8 +118,6 @@ describe('base helpers', function() { }); it('returns a promise that resolves to false when the promise is resolved', function() { - jasmine.getEnv().requirePromises(); - // eslint-disable-next-line compat/compat var promise = Promise.resolve(); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( false @@ -132,8 +125,6 @@ describe('base helpers', function() { }); it('returns a promise that resolves to false when the promise is rejected', function() { - jasmine.getEnv().requirePromises(); - // eslint-disable-next-line compat/compat var promise = Promise.reject(); return expectAsync(jasmineUnderTest.isPending_(promise)).toBeResolvedTo( false diff --git a/spec/core/integration/CustomAsyncMatchersSpec.js b/spec/core/integration/CustomAsyncMatchersSpec.js index e015e2fc..36fe3fde 100644 --- a/spec/core/integration/CustomAsyncMatchersSpec.js +++ b/spec/core/integration/CustomAsyncMatchersSpec.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ describe('Custom Async Matchers (Integration)', function() { var env; @@ -12,8 +11,6 @@ describe('Custom Async Matchers (Integration)', function() { }); it('passes the spec if the custom async matcher passes', function(done) { - jasmine.getEnv().requirePromises(); - env.it('spec using custom async matcher', function() { env.addAsyncMatchers({ toBeReal: function() { @@ -37,8 +34,6 @@ describe('Custom Async Matchers (Integration)', function() { }); it('uses the negative compare function for a negative comparison, if provided', function(done) { - jasmine.getEnv().requirePromises(); - env.it('spec with custom negative comparison matcher', function() { env.addAsyncMatchers({ toBeReal: function() { @@ -65,8 +60,6 @@ describe('Custom Async Matchers (Integration)', function() { }); it('generates messages with the same rules as built in matchers absent a custom message', function(done) { - jasmine.getEnv().requirePromises(); - env.it('spec with an expectation', function() { env.addAsyncMatchers({ toBeReal: function() { @@ -92,8 +85,6 @@ describe('Custom Async Matchers (Integration)', function() { }); it('passes the jasmine utility to the matcher factory', function(done) { - jasmine.getEnv().requirePromises(); - var matcherFactory = function(util) { return { compare: function() { @@ -125,8 +116,6 @@ describe('Custom Async Matchers (Integration)', function() { }); it('provides custom equality testers to the matcher factory via matchersUtil', function(done) { - jasmine.getEnv().requirePromises(); - var matcherFactory = function(matchersUtil) { return { compare: function(actual, expected) { diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 707bab02..7d15d639 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -156,10 +156,6 @@ describe('Env integration', function() { message: 'Failed: error message', stack: { asymmetricMatch: function(other) { - if (!other) { - // IE doesn't give us a stacktrace so just ignore it. - return true; - } var split = other.split('\n'), firstLine = split[0]; if (firstLine.indexOf('error message') >= 0) { @@ -2709,8 +2705,6 @@ describe('Env integration', function() { }); it('supports async matchers', function(done) { - jasmine.getEnv().requirePromises(); - var specDone = jasmine.createSpy('specDone'), suiteDone = jasmine.createSpy('suiteDone'), jasmineDone = jasmine.createSpy('jasmineDone'); @@ -2723,7 +2717,6 @@ describe('Env integration', function() { function fail(innerDone) { var resolve; - // eslint-disable-next-line compat/compat var p = new Promise(function(res, rej) { resolve = res; }); @@ -2779,8 +2772,6 @@ describe('Env integration', function() { jasmine.getEnv().skipBrowserFlake(); } - jasmine.getEnv().requirePromises(); - var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); @@ -2789,7 +2780,7 @@ describe('Env integration', function() { env.addCustomEqualityTester(function() { return true; }); - var p = Promise.resolve('something'); // eslint-disable-line compat/compat + var p = Promise.resolve('something'); return env.expectAsync(p).toBeResolvedTo('something else'); }); @@ -2805,8 +2796,6 @@ describe('Env integration', function() { }); it('includes useful stack frames in async matcher failures', function(done) { - jasmine.getEnv().requirePromises(); - var specDone = jasmine.createSpy('specDone'); env.addReporter({ specDone: specDone }); @@ -2815,7 +2804,7 @@ describe('Env integration', function() { env.addCustomEqualityTester(function() { return true; }); - var p = Promise.resolve(); // eslint-disable-line compat/compat + var p = Promise.resolve(); return env.expectAsync(p).toBeRejected(); }); @@ -2834,11 +2823,8 @@ describe('Env integration', function() { }); it('reports an error when an async expectation occurs after the spec finishes', function(done) { - jasmine.getEnv().requirePromises(); - var resolve, jasmineDone = jasmine.createSpy('jasmineDone'), - // eslint-disable-next-line compat/compat promise = new Promise(function(res) { resolve = res; }); @@ -2897,11 +2883,8 @@ describe('Env integration', function() { }); it('reports an error when an async expectation occurs after the suite finishes', function(done) { - jasmine.getEnv().requirePromises(); - var resolve, jasmineDone = jasmine.createSpy('jasmineDone'), - // eslint-disable-next-line compat/compat promise = new Promise(function(res) { resolve = res; }); diff --git a/spec/core/integration/MatchersSpec.js b/spec/core/integration/MatchersSpec.js index 86fe77c4..9e3f7f6c 100644 --- a/spec/core/integration/MatchersSpec.js +++ b/spec/core/integration/MatchersSpec.js @@ -90,8 +90,6 @@ describe('Matchers (Integration)', function() { function verifyPassesAsync(expectations) { it('passes', function(done) { - jasmine.getEnv().requirePromises(); - env.it('a spec', function() { return expectations(env); }); @@ -118,8 +116,6 @@ describe('Matchers (Integration)', function() { function verifyFailsAsync(expectations) { it('fails', function(done) { - jasmine.getEnv().requirePromises(); - env.it('a spec', function() { return expectations(env); }); @@ -147,7 +143,6 @@ describe('Matchers (Integration)', function() { function verifyFailsWithCustomObjectFormattersAsync(config) { it('uses custom object formatters', function(done) { var env = new jasmineUnderTest.Env(); - jasmine.getEnv().requirePromises(); env.it('a spec', function() { env.addCustomObjectFormatter(config.formatter); return config.expectations(env); @@ -348,12 +343,10 @@ describe('Matchers (Integration)', function() { describe('toBeResolved', function() { verifyPassesAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve()).toBeResolved(); }); verifyFailsAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.reject()).toBeResolved(); }); }); @@ -363,12 +356,10 @@ describe('Matchers (Integration)', function() { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve('5')).toBeResolvedTo(5); }); verifyFailsAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve('foo')).toBeResolvedTo('bar'); }); @@ -377,7 +368,6 @@ describe('Matchers (Integration)', function() { return '|' + val + '|'; }, expectations: function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve('x')).toBeResolvedTo('y'); }, expectedMessage: @@ -388,12 +378,10 @@ describe('Matchers (Integration)', function() { describe('toBeRejected', function() { verifyPassesAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.reject('nope')).toBeRejected(); }); verifyFailsAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve()).toBeRejected(); }); }); @@ -403,12 +391,10 @@ describe('Matchers (Integration)', function() { env.addCustomEqualityTester(function(a, b) { return a.toString() === b.toString(); }); - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.reject('5')).toBeRejectedWith(5); }); verifyFailsAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve()).toBeRejectedWith('nope'); }); @@ -417,7 +403,6 @@ describe('Matchers (Integration)', function() { return '|' + val + '|'; }, expectations: function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.reject('x')).toBeRejectedWith('y'); }, expectedMessage: @@ -428,16 +413,12 @@ describe('Matchers (Integration)', function() { describe('toBeRejectedWithError', function() { verifyPassesAsync(function(env) { - return ( - env - // eslint-disable-next-line compat/compat - .expectAsync(Promise.reject(new Error())) - .toBeRejectedWithError(Error) - ); + return env + .expectAsync(Promise.reject(new Error())) + .toBeRejectedWithError(Error); }); verifyFailsAsync(function(env) { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve()).toBeRejectedWithError(Error); }); @@ -446,12 +427,9 @@ describe('Matchers (Integration)', function() { return '|' + val + '|'; }, expectations: function(env) { - return ( - env - // eslint-disable-next-line compat/compat - .expectAsync(Promise.reject('foo')) - .toBeRejectedWithError('foo') - ); + return env + .expectAsync(Promise.reject('foo')) + .toBeRejectedWithError('foo'); }, expectedMessage: 'Expected a promise to be rejected with Error: |foo| ' + @@ -757,10 +735,7 @@ describe('Matchers (Integration)', function() { describe('When an async matcher is used with .already()', function() { it('propagates the matcher result when the promise is resolved', function(done) { - jasmine.getEnv().requirePromises(); - env.it('a spec', function() { - // eslint-disable-next-line compat/compat return env.expectAsync(Promise.resolve()).already.toBeRejected(); }); @@ -782,15 +757,10 @@ describe('Matchers (Integration)', function() { }); it('propagates the matcher result when the promise is rejected', function(done) { - jasmine.getEnv().requirePromises(); - env.it('a spec', function() { - return ( - env - // eslint-disable-next-line compat/compat - .expectAsync(Promise.reject(new Error('nope'))) - .already.toBeResolved() - ); + return env + .expectAsync(Promise.reject(new Error('nope'))) + .already.toBeResolved(); }); var specExpectations = function(result) { @@ -812,9 +782,6 @@ describe('Matchers (Integration)', function() { }); it('fails when the promise is pending', function(done) { - jasmine.getEnv().requirePromises(); - - // eslint-disable-next-line compat/compat var promise = new Promise(function() {}); env.it('a spec', function() { diff --git a/spec/core/matchers/async/toBePendingSpec.js b/spec/core/matchers/async/toBePendingSpec.js index 0b78d8cd..385a08be 100644 --- a/spec/core/matchers/async/toBePendingSpec.js +++ b/spec/core/matchers/async/toBePendingSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ 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() {}); @@ -13,8 +10,6 @@ describe('toBePending', function() { }); 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(); @@ -25,8 +20,6 @@ describe('toBePending', function() { }); 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')); diff --git a/spec/core/matchers/async/toBeRejectedSpec.js b/spec/core/matchers/async/toBeRejectedSpec.js index c1ea377b..e69f0044 100644 --- a/spec/core/matchers/async/toBeRejectedSpec.js +++ b/spec/core/matchers/async/toBeRejectedSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ describe('toBeRejected', function() { it('passes if the actual is rejected', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil), actual = Promise.reject('AsyncExpectationSpec rejection'); @@ -13,8 +10,6 @@ describe('toBeRejected', function() { }); it('fails if the actual is resolved', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejected(matchersUtil), actual = Promise.resolve(); diff --git a/spec/core/matchers/async/toBeRejectedWithErrorSpec.js b/spec/core/matchers/async/toBeRejectedWithErrorSpec.js index d7d3f659..32a25ada 100644 --- a/spec/core/matchers/async/toBeRejectedWithErrorSpec.js +++ b/spec/core/matchers/async/toBeRejectedWithErrorSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ describe('#toBeRejectedWithError', function() { it('passes when Error type matches', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -23,8 +20,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when Error type and message matches', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -45,8 +40,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when Error matches and is exactly Error', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -67,8 +60,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when Error message matches a string', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -89,8 +80,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when Error message matches a RegExp', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -111,8 +100,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when Error message is empty', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -133,8 +120,6 @@ describe('#toBeRejectedWithError', function() { }); it('passes when no arguments', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -155,8 +140,6 @@ describe('#toBeRejectedWithError', function() { }); it('fails when resolved', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -176,8 +159,6 @@ describe('#toBeRejectedWithError', function() { }); it('fails when rejected with non Error type', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -198,8 +179,6 @@ describe('#toBeRejectedWithError', function() { }); it('fails when Error type mismatches', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -220,8 +199,6 @@ describe('#toBeRejectedWithError', function() { }); it('fails when Error message mismatches', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), diff --git a/spec/core/matchers/async/toBeRejectedWithSpec.js b/spec/core/matchers/async/toBeRejectedWithSpec.js index 9c663930..af96719f 100644 --- a/spec/core/matchers/async/toBeRejectedWithSpec.js +++ b/spec/core/matchers/async/toBeRejectedWithSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ describe('#toBeRejectedWith', function() { it('should return true if the promise is rejected with the expected value', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.reject({ error: 'PEBCAK' }); @@ -13,8 +10,6 @@ describe('#toBeRejectedWith', function() { }); it('should fail if the promise resolves', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeRejectedWith(matchersUtil), actual = Promise.resolve(); @@ -25,8 +20,6 @@ describe('#toBeRejectedWith', function() { }); it('should fail if the promise is rejected with a different value', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -45,8 +38,6 @@ describe('#toBeRejectedWith', function() { }); it('should build its error correctly when negated', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -64,8 +55,6 @@ describe('#toBeRejectedWith', function() { }); it('should support custom equality testers', function() { - jasmine.getEnv().requirePromises(); - var customEqualityTesters = [ function() { return true; diff --git a/spec/core/matchers/async/toBeResolvedSpec.js b/spec/core/matchers/async/toBeResolvedSpec.js index b90a537d..42ce930e 100644 --- a/spec/core/matchers/async/toBeResolvedSpec.js +++ b/spec/core/matchers/async/toBeResolvedSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ describe('toBeResolved', function() { it('passes if the actual is resolved', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeResolved(matchersUtil), actual = Promise.resolve(); @@ -13,8 +10,6 @@ describe('toBeResolved', function() { }); it('fails if the actual is rejected', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter([]) }), diff --git a/spec/core/matchers/async/toBeResolvedToSpec.js b/spec/core/matchers/async/toBeResolvedToSpec.js index 734b780e..20f465d2 100644 --- a/spec/core/matchers/async/toBeResolvedToSpec.js +++ b/spec/core/matchers/async/toBeResolvedToSpec.js @@ -1,8 +1,5 @@ -/* eslint-disable compat/compat */ describe('#toBeResolvedTo', function() { it('passes if the promise is resolved to the expected value', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), matcher = jasmineUnderTest.asyncMatchers.toBeResolvedTo(matchersUtil), actual = Promise.resolve({ foo: 42 }); @@ -13,8 +10,6 @@ describe('#toBeResolvedTo', function() { }); it('fails if the promise is rejected', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -34,8 +29,6 @@ describe('#toBeResolvedTo', function() { }); it('fails if the promise is resolved to a different value', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -54,8 +47,6 @@ describe('#toBeResolvedTo', function() { }); it('builds its message correctly when negated', function() { - jasmine.getEnv().requirePromises(); - var matchersUtil = new jasmineUnderTest.MatchersUtil({ pp: jasmineUnderTest.makePrettyPrinter() }), @@ -73,8 +64,6 @@ describe('#toBeResolvedTo', function() { }); it('supports custom equality testers', function() { - jasmine.getEnv().requirePromises(); - var customEqualityTesters = [ function() { return true; diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index d8b284a1..65d3d8f7 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -232,8 +232,8 @@ describe('matchersUtil', function() { return; } - var p1 = new Promise(function() {}), // eslint-disable-line compat/compat - p2 = new Promise(function() {}), // eslint-disable-line compat/compat + var p1 = new Promise(function() {}), + p2 = new Promise(function() {}), matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals(p1, p1)).toBe(true); @@ -655,48 +655,35 @@ describe('matchersUtil', function() { }); it('passes when comparing two identical URLs', function() { - jasmine.getEnv().requireUrls(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(); expect( matchersUtil.equals( - // eslint-disable-next-line compat/compat new URL('http://localhost/1'), - // eslint-disable-next-line compat/compat new URL('http://localhost/1') ) ).toBe(true); }); it('fails when comparing two different URLs', function() { - jasmine.getEnv().requireUrls(); - var matchersUtil = new jasmineUnderTest.MatchersUtil(), - // eslint-disable-next-line compat/compat url1 = new URL('http://localhost/1'); - // eslint-disable-next-line compat/compat expect(matchersUtil.equals(url1, new URL('http://localhost/2'))).toBe( false ); - // eslint-disable-next-line compat/compat expect(matchersUtil.equals(url1, new URL('http://localhost/1?foo'))).toBe( false ); - // eslint-disable-next-line compat/compat expect(matchersUtil.equals(url1, new URL('http://localhost/1#foo'))).toBe( false ); - // eslint-disable-next-line compat/compat expect(matchersUtil.equals(url1, new URL('https://localhost/1'))).toBe( false ); expect( - // eslint-disable-next-line compat/compat matchersUtil.equals(url1, new URL('http://localhost:8080/1')) ).toBe(false); - // eslint-disable-next-line compat/compat expect(matchersUtil.equals(url1, new URL('http://example.com/1'))).toBe( false ); @@ -721,15 +708,12 @@ describe('matchersUtil', function() { describe('Typed arrays', function() { it('fails for typed arrays of same length and contents but different types', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); - // eslint-disable-next-line compat/compat var a1 = new Int8Array(1); - // eslint-disable-next-line compat/compat var a2 = new Uint8Array(1); a1[0] = a2[0] = 0; expect(matchersUtil.equals(a1, a2)).toBe(false); }); - // eslint-disable-next-line compat/compat [ 'Int8Array', 'Uint8Array', @@ -741,20 +725,11 @@ describe('matchersUtil', function() { 'Float32Array', 'Float64Array' ].forEach(function(typeName) { - function requireType() { - var TypedArrayCtor = jasmine.getGlobal()[typeName]; - - if (!TypedArrayCtor) { - pending('Browser does not support ' + typeName); - } - - return TypedArrayCtor; - } + var TypedArrayCtor = jasmine.getGlobal()[typeName]; it( 'passes for ' + typeName + 's with same length and content', function() { - var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(2); @@ -765,7 +740,6 @@ describe('matchersUtil', function() { ); it('fails for ' + typeName + 's with different length', function() { - var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(2); var a2 = new TypedArrayCtor(1); @@ -776,7 +750,6 @@ describe('matchersUtil', function() { it( 'fails for ' + typeName + 's with same length but different content', function() { - var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); @@ -787,7 +760,6 @@ describe('matchersUtil', function() { ); it('checks nonstandard properties of ' + typeName, function() { - var TypedArrayCtor = requireType(); var matchersUtil = new jasmineUnderTest.MatchersUtil(); var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); @@ -797,7 +769,6 @@ describe('matchersUtil', function() { }); it('works with custom equality testers with ' + typeName, function() { - var TypedArrayCtor = requireType(); var a1 = new TypedArrayCtor(1); var a2 = new TypedArrayCtor(1); var matchersUtil = new jasmineUnderTest.MatchersUtil({ diff --git a/spec/core/matchers/toBeInstanceOfSpec.js b/spec/core/matchers/toBeInstanceOfSpec.js index f63ec842..252122f1 100644 --- a/spec/core/matchers/toBeInstanceOfSpec.js +++ b/spec/core/matchers/toBeInstanceOfSpec.js @@ -104,8 +104,6 @@ describe('toBeInstanceOf', function() { }); it('passes for an async function', function() { - jasmine.getEnv().requireAsyncAwait(); - var fn = eval("(async function fn() { return 'foo'; })"); var matcher = jasmineUnderTest.matchers.toBeInstanceOf(); diff --git a/spec/core/matchers/toEqualSpec.js b/spec/core/matchers/toEqualSpec.js index fe10bab4..5eed167d 100644 --- a/spec/core/matchers/toEqualSpec.js +++ b/spec/core/matchers/toEqualSpec.js @@ -620,9 +620,7 @@ describe('toEqual', function() { }); it('does not report mismatches when comparing Maps with the same symbol keys', function() { - jasmine.getEnv().requireFunctioningSymbols(); - - var key = Symbol(); // eslint-disable-line compat/compat + var key = Symbol(); var actual = new Map(); actual.set(key, 1); var expected = new Map(); @@ -632,12 +630,10 @@ describe('toEqual', function() { }); it('reports mismatches between Maps with different symbol keys', function() { - jasmine.getEnv().requireFunctioningSymbols(); - var actual = new Map(); - actual.set(Symbol(), 1); // eslint-disable-line compat/compat + actual.set(Symbol(), 1); var expected = new Map(); - expected.set(Symbol(), 1); // eslint-disable-line compat/compat + expected.set(Symbol(), 1); var message = 'Expected Map( [ Symbol(), 1 ] ) to equal Map( [ Symbol(), 1 ] ).'; @@ -645,10 +641,8 @@ describe('toEqual', function() { }); it('does not report mismatches when comparing Map symbol key to jasmine.anything()', function() { - jasmine.getEnv().requireFunctioningSymbols(); - var actual = new Map(); - actual.set(Symbol(), 1); // eslint-disable-line compat/compat + actual.set(Symbol(), 1); var expected = new Map(); expected.set(jasmineUnderTest.anything(), 1); diff --git a/spec/core/matchers/toHaveSizeSpec.js b/spec/core/matchers/toHaveSizeSpec.js index c0f3344c..afcf8e81 100644 --- a/spec/core/matchers/toHaveSizeSpec.js +++ b/spec/core/matchers/toHaveSizeSpec.js @@ -102,16 +102,14 @@ describe('toHaveSize', function() { }); it('throws an error for WeakSet', function() { - jasmine.getEnv().requireWeakSets(); var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { - matcher.compare(new WeakSet(), 2); // eslint-disable-line compat/compat + matcher.compare(new WeakSet(), 2); }).toThrowError('Cannot get size of [object WeakSet].'); }); it('throws an error for WeakMap', function() { - jasmine.getEnv().requireWeakMaps(); var matcher = jasmineUnderTest.matchers.toHaveSize(); expect(function() { diff --git a/spec/helpers/asyncAwait.js b/spec/helpers/asyncAwait.js deleted file mode 100644 index 9cdead0d..00000000 --- a/spec/helpers/asyncAwait.js +++ /dev/null @@ -1,26 +0,0 @@ -(function(env) { - function getAsyncCtor() { - try { - eval('var func = async function(){};'); - } catch (e) { - return null; - } - - return Object.getPrototypeOf(func).constructor; - } - - function hasAsyncAwaitSupport() { - return getAsyncCtor() !== null; - } - - env.makeAsyncAwaitFunction = function() { - var AsyncFunction = getAsyncCtor(); - return new AsyncFunction(''); - }; - - env.requireAsyncAwait = function() { - if (!hasAsyncAwaitSupport()) { - env.pending('Environment does not support async/await functions'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/checkForMap.js b/spec/helpers/checkForMap.js deleted file mode 100644 index 87f66410..00000000 --- a/spec/helpers/checkForMap.js +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - 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 deleted file mode 100644 index 203befcc..00000000 --- a/spec/helpers/checkForSet.js +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - env.requireWeakSets = function() { - if (typeof WeakSet === 'undefined') { - env.pending('Browser does not have support for WeakSet'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/checkForSymbol.js b/spec/helpers/checkForSymbol.js deleted file mode 100644 index 8b5e4b1e..00000000 --- a/spec/helpers/checkForSymbol.js +++ /dev/null @@ -1,28 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasFunctioningSymbols() { - if (typeof Symbol === 'undefined') { - return false; - } - - try { - var s1 = Symbol(); - var s2 = Symbol(); - if (typeof s1 !== 'symbol') { - return false; - } - if (s1 === s2) { - return false; - } - return true; - } catch (e) { - return false; - } - } - - env.requireFunctioningSymbols = function() { - if (!hasFunctioningSymbols()) { - env.pending('Browser has incomplete or missing support for Symbols'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/checkForUrl.js b/spec/helpers/checkForUrl.js deleted file mode 100644 index f8401fbb..00000000 --- a/spec/helpers/checkForUrl.js +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable compat/compat */ -(function(env) { - function hasUrlConstructor() { - try { - new URL('http://localhost/'); - return true; - } catch (e) { - return false; - } - } - - env.requireUrls = function() { - if (!hasUrlConstructor()) { - env.pending('Environment does not support URLs'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/generator.js b/spec/helpers/generator.js deleted file mode 100644 index b62f5acd..00000000 --- a/spec/helpers/generator.js +++ /dev/null @@ -1,22 +0,0 @@ -(function(env) { - function getGeneratorFuncCtor() { - try { - eval('var func = function*() {}'); - } catch (e) { - return null; - } - - return Object.getPrototypeOf(func).constructor; - } - - env.makeGeneratorFunction = function(text) { - var GeneratorFunction = getGeneratorFuncCtor(); - return new GeneratorFunction(text || ''); - }; - - env.requireGeneratorFunctions = function() { - if (!getGeneratorFuncCtor()) { - env.pending('Environment does not support generator functions'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/helpers/promises.js b/spec/helpers/promises.js deleted file mode 100644 index a194af0c..00000000 --- a/spec/helpers/promises.js +++ /dev/null @@ -1,7 +0,0 @@ -(function(env) { - env.requirePromises = function() { - if (typeof Promise !== 'function') { - env.pending('Environment does not support promises'); - } - }; -})(jasmine.getEnv()); diff --git a/spec/html/SpyRegistryHtmlSpec.js b/spec/html/SpyRegistryHtmlSpec.js index e43e9eeb..bad2d2bd 100644 --- a/spec/html/SpyRegistryHtmlSpec.js +++ b/spec/html/SpyRegistryHtmlSpec.js @@ -4,8 +4,6 @@ describe('Spy Registry browser-specific behavior', function() { } it('can spy on and unspy window.onerror', function() { - requireWriteableOnerror(); - var spies = [], spyRegistry = new jasmineUnderTest.SpyRegistry({ currentSpies: function() { @@ -24,18 +22,4 @@ describe('Spy Registry browser-specific behavior', function() { window.onerror = originalHandler; } }); - - function requireWriteableOnerror() { - var descriptor; - - try { - descriptor = Object.getOwnPropertyDescriptor(window, 'onerror'); - } catch (e) { - // IE 8 doesn't support `definePropery` on non-DOM nodes - } - - if (descriptor && !(descriptor.writable || descriptor.set)) { - pending('Browser declares window.onerror to be readonly'); - } - } }); diff --git a/spec/support/jasmine-browser.js b/spec/support/jasmine-browser.js index 0845989b..1277d421 100644 --- a/spec/support/jasmine-browser.js +++ b/spec/support/jasmine-browser.js @@ -17,16 +17,10 @@ module.exports = { specDir: 'spec', specFiles: ['**/*[Ss]pec.js', '!npmPackage/**/*'], helpers: [ - 'helpers/asyncAwait.js', 'helpers/generator.js', 'helpers/BrowserFlags.js', - 'helpers/checkForMap.js', - 'helpers/checkForSet.js', - 'helpers/checkForSymbol.js', - 'helpers/checkForUrl.js', 'helpers/domHelpers.js', 'helpers/integrationMatchers.js', - 'helpers/promises.js', 'helpers/defineJasmineUnderTest.js', 'helpers/resetEnv.js' ], diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index 2c3c5107..f24ab080 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -5,15 +5,8 @@ "npmPackage/**/*[Ss]pec.js" ], "helpers": [ - "helpers/asyncAwait.js", - "helpers/generator.js", - "helpers/checkForMap.js", - "helpers/checkForSet.js", - "helpers/checkForSymbol.js", - "helpers/checkForUrl.js", "helpers/domHelpers.js", "helpers/integrationMatchers.js", - "helpers/promises.js", "helpers/overrideConsoleLogForCircleCi.js", "helpers/nodeDefineJasmineUnderTest.js", "helpers/resetEnv.js" diff --git a/src/core/Expectation.js b/src/core/Expectation.js index 0309ec34..a92af848 100644 --- a/src/core/Expectation.js +++ b/src/core/Expectation.js @@ -75,15 +75,8 @@ getJasmineRequireObj().Expectation = function(j$) { * @namespace async-matchers */ function AsyncExpectation(options) { - var global = options.global || j$.getGlobal(); this.expector = new j$.Expector(options); - if (!global.Promise) { - throw new Error( - 'expectAsync is unavailable because the environment does not support promises.' - ); - } - var customAsyncMatchers = options.customAsyncMatchers || {}; for (var matcherName in customAsyncMatchers) { this[matcherName] = wrapAsyncCompare( diff --git a/src/core/MockDate.js b/src/core/MockDate.js index 7b642038..a0dd164c 100644 --- a/src/core/MockDate.js +++ b/src/core/MockDate.js @@ -87,11 +87,7 @@ getJasmineRequireObj().MockDate = function() { FakeDate.prototype = GlobalDate.prototype; FakeDate.now = function() { - if (GlobalDate.now) { - return currentTime; - } else { - throw new Error('Browser does not support Date.now()'); - } + return currentTime; }; FakeDate.toSource = GlobalDate.toSource; diff --git a/src/core/StackTrace.js b/src/core/StackTrace.js index 44db4ff1..c32ee8b2 100644 --- a/src/core/StackTrace.js +++ b/src/core/StackTrace.js @@ -17,7 +17,7 @@ getJasmineRequireObj().StackTrace = function(j$) { } var framePatterns = [ - // PhantomJS on Linux, Node, Chrome, IE, Edge + // Node, Chrome, Edge // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)" // Note that the "function name" can include a surprisingly large set of // characters, including angle brackets and square brackets. diff --git a/src/core/asymmetric_equality/MapContaining.js b/src/core/asymmetric_equality/MapContaining.js index 8e29fbe9..9e0ee422 100644 --- a/src/core/asymmetric_equality/MapContaining.js +++ b/src/core/asymmetric_equality/MapContaining.js @@ -13,27 +13,26 @@ getJasmineRequireObj().MapContaining = function(j$) { MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isMap(other)) return false; - var hasAllMatches = true; - j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) { + for (const [key, value] of this.sample) { // for each key/value pair in `sample` // there should be at least one pair in `other` whose key and value both match var hasMatch = false; - j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) { + for (const [oKey, oValue] of other) { if ( matchersUtil.equals(oKey, key) && matchersUtil.equals(oValue, value) ) { hasMatch = true; - oBreakLoop(); + break; } - }); - if (!hasMatch) { - hasAllMatches = false; - breakLoop(); } - }); - return hasAllMatches; + if (!hasMatch) { + return false; + } + } + + return true; }; MapContaining.prototype.jasmineToString = function(pp) { diff --git a/src/core/asymmetric_equality/SetContaining.js b/src/core/asymmetric_equality/SetContaining.js index fe4d6293..46c0e88c 100644 --- a/src/core/asymmetric_equality/SetContaining.js +++ b/src/core/asymmetric_equality/SetContaining.js @@ -13,25 +13,24 @@ getJasmineRequireObj().SetContaining = function(j$) { SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) { if (!j$.isSet(other)) return false; - var hasAllMatches = true; - j$.util.forEachBreakable(this.sample, function(breakLoop, item) { + for (const item of this.sample) { // for each item in `sample` there should be at least one matching item in `other` // (not using `matchersUtil.contains` because it compares set members by reference, // not by deep value equality) var hasMatch = false; - j$.util.forEachBreakable(other, function(oBreakLoop, oItem) { + for (const oItem of other) { if (matchersUtil.equals(oItem, item)) { hasMatch = true; - oBreakLoop(); + break; } - }); - if (!hasMatch) { - hasAllMatches = false; - breakLoop(); } - }); - return hasAllMatches; + if (!hasMatch) { + return false; + } + } + + return true; }; SetContaining.prototype.jasmineToString = function(pp) { diff --git a/src/core/base.js b/src/core/base.js index 35fd1ca9..f773fd10 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -106,25 +106,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { if (value instanceof Error) { return true; } - if ( - typeof window !== 'undefined' && - typeof window.trustedTypes !== 'undefined' - ) { - return ( - typeof value.stack === 'string' && typeof value.message === 'string' - ); - } - if (value && value.constructor && value.constructor.constructor) { - var valueGlobal = value.constructor.constructor('return this'); - if (j$.isFunction_(valueGlobal)) { - valueGlobal = valueGlobal(); - } - if (valueGlobal.Error && value instanceof valueGlobal.Error) { - return true; - } - } - return false; + return typeof value.stack === 'string' && typeof value.message === 'string'; }; j$.isAsymmetricEqualityTester_ = function(obj) { @@ -166,7 +149,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.WeakMap !== 'undefined' && obj.constructor === jasmineGlobal.WeakMap ); }; @@ -175,7 +157,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.URL !== 'undefined' && obj.constructor === jasmineGlobal.URL ); }; @@ -184,17 +165,12 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { return ( obj !== null && typeof obj !== 'undefined' && - typeof jasmineGlobal.DataView !== 'undefined' && obj.constructor === jasmineGlobal.DataView ); }; j$.isPromise = function(obj) { - return ( - typeof jasmineGlobal.Promise !== 'undefined' && - !!obj && - obj.constructor === jasmineGlobal.Promise - ); + return !!obj && obj.constructor === jasmineGlobal.Promise; }; j$.isPromiseLike = function(obj) { @@ -215,7 +191,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { j$.isPending_ = function(promise) { var sentinel = {}; - // eslint-disable-next-line compat/compat return Promise.race([promise, Promise.resolve(sentinel)]).then( function(result) { return result === sentinel; diff --git a/src/core/matchers/async/toBePending.js b/src/core/matchers/async/toBePending.js index 1e438d4f..d6703d7b 100644 --- a/src/core/matchers/async/toBePending.js +++ b/src/core/matchers/async/toBePending.js @@ -1,4 +1,3 @@ -/* eslint-disable compat/compat */ getJasmineRequireObj().toBePending = function(j$) { /** * Expect a promise to be pending, i.e. the promise is neither resolved nor rejected. diff --git a/src/core/matchers/toHaveSize.js b/src/core/matchers/toHaveSize.js index 403080a8..87b75af7 100644 --- a/src/core/matchers/toHaveSize.js +++ b/src/core/matchers/toHaveSize.js @@ -37,7 +37,7 @@ getJasmineRequireObj().toHaveSize = function(j$) { }; } - var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; // eslint-disable-line compat/compat + var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; function isLength(value) { return ( typeof value == 'number' && diff --git a/src/core/util.js b/src/core/util.js index 64aedef1..21c31f58 100644 --- a/src/core/util.js +++ b/src/core/util.js @@ -127,20 +127,5 @@ getJasmineRequireObj().util = function(j$) { StopIteration.prototype = Object.create(Error.prototype); StopIteration.prototype.constructor = StopIteration; - // useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them - util.forEachBreakable = function(iterable, iteratee) { - function breakLoop() { - throw new StopIteration(); - } - - try { - iterable.forEach(function(value, key) { - iteratee(breakLoop, value, key, iterable); - }); - } catch (error) { - if (!(error instanceof StopIteration)) throw error; - } - }; - return util; }; From ed9363f477db3f0ef40892e26cde32de29f2d37c Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 24 Jul 2021 08:23:09 -0700 Subject: [PATCH 13/71] Removed bower.json Bower itself has been deprecated for four years, so we should drop support for it in 4.0. [Finishes #178512921] --- bower.json | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 bower.json diff --git a/bower.json b/bower.json deleted file mode 100644 index 34157580..00000000 --- a/bower.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "jasmine-core", - "homepage": "https://jasmine.github.io", - "authors": [ - "slackersoft " - ], - "description": "Official packaging of Jasmine's core files", - "keywords": [ - "test", - "jasmine", - "tdd", - "bdd" - ], - "license": "MIT", - "moduleType": "globals", - "main": "lib/jasmine-core/jasmine.js", - "ignore": [ - "**/.*", - "dist", - "grunt", - "node_modules", - "pkg", - "release_notes", - "spec", - "src", - "Gemfile", - "Gemfile.lock", - "Rakefile", - "jasmine-core.gemspec", - "*.sh", - "*.py", - "Gruntfile.js", - "lib/jasmine-core.rb", - "lib/jasmine-core/boot/", - "lib/jasmine-core/spec", - "lib/jasmine-core/version.rb", - "lib/jasmine-core/*.py", - "sauce_connect.log" - ] -} From 0170005015b68b0dfa872c35669f1e6a8d730869 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 24 Jul 2021 09:30:39 -0700 Subject: [PATCH 14/71] Treat any argument to the done callback as an error This reduces the risk of incorrectly passing a spec due to not correctly detecting that an argument is an `Error` instance. Detecting Error instances in a way that's reliable and portable across different browsers, TrustedTypes, and frames is difficult. [Finishes #178267587] --- lib/jasmine-core/jasmine.js | 8 +-- spec/core/QueueRunnerSpec.js | 120 ++++++----------------------------- src/core/QueueRunner.js | 8 +-- 3 files changed, 23 insertions(+), 113 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 8dca5bf2..c74a5805 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -7491,17 +7491,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { next = once(function next(err) { cleanup(); - if (j$.isError_(err)) { + if (typeof err !== 'undefined') { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } self.errored = errored = true; - } else if (typeof err !== 'undefined' && !self.errored) { - self.deprecated( - 'Any argument passed to a done callback will be treated as an ' + - 'error in a future release. Call the done callback without ' + - "arguments if you don't want to trigger a spec failure." - ); } function runNext() { diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 134cfc01..955f3837 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -150,109 +150,31 @@ describe('QueueRunner', function() { }); describe('When next is called with an argument', function() { - describe('that is an Error', function() { - it('explicitly fails and moves to the next function', function() { - var err = new Error('foo'), - queueableFn1 = { - fn: function(done) { - setTimeout(function() { - done(err); - }, 100); - } - }, - queueableFn2 = { fn: jasmine.createSpy('fn2') }, - failFn = jasmine.createSpy('fail'), - queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn1, queueableFn2], - fail: failFn - }); + it('explicitly fails and moves to the next function', function() { + var err = 'anything except undefined', + queueableFn1 = { + fn: function(done) { + setTimeout(function() { + done(err); + }, 100); + } + }, + queueableFn2 = { fn: jasmine.createSpy('fn2') }, + failFn = jasmine.createSpy('fail'), + queueRunner = new jasmineUnderTest.QueueRunner({ + queueableFns: [queueableFn1, queueableFn2], + fail: failFn + }); - queueRunner.execute(); + queueRunner.execute(); - expect(failFn).not.toHaveBeenCalled(); - expect(queueableFn2.fn).not.toHaveBeenCalled(); + expect(failFn).not.toHaveBeenCalled(); + expect(queueableFn2.fn).not.toHaveBeenCalled(); - jasmine.clock().tick(100); + jasmine.clock().tick(100); - expect(failFn).toHaveBeenCalledWith(err); - expect(queueableFn2.fn).toHaveBeenCalled(); - }); - - it('does not log a deprecation', function() { - var err = new Error('foo'), - queueableFn1 = { - fn: function(done) { - setTimeout(function() { - done(err); - }, 100); - } - }, - deprecated = jasmine.createSpy('deprecated'), - queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn1], - deprecated: deprecated - }); - - queueRunner.execute(); - - jasmine.clock().tick(100); - - expect(deprecated).not.toHaveBeenCalled(); - }); - }); - - describe('that is not an Error', function() { - it('logs a deprecation', function() { - var queueableFn1 = { - fn: function(done) { - setTimeout(function() { - done('not an Error'); - }, 100); - } - }, - deprecated = jasmine.createSpy('deprecated'), - queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn1], - deprecated: deprecated - }); - - queueRunner.execute(); - - jasmine.clock().tick(100); - - expect(deprecated).toHaveBeenCalledWith( - 'Any argument passed to a done callback will be treated as an ' + - 'error in a future release. Call the done callback without ' + - "arguments if you don't want to trigger a spec failure." - ); - }); - - it('moves to the next function without failing', function() { - var queueableFn1 = { - fn: function(done) { - setTimeout(function() { - done('not an Error'); - }, 100); - } - }, - queueableFn2 = { fn: jasmine.createSpy('fn2') }, - failFn = jasmine.createSpy('fail'), - queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn1, queueableFn2], - fail: failFn, - deprecated: function() {} - }); - - queueRunner.execute(); - - expect(failFn).not.toHaveBeenCalled(); - expect(queueableFn2.fn).not.toHaveBeenCalled(); - - jasmine.clock().tick(100); - - expect(failFn).not.toHaveBeenCalled(); - expect(queueableFn2.fn).toHaveBeenCalled(); - }); + expect(failFn).toHaveBeenCalledWith(err); + expect(queueableFn2.fn).toHaveBeenCalled(); }); }); diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index ce227108..57b70901 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -100,17 +100,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { next = once(function next(err) { cleanup(); - if (j$.isError_(err)) { + if (typeof err !== 'undefined') { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } self.errored = errored = true; - } else if (typeof err !== 'undefined' && !self.errored) { - self.deprecated( - 'Any argument passed to a done callback will be treated as an ' + - 'error in a future release. Call the done callback without ' + - "arguments if you don't want to trigger a spec failure." - ); } function runNext() { From c73df57720bc867c972d7915673df165430ce31a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 24 Jul 2021 14:23:05 -0700 Subject: [PATCH 15/71] MatchersUtil#contains uses deep equality rather than === for set members [#169001712] --- lib/jasmine-core/jasmine.js | 42 +++++++++++++++++++++----- spec/core/baseSpec.js | 22 ++++++++++++++ spec/core/matchers/matchersUtilSpec.js | 20 +++++++++--- src/core/base.js | 4 +++ src/core/matchers/matchersUtil.js | 38 ++++++++++++++++++----- 5 files changed, 106 insertions(+), 20 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index c74a5805..d22d0bb4 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -322,6 +322,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { ); }; + j$.isIterable_ = function(value) { + return value && !!value[Symbol.iterator]; + }; + j$.isDataView = function(obj) { return ( obj !== null && @@ -4685,23 +4689,45 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @returns {boolean} True if `needle` was found in `haystack` */ MatchersUtil.prototype.contains = function(haystack, needle) { - if (j$.isSet(haystack)) { - return haystack.has(needle); + if (!haystack) { + return false; } - if ( - Object.prototype.toString.apply(haystack) === '[object Array]' || - (!!haystack && !haystack.indexOf) - ) { + if (j$.isSet(haystack)) { + // Try .has() first. It should be faster in cases where + // needle === something in haystack. Fall back to .equals() comparison + // if that fails. + if (haystack.has(needle)) { + return true; + } + } + + if (j$.isIterable_(haystack) && !j$.isString_(haystack)) { + // Arrays, Sets, etc. + for (const candidate of haystack) { + if (this.equals(candidate, needle)) { + return true; + } + } + + return false; + } + + if (haystack.indexOf) { + // Mainly strings + return haystack.indexOf(needle) >= 0; + } + + if (j$.isNumber_(haystack.length)) { + // Objects that are shaped like arrays but aren't iterable for (var i = 0; i < haystack.length; i++) { if (this.equals(haystack[i], needle)) { return true; } } - return false; } - return !!haystack && haystack.indexOf(needle) >= 0; + return false; }; MatchersUtil.prototype.buildFailureMessage = function() { diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 91a73337..7cb8230d 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -109,6 +109,28 @@ describe('base helpers', function() { }); }); + describe('isIterable_', function() { + it('returns true when the object is an Array', function() { + expect(jasmineUnderTest.isIterable_([])).toBe(true); + }); + + it('returns true when the object is a Set', function() { + expect(jasmineUnderTest.isIterable_(new Set())).toBe(true); + }); + it('returns true when the object is a Map', function() { + expect(jasmineUnderTest.isIterable_(new Map())).toBe(true); + }); + + it('returns true when the object implements @@iterator', function() { + const myIterable = { [Symbol.iterator]: function() {} }; + expect(jasmineUnderTest.isIterable_(myIterable)).toBe(true); + }); + + it('returns false when the object does not implement @@iterator', function() { + expect(jasmineUnderTest.isIterable_({})).toBe(false); + }); + }); + describe('isPending_', function() { it('returns a promise that resolves to true when the promise is pending', function() { var promise = new Promise(function() {}); diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 65d3d8f7..a01c16e4 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -1030,7 +1030,7 @@ describe('matchersUtil', function() { expect(matchersUtil.contains(null, 'A')).toBe(false); }); - it('passes with array-like objects', function() { + it('works with array-like objects that implement iterable', function() { var capturedArgs = null, matchersUtil = new jasmineUnderTest.MatchersUtil(); @@ -1040,6 +1040,19 @@ describe('matchersUtil', function() { testFunction('foo', 'bar'); expect(matchersUtil.contains(capturedArgs, 'bar')).toBe(true); + expect(matchersUtil.contains(capturedArgs, 'baz')).toBe(false); + }); + + it("passes with array-like objects that don't implement iterable", function() { + const arrayLike = { + 0: 'a', + 1: 'b', + length: 2 + }; + const matchersUtil = new jasmineUnderTest.MatchersUtil(); + + expect(matchersUtil.contains(arrayLike, 'b')).toBe(true); + expect(matchersUtil.contains(arrayLike, 'c')).toBe(false); }); it('passes for set members', function() { @@ -1051,13 +1064,12 @@ describe('matchersUtil', function() { expect(matchersUtil.contains(set, setItem)).toBe(true); }); - // documenting current behavior - it('fails (!) for objects that equal to a set member', function() { + it('passes for objects that equal to a set member', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var set = new Set(); set.add({ foo: 'bar' }); - expect(matchersUtil.contains(set, { foo: 'bar' })).toBe(false); + expect(matchersUtil.contains(set, { foo: 'bar' })).toBe(true); }); }); diff --git a/src/core/base.js b/src/core/base.js index f773fd10..983e1602 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -161,6 +161,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { ); }; + j$.isIterable_ = function(value) { + return value && !!value[Symbol.iterator]; + }; + j$.isDataView = function(obj) { return ( obj !== null && diff --git a/src/core/matchers/matchersUtil.js b/src/core/matchers/matchersUtil.js index ddd53798..1650b64f 100644 --- a/src/core/matchers/matchersUtil.js +++ b/src/core/matchers/matchersUtil.js @@ -32,23 +32,45 @@ getJasmineRequireObj().MatchersUtil = function(j$) { * @returns {boolean} True if `needle` was found in `haystack` */ MatchersUtil.prototype.contains = function(haystack, needle) { - if (j$.isSet(haystack)) { - return haystack.has(needle); + if (!haystack) { + return false; } - if ( - Object.prototype.toString.apply(haystack) === '[object Array]' || - (!!haystack && !haystack.indexOf) - ) { + if (j$.isSet(haystack)) { + // Try .has() first. It should be faster in cases where + // needle === something in haystack. Fall back to .equals() comparison + // if that fails. + if (haystack.has(needle)) { + return true; + } + } + + if (j$.isIterable_(haystack) && !j$.isString_(haystack)) { + // Arrays, Sets, etc. + for (const candidate of haystack) { + if (this.equals(candidate, needle)) { + return true; + } + } + + return false; + } + + if (haystack.indexOf) { + // Mainly strings + return haystack.indexOf(needle) >= 0; + } + + if (j$.isNumber_(haystack.length)) { + // Objects that are shaped like arrays but aren't iterable for (var i = 0; i < haystack.length; i++) { if (this.equals(haystack[i], needle)) { return true; } } - return false; } - return !!haystack && haystack.indexOf(needle) >= 0; + return false; }; MatchersUtil.prototype.buildFailureMessage = function() { From 0424d4ae993e679c88ff4e25d401574967d37089 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 26 Jul 2021 18:28:38 -0700 Subject: [PATCH 16/71] Removed Python support --- .github/CONTRIBUTING.md | 2 +- .gitignore | 2 - MANIFEST.in | 6 --- RELEASE.md | 7 --- images/__init__.py | 0 lib/jasmine-core/__init__.py | 1 - lib/jasmine-core/boot.js | 2 +- lib/jasmine-core/boot/boot.js | 2 +- lib/jasmine-core/core.py | 94 ----------------------------------- requirements.txt | 1 - setup.py | 70 -------------------------- 11 files changed, 3 insertions(+), 184 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 images/__init__.py delete mode 100644 lib/jasmine-core/__init__.py delete mode 100644 lib/jasmine-core/core.py delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d4986bb6..1210ec89 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -42,7 +42,7 @@ Once you've pushed a feature branch to your forked repo, you're ready to open a * mirrors the source directory * there are some additional files * `/lib` contains the compiled copy of Jasmine. This is used to self-test and - distributed as the `jasmine-core` Node, Ruby, and Python packages. + distributed as the `jasmine-core` Node, and Ruby packages. ### Self-testing diff --git a/.gitignore b/.gitignore index 644ebecd..8dcc71a6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,11 +17,9 @@ pkg/* .sass-cache/* src/html/.sass-cache/* node_modules/ -*.pyc sauce_connect.log *.swp build/ -*.egg-info/ dist nbproject/ *.iml diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 122cd026..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -recursive-include . *.py -prune node_modules -include lib/jasmine-core/*.js -include lib/jasmine-core/*.css -include images/*.png -include package.json diff --git a/RELEASE.md b/RELEASE.md index 7e3d959b..3f0029d3 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -50,13 +50,6 @@ When ready to release - specs are all green and the stories are done: 1. __NOTE__: You will likely need to push a new jasmine gem with a dependent version right after this release. See below. 1. `rake release` - tags the repo with the version, builds the `jasmine-core` gem, pushes the gem to Rubygems.org. In order to release you will have to ensure you have rubygems creds locally. -### Release the core Python egg - -Install [twine](https://github.com/pypa/twine) - -1. `python setup.py sdist` -1. `twine upload dist/jasmine-core-.tar.gz` You will need pypi credentials to upload the egg. - ### Release the core NPM module 1. Run the tests on Windows. (CI only tests on Linux.) diff --git a/images/__init__.py b/images/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/jasmine-core/__init__.py b/lib/jasmine-core/__init__.py deleted file mode 100644 index a8d584aa..00000000 --- a/lib/jasmine-core/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .core import Core \ No newline at end of file diff --git a/lib/jasmine-core/boot.js b/lib/jasmine-core/boot.js index 187e6355..522cf413 100644 --- a/lib/jasmine-core/boot.js +++ b/lib/jasmine-core/boot.js @@ -27,7 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. - If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. + If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments will have different mechanisms. The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index c776eb13..7f4b9b51 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -5,7 +5,7 @@ Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. - If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. + If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments will have different mechanisms. The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. diff --git a/lib/jasmine-core/core.py b/lib/jasmine-core/core.py deleted file mode 100644 index 936e9b0f..00000000 --- a/lib/jasmine-core/core.py +++ /dev/null @@ -1,94 +0,0 @@ -import pkg_resources -import os - -if 'SUPPRESS_JASMINE_DEPRECATION' not in os.environ: - print('DEPRECATION WARNING:\n' + - '\n' + - 'The Jasmine packages for Python are deprecated. There will be no further\n' + - 'releases after the end of the Jasmine 3.x series. We recommend migrating to the\n' + - 'following options:\n' + - '\n' + - '* jasmine-browser-runner (,\n' + - ' `npm install jasmine-browser-runner`) to run specs in browsers, including\n' + - ' headless Chrome and Saucelabs. This is the most direct replacement for the\n' + - ' jasmine server` and `jasmine ci` commands provided by the `jasmine` Python\n' + - ' package.\n' + - '* The jasmine npm package (,\n' + - ' `npm install jasmine`) to run specs under Node.js.\n' + - '* The standalone distribution from the latest Jasmine release\n' + - ' to run specs in browsers with\n' + - ' no additional tools.\n' + - '* The jasmine-core npm package (`npm install jasmine-core`) if all you need is\n' + - ' the Jasmine assets. This is the direct equivalent of the jasmine-core Python\n' + - ' package.\n' + - '\n' + - 'Except for the standalone distribution, all of the above are distributed through\n' + - 'npm.\n' + - '\n' + - 'To prevent this message from appearing, set the SUPPRESS_JASMINE_DEPRECATION\n' + - 'environment variable.\n') - - -try: - from collections import OrderedDict -except ImportError: - from ordereddict import OrderedDict - -class Core(object): - @classmethod - def js_package(cls): - return __package__ - - @classmethod - def css_package(cls): - return __package__ - - @classmethod - def image_package(cls): - return __package__ + ".images" - - @classmethod - def js_files(cls): - js_files = sorted(list(filter(lambda x: '.js' in x, pkg_resources.resource_listdir(cls.js_package(), '.')))) - - # jasmine.js needs to be first - js_files.insert(0, 'jasmine.js') - - # boot needs to be last - js_files.remove('boot.js') - js_files.append('boot.js') - - # Remove the new boot files. jasmine-py will continue to use the legacy - # boot.js. - js_files.remove('boot0.js') - js_files.remove('boot1.js') - - return cls._uniq(js_files) - - @classmethod - def css_files(cls): - return cls._uniq(sorted(filter(lambda x: '.css' in x, pkg_resources.resource_listdir(cls.css_package(), '.')))) - - @classmethod - def favicon(cls): - return 'jasmine_favicon.png' - - @classmethod - def _uniq(self, items, idfun=None): - # order preserving - - if idfun is None: - def idfun(x): return x - seen = {} - result = [] - for item in items: - marker = idfun(item) - # in old Python versions: - # if seen.has_key(marker) - # but in new ones: - if marker in seen: - continue - - seen[marker] = 1 - result.append(item) - return result diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 591279c2..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -ordereddict==1.1 diff --git a/setup.py b/setup.py deleted file mode 100644 index eab51064..00000000 --- a/setup.py +++ /dev/null @@ -1,70 +0,0 @@ -from setuptools import setup, find_packages, os -import json - -with open('package.json') as packageFile: - version = json.load(packageFile)['version'] - -short_description=('Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on '+ - 'browsers, DOM, or any JavaScript framework. Thus it\'s suited for websites, '+ - 'Node.js (http://nodejs.org) projects, or anywhere that JavaScript can run.') -deprecation=('The Jasmine packages for Python are deprecated. There will be no further\n' + - 'releases after the end of the Jasmine 3.x series. We recommend migrating to the\n' + - 'following options:\n' + - '\n' + - '* jasmine-browser-runner (,\n' + - ' `npm install jasmine-browser-runner`) to run specs in browsers, including\n' + - ' headless Chrome and Saucelabs. This is the most direct replacement for the\n' + - ' jasmine server` and `jasmine ci` commands provided by the `jasmine` Python\n' + - ' package.\n' + - '* The jasmine npm package (,\n' + - ' `npm install jasmine`) to run specs under Node.js.\n' + - '* The standalone distribution from the latest Jasmine release\n' + - ' to run specs in browsers with\n' + - ' no additional tools.\n' + - '* The jasmine-core npm package (`npm install jasmine-core`) if all you need is\n' + - ' the Jasmine assets. This is the direct equivalent of the jasmine-core Python\n' + - ' package.\n' + - '\n' + - 'Except for the standalone distribution, all of the above are distributed through\n' - 'npm.\n') -long_description = short_description + '\n\n' + deprecation - - -setup( - name="jasmine-core", - version=version, - url="http://jasmine.github.io", - author="Pivotal Labs", - author_email="jasmine-js@googlegroups.com", - description=short_description, - long_description=long_description, - long_description_content_type='text/plain', - license='MIT', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Environment :: Web Environment', - 'Framework :: Django', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Software Development :: Build Tools', - 'Topic :: Software Development :: Quality Assurance', - 'Topic :: Software Development :: Testing', - ], - - packages=['jasmine_core', 'jasmine_core.images'], - package_dir={'jasmine_core': 'lib/jasmine-core', 'jasmine_core.images': 'images'}, - package_data={'jasmine_core': ['*.js', '*.css'], 'jasmine_core.images': ['*.png']}, - - include_package_data=True, - - install_requires=['glob2>=0.4.1', 'ordereddict==1.1'] -) From 310e4d5e6cf2b257fd6bbae52c6711e73df56100 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 26 Jul 2021 18:29:54 -0700 Subject: [PATCH 17/71] Removed legacy boot.js file --- grunt/config/concat.js | 4 - lib/jasmine-core.rb | 2 +- lib/jasmine-core/boot.js | 159 ------------------------------ lib/jasmine-core/boot/boot.js | 137 ------------------------- spec/npmPackage/npmPackageSpec.js | 4 - 5 files changed, 1 insertion(+), 305 deletions(-) delete mode 100644 lib/jasmine-core/boot.js delete mode 100644 lib/jasmine-core/boot/boot.js diff --git a/grunt/config/concat.js b/grunt/config/concat.js index 098aa2a8..8c887a7d 100644 --- a/grunt/config/concat.js +++ b/grunt/config/concat.js @@ -37,10 +37,6 @@ module.exports = { ], dest: 'lib/jasmine-core/jasmine.js' }, - boot: { - src: ['lib/jasmine-core/boot/boot.js'], - dest: 'lib/jasmine-core/boot.js' - }, boot0: { src: ['lib/jasmine-core/boot/boot0.js'], dest: 'lib/jasmine-core/boot0.js' diff --git a/lib/jasmine-core.rb b/lib/jasmine-core.rb index d540f631..947f5ba2 100644 --- a/lib/jasmine-core.rb +++ b/lib/jasmine-core.rb @@ -24,7 +24,7 @@ module Jasmine end def boot_files - ["boot.js"] + ["boot0.js", "boot1.js"] end def node_boot_files diff --git a/lib/jasmine-core/boot.js b/lib/jasmine-core/boot.js deleted file mode 100644 index 522cf413..00000000 --- a/lib/jasmine-core/boot.js +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright (c) 2008-2021 Pivotal Labs - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -/** - - NOTE: This file is deprecated and will be removed in a future release. - Include both boot0.js and boot1.js (in that order) instead. - - Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. - - If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments will have different mechanisms. - - The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. - - [jasmine-gem]: http://github.com/pivotal/jasmine-gem - */ - -(function() { - var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); - - /** - * ## Require & Instantiate - * - * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. - */ - var jasmine = jasmineRequire.core(jasmineRequire), - global = jasmine.getGlobal(); - global.jasmine = jasmine; - - /** - * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. - */ - jasmineRequire.html(jasmine); - - /** - * Create the Jasmine environment. This is used to run all specs in a project. - */ - var env = jasmine.getEnv(); - - /** - * ## The Global Interface - * - * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. - */ - var jasmineInterface = jasmineRequire.interface(jasmine, env); - - /** - * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. - */ - extend(global, jasmineInterface); - - /** - * ## Runner Parameters - * - * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. - */ - - var queryString = new jasmine.QueryString({ - getWindowLocation: function() { return window.location; } - }); - - var filterSpecs = !!queryString.getParam("spec"); - - var config = { - failFast: queryString.getParam("failFast"), - oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"), - hideDisabled: queryString.getParam("hideDisabled") - }; - - var random = queryString.getParam("random"); - - if (random !== undefined && random !== "") { - config.random = random; - } - - var seed = queryString.getParam("seed"); - if (seed) { - config.seed = seed; - } - - /** - * ## Reporters - * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). - */ - var htmlReporter = new jasmine.HtmlReporter({ - env: env, - navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, - addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, - getContainer: function() { return document.body; }, - createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); }, - timer: new jasmine.Timer(), - filterSpecs: filterSpecs - }); - - /** - * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. - */ - env.addReporter(jasmineInterface.jsApiReporter); - env.addReporter(htmlReporter); - - /** - * Filter which specs will be run by matching the start of the full name against the `spec` query param. - */ - var specFilter = new jasmine.HtmlSpecFilter({ - filterString: function() { return queryString.getParam("spec"); } - }); - - config.specFilter = function(spec) { - return specFilter.matches(spec.getFullName()); - }; - - env.configure(config); - - /** - * ## Execution - * - * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. - */ - var currentWindowOnload = window.onload; - - window.onload = function() { - if (currentWindowOnload) { - currentWindowOnload(); - } - htmlReporter.initialize(); - env.execute(); - }; - - /** - * Helper function for readability above. - */ - function extend(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; - } - - env.deprecated('boot.js is deprecated. Please use boot0.js and boot1.js instead.', - { ignoreRunnable: true }); -}()); diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js deleted file mode 100644 index 7f4b9b51..00000000 --- a/lib/jasmine-core/boot/boot.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - - NOTE: This file is deprecated and will be removed in a future release. - Include both boot0.js and boot1.js (in that order) instead. - - Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. - - If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments will have different mechanisms. - - The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. - - [jasmine-gem]: http://github.com/pivotal/jasmine-gem - */ - -(function() { - var jasmineRequire = window.jasmineRequire || require('./jasmine.js'); - - /** - * ## Require & Instantiate - * - * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. - */ - var jasmine = jasmineRequire.core(jasmineRequire), - global = jasmine.getGlobal(); - global.jasmine = jasmine; - - /** - * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. - */ - jasmineRequire.html(jasmine); - - /** - * Create the Jasmine environment. This is used to run all specs in a project. - */ - var env = jasmine.getEnv(); - - /** - * ## The Global Interface - * - * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. - */ - var jasmineInterface = jasmineRequire.interface(jasmine, env); - - /** - * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. - */ - extend(global, jasmineInterface); - - /** - * ## Runner Parameters - * - * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. - */ - - var queryString = new jasmine.QueryString({ - getWindowLocation: function() { return window.location; } - }); - - var filterSpecs = !!queryString.getParam("spec"); - - var config = { - failFast: queryString.getParam("failFast"), - oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"), - hideDisabled: queryString.getParam("hideDisabled") - }; - - var random = queryString.getParam("random"); - - if (random !== undefined && random !== "") { - config.random = random; - } - - var seed = queryString.getParam("seed"); - if (seed) { - config.seed = seed; - } - - /** - * ## Reporters - * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). - */ - var htmlReporter = new jasmine.HtmlReporter({ - env: env, - navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, - addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, - getContainer: function() { return document.body; }, - createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); }, - timer: new jasmine.Timer(), - filterSpecs: filterSpecs - }); - - /** - * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. - */ - env.addReporter(jasmineInterface.jsApiReporter); - env.addReporter(htmlReporter); - - /** - * Filter which specs will be run by matching the start of the full name against the `spec` query param. - */ - var specFilter = new jasmine.HtmlSpecFilter({ - filterString: function() { return queryString.getParam("spec"); } - }); - - config.specFilter = function(spec) { - return specFilter.matches(spec.getFullName()); - }; - - env.configure(config); - - /** - * ## Execution - * - * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. - */ - var currentWindowOnload = window.onload; - - window.onload = function() { - if (currentWindowOnload) { - currentWindowOnload(); - } - htmlReporter.initialize(); - env.execute(); - }; - - /** - * Helper function for readability above. - */ - function extend(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; - } - - env.deprecated('boot.js is deprecated. Please use boot0.js and boot1.js instead.', - { ignoreRunnable: true }); -}()); diff --git a/spec/npmPackage/npmPackageSpec.js b/spec/npmPackage/npmPackageSpec.js index 4e1ec86d..be141dde 100644 --- a/spec/npmPackage/npmPackageSpec.js +++ b/spec/npmPackage/npmPackageSpec.js @@ -82,10 +82,6 @@ describe('npm package', function() { expect(fileName).toExistInPath(packagedCore.files.bootDir); }); - // For backwards compatibility, boot.js should be packaged even though - // it is no longer in bootFiles. - expect('boot.js').toExistInPath(packagedCore.files.bootDir); - var packagedCore = this.packagedCore; this.packagedCore.files.nodeBootFiles.forEach(function(fileName) { expect(fileName).toExistInPath(packagedCore.files.bootDir); From e9bddc7a0631f752a3377a84ce8b290b189914c9 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 26 Jul 2021 19:04:43 -0700 Subject: [PATCH 18/71] Removed obsolete timing function hacks from boot1.js --- lib/jasmine-core/boot/boot1.js | 8 -------- lib/jasmine-core/boot1.js | 8 -------- 2 files changed, 16 deletions(-) diff --git a/lib/jasmine-core/boot/boot1.js b/lib/jasmine-core/boot/boot1.js index 5df04bb8..60663cde 100644 --- a/lib/jasmine-core/boot/boot1.js +++ b/lib/jasmine-core/boot/boot1.js @@ -77,14 +77,6 @@ env.configure(config); - /** - * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. - */ - window.setTimeout = window.setTimeout; - window.setInterval = window.setInterval; - window.clearTimeout = window.clearTimeout; - window.clearInterval = window.clearInterval; - /** * ## Execution * diff --git a/lib/jasmine-core/boot1.js b/lib/jasmine-core/boot1.js index 6c8748ea..5a6a5647 100644 --- a/lib/jasmine-core/boot1.js +++ b/lib/jasmine-core/boot1.js @@ -99,14 +99,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. env.configure(config); - /** - * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. - */ - window.setTimeout = window.setTimeout; - window.setInterval = window.setInterval; - window.clearTimeout = window.clearTimeout; - window.clearInterval = window.clearInterval; - /** * ## Execution * From 09d2ce9bc9ab2813f017f375fd108260044c6a89 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 27 Jul 2021 17:53:09 -0700 Subject: [PATCH 19/71] Removed more code that supported browsers we no longer run on --- lib/jasmine-core/jasmine.js | 14 +------------- spec/core/PrettyPrintSpec.js | 16 +++++++--------- .../asymmetric_equality/ObjectContainingSpec.js | 11 +---------- src/core/asymmetric_equality/ObjectContaining.js | 14 +------------- 4 files changed, 10 insertions(+), 45 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6870c59b..088972b7 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -2577,18 +2577,6 @@ getJasmineRequireObj().ObjectContaining = function(j$) { this.sample = sample; } - function getPrototype(obj) { - if (Object.getPrototypeOf) { - return Object.getPrototypeOf(obj); - } - - if (obj.constructor.prototype == obj) { - return null; - } - - return obj.constructor.prototype; - } - function hasProperty(obj, property) { if (!obj || typeof obj !== 'object') { return false; @@ -2598,7 +2586,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) { return true; } - return hasProperty(getPrototype(obj), property); + return hasProperty(Object.getPrototypeOf(obj), property); } ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) { diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index 2fa0a74d..ed239191 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -268,15 +268,13 @@ describe('PrettyPrinter', function() { }); it('should stringify immutable circular objects', function() { - if (Object.freeze) { - var pp = jasmineUnderTest.makePrettyPrinter(); - var frozenObject = { foo: { bar: 'baz' } }; - frozenObject.circular = frozenObject; - frozenObject = Object.freeze(frozenObject); - expect(pp(frozenObject)).toEqual( - "Object({ foo: Object({ bar: 'baz' }), circular: })" - ); - } + var pp = jasmineUnderTest.makePrettyPrinter(); + var frozenObject = { foo: { bar: 'baz' } }; + frozenObject.circular = frozenObject; + frozenObject = Object.freeze(frozenObject); + expect(pp(frozenObject)).toEqual( + "Object({ foo: Object({ bar: 'baz' }), circular: })" + ); }); it('should stringify RegExp objects properly', function() { diff --git a/spec/core/asymmetric_equality/ObjectContainingSpec.js b/spec/core/asymmetric_equality/ObjectContainingSpec.js index 07b86148..07772047 100644 --- a/spec/core/asymmetric_equality/ObjectContainingSpec.js +++ b/spec/core/asymmetric_equality/ObjectContainingSpec.js @@ -110,16 +110,7 @@ describe('ObjectContaining', function() { var matchersUtil = new jasmineUnderTest.MatchersUtil(); var prototypeObject = { foo: 'fooVal' }; - var obj; - - if (Object.create) { - obj = Object.create(prototypeObject); - } else { - function Foo() {} - Foo.prototype = prototypeObject; - Foo.prototype.constructor = Foo; - obj = new Foo(); - } + var obj = Object.create(prototypeObject); expect(containing.asymmetricMatch(obj, matchersUtil)).toBe(true); }); diff --git a/src/core/asymmetric_equality/ObjectContaining.js b/src/core/asymmetric_equality/ObjectContaining.js index 5e473033..249716c7 100644 --- a/src/core/asymmetric_equality/ObjectContaining.js +++ b/src/core/asymmetric_equality/ObjectContaining.js @@ -3,18 +3,6 @@ getJasmineRequireObj().ObjectContaining = function(j$) { this.sample = sample; } - function getPrototype(obj) { - if (Object.getPrototypeOf) { - return Object.getPrototypeOf(obj); - } - - if (obj.constructor.prototype == obj) { - return null; - } - - return obj.constructor.prototype; - } - function hasProperty(obj, property) { if (!obj || typeof obj !== 'object') { return false; @@ -24,7 +12,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) { return true; } - return hasProperty(getPrototype(obj), property); + return hasProperty(Object.getPrototypeOf(obj), property); } ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) { From 13dfcacbb0d1a7825eeea7f66cd858bd77996260 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 30 Jul 2021 17:36:50 -0700 Subject: [PATCH 20/71] Remove access to non-public properties of suites and specs returned by describe, it, etc. [#179064612] --- lib/jasmine-core/jasmine.js | 182 ++++++++++++++++++++---------------- spec/core/EnvSpec.js | 77 ++++++++++++++- src/core/Env.js | 21 +++-- src/core/Spec.js | 61 ++++++------ src/core/Suite.js | 100 +++++++++++--------- 5 files changed, 272 insertions(+), 169 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 023dec91..fef0a9e6 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -663,12 +663,6 @@ getJasmineRequireObj().Spec = function(j$) { 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} - */ this.id = attrs.id; this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; @@ -898,34 +892,43 @@ getJasmineRequireObj().Spec = function(j$) { * @interface Spec * @see Configuration#specFilter */ - Spec.prototype.buildMetadata = function() { - return { - /** - * The description passed to the {@link it} that created this spec. - * @name Spec#description - * @readonly - * @type {string} - */ - description: this.description, + Object.defineProperty(Spec.prototype, 'metadata', { + get: function() { + if (!this.metadata_) { + this.metadata_ = { + /** + * The unique ID of this spec. + * @name Spec#id + * @readonly + * @type {string} + */ + id: this.id, - /** - * The full description including all ancestors of this spec. - * @name Spec#getFullName - * @function - * @returns {string} - */ - getFullName: this.getFullName.bind(this) - }; - }; + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + } + + return this.metadata_; + } + }); return Spec; }; -if (typeof window == void 0 && typeof exports == 'object') { - /* globals exports */ - exports.Spec = jasmineRequire.Spec; -} - /*jshint bitwise: false*/ getJasmineRequireObj().Order = function() { @@ -1523,7 +1526,7 @@ getJasmineRequireObj().Env = function(j$) { * @return {Suite} the root suite */ this.topSuite = function() { - return topSuite.buildMetadata(null); + return topSuite.metadata; }; /** @@ -1906,7 +1909,7 @@ getJasmineRequireObj().Env = function(j$) { if (suite.parentSuite && !suite.children.length) { throw new Error('describe with no children (describe() or it())'); } - return suite; + return suite.metadata; }; this.xdescribe = function(description, specDefinitions) { @@ -1915,7 +1918,7 @@ getJasmineRequireObj().Env = function(j$) { var suite = suiteFactory(description); suite.pend(); addSpecsToSuite(suite, specDefinitions); - return suite; + return suite.metadata; }; var focusedRunnables = []; @@ -1930,7 +1933,7 @@ getJasmineRequireObj().Env = function(j$) { unfocusAncestor(); addSpecsToSuite(suite, specDefinitions); - return suite; + return suite.metadata; }; function addSpecsToSuite(suite, specDefinitions) { @@ -2020,7 +2023,7 @@ getJasmineRequireObj().Env = function(j$) { } }; - this.it = function(description, fn, timeout) { + this.it_ = function(description, fn, timeout) { ensureIsNotNested('it'); // it() sometimes doesn't have a fn argument, so only check the type if // it's given. @@ -2036,6 +2039,11 @@ getJasmineRequireObj().Env = function(j$) { return spec; }; + this.it = function(description, fn, timeout) { + const spec = this.it_(description, fn, timeout); + return spec.metadata; + }; + this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); // xit(), like it(), doesn't always have a fn argument, so only check the @@ -2043,9 +2051,9 @@ getJasmineRequireObj().Env = function(j$) { if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } - var spec = this.it.apply(this, arguments); + var spec = this.it_.apply(this, arguments); spec.pend('Temporarily disabled with xit'); - return spec; + return spec.metadata; }; this.fit = function(description, fn, timeout) { @@ -2055,7 +2063,7 @@ getJasmineRequireObj().Env = function(j$) { currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); unfocusAncestor(); - return spec; + return spec.metadata; }; /** @@ -9045,12 +9053,6 @@ getJasmineRequireObj().StackTrace = function(j$) { getJasmineRequireObj().Suite = function(j$) { function Suite(attrs) { this.env = attrs.env; - /** - * The unique ID of this suite. - * @name Suite#id - * @readonly - * @type {string} - */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; @@ -9235,49 +9237,68 @@ getJasmineRequireObj().Suite = function(j$) { ); }; - Suite.prototype.buildMetadata = function(parentMetadata) { + Object.defineProperty(Suite.prototype, 'metadata', { + get: function() { + if (!this.metadata_) { + this.metadata_ = new SuiteMetadata(this); + } + + return this.metadata_; + } + }); + + /** + * @interface Suite + * @see Env#topSuite + */ + function SuiteMetadata(suite) { + this.suite_ = suite; /** - * @interface Suite - * @see Env#topSuite + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} */ - var result = { - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ - parentSuite: parentMetadata, - - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - */ - description: this.description, - - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - */ - getFullName: this.getFullName.bind(this) - }; + this.id = suite.id; /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} */ - result.children = this.children.map(function(child) { - return child.buildMetadata(result); - }); + this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; - return result; + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + */ + this.description = suite.description; + } + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + */ + SuiteMetadata.prototype.getFullName = function() { + return this.suite_.getFullName(); }; + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + */ + Object.defineProperty(SuiteMetadata.prototype, 'children', { + get: function() { + return this.suite_.children.map(child => child.metadata); + } + }); + function isFailure(args) { return !args[0]; } @@ -9285,11 +9306,6 @@ getJasmineRequireObj().Suite = function(j$) { return Suite; }; -if (typeof window == void 0 && typeof exports == 'object') { - /* globals exports */ - exports.Suite = jasmineRequire.Suite; -} - getJasmineRequireObj().Timer = function() { var defaultNow = (function(Date) { return function() { diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index be10480e..ae790a9c 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -90,7 +90,7 @@ describe('Env', function() { it('can configure specs to throw errors on expectation failures', function() { env.configure({ oneFailurePerSpec: true }); - spyOn(jasmineUnderTest, 'Spec'); + spyOn(jasmineUnderTest, 'Spec').and.callThrough(); env.it('foo', function() {}); expect(jasmineUnderTest.Spec).toHaveBeenCalledWith( jasmine.objectContaining({ @@ -162,7 +162,7 @@ describe('Env', function() { }); it('defaults to multiple failures for specs', function() { - spyOn(jasmineUnderTest, 'Spec'); + spyOn(jasmineUnderTest, 'Spec').and.callThrough(); env.it('bar', function() {}); expect(jasmineUnderTest.Spec).toHaveBeenCalledWith( jasmine.objectContaining({ @@ -181,7 +181,40 @@ describe('Env', function() { ); }); + function behavesLikeDescribe(methodName) { + it('returns a suite metadata object', function() { + let innerSuite; + let spec; + const suite = env.describe('outer suite', function() { + innerSuite = env.describe('inner suite', function() { + spec = env.it('a spec'); + }); + }); + + expect(suite.parentSuite).toEqual( + jasmine.objectContaining({ + description: 'Jasmine__TopLevel__Suite' + }) + ); + expect(suite.parentSuite.pend).toBeUndefined(); + expect(suite.pend).toBeUndefined(); + expect(suite.description).toEqual('outer suite'); + expect(suite.getFullName()).toEqual('outer suite'); + expect(suite.id).toBeInstanceOf(String); + expect(suite.id).not.toEqual(''); + expect(suite.children.length).toEqual(1); + expect(suite.children[0]).toBe(innerSuite); + expect(innerSuite.children.length).toEqual(1); + expect(innerSuite.children[0]).toBe(spec); + expect(innerSuite.getFullName()).toEqual('outer suite inner suite'); + expect(innerSuite.parentSuite).toBe(suite); + expect(spec.getFullName()).toEqual('outer suite inner suite a spec'); + }); + } + describe('#describe', function() { + behavesLikeDescribe('describe'); + it('throws an error when given arguments', function() { expect(function() { env.describe('done method', function(done) {}); @@ -232,7 +265,41 @@ describe('Env', function() { }); }); + describe('#fdescribe', function() { + behavesLikeDescribe('fdescribe'); + }); + + describe('xdescribe', function() { + behavesLikeDescribe('xdescribe'); + }); + + function behavesLikeIt(methodName) { + it('returns a spec metadata object', function() { + let spec; + + env.describe('a suite', function() { + spec = env[methodName]('a spec', function() {}); + }); + + expect(spec.description) + .withContext('description') + .toEqual('a spec'); + expect(spec.getFullName()) + .withContext('getFullName') + .toEqual('a suite a spec'); + expect(spec.id) + .withContext('id') + .toBeInstanceOf(String); + expect(spec.id) + .withContext('id') + .not.toEqual(''); + expect(spec.pend).toBeFalsy(); + }); + } + describe('#it', function() { + behavesLikeIt('it'); + it('throws an error when it receives a non-fn argument', function() { expect(function() { env.it('undefined arg', null); @@ -255,9 +322,11 @@ describe('Env', function() { }); describe('#xit', function() { + behavesLikeIt('xit'); + it('calls spec.pend with "Temporarily disabled with xit"', function() { var pendSpy = jasmine.createSpy(); - spyOn(env, 'it').and.returnValue({ + spyOn(env, 'it_').and.returnValue({ pend: pendSpy }); env.xit('foo', function() {}); @@ -286,6 +355,8 @@ describe('Env', function() { }); describe('#fit', function() { + behavesLikeIt('fit'); + it('throws an error when it receives a non-fn argument', function() { expect(function() { env.fit('undefined arg', undefined); diff --git a/src/core/Env.js b/src/core/Env.js index ef26385a..d019fc4b 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -549,7 +549,7 @@ getJasmineRequireObj().Env = function(j$) { * @return {Suite} the root suite */ this.topSuite = function() { - return topSuite.buildMetadata(null); + return topSuite.metadata; }; /** @@ -932,7 +932,7 @@ getJasmineRequireObj().Env = function(j$) { if (suite.parentSuite && !suite.children.length) { throw new Error('describe with no children (describe() or it())'); } - return suite; + return suite.metadata; }; this.xdescribe = function(description, specDefinitions) { @@ -941,7 +941,7 @@ getJasmineRequireObj().Env = function(j$) { var suite = suiteFactory(description); suite.pend(); addSpecsToSuite(suite, specDefinitions); - return suite; + return suite.metadata; }; var focusedRunnables = []; @@ -956,7 +956,7 @@ getJasmineRequireObj().Env = function(j$) { unfocusAncestor(); addSpecsToSuite(suite, specDefinitions); - return suite; + return suite.metadata; }; function addSpecsToSuite(suite, specDefinitions) { @@ -1046,7 +1046,7 @@ getJasmineRequireObj().Env = function(j$) { } }; - this.it = function(description, fn, timeout) { + this.it_ = function(description, fn, timeout) { ensureIsNotNested('it'); // it() sometimes doesn't have a fn argument, so only check the type if // it's given. @@ -1062,6 +1062,11 @@ getJasmineRequireObj().Env = function(j$) { return spec; }; + this.it = function(description, fn, timeout) { + const spec = this.it_(description, fn, timeout); + return spec.metadata; + }; + this.xit = function(description, fn, timeout) { ensureIsNotNested('xit'); // xit(), like it(), doesn't always have a fn argument, so only check the @@ -1069,9 +1074,9 @@ getJasmineRequireObj().Env = function(j$) { if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunctionOrAsync(fn, 'xit'); } - var spec = this.it.apply(this, arguments); + var spec = this.it_.apply(this, arguments); spec.pend('Temporarily disabled with xit'); - return spec; + return spec.metadata; }; this.fit = function(description, fn, timeout) { @@ -1081,7 +1086,7 @@ getJasmineRequireObj().Env = function(j$) { currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); unfocusAncestor(); - return spec; + return spec.metadata; }; /** diff --git a/src/core/Spec.js b/src/core/Spec.js index 20ee9041..82d7e235 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -3,12 +3,6 @@ getJasmineRequireObj().Spec = function(j$) { 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} - */ this.id = attrs.id; this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; @@ -238,30 +232,39 @@ getJasmineRequireObj().Spec = function(j$) { * @interface Spec * @see Configuration#specFilter */ - Spec.prototype.buildMetadata = function() { - return { - /** - * The description passed to the {@link it} that created this spec. - * @name Spec#description - * @readonly - * @type {string} - */ - description: this.description, + Object.defineProperty(Spec.prototype, 'metadata', { + get: function() { + if (!this.metadata_) { + this.metadata_ = { + /** + * The unique ID of this spec. + * @name Spec#id + * @readonly + * @type {string} + */ + id: this.id, - /** - * The full description including all ancestors of this spec. - * @name Spec#getFullName - * @function - * @returns {string} - */ - getFullName: this.getFullName.bind(this) - }; - }; + /** + * The description passed to the {@link it} that created this spec. + * @name Spec#description + * @readonly + * @type {string} + */ + description: this.description, + + /** + * The full description including all ancestors of this spec. + * @name Spec#getFullName + * @function + * @returns {string} + */ + getFullName: this.getFullName.bind(this) + }; + } + + return this.metadata_; + } + }); return Spec; }; - -if (typeof window == void 0 && typeof exports == 'object') { - /* globals exports */ - exports.Spec = jasmineRequire.Spec; -} diff --git a/src/core/Suite.js b/src/core/Suite.js index 0403dc02..a15be857 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,12 +1,6 @@ getJasmineRequireObj().Suite = function(j$) { function Suite(attrs) { this.env = attrs.env; - /** - * The unique ID of this suite. - * @name Suite#id - * @readonly - * @type {string} - */ this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; @@ -191,57 +185,71 @@ getJasmineRequireObj().Suite = function(j$) { ); }; - Suite.prototype.buildMetadata = function(parentMetadata) { + Object.defineProperty(Suite.prototype, 'metadata', { + get: function() { + if (!this.metadata_) { + this.metadata_ = new SuiteMetadata(this); + } + + return this.metadata_; + } + }); + + /** + * @interface Suite + * @see Env#topSuite + */ + function SuiteMetadata(suite) { + this.suite_ = suite; /** - * @interface Suite - * @see Env#topSuite + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} */ - var result = { - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ - parentSuite: parentMetadata, - - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - */ - description: this.description, - - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - */ - getFullName: this.getFullName.bind(this) - }; + this.id = suite.id; /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} */ - result.children = this.children.map(function(child) { - return child.buildMetadata(result); - }); + this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; - return result; + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + */ + this.description = suite.description; + } + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + */ + SuiteMetadata.prototype.getFullName = function() { + return this.suite_.getFullName(); }; + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + */ + Object.defineProperty(SuiteMetadata.prototype, 'children', { + get: function() { + return this.suite_.children.map(child => child.metadata); + } + }); + function isFailure(args) { return !args[0]; } return Suite; }; - -if (typeof window == void 0 && typeof exports == 'object') { - /* globals exports */ - exports.Suite = jasmineRequire.Suite; -} From d8862aa583abf28a0a4ae61d6f2c1b51450a1447 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 31 Jul 2021 09:23:52 -0700 Subject: [PATCH 21/71] Removed the failFast and oneFailurePerSpec config properties --- lib/jasmine-core/boot/boot1.js | 4 +- lib/jasmine-core/boot1.js | 4 +- lib/jasmine-core/jasmine-html.js | 4 +- lib/jasmine-core/jasmine.js | 92 ++---------------------- spec/core/EnvSpec.js | 87 ---------------------- spec/core/integration/SpecRunningSpec.js | 17 +---- spec/html/HtmlReporterSpec.js | 17 +++-- src/core/Env.js | 92 ++---------------------- src/html/HtmlReporter.js | 4 +- 9 files changed, 35 insertions(+), 286 deletions(-) diff --git a/lib/jasmine-core/boot/boot1.js b/lib/jasmine-core/boot/boot1.js index f0a085e0..ce41a065 100644 --- a/lib/jasmine-core/boot/boot1.js +++ b/lib/jasmine-core/boot/boot1.js @@ -27,8 +27,8 @@ var filterSpecs = !!queryString.getParam("spec"); var config = { - stopOnSpecFailure: queryString.getParam("failFast"), - stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"), + stopOnSpecFailure: queryString.getParam("stopOnSpecFailure"), + stopSpecOnExpectationFailure: queryString.getParam("stopSpecOnExpectationFailure"), hideDisabled: queryString.getParam("hideDisabled") }; diff --git a/lib/jasmine-core/boot1.js b/lib/jasmine-core/boot1.js index 940bb087..152c8769 100644 --- a/lib/jasmine-core/boot1.js +++ b/lib/jasmine-core/boot1.js @@ -49,8 +49,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. var filterSpecs = !!queryString.getParam("spec"); var config = { - stopOnSpecFailure: queryString.getParam("failFast"), - stopSpecOnExpectationFailure: queryString.getParam("oneFailurePerSpec"), + stopOnSpecFailure: queryString.getParam("stopOnSpecFailure"), + stopSpecOnExpectationFailure: queryString.getParam("stopSpecOnExpectationFailure"), hideDisabled: queryString.getParam("hideDisabled") }; diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 2eb408cf..51f79786 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -571,7 +571,7 @@ jasmineRequire.HtmlReporter = function(j$) { var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); failFastCheckbox.checked = config.stopOnSpecFailure; failFastCheckbox.onclick = function() { - navigateWithNewParam('failFast', !config.stopOnSpecFailure); + navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure); }; var throwCheckbox = optionsMenuDom.querySelector( @@ -580,7 +580,7 @@ jasmineRequire.HtmlReporter = function(j$) { throwCheckbox.checked = config.stopSpecOnExpectationFailure; throwCheckbox.onclick = function() { navigateWithNewParam( - 'oneFailurePerSpec', + 'stopSpecOnExpectationFailure', !config.stopSpecOnExpectationFailure ); }; diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b0fff9fb..ee4a6534 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1036,15 +1036,6 @@ getJasmineRequireObj().Env = function(j$) { * @default null */ seed: null, - /** - * Whether to stop execution of the suite after the first spec failure - * @name Configuration#failFast - * @since 3.3.0 - * @type Boolean - * @default false - * @deprecated Use the `stopOnSpecFailure` config property instead. - */ - failFast: false, /** * Whether to stop execution of the suite after the first spec failure * @name Configuration#stopOnSpecFailure @@ -1063,15 +1054,6 @@ getJasmineRequireObj().Env = function(j$) { * @default false */ failSpecWithNoExpectations: false, - /** - * Whether to cause specs to only have one expectation failure. - * @name Configuration#oneFailurePerSpec - * @since 3.3.0 - * @type Boolean - * @default false - * @deprecated Use the `stopSpecOnExpectationFailure` config property instead. - */ - oneFailurePerSpec: false, /** * Whether to cause specs to only have one expectation failure. * @name Configuration#stopSpecOnExpectationFailure @@ -1180,7 +1162,9 @@ getJasmineRequireObj().Env = function(j$) { var booleanProps = [ 'random', 'failSpecWithNoExpectations', - 'hideDisabled' + 'hideDisabled', + 'stopOnSpecFailure', + 'stopSpecOnExpectationFailure' ]; booleanProps.forEach(function(prop) { @@ -1189,70 +1173,6 @@ getJasmineRequireObj().Env = function(j$) { } }); - if (typeof configuration.failFast !== 'undefined') { - // We can't unconditionally issue a warning here because then users who - // get the configuration from Jasmine, modify it, and pass it back would - // see the warning. - if (configuration.failFast !== config.failFast) { - this.deprecated( - 'The `failFast` config property is deprecated and will be removed ' + - 'in a future version of Jasmine. Please use `stopOnSpecFailure` ' + - 'instead.', - { ignoreRunnable: true } - ); - } - - if (typeof configuration.stopOnSpecFailure !== 'undefined') { - if (configuration.stopOnSpecFailure !== configuration.failFast) { - throw new Error( - 'stopOnSpecFailure and failFast are aliases for ' + - "each other. Don't set failFast if you also set stopOnSpecFailure." - ); - } - } - - config.failFast = configuration.failFast; - config.stopOnSpecFailure = configuration.failFast; - } else if (typeof configuration.stopOnSpecFailure !== 'undefined') { - config.failFast = configuration.stopOnSpecFailure; - config.stopOnSpecFailure = configuration.stopOnSpecFailure; - } - - if (typeof configuration.oneFailurePerSpec !== 'undefined') { - // We can't unconditionally issue a warning here because then users who - // get the configuration from Jasmine, modify it, and pass it back would - // see the warning. - if (configuration.oneFailurePerSpec !== config.oneFailurePerSpec) { - this.deprecated( - 'The `oneFailurePerSpec` config property is deprecated and will be ' + - 'removed in a future version of Jasmine. Please use ' + - '`stopSpecOnExpectationFailure` instead.', - { ignoreRunnable: true } - ); - } - - if (typeof configuration.stopSpecOnExpectationFailure !== 'undefined') { - if ( - configuration.stopSpecOnExpectationFailure !== - configuration.oneFailurePerSpec - ) { - throw new Error( - 'stopSpecOnExpectationFailure and oneFailurePerSpec are aliases for ' + - "each other. Don't set oneFailurePerSpec if you also set stopSpecOnExpectationFailure." - ); - } - } - - config.oneFailurePerSpec = configuration.oneFailurePerSpec; - config.stopSpecOnExpectationFailure = configuration.oneFailurePerSpec; - } else if ( - typeof configuration.stopSpecOnExpectationFailure !== 'undefined' - ) { - config.oneFailurePerSpec = configuration.stopSpecOnExpectationFailure; - config.stopSpecOnExpectationFailure = - configuration.stopSpecOnExpectationFailure; - } - if (configuration.specFilter) { config.specFilter = configuration.specFilter; } @@ -1969,7 +1889,7 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: config.oneFailurePerSpec + throwOnExpectationFailure: config.stopSpecOnExpectationFailure }); return suite; @@ -2080,7 +2000,7 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: config.oneFailurePerSpec, + throwOnExpectationFailure: config.stopSpecOnExpectationFailure, timer: new j$.Timer() }); return spec; @@ -2274,7 +2194,7 @@ getJasmineRequireObj().Env = function(j$) { error: error && error.message ? error : null }); - if (config.oneFailurePerSpec) { + if (config.stopSpecOnExpectationFailure) { throw new Error(message); } }; diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 514192fe..d6e5fb32 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -116,9 +116,7 @@ describe('Env', function() { var initialConfig = { random: true, seed: '123', - failFast: true, failSpecWithNoExpectations: true, - oneFailurePerSpec: true, stopSpecOnExpectationFailure: true, stopOnSpecFailure: true, hideDisabled: true @@ -128,9 +126,7 @@ describe('Env', function() { env.configure({ random: undefined, seed: undefined, - failFast: undefined, failSpecWithNoExpectations: undefined, - oneFailurePerSpec: undefined, stopSpecOnExpectationFailure: undefined, stopOnSpecFailure: undefined, hideDisabled: undefined @@ -141,89 +137,6 @@ describe('Env', function() { ); }); - it('sets stopOnSpecFailure when failFast is set, and vice versa', function() { - spyOn(env, 'deprecated'); - env.configure({ failFast: true }); - expect(env.configuration()).toEqual( - jasmine.objectContaining({ - failFast: true, - stopOnSpecFailure: true - }) - ); - - env.configure({ stopOnSpecFailure: false }); - expect(env.configuration()).toEqual( - jasmine.objectContaining({ - failFast: false, - stopOnSpecFailure: false - }) - ); - }); - - it('rejects a single call that sets stopOnSpecFailure and failFast to different values', function() { - spyOn(env, 'deprecated'); - expect(function() { - env.configure({ failFast: true, stopOnSpecFailure: false }); - }).toThrowError( - 'stopOnSpecFailure and failFast are aliases for each ' + - "other. Don't set failFast if you also set stopOnSpecFailure." - ); - }); - - it('deprecates the failFast config property', function() { - spyOn(env, 'deprecated'); - env.configure({ failFast: true }); - expect(env.deprecated).toHaveBeenCalledWith( - 'The `failFast` config property is deprecated and will be removed in a ' + - 'future version of Jasmine. Please use `stopOnSpecFailure` instead.', - { ignoreRunnable: true } - ); - }); - - it('sets stopSpecOnExpectationFailure when oneFailurePerSpec is set, and vice versa', function() { - spyOn(env, 'deprecated'); - env.configure({ oneFailurePerSpec: true }); - expect(env.configuration()).toEqual( - jasmine.objectContaining({ - oneFailurePerSpec: true, - stopSpecOnExpectationFailure: true - }) - ); - - env.configure({ stopSpecOnExpectationFailure: false }); - expect(env.configuration()).toEqual( - jasmine.objectContaining({ - oneFailurePerSpec: false, - stopSpecOnExpectationFailure: false - }) - ); - }); - - it('rejects a single call that sets stopSpecOnExpectationFailure and oneFailurePerSpec to different values', function() { - spyOn(env, 'deprecated'); - expect(function() { - env.configure({ - oneFailurePerSpec: true, - stopSpecOnExpectationFailure: false - }); - }).toThrowError( - 'stopSpecOnExpectationFailure and oneFailurePerSpec are ' + - "aliases for each other. Don't set oneFailurePerSpec if you also set " + - 'stopSpecOnExpectationFailure.' - ); - }); - - it('deprecates the oneFailurePerSpec config property', function() { - spyOn(env, 'deprecated'); - env.configure({ oneFailurePerSpec: true }); - expect(env.deprecated).toHaveBeenCalledWith( - 'The `oneFailurePerSpec` config property is deprecated and will be ' + - 'removed in a future version of Jasmine. Please use ' + - '`stopSpecOnExpectationFailure` instead.', - { ignoreRunnable: true } - ); - }); - describe('promise library', function() { it('can be configured without a custom library', function() { env.configure({}); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index e2a91b76..8033ceb5 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -886,7 +886,7 @@ describe('spec running', function() { }); }); - function behavesLikeStopOnSpecFailureIsOn(configureFn) { + describe('when stopOnSpecFailure is on', function() { it('does not run further specs when one fails', function(done) { var actions = [], config; @@ -905,25 +905,12 @@ describe('spec running', function() { }); env.configure({ random: false }); - configureFn(env); + env.configure({ stopOnSpecFailure: true }); env.execute(null, function() { expect(actions).toEqual(['fails']); done(); }); }); - } - - describe('when failFast is on', function() { - behavesLikeStopOnSpecFailureIsOn(function(env) { - spyOn(env, 'deprecated'); - env.configure({ failFast: true }); - }); - }); - - describe('when stopOnSpecFailure is on', function() { - behavesLikeStopOnSpecFailureIsOn(function(env) { - env.configure({ stopOnSpecFailure: true }); - }); }); }); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index d098fbc1..a79e9cef 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -818,7 +818,10 @@ describe('HtmlReporter', function() { var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); stopOnFailureUI.click(); - expect(navigationHandler).toHaveBeenCalledWith('failFast', true); + expect(navigationHandler).toHaveBeenCalledWith( + 'stopOnSpecFailure', + true + ); }); it('should navigate and turn the setting off', function() { @@ -847,7 +850,10 @@ describe('HtmlReporter', function() { var stopOnFailureUI = container.querySelector('.jasmine-fail-fast'); stopOnFailureUI.click(); - expect(navigationHandler).toHaveBeenCalledWith('failFast', false); + expect(navigationHandler).toHaveBeenCalledWith( + 'stopOnSpecFailure', + false + ); }); }); @@ -924,7 +930,10 @@ describe('HtmlReporter', function() { var throwingExpectationsUI = container.querySelector('.jasmine-throw'); throwingExpectationsUI.click(); - expect(navigateHandler).toHaveBeenCalledWith('oneFailurePerSpec', true); + expect(navigateHandler).toHaveBeenCalledWith( + 'stopSpecOnExpectationFailure', + true + ); }); it('should navigate and change the setting to off', function() { @@ -954,7 +963,7 @@ describe('HtmlReporter', function() { throwingExpectationsUI.click(); expect(navigateHandler).toHaveBeenCalledWith( - 'oneFailurePerSpec', + 'stopSpecOnExpectationFailure', false ); }); diff --git a/src/core/Env.js b/src/core/Env.js index 189f5abb..b16dabc8 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -59,15 +59,6 @@ getJasmineRequireObj().Env = function(j$) { * @default null */ seed: null, - /** - * Whether to stop execution of the suite after the first spec failure - * @name Configuration#failFast - * @since 3.3.0 - * @type Boolean - * @default false - * @deprecated Use the `stopOnSpecFailure` config property instead. - */ - failFast: false, /** * Whether to stop execution of the suite after the first spec failure * @name Configuration#stopOnSpecFailure @@ -86,15 +77,6 @@ getJasmineRequireObj().Env = function(j$) { * @default false */ failSpecWithNoExpectations: false, - /** - * Whether to cause specs to only have one expectation failure. - * @name Configuration#oneFailurePerSpec - * @since 3.3.0 - * @type Boolean - * @default false - * @deprecated Use the `stopSpecOnExpectationFailure` config property instead. - */ - oneFailurePerSpec: false, /** * Whether to cause specs to only have one expectation failure. * @name Configuration#stopSpecOnExpectationFailure @@ -203,7 +185,9 @@ getJasmineRequireObj().Env = function(j$) { var booleanProps = [ 'random', 'failSpecWithNoExpectations', - 'hideDisabled' + 'hideDisabled', + 'stopOnSpecFailure', + 'stopSpecOnExpectationFailure' ]; booleanProps.forEach(function(prop) { @@ -212,70 +196,6 @@ getJasmineRequireObj().Env = function(j$) { } }); - if (typeof configuration.failFast !== 'undefined') { - // We can't unconditionally issue a warning here because then users who - // get the configuration from Jasmine, modify it, and pass it back would - // see the warning. - if (configuration.failFast !== config.failFast) { - this.deprecated( - 'The `failFast` config property is deprecated and will be removed ' + - 'in a future version of Jasmine. Please use `stopOnSpecFailure` ' + - 'instead.', - { ignoreRunnable: true } - ); - } - - if (typeof configuration.stopOnSpecFailure !== 'undefined') { - if (configuration.stopOnSpecFailure !== configuration.failFast) { - throw new Error( - 'stopOnSpecFailure and failFast are aliases for ' + - "each other. Don't set failFast if you also set stopOnSpecFailure." - ); - } - } - - config.failFast = configuration.failFast; - config.stopOnSpecFailure = configuration.failFast; - } else if (typeof configuration.stopOnSpecFailure !== 'undefined') { - config.failFast = configuration.stopOnSpecFailure; - config.stopOnSpecFailure = configuration.stopOnSpecFailure; - } - - if (typeof configuration.oneFailurePerSpec !== 'undefined') { - // We can't unconditionally issue a warning here because then users who - // get the configuration from Jasmine, modify it, and pass it back would - // see the warning. - if (configuration.oneFailurePerSpec !== config.oneFailurePerSpec) { - this.deprecated( - 'The `oneFailurePerSpec` config property is deprecated and will be ' + - 'removed in a future version of Jasmine. Please use ' + - '`stopSpecOnExpectationFailure` instead.', - { ignoreRunnable: true } - ); - } - - if (typeof configuration.stopSpecOnExpectationFailure !== 'undefined') { - if ( - configuration.stopSpecOnExpectationFailure !== - configuration.oneFailurePerSpec - ) { - throw new Error( - 'stopSpecOnExpectationFailure and oneFailurePerSpec are aliases for ' + - "each other. Don't set oneFailurePerSpec if you also set stopSpecOnExpectationFailure." - ); - } - } - - config.oneFailurePerSpec = configuration.oneFailurePerSpec; - config.stopSpecOnExpectationFailure = configuration.oneFailurePerSpec; - } else if ( - typeof configuration.stopSpecOnExpectationFailure !== 'undefined' - ) { - config.oneFailurePerSpec = configuration.stopSpecOnExpectationFailure; - config.stopSpecOnExpectationFailure = - configuration.stopSpecOnExpectationFailure; - } - if (configuration.specFilter) { config.specFilter = configuration.specFilter; } @@ -992,7 +912,7 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: config.oneFailurePerSpec + throwOnExpectationFailure: config.stopSpecOnExpectationFailure }); return suite; @@ -1103,7 +1023,7 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: config.oneFailurePerSpec, + throwOnExpectationFailure: config.stopSpecOnExpectationFailure, timer: new j$.Timer() }); return spec; @@ -1297,7 +1217,7 @@ getJasmineRequireObj().Env = function(j$) { error: error && error.message ? error : null }); - if (config.oneFailurePerSpec) { + if (config.stopSpecOnExpectationFailure) { throw new Error(message); } }; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index ac5a4213..5cc4e86e 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -540,7 +540,7 @@ jasmineRequire.HtmlReporter = function(j$) { var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); failFastCheckbox.checked = config.stopOnSpecFailure; failFastCheckbox.onclick = function() { - navigateWithNewParam('failFast', !config.stopOnSpecFailure); + navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure); }; var throwCheckbox = optionsMenuDom.querySelector( @@ -549,7 +549,7 @@ jasmineRequire.HtmlReporter = function(j$) { throwCheckbox.checked = config.stopSpecOnExpectationFailure; throwCheckbox.onclick = function() { navigateWithNewParam( - 'oneFailurePerSpec', + 'stopSpecOnExpectationFailure', !config.stopSpecOnExpectationFailure ); }; From 37b9f8e420baf66c23f515ec99791ec9ac98e86d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 30 Aug 2021 18:53:13 -0700 Subject: [PATCH 22/71] Removed Ruby support [#179247162] --- .editorconfig | 10 +---- Gemfile | 2 - Gruntfile.js | 6 --- README.md | 3 -- RELEASE.md | 24 +++--------- Rakefile | 2 - grunt/tasks/version.js | 14 ------- jasmine-core.gemspec | 30 -------------- lib/jasmine-core.rb | 78 ------------------------------------- lib/jasmine-core/version.rb | 9 ----- 10 files changed, 6 insertions(+), 172 deletions(-) delete mode 100644 Gemfile delete mode 100644 Rakefile delete mode 100644 grunt/tasks/version.js delete mode 100644 jasmine-core.gemspec delete mode 100644 lib/jasmine-core.rb delete mode 100644 lib/jasmine-core/version.rb diff --git a/.editorconfig b/.editorconfig index 9582a3cc..12562f79 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,14 +3,6 @@ charset = utf-8 end_of_line = lf insert_final_newline = true -[*.{js, json, sh, yml, gemspec}] +[*.{js, json, sh, yml}] indent_style = space indent_size = 2 - -[{Rakefile, .jshintrc}] -indent_style = space -indent_size = 2 - -[*.{py}] -indent_style = space -indent_size = 4 diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 851fabc2..00000000 --- a/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gemspec diff --git a/Gruntfile.js b/Gruntfile.js index 14077d78..6d65e5e3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -16,12 +16,6 @@ module.exports = function(grunt) { grunt.registerTask('default', ['sass:dist', "cssUrlEmbed"]); - var version = require('./grunt/tasks/version.js'); - - grunt.registerTask('build:copyVersionToGem', - "Propagates the version from package.json to version.rb", - version.copyToGem); - grunt.registerTask('buildDistribution', 'Builds and lints jasmine.js, jasmine-html.js, jasmine.css', [ diff --git a/README.md b/README.md index 69d32a8b..ffad57c6 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,6 @@ For the Jasmine NPM module:
For the Jasmine browser runner:
[https://github.com/jasmine/jasmine-browser](https://github.com/jasmine/jasmine-browser). -For the Jasmine Ruby Gem:
-[https://github.com/jasmine/jasmine-gem](https://github.com/jasmine/jasmine-gem). - To install Jasmine standalone on your local box (where **_{#.#.#}_** below is substituted by the release number downloaded): * Download the standalone distribution for your desired release from the [releases page](https://github.com/jasmine/jasmine/releases). diff --git a/RELEASE.md b/RELEASE.md index 3f0029d3..6762af90 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -13,13 +13,14 @@ Please attempt to keep commits to `main` small, but cohesive. If a feature is co We attempt to stick to [Semantic Versioning](http://semver.org/). Most of the time, development should be against a new minor version - fixing bugs and adding new features that are backwards compatible. -The current version lives in the file `/package.json`. This version will be the version number that is currently released. When releasing a new version, update `package.json` with the new version and `grunt build:copyVersionToGem` to update the gem version number. - -This version is used by both `jasmine.js` and the `jasmine-core` Ruby gem. +The current version lives in the file `/package.json`. This version will be +copied to `jasmine.js` when the distribution is built. When releasing a new +version, update `package.json` with the new version and `npm run build` to +update the gem version number. Note that Jasmine should only use the "patch" version number in the following cases: -* Changes related to packaging for a specific platform (npm, gem, or pip). +* Changes related to packaging for a specific binding library (npm or browser-runner) * Fixes for regressions. When jasmine-core revs its major or minor version, the binding libraries should also rev to that version. @@ -31,7 +32,6 @@ When ready to release - specs are all green and the stories are done: 1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly. Include a list of supported environments. 1. Update the version in `package.json` 1. Run `npm run build`. -1. Copy version to the Ruby gem with `grunt build:copyVersionToGem` ### Commit and push core changes @@ -45,11 +45,6 @@ When ready to release - specs are all green and the stories are done: 1. Build the standalone distribution with `grunt buildStandaloneDist` 1. This will generate `dist/jasmine-standalone-.zip`, which you will upload later (see "Finally" below). -### Release the core Ruby gem - -1. __NOTE__: You will likely need to push a new jasmine gem with a dependent version right after this release. See below. -1. `rake release` - tags the repo with the version, builds the `jasmine-core` gem, pushes the gem to Rubygems.org. In order to release you will have to ensure you have rubygems creds locally. - ### Release the core NPM module 1. Run the tests on Windows. (CI only tests on Linux.) @@ -76,15 +71,6 @@ Probably only need to do this when releasing a minor version, and not a patch ve 1. Run the tests on Windows locally. 1. `grunt release `. (Note: This will publish the package by running `npm publish`.) -#### Gem - -1. Create release notes using Anchorman as above -1. Update the version number in `lib/jasmine/version.rb`. -1. Update the jasmine-core dependency version in `jasmine.gemspec`. -1. Commit and push. -1. Wait for Circle CI to go green again. -1. `rake release` - ### Finally For each of the above GitHub repos: diff --git a/Rakefile b/Rakefile deleted file mode 100644 index 2480d0e6..00000000 --- a/Rakefile +++ /dev/null @@ -1,2 +0,0 @@ -require "bundler" -Bundler::GemHelper.install_tasks diff --git a/grunt/tasks/version.js b/grunt/tasks/version.js deleted file mode 100644 index f8ff6a10..00000000 --- a/grunt/tasks/version.js +++ /dev/null @@ -1,14 +0,0 @@ -var grunt = require("grunt"); - -function gemLib(path) { return './lib/jasmine-core/' + path; } -function nodeToRuby(version) { return version.replace('-', '.'); } - -module.exports = { - copyToGem: function() { - var versionRb = grunt.template.process( - grunt.file.read("grunt/templates/version.rb.jst"), - { data: { jasmineVersion: nodeToRuby(global.jasmineVersion) }}); - - grunt.file.write(gemLib("version.rb"), versionRb); - } -}; diff --git a/jasmine-core.gemspec b/jasmine-core.gemspec deleted file mode 100644 index fece3c1c..00000000 --- a/jasmine-core.gemspec +++ /dev/null @@ -1,30 +0,0 @@ -# -*- encoding: utf-8 -*- -$:.push File.expand_path("../lib", __FILE__) -require "jasmine-core/version" - -Gem::Specification.new do |s| - s.name = "jasmine-core" - s.version = Jasmine::Core::VERSION - s.platform = Gem::Platform::RUBY - s.authors = ["Gregg Van Hove"] - s.summary = %q{JavaScript BDD framework} - s.description = <<~DESC - Test your JavaScript without any framework dependencies, in any environment, - and with a nice descriptive syntax. - - Jasmine for Ruby is deprecated. The direct replacment for the jasmine-core - gem is the jasmine-core NPM package. If you are also using the jasmine gem, - we recommend using the jasmine-browser-runner NPM package instead. It - supports all the same scenarios as the jasmine gem gem plus Webpacker. See - https://jasmine.github.io/setup/browser.html for setup instructions, and - https://github.com/jasmine/jasmine-gem/blob/main/release_notes/3.9.0.md - for other options. - DESC - s.email = %q{jasmine-js@googlegroups.com} - s.homepage = "http://jasmine.github.io" - s.license = "MIT" - - s.files = Dir.glob("./lib/**/*") - s.require_paths = ["lib"] - s.add_development_dependency "rake" -end diff --git a/lib/jasmine-core.rb b/lib/jasmine-core.rb deleted file mode 100644 index 55a03fba..00000000 --- a/lib/jasmine-core.rb +++ /dev/null @@ -1,78 +0,0 @@ -if ENV["SUPPRESS_JASMINE_DEPRECATION"].nil? - puts <<~END_DEPRECATION_MSG - The Jasmine Ruby gems are deprecated. There will be no further releases after - the end of the Jasmine 3.x series. We recommend that most users migrate to the - jasmine-browser-runner npm package, which is the direct replacement for the - jasmine gem. See for setup - instructions, including for Rails applications that use either Sprockets or - Webpacker. - - If jasmine-browser-runner doesn't meet your needs, one of these might: - - * The jasmine npm package to run specs in Node.js: - - * The standalone distribution to run specs in browsers with no additional - tools: - * The jasmine-core npm package if all you need is the Jasmine assets: - . This is the direct equivalent of the - jasmine-core Ruby gem. - - To prevent this message from appearing, set the SUPPRESS_JASMINE_DEPRECATION - environment variable. - - END_DEPRECATION_MSG -end - -module Jasmine - module Core - class << self - def path - File.join(File.dirname(__FILE__), "jasmine-core") - end - - def js_files - (["jasmine.js"] + Dir.glob(File.join(path, "*.js"))).map { |f| File.basename(f) }.uniq - boot_files - ["boot0.js", "boot1.js"] - node_boot_files - end - - SPEC_TYPES = ["core", "html", "node"] - - def core_spec_files - spec_files("core") - end - - def html_spec_files - spec_files("html") - end - - def node_spec_files - spec_files("node") - end - - def boot_files - ["boot0.js", "boot1.js"] - end - - def node_boot_files - ["node_boot.js"] - end - - def boot_dir - path - end - - def spec_files(type) - raise ArgumentError.new("Unrecognized spec type") unless SPEC_TYPES.include?(type) - (Dir.glob(File.join(path, "spec", type, "*.js"))).map { |f| File.join("spec", type, File.basename(f)) }.uniq - end - - def css_files - Dir.glob(File.join(path, "*.css")).map { |f| File.basename(f) } - end - - def images_dir - File.join(File.dirname(__FILE__), '../images') - end - - end - end -end diff --git a/lib/jasmine-core/version.rb b/lib/jasmine-core/version.rb deleted file mode 100644 index ccee40c5..00000000 --- a/lib/jasmine-core/version.rb +++ /dev/null @@ -1,9 +0,0 @@ -# -# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated -# by a grunt task when the standalone release is built. -# -module Jasmine - module Core - VERSION = "3.9.0" - end -end From d61800c5c8c634f53b9e28a1b27afe17080b08dd Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 30 Aug 2021 19:07:26 -0700 Subject: [PATCH 23/71] Removed support for custom promise libraries All supported platforms now provide promises, so there's no longer a need for Jasmine to be able to create them via a user-provided library. Jasmine can still consume non-native promises but will always use the built-in Promise object to create promises. [#179078103] --- lib/jasmine-core/jasmine.js | 80 ++++-------------------------------- spec/core/EnvSpec.js | 31 -------------- spec/core/SpySpec.js | 16 +------- spec/core/SpyStrategySpec.js | 52 +++-------------------- src/core/Env.js | 43 ++----------------- src/core/Spy.js | 11 +---- src/core/SpyFactory.js | 5 +-- src/core/SpyStrategy.js | 21 ---------- 8 files changed, 22 insertions(+), 237 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 406ce514..b0fda0da 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -989,7 +989,6 @@ getJasmineRequireObj().Env = function(j$) { var self = this; var global = options.global || j$.getGlobal(); - var customPromise; var totalSpecsDefined = 0; @@ -1183,27 +1182,6 @@ getJasmineRequireObj().Env = function(j$) { config.seed = configuration.seed; } - // Don't use hasOwnProperty to check for Promise existence because Promise - // can be initialized to undefined, either explicitly or by using the - // object returned from Env#configuration. In particular, Karma does this. - if (configuration.Promise) { - if ( - typeof configuration.Promise.resolve === 'function' && - typeof configuration.Promise.reject === 'function' - ) { - customPromise = configuration.Promise; - self.deprecated( - 'The `Promise` config property is deprecated. Future versions ' + - 'of Jasmine will create native promises even if the `Promise` ' + - 'config property is set. Please remove it.' - ); - } else { - throw new Error( - 'Custom promise library missing `resolve`/`reject` functions' - ); - } - } - if (configuration.hasOwnProperty('verboseDeprecations')) { config.verboseDeprecations = configuration.verboseDeprecations; deprecator.verboseDeprecations(config.verboseDeprecations); @@ -1696,25 +1674,15 @@ getJasmineRequireObj().Env = function(j$) { var jasmineTimer = new j$.Timer(); jasmineTimer.start(); - var Promise = customPromise || global.Promise; - - if (Promise) { - return new Promise(function(resolve) { - runAll(function() { - if (onComplete) { - onComplete(); - } - - resolve(); - }); - }); - } else { + return new Promise(function(resolve) { runAll(function() { if (onComplete) { onComplete(); } + + resolve(); }); - } + }); function runAll(done) { /** @@ -1830,9 +1798,6 @@ getJasmineRequireObj().Env = function(j$) { } return undefined; - }, - function getPromise() { - return customPromise || global.Promise; } ); @@ -8229,13 +8194,7 @@ getJasmineRequireObj().Spy = function(j$) { * @class Spy * @hideconstructor */ - function Spy( - name, - originalFn, - customStrategies, - defaultStrategyFn, - getPromise - ) { + function Spy(name, originalFn, customStrategies, defaultStrategyFn) { var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); @@ -8246,8 +8205,7 @@ getJasmineRequireObj().Spy = function(j$) { getSpy: function() { return wrapper; }, - customStrategies: customStrategies, - getPromise: getPromise + customStrategies: customStrategies }), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { @@ -8430,7 +8388,7 @@ getJasmineRequireObj().Spy = function(j$) { }; getJasmineRequireObj().SpyFactory = function(j$) { - function SpyFactory(getCustomStrategies, getDefaultStrategyFn, getPromise) { + function SpyFactory(getCustomStrategies, getDefaultStrategyFn) { var self = this; this.createSpy = function(name, originalFn) { @@ -8438,8 +8396,7 @@ getJasmineRequireObj().SpyFactory = function(j$) { name, originalFn, getCustomStrategies(), - getDefaultStrategyFn(), - getPromise + getDefaultStrategyFn() ); }; @@ -8791,24 +8748,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { } } - var getPromise = - typeof options.getPromise === 'function' - ? options.getPromise - : function() {}; - - var requirePromise = function(name) { - var Promise = getPromise(); - - if (!Promise) { - throw new Error( - name + - ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' - ); - } - - return Promise; - }; - /** * Tell the spy to return a promise resolving to the specified value when invoked. * @name SpyStrategy#resolveTo @@ -8817,7 +8756,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { * @param {*} value The value to return. */ this.resolveTo = function(value) { - var Promise = requirePromise('resolveTo'); self.plan = function() { return Promise.resolve(value); }; @@ -8832,8 +8770,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { * @param {*} value The value to return. */ this.rejectWith = function(value) { - var Promise = requirePromise('rejectWith'); - self.plan = function() { return Promise.reject(value); }; diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 34e8bb49..c90d7399 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -137,37 +137,6 @@ describe('Env', function() { ); }); - describe('promise library', function() { - it('can be configured without a custom library', function() { - env.configure({}); - env.configure({ Promise: undefined }); - }); - - it('can be configured with a custom library', function() { - spyOn(env, 'deprecated'); - var myLibrary = { - resolve: jasmine.createSpy(), - reject: jasmine.createSpy() - }; - env.configure({ Promise: myLibrary }); - expect(env.deprecated).toHaveBeenCalledWith( - 'The `Promise` config property is deprecated. Future versions of ' + - 'Jasmine will create native promises even if the `Promise` config ' + - 'property is set. Please remove it.' - ); - }); - - it('cannot be configured with an invalid promise library', function() { - var myLibrary = {}; - - expect(function() { - env.configure({ Promise: myLibrary }); - }).toThrowError( - 'Custom promise library missing `resolve`/`reject` functions' - ); - }); - }); - it('defaults to multiple failures for specs', function() { spyOn(jasmineUnderTest, 'Spec').and.callThrough(); env.it('bar', function() {}); diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 6a8f2e7e..6271c900 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -248,7 +248,7 @@ describe('Spies', function() { }); describe('any promise-based strategy', function() { - it('works with global Promise library when available', function(done) { + it('works with global Promise library', function(done) { var spy = env.createSpy('foo').and.resolveTo(42); spy() .then(function(result) { @@ -257,20 +257,6 @@ describe('Spies', function() { }) .catch(done.fail); }); - - it('works with a custom Promise library', function() { - var customPromise = { - resolve: jasmine.createSpy(), - reject: jasmine.createSpy() - }; - customPromise.resolve.and.returnValue('resolved'); - spyOn(env, 'deprecated'); - env.configure({ Promise: customPromise }); - - var spy = env.createSpy('foo').and.resolveTo(42); - expect(spy()).toEqual('resolved'); - expect(customPromise.resolve).toHaveBeenCalledWith(42); - }); }); describe('when withArgs is used without a base strategy', function() { diff --git a/spec/core/SpyStrategySpec.js b/spec/core/SpyStrategySpec.js index abd7eb39..f8f96920 100644 --- a/spec/core/SpyStrategySpec.js +++ b/spec/core/SpyStrategySpec.js @@ -131,12 +131,8 @@ describe('SpyStrategy', function() { describe('#resolveTo', function() { it('allows a resolved promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), - getPromise = function() { - return Promise; - }, spyStrategy = new jasmineUnderTest.SpyStrategy({ - fn: originalFn, - getPromise: getPromise + fn: originalFn }); spyStrategy.resolveTo(37); @@ -151,12 +147,8 @@ describe('SpyStrategy', function() { it('allows an empty resolved promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), - getPromise = function() { - return Promise; - }, spyStrategy = new jasmineUnderTest.SpyStrategy({ - fn: originalFn, - getPromise: getPromise + fn: originalFn }); spyStrategy.resolveTo(); @@ -168,28 +160,13 @@ describe('SpyStrategy', function() { }) .catch(done.fail); }); - - it('fails if promises are not available', function() { - var originalFn = jasmine.createSpy('original'), - spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); - - expect(function() { - spyStrategy.resolveTo(37); - }).toThrowError( - 'resolveTo requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' - ); - }); }); describe('#rejectWith', function() { it('allows a rejected promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), - getPromise = function() { - return Promise; - }, spyStrategy = new jasmineUnderTest.SpyStrategy({ - fn: originalFn, - getPromise: getPromise + fn: originalFn }); spyStrategy.rejectWith(new Error('oops')); @@ -205,12 +182,8 @@ describe('SpyStrategy', function() { it('allows an empty rejected promise to be returned', function(done) { var originalFn = jasmine.createSpy('original'), - getPromise = function() { - return Promise; - }, spyStrategy = new jasmineUnderTest.SpyStrategy({ - fn: originalFn, - getPromise: getPromise + fn: originalFn }); spyStrategy.rejectWith(); @@ -226,12 +199,8 @@ describe('SpyStrategy', function() { it('allows a non-Error to be rejected', function(done) { var originalFn = jasmine.createSpy('original'), - getPromise = function() { - return Promise; - }, spyStrategy = new jasmineUnderTest.SpyStrategy({ - fn: originalFn, - getPromise: getPromise + fn: originalFn }); spyStrategy.rejectWith('oops'); @@ -244,17 +213,6 @@ describe('SpyStrategy', function() { }) .catch(done.fail); }); - - it('fails if promises are not available', function() { - var originalFn = jasmine.createSpy('original'), - spyStrategy = new jasmineUnderTest.SpyStrategy({ fn: originalFn }); - - expect(function() { - spyStrategy.rejectWith(new Error('oops')); - }).toThrowError( - 'rejectWith requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' - ); - }); }); it('allows a custom strategy to be used', function() { diff --git a/src/core/Env.js b/src/core/Env.js index 13274dfa..8defeec5 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -12,7 +12,6 @@ getJasmineRequireObj().Env = function(j$) { var self = this; var global = options.global || j$.getGlobal(); - var customPromise; var totalSpecsDefined = 0; @@ -206,27 +205,6 @@ getJasmineRequireObj().Env = function(j$) { config.seed = configuration.seed; } - // Don't use hasOwnProperty to check for Promise existence because Promise - // can be initialized to undefined, either explicitly or by using the - // object returned from Env#configuration. In particular, Karma does this. - if (configuration.Promise) { - if ( - typeof configuration.Promise.resolve === 'function' && - typeof configuration.Promise.reject === 'function' - ) { - customPromise = configuration.Promise; - self.deprecated( - 'The `Promise` config property is deprecated. Future versions ' + - 'of Jasmine will create native promises even if the `Promise` ' + - 'config property is set. Please remove it.' - ); - } else { - throw new Error( - 'Custom promise library missing `resolve`/`reject` functions' - ); - } - } - if (configuration.hasOwnProperty('verboseDeprecations')) { config.verboseDeprecations = configuration.verboseDeprecations; deprecator.verboseDeprecations(config.verboseDeprecations); @@ -719,25 +697,15 @@ getJasmineRequireObj().Env = function(j$) { var jasmineTimer = new j$.Timer(); jasmineTimer.start(); - var Promise = customPromise || global.Promise; - - if (Promise) { - return new Promise(function(resolve) { - runAll(function() { - if (onComplete) { - onComplete(); - } - - resolve(); - }); - }); - } else { + return new Promise(function(resolve) { runAll(function() { if (onComplete) { onComplete(); } + + resolve(); }); - } + }); function runAll(done) { /** @@ -853,9 +821,6 @@ getJasmineRequireObj().Env = function(j$) { } return undefined; - }, - function getPromise() { - return customPromise || global.Promise; } ); diff --git a/src/core/Spy.js b/src/core/Spy.js index 101725a9..7b7e422b 100644 --- a/src/core/Spy.js +++ b/src/core/Spy.js @@ -19,13 +19,7 @@ getJasmineRequireObj().Spy = function(j$) { * @class Spy * @hideconstructor */ - function Spy( - name, - originalFn, - customStrategies, - defaultStrategyFn, - getPromise - ) { + function Spy(name, originalFn, customStrategies, defaultStrategyFn) { var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); @@ -36,8 +30,7 @@ getJasmineRequireObj().Spy = function(j$) { getSpy: function() { return wrapper; }, - customStrategies: customStrategies, - getPromise: getPromise + customStrategies: customStrategies }), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { diff --git a/src/core/SpyFactory.js b/src/core/SpyFactory.js index 0f29a3b1..808ec647 100644 --- a/src/core/SpyFactory.js +++ b/src/core/SpyFactory.js @@ -1,5 +1,5 @@ getJasmineRequireObj().SpyFactory = function(j$) { - function SpyFactory(getCustomStrategies, getDefaultStrategyFn, getPromise) { + function SpyFactory(getCustomStrategies, getDefaultStrategyFn) { var self = this; this.createSpy = function(name, originalFn) { @@ -7,8 +7,7 @@ getJasmineRequireObj().SpyFactory = function(j$) { name, originalFn, getCustomStrategies(), - getDefaultStrategyFn(), - getPromise + getDefaultStrategyFn() ); }; diff --git a/src/core/SpyStrategy.js b/src/core/SpyStrategy.js index 382164b6..c4334611 100644 --- a/src/core/SpyStrategy.js +++ b/src/core/SpyStrategy.js @@ -27,24 +27,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { } } - var getPromise = - typeof options.getPromise === 'function' - ? options.getPromise - : function() {}; - - var requirePromise = function(name) { - var Promise = getPromise(); - - if (!Promise) { - throw new Error( - name + - ' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`' - ); - } - - return Promise; - }; - /** * Tell the spy to return a promise resolving to the specified value when invoked. * @name SpyStrategy#resolveTo @@ -53,7 +35,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { * @param {*} value The value to return. */ this.resolveTo = function(value) { - var Promise = requirePromise('resolveTo'); self.plan = function() { return Promise.resolve(value); }; @@ -68,8 +49,6 @@ getJasmineRequireObj().SpyStrategy = function(j$) { * @param {*} value The value to return. */ this.rejectWith = function(value) { - var Promise = requirePromise('rejectWith'); - self.plan = function() { return Promise.reject(value); }; From 6603ed7ddcd4c2e699c0e3a0c737f48b476f8986 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 3 Sep 2021 15:40:41 -0700 Subject: [PATCH 24/71] Don't distribute boot src files [#179017951] --- .github/CONTRIBUTING.md | 1 + grunt/config/compress.js | 2 +- grunt/config/concat.js | 6 +++--- spec/support/jasmine-browser.js | 3 ++- {lib/jasmine-core => src}/boot/boot0.js | 0 {lib/jasmine-core => src}/boot/boot1.js | 0 {lib/jasmine-core => src}/boot/node_boot.js | 0 7 files changed, 7 insertions(+), 5 deletions(-) rename {lib/jasmine-core => src}/boot/boot0.js (100%) rename {lib/jasmine-core => src}/boot/boot1.js (100%) rename {lib/jasmine-core => src}/boot/node_boot.js (100%) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1210ec89..271dae5b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -38,6 +38,7 @@ Once you've pushed a feature branch to your forked repo, you're ready to open a * `/src` contains all of the source files * `/src/core` - generic source files * `/src/html` - browser-specific files + * `/src/boot` - sources for boot files (see below) * `/spec` contains all of the tests * mirrors the source directory * there are some additional files diff --git a/grunt/config/compress.js b/grunt/config/compress.js index d8905113..551b50b4 100644 --- a/grunt/config/compress.js +++ b/grunt/config/compress.js @@ -32,7 +32,7 @@ module.exports = { src: [ "boot0.js", "boot1.js" ], dest: standaloneLibDir, expand: true, - cwd: libJasmineCore("boot") + cwd: libJasmineCore("") }, { src: [ "SpecRunner.html" ], diff --git a/grunt/config/concat.js b/grunt/config/concat.js index 8c887a7d..23997b48 100644 --- a/grunt/config/concat.js +++ b/grunt/config/concat.js @@ -38,15 +38,15 @@ module.exports = { dest: 'lib/jasmine-core/jasmine.js' }, boot0: { - src: ['lib/jasmine-core/boot/boot0.js'], + src: ['src/boot/boot0.js'], dest: 'lib/jasmine-core/boot0.js' }, boot1: { - src: ['lib/jasmine-core/boot/boot1.js'], + src: ['src/boot/boot1.js'], dest: 'lib/jasmine-core/boot1.js' }, nodeBoot: { - src: ['lib/jasmine-core/boot/node_boot.js'], + src: ['src/boot/node_boot.js'], dest: 'lib/jasmine-core/node_boot.js' }, options: { diff --git a/spec/support/jasmine-browser.js b/spec/support/jasmine-browser.js index 1277d421..04950c16 100644 --- a/spec/support/jasmine-browser.js +++ b/spec/support/jasmine-browser.js @@ -12,7 +12,8 @@ module.exports = { 'core/Suite.js', 'core/**/*.js', 'html/**/*.js', - '**/*.js' + '**/*.js', + '!boot/**.js' ], specDir: 'spec', specFiles: ['**/*[Ss]pec.js', '!npmPackage/**/*'], diff --git a/lib/jasmine-core/boot/boot0.js b/src/boot/boot0.js similarity index 100% rename from lib/jasmine-core/boot/boot0.js rename to src/boot/boot0.js diff --git a/lib/jasmine-core/boot/boot1.js b/src/boot/boot1.js similarity index 100% rename from lib/jasmine-core/boot/boot1.js rename to src/boot/boot1.js diff --git a/lib/jasmine-core/boot/node_boot.js b/src/boot/node_boot.js similarity index 100% rename from lib/jasmine-core/boot/node_boot.js rename to src/boot/node_boot.js From bbcb5ff42f180fbaaa5661fa4fcc8d9678d1a97e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 3 Sep 2021 15:46:23 -0700 Subject: [PATCH 25/71] Fixed linter & formatter issues in boot files --- lib/jasmine-core/boot0.js | 2 +- lib/jasmine-core/boot1.js | 57 ++++++++++++++++++++--------------- lib/jasmine-core/node_boot.js | 2 +- src/boot/boot0.js | 2 +- src/boot/boot1.js | 57 ++++++++++++++++++++--------------- src/boot/node_boot.js | 2 +- 6 files changed, 68 insertions(+), 54 deletions(-) diff --git a/lib/jasmine-core/boot0.js b/lib/jasmine-core/boot0.js index 1bfa4193..90afa2fd 100644 --- a/lib/jasmine-core/boot0.js +++ b/lib/jasmine-core/boot0.js @@ -61,4 +61,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. for (var property in jasmineInterface) { global[property] = jasmineInterface[property]; } -}()); +})(); diff --git a/lib/jasmine-core/boot1.js b/lib/jasmine-core/boot1.js index 152c8769..0f40607a 100644 --- a/lib/jasmine-core/boot1.js +++ b/lib/jasmine-core/boot1.js @@ -21,7 +21,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** - This file finishes "booting" Jasmine, performing all of the necessary + This file finishes 'booting' Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `boot0.js` but before any project source files or spec files are loaded. Thus this file can also be used to @@ -43,24 +43,28 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var queryString = new jasmine.QueryString({ - getWindowLocation: function() { return window.location; } + getWindowLocation: function() { + return window.location; + } }); - var filterSpecs = !!queryString.getParam("spec"); + var filterSpecs = !!queryString.getParam('spec'); var config = { - stopOnSpecFailure: queryString.getParam("stopOnSpecFailure"), - stopSpecOnExpectationFailure: queryString.getParam("stopSpecOnExpectationFailure"), - hideDisabled: queryString.getParam("hideDisabled") + stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'), + stopSpecOnExpectationFailure: queryString.getParam( + 'stopSpecOnExpectationFailure' + ), + hideDisabled: queryString.getParam('hideDisabled') }; - var random = queryString.getParam("random"); + var random = queryString.getParam('random'); - if (random !== undefined && random !== "") { + if (random !== undefined && random !== '') { config.random = random; } - var seed = queryString.getParam("seed"); + var seed = queryString.getParam('seed'); if (seed) { config.seed = seed; } @@ -71,11 +75,21 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var htmlReporter = new jasmine.HtmlReporter({ env: env, - navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, - addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, - getContainer: function() { return document.body; }, - createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + navigateWithNewParam: function(key, value) { + return queryString.navigateWithNewParam(key, value); + }, + addToExistingQueryString: function(key, value) { + return queryString.fullStringWithNewParam(key, value); + }, + getContainer: function() { + return document.body; + }, + createElement: function() { + return document.createElement.apply(document, arguments); + }, + createTextNode: function() { + return document.createTextNode.apply(document, arguments); + }, timer: new jasmine.Timer(), filterSpecs: filterSpecs }); @@ -90,7 +104,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * Filter which specs will be run by matching the start of the full name against the `spec` query param. */ var specFilter = new jasmine.HtmlSpecFilter({ - filterString: function() { return queryString.getParam("spec"); } + filterString: function() { + return queryString.getParam('spec'); + } }); config.specFilter = function(spec) { @@ -113,13 +129,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. htmlReporter.initialize(); env.execute(); }; - - /** - * Helper function for readability above. - */ - function extend(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; - } - -}()); +})(); diff --git a/lib/jasmine-core/node_boot.js b/lib/jasmine-core/node_boot.js index 4016e3b8..7d4c9c26 100644 --- a/lib/jasmine-core/node_boot.js +++ b/lib/jasmine-core/node_boot.js @@ -23,7 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. module.exports = function(jasmineRequire) { var jasmine = jasmineRequire.core(jasmineRequire); - var env = jasmine.getEnv({suppressLoadErrors: true}); + var env = jasmine.getEnv({ suppressLoadErrors: true }); var jasmineInterface = jasmineRequire.interface(jasmine, env); diff --git a/src/boot/boot0.js b/src/boot/boot0.js index ca72e496..80500089 100644 --- a/src/boot/boot0.js +++ b/src/boot/boot0.js @@ -39,4 +39,4 @@ for (var property in jasmineInterface) { global[property] = jasmineInterface[property]; } -}()); +})(); diff --git a/src/boot/boot1.js b/src/boot/boot1.js index ce41a065..20ec9562 100644 --- a/src/boot/boot1.js +++ b/src/boot/boot1.js @@ -1,5 +1,5 @@ /** - This file finishes "booting" Jasmine, performing all of the necessary + This file finishes 'booting' Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `boot0.js` but before any project source files or spec files are loaded. Thus this file can also be used to @@ -21,24 +21,28 @@ */ var queryString = new jasmine.QueryString({ - getWindowLocation: function() { return window.location; } + getWindowLocation: function() { + return window.location; + } }); - var filterSpecs = !!queryString.getParam("spec"); + var filterSpecs = !!queryString.getParam('spec'); var config = { - stopOnSpecFailure: queryString.getParam("stopOnSpecFailure"), - stopSpecOnExpectationFailure: queryString.getParam("stopSpecOnExpectationFailure"), - hideDisabled: queryString.getParam("hideDisabled") + stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'), + stopSpecOnExpectationFailure: queryString.getParam( + 'stopSpecOnExpectationFailure' + ), + hideDisabled: queryString.getParam('hideDisabled') }; - var random = queryString.getParam("random"); + var random = queryString.getParam('random'); - if (random !== undefined && random !== "") { + if (random !== undefined && random !== '') { config.random = random; } - var seed = queryString.getParam("seed"); + var seed = queryString.getParam('seed'); if (seed) { config.seed = seed; } @@ -49,11 +53,21 @@ */ var htmlReporter = new jasmine.HtmlReporter({ env: env, - navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); }, - addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, - getContainer: function() { return document.body; }, - createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); }, + navigateWithNewParam: function(key, value) { + return queryString.navigateWithNewParam(key, value); + }, + addToExistingQueryString: function(key, value) { + return queryString.fullStringWithNewParam(key, value); + }, + getContainer: function() { + return document.body; + }, + createElement: function() { + return document.createElement.apply(document, arguments); + }, + createTextNode: function() { + return document.createTextNode.apply(document, arguments); + }, timer: new jasmine.Timer(), filterSpecs: filterSpecs }); @@ -68,7 +82,9 @@ * Filter which specs will be run by matching the start of the full name against the `spec` query param. */ var specFilter = new jasmine.HtmlSpecFilter({ - filterString: function() { return queryString.getParam("spec"); } + filterString: function() { + return queryString.getParam('spec'); + } }); config.specFilter = function(spec) { @@ -91,13 +107,4 @@ htmlReporter.initialize(); env.execute(); }; - - /** - * Helper function for readability above. - */ - function extend(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; - } - -}()); +})(); diff --git a/src/boot/node_boot.js b/src/boot/node_boot.js index 89ee49b1..af588102 100644 --- a/src/boot/node_boot.js +++ b/src/boot/node_boot.js @@ -1,7 +1,7 @@ module.exports = function(jasmineRequire) { var jasmine = jasmineRequire.core(jasmineRequire); - var env = jasmine.getEnv({suppressLoadErrors: true}); + var env = jasmine.getEnv({ suppressLoadErrors: true }); var jasmineInterface = jasmineRequire.interface(jasmine, env); From d092a59bd16e51c55d6dabeba4ed8d77d41faed2 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 10 Sep 2021 18:07:35 -0700 Subject: [PATCH 26/71] Treat multiple calls to done callbacks as errors --- lib/jasmine-core/jasmine.js | 70 +++++++++++--------- spec/core/SpecSpec.js | 18 +++-- spec/core/SuiteSpec.js | 36 +++++----- spec/core/integration/EnvSpec.js | 110 ++++++++++++------------------- src/core/Env.js | 24 +++++-- src/core/ReportDispatcher.js | 12 ++-- src/core/Spec.js | 18 +++-- src/core/Suite.js | 16 ++--- 8 files changed, 144 insertions(+), 160 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 4b9c456d..600302b8 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -684,7 +684,7 @@ getJasmineRequireObj().Spec = function(j$) { }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; - this.deprecated = attrs.deprecated || function() {}; + this.onLateError = attrs.onLateError || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || @@ -783,15 +783,13 @@ getJasmineRequireObj().Spec = function(j$) { // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. - self.deprecated( - "An asynchronous function called its 'done' " + - 'callback more than once. This is a bug in the spec, beforeAll, ' + - 'beforeEach, afterAll, or afterEach function in question. This will ' + - 'be treated as an error in a future version.\n' + - '(in spec: ' + - self.getFullName() + - ')', - { ignoreRunnable: true } + self.onLateError( + new Error( + 'An asynchronous spec, beforeEach, or afterEach function called its ' + + "'done' callback more than once.\n(in spec: " + + self.getFullName() + + ')' + ) ); }, onComplete: function() { @@ -1332,6 +1330,18 @@ getJasmineRequireObj().Env = function(j$) { } }; + function recordLateError(error) { + topSuite.result.failedExpectations.push( + expectationResultFactory({ + error, + passed: false, + matcherName: '', + expected: '', + actual: '' + }) + ); + } + function recordLateExpectation(runable, runableType, result) { var delayedExpectationResult = {}; Object.keys(result).forEach(function(k) { @@ -1509,12 +1519,12 @@ getJasmineRequireObj().Env = function(j$) { }; var topSuite = new j$.Suite({ - env: this, id: getNextSuiteId(), description: 'Jasmine__TopLevel__Suite', expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, - expectationResultFactory: expectationResultFactory + expectationResultFactory: expectationResultFactory, + onLateError: recordLateError }); var deprecator = new j$.Deprecator(topSuite); defaultResourcesForRunnable(topSuite.id); @@ -1604,7 +1614,7 @@ getJasmineRequireObj().Env = function(j$) { 'specDone' ], queueRunnerFactory, - self.deprecated + recordLateError ); /** @@ -1898,7 +1908,6 @@ getJasmineRequireObj().Env = function(j$) { var suiteFactory = function(description) { var suite = new j$.Suite({ - env: self, id: getNextSuiteId(), description: description, parentSuite: currentDeclarationSuite, @@ -1906,7 +1915,8 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: config.stopSpecOnExpectationFailure + throwOnExpectationFailure: config.stopSpecOnExpectationFailure, + onLateError: recordLateError }); return suite; @@ -2002,7 +2012,7 @@ getJasmineRequireObj().Env = function(j$) { beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: expectationFactory, asyncExpectationFactory: specAsyncExpectationFactory, - deprecated: self.deprecated, + onLateError: recordLateError, resultCallback: specResultCallback, getSpecName: function(spec) { return getSpecName(spec, suite); @@ -7723,7 +7733,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; getJasmineRequireObj().ReportDispatcher = function(j$) { - function ReportDispatcher(methods, queueRunnerFactory, deprecated) { + function ReportDispatcher(methods, queueRunnerFactory, onLateError) { var dispatchedMethods = methods || []; for (var i = 0; i < dispatchedMethods.length; i++) { @@ -7769,11 +7779,11 @@ getJasmineRequireObj().ReportDispatcher = function(j$) { onComplete: onComplete, isReporter: true, onMultipleDone: function() { - deprecated( - "An asynchronous reporter callback called its 'done' callback " + - 'more than once. This is a bug in the reporter callback in ' + - 'question. This will be treated as an error in a future version.', - { ignoreRunnable: true } + onLateError( + new Error( + "An asynchronous reporter callback called its 'done' callback " + + 'more than once.' + ) ); } }); @@ -9091,7 +9101,6 @@ getJasmineRequireObj().StackTrace = function(j$) { getJasmineRequireObj().Suite = function(j$) { function Suite(attrs) { - this.env = attrs.env; this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; @@ -9099,6 +9108,7 @@ getJasmineRequireObj().Suite = function(j$) { this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.expectationResultFactory = attrs.expectationResultFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.onLateError = attrs.onLateError; this.beforeFns = []; this.afterFns = []; @@ -9258,29 +9268,25 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.onMultipleDone = function() { - var msg; + let msg; // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. if (this.parentSuite) { msg = - "An asynchronous function called its 'done' callback more than " + - 'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' + - 'or afterEach function in question. This will be treated as an error ' + - 'in a future version.\n' + + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n' + '(in suite: ' + this.getFullName() + ')'; } else { msg = 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once. This is a bug in the beforeAll " + - 'or afterAll function in question. This will be treated as an ' + - 'error in a future version.'; + "'done' callback more than once."; } - this.env.deprecated(msg, { ignoreRunnable: true }); + this.onLateError(new Error(msg)); }; Suite.prototype.addExpectationResult = function() { diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index dabc698e..2a69f78b 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -513,11 +513,11 @@ describe('Spec', function() { expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]); }); - it('passes an onMultipleDone that logs a deprecation', function() { + it('treats multiple done calls as late errors', function() { var queueRunnerFactory = jasmine.createSpy('queueRunnerFactory'), - deprecated = jasmine.createSpy('depredated'), + onLateError = jasmine.createSpy('onLateError'), spec = new jasmineUnderTest.Spec({ - deprecated: deprecated, + onLateError: onLateError, queueableFn: { fn: function() {} }, queueRunnerFactory: queueRunnerFactory, getSpecName: function() { @@ -530,13 +530,11 @@ describe('Spec', function() { expect(queueRunnerFactory).toHaveBeenCalled(); queueRunnerFactory.calls.argsFor(0)[0].onMultipleDone(); - expect(deprecated).toHaveBeenCalledWith( - "An asynchronous function called its 'done' " + - 'callback more than once. This is a bug in the spec, beforeAll, ' + - 'beforeEach, afterAll, or afterEach function in question. This will ' + - 'be treated as an error in a future version.\n' + - '(in spec: a spec)', - { ignoreRunnable: true } + expect(onLateError).toHaveBeenCalledTimes(1); + expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); + expect(onLateError.calls.argsFor(0)[0].message).toEqual( + 'An asynchronous spec, beforeEach, or afterEach function called its ' + + "'done' callback more than once.\n(in spec: a spec)" ); }); }); diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 60b96285..73cfab4d 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -144,25 +144,27 @@ describe('Suite', function() { }); describe('#onMultipleDone', function() { - it('logs a special deprecation when it is the top suite', function() { - var env = jasmine.createSpyObj('env', ['deprecated']); - var suite = new jasmineUnderTest.Suite({ env: env, parentSuite: null }); + it('reports a special error when it is the top suite', function() { + const onLateError = jasmine.createSpy('onLateError'); + const suite = new jasmineUnderTest.Suite({ + onLateError, + parentSuite: null + }); suite.onMultipleDone(); - expect(env.deprecated).toHaveBeenCalledWith( + expect(onLateError).toHaveBeenCalledTimes(1); + expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); + expect(onLateError.calls.argsFor(0)[0].message).toEqual( 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once. This is a bug in the beforeAll " + - 'or afterAll function in question. This will be treated as an ' + - 'error in a future version.', - { ignoreRunnable: true } + "'done' callback more than once." ); }); - it('logs a deprecation including the suite name when it is a normal suite', function() { - var env = jasmine.createSpyObj('env', ['deprecated']); + it('reports an error including the suite name when it is a normal suite', function() { + const onLateError = jasmine.createSpy('onLateError'); var suite = new jasmineUnderTest.Suite({ - env: env, + onLateError, description: 'the suite', parentSuite: { description: 'the parent suite', @@ -172,13 +174,11 @@ describe('Suite', function() { suite.onMultipleDone(); - expect(env.deprecated).toHaveBeenCalledWith( - "An asynchronous function called its 'done' callback more than " + - 'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' + - 'or afterEach function in question. This will be treated as an error ' + - 'in a future version.\n' + - '(in suite: the parent suite the suite)', - { ignoreRunnable: true } + expect(onLateError).toHaveBeenCalledTimes(1); + expect(onLateError.calls.argsFor(0)[0]).toBeInstanceOf(Error); + expect(onLateError.calls.argsFor(0)[0].message).toEqual( + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n(in suite: the parent suite the suite)' ); }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index cd084b6b..fdac97f7 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -509,17 +509,13 @@ describe('Env integration', function() { env.execute(null, assertions); }); - it('deprecates multiple calls to done in the top suite', function(done) { + it('reports multiple calls to done in the top suite as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once. This is a bug in the beforeAll " + - 'or afterAll function in question. This will be treated as an ' + - 'error in a future version.'; + "'done' callback more than once."; - spyOn(console, 'error'); env.addReporter(reporter); - env.configure({ verboseDeprecations: true }); env.beforeAll(function(innerDone) { innerDone(); innerDone(); @@ -531,31 +527,27 @@ describe('Env integration', function() { }); env.execute(null, function() { - var warnings; expect(reporter.jasmineDone).toHaveBeenCalled(); - warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings; - expect(warnings.length).toEqual(2); - expect(warnings[0]) + const errors = reporter.jasmineDone.calls.argsFor(0)[0] + .failedExpectations; + expect(errors.length).toEqual(2); + expect(errors[0].message) .withContext('top beforeAll') - .toEqual(jasmine.objectContaining({ message: message })); - expect(warnings[1]) + .toContain(message); + expect(errors[1].message) .withContext('top afterAll') - .toEqual(jasmine.objectContaining({ message: message })); + .toContain(message); done(); }); }); - it('deprecates multiple calls to done in a non-top suite', function(done) { + it('reports multiple calls to done in a non-top suite as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = - "An asynchronous function called its 'done' " + - 'callback more than once. This is a bug in the spec, beforeAll, ' + - 'beforeEach, afterAll, or afterEach function in question. This will ' + - 'be treated as an error in a future version.'; + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n(in suite: a suite)'; - spyOn(console, 'error'); env.addReporter(reporter); - env.configure({ verboseDeprecations: true }); env.describe('a suite', function() { env.beforeAll(function(innerDone) { innerDone(); @@ -569,40 +561,27 @@ describe('Env integration', function() { }); env.execute(null, function() { - var warnings; expect(reporter.jasmineDone).toHaveBeenCalled(); - warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings; - expect(warnings.length).toEqual(2); - expect(warnings[0]) + const errors = reporter.jasmineDone.calls.argsFor(0)[0] + .failedExpectations; + expect(errors.length).toEqual(2); + expect(errors[0].message) .withContext('suite beforeAll') - .toEqual( - jasmine.objectContaining({ - message: message + '\n(in suite: a suite)' - }) - ); - expect(warnings[1]) + .toContain(message); + expect(errors[1].message) .withContext('suite afterAll') - .toEqual( - jasmine.objectContaining({ - message: message + '\n(in suite: a suite)' - }) - ); + .toContain(message); done(); }); }); - it('deprecates multiple calls to done in a spec', function(done) { + it('reports multiple calls to done in a spec as errors', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']); var message = - "An asynchronous function called its 'done' " + - 'callback more than once. This is a bug in the spec, beforeAll, ' + - 'beforeEach, afterAll, or afterEach function in question. This will ' + - 'be treated as an error in a future version.\n' + - '(in spec: a suite a spec)'; + 'An asynchronous spec, beforeEach, or afterEach function called its ' + + "'done' callback more than once.\n(in spec: a suite a spec)"; - spyOn(console, 'error'); env.addReporter(reporter); - env.configure({ verboseDeprecations: true }); env.describe('a suite', function() { env.beforeEach(function(innerDone) { innerDone(); @@ -619,30 +598,27 @@ describe('Env integration', function() { }); env.execute(null, function() { - var warnings; expect(reporter.jasmineDone).toHaveBeenCalled(); - warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings; - expect(warnings.length).toEqual(3); - expect(warnings[0]) - .withContext('warning caused by beforeEach') - .toEqual(jasmine.objectContaining({ message: message })); - expect(warnings[1]) - .withContext('warning caused by it') - .toEqual(jasmine.objectContaining({ message: message })); - expect(warnings[2]) - .withContext('warning caused by afterEach') - .toEqual(jasmine.objectContaining({ message: message })); + const errors = reporter.jasmineDone.calls.argsFor(0)[0] + .failedExpectations; + expect(errors.length).toEqual(3); + expect(errors[0].message) + .withContext('error caused by beforeEach') + .toContain(message); + expect(errors[1].message) + .withContext('error caused by it') + .toContain(message); + expect(errors[2].message) + .withContext('error caused by afterEach') + .toContain(message); done(); }); }); - it('deprecates multiple calls to done in reporters', function(done) { + it('reports multiple calls to done in reporters as errors', function(done) { var message = "An asynchronous reporter callback called its 'done' callback more " + - 'than once. This is a bug in the reporter callback in question. This ' + - 'will be treated as an error in a future version.\nNote: This message ' + - 'will be shown only once. Set config.verboseDeprecations to true to ' + - 'see every occurrence.'; + 'than once.'; var reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone']); reporter.specDone = function(result, done) { done(); @@ -652,19 +628,17 @@ describe('Env integration', function() { env.it('a spec', function() {}); - spyOn(console, 'error'); env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalled(); - warnings = reporter.jasmineDone.calls.argsFor(0)[0].deprecationWarnings; - expect(warnings.length).toEqual(1); - expect(warnings[0]).toEqual( - jasmine.objectContaining({ message: message }) - ); + const errors = reporter.jasmineDone.calls.argsFor(0)[0] + .failedExpectations; + expect(errors.length).toEqual(1); + expect(errors[0].message).toContain(message); done(); }); }); - it('does not deprecate a call to done that comes after a timeout', function(done) { + it('does not report an error for a call to done that comes after a timeout', function(done) { var reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']), firstSpecDone; @@ -687,7 +661,7 @@ describe('Env integration', function() { env.execute(null, function() { expect(reporter.jasmineDone).toHaveBeenCalledWith( jasmine.objectContaining({ - deprecationWarnings: [] + failedExpectations: [] }) ); done(); diff --git a/src/core/Env.js b/src/core/Env.js index 2897bedc..49c6735a 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -338,6 +338,18 @@ getJasmineRequireObj().Env = function(j$) { } }; + function recordLateError(error) { + topSuite.result.failedExpectations.push( + expectationResultFactory({ + error, + passed: false, + matcherName: '', + expected: '', + actual: '' + }) + ); + } + function recordLateExpectation(runable, runableType, result) { var delayedExpectationResult = {}; Object.keys(result).forEach(function(k) { @@ -515,12 +527,12 @@ getJasmineRequireObj().Env = function(j$) { }; var topSuite = new j$.Suite({ - env: this, id: getNextSuiteId(), description: 'Jasmine__TopLevel__Suite', expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, - expectationResultFactory: expectationResultFactory + expectationResultFactory: expectationResultFactory, + onLateError: recordLateError }); var deprecator = new j$.Deprecator(topSuite); defaultResourcesForRunnable(topSuite.id); @@ -610,7 +622,7 @@ getJasmineRequireObj().Env = function(j$) { 'specDone' ], queueRunnerFactory, - self.deprecated + recordLateError ); /** @@ -904,7 +916,6 @@ getJasmineRequireObj().Env = function(j$) { var suiteFactory = function(description) { var suite = new j$.Suite({ - env: self, id: getNextSuiteId(), description: description, parentSuite: currentDeclarationSuite, @@ -912,7 +923,8 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: suiteAsyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: config.stopSpecOnExpectationFailure + throwOnExpectationFailure: config.stopSpecOnExpectationFailure, + onLateError: recordLateError }); return suite; @@ -1008,7 +1020,7 @@ getJasmineRequireObj().Env = function(j$) { beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: expectationFactory, asyncExpectationFactory: specAsyncExpectationFactory, - deprecated: self.deprecated, + onLateError: recordLateError, resultCallback: specResultCallback, getSpecName: function(spec) { return getSpecName(spec, suite); diff --git a/src/core/ReportDispatcher.js b/src/core/ReportDispatcher.js index 6c3759ba..c2f957dc 100644 --- a/src/core/ReportDispatcher.js +++ b/src/core/ReportDispatcher.js @@ -1,5 +1,5 @@ getJasmineRequireObj().ReportDispatcher = function(j$) { - function ReportDispatcher(methods, queueRunnerFactory, deprecated) { + function ReportDispatcher(methods, queueRunnerFactory, onLateError) { var dispatchedMethods = methods || []; for (var i = 0; i < dispatchedMethods.length; i++) { @@ -45,11 +45,11 @@ getJasmineRequireObj().ReportDispatcher = function(j$) { onComplete: onComplete, isReporter: true, onMultipleDone: function() { - deprecated( - "An asynchronous reporter callback called its 'done' callback " + - 'more than once. This is a bug in the reporter callback in ' + - 'question. This will be treated as an error in a future version.', - { ignoreRunnable: true } + onLateError( + new Error( + "An asynchronous reporter callback called its 'done' callback " + + 'more than once.' + ) ); } }); diff --git a/src/core/Spec.js b/src/core/Spec.js index 4ab881a8..8a0299cc 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -24,7 +24,7 @@ getJasmineRequireObj().Spec = function(j$) { }; this.expectationResultFactory = attrs.expectationResultFactory || function() {}; - this.deprecated = attrs.deprecated || function() {}; + this.onLateError = attrs.onLateError || function() {}; this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; this.catchingExceptions = attrs.catchingExceptions || @@ -123,15 +123,13 @@ getJasmineRequireObj().Spec = function(j$) { // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. - self.deprecated( - "An asynchronous function called its 'done' " + - 'callback more than once. This is a bug in the spec, beforeAll, ' + - 'beforeEach, afterAll, or afterEach function in question. This will ' + - 'be treated as an error in a future version.\n' + - '(in spec: ' + - self.getFullName() + - ')', - { ignoreRunnable: true } + self.onLateError( + new Error( + 'An asynchronous spec, beforeEach, or afterEach function called its ' + + "'done' callback more than once.\n(in spec: " + + self.getFullName() + + ')' + ) ); }, onComplete: function() { diff --git a/src/core/Suite.js b/src/core/Suite.js index 5f46561d..7ed92190 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,6 +1,5 @@ getJasmineRequireObj().Suite = function(j$) { function Suite(attrs) { - this.env = attrs.env; this.id = attrs.id; this.parentSuite = attrs.parentSuite; this.description = attrs.description; @@ -8,6 +7,7 @@ getJasmineRequireObj().Suite = function(j$) { this.asyncExpectationFactory = attrs.asyncExpectationFactory; this.expectationResultFactory = attrs.expectationResultFactory; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.onLateError = attrs.onLateError; this.beforeFns = []; this.afterFns = []; @@ -167,29 +167,25 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.onMultipleDone = function() { - var msg; + let msg; // Issue a deprecation. Include the context ourselves and pass // ignoreRunnable: true, since getting here always means that we've already // moved on and the current runnable isn't the one that caused the problem. if (this.parentSuite) { msg = - "An asynchronous function called its 'done' callback more than " + - 'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' + - 'or afterEach function in question. This will be treated as an error ' + - 'in a future version.\n' + + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n' + '(in suite: ' + this.getFullName() + ')'; } else { msg = 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once. This is a bug in the beforeAll " + - 'or afterAll function in question. This will be treated as an ' + - 'error in a future version.'; + "'done' callback more than once."; } - this.env.deprecated(msg, { ignoreRunnable: true }); + this.onLateError(new Error(msg)); }; Suite.prototype.addExpectationResult = function() { From 6e10f2240337d218c6bb62525b8280a969de10f0 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Sep 2021 08:57:50 -0700 Subject: [PATCH 27/71] Don't display late errors as AfterAll errors in the HTML reporter --- lib/jasmine-core/jasmine-html.js | 4 ++- lib/jasmine-core/jasmine.js | 21 ++++++++------- spec/core/integration/EnvSpec.js | 8 ++++++ spec/html/HtmlReporterSpec.js | 44 ++++++++++++++++++++++++++++++++ src/core/Env.js | 18 ++++++------- src/core/ExpectationResult.js | 3 +++ src/html/HtmlReporter.js | 4 ++- 7 files changed, 82 insertions(+), 20 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 51f79786..ba3fb447 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -303,8 +303,10 @@ jasmineRequire.HtmlReporter = function(j$) { } else { return prefix; } - } else { + } else if (failure.globalErrorType === 'afterAll') { return afterAllMessagePrefix + failure.message; + } else { + return failure.message; } } diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 600302b8..d4badddb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1331,15 +1331,15 @@ getJasmineRequireObj().Env = function(j$) { }; function recordLateError(error) { - topSuite.result.failedExpectations.push( - expectationResultFactory({ - error, - passed: false, - matcherName: '', - expected: '', - actual: '' - }) - ); + const result = expectationResultFactory({ + error, + passed: false, + matcherName: '', + expected: '', + actual: '' + }); + result.globalErrorType = 'lateError'; + topSuite.result.failedExpectations.push(result); } function recordLateExpectation(runable, runableType, result) { @@ -3912,6 +3912,9 @@ getJasmineRequireObj().buildExpectationResult = function(j$) { * @property {Boolean} passed - Whether the expectation passed or failed. * @property {Object} expected - If the expectation failed, what was the expected value. * @property {Object} actual - If the expectation failed, what actual value was produced. + * @property {String|undefined} globalErrorType - The type of an error that + * is reported on the top suite. Valid values are undefined, "afterAll", + * "load", "lateExpectation", and "lateError". */ var result = { matcherName: options.matcherName, diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index fdac97f7..f712ec2a 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -534,9 +534,11 @@ describe('Env integration', function() { expect(errors[0].message) .withContext('top beforeAll') .toContain(message); + expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('top afterAll') .toContain(message); + expect(errors[1].globalErrorType).toEqual('lateError'); done(); }); }); @@ -568,9 +570,11 @@ describe('Env integration', function() { expect(errors[0].message) .withContext('suite beforeAll') .toContain(message); + expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('suite afterAll') .toContain(message); + expect(errors[1].globalErrorType).toEqual('lateError'); done(); }); }); @@ -605,12 +609,15 @@ describe('Env integration', function() { expect(errors[0].message) .withContext('error caused by beforeEach') .toContain(message); + expect(errors[0].globalErrorType).toEqual('lateError'); expect(errors[1].message) .withContext('error caused by it') .toContain(message); + expect(errors[1].globalErrorType).toEqual('lateError'); expect(errors[2].message) .withContext('error caused by afterEach') .toContain(message); + expect(errors[2].globalErrorType).toEqual('lateError'); done(); }); }); @@ -634,6 +641,7 @@ describe('Env integration', function() { .failedExpectations; expect(errors.length).toEqual(1); expect(errors[0].message).toContain(message); + expect(errors[0].globalErrorType).toEqual('lateError'); done(); }); }); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index a79e9cef..b99751bc 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -704,6 +704,50 @@ describe('HtmlReporter', function() { expect(alertBars[2].innerHTML).not.toMatch(/line/); }); + it('does not display the "AfterAll" prefix for other error types', function() { + const container = document.createElement('div'); + const getContainer = function() { + return container; + }; + const reporter = new jasmineUnderTest.HtmlReporter({ + env: env, + getContainer: getContainer, + createElement: function() { + return document.createElement.apply(document, arguments); + }, + createTextNode: function() { + return document.createTextNode.apply(document, arguments); + } + }); + + reporter.initialize(); + + reporter.jasmineStarted({}); + reporter.jasmineDone({ + failedExpectations: [ + { message: 'load error', globalErrorType: 'load' }, + { + message: 'lateExpectation error', + globalErrorType: 'lateExpectation' + }, + { message: 'lateError error', globalErrorType: 'lateError' } + ] + }); + + const alertBars = container.querySelectorAll( + '.jasmine-alert .jasmine-bar' + ); + + expect(alertBars.length).toEqual(4); + expect(alertBars[1].textContent).toContain('load error'); + expect(alertBars[2].textContent).toContain('lateExpectation error'); + expect(alertBars[3].textContent).toContain('lateError error'); + + for (let bar of alertBars) { + expect(bar.textContent).not.toContain('AfterAll'); + } + }); + it('displays file and line information if available', function() { var container = document.createElement('div'), getContainer = function() { diff --git a/src/core/Env.js b/src/core/Env.js index 49c6735a..be59c1e7 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -339,15 +339,15 @@ getJasmineRequireObj().Env = function(j$) { }; function recordLateError(error) { - topSuite.result.failedExpectations.push( - expectationResultFactory({ - error, - passed: false, - matcherName: '', - expected: '', - actual: '' - }) - ); + const result = expectationResultFactory({ + error, + passed: false, + matcherName: '', + expected: '', + actual: '' + }); + result.globalErrorType = 'lateError'; + topSuite.result.failedExpectations.push(result); } function recordLateExpectation(runable, runableType, result) { diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js index d3ea5cb3..8834b3e0 100644 --- a/src/core/ExpectationResult.js +++ b/src/core/ExpectationResult.js @@ -12,6 +12,9 @@ getJasmineRequireObj().buildExpectationResult = function(j$) { * @property {Boolean} passed - Whether the expectation passed or failed. * @property {Object} expected - If the expectation failed, what was the expected value. * @property {Object} actual - If the expectation failed, what actual value was produced. + * @property {String|undefined} globalErrorType - The type of an error that + * is reported on the top suite. Valid values are undefined, "afterAll", + * "load", "lateExpectation", and "lateError". */ var result = { matcherName: options.matcherName, diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 5cc4e86e..802c484d 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -272,8 +272,10 @@ jasmineRequire.HtmlReporter = function(j$) { } else { return prefix; } - } else { + } else if (failure.globalErrorType === 'afterAll') { return afterAllMessagePrefix + failure.message; + } else { + return failure.message; } } From 760f2d90030ad9318d7c82791e4bbbd105eb7e24 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 18 Sep 2021 09:40:30 -0700 Subject: [PATCH 28/71] Removed additional Ruby support files --- .rspec | 1 - grunt/templates/version.rb.jst | 9 --------- src/templates/version.rb.erb | 6 ------ 3 files changed, 16 deletions(-) delete mode 100644 .rspec delete mode 100644 grunt/templates/version.rb.jst delete mode 100644 src/templates/version.rb.erb diff --git a/.rspec b/.rspec deleted file mode 100644 index 4e1e0d2f..00000000 --- a/.rspec +++ /dev/null @@ -1 +0,0 @@ ---color diff --git a/grunt/templates/version.rb.jst b/grunt/templates/version.rb.jst deleted file mode 100644 index 411403c2..00000000 --- a/grunt/templates/version.rb.jst +++ /dev/null @@ -1,9 +0,0 @@ -# -# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated -# by a grunt task when the standalone release is built. -# -module Jasmine - module Core - VERSION = "<%= jasmineVersion %>" - end -end diff --git a/src/templates/version.rb.erb b/src/templates/version.rb.erb deleted file mode 100644 index 7fb8433d..00000000 --- a/src/templates/version.rb.erb +++ /dev/null @@ -1,6 +0,0 @@ -module Jasmine - module Core - VERSION = "<%= "#{major}.#{minor}.#{build}" %><%= ".rc#{release_candidate}" if release_candidate %>" - end -end - From 3a77ae3dfe79bab01dca1dcd59fcb399bdcad5aa Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 23 Sep 2021 16:10:59 -0700 Subject: [PATCH 29/71] Throw if the argument to jasmine.clock().mockDate() is not a Date --- lib/jasmine-core/jasmine.js | 5 ++--- spec/core/ClockSpec.js | 9 +++------ src/core/MockDate.js | 5 ++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 401d5df6..ee776eab 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -7054,10 +7054,9 @@ getJasmineRequireObj().MockDate = function(j$) { currentTime = mockDate.getTime(); } else { if (!j$.util.isUndefined(mockDate)) { - j$.getEnv().deprecated( + throw new Error( '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.' + 'should be a Date instance.' ); } diff --git a/spec/core/ClockSpec.js b/spec/core/ClockSpec.js index 126fe8ca..69c05fc4 100644 --- a/spec/core/ClockSpec.js +++ b/spec/core/ClockSpec.js @@ -950,7 +950,7 @@ describe('Clock (acceptance)', function() { expect(timeoutDate).toEqual(baseTime.getTime() + 150); }); - it('logs a deprecation when mockDate is called with a non-Date', function() { + it('throws mockDate is called with a non-Date', function() { var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(), global = { Date: Date }, mockDate = new jasmineUnderTest.MockDate(global), @@ -963,12 +963,9 @@ describe('Clock (acceptance)', function() { ), env = jasmineUnderTest.getEnv(); - spyOn(env, 'deprecated'); - clock.mockDate(12345); - expect(env.deprecated).toHaveBeenCalledWith( + expect(() => clock.mockDate(12345)).toThrowError( '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.' + 'a Date instance.' ); }); diff --git a/src/core/MockDate.js b/src/core/MockDate.js index e8738a44..feefe458 100644 --- a/src/core/MockDate.js +++ b/src/core/MockDate.js @@ -17,10 +17,9 @@ getJasmineRequireObj().MockDate = function(j$) { currentTime = mockDate.getTime(); } else { if (!j$.util.isUndefined(mockDate)) { - j$.getEnv().deprecated( + throw new Error( '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.' + 'should be a Date instance.' ); } From 47081258cd668a8795186a90c27b24442af271c6 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 2 Oct 2021 09:56:25 -0700 Subject: [PATCH 30/71] Revert "Revert "Added the ability to associate trace information with failing specs"" This reverts commit fdad8849df475b95cfc280e91086f0a73b18187a. --- lib/jasmine-core/jasmine-html.js | 44 +++++++++++++ lib/jasmine-core/jasmine.css | 13 ++++ lib/jasmine-core/jasmine.js | 51 ++++++++++++++- spec/core/SpecSpec.js | 109 ++++++++++++++++++++++++++++++- spec/core/baseSpec.js | 8 +++ spec/core/integration/EnvSpec.js | 83 +++++++++++++++++++++++ spec/html/HtmlReporterSpec.js | 35 +++++++++- src/core/Env.js | 10 +++ src/core/Spec.js | 25 ++++++- src/core/base.js | 16 +++++ src/html/HtmlReporter.js | 44 +++++++++++++ src/html/_HTMLReporter.scss | 16 +++++ 12 files changed, 447 insertions(+), 7 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index ba3fb447..8e4917b7 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -436,9 +436,53 @@ jasmineRequire.HtmlReporter = function(j$) { ); } + if (result.trace) { + messages.appendChild(traceTable(result.trace)); + } + return failure; } + function traceTable(trace) { + var tbody = createDom('tbody'); + + trace.forEach(function(entry) { + tbody.appendChild( + createDom( + 'tr', + {}, + createDom('td', {}, entry.timestamp.toString()), + createDom('td', {}, entry.message) + ) + ); + }); + + return createDom( + 'div', + { className: 'jasmine-trace' }, + createDom( + 'div', + { className: 'jasmine-trace-header' }, + 'Trace information' + ), + createDom( + 'table', + {}, + createDom( + 'thead', + {}, + createDom( + 'tr', + {}, + createDom('th', {}, 'Time (ms)'), + createDom('th', {}, 'Message') + ) + ), + tbody + ) + ); + } + function summaryList(resultsTree, domParent) { var specListNode; for (var i = 0; i < resultsTree.children.length; i++) { diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 18b6457c..9c70317f 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -287,4 +287,17 @@ body { display: block; margin-left: 14px; padding: 5px; +} +.jasmine_html-reporter .jasmine-trace { + margin: 5px 0 0 0; + padding: 5px; + color: #666; + border: 1px solid #ddd; + background: white; +} +.jasmine_html-reporter .jasmine-trace table { + border-spacing: 0; +} +.jasmine_html-reporter .jasmine-trace table, .jasmine_html-reporter .jasmine-trace th, .jasmine_html-reporter .jasmine-trace td { + border: 1px solid #ddd; } \ No newline at end of file diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index c88a8725..b91f4ece 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -559,6 +559,22 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { putativeSpy.calls instanceof j$.CallTracker ); }; + + /** + * Logs a message for use in debugging. If the spec fails, trace messages + * will be included in the {@link SpecResult|result} passed to the + * reporter's specDone method. + * + * This method should be called only when a spec (including any associated + * beforeEach or afterEach functions) is running. + * @function + * @name jasmine.trace + * @since 3.10.0 + * @param {String} msg - The message to log + */ + j$.trace = function(msg) { + j$.getEnv().trace(msg); + }; }; getJasmineRequireObj().util = function(j$) { @@ -779,8 +795,9 @@ 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} + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. * @since 2.0.0 -x */ + */ this.result = { id: this.id, description: this.description, @@ -790,7 +807,8 @@ x */ deprecationWarnings: [], pendingReason: '', duration: null, - properties: null + properties: null, + trace: null }; } @@ -835,6 +853,11 @@ x */ self.queueableFn.fn = null; self.result.status = self.status(excluded, failSpecWithNoExp); self.result.duration = self.timer.elapsed(); + + if (self.result.status !== 'failed') { + self.result.trace = null; + } + self.resultCallback(self.result, done); } }; @@ -961,6 +984,20 @@ x */ ); }; + Spec.prototype.trace = function(msg) { + if (!this.result.trace) { + this.result.trace = []; + } + + /** + * @typedef TraceEntry + * @property {String} message - The message that was passed to {@link Env#trace}. + * @property {number} timestamp - The time when the entry was added, in + * milliseconds from the spec's start time + */ + this.result.trace.push({ message: msg, timestamp: this.timer.elapsed() }); + }; + var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), @@ -2217,6 +2254,16 @@ getJasmineRequireObj().Env = function(j$) { currentSuite().setSuiteProperty(key, value); }; + this.trace = function(msg) { + var maybeSpec = currentRunnable(); + + if (!maybeSpec || !maybeSpec.trace) { + throw new Error("'trace' was called when there was no current spec"); + } + + maybeSpec.trace(msg); + }; + this.expect = function(actual) { if (!currentRunnable()) { throw new Error( diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 2a69f78b..5c29b80c 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -224,7 +224,8 @@ describe('Spec', function() { deprecationWarnings: [], pendingReason: '', duration: jasmine.any(Number), - properties: null + properties: null, + trace: null }, 'things' ); @@ -537,4 +538,110 @@ describe('Spec', function() { "'done' callback more than once.\n(in spec: a spec)" ); }); + + describe('#trace', function() { + it('adds the messages to the result', function() { + var timer = jasmine.createSpyObj('timer', ['start', 'elapsed']), + spec = new jasmineUnderTest.Spec({ + queueableFn: { + fn: function() {} + }, + queueRunnerFactory: function() {}, + timer: timer + }), + t1 = 123, + t2 = 456; + + spec.execute(); + expect(spec.result.trace).toBeNull(); + timer.elapsed.and.returnValue(t1); + spec.trace('msg 1'); + expect(spec.result.trace).toEqual([{ message: 'msg 1', timestamp: t1 }]); + timer.elapsed.and.returnValue(t2); + spec.trace('msg 2'); + expect(spec.result.trace).toEqual([ + { message: 'msg 1', timestamp: t1 }, + { message: 'msg 2', timestamp: t2 } + ]); + }); + + describe('When the spec passes', function() { + it('omits the messages from the reported result', function() { + var resultCallback = jasmine.createSpy('resultCallback'), + spec = new jasmineUnderTest.Spec({ + queueableFn: { + fn: function() {} + }, + resultCallback: resultCallback, + queueRunnerFactory: function(config) { + spec.trace('msg'); + config.cleanupFns.forEach(function(fn) { + fn.fn(); + }); + config.onComplete(false); + } + }); + + spec.execute(function() {}); + expect(resultCallback).toHaveBeenCalledWith( + jasmine.objectContaining({ trace: null }), + undefined + ); + }); + + it('removes the messages to save memory', function() { + var resultCallback = jasmine.createSpy('resultCallback'), + spec = new jasmineUnderTest.Spec({ + queueableFn: { + fn: function() {} + }, + resultCallback: resultCallback, + queueRunnerFactory: function(config) { + spec.trace('msg'); + config.cleanupFns.forEach(function(fn) { + fn.fn(); + }); + config.onComplete(false); + } + }); + + spec.execute(function() {}); + expect(resultCallback).toHaveBeenCalled(); + expect(spec.result.trace).toBeNull(); + }); + }); + + describe('When the spec fails', function() { + it('includes the messages in the reported result', function() { + var resultCallback = jasmine.createSpy('resultCallback'), + timer = jasmine.createSpyObj('timer', ['start', 'elapsed']), + spec = new jasmineUnderTest.Spec({ + queueableFn: { + fn: function() {} + }, + resultCallback: resultCallback, + queueRunnerFactory: function(config) { + spec.trace('msg'); + spec.onException(new Error('nope')); + config.cleanupFns.forEach(function(fn) { + fn.fn(); + }); + config.onComplete(true); + }, + timer: timer + }), + timestamp = 12345; + + timer.elapsed.and.returnValue(timestamp); + + spec.execute(function() {}); + expect(resultCallback).toHaveBeenCalledWith( + jasmine.objectContaining({ + trace: [{ message: 'msg', timestamp: timestamp }] + }), + undefined + ); + }); + }); + }); }); diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 67e264a5..9cd94bd7 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -198,4 +198,12 @@ describe('base helpers', function() { }); }); }); + + describe('trace', function() { + it("forwards to the current env's trace function", function() { + spyOn(jasmineUnderTest.getEnv(), 'trace'); + jasmineUnderTest.trace('a message'); + expect(jasmineUnderTest.getEnv().trace).toHaveBeenCalledWith('a message'); + }); + }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 76c80d03..09d3947d 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3324,4 +3324,87 @@ describe('Env integration', function() { }); }); }); + + it('sends traces to the reporter when the spec fails', function(done) { + var reporter = jasmine.createSpyObj('reporter', ['specDone']), + startTime, + endTime; + + env.addReporter(reporter); + env.configure({ random: false }); + + env.it('fails', function() { + startTime = new Date().getTime(); + env.trace('message 1'); + env.trace('message 2'); + env.expect(1).toBe(2); + endTime = new Date().getTime(); + }); + + env.it('passes', function() { + env.trace('message that should not be reported'); + }); + + env.execute(null, function() { + function numberInRange(min, max) { + return { + asymmetricMatch: function(compareTo) { + return compareTo >= min && compareTo <= max; + }, + jasmineToString: function(pp) { + return ''; + } + }; + } + + var duration; + + expect(reporter.specDone).toHaveBeenCalledTimes(2); + duration = reporter.specDone.calls.argsFor(0)[0].duration; + expect(reporter.specDone.calls.argsFor(0)[0]).toEqual( + jasmine.objectContaining({ + trace: [ + { + timestamp: numberInRange(0, duration), + message: 'message 1' + }, + { + timestamp: numberInRange(0, duration), + message: 'message 2' + } + ] + }) + ); + expect(reporter.specDone.calls.argsFor(1)[0].trace).toBeFalsy(); + done(); + }); + }); + + it('reports an error when trace is used when a spec is not running', function(done) { + var reporter = jasmine.createSpyObj('reporter', ['suiteDone']); + + env.describe('a suite', function() { + env.beforeAll(function() { + env.trace('a message'); + }); + + env.it('a spec', function() {}); + }); + + env.addReporter(reporter); + env.execute(null, function() { + expect(reporter.suiteDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + failedExpectations: [ + jasmine.objectContaining({ + message: jasmine.stringContaining( + "'trace' was called when there was no current spec" + ) + }) + ] + }) + ); + done(); + }); + }); }); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index b99751bc..19e2ef97 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -1514,6 +1514,23 @@ describe('HtmlReporter', function() { } ] }; + var failingSpecResultWithTrace = { + id: 567, + status: 'failed', + description: 'a failing spec', + fullName: 'a suite inner suite a failing spec', + passedExpectations: [], + failedExpectations: [ + { + message: 'a failure message', + stack: 'a stack trace' + } + ], + trace: [ + { timestamp: 123, message: 'msg 1' }, + { timestamp: 456, message: 'msg 1' } + ] + }; var passingSuiteResult = { id: 1, @@ -1531,18 +1548,20 @@ describe('HtmlReporter', function() { reporter.suiteDone(passingSuiteResult); reporter.suiteDone(failingSuiteResult); reporter.suiteDone(passingSuiteResult); + reporter.specStarted(failingSpecResultWithTrace); + reporter.specDone(failingSpecResultWithTrace); reporter.jasmineDone({}); }); it('reports the specs counts', function() { var alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); - expect(alertBar.innerHTML).toMatch(/2 specs, 2 failure/); + expect(alertBar.innerHTML).toMatch(/3 specs, 3 failures/); }); it('reports failure messages and stack traces', function() { var specFailures = container.querySelector('.jasmine-failures'); - expect(specFailures.childNodes.length).toEqual(2); + expect(specFailures.childNodes.length).toEqual(3); var specFailure = specFailures.childNodes[0]; expect(specFailure.getAttribute('class')).toMatch(/jasmine-failed/); @@ -1583,6 +1602,18 @@ describe('HtmlReporter', function() { expect(suiteStackTrace.innerHTML).toEqual('a stack trace'); }); + it('reports traces when present', function() { + var specFailure = container.querySelectorAll( + '.jasmine-spec-detail.jasmine-failed' + )[2], + trace = specFailure.querySelector('.jasmine-trace table'), + rows; + + expect(trace).toBeTruthy(); + rows = trace.querySelectorAll('tbody tr'); + expect(rows.length).toEqual(2); + }); + it('provides links to focus on a failure and each containing suite', function() { var description = container.querySelector( '.jasmine-failures .jasmine-description' diff --git a/src/core/Env.js b/src/core/Env.js index 278162a8..0dd7930e 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -1148,6 +1148,16 @@ getJasmineRequireObj().Env = function(j$) { currentSuite().setSuiteProperty(key, value); }; + this.trace = function(msg) { + var maybeSpec = currentRunnable(); + + if (!maybeSpec || !maybeSpec.trace) { + throw new Error("'trace' was called when there was no current spec"); + } + + maybeSpec.trace(msg); + }; + this.expect = function(actual) { if (!currentRunnable()) { throw new Error( diff --git a/src/core/Spec.js b/src/core/Spec.js index 9c85902e..458eb751 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -69,8 +69,9 @@ 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} + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. * @since 2.0.0 -x */ + */ this.result = { id: this.id, description: this.description, @@ -80,7 +81,8 @@ x */ deprecationWarnings: [], pendingReason: '', duration: null, - properties: null + properties: null, + trace: null }; } @@ -125,6 +127,11 @@ x */ self.queueableFn.fn = null; self.result.status = self.status(excluded, failSpecWithNoExp); self.result.duration = self.timer.elapsed(); + + if (self.result.status !== 'failed') { + self.result.trace = null; + } + self.resultCallback(self.result, done); } }; @@ -251,6 +258,20 @@ x */ ); }; + Spec.prototype.trace = function(msg) { + if (!this.result.trace) { + this.result.trace = []; + } + + /** + * @typedef TraceEntry + * @property {String} message - The message that was passed to {@link Env#trace}. + * @property {number} timestamp - The time when the entry was added, in + * milliseconds from the spec's start time + */ + this.result.trace.push({ message: msg, timestamp: this.timer.elapsed() }); + }; + var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), diff --git a/src/core/base.js b/src/core/base.js index aeef38b1..c0a13503 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -397,4 +397,20 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { putativeSpy.calls instanceof j$.CallTracker ); }; + + /** + * Logs a message for use in debugging. If the spec fails, trace messages + * will be included in the {@link SpecResult|result} passed to the + * reporter's specDone method. + * + * This method should be called only when a spec (including any associated + * beforeEach or afterEach functions) is running. + * @function + * @name jasmine.trace + * @since 3.10.0 + * @param {String} msg - The message to log + */ + j$.trace = function(msg) { + j$.getEnv().trace(msg); + }; }; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 802c484d..7a3afc41 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -405,9 +405,53 @@ jasmineRequire.HtmlReporter = function(j$) { ); } + if (result.trace) { + messages.appendChild(traceTable(result.trace)); + } + return failure; } + function traceTable(trace) { + var tbody = createDom('tbody'); + + trace.forEach(function(entry) { + tbody.appendChild( + createDom( + 'tr', + {}, + createDom('td', {}, entry.timestamp.toString()), + createDom('td', {}, entry.message) + ) + ); + }); + + return createDom( + 'div', + { className: 'jasmine-trace' }, + createDom( + 'div', + { className: 'jasmine-trace-header' }, + 'Trace information' + ), + createDom( + 'table', + {}, + createDom( + 'thead', + {}, + createDom( + 'tr', + {}, + createDom('th', {}, 'Time (ms)'), + createDom('th', {}, 'Message') + ) + ), + tbody + ) + ); + } + function summaryList(resultsTree, domParent) { var specListNode; for (var i = 0; i < resultsTree.children.length; i++) { diff --git a/src/html/_HTMLReporter.scss b/src/html/_HTMLReporter.scss index dc06ff95..bd8537c4 100644 --- a/src/html/_HTMLReporter.scss +++ b/src/html/_HTMLReporter.scss @@ -413,4 +413,20 @@ body { margin-left: $margin-unit; padding: 5px; } + + .jasmine-trace { + margin: 5px 0 0 0; + padding: 5px; + color: $light-text-color; + border: 1px solid #ddd; + background: white; + + table { + border-spacing: 0; + } + + table, th, td { + border: 1px solid #ddd; + } + } } From b2067d9ce0f945077c473706659dfa8beb85fbe4 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 2 Oct 2021 09:58:47 -0700 Subject: [PATCH 31/71] Fixed references to Env#trace in jsdocs --- lib/jasmine-core/jasmine.js | 4 ++-- src/core/Spec.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b91f4ece..74bfe154 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -795,7 +795,7 @@ 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} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link jasmine.trace} during a failing spec. * @since 2.0.0 */ this.result = { @@ -991,7 +991,7 @@ getJasmineRequireObj().Spec = function(j$) { /** * @typedef TraceEntry - * @property {String} message - The message that was passed to {@link Env#trace}. + * @property {String} message - The message that was passed to {@link jasmine.trace}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ diff --git a/src/core/Spec.js b/src/core/Spec.js index 458eb751..6198d24f 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -69,7 +69,7 @@ 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} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link jasmine.trace} during a failing spec. * @since 2.0.0 */ this.result = { @@ -265,7 +265,7 @@ getJasmineRequireObj().Spec = function(j$) { /** * @typedef TraceEntry - * @property {String} message - The message that was passed to {@link Env#trace}. + * @property {String} message - The message that was passed to {@link jasmine.trace}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ From a1f14efac611957479df42cda3253878436ff02e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 25 Sep 2021 17:47:49 -0700 Subject: [PATCH 32/71] Improved specs for stopSpecOnExpectationFailure * #1533 --- spec/core/integration/SpecRunningSpec.js | 322 +++++++++++++++++++++-- 1 file changed, 299 insertions(+), 23 deletions(-) diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 8033ceb5..b275ed22 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -792,8 +792,198 @@ describe('spec running', function() { }); }); - describe('When stopSpecOnExpectationFailure is set', function() { - it('skips to cleanup functions after an error', function(done) { + describe('When stopSpecOnExpectationFailure is true', function() { + it('skips to cleanup functions after a thrown error', function(done) { + var actions = []; + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + throw new Error('error'); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + env.execute(null, function() { + expect(actions).toEqual([ + 'outer beforeEach', + 'inner afterEach', + 'outer afterEach' + ]); + done(); + }); + }); + + it('skips to cleanup functions after a rejected promise', async function() { + var actions = []; + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + return Promise.reject(new Error('error')); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + await env.execute(); + + expect(actions).toEqual([ + 'outer beforeEach', + 'inner afterEach', + 'outer afterEach' + ]); + }); + + it('skips to cleanup functions after an expectation failure', async function() { + var actions = []; + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + env.expect(1).toBe(2); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + await env.execute(); + + expect(actions).toEqual([ + 'outer beforeEach', + 'inner afterEach', + 'outer afterEach' + ]); + }); + + it('skips to cleanup functions after done.fail is called', function(done) { + var actions = []; + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.describe('Something', function() { + env.beforeEach(function(done) { + actions.push('beforeEach'); + done.fail('error'); + actions.push('after done.fail'); + }); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it', function() { + actions.push('it'); + }); + }); + + env.execute(null, function() { + expect(actions).toEqual(['beforeEach', 'afterEach']); + done(); + }); + }); + + it('skips to cleanup functions when an async function times out', function(done) { + var actions = []; + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.describe('Something', function() { + env.beforeEach(function(innerDone) { + actions.push('beforeEach'); + }, 1); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it', function() { + actions.push('it'); + }); + }); + + env.execute(null, function() { + expect(actions).toEqual(['beforeEach', 'afterEach']); + done(); + }); + }); + + it('runs all reporter callbacks even if one fails', async function() { + var laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); + + env.configure({ stopSpecOnExpectationFailure: true }); + + env.it('a spec', function() {}); + env.addReporter({ + specDone: function() { + throw new Error('nope'); + } + }); + env.addReporter(laterReporter); + + await env.execute(); + + expect(laterReporter.specDone).toHaveBeenCalled(); + }); + }); + + describe('When stopSpecOnExpectationFailure is false', function() { + it('does not skip anything after a thrown error', async function() { var actions = []; env.describe('Something', function() { @@ -821,26 +1011,102 @@ describe('spec running', function() { }); }); - env.configure({ stopSpecOnExpectationFailure: true }); + await env.execute(); - env.execute(null, function() { - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); - done(); - }); + expect(actions).toEqual([ + 'outer beforeEach', + 'inner beforeEach', + 'inner it', + 'inner afterEach', + 'outer afterEach' + ]); }); - it('skips to cleanup functions after done.fail is called', function(done) { + it('does not skip anything after a rejected promise', async function() { + var actions = []; + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + return Promise.reject(new Error('error')); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + await env.execute(); + + expect(actions).toEqual([ + 'outer beforeEach', + 'inner beforeEach', + 'inner it', + 'inner afterEach', + 'outer afterEach' + ]); + }); + + it('does not skip anything after an expectation failure', async function() { + var actions = []; + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + env.expect(1).toBe(2); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + await env.execute(); + + expect(actions).toEqual([ + 'outer beforeEach', + 'inner beforeEach', + 'inner it', + 'inner afterEach', + 'outer afterEach' + ]); + }); + + it('does not skip anything after done.fail is called', async function() { var actions = []; env.describe('Something', function() { env.beforeEach(function(done) { actions.push('beforeEach'); done.fail('error'); - actions.push('after done.fail'); }); env.afterEach(function() { @@ -852,15 +1118,12 @@ describe('spec running', function() { }); }); - env.configure({ stopSpecOnExpectationFailure: true }); + await env.execute(); - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - done(); - }); + expect(actions).toEqual(['beforeEach', 'it', 'afterEach']); }); - it('skips to cleanup functions when an async function times out', function(done) { + it('does not skip anything when an async function times out', async function() { var actions = []; env.describe('Something', function() { @@ -877,12 +1140,25 @@ describe('spec running', function() { }); }); - env.configure({ stopSpecOnExpectationFailure: true }); + await env.execute(); - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - done(); + expect(actions).toEqual(['beforeEach', 'it', 'afterEach']); + }); + + it('runs all reporter callbacks even if one fails', async function() { + var laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); + + env.it('a spec', function() {}); + env.addReporter({ + specDone: function() { + throw new Error('nope'); + } }); + env.addReporter(laterReporter); + + await env.execute(); + + expect(laterReporter.specDone).toHaveBeenCalled(); }); }); From 457a2727badcc255124c096a4d71819566bdc893 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 29 Sep 2021 12:35:00 -0700 Subject: [PATCH 33/71] Skip to afterEach fns when a beforeEach fn errors * #1533 --- lib/jasmine-core/jasmine.js | 2 +- spec/core/integration/SpecRunningSpec.js | 16 ++++++---------- src/core/Env.js | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 74bfe154..b2fcceda 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1610,7 +1610,7 @@ getJasmineRequireObj().Env = function(j$) { var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { - failFast = config.stopSpecOnExpectationFailure; + failFast = true; } else if (!options.isReporter) { failFast = config.stopOnSpecFailure; } diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index b275ed22..52d8ab32 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -983,7 +983,7 @@ describe('spec running', function() { }); describe('When stopSpecOnExpectationFailure is false', function() { - it('does not skip anything after a thrown error', async function() { + it('skips to cleanup functions after a thrown error', async function() { var actions = []; env.describe('Something', function() { @@ -1015,14 +1015,12 @@ describe('spec running', function() { expect(actions).toEqual([ 'outer beforeEach', - 'inner beforeEach', - 'inner it', 'inner afterEach', 'outer afterEach' ]); }); - it('does not skip anything after a rejected promise', async function() { + it('skips to cleanup functions after a rejected promise', async function() { var actions = []; env.describe('Something', function() { @@ -1054,8 +1052,6 @@ describe('spec running', function() { expect(actions).toEqual([ 'outer beforeEach', - 'inner beforeEach', - 'inner it', 'inner afterEach', 'outer afterEach' ]); @@ -1100,7 +1096,7 @@ describe('spec running', function() { ]); }); - it('does not skip anything after done.fail is called', async function() { + it('skips to cleanup functions after done.fail is called', async function() { var actions = []; env.describe('Something', function() { @@ -1120,10 +1116,10 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual(['beforeEach', 'it', 'afterEach']); + expect(actions).toEqual(['beforeEach', 'afterEach']); }); - it('does not skip anything when an async function times out', async function() { + it('skips to cleanup functions when an async function times out', async function() { var actions = []; env.describe('Something', function() { @@ -1142,7 +1138,7 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual(['beforeEach', 'it', 'afterEach']); + expect(actions).toEqual(['beforeEach', 'afterEach']); }); it('runs all reporter callbacks even if one fails', async function() { diff --git a/src/core/Env.js b/src/core/Env.js index 0dd7930e..c6c53950 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -504,7 +504,7 @@ getJasmineRequireObj().Env = function(j$) { var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { - failFast = config.stopSpecOnExpectationFailure; + failFast = true; } else if (!options.isReporter) { failFast = config.stopOnSpecFailure; } From 5eaeeb0b6c8c357667388df89816dd967057d6ca Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 29 Sep 2021 12:14:07 -0700 Subject: [PATCH 34/71] Moved fn skipping policy out of QueueRunner This should allow us to more easily support complex skipping strategies like skipping nested cleanup fns when the corresponding befores were skipped, or skipping specs and suites when a beforeAll fails. * #1533 --- lib/jasmine-core/jasmine.js | 85 +++++++++++++------ .../CompleteOnFirstErrorSkipPolicySpec.js | 45 ++++++++++ spec/core/QueueRunnerSpec.js | 72 ++++++++++++++-- src/core/CompleteOnFirstErrorSkipPolicy.js | 19 +++++ src/core/Env.js | 16 ++-- src/core/NeverSkipPolicy.js | 9 ++ src/core/QueueRunner.js | 35 ++++---- src/core/requireCore.js | 4 + 8 files changed, 228 insertions(+), 57 deletions(-) create mode 100644 spec/core/CompleteOnFirstErrorSkipPolicySpec.js create mode 100644 src/core/CompleteOnFirstErrorSkipPolicy.js create mode 100644 src/core/NeverSkipPolicy.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b2fcceda..1fb3973c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -82,6 +82,10 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.MapContaining = jRequire.MapContaining(j$); j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); + j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( + j$ + ); j$.ReportDispatcher = jRequire.ReportDispatcher(j$); j$.Spec = jRequire.Spec(j$); j$.Spy = jRequire.Spy(j$); @@ -1608,12 +1612,17 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - var failFast = false; - if (options.isLeaf) { - failFast = true; - } else if (!options.isReporter) { - failFast = config.stopOnSpecFailure; + if ( + // A spec + options.isLeaf || + // A suite, and config.stopOnSpecFailure is set + (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) + ) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.NeverSkipPolicy; } + options.clearStack = options.clearStack || clearStack; options.timeout = { setTimeout: realSetTimeout, @@ -1621,7 +1630,6 @@ getJasmineRequireObj().Env = function(j$) { }; options.fail = self.fail; options.globalErrors = globalErrors; - options.completeOnFirstError = failFast; options.onException = options.onException || function(e) { @@ -3380,6 +3388,26 @@ getJasmineRequireObj().Clock = function() { return Clock; }; +getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { + function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.firstCleanupIx_ = firstCleanupIx; + } + + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( + lastRanFnIx, + errored + ) { + if (errored && lastRanFnIx < this.firstCleanupIx_) { + return this.firstCleanupIx_; + } else { + return lastRanFnIx + 1; + } + }; + + return CompleteOnFirstErrorSkipPolicy; +}; + getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function DelayedFunctionScheduler() { var self = this; @@ -7257,6 +7285,16 @@ getJasmineRequireObj().MockDate = function(j$) { return MockDate; }; +getJasmineRequireObj().NeverSkipPolicy = function(j$) { + function NeverSkipPolicy(queueableFns, firstCleanupIx) {} + + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + return lastRanFnIx + 1; + }; + + return NeverSkipPolicy; +}; + getJasmineRequireObj().makePrettyPrinter = function(j$) { function SinglePrettyPrintRun(customObjectFormatters, pp) { this.customObjectFormatters_ = customObjectFormatters; @@ -7721,7 +7759,9 @@ getJasmineRequireObj().QueueRunner = function(j$) { pushListener: emptyFn, popListener: emptyFn }; - this.completeOnFirstError = !!attrs.completeOnFirstError; + + const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; + this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); this.errored = false; if (typeof this.onComplete !== 'function') { @@ -7742,14 +7782,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { this.run(0); }; - QueueRunner.prototype.skipToCleanup = function(lastRanIndex) { - if (lastRanIndex < this.firstCleanupIx) { - this.run(this.firstCleanupIx); - } else { - this.run(lastRanIndex + 1); - } - }; - QueueRunner.prototype.clearTimeout = function(timeoutId) { Function.prototype.apply.apply(this.timeout.clearTimeout, [ j$.getGlobal(), @@ -7790,11 +7822,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { } function runNext() { - if (self.completeOnFirstError && errored) { - self.skipToCleanup(iterativeIndex); - } else { - self.run(iterativeIndex + 1); - } + self.run(self.nextFnIx_(iterativeIndex)); } if (completedSynchronously) { @@ -7892,7 +7920,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { for ( iterativeIndex = recursiveIndex; iterativeIndex < length; - iterativeIndex++ + iterativeIndex = this.nextFnIx_(iterativeIndex) ) { var result = this.attempt(iterativeIndex); @@ -7901,11 +7929,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } self.errored = self.errored || result.errored; - - if (this.completeOnFirstError && result.errored) { - this.skipToCleanup(iterativeIndex); - return; - } } this.clearStack(function() { @@ -7919,6 +7942,16 @@ getJasmineRequireObj().QueueRunner = function(j$) { }); }; + QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { + const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + + if (result === currentFnIx) { + throw new Error("Can't skip to the same queueable fn that just finished"); + } + + return result; + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js new file mode 100644 index 00000000..5c746fb7 --- /dev/null +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -0,0 +1,45 @@ +describe('CompleteOnFirstErrorSkipPolicy', function() { + describe('#skipTo', function() { + describe('When errored is false', function() { + it('returns the next index', function() { + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + arrayOfArbitraryFns(4), + 4 + ); + expect(policy.skipTo(1, false)).toEqual(2); + }); + }); + + describe('When errored is true', function() { + it('returns the first cleanup fn when called with a non cleanup fn', function() { + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + arrayOfArbitraryFns(4), + 2 + ); + + expect(policy.skipTo(0, true)).toEqual(2); + expect(policy.skipTo(1, true)).toEqual(2); + }); + + it('returns the next index when called with a cleanup fn', function() { + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + arrayOfArbitraryFns(4), + 1 + ); + + expect(policy.skipTo(1, true)).toEqual(2); + expect(policy.skipTo(2, true)).toEqual(3); + }); + }); + }); +}); + +function arrayOfArbitraryFns(n) { + const result = []; + + for (let i = 0; i < n; i++) { + result.push({ fn: () => {} }); + } + + return result; +} diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index d9d68d20..180736f2 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -649,6 +649,68 @@ describe('QueueRunner', function() { expect(nextQueueableFn.fn).toHaveBeenCalled(); }); + describe('When configured with a skip policy', function() { + it('instantiates the skip policy', function() { + const SkipPolicy = jasmine.createSpy('SkipPolicy ctor'); + const queueableFns = [{ fn: () => {} }, { fn: () => {} }]; + const cleanupFns = [{ fn: () => {} }]; + + new jasmineUnderTest.QueueRunner({ + queueableFns, + cleanupFns, + SkipPolicy + }); + + expect(SkipPolicy).toHaveBeenCalledWith( + [...queueableFns, ...cleanupFns], + 2 + ); + }); + + it('uses the skip policy to determine which fn to run next', function() { + const queueableFns = [ + { fn: jasmine.createSpy('fn0') }, + { fn: jasmine.createSpy('fn1') }, + { fn: jasmine.createSpy('fn2').and.throwError(new Error('nope')) }, + { fn: jasmine.createSpy('fn3') } + ]; + const skipPolicy = jasmine.createSpyObj('skipPolicy', ['skipTo']); + skipPolicy.skipTo.and.callFake(function(lastRanIx) { + return lastRanIx === 0 ? 2 : lastRanIx + 1; + }); + const queueRunner = new jasmineUnderTest.QueueRunner({ + queueableFns, + SkipPolicy: function() { + return skipPolicy; + } + }); + + queueRunner.execute(); + + expect(skipPolicy.skipTo).toHaveBeenCalledWith(0, false); + expect(skipPolicy.skipTo).toHaveBeenCalledWith(2, true); + expect(queueableFns[0].fn).toHaveBeenCalled(); + expect(queueableFns[1].fn).not.toHaveBeenCalled(); + expect(queueableFns[2].fn).toHaveBeenCalled(); + expect(queueableFns[3].fn).toHaveBeenCalled(); + }); + + it('throws if the skip policy returns the current fn', function() { + const skipPolicy = { skipTo: i => i }; + const queueableFns = [{ fn: () => {} }]; + const queueRunner = new jasmineUnderTest.QueueRunner({ + queueableFns, + SkipPolicy: function() { + return skipPolicy; + } + }); + + expect(function() { + queueRunner.execute(); + }).toThrowError("Can't skip to the same queueable fn that just finished"); + }); + }); + describe('When configured to complete on first error', function() { it('skips to cleanup functions on the first exception', function() { var queueableFn = { @@ -663,7 +725,7 @@ describe('QueueRunner', function() { queueableFns: [queueableFn, nextQueueableFn], cleanupFns: [cleanupFn], onComplete: onComplete, - completeOnFirstError: true + SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); @@ -685,7 +747,7 @@ describe('QueueRunner', function() { queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn], cleanupFns: [cleanupFn1, cleanupFn2], - completeOnFirstError: true + SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); @@ -721,7 +783,7 @@ describe('QueueRunner', function() { }, queueableFns: [queueableFn, nextQueueableFn], cleanupFns: [cleanupFn], - completeOnFirstError: true + SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }), queueableFnDone; @@ -744,7 +806,7 @@ describe('QueueRunner', function() { queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn], cleanupFns: [cleanupFn], - completeOnFirstError: true + SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); @@ -764,7 +826,7 @@ describe('QueueRunner', function() { queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn, nextQueueableFn], cleanupFns: [cleanupFn], - completeOnFirstError: true + SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); queueRunner.execute(); diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js new file mode 100644 index 00000000..89a6070f --- /dev/null +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -0,0 +1,19 @@ +getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { + function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.firstCleanupIx_ = firstCleanupIx; + } + + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( + lastRanFnIx, + errored + ) { + if (errored && lastRanFnIx < this.firstCleanupIx_) { + return this.firstCleanupIx_; + } else { + return lastRanFnIx + 1; + } + }; + + return CompleteOnFirstErrorSkipPolicy; +}; diff --git a/src/core/Env.js b/src/core/Env.js index c6c53950..15f06f6a 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -502,12 +502,17 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - var failFast = false; - if (options.isLeaf) { - failFast = true; - } else if (!options.isReporter) { - failFast = config.stopOnSpecFailure; + if ( + // A spec + options.isLeaf || + // A suite, and config.stopOnSpecFailure is set + (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) + ) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.NeverSkipPolicy; } + options.clearStack = options.clearStack || clearStack; options.timeout = { setTimeout: realSetTimeout, @@ -515,7 +520,6 @@ getJasmineRequireObj().Env = function(j$) { }; options.fail = self.fail; options.globalErrors = globalErrors; - options.completeOnFirstError = failFast; options.onException = options.onException || function(e) { diff --git a/src/core/NeverSkipPolicy.js b/src/core/NeverSkipPolicy.js new file mode 100644 index 00000000..c256bd3c --- /dev/null +++ b/src/core/NeverSkipPolicy.js @@ -0,0 +1,9 @@ +getJasmineRequireObj().NeverSkipPolicy = function(j$) { + function NeverSkipPolicy(queueableFns, firstCleanupIx) {} + + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + return lastRanFnIx + 1; + }; + + return NeverSkipPolicy; +}; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 8d485424..03089d0c 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -56,7 +56,9 @@ getJasmineRequireObj().QueueRunner = function(j$) { pushListener: emptyFn, popListener: emptyFn }; - this.completeOnFirstError = !!attrs.completeOnFirstError; + + const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; + this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); this.errored = false; if (typeof this.onComplete !== 'function') { @@ -77,14 +79,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { this.run(0); }; - QueueRunner.prototype.skipToCleanup = function(lastRanIndex) { - if (lastRanIndex < this.firstCleanupIx) { - this.run(this.firstCleanupIx); - } else { - this.run(lastRanIndex + 1); - } - }; - QueueRunner.prototype.clearTimeout = function(timeoutId) { Function.prototype.apply.apply(this.timeout.clearTimeout, [ j$.getGlobal(), @@ -125,11 +119,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { } function runNext() { - if (self.completeOnFirstError && errored) { - self.skipToCleanup(iterativeIndex); - } else { - self.run(iterativeIndex + 1); - } + self.run(self.nextFnIx_(iterativeIndex)); } if (completedSynchronously) { @@ -227,7 +217,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { for ( iterativeIndex = recursiveIndex; iterativeIndex < length; - iterativeIndex++ + iterativeIndex = this.nextFnIx_(iterativeIndex) ) { var result = this.attempt(iterativeIndex); @@ -236,11 +226,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } self.errored = self.errored || result.errored; - - if (this.completeOnFirstError && result.errored) { - this.skipToCleanup(iterativeIndex); - return; - } } this.clearStack(function() { @@ -254,6 +239,16 @@ getJasmineRequireObj().QueueRunner = function(j$) { }); }; + QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { + const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + + if (result === currentFnIx) { + throw new Error("Can't skip to the same queueable fn that just finished"); + } + + return result; + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; diff --git a/src/core/requireCore.js b/src/core/requireCore.js index a185bd47..08c1e006 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -60,6 +60,10 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.MapContaining = jRequire.MapContaining(j$); j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); + j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( + j$ + ); j$.ReportDispatcher = jRequire.ReportDispatcher(j$); j$.Spec = jRequire.Spec(j$); j$.Spy = jRequire.Spy(j$); From 5f1ef5ac2bc0d6738f12c4d92a17a4a3be8337d7 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 30 Sep 2021 10:19:58 -0700 Subject: [PATCH 35/71] Skip everything except afterAll fns when a beforeAll fn errors * Fixes #1533 --- lib/jasmine-core/jasmine.js | 104 +++++++++++++----- package.json | 3 + .../CompleteOnFirstErrorSkipPolicySpec.js | 16 +-- spec/core/QueueRunnerSpec.js | 10 +- .../core/SkipAfterBeforeAllErrorPolicySpec.js | 65 +++++++++++ spec/core/TreeProcessorSpec.js | 23 ++-- spec/core/integration/SpecRunningSpec.js | 62 +++++++++++ src/core/CompleteOnFirstErrorSkipPolicy.js | 13 ++- src/core/Env.js | 16 ++- src/core/NeverSkipPolicy.js | 4 +- src/core/QueueRunner.js | 24 ++-- src/core/SkipAfterBeforeAllErrorPolicy.js | 32 ++++++ src/core/TreeProcessor.js | 11 +- src/core/requireCore.js | 3 + 14 files changed, 316 insertions(+), 70 deletions(-) create mode 100644 spec/core/SkipAfterBeforeAllErrorPolicySpec.js create mode 100644 src/core/SkipAfterBeforeAllErrorPolicy.js diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 1fb3973c..638f7410 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -83,6 +83,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( + j$ + ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ ); @@ -1612,15 +1615,19 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - if ( + if (options.isLeaf) { // A spec - options.isLeaf || - // A suite, and config.stopOnSpecFailure is set - (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) - ) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; - } else { + } else if (options.isReporter) { + // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; + } else { + // A suite + if (config.stopOnSpecFailure) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; + } } options.clearStack = options.clearStack || clearStack; @@ -3390,21 +3397,22 @@ getJasmineRequireObj().Clock = function() { getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { - this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; + this.skipping_ = false; } - CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( - lastRanFnIx, - errored - ) { - if (errored && lastRanFnIx < this.firstCleanupIx_) { + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { return this.firstCleanupIx_; } else { return lastRanFnIx + 1; } }; + CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { + this.skipping_ = true; + }; + return CompleteOnFirstErrorSkipPolicy; }; @@ -7288,10 +7296,12 @@ getJasmineRequireObj().MockDate = function(j$) { getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns, firstCleanupIx) {} - NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; + NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; + return NeverSkipPolicy; }; @@ -7762,7 +7772,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); - this.errored = false; + this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); @@ -7818,7 +7828,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } - self.errored = errored = true; + self.recordError_(iterativeIndex); } function runNext() { @@ -7844,7 +7854,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } ), - errored = false, timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, @@ -7852,7 +7861,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { next.fail = function nextFail() { self.fail.apply(null, arguments); - self.errored = errored = true; + self.recordError_(iterativeIndex); next(); }; @@ -7895,15 +7904,15 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } catch (e) { onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } cleanup(); - return { completedSynchronously: true, errored: errored }; + return { completedSynchronously: true }; function onException(e) { self.onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } function onPromiseRejection(e) { @@ -7927,14 +7936,12 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!result.completedSynchronously) { return; } - - self.errored = self.errored || result.errored; } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); - if (self.errored) { + if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); @@ -7943,7 +7950,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { - const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); @@ -7952,6 +7959,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { return result; }; + QueueRunner.prototype.recordError_ = function(currentFnIx) { + this.errored_ = true; + this.skipPolicy_.fnErrored(currentFnIx); + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; @@ -8496,6 +8508,39 @@ getJasmineRequireObj().interface = function(jasmine, env) { return jasmineInterface; }; +getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { + function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.skipping_ = false; + } + + SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_) { + return this.nextAfterAllAfter_(lastRanFnIx); + } else { + return lastRanFnIx + 1; + } + }; + + SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { + for ( + i++; + i < this.queueableFns_.length && + this.queueableFns_[i].type !== 'afterAll'; + i++ + ) {} + return i; + }; + + SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { + if (this.queueableFns_[fnIx].type === 'beforeAll') { + this.skipping_ = true; + } + }; + + return SkipAfterBeforeAllErrorPolicy; +}; + getJasmineRequireObj().Spy = function(j$) { var nextOrder = (function() { var order = 0; @@ -9942,7 +9987,16 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns.concat(result).concat(node.afterAllFns); + return node.beforeAllFns + .map(function(fn) { + return { type: 'beforeAll', ...fn }; + }) + .concat(result) + .concat( + node.afterAllFns.map(function(fn) { + return { type: 'afterAll', ...fn }; + }) + ); } } diff --git a/package.json b/package.json index 9edf722e..b7cbb3fa 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,9 @@ "node": true, "es2017": true }, + "parserOptions": { + "ecmaVersion": 2018 + }, "rules": { "quotes": [ "error", diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index 5c746fb7..1064cc03 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -1,24 +1,25 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { describe('#skipTo', function() { - describe('When errored is false', function() { + describe('Before anything has errored', function() { it('returns the next index', function() { const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( arrayOfArbitraryFns(4), 4 ); - expect(policy.skipTo(1, false)).toEqual(2); + expect(policy.skipTo(1)).toEqual(2); }); }); - describe('When errored is true', function() { + describe('After something has errored', function() { it('returns the first cleanup fn when called with a non cleanup fn', function() { const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( arrayOfArbitraryFns(4), 2 ); - expect(policy.skipTo(0, true)).toEqual(2); - expect(policy.skipTo(1, true)).toEqual(2); + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(2); + expect(policy.skipTo(1)).toEqual(2); }); it('returns the next index when called with a cleanup fn', function() { @@ -27,8 +28,9 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { 1 ); - expect(policy.skipTo(1, true)).toEqual(2); - expect(policy.skipTo(2, true)).toEqual(3); + policy.fnErrored(0); + expect(policy.skipTo(1)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); }); }); }); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 180736f2..87f575fe 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -674,7 +674,10 @@ describe('QueueRunner', function() { { fn: jasmine.createSpy('fn2').and.throwError(new Error('nope')) }, { fn: jasmine.createSpy('fn3') } ]; - const skipPolicy = jasmine.createSpyObj('skipPolicy', ['skipTo']); + const skipPolicy = jasmine.createSpyObj('skipPolicy', [ + 'skipTo', + 'fnErrored' + ]); skipPolicy.skipTo.and.callFake(function(lastRanIx) { return lastRanIx === 0 ? 2 : lastRanIx + 1; }); @@ -687,8 +690,9 @@ describe('QueueRunner', function() { queueRunner.execute(); - expect(skipPolicy.skipTo).toHaveBeenCalledWith(0, false); - expect(skipPolicy.skipTo).toHaveBeenCalledWith(2, true); + expect(skipPolicy.skipTo).toHaveBeenCalledWith(0); + expect(skipPolicy.skipTo).toHaveBeenCalledWith(2); + expect(skipPolicy.fnErrored).toHaveBeenCalledWith(2); expect(queueableFns[0].fn).toHaveBeenCalled(); expect(queueableFns[1].fn).not.toHaveBeenCalled(); expect(queueableFns[2].fn).toHaveBeenCalled(); diff --git a/spec/core/SkipAfterBeforeAllErrorPolicySpec.js b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js new file mode 100644 index 00000000..13a1e9ba --- /dev/null +++ b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js @@ -0,0 +1,65 @@ +describe('SkipAfterBeforeAllErrorPolicy', function() { + describe('#skipTo', function() { + describe('When nothing has errored', function() { + it('does not skip anything', function() { + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + arrayOfArbitraryFns(4), + 2 + ); + + expect(policy.skipTo(0)).toEqual(1); + expect(policy.skipTo(1)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + + describe('When anything but a beforeAll has errored', function() { + it('does not skip anything', function() { + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + arrayOfArbitraryFns(4), + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(1); + policy.fnErrored(1); + expect(policy.skipTo(1)).toEqual(2); + policy.fnErrored(2); + expect(policy.skipTo(2)).toEqual(3); + policy.fnErrored(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + + describe('When a beforeAll has errored', function() { + it('skips subsequent functions other than afterAll', function() { + const fns = [ + { type: 'beforeAll', fn: () => {} }, + { fn: () => {} }, + { fn: () => {} }, + { type: 'afterAll', fn: () => {} }, + { type: 'afterAll', fn: () => {} } + ]; + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + }); +}); + +function arrayOfArbitraryFns(n) { + const result = []; + + for (let i = 0; i < n; i++) { + result.push({ fn: () => {} }); + } + + return result; +} diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index b494d1ac..a3967d42 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -482,7 +482,10 @@ describe('TreeProcessor', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], - beforeAllFns: ['beforeAll1', 'beforeAll2'] + beforeAllFns: [ + { fn: 'beforeAll1', timeout: 1 }, + { fn: 'beforeAll2', timeout: 2 } + ] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -502,8 +505,8 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, - 'beforeAll1', - 'beforeAll2', + { type: 'beforeAll', fn: 'beforeAll1', timeout: 1 }, + { type: 'beforeAll', fn: 'beforeAll2', timeout: 2 }, { fn: jasmine.any(Function) } ]); }); @@ -512,7 +515,7 @@ describe('TreeProcessor', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], - afterAllFns: ['afterAll1', 'afterAll2'] + afterAllFns: [{ fn: 'afterAll1' }, { fn: 'afterAll2' }] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -533,15 +536,15 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) }, - 'afterAll1', - 'afterAll2' + { type: 'afterAll', fn: 'afterAll1' }, + { type: 'afterAll', fn: 'afterAll2' } ]); }); it('does not run beforeAlls or afterAlls for a node with no children', function() { var node = new Node({ - beforeAllFns: ['before'], - afterAllFns: ['after'] + beforeAllFns: [{ fn: 'before' }], + afterAllFns: [{ fn: 'after' }] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -566,8 +569,8 @@ describe('TreeProcessor', function() { var leaf = new Leaf({ markedPending: true }), node = new Node({ children: [leaf], - beforeAllFns: ['before'], - afterAllFns: ['after'], + beforeAllFns: [{ fn: 'before' }], + afterAllFns: [{ fn: 'after' }], markedPending: false }), root = new Node({ children: [node] }), diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 52d8ab32..60b9c0e4 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1158,6 +1158,68 @@ describe('spec running', function() { }); }); + describe('When a beforeAll function fails', function() { + it('skips contained specs and suites', async function() { + const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); + const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); + const outerAfterEach = jasmine.createSpy('outerAfterEach'); + const nestedAfterEach = jasmine.createSpy('nestedAfterEach'); + const outerIt = jasmine.createSpy('outerIt'); + const nestedIt = jasmine.createSpy('nestedIt'); + const nestedBeforeAll = jasmine.createSpy('nestedBeforeAll'); + + env.beforeAll(function() { + throw new Error('nope'); + }); + + env.beforeEach(outerBeforeEach); + env.it('a spec', outerIt); + env.describe('a nested suite', function() { + env.beforeAll(nestedBeforeAll); + env.beforeEach(nestedBeforeEach); + env.it('a nested spec', nestedIt); + env.afterEach(nestedAfterEach); + }); + env.afterEach(outerAfterEach); + + await env.execute(); + + expect(outerBeforeEach).not.toHaveBeenCalled(); + expect(outerIt).not.toHaveBeenCalled(); + expect(nestedBeforeAll).not.toHaveBeenCalled(); + expect(nestedBeforeEach).not.toHaveBeenCalled(); + expect(nestedIt).not.toHaveBeenCalled(); + expect(nestedAfterEach).not.toHaveBeenCalled(); + expect(outerAfterEach).not.toHaveBeenCalled(); + }); + + it('runs afterAll functions in the current suite and outer scopes', async function() { + const outerAfterAll = jasmine.createSpy('outerAfterAll'); + const nestedAfterAll = jasmine.createSpy('nestedAfterAll'); + const secondNestedAfterAll = jasmine.createSpy('secondNestedAfterAll'); + + env.describe('a nested suite', function() { + env.beforeAll(function() { + throw new Error('nope'); + }); + + env.describe('more nesting', function() { + env.it('a nested spec', function() {}); + env.afterAll(secondNestedAfterAll); + }); + + env.afterAll(nestedAfterAll); + }); + env.afterAll(outerAfterAll); + + await env.execute(); + + expect(secondNestedAfterAll).not.toHaveBeenCalled(); + expect(nestedAfterAll).toHaveBeenCalled(); + expect(outerAfterAll).toHaveBeenCalled(); + }); + }); + describe('when stopOnSpecFailure is on', function() { it('does not run further specs when one fails', function(done) { var actions = [], diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index 89a6070f..d99e0124 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -1,19 +1,20 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { - this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; + this.skipping_ = false; } - CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( - lastRanFnIx, - errored - ) { - if (errored && lastRanFnIx < this.firstCleanupIx_) { + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { return this.firstCleanupIx_; } else { return lastRanFnIx + 1; } }; + CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { + this.skipping_ = true; + }; + return CompleteOnFirstErrorSkipPolicy; }; diff --git a/src/core/Env.js b/src/core/Env.js index 15f06f6a..ce6cf454 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -502,15 +502,19 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - if ( + if (options.isLeaf) { // A spec - options.isLeaf || - // A suite, and config.stopOnSpecFailure is set - (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) - ) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; - } else { + } else if (options.isReporter) { + // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; + } else { + // A suite + if (config.stopOnSpecFailure) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; + } } options.clearStack = options.clearStack || clearStack; diff --git a/src/core/NeverSkipPolicy.js b/src/core/NeverSkipPolicy.js index c256bd3c..75fb78d9 100644 --- a/src/core/NeverSkipPolicy.js +++ b/src/core/NeverSkipPolicy.js @@ -1,9 +1,11 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns, firstCleanupIx) {} - NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; + NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; + return NeverSkipPolicy; }; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 03089d0c..9223c5e0 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -59,7 +59,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); - this.errored = false; + this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); @@ -115,7 +115,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } - self.errored = errored = true; + self.recordError_(iterativeIndex); } function runNext() { @@ -141,7 +141,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } ), - errored = false, timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, @@ -149,7 +148,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { next.fail = function nextFail() { self.fail.apply(null, arguments); - self.errored = errored = true; + self.recordError_(iterativeIndex); next(); }; @@ -192,15 +191,15 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } catch (e) { onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } cleanup(); - return { completedSynchronously: true, errored: errored }; + return { completedSynchronously: true }; function onException(e) { self.onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } function onPromiseRejection(e) { @@ -224,14 +223,12 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!result.completedSynchronously) { return; } - - self.errored = self.errored || result.errored; } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); - if (self.errored) { + if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); @@ -240,7 +237,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { - const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); @@ -249,6 +246,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { return result; }; + QueueRunner.prototype.recordError_ = function(currentFnIx) { + this.errored_ = true; + this.skipPolicy_.fnErrored(currentFnIx); + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; diff --git a/src/core/SkipAfterBeforeAllErrorPolicy.js b/src/core/SkipAfterBeforeAllErrorPolicy.js new file mode 100644 index 00000000..e2d37630 --- /dev/null +++ b/src/core/SkipAfterBeforeAllErrorPolicy.js @@ -0,0 +1,32 @@ +getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { + function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.skipping_ = false; + } + + SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_) { + return this.nextAfterAllAfter_(lastRanFnIx); + } else { + return lastRanFnIx + 1; + } + }; + + SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { + for ( + i++; + i < this.queueableFns_.length && + this.queueableFns_[i].type !== 'afterAll'; + i++ + ) {} + return i; + }; + + SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { + if (this.queueableFns_[fnIx].type === 'beforeAll') { + this.skipping_ = true; + } + }; + + return SkipAfterBeforeAllErrorPolicy; +}; diff --git a/src/core/TreeProcessor.js b/src/core/TreeProcessor.js index f93fc044..e3d8eeff 100644 --- a/src/core/TreeProcessor.js +++ b/src/core/TreeProcessor.js @@ -253,7 +253,16 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns.concat(result).concat(node.afterAllFns); + return node.beforeAllFns + .map(function(fn) { + return { type: 'beforeAll', ...fn }; + }) + .concat(result) + .concat( + node.afterAllFns.map(function(fn) { + return { type: 'afterAll', ...fn }; + }) + ); } } diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 08c1e006..e8e17994 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -61,6 +61,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( + j$ + ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ ); From b67a3043c7e5ead1adeaeb4c6e9c9ace324d1671 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 1 Oct 2021 16:36:36 -0700 Subject: [PATCH 36/71] Skip afterEach fns in nested suites when a beforeEach fn errors This matches the behavior of beforeAll errors. * #1533 --- lib/jasmine-core/jasmine.js | 43 ++++++++--- .../CompleteOnFirstErrorSkipPolicySpec.js | 77 +++++++++++++++++-- spec/core/SuiteSpec.js | 18 +++-- spec/core/integration/SpecRunningSpec.js | 53 +++++++------ src/core/CompleteOnFirstErrorSkipPolicy.js | 39 ++++++++-- src/core/Suite.js | 4 +- 6 files changed, 178 insertions(+), 56 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 638f7410..ef5c44b8 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3397,22 +3397,47 @@ getJasmineRequireObj().Clock = function() { getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; - this.skipping_ = false; + this.erroredFnIx_ = null; } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { - if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { - return this.firstCleanupIx_; - } else { - return lastRanFnIx + 1; - } + for ( + i = lastRanFnIx + 1; + i < this.queueableFns_.length && this.shouldSkip_(i); + i++ + ) {} + return i; }; CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { - this.skipping_ = true; + this.erroredFnIx_ = fnIx; }; + CompleteOnFirstErrorSkipPolicy.prototype.shouldSkip_ = function(fnIx) { + if (this.erroredFnIx_ === null) { + return false; + } + + const candidateSuite = this.queueableFns_[fnIx].suite; + const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; + return ( + fnIx < this.firstCleanupIx_ || + (candidateSuite && isDescendent(candidateSuite, errorSuite)) + ); + }; + + function isDescendent(candidate, ancestor) { + if (!candidate.parentSuite) { + return false; + } else if (candidate.parentSuite === ancestor) { + return true; + } else { + return isDescendent(candidate.parentSuite, ancestor); + } + } + return CompleteOnFirstErrorSkipPolicy; }; @@ -9501,7 +9526,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift(fn); + this.beforeFns.unshift({ ...fn, suite: this }); }; Suite.prototype.beforeAll = function(fn) { @@ -9509,7 +9534,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift(fn); + this.afterFns.unshift({ ...fn, suite: this }); }; Suite.prototype.afterAll = function(fn) { diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index 1064cc03..b415d916 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -11,26 +11,89 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { }); describe('After something has errored', function() { - it('returns the first cleanup fn when called with a non cleanup fn', function() { + it('skips non cleanup fns', function() { + const fns = arrayOfArbitraryFns(4); const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - arrayOfArbitraryFns(4), + fns, 2 ); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(2); - expect(policy.skipTo(1)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); + expect(policy.skipTo(3)).toEqual(4); }); - it('returns the next index when called with a cleanup fn', function() { + describe('When the error was in a beforeEach fn', function() { + it('runs cleanup fns defined by the current and containing suites', function() { + const parentSuite = { description: 'parentSuite' }; + const suite = { description: 'suite', parentSuite }; + const fns = [ + { + suite: suite + }, + { + fn: () => {} + }, + { + fn: () => {}, + suite: suite + }, + { + fn: () => {}, + suite: parentSuite + } + ]; + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); + }); + + it('skips cleanup fns defined by nested suites', function() { + const parentSuite = { description: 'parentSuite' }; + const suite = { description: 'suite', parentSuite }; + const fns = [ + { + fn: () => {}, + type: 'beforeEach', + suite: parentSuite + }, + { + fn: () => {} + }, + { + fn: () => {}, + suite: suite + }, + { + fn: () => {}, + suite: parentSuite + } + ]; + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(3); + }); + }); + + it('does not skip cleanup fns that have no suite, such as the spec complete fn', function() { + const fns = [{ fn: () => {} }, { fn: () => {} }]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - arrayOfArbitraryFns(4), + fns, 1 ); policy.fnErrored(0); - expect(policy.skipTo(1)).toEqual(2); - expect(policy.skipTo(2)).toEqual(3); + expect(policy.skipTo(0)).toEqual(1); }); }); }); diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 73cfab4d..d825dd27 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -48,13 +48,16 @@ describe('Suite', function() { env: env, description: 'I am a suite' }), - outerBefore = jasmine.createSpy('outerBeforeEach'), - innerBefore = jasmine.createSpy('insideBeforeEach'); + outerBefore = { fn: 'outerBeforeEach' }, + innerBefore = { fn: 'insideBeforeEach' }; suite.beforeEach(outerBefore); suite.beforeEach(innerBefore); - expect(suite.beforeFns).toEqual([innerBefore, outerBefore]); + expect(suite.beforeFns).toEqual([ + { fn: innerBefore.fn, suite }, + { fn: outerBefore.fn, suite } + ]); }); it('adds after functions in order of needed execution', function() { @@ -62,13 +65,16 @@ describe('Suite', function() { env: env, description: 'I am a suite' }), - outerAfter = jasmine.createSpy('outerAfterEach'), - innerAfter = jasmine.createSpy('insideAfterEach'); + outerAfter = { fn: 'outerAfterEach' }, + innerAfter = { fn: 'insideAfterEach' }; suite.afterEach(outerAfter); suite.afterEach(innerAfter); - expect(suite.afterFns).toEqual([innerAfter, outerAfter]); + expect(suite.afterFns).toEqual([ + { fn: innerAfter.fn, suite }, + { fn: outerAfter.fn, suite } + ]); }); it('has a status of failed if any expectations have failed', function() { diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 60b9c0e4..8ce17280 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -824,11 +824,7 @@ describe('spec running', function() { }); env.execute(null, function() { - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); done(); }); }); @@ -865,11 +861,7 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after an expectation failure', async function() { @@ -904,11 +896,7 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after done.fail is called', function(done) { @@ -1013,11 +1001,7 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after a rejected promise', async function() { @@ -1050,11 +1034,7 @@ describe('spec running', function() { await env.execute(); - expect(actions).toEqual([ - 'outer beforeEach', - 'inner afterEach', - 'outer afterEach' - ]); + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('does not skip anything after an expectation failure', async function() { @@ -1141,6 +1121,29 @@ describe('spec running', function() { expect(actions).toEqual(['beforeEach', 'afterEach']); }); + it('skips cleanup functions that are defined in child suites when a beforeEach errors', async function() { + const parentAfterEachFn = jasmine.createSpy('parentAfterEachFn'); + const childAfterEachFn = jasmine.createSpy('childAfterEachFn'); + + env.describe('parent suite', function() { + env.beforeEach(function() { + throw new Error('nope'); + }); + + env.afterEach(parentAfterEachFn); + + env.describe('child suite', function() { + env.it('a spec', function() {}); + env.afterEach(childAfterEachFn); + }); + }); + + await env.execute(); + + expect(parentAfterEachFn).toHaveBeenCalled(); + expect(childAfterEachFn).not.toHaveBeenCalled(); + }); + it('runs all reporter callbacks even if one fails', async function() { var laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index d99e0124..98ad7caa 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -1,20 +1,45 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; - this.skipping_ = false; + this.erroredFnIx_ = null; } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { - if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { - return this.firstCleanupIx_; - } else { - return lastRanFnIx + 1; - } + for ( + i = lastRanFnIx + 1; + i < this.queueableFns_.length && this.shouldSkip_(i); + i++ + ) {} + return i; }; CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { - this.skipping_ = true; + this.erroredFnIx_ = fnIx; }; + CompleteOnFirstErrorSkipPolicy.prototype.shouldSkip_ = function(fnIx) { + if (this.erroredFnIx_ === null) { + return false; + } + + const candidateSuite = this.queueableFns_[fnIx].suite; + const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; + return ( + fnIx < this.firstCleanupIx_ || + (candidateSuite && isDescendent(candidateSuite, errorSuite)) + ); + }; + + function isDescendent(candidate, ancestor) { + if (!candidate.parentSuite) { + return false; + } else if (candidate.parentSuite === ancestor) { + return true; + } else { + return isDescendent(candidate.parentSuite, ancestor); + } + } + return CompleteOnFirstErrorSkipPolicy; }; diff --git a/src/core/Suite.js b/src/core/Suite.js index bf182680..5e9dba66 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -105,7 +105,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift(fn); + this.beforeFns.unshift({ ...fn, suite: this }); }; Suite.prototype.beforeAll = function(fn) { @@ -113,7 +113,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift(fn); + this.afterFns.unshift({ ...fn, suite: this }); }; Suite.prototype.afterAll = function(fn) { From 1a9d16715d8a5ea5f2926818084ce11f68ee3958 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 6 Oct 2021 08:42:20 -0700 Subject: [PATCH 37/71] Clarify which behaviors are specific to different stopSpecOnExpectationFailure values * #1533 --- spec/core/integration/SpecRunningSpec.js | 333 +++++++---------------- 1 file changed, 102 insertions(+), 231 deletions(-) diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 8ce17280..5327df28 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -792,11 +792,9 @@ describe('spec running', function() { }); }); - describe('When stopSpecOnExpectationFailure is true', function() { - it('skips to cleanup functions after a thrown error', function(done) { - var actions = []; - - env.configure({ stopSpecOnExpectationFailure: true }); + function hasStandardErrorHandlingBehavior() { + it('skips to cleanup functions after a thrown error', async function() { + const actions = []; env.describe('Something', function() { env.beforeEach(function() { @@ -823,16 +821,13 @@ describe('spec running', function() { }); }); - env.execute(null, function() { - expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); - done(); - }); + await env.execute(); + + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); it('skips to cleanup functions after a rejected promise', async function() { - var actions = []; - - env.configure({ stopSpecOnExpectationFailure: true }); + const actions = []; env.describe('Something', function() { env.beforeEach(function() { @@ -864,11 +859,101 @@ describe('spec running', function() { expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); + it('skips to cleanup functions after done.fail is called', async function() { + const actions = []; + + env.describe('Something', function() { + env.beforeEach(function(done) { + actions.push('beforeEach'); + done.fail('error'); + }); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it', function() { + actions.push('it'); + }); + }); + + await env.execute(); + + expect(actions).toEqual(['beforeEach', 'afterEach']); + }); + + it('skips to cleanup functions when an async function times out', async function() { + const actions = []; + + env.describe('Something', function() { + env.beforeEach(function(innerDone) { + actions.push('beforeEach'); + }, 1); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it', function() { + actions.push('it'); + }); + }); + + await env.execute(); + + expect(actions).toEqual(['beforeEach', 'afterEach']); + }); + + it('runs all reporter callbacks even if one fails', async function() { + const laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); + + env.it('a spec', function() {}); + env.addReporter({ + specDone: function() { + throw new Error('nope'); + } + }); + env.addReporter(laterReporter); + + await env.execute(); + + expect(laterReporter.specDone).toHaveBeenCalled(); + }); + + it('skips cleanup functions that are defined in child suites when a beforeEach errors', async function() { + const parentAfterEachFn = jasmine.createSpy('parentAfterEachFn'); + const childAfterEachFn = jasmine.createSpy('childAfterEachFn'); + + env.describe('parent suite', function() { + env.beforeEach(function() { + throw new Error('nope'); + }); + + env.afterEach(parentAfterEachFn); + + env.describe('child suite', function() { + env.it('a spec', function() {}); + env.afterEach(childAfterEachFn); + }); + }); + + await env.execute(); + + expect(parentAfterEachFn).toHaveBeenCalled(); + expect(childAfterEachFn).not.toHaveBeenCalled(); + }); + } + + describe('When stopSpecOnExpectationFailure is true', function() { + beforeEach(function() { + env.configure({ stopSpecOnExpectationFailure: true }); + }); + + hasStandardErrorHandlingBehavior(); + it('skips to cleanup functions after an expectation failure', async function() { var actions = []; - env.configure({ stopSpecOnExpectationFailure: true }); - env.describe('Something', function() { env.beforeEach(function() { actions.push('outer beforeEach'); @@ -898,144 +983,14 @@ describe('spec running', function() { expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); }); - - it('skips to cleanup functions after done.fail is called', function(done) { - var actions = []; - - env.configure({ stopSpecOnExpectationFailure: true }); - - env.describe('Something', function() { - env.beforeEach(function(done) { - actions.push('beforeEach'); - done.fail('error'); - actions.push('after done.fail'); - }); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - done(); - }); - }); - - it('skips to cleanup functions when an async function times out', function(done) { - var actions = []; - - env.configure({ stopSpecOnExpectationFailure: true }); - - env.describe('Something', function() { - env.beforeEach(function(innerDone) { - actions.push('beforeEach'); - }, 1); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - env.execute(null, function() { - expect(actions).toEqual(['beforeEach', 'afterEach']); - done(); - }); - }); - - it('runs all reporter callbacks even if one fails', async function() { - var laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); - - env.configure({ stopSpecOnExpectationFailure: true }); - - env.it('a spec', function() {}); - env.addReporter({ - specDone: function() { - throw new Error('nope'); - } - }); - env.addReporter(laterReporter); - - await env.execute(); - - expect(laterReporter.specDone).toHaveBeenCalled(); - }); }); describe('When stopSpecOnExpectationFailure is false', function() { - it('skips to cleanup functions after a thrown error', async function() { - var actions = []; - - env.describe('Something', function() { - env.beforeEach(function() { - actions.push('outer beforeEach'); - throw new Error('error'); - }); - - env.afterEach(function() { - actions.push('outer afterEach'); - }); - - env.describe('Inner', function() { - env.beforeEach(function() { - actions.push('inner beforeEach'); - }); - - env.afterEach(function() { - actions.push('inner afterEach'); - }); - - env.it('does it', function() { - actions.push('inner it'); - }); - }); - }); - - await env.execute(); - - expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); + beforeEach(function() { + env.configure({ stopSpecOnExpectationFailure: false }); }); - it('skips to cleanup functions after a rejected promise', async function() { - var actions = []; - - env.describe('Something', function() { - env.beforeEach(function() { - actions.push('outer beforeEach'); - return Promise.reject(new Error('error')); - }); - - env.afterEach(function() { - actions.push('outer afterEach'); - }); - - env.describe('Inner', function() { - env.beforeEach(function() { - actions.push('inner beforeEach'); - }); - - env.afterEach(function() { - actions.push('inner afterEach'); - }); - - env.it('does it', function() { - actions.push('inner it'); - }); - }); - }); - - await env.execute(); - - expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); - }); + hasStandardErrorHandlingBehavior(); it('does not skip anything after an expectation failure', async function() { var actions = []; @@ -1075,90 +1030,6 @@ describe('spec running', function() { 'outer afterEach' ]); }); - - it('skips to cleanup functions after done.fail is called', async function() { - var actions = []; - - env.describe('Something', function() { - env.beforeEach(function(done) { - actions.push('beforeEach'); - done.fail('error'); - }); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - await env.execute(); - - expect(actions).toEqual(['beforeEach', 'afterEach']); - }); - - it('skips to cleanup functions when an async function times out', async function() { - var actions = []; - - env.describe('Something', function() { - env.beforeEach(function(innerDone) { - actions.push('beforeEach'); - }, 1); - - env.afterEach(function() { - actions.push('afterEach'); - }); - - env.it('does it', function() { - actions.push('it'); - }); - }); - - await env.execute(); - - expect(actions).toEqual(['beforeEach', 'afterEach']); - }); - - it('skips cleanup functions that are defined in child suites when a beforeEach errors', async function() { - const parentAfterEachFn = jasmine.createSpy('parentAfterEachFn'); - const childAfterEachFn = jasmine.createSpy('childAfterEachFn'); - - env.describe('parent suite', function() { - env.beforeEach(function() { - throw new Error('nope'); - }); - - env.afterEach(parentAfterEachFn); - - env.describe('child suite', function() { - env.it('a spec', function() {}); - env.afterEach(childAfterEachFn); - }); - }); - - await env.execute(); - - expect(parentAfterEachFn).toHaveBeenCalled(); - expect(childAfterEachFn).not.toHaveBeenCalled(); - }); - - it('runs all reporter callbacks even if one fails', async function() { - var laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); - - env.it('a spec', function() {}); - env.addReporter({ - specDone: function() { - throw new Error('nope'); - } - }); - env.addReporter(laterReporter); - - await env.execute(); - - expect(laterReporter.specDone).toHaveBeenCalled(); - }); }); describe('When a beforeAll function fails', function() { From 15710937b8c2d9f1a892d49bfdf72af549cdb65e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 6 Oct 2021 11:05:55 -0700 Subject: [PATCH 38/71] Added a test that verifies skip to cleanup fns after pending() Because pending() is implemented via the standard exception handling path, we effectively got this feature for free as a result of the changes for #1533, particularly 457a2727. * [#178598493] * Fixes #1579 --- spec/core/integration/SpecRunningSpec.js | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 5327df28..0f0a161a 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -904,6 +904,39 @@ describe('spec running', function() { expect(actions).toEqual(['beforeEach', 'afterEach']); }); + it('skips to cleanup functions after pending() is called', async function() { + const actions = []; + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + pending(); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it', function() { + actions.push('inner it'); + }); + }); + }); + + await env.execute(); + + expect(actions).toEqual(['outer beforeEach', 'outer afterEach']); + }); + it('runs all reporter callbacks even if one fails', async function() { const laterReporter = jasmine.createSpyObj('laterReporter', ['specDone']); From 6f0c51260f1946161134bc717d925692b517ce9f Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 6 Oct 2021 17:54:54 -0700 Subject: [PATCH 39/71] Depend on the 4.0 branch of -npm --- Gruntfile.js | 13 ++++++++----- package.json | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 6d65e5e3..cef1eb15 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -34,11 +34,14 @@ module.exports = function(grunt) { jasmine = new Jasmine({jasmineCore: jasmineCore}); jasmine.loadConfigFile('./spec/support/jasmine.json'); - jasmine.onComplete(function(passed) { - done(passed); - }); - - jasmine.execute(); + jasmine.exitOnCompletion = false; + jasmine.execute().then( + result => done(result.overallStatus === 'passed'), + err => { + console.error(err); + exit(1); + } + ); } ); diff --git a/package.json b/package.json index b7cbb3fa..a44be9eb 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "grunt-contrib-concat": "^1.0.1", "grunt-css-url-embed": "^1.11.1", "grunt-sass": "^3.0.2", - "jasmine": "^3.4.0", + "jasmine": "github:jasmine/jasmine-npm#4.0", "jasmine-browser-runner": "github:jasmine/jasmine-browser#main", "jsdom": "^15.0.0", "load-grunt-tasks": "^4.0.0", From d4c15b8df4af27368e564d434a3f9c9246f97dc2 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 6 Oct 2021 17:57:48 -0700 Subject: [PATCH 40/71] No longer test Node <12.17 --- .circleci/config.yml | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1498ecb2..c4cd7246 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,11 +17,7 @@ executors: working_directory: ~/workspace node12: docker: - - image: circleci/node:12 - working_directory: ~/workspace - node10: - docker: - - image: circleci/node:10 + - image: circleci/node:12.17 working_directory: ~/workspace jobs: @@ -118,9 +114,6 @@ workflows: - build: executor: node12 name: build_node_12 - - build: - executor: node10 - name: build_node_10 - test_node: executor: node16 name: test_node_16 @@ -131,11 +124,6 @@ workflows: name: test_node_12 requires: - build_node_12 - - test_node: - executor: node10 - name: test_node_10 - requires: - - build_node_10 - test_browsers: requires: - build_node_14 @@ -154,9 +142,6 @@ workflows: - build: executor: node12 name: build_node_12 - - build: - executor: node10 - name: build_node_10 - test_node: executor: node16 name: test_node_16 @@ -172,11 +157,6 @@ workflows: name: test_node_12 requires: - build_node_12 - - test_node: - executor: node10 - name: test_node_10 - requires: - - build_node_10 - test_browsers: requires: - build_node_14 From 36a4ddf433b1c6ed738c416bb121dd2dfce86bf9 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 7 Oct 2021 10:56:52 -0700 Subject: [PATCH 41/71] Revert "Removed jsdoc entry for SpecResult#trace" This reverts commit 4482355885d07c1b4794ce3cd60a1de74db5520e. --- lib/jasmine-core/jasmine.js | 1 + src/core/Spec.js | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 1d71abed..0f721e46 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -931,6 +931,7 @@ 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} + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. * @since 2.0.0 */ this.result = { diff --git a/src/core/Spec.js b/src/core/Spec.js index fc7b935e..d63b6f79 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -198,6 +198,7 @@ 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} + * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. * @since 2.0.0 */ this.result = { From 976928c7ae8d4426531839af0b38b5a6bf5202ed Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 8 Oct 2021 08:48:22 -0700 Subject: [PATCH 42/71] Set version to 4.0.0-pre.0 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 0f721e46..b2bf0729 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -10141,5 +10141,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '3.9.0'; + return '4.0.0-pre.0'; }; diff --git a/package.json b/package.json index a44be9eb..4f200537 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "3.9.0", + "version": "4.0.0-pre.0", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" From 25c3f0683909fb707bf43e266b2b9a5e70004081 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 8 Oct 2021 14:19:56 -0700 Subject: [PATCH 43/71] Run afterAll fns after failure even if stopOnSpecFailure is true [#160905297] --- lib/jasmine-core/jasmine.js | 6 ++++ .../CompleteOnFirstErrorSkipPolicySpec.js | 17 +++++++++ spec/core/integration/SpecRunningSpec.js | 35 +++++++++++++++++++ src/core/CompleteOnFirstErrorSkipPolicy.js | 6 ++++ 4 files changed, 64 insertions(+) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b2bf0729..fe43148b 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3490,6 +3490,12 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } + // firstCleanupIx_ isn't correct for suites with afterAll functions. + // Rely on the type for those. + if (this.queueableFns_[fnIx].type === 'afterAll') { + return false; + } + const candidateSuite = this.queueableFns_[fnIx].suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; return ( diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index b415d916..b1536ae0 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -95,6 +95,23 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); }); + + it('does not skip afterAll fns, even if before the first cleanup fn index', function() { + const fns = [ + { fn: () => {} }, + { + fn: () => {}, + type: 'afterAll' + } + ]; + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(1); + }); }); }); }); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 9212e88a..a7457d3b 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1153,6 +1153,41 @@ describe('spec running', function() { done(); }); }); + + it('runs afterAll functions', async function() { + const actions = []; + + env.describe('outer suite', function() { + env.describe('inner suite', function() { + env.it('fails', function() { + actions.push('fails'); + env.expect(1).toBe(2); + }); + + env.afterAll(function() { + actions.push('inner afterAll'); + }); + }); + + env.afterAll(function() { + actions.push('outer afterAll'); + }); + }); + + env.afterAll(function() { + actions.push('top afterAll'); + }); + + env.configure({ stopOnSpecFailure: true }); + await env.execute(); + + expect(actions).toEqual([ + 'fails', + 'inner afterAll', + 'outer afterAll', + 'top afterAll' + ]); + }); }); describe('run multiple times', function() { diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index 98ad7caa..afca843c 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -23,6 +23,12 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } + // firstCleanupIx_ isn't correct for suites with afterAll functions. + // Rely on the type for those. + if (this.queueableFns_[fnIx].type === 'afterAll') { + return false; + } + const candidateSuite = this.queueableFns_[fnIx].suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; return ( From 41f5c539597b82d7306240e206615eb95f3ca6f0 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 11 Oct 2021 17:58:40 -0700 Subject: [PATCH 44/71] Consistently identify clenaup fns by a type tag, not position This was already done for everything except spec cleanup fns, since the various skip policies need to know the difference between afterEach and afterAll. --- lib/jasmine-core/jasmine.js | 55 +++++--------- .../CompleteOnFirstErrorSkipPolicySpec.js | 74 ++++++++++--------- spec/core/QueueRunnerSpec.js | 64 ++++++---------- spec/core/SpecSpec.js | 47 +++++++----- spec/core/SuiteSpec.js | 42 ++++++++++- spec/core/TreeProcessorSpec.js | 29 ++++---- src/core/CompleteOnFirstErrorSkipPolicy.js | 18 ++--- src/core/NeverSkipPolicy.js | 2 +- src/core/QueueRunner.js | 6 +- src/core/SkipAfterBeforeAllErrorPolicy.js | 2 +- src/core/Spec.js | 10 +-- src/core/Suite.js | 6 +- src/core/TreeProcessor.js | 11 +-- 13 files changed, 182 insertions(+), 184 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index fe43148b..bc24d385 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -870,16 +870,15 @@ getJasmineRequireObj().Spec = function(j$) { } self.resultCallback(self.result, done); - } + }, + type: 'specCleanup' }; var fns = this.beforeAndAfterFns(); - var regularFns = fns.befores.concat(this.queueableFn); var runnerConfig = { isLeaf: true, - queueableFns: regularFns, - cleanupFns: fns.afters, + queueableFns: [...fns.befores, this.queueableFn, ...fns.afters], onException: function() { self.onException.apply(self, arguments); }, @@ -909,11 +908,10 @@ getJasmineRequireObj().Spec = function(j$) { if (this.markedPending || excluded === true) { runnerConfig.queueableFns = []; - runnerConfig.cleanupFns = []; } runnerConfig.queueableFns.unshift(onStart); - runnerConfig.cleanupFns.push(complete); + runnerConfig.queueableFns.push(complete); this.queueRunnerFactory(runnerConfig); }; @@ -3466,9 +3464,8 @@ getJasmineRequireObj().Clock = function() { }; getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { - function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + function CompleteOnFirstErrorSkipPolicy(queueableFns) { this.queueableFns_ = queueableFns; - this.firstCleanupIx_ = firstCleanupIx; this.erroredFnIx_ = null; } @@ -3490,16 +3487,15 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } - // firstCleanupIx_ isn't correct for suites with afterAll functions. - // Rely on the type for those. - if (this.queueableFns_[fnIx].type === 'afterAll') { - return false; - } - - const candidateSuite = this.queueableFns_[fnIx].suite; + const fn = this.queueableFns_[fnIx]; + const candidateSuite = fn.suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; + const wasCleanupFn = + fn.type === 'afterEach' || + fn.type === 'afterAll' || + fn.type === 'specCleanup'; return ( - fnIx < this.firstCleanupIx_ || + !wasCleanupFn || (candidateSuite && isDescendent(candidateSuite, errorSuite)) ); }; @@ -7395,7 +7391,7 @@ getJasmineRequireObj().MockDate = function(j$) { }; getJasmineRequireObj().NeverSkipPolicy = function(j$) { - function NeverSkipPolicy(queueableFns, firstCleanupIx) {} + function NeverSkipPolicy(queueableFns) {} NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; @@ -7849,9 +7845,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { function QueueRunner(attrs) { this.id_ = nextid++; - var queueableFns = attrs.queueableFns || []; - this.queueableFns = queueableFns.concat(attrs.cleanupFns || []); - this.firstCleanupIx = queueableFns.length; + this.queueableFns = attrs.queueableFns || []; this.onComplete = attrs.onComplete || emptyFn; this.clearStack = attrs.clearStack || @@ -7872,7 +7866,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; - this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); + this.skipPolicy_ = new SkipPolicy(this.queueableFns); this.errored_ = false; if (typeof this.onComplete !== 'function') { @@ -8610,7 +8604,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { }; getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { - function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + function SkipAfterBeforeAllErrorPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.skipping_ = false; } @@ -9600,15 +9594,15 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push(fn); + this.beforeAllFns.push({ ...fn, type: 'beforeAll' }); }; Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift({ ...fn, suite: this }); + this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); }; Suite.prototype.afterAll = function(fn) { - this.afterAllFns.unshift(fn); + this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); }; Suite.prototype.startTimer = function() { @@ -10112,16 +10106,7 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns - .map(function(fn) { - return { type: 'beforeAll', ...fn }; - }) - .concat(result) - .concat( - node.afterAllFns.map(function(fn) { - return { type: 'afterAll', ...fn }; - }) - ); + return node.beforeAllFns.concat(result).concat(node.afterAllFns); } } diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index b1536ae0..babe4605 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -13,10 +13,9 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { describe('After something has errored', function() { it('skips non cleanup fns', function() { const fns = arrayOfArbitraryFns(4); - const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - fns, - 2 - ); + fns[2].type = arbitraryCleanupType(); + fns[3].type = arbitraryCleanupType(); + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(2); @@ -24,6 +23,19 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { expect(policy.skipTo(3)).toEqual(4); }); + for (const type of ['afterEach', 'specCleanup', 'afterAll']) { + it(`does not skip ${type} fns`, function() { + const fns = arrayOfArbitraryFns(2); + fns[1].type = type; + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + fns + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(1); + }); + } + describe('When the error was in a beforeEach fn', function() { it('runs cleanup fns defined by the current and containing suites', function() { const parentSuite = { description: 'parentSuite' }; @@ -37,16 +49,17 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { }, { fn: () => {}, - suite: suite + suite: suite, + type: arbitraryCleanupType() }, { fn: () => {}, - suite: parentSuite + suite: parentSuite, + type: arbitraryCleanupType() } ]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - fns, - 2 + fns ); policy.fnErrored(0); @@ -68,16 +81,17 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { }, { fn: () => {}, - suite: suite + suite: suite, + type: arbitraryCleanupType() }, { fn: () => {}, - suite: parentSuite + suite: parentSuite, + type: arbitraryCleanupType() } ]; const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - fns, - 2 + fns ); policy.fnErrored(0); @@ -86,42 +100,32 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { }); it('does not skip cleanup fns that have no suite, such as the spec complete fn', function() { - const fns = [{ fn: () => {} }, { fn: () => {} }]; - const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - fns, - 1 - ); - - policy.fnErrored(0); - expect(policy.skipTo(0)).toEqual(1); - }); - - it('does not skip afterAll fns, even if before the first cleanup fn index', function() { const fns = [ { fn: () => {} }, { fn: () => {}, - type: 'afterAll' + type: arbitraryCleanupType() } ]; - const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( - fns, - 2 - ); + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); }); }); }); -}); -function arrayOfArbitraryFns(n) { - const result = []; + function arrayOfArbitraryFns(n) { + const result = []; - for (let i = 0; i < n; i++) { - result.push({ fn: () => {} }); + for (let i = 0; i < n; i++) { + result.push({ fn: () => {} }); + } + + return result; } - return result; -} + function arbitraryCleanupType() { + return 'specCleanup'; + } +}); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 87f575fe..34141f4f 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -18,26 +18,6 @@ describe('QueueRunner', function() { expect(calls).toEqual(['fn1', 'fn2']); }); - it('runs cleanup functions after the others', function() { - var calls = [], - queueableFn1 = { fn: jasmine.createSpy('fn1') }, - queueableFn2 = { fn: jasmine.createSpy('fn2') }, - queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn1], - cleanupFns: [queueableFn2] - }); - queueableFn1.fn.and.callFake(function() { - calls.push('fn1'); - }); - queueableFn2.fn.and.callFake(function() { - calls.push('fn2'); - }); - - queueRunner.execute(); - - expect(calls).toEqual(['fn1', 'fn2']); - }); - it("calls each function with a consistent 'this'-- an empty object", function() { var queueableFn1 = { fn: jasmine.createSpy('fn1') }, queueableFn2 = { fn: jasmine.createSpy('fn2') }, @@ -653,18 +633,13 @@ describe('QueueRunner', function() { it('instantiates the skip policy', function() { const SkipPolicy = jasmine.createSpy('SkipPolicy ctor'); const queueableFns = [{ fn: () => {} }, { fn: () => {} }]; - const cleanupFns = [{ fn: () => {} }]; new jasmineUnderTest.QueueRunner({ queueableFns, - cleanupFns, SkipPolicy }); - expect(SkipPolicy).toHaveBeenCalledWith( - [...queueableFns, ...cleanupFns], - 2 - ); + expect(SkipPolicy).toHaveBeenCalledWith(queueableFns); }); it('uses the skip policy to determine which fn to run next', function() { @@ -723,11 +698,13 @@ describe('QueueRunner', function() { } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, - cleanupFn = { fn: jasmine.createSpy('cleanup') }, + cleanupFn = { + fn: jasmine.createSpy('cleanup'), + type: 'specCleanup' + }, onComplete = jasmine.createSpy('onComplete'), queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn, nextQueueableFn], - cleanupFns: [cleanupFn], + queueableFns: [queueableFn, nextQueueableFn, cleanupFn], onComplete: onComplete, SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); @@ -745,12 +722,15 @@ describe('QueueRunner', function() { cleanupFn1 = { fn: function() { throw new Error('error'); - } + }, + type: 'afterEach' + }, + cleanupFn2 = { + fn: jasmine.createSpy('cleanupFn2'), + type: 'afterEach' }, - cleanupFn2 = { fn: jasmine.createSpy('cleanupFn2') }, queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn], - cleanupFns: [cleanupFn1, cleanupFn2], + queueableFns: [queueableFn, cleanupFn1, cleanupFn2], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); @@ -775,7 +755,7 @@ describe('QueueRunner', function() { } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, - cleanupFn = { fn: jasmine.createSpy('cleanup') }, + cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, queueRunner = new jasmineUnderTest.QueueRunner({ globalErrors: { pushListener: function(f) { @@ -785,8 +765,7 @@ describe('QueueRunner', function() { errorListeners.pop(); } }, - queueableFns: [queueableFn, nextQueueableFn], - cleanupFns: [cleanupFn], + queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }), queueableFnDone; @@ -806,10 +785,9 @@ describe('QueueRunner', function() { } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, - cleanupFn = { fn: jasmine.createSpy('cleanup') }, + cleanupFn = { fn: jasmine.createSpy('cleanup'), type: 'specCleanup' }, queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn, nextQueueableFn], - cleanupFns: [cleanupFn], + queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); @@ -826,10 +804,12 @@ describe('QueueRunner', function() { } }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, - cleanupFn = { fn: jasmine.createSpy('cleanup') }, + cleanupFn = { + fn: jasmine.createSpy('cleanup'), + type: 'specCleanup' + }, queueRunner = new jasmineUnderTest.QueueRunner({ - queueableFns: [queueableFn, nextQueueableFn], - cleanupFns: [cleanupFn], + queueableFns: [queueableFn, nextQueueableFn, cleanupFn], SkipPolicy: jasmineUnderTest.CompleteOnFirstErrorSkipPolicy }); diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 5c29b80c..6abb1f9e 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -116,9 +116,13 @@ describe('Spec', function() { expect(options.queueableFns).toEqual([ { fn: jasmine.any(Function) }, before, - queueableFn + queueableFn, + after, + { + fn: jasmine.any(Function), + type: 'specCleanup' + } ]); - expect(options.cleanupFns).toEqual([after, { fn: jasmine.any(Function) }]); }); it("tells the queue runner that it's a leaf node", function() { @@ -171,8 +175,13 @@ describe('Spec', function() { expect(fakeQueueRunner).toHaveBeenCalledWith( jasmine.objectContaining({ onComplete: jasmine.any(Function), - queueableFns: [{ fn: jasmine.any(Function) }], - cleanupFns: [{ fn: jasmine.any(Function) }] + queueableFns: [ + { fn: jasmine.any(Function) }, + { + fn: jasmine.any(Function), + type: 'specCleanup' + } + ] }) ); expect(specBody).not.toHaveBeenCalled(); @@ -180,7 +189,7 @@ describe('Spec', function() { var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); - args.cleanupFns[0].fn(); + args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback).toHaveBeenCalled(); expect(spec.result.status).toBe('excluded'); @@ -212,7 +221,7 @@ describe('Spec', function() { var args = fakeQueueRunner.calls.mostRecent().args[0]; args.queueableFns[0].fn(); expect(startCallback).toHaveBeenCalled(); - args.cleanupFns[0].fn('things'); + args.queueableFns[1].fn('things'); expect(resultCallback).toHaveBeenCalledWith( { id: spec.id, @@ -284,9 +293,6 @@ describe('Spec', function() { config.queueableFns.forEach(function(qf) { qf.fn(); }); - config.cleanupFns.forEach(function(qf) { - qf.fn(); - }); config.onComplete(); }, timer: timer @@ -354,7 +360,9 @@ describe('Spec', function() { spec.execute(); - fakeQueueRunner.calls.mostRecent().args[0].cleanupFns[0].fn(); + const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns; + fns[fns.length - 1].fn(); + expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([ 'expectation1' ]); @@ -383,7 +391,8 @@ describe('Spec', function() { spec.execute(); - fakeQueueRunner.calls.mostRecent().args[0].cleanupFns[0].fn(); + const fns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns; + fns[fns.length - 1].fn(); expect(resultCallback.calls.first().args[0].passedExpectations).toEqual([ 'passed' ]); @@ -482,7 +491,7 @@ describe('Spec', function() { spec.execute(); var args = fakeQueueRunner.calls.mostRecent().args[0]; - args.cleanupFns[0].fn(); + args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([ { error: 'foo', @@ -510,7 +519,7 @@ describe('Spec', function() { spec.execute(); var args = fakeQueueRunner.calls.mostRecent().args[0]; - args.cleanupFns[0].fn(); + args.queueableFns[args.queueableFns.length - 1].fn(); expect(resultCallback.calls.first().args[0].failedExpectations).toEqual([]); }); @@ -575,9 +584,9 @@ describe('Spec', function() { resultCallback: resultCallback, queueRunnerFactory: function(config) { spec.trace('msg'); - config.cleanupFns.forEach(function(fn) { + for (const fn of config.queueableFns) { fn.fn(); - }); + } config.onComplete(false); } }); @@ -598,9 +607,9 @@ describe('Spec', function() { resultCallback: resultCallback, queueRunnerFactory: function(config) { spec.trace('msg'); - config.cleanupFns.forEach(function(fn) { + for (const fn of config.queueableFns) { fn.fn(); - }); + } config.onComplete(false); } }); @@ -623,9 +632,9 @@ describe('Spec', function() { queueRunnerFactory: function(config) { spec.trace('msg'); spec.onException(new Error('nope')); - config.cleanupFns.forEach(function(fn) { + for (const fn of config.queueableFns) { fn.fn(); - }); + } config.onComplete(true); }, timer: timer diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 098c67f1..84fce87e 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -43,7 +43,7 @@ describe('Suite', function() { expect(suite.getFullName()).toEqual('I am a parent suite I am a suite'); }); - it('adds before functions in order of needed execution', function() { + it('adds beforeEach functions in order of needed execution', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' @@ -60,7 +60,24 @@ describe('Suite', function() { ]); }); - it('adds after functions in order of needed execution', function() { + it('adds beforeAll functions in order of needed execution', function() { + var suite = new jasmineUnderTest.Suite({ + env: env, + description: 'I am a suite' + }), + outerBefore = { fn: 'outerBeforeAll' }, + innerBefore = { fn: 'insideBeforeAll' }; + + suite.beforeAll(outerBefore); + suite.beforeAll(innerBefore); + + expect(suite.beforeAllFns).toEqual([ + { fn: outerBefore.fn, type: 'beforeAll' }, + { fn: innerBefore.fn, type: 'beforeAll' } + ]); + }); + + it('adds afterEach functions in order of needed execution', function() { var suite = new jasmineUnderTest.Suite({ env: env, description: 'I am a suite' @@ -72,8 +89,25 @@ describe('Suite', function() { suite.afterEach(innerAfter); expect(suite.afterFns).toEqual([ - { fn: innerAfter.fn, suite }, - { fn: outerAfter.fn, suite } + { fn: innerAfter.fn, suite, type: 'afterEach' }, + { fn: outerAfter.fn, suite, type: 'afterEach' } + ]); + }); + + it('adds afterAll functions in order of needed execution', function() { + const suite = new jasmineUnderTest.Suite({ + env: env, + description: 'I am a suite' + }), + outerAfter = { fn: 'outerAfterAll' }, + innerAfter = { fn: 'insideAfterAl' }; + + suite.afterAll(outerAfter); + suite.afterAll(innerAfter); + + expect(suite.afterAllFns).toEqual([ + { fn: innerAfter.fn, type: 'afterAll' }, + { fn: outerAfter.fn, type: 'afterAll' } ]); }); diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index a3967d42..7ada587d 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -505,27 +505,28 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, - { type: 'beforeAll', fn: 'beforeAll1', timeout: 1 }, - { type: 'beforeAll', fn: 'beforeAll2', timeout: 2 }, + { fn: 'beforeAll1', timeout: 1 }, + { fn: 'beforeAll2', timeout: 2 }, { fn: jasmine.any(Function) } ]); }); it('runs afterAlls for a node with children', function() { var leaf = new Leaf(), - node = new Node({ - children: [leaf], - afterAllFns: [{ fn: 'afterAll1' }, { fn: 'afterAll2' }] - }), - root = new Node({ children: [node] }), - queueRunner = jasmine.createSpy('queueRunner'), - processor = new jasmineUnderTest.TreeProcessor({ + afterAllFns = [{ fn: 'afterAll1' }, { fn: 'afterAll2' }]; + (node = new Node({ + children: [leaf], + afterAllFns + })), + (root = new Node({ children: [node] })), + (queueRunner = jasmine.createSpy('queueRunner')), + (processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner - }), - treeComplete = jasmine.createSpy('treeComplete'), - nodeDone = jasmine.createSpy('nodeDone'); + })), + (treeComplete = jasmine.createSpy('treeComplete')), + (nodeDone = jasmine.createSpy('nodeDone')); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; @@ -536,8 +537,8 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) }, - { type: 'afterAll', fn: 'afterAll1' }, - { type: 'afterAll', fn: 'afterAll2' } + afterAllFns[0], + afterAllFns[1] ]); }); diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index afca843c..5be5c79f 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -1,7 +1,6 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { - function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { + function CompleteOnFirstErrorSkipPolicy(queueableFns) { this.queueableFns_ = queueableFns; - this.firstCleanupIx_ = firstCleanupIx; this.erroredFnIx_ = null; } @@ -23,16 +22,15 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } - // firstCleanupIx_ isn't correct for suites with afterAll functions. - // Rely on the type for those. - if (this.queueableFns_[fnIx].type === 'afterAll') { - return false; - } - - const candidateSuite = this.queueableFns_[fnIx].suite; + const fn = this.queueableFns_[fnIx]; + const candidateSuite = fn.suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; + const wasCleanupFn = + fn.type === 'afterEach' || + fn.type === 'afterAll' || + fn.type === 'specCleanup'; return ( - fnIx < this.firstCleanupIx_ || + !wasCleanupFn || (candidateSuite && isDescendent(candidateSuite, errorSuite)) ); }; diff --git a/src/core/NeverSkipPolicy.js b/src/core/NeverSkipPolicy.js index 75fb78d9..7d72cd50 100644 --- a/src/core/NeverSkipPolicy.js +++ b/src/core/NeverSkipPolicy.js @@ -1,5 +1,5 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) { - function NeverSkipPolicy(queueableFns, firstCleanupIx) {} + function NeverSkipPolicy(queueableFns) {} NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 9223c5e0..ebf3b5c3 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -35,9 +35,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { function QueueRunner(attrs) { this.id_ = nextid++; - var queueableFns = attrs.queueableFns || []; - this.queueableFns = queueableFns.concat(attrs.cleanupFns || []); - this.firstCleanupIx = queueableFns.length; + this.queueableFns = attrs.queueableFns || []; this.onComplete = attrs.onComplete || emptyFn; this.clearStack = attrs.clearStack || @@ -58,7 +56,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; - this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); + this.skipPolicy_ = new SkipPolicy(this.queueableFns); this.errored_ = false; if (typeof this.onComplete !== 'function') { diff --git a/src/core/SkipAfterBeforeAllErrorPolicy.js b/src/core/SkipAfterBeforeAllErrorPolicy.js index e2d37630..ce49a830 100644 --- a/src/core/SkipAfterBeforeAllErrorPolicy.js +++ b/src/core/SkipAfterBeforeAllErrorPolicy.js @@ -1,5 +1,5 @@ getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { - function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + function SkipAfterBeforeAllErrorPolicy(queueableFns) { this.queueableFns_ = queueableFns; this.skipping_ = false; } diff --git a/src/core/Spec.js b/src/core/Spec.js index d63b6f79..9b35f749 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -137,16 +137,15 @@ getJasmineRequireObj().Spec = function(j$) { } self.resultCallback(self.result, done); - } + }, + type: 'specCleanup' }; var fns = this.beforeAndAfterFns(); - var regularFns = fns.befores.concat(this.queueableFn); var runnerConfig = { isLeaf: true, - queueableFns: regularFns, - cleanupFns: fns.afters, + queueableFns: [...fns.befores, this.queueableFn, ...fns.afters], onException: function() { self.onException.apply(self, arguments); }, @@ -176,11 +175,10 @@ getJasmineRequireObj().Spec = function(j$) { if (this.markedPending || excluded === true) { runnerConfig.queueableFns = []; - runnerConfig.cleanupFns = []; } runnerConfig.queueableFns.unshift(onStart); - runnerConfig.cleanupFns.push(complete); + runnerConfig.queueableFns.push(complete); this.queueRunnerFactory(runnerConfig); }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 672bcb7e..2cb2e7ca 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -103,15 +103,15 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push(fn); + this.beforeAllFns.push({ ...fn, type: 'beforeAll' }); }; Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift({ ...fn, suite: this }); + this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); }; Suite.prototype.afterAll = function(fn) { - this.afterAllFns.unshift(fn); + this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); }; Suite.prototype.startTimer = function() { diff --git a/src/core/TreeProcessor.js b/src/core/TreeProcessor.js index e3d8eeff..f93fc044 100644 --- a/src/core/TreeProcessor.js +++ b/src/core/TreeProcessor.js @@ -253,16 +253,7 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns - .map(function(fn) { - return { type: 'beforeAll', ...fn }; - }) - .concat(result) - .concat( - node.afterAllFns.map(function(fn) { - return { type: 'afterAll', ...fn }; - }) - ); + return node.beforeAllFns.concat(result).concat(node.afterAllFns); } } From 2a049015b02bfd45a641895f364adcea6e028902 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 15 Nov 2021 18:30:43 -0800 Subject: [PATCH 45/71] Use custom equality testers in Spy#withArgs Fixes #1836. --- lib/jasmine-core/jasmine.js | 71 ++++++++++++++++++-------------- spec/core/SpySpec.js | 19 ++++++++- spec/core/integration/EnvSpec.js | 52 +++++++++++++++++++++++ src/core/Env.js | 21 ++++++---- src/core/Spy.js | 35 ++++++++-------- src/core/SpyFactory.js | 15 ++++--- 6 files changed, 152 insertions(+), 61 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index e79fe8f2..b7188584 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1490,12 +1490,18 @@ getJasmineRequireObj().Env = function(j$) { }; var makeMatchersUtil = function() { - var customEqualityTesters = - runnableResources[currentRunnable().id].customEqualityTesters; - return new j$.MatchersUtil({ - customTesters: customEqualityTesters, - pp: makePrettyPrinter() - }); + const cr = currentRunnable(); + + if (cr) { + const customEqualityTesters = + runnableResources[cr.id].customEqualityTesters; + return new j$.MatchersUtil({ + customTesters: customEqualityTesters, + pp: makePrettyPrinter() + }); + } else { + return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ }); + } }; var expectationFactory = function(actual, spec) { @@ -2026,7 +2032,8 @@ getJasmineRequireObj().Env = function(j$) { } return undefined; - } + }, + makeMatchersUtil ); var spyRegistry = new j$.SpyRegistry({ @@ -8647,11 +8654,6 @@ getJasmineRequireObj().Spy = function(j$) { }; })(); - var matchersUtil = new j$.MatchersUtil({ - customTesters: [], - pp: j$.makePrettyPrinter() - }); - /** * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn}, * {@link spyOnProperty}, {@link jasmine.createSpy}, or @@ -8659,19 +8661,24 @@ getJasmineRequireObj().Spy = function(j$) { * @class Spy * @hideconstructor */ - function Spy(name, originalFn, customStrategies, defaultStrategyFn) { + function Spy(name, matchersUtil, optionals) { + const { originalFn, customStrategies, defaultStrategyFn } = optionals || {}; + var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); }), - strategyDispatcher = new SpyStrategyDispatcher({ - name: name, - fn: originalFn, - getSpy: function() { - return wrapper; + strategyDispatcher = new SpyStrategyDispatcher( + { + name: name, + fn: originalFn, + getSpy: function() { + return wrapper; + }, + customStrategies: customStrategies }, - customStrategies: customStrategies - }), + matchersUtil + ), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { /** @@ -8783,11 +8790,11 @@ getJasmineRequireObj().Spy = function(j$) { return wrapper; } - function SpyStrategyDispatcher(strategyArgs) { + function SpyStrategyDispatcher(strategyArgs, matchersUtil) { var baseStrategy = new j$.SpyStrategy(strategyArgs); var argsStrategies = new StrategyDict(function() { return new j$.SpyStrategy(strategyArgs); - }); + }, matchersUtil); this.and = baseStrategy; @@ -8816,9 +8823,10 @@ getJasmineRequireObj().Spy = function(j$) { }; } - function StrategyDict(strategyFactory) { + function StrategyDict(strategyFactory, matchersUtil) { this.strategies = []; this.strategyFactory = strategyFactory; + this.matchersUtil = matchersUtil; } StrategyDict.prototype.any = function() { @@ -8843,7 +8851,7 @@ getJasmineRequireObj().Spy = function(j$) { var i; for (i = 0; i < this.strategies.length; i++) { - if (matchersUtil.equals(args, this.strategies[i].args)) { + if (this.matchersUtil.equals(args, this.strategies[i].args)) { return this.strategies[i].strategy; } } @@ -8853,16 +8861,19 @@ getJasmineRequireObj().Spy = function(j$) { }; getJasmineRequireObj().SpyFactory = function(j$) { - function SpyFactory(getCustomStrategies, getDefaultStrategyFn) { + function SpyFactory( + getCustomStrategies, + getDefaultStrategyFn, + getMatchersUtil + ) { var self = this; this.createSpy = function(name, originalFn) { - return j$.Spy( - name, + return j$.Spy(name, getMatchersUtil(), { originalFn, - getCustomStrategies(), - getDefaultStrategyFn() - ); + customStrategies: getCustomStrategies(), + defaultStrategyFn: getDefaultStrategyFn() + }); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { diff --git a/spec/core/SpySpec.js b/spec/core/SpySpec.js index 6271c900..bfc08e98 100644 --- a/spec/core/SpySpec.js +++ b/spec/core/SpySpec.js @@ -231,7 +231,7 @@ describe('Spies', function() { expect(spy('baz', 'grault', 'waldo')).toEqual(42); }); - it('uses custom equality testers when selecting a strategy', function() { + it('uses asymmetric equality testers when selecting a strategy', function() { var spy = env.createSpy('foo'); spy.and.returnValue(42); spy.withArgs(jasmineUnderTest.any(String)).and.returnValue(-1); @@ -240,6 +240,23 @@ describe('Spies', function() { expect(spy({})).toEqual(42); }); + it('uses the provided matchersUtil selecting a strategy', function() { + const matchersUtil = new jasmineUnderTest.MatchersUtil({ + customTesters: [ + function(a, b) { + if ((a === 'bar' && b === 'baz') || (a === 'baz' && b === 'bar')) { + return true; + } + } + ] + }); + const spy = new jasmineUnderTest.Spy('aSpy', matchersUtil); + spy.and.returnValue('default strategy return value'); + spy.withArgs('bar').and.returnValue('custom strategy return value'); + expect(spy('foo')).toEqual('default strategy return value'); + expect(spy('baz')).toEqual('custom strategy return value'); + }); + it('can reconfigure an argument-specific strategy', function() { var spy = env.createSpy('foo'); spy.withArgs('foo').and.returnValue(42); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 462893d9..2d0b0072 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3413,4 +3413,56 @@ describe('Env integration', function() { done(); }); }); + + it('uses custom equality testers in Spy#withArgs', async function() { + env.it('a spec', function() { + const createSpySpy = env.createSpy('via createSpy'); + const spiedOn = { foo: function() {} }; + env.spyOn(spiedOn, 'foo'); + const spyObj = env.createSpyObj('spyObj', ['foo']); + const spiedOnAllFuncs = { foo: function() {} }; + env.spyOnAllFunctions(spiedOnAllFuncs); + + for (spy of [ + createSpySpy, + spiedOn.foo, + spyObj.foo, + spiedOnAllFuncs.foo + ]) { + spy.and.returnValue('default strategy'); + spy.withArgs(42).and.returnValue('custom strategy'); + } + + env.addCustomEqualityTester(function(a, b) { + if ((a === 'x' && b === 42) || (a === 42 && b === 'x')) { + return true; + } + }); + + env + .expect(createSpySpy('x')) + .withContext('createSpy') + .toEqual('custom strategy'); + env + .expect(spiedOn.foo('x')) + .withContext('spyOn') + .toEqual('custom strategy'); + env + .expect(spyObj.foo('x')) + .withContext('createSpyObj') + .toEqual('custom strategy'); + env + .expect(spiedOnAllFuncs.foo('x')) + .withContext('spyOnAllFunctions') + .toEqual('custom strategy'); + }); + + let failedExpectations; + env.addReporter({ + specDone: r => (failedExpectations = r.failedExpectations) + }); + + await env.execute(); + expect(failedExpectations).toEqual([]); + }); }); diff --git a/src/core/Env.js b/src/core/Env.js index 4ee1eae1..ddd9d4ee 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -327,12 +327,18 @@ getJasmineRequireObj().Env = function(j$) { }; var makeMatchersUtil = function() { - var customEqualityTesters = - runnableResources[currentRunnable().id].customEqualityTesters; - return new j$.MatchersUtil({ - customTesters: customEqualityTesters, - pp: makePrettyPrinter() - }); + const cr = currentRunnable(); + + if (cr) { + const customEqualityTesters = + runnableResources[cr.id].customEqualityTesters; + return new j$.MatchersUtil({ + customTesters: customEqualityTesters, + pp: makePrettyPrinter() + }); + } else { + return new j$.MatchersUtil({ pp: j$.basicPrettyPrinter_ }); + } }; var expectationFactory = function(actual, spec) { @@ -863,7 +869,8 @@ getJasmineRequireObj().Env = function(j$) { } return undefined; - } + }, + makeMatchersUtil ); var spyRegistry = new j$.SpyRegistry({ diff --git a/src/core/Spy.js b/src/core/Spy.js index 7b7e422b..26d4b6b4 100644 --- a/src/core/Spy.js +++ b/src/core/Spy.js @@ -7,11 +7,6 @@ getJasmineRequireObj().Spy = function(j$) { }; })(); - var matchersUtil = new j$.MatchersUtil({ - customTesters: [], - pp: j$.makePrettyPrinter() - }); - /** * @classdesc _Note:_ Do not construct this directly. Use {@link spyOn}, * {@link spyOnProperty}, {@link jasmine.createSpy}, or @@ -19,19 +14,24 @@ getJasmineRequireObj().Spy = function(j$) { * @class Spy * @hideconstructor */ - function Spy(name, originalFn, customStrategies, defaultStrategyFn) { + function Spy(name, matchersUtil, optionals) { + const { originalFn, customStrategies, defaultStrategyFn } = optionals || {}; + var numArgs = typeof originalFn === 'function' ? originalFn.length : 0, wrapper = makeFunc(numArgs, function(context, args, invokeNew) { return spy(context, args, invokeNew); }), - strategyDispatcher = new SpyStrategyDispatcher({ - name: name, - fn: originalFn, - getSpy: function() { - return wrapper; + strategyDispatcher = new SpyStrategyDispatcher( + { + name: name, + fn: originalFn, + getSpy: function() { + return wrapper; + }, + customStrategies: customStrategies }, - customStrategies: customStrategies - }), + matchersUtil + ), callTracker = new j$.CallTracker(), spy = function(context, args, invokeNew) { /** @@ -143,11 +143,11 @@ getJasmineRequireObj().Spy = function(j$) { return wrapper; } - function SpyStrategyDispatcher(strategyArgs) { + function SpyStrategyDispatcher(strategyArgs, matchersUtil) { var baseStrategy = new j$.SpyStrategy(strategyArgs); var argsStrategies = new StrategyDict(function() { return new j$.SpyStrategy(strategyArgs); - }); + }, matchersUtil); this.and = baseStrategy; @@ -176,9 +176,10 @@ getJasmineRequireObj().Spy = function(j$) { }; } - function StrategyDict(strategyFactory) { + function StrategyDict(strategyFactory, matchersUtil) { this.strategies = []; this.strategyFactory = strategyFactory; + this.matchersUtil = matchersUtil; } StrategyDict.prototype.any = function() { @@ -203,7 +204,7 @@ getJasmineRequireObj().Spy = function(j$) { var i; for (i = 0; i < this.strategies.length; i++) { - if (matchersUtil.equals(args, this.strategies[i].args)) { + if (this.matchersUtil.equals(args, this.strategies[i].args)) { return this.strategies[i].strategy; } } diff --git a/src/core/SpyFactory.js b/src/core/SpyFactory.js index 808ec647..03bd6035 100644 --- a/src/core/SpyFactory.js +++ b/src/core/SpyFactory.js @@ -1,14 +1,17 @@ getJasmineRequireObj().SpyFactory = function(j$) { - function SpyFactory(getCustomStrategies, getDefaultStrategyFn) { + function SpyFactory( + getCustomStrategies, + getDefaultStrategyFn, + getMatchersUtil + ) { var self = this; this.createSpy = function(name, originalFn) { - return j$.Spy( - name, + return j$.Spy(name, getMatchersUtil(), { originalFn, - getCustomStrategies(), - getDefaultStrategyFn() - ); + customStrategies: getCustomStrategies(), + defaultStrategyFn: getDefaultStrategyFn() + }); }; this.createSpyObj = function(baseName, methodNames, propertyNames) { From 7a685b16f656274ce693441bb396eb72d6a3ed63 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 16 Nov 2021 12:52:07 -0800 Subject: [PATCH 46/71] Removed duplicate message from errors (incl. matcher failures) on V8 --- lib/jasmine-core/jasmine.js | 8 +++-- spec/core/ExceptionFormatterSpec.js | 56 +++++++++++++++++++++++++++++ spec/core/ExpectationResultSpec.js | 8 +++-- spec/core/integration/EnvSpec.js | 10 ++++-- src/core/ExceptionFormatter.js | 4 +-- src/core/ExpectationResult.js | 4 ++- 6 files changed, 79 insertions(+), 11 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b7188584..0a679f7c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3843,7 +3843,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { return message; }; - this.stack = function(error) { + this.stack = function(error, { omitMessage } = {}) { if (!error || !error.stack) { return null; } @@ -3852,7 +3852,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { var lines = filterJasmine(stackTrace); var result = ''; - if (stackTrace.message) { + if (stackTrace.message && !omitMessage) { lines.unshift(stackTrace.message); } @@ -4302,7 +4302,9 @@ getJasmineRequireObj().buildExpectationResult = function(j$) { } } } - return stackFormatter(error); + // Omit the message from the stack trace because it will be + // included elsewhere. + return stackFormatter(error, { omitMessage: true }); } } diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index 1c4a1c62..f4f15700 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -225,5 +225,61 @@ describe('ExceptionFormatter', function() { expect(result).toMatch(/error properties:.*someProperty.*hello there/); }); + + describe('When omitMessage is true', function() { + it('filters the message from V8-style stack traces', function() { + const error = { + message: 'nope', + stack: + 'Error: nope\n' + + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + + ' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + + ' at fn3 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)\n' + }; + const subject = new jasmineUnderTest.ExceptionFormatter({ + jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' + }); + const result = subject.stack(error, { omitMessage: true }); + expect(result).toEqual( + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + + ' at \n' + + ' at fn4 (http://localhost:8888/__spec__/core/UtilSpec.js:110:19)' + ); + }); + + it('handles Webkit style traces that do not include a message', function() { + const error = { + stack: + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + + 'fn1@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + + 'fn2@http://localhost:8888/__jasmine__/jasmine.js:4320:27\n' + + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' + }; + const subject = new jasmineUnderTest.ExceptionFormatter({ + jasmineFile: 'http://localhost:8888/__jasmine__/jasmine.js' + }); + const result = subject.stack(error, { omitMessage: true }); + expect(result).toEqual( + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + + '\n' + + 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28' + ); + }); + + it('ensures that stack traces do not include the message in this environment', function() { + let error; + try { + throw new Error('an error'); + } catch (e) { + error = e; + } + const subject = new jasmineUnderTest.ExceptionFormatter({ + jasmineFile: jasmine.util.jasmineFile() + }); + const result = subject.stack(error, { omitMessage: true }); + expect(result).not.toContain('an error'); + }); + }); }); }); diff --git a/spec/core/ExpectationResultSpec.js b/spec/core/ExpectationResultSpec.js index b28818aa..d68b1655 100644 --- a/spec/core/ExpectationResultSpec.js +++ b/spec/core/ExpectationResultSpec.js @@ -50,7 +50,9 @@ describe('buildExpectationResult', function() { stackFormatter: stackFormatter }); - expect(stackFormatter).toHaveBeenCalledWith(fakeError); + expect(stackFormatter).toHaveBeenCalledWith(fakeError, { + omitMessage: true + }); expect(result.stack).toEqual('foo'); }); @@ -66,7 +68,9 @@ describe('buildExpectationResult', function() { stackFormatter: stackFormatter }); - expect(stackFormatter).toHaveBeenCalledWith(fakeError); + expect(stackFormatter).toHaveBeenCalledWith(fakeError, { + omitMessage: true + }); expect(result.stack).toEqual('foo'); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 2d0b0072..45846e4f 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -2839,7 +2839,7 @@ describe('Env integration', function() { expect(result.deprecationWarnings).toEqual([ jasmine.objectContaining({ message: topLevelError.message, - stack: exceptionFormatter.stack(topLevelError) + stack: exceptionFormatter.stack(topLevelError, { omitMessage: true }) }) ]); @@ -2849,7 +2849,9 @@ describe('Env integration', function() { deprecationWarnings: [ jasmine.objectContaining({ message: suiteLevelError.message, - stack: exceptionFormatter.stack(suiteLevelError) + stack: exceptionFormatter.stack(suiteLevelError, { + omitMessage: true + }) }) ] }) @@ -2861,7 +2863,9 @@ describe('Env integration', function() { deprecationWarnings: [ jasmine.objectContaining({ message: specLevelError.message, - stack: exceptionFormatter.stack(specLevelError) + stack: exceptionFormatter.stack(specLevelError, { + omitMessage: true + }) }) ] }) diff --git a/src/core/ExceptionFormatter.js b/src/core/ExceptionFormatter.js index 113f7af7..a36d1422 100644 --- a/src/core/ExceptionFormatter.js +++ b/src/core/ExceptionFormatter.js @@ -38,7 +38,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { return message; }; - this.stack = function(error) { + this.stack = function(error, { omitMessage } = {}) { if (!error || !error.stack) { return null; } @@ -47,7 +47,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { var lines = filterJasmine(stackTrace); var result = ''; - if (stackTrace.message) { + if (stackTrace.message && !omitMessage) { lines.unshift(stackTrace.message); } diff --git a/src/core/ExpectationResult.js b/src/core/ExpectationResult.js index 8834b3e0..23c91013 100644 --- a/src/core/ExpectationResult.js +++ b/src/core/ExpectationResult.js @@ -76,7 +76,9 @@ getJasmineRequireObj().buildExpectationResult = function(j$) { } } } - return stackFormatter(error); + // Omit the message from the stack trace because it will be + // included elsewhere. + return stackFormatter(error, { omitMessage: true }); } } From 871ba99a300cba5dc1b0db805ae05bc12649cd80 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 17 Nov 2021 12:50:16 -0800 Subject: [PATCH 47/71] Allow custom spy strategies to be inherited like other runnable resources --- lib/jasmine-core/jasmine.js | 3 +++ spec/core/integration/CustomSpyStrategiesSpec.js | 2 +- src/core/Env.js | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 0a679f7c..eefa05e0 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1604,6 +1604,9 @@ getJasmineRequireObj().Env = function(j$) { resources.customObjectFormatters = j$.util.clone( runnableResources[parentRunnableId].customObjectFormatters ); + resources.customSpyStrategies = j$.util.clone( + runnableResources[parentRunnableId].customSpyStrategies + ); resources.defaultStrategyFn = runnableResources[parentRunnableId].defaultStrategyFn; } diff --git a/spec/core/integration/CustomSpyStrategiesSpec.js b/spec/core/integration/CustomSpyStrategiesSpec.js index 92372c3f..9b6d1eec 100644 --- a/spec/core/integration/CustomSpyStrategiesSpec.js +++ b/spec/core/integration/CustomSpyStrategiesSpec.js @@ -16,7 +16,7 @@ describe('Custom Spy Strategies (Integration)', function() { var jasmineDone = jasmine.createSpy('jasmineDone'); env.describe('suite defining a custom spy strategy', function() { - env.beforeEach(function() { + env.beforeAll(function() { env.addSpyStrategy('frobnicate', strategy); }); diff --git a/src/core/Env.js b/src/core/Env.js index ddd9d4ee..394b5363 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -441,6 +441,9 @@ getJasmineRequireObj().Env = function(j$) { resources.customObjectFormatters = j$.util.clone( runnableResources[parentRunnableId].customObjectFormatters ); + resources.customSpyStrategies = j$.util.clone( + runnableResources[parentRunnableId].customSpyStrategies + ); resources.defaultStrategyFn = runnableResources[parentRunnableId].defaultStrategyFn; } From 42e6c45efa8c427fc8bd612d587a2f32d9aafa73 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 29 Nov 2021 18:49:05 -0800 Subject: [PATCH 48/71] Allow use without creating globals * Fixes #1235 --- Gruntfile.js | 14 ++++++- lib/jasmine-core.js | 38 ++++++++++++++++++- lib/jasmine-core/jasmine.js | 2 + package.json | 1 + spec/core/JsApiReporterSpec.js | 2 +- spec/core/QueueRunnerSpec.js | 24 ++++++------ spec/core/TimerSpec.js | 2 + spec/core/TreeProcessorSpec.js | 22 +++++------ spec/core/integration/EnvSpec.js | 2 +- spec/core/matchers/DiffBuilderSpec.js | 4 +- spec/core/matchers/matchersUtilSpec.js | 2 +- .../matchers/toHaveBeenCalledBeforeSpec.js | 4 +- spec/html/HtmlReporterSpec.js | 4 -- spec/npmPackage/npmPackageSpec.js | 2 +- src/core/CompleteOnFirstErrorSkipPolicy.js | 2 + 15 files changed, 88 insertions(+), 37 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index cef1eb15..9a04fccb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -28,7 +28,8 @@ module.exports = function(grunt) { grunt.registerTask("execSpecsInNode", "Run Jasmine core specs in Node.js", function() { - var done = this.async(), + verifyNoGlobals(() => require('./lib/jasmine-core.js').noGlobals()); + const done = this.async(), Jasmine = require('jasmine'), jasmineCore = require('./lib/jasmine-core.js'), jasmine = new Jasmine({jasmineCore: jasmineCore}); @@ -52,3 +53,14 @@ module.exports = function(grunt) { } ); }; + +function verifyNoGlobals(fn) { + const initialGlobals = Object.keys(global); + fn(); + + const extras = Object.keys(global).filter(k => !initialGlobals.includes(k)); + + if (extras.length !== 0) { + throw new Error('Globals were unexpectedly created: ' + extras.join(', ')); + } +} diff --git a/lib/jasmine-core.js b/lib/jasmine-core.js index 886b7920..314ff9e7 100644 --- a/lib/jasmine-core.js +++ b/lib/jasmine-core.js @@ -1,6 +1,42 @@ -module.exports = require("./jasmine-core/jasmine.js"); +/** + * Note: Only available on Node. + * @module jasmine-core + */ + +const jasmineRequire = require('./jasmine-core/jasmine.js'); +module.exports = jasmineRequire; + +/** + * Boots a copy of Jasmine and returns an object as described in {@link jasmine}. + * @type {function} + * @return {jasmine} + */ module.exports.boot = require('./jasmine-core/node_boot.js'); +/** + * Boots a copy of Jasmine and returns an object containing the properties + * that would normally be added to the global object. If noGlobals is called + * multiple times, the same object is returned every time. + * + * Do not call boot() if you also call noGlobals(). + * + * @example + * const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals(); + */ +module.exports.noGlobals = (function() { + let jasmineInterface; + + return function bootWithoutGlobals() { + if (!jasmineInterface) { + const jasmine = jasmineRequire.core(jasmineRequire); + const env = jasmine.getEnv({ suppressLoadErrors: true }); + jasmineInterface = jasmineRequire.interface(jasmine, env); + } + + return jasmineInterface; + }; +}()); + var path = require('path'), fs = require('fs'); diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index d93e08c1..947a8b7f 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3482,6 +3482,8 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + let i; + for ( i = lastRanFnIx + 1; i < this.queueableFns_.length && this.shouldSkip_(i); diff --git a/package.json b/package.json index 4035265c..7f8d3815 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "args": "none" } ], + "no-implicit-globals": "error", "block-spacing": "error", "func-call-spacing": [ "error", diff --git a/spec/core/JsApiReporterSpec.js b/spec/core/JsApiReporterSpec.js index d0985a31..ea3e67b7 100644 --- a/spec/core/JsApiReporterSpec.js +++ b/spec/core/JsApiReporterSpec.js @@ -99,7 +99,7 @@ describe('JsApiReporter', function() { }); describe('#suiteResults', function() { - var reporter, suiteResult1, suiteResult2; + var reporter, suiteStarted1, suiteResult1, suiteResult2; beforeEach(function() { reporter = new jasmineUnderTest.JsApiReporter({}); suiteStarted1 = { diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 34141f4f..5adf6ea7 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -471,20 +471,20 @@ describe('QueueRunner', function() { }, 100); return p1; } - }; - (queueableFn2 = { - fn: function() { - fnCallback(); - setTimeout(function() { - p2.resolveHandler(); - }, 100); - return p2; - } - }), - (queueRunner = new jasmineUnderTest.QueueRunner({ + }, + queueableFn2 = { + fn: function() { + fnCallback(); + setTimeout(function() { + p2.resolveHandler(); + }, 100); + return p2; + } + }, + queueRunner = new jasmineUnderTest.QueueRunner({ queueableFns: [queueableFn1, queueableFn2], onComplete: onComplete - })); + }); queueRunner.execute(); expect(fnCallback).not.toHaveBeenCalled(); diff --git a/spec/core/TimerSpec.js b/spec/core/TimerSpec.js index f733f0d9..39d74dc6 100644 --- a/spec/core/TimerSpec.js +++ b/spec/core/TimerSpec.js @@ -14,10 +14,12 @@ describe('Timer', function() { describe('when date is stubbed, perhaps by other testing helpers', function() { var origDate = Date; beforeEach(function() { + // eslint-disable-next-line no-implicit-globals Date = jasmine.createSpy('date spy'); }); afterEach(function() { + // eslint-disable-next-line no-implicit-globals Date = origDate; }); diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index 7ada587d..c33a0000 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -513,20 +513,20 @@ describe('TreeProcessor', function() { it('runs afterAlls for a node with children', function() { var leaf = new Leaf(), - afterAllFns = [{ fn: 'afterAll1' }, { fn: 'afterAll2' }]; - (node = new Node({ - children: [leaf], - afterAllFns - })), - (root = new Node({ children: [node] })), - (queueRunner = jasmine.createSpy('queueRunner')), - (processor = new jasmineUnderTest.TreeProcessor({ + afterAllFns = [{ fn: 'afterAll1' }, { fn: 'afterAll2' }], + node = new Node({ + children: [leaf], + afterAllFns + }), + root = new Node({ children: [node] }), + queueRunner = jasmine.createSpy('queueRunner'), + processor = new jasmineUnderTest.TreeProcessor({ tree: root, runnableIds: [node.id], queueRunnerFactory: queueRunner - })), - (treeComplete = jasmine.createSpy('treeComplete')), - (nodeDone = jasmine.createSpy('nodeDone')); + }), + treeComplete = jasmine.createSpy('treeComplete'), + nodeDone = jasmine.createSpy('nodeDone'); processor.execute(treeComplete); var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns; diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 45846e4f..b7b607df 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3427,7 +3427,7 @@ describe('Env integration', function() { const spiedOnAllFuncs = { foo: function() {} }; env.spyOnAllFunctions(spiedOnAllFuncs); - for (spy of [ + for (const spy of [ createSpySpy, spiedOn.foo, spyObj.foo, diff --git a/spec/core/matchers/DiffBuilderSpec.js b/spec/core/matchers/DiffBuilderSpec.js index d1a3d884..840eff68 100644 --- a/spec/core/matchers/DiffBuilderSpec.js +++ b/spec/core/matchers/DiffBuilderSpec.js @@ -112,7 +112,7 @@ describe('DiffBuilder', function() { return '[number:' + x + ']'; } }; - prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); + const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); var diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); @@ -131,7 +131,7 @@ describe('DiffBuilder', function() { return '[thing with a=' + x.a + ', b=' + JSON.stringify(x.b) + ']'; } }; - prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); + const prettyPrinter = jasmineUnderTest.makePrettyPrinter([formatter]); var diffBuilder = new jasmineUnderTest.DiffBuilder({ prettyPrinter: prettyPrinter }); diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index a01c16e4..b9dc1727 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -94,7 +94,7 @@ describe('matchersUtil', function() { }); it('fails for Arrays that have different lengths', function() { - matchersUtil = new jasmineUnderTest.MatchersUtil(); + const matchersUtil = new jasmineUnderTest.MatchersUtil(); expect(matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false); }); diff --git a/spec/core/matchers/toHaveBeenCalledBeforeSpec.js b/spec/core/matchers/toHaveBeenCalledBeforeSpec.js index 2bf316e3..b8ad4951 100644 --- a/spec/core/matchers/toHaveBeenCalledBeforeSpec.js +++ b/spec/core/matchers/toHaveBeenCalledBeforeSpec.js @@ -30,7 +30,7 @@ describe('toHaveBeenCalledBefore', function() { secondSpy(); - result = matcher.compare(firstSpy, secondSpy); + const result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toMatch( /Expected spy first spy to have been called./ @@ -44,7 +44,7 @@ describe('toHaveBeenCalledBefore', function() { firstSpy(); - result = matcher.compare(firstSpy, secondSpy); + const result = matcher.compare(firstSpy, secondSpy); expect(result.pass).toBe(false); expect(result.message).toMatch( /Expected spy second spy to have been called./ diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index 19e2ef97..32350f81 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -73,10 +73,6 @@ describe('HtmlReporter', function() { describe('and no expectations ran', function() { var container, reporter; beforeEach(function() { - if (typeof console === 'undefined') { - console = { warn: function() {}, error: function() {} }; - } - container = document.createElement('div'); reporter = new jasmineUnderTest.HtmlReporter({ env: env, diff --git a/spec/npmPackage/npmPackageSpec.js b/spec/npmPackage/npmPackageSpec.js index be141dde..f5995c92 100644 --- a/spec/npmPackage/npmPackageSpec.js +++ b/spec/npmPackage/npmPackageSpec.js @@ -143,7 +143,7 @@ describe('npm package', function() { j; for (j = 0; j < dirents.length; j++) { - dirent = dirents[j]; + const dirent = dirents[j]; if (dirent.isDirectory()) { getFiles(path.resolve(dir, dirent.name)); diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index 5be5c79f..1dcc4019 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -5,6 +5,8 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { } CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + let i; + for ( i = lastRanFnIx + 1; i < this.queueableFns_.length && this.shouldSkip_(i); From d739c23401e1a1bf427ec6cb0b79b13f9231e5c0 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 30 Nov 2021 20:05:23 -0800 Subject: [PATCH 49/71] Resolve the promise returned by Env#execute to the overall status --- lib/jasmine-core/jasmine.js | 18 +++--- .../integration/CustomSpyStrategiesSpec.js | 57 +++++-------------- .../integration/DefaultSpyStrategySpec.js | 26 ++------- spec/core/integration/EnvSpec.js | 4 +- src/core/Env.js | 18 +++--- 5 files changed, 45 insertions(+), 78 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 947a8b7f..0452e26a 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1832,19 +1832,21 @@ getJasmineRequireObj().Env = function(j$) { * the second parameter. To specify a completion callback but not a list of * specs/suites to run, pass null or undefined as the first parameter. * - * execute should not be called more than once. + * execute should not be called more than once unless the env has been + * configured with `{autoCleanClosures: false}`. * * If the environment supports promises, execute will return a promise that * is resolved after the suite finishes executing. The promise will be - * resolved (not rejected) as long as the suite runs to completion. Use a - * {@link Reporter} to determine whether or not the suite passed. + * resolved (not rejected) to the suite's overall status as long as the + * suite runs to completion. To determine whether the suite passed, check + * the value that the promise resolves to or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run - * @return {Promise} + * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { @@ -1910,12 +1912,12 @@ getJasmineRequireObj().Env = function(j$) { jasmineTimer.start(); return new Promise(function(resolve) { - runAll(function() { + runAll(function(overallStatus) { if (onComplete) { onComplete(); } - resolve(); + resolve(overallStatus); }); }); @@ -1975,7 +1977,9 @@ getJasmineRequireObj().Env = function(j$) { failedExpectations: topSuite.result.failedExpectations, deprecationWarnings: topSuite.result.deprecationWarnings }, - done + function() { + done(overallStatus); + } ); }); } diff --git a/spec/core/integration/CustomSpyStrategiesSpec.js b/spec/core/integration/CustomSpyStrategiesSpec.js index 9b6d1eec..3581e96b 100644 --- a/spec/core/integration/CustomSpyStrategiesSpec.js +++ b/spec/core/integration/CustomSpyStrategiesSpec.js @@ -10,10 +10,9 @@ describe('Custom Spy Strategies (Integration)', function() { env.cleanup_(); }); - it('allows adding more strategies local to a suite', function(done) { + it('allows adding more strategies local to a suite', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); - var jasmineDone = jasmine.createSpy('jasmineDone'); env.describe('suite defining a custom spy strategy', function() { env.beforeAll(function() { @@ -32,20 +31,13 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(null, expectations); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); }); - it('allows adding more strategies local to a spec', function(done) { + it('allows adding more strategies local to a spec', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); - var jasmineDone = jasmine.createSpy('jasmineDone'); env.it('spec defining a custom spy strategy', function() { env.addSpyStrategy('frobnicate', strategy); @@ -59,20 +51,13 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(null, expectations); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); }); - it('allows using custom strategies on a per-argument basis', function(done) { + it('allows using custom strategies on a per-argument basis', async function() { var plan = jasmine.createSpy('custom strategy plan').and.returnValue(42); var strategy = jasmine.createSpy('custom strategy').and.returnValue(plan); - var jasmineDone = jasmine.createSpy('jasmineDone'); env.it('spec defining a custom spy strategy', function() { env.addSpyStrategy('frobnicate', strategy); @@ -92,23 +77,16 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(null, expectations); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); }); - it('allows multiple custom strategies to be used', function(done) { + it('allows multiple custom strategies to be used', async function() { var plan1 = jasmine.createSpy('plan 1').and.returnValue(42), strategy1 = jasmine.createSpy('strat 1').and.returnValue(plan1), plan2 = jasmine.createSpy('plan 2').and.returnValue(24), strategy2 = jasmine.createSpy('strat 2').and.returnValue(plan2), - specDone = jasmine.createSpy('specDone'), - jasmineDone = jasmine.createSpy('jasmineDone'); + specDone = jasmine.createSpy('specDone'); env.beforeEach(function() { env.addSpyStrategy('frobnicate', strategy1); @@ -133,14 +111,9 @@ describe('Custom Spy Strategies (Integration)', function() { expect(plan2).toHaveBeenCalled(); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - expect(specDone.calls.count()).toBe(2); - done(); - } - - env.addReporter({ jasmineDone: jasmineDone, specDone: specDone }); - env.execute(null, expectations); + env.addReporter({ specDone: specDone }); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); + expect(specDone.calls.count()).toBe(2); }); }); diff --git a/spec/core/integration/DefaultSpyStrategySpec.js b/spec/core/integration/DefaultSpyStrategySpec.js index 3f17a1d4..bbe31a76 100644 --- a/spec/core/integration/DefaultSpyStrategySpec.js +++ b/spec/core/integration/DefaultSpyStrategySpec.js @@ -10,7 +10,7 @@ describe('Default Spy Strategy (Integration)', function() { env.cleanup_(); }); - it('allows defining a default spy strategy', function(done) { + it('allows defining a default spy strategy', async function() { env.describe('suite with default strategy', function() { env.beforeEach(function() { env.setDefaultSpyStrategy(function(and) { @@ -29,18 +29,11 @@ describe('Default Spy Strategy (Integration)', function() { expect(spy()).toBeUndefined(); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - done(); - } - - var jasmineDone = jasmine.createSpy('jasmineDone'); - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(null, expectations); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); }); - it('uses the default spy strategy defined when the spy is created', function(done) { + it('uses the default spy strategy defined when the spy is created', async function() { env.it('spec', function() { var a = env.createSpy('a'); env.setDefaultSpyStrategy(function(and) { @@ -67,14 +60,7 @@ describe('Default Spy Strategy (Integration)', function() { expect(d.and.isConfigured()).toBe(false); }); - function expectations() { - var result = jasmineDone.calls.argsFor(0)[0]; - expect(result.overallStatus).toEqual('passed'); - done(); - } - - var jasmineDone = jasmine.createSpy('jasmineDone'); - env.addReporter({ jasmineDone: jasmineDone }); - env.execute(null, expectations); + const overallStatus = await env.execute(); + expect(overallStatus).toEqual('passed'); }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index b7b607df..e800f184 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3229,14 +3229,14 @@ describe('Env integration', function() { }); }); - it('is resolved even if specs fail', function() { + it('is resolved to the overall status', function() { env.describe('suite', function() { env.it('spec', function() { env.expect(true).toBe(false); }); }); - return expectAsync(env.execute(null)).toBeResolved(); + return expectAsync(env.execute(null)).toBeResolvedTo('failed'); }); }); diff --git a/src/core/Env.js b/src/core/Env.js index 394b5363..b5be2ed0 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -669,19 +669,21 @@ getJasmineRequireObj().Env = function(j$) { * the second parameter. To specify a completion callback but not a list of * specs/suites to run, pass null or undefined as the first parameter. * - * execute should not be called more than once. + * execute should not be called more than once unless the env has been + * configured with `{autoCleanClosures: false}`. * * If the environment supports promises, execute will return a promise that * is resolved after the suite finishes executing. The promise will be - * resolved (not rejected) as long as the suite runs to completion. Use a - * {@link Reporter} to determine whether or not the suite passed. + * resolved (not rejected) to the suite's overall status as long as the + * suite runs to completion. To determine whether the suite passed, check + * the value that the promise resolves to or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run - * @return {Promise} + * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { @@ -747,12 +749,12 @@ getJasmineRequireObj().Env = function(j$) { jasmineTimer.start(); return new Promise(function(resolve) { - runAll(function() { + runAll(function(overallStatus) { if (onComplete) { onComplete(); } - resolve(); + resolve(overallStatus); }); }); @@ -812,7 +814,9 @@ getJasmineRequireObj().Env = function(j$) { failedExpectations: topSuite.result.failedExpectations, deprecationWarnings: topSuite.result.deprecationWarnings }, - done + function() { + done(overallStatus); + } ); }); } From 5eb42d67a764a763cb68465e17655b3286031dea Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 2 Dec 2021 12:12:59 -0800 Subject: [PATCH 50/71] Added a note about async testing style to contributing guide --- .github/CONTRIBUTING.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 271dae5b..573b8866 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -97,7 +97,12 @@ Or, How to make a successful pull request without test-driving it. * _Write code in the style of the rest of the repo_ - Jasmine should look like a cohesive whole. - * **Exception**: Prefer `const` or `let` over `var`. + + **Key exceptions:** + * Use `const` or `let` for new variable declarations, even if nearby code + uses `var`. + * New async specs should usually be async/await or promise-returning, not + callback based. * _Ensure the *entire* test suite is green_ in all the big browsers, Node, and ESLint. Your contribution shouldn't break Jasmine for other users. From 40fac8b6a27bc40d6e14eadba640d0429886411a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 2 Dec 2021 14:46:56 -0800 Subject: [PATCH 51/71] Renamed the trace feature to debugLog[s] "trace" was ambiguous and could easily be understood to have something to do with stack traces. --- lib/jasmine-core/jasmine-html.js | 14 ++++----- lib/jasmine-core/jasmine.css | 6 ++-- lib/jasmine-core/jasmine.js | 54 +++++++++++++------------------- spec/core/SpecSpec.js | 26 ++++++++------- spec/core/baseSpec.js | 12 ++++--- spec/core/integration/EnvSpec.js | 18 +++++------ spec/html/HtmlReporterSpec.js | 14 ++++----- src/core/Env.js | 8 ++--- src/core/Spec.js | 38 ++++++++-------------- src/core/base.js | 8 ++--- src/html/HtmlReporter.js | 14 ++++----- src/html/_HTMLReporter.scss | 2 +- 12 files changed, 97 insertions(+), 117 deletions(-) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 8e4917b7..4b1454b5 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -436,17 +436,17 @@ jasmineRequire.HtmlReporter = function(j$) { ); } - if (result.trace) { - messages.appendChild(traceTable(result.trace)); + if (result.debugLogs) { + messages.appendChild(debugLogTable(result.debugLogs)); } return failure; } - function traceTable(trace) { + function debugLogTable(debugLogs) { var tbody = createDom('tbody'); - trace.forEach(function(entry) { + debugLogs.forEach(function(entry) { tbody.appendChild( createDom( 'tr', @@ -459,11 +459,11 @@ jasmineRequire.HtmlReporter = function(j$) { return createDom( 'div', - { className: 'jasmine-trace' }, + { className: 'jasmine-debug-log' }, createDom( 'div', - { className: 'jasmine-trace-header' }, - 'Trace information' + { className: 'jasmine-debug-log-header' }, + 'Debug logs' ), createDom( 'table', diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 9c70317f..70ab3592 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -288,16 +288,16 @@ body { margin-left: 14px; padding: 5px; } -.jasmine_html-reporter .jasmine-trace { +.jasmine_html-reporter .jasmine-debug-log { margin: 5px 0 0 0; padding: 5px; color: #666; border: 1px solid #ddd; background: white; } -.jasmine_html-reporter .jasmine-trace table { +.jasmine_html-reporter .jasmine-debug-log table { border-spacing: 0; } -.jasmine_html-reporter .jasmine-trace table, .jasmine_html-reporter .jasmine-trace th, .jasmine_html-reporter .jasmine-trace td { +.jasmine_html-reporter .jasmine-debug-log table, .jasmine_html-reporter .jasmine-debug-log th, .jasmine_html-reporter .jasmine-debug-log td { border: 1px solid #ddd; } \ No newline at end of file diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 0452e26a..b6301afd 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -575,12 +575,12 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { * This method should be called only when a spec (including any associated * beforeEach or afterEach functions) is running. * @function - * @name jasmine.trace - * @since 3.10.0 + * @name jasmine.debugLog + * @since 4.0.0 * @param {String} msg - The message to log */ - j$.trace = function(msg) { - j$.getEnv().trace(msg); + j$.debugLog = function(msg) { + j$.getEnv().debugLog(msg); }; }; @@ -804,7 +804,7 @@ 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} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link jasmine.trace} during a failing spec. + * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. * @since 2.0.0 */ this.result = { @@ -817,7 +817,7 @@ getJasmineRequireObj().Spec = function(j$) { pendingReason: '', duration: null, properties: null, - trace: null + debugLogs: null }; } @@ -866,7 +866,7 @@ getJasmineRequireObj().Spec = function(j$) { self.result.duration = self.timer.elapsed(); if (self.result.status !== 'failed') { - self.result.trace = null; + self.result.debugLogs = null; } self.resultCallback(self.result, done); @@ -917,21 +917,6 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.reset = function() { - /** - * @typedef SpecResult - * @property {Int} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. - * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. - * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. - * @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 properties, if any, that were set using {@link Env#setSpecProperty} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. - * @since 2.0.0 - */ this.result = { id: this.id, description: this.description, @@ -942,7 +927,7 @@ getJasmineRequireObj().Spec = function(j$) { pendingReason: this.excludeMessage, duration: null, properties: null, - trace: null + debugLogs: null }; this.markedPending = this.markedExcluding; }; @@ -1041,18 +1026,21 @@ getJasmineRequireObj().Spec = function(j$) { ); }; - Spec.prototype.trace = function(msg) { - if (!this.result.trace) { - this.result.trace = []; + Spec.prototype.debugLog = function(msg) { + if (!this.result.debugLogs) { + this.result.debugLogs = []; } /** - * @typedef TraceEntry - * @property {String} message - The message that was passed to {@link jasmine.trace}. + * @typedef DebugLogEntry + * @property {String} message - The message that was passed to {@link jasmine.debugLog}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ - this.result.trace.push({ message: msg, timestamp: this.timer.elapsed() }); + this.result.debugLogs.push({ + message: msg, + timestamp: this.timer.elapsed() + }); }; var extractCustomPendingMessage = function(e) { @@ -2353,14 +2341,14 @@ getJasmineRequireObj().Env = function(j$) { currentSuite().setSuiteProperty(key, value); }; - this.trace = function(msg) { + this.debugLog = function(msg) { var maybeSpec = currentRunnable(); - if (!maybeSpec || !maybeSpec.trace) { - throw new Error("'trace' was called when there was no current spec"); + if (!maybeSpec || !maybeSpec.debugLog) { + throw new Error("'debugLog' was called when there was no current spec"); } - maybeSpec.trace(msg); + maybeSpec.debugLog(msg); }; this.expect = function(actual) { diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index 6abb1f9e..9efebbdf 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -234,7 +234,7 @@ describe('Spec', function() { pendingReason: '', duration: jasmine.any(Number), properties: null, - trace: null + debugLogs: null }, 'things' ); @@ -562,13 +562,15 @@ describe('Spec', function() { t2 = 456; spec.execute(); - expect(spec.result.trace).toBeNull(); + expect(spec.result.debugLogs).toBeNull(); timer.elapsed.and.returnValue(t1); - spec.trace('msg 1'); - expect(spec.result.trace).toEqual([{ message: 'msg 1', timestamp: t1 }]); + spec.debugLog('msg 1'); + expect(spec.result.debugLogs).toEqual([ + { message: 'msg 1', timestamp: t1 } + ]); timer.elapsed.and.returnValue(t2); - spec.trace('msg 2'); - expect(spec.result.trace).toEqual([ + spec.debugLog('msg 2'); + expect(spec.result.debugLogs).toEqual([ { message: 'msg 1', timestamp: t1 }, { message: 'msg 2', timestamp: t2 } ]); @@ -583,7 +585,7 @@ describe('Spec', function() { }, resultCallback: resultCallback, queueRunnerFactory: function(config) { - spec.trace('msg'); + spec.debugLog('msg'); for (const fn of config.queueableFns) { fn.fn(); } @@ -593,7 +595,7 @@ describe('Spec', function() { spec.execute(function() {}); expect(resultCallback).toHaveBeenCalledWith( - jasmine.objectContaining({ trace: null }), + jasmine.objectContaining({ debugLogs: null }), undefined ); }); @@ -606,7 +608,7 @@ describe('Spec', function() { }, resultCallback: resultCallback, queueRunnerFactory: function(config) { - spec.trace('msg'); + spec.debugLog('msg'); for (const fn of config.queueableFns) { fn.fn(); } @@ -616,7 +618,7 @@ describe('Spec', function() { spec.execute(function() {}); expect(resultCallback).toHaveBeenCalled(); - expect(spec.result.trace).toBeNull(); + expect(spec.result.debugLogs).toBeNull(); }); }); @@ -630,7 +632,7 @@ describe('Spec', function() { }, resultCallback: resultCallback, queueRunnerFactory: function(config) { - spec.trace('msg'); + spec.debugLog('msg'); spec.onException(new Error('nope')); for (const fn of config.queueableFns) { fn.fn(); @@ -646,7 +648,7 @@ describe('Spec', function() { spec.execute(function() {}); expect(resultCallback).toHaveBeenCalledWith( jasmine.objectContaining({ - trace: [{ message: 'msg', timestamp: timestamp }] + debugLogs: [{ message: 'msg', timestamp: timestamp }] }), undefined ); diff --git a/spec/core/baseSpec.js b/spec/core/baseSpec.js index 9cd94bd7..703a4f50 100644 --- a/spec/core/baseSpec.js +++ b/spec/core/baseSpec.js @@ -199,11 +199,13 @@ describe('base helpers', function() { }); }); - describe('trace', function() { - it("forwards to the current env's trace function", function() { - spyOn(jasmineUnderTest.getEnv(), 'trace'); - jasmineUnderTest.trace('a message'); - expect(jasmineUnderTest.getEnv().trace).toHaveBeenCalledWith('a message'); + describe('debugLog', function() { + it("forwards to the current env's debugLog function", function() { + spyOn(jasmineUnderTest.getEnv(), 'debugLog'); + jasmineUnderTest.debugLog('a message'); + expect(jasmineUnderTest.getEnv().debugLog).toHaveBeenCalledWith( + 'a message' + ); }); }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index e800f184..c46adbee 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3335,7 +3335,7 @@ describe('Env integration', function() { }); }); - it('sends traces to the reporter when the spec fails', function(done) { + it('sends debug logs to the reporter when the spec fails', function(done) { var reporter = jasmine.createSpyObj('reporter', ['specDone']), startTime, endTime; @@ -3345,14 +3345,14 @@ describe('Env integration', function() { env.it('fails', function() { startTime = new Date().getTime(); - env.trace('message 1'); - env.trace('message 2'); + env.debugLog('message 1'); + env.debugLog('message 2'); env.expect(1).toBe(2); endTime = new Date().getTime(); }); env.it('passes', function() { - env.trace('message that should not be reported'); + env.debugLog('message that should not be reported'); }); env.execute(null, function() { @@ -3373,7 +3373,7 @@ describe('Env integration', function() { duration = reporter.specDone.calls.argsFor(0)[0].duration; expect(reporter.specDone.calls.argsFor(0)[0]).toEqual( jasmine.objectContaining({ - trace: [ + debugLogs: [ { timestamp: numberInRange(0, duration), message: 'message 1' @@ -3385,17 +3385,17 @@ describe('Env integration', function() { ] }) ); - expect(reporter.specDone.calls.argsFor(1)[0].trace).toBeFalsy(); + expect(reporter.specDone.calls.argsFor(1)[0].debugLogs).toBeFalsy(); done(); }); }); - it('reports an error when trace is used when a spec is not running', function(done) { + it('reports an error when debugLog is used when a spec is not running', function(done) { var reporter = jasmine.createSpyObj('reporter', ['suiteDone']); env.describe('a suite', function() { env.beforeAll(function() { - env.trace('a message'); + env.debugLog('a message'); }); env.it('a spec', function() {}); @@ -3408,7 +3408,7 @@ describe('Env integration', function() { failedExpectations: [ jasmine.objectContaining({ message: jasmine.stringContaining( - "'trace' was called when there was no current spec" + "'debugLog' was called when there was no current spec" ) }) ] diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index 32350f81..d31a3a35 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -1510,7 +1510,7 @@ describe('HtmlReporter', function() { } ] }; - var failingSpecResultWithTrace = { + var failingSpecResultWithDebugLogs = { id: 567, status: 'failed', description: 'a failing spec', @@ -1522,7 +1522,7 @@ describe('HtmlReporter', function() { stack: 'a stack trace' } ], - trace: [ + debugLogs: [ { timestamp: 123, message: 'msg 1' }, { timestamp: 456, message: 'msg 1' } ] @@ -1544,8 +1544,8 @@ describe('HtmlReporter', function() { reporter.suiteDone(passingSuiteResult); reporter.suiteDone(failingSuiteResult); reporter.suiteDone(passingSuiteResult); - reporter.specStarted(failingSpecResultWithTrace); - reporter.specDone(failingSpecResultWithTrace); + reporter.specStarted(failingSpecResultWithDebugLogs); + reporter.specDone(failingSpecResultWithDebugLogs); reporter.jasmineDone({}); }); @@ -1602,11 +1602,11 @@ describe('HtmlReporter', function() { var specFailure = container.querySelectorAll( '.jasmine-spec-detail.jasmine-failed' )[2], - trace = specFailure.querySelector('.jasmine-trace table'), + debugLogs = specFailure.querySelector('.jasmine-debug-log table'), rows; - expect(trace).toBeTruthy(); - rows = trace.querySelectorAll('tbody tr'); + expect(debugLogs).toBeTruthy(); + rows = debugLogs.querySelectorAll('tbody tr'); expect(rows.length).toEqual(2); }); diff --git a/src/core/Env.js b/src/core/Env.js index b5be2ed0..7de139b3 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -1190,14 +1190,14 @@ getJasmineRequireObj().Env = function(j$) { currentSuite().setSuiteProperty(key, value); }; - this.trace = function(msg) { + this.debugLog = function(msg) { var maybeSpec = currentRunnable(); - if (!maybeSpec || !maybeSpec.trace) { - throw new Error("'trace' was called when there was no current spec"); + if (!maybeSpec || !maybeSpec.debugLog) { + throw new Error("'debugLog' was called when there was no current spec"); } - maybeSpec.trace(msg); + maybeSpec.debugLog(msg); }; this.expect = function(actual) { diff --git a/src/core/Spec.js b/src/core/Spec.js index e0a86dd8..f9a774a8 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -71,7 +71,7 @@ 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} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link jasmine.trace} during a failing spec. + * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec. * @since 2.0.0 */ this.result = { @@ -84,7 +84,7 @@ getJasmineRequireObj().Spec = function(j$) { pendingReason: '', duration: null, properties: null, - trace: null + debugLogs: null }; } @@ -133,7 +133,7 @@ getJasmineRequireObj().Spec = function(j$) { self.result.duration = self.timer.elapsed(); if (self.result.status !== 'failed') { - self.result.trace = null; + self.result.debugLogs = null; } self.resultCallback(self.result, done); @@ -184,21 +184,6 @@ getJasmineRequireObj().Spec = function(j$) { }; Spec.prototype.reset = function() { - /** - * @typedef SpecResult - * @property {Int} id - The unique id of this spec. - * @property {String} description - The description passed to the {@link it} that created this spec. - * @property {String} fullName - The full description including all ancestors of this spec. - * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. - * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. - * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. - * @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 properties, if any, that were set using {@link Env#setSpecProperty} - * @property {TraceEntry[]|null} trace - Trace messages, if any, that were logged using {@link Env#trace} during a failing spec. - * @since 2.0.0 - */ this.result = { id: this.id, description: this.description, @@ -209,7 +194,7 @@ getJasmineRequireObj().Spec = function(j$) { pendingReason: this.excludeMessage, duration: null, properties: null, - trace: null + debugLogs: null }; this.markedPending = this.markedExcluding; }; @@ -308,18 +293,21 @@ getJasmineRequireObj().Spec = function(j$) { ); }; - Spec.prototype.trace = function(msg) { - if (!this.result.trace) { - this.result.trace = []; + Spec.prototype.debugLog = function(msg) { + if (!this.result.debugLogs) { + this.result.debugLogs = []; } /** - * @typedef TraceEntry - * @property {String} message - The message that was passed to {@link jasmine.trace}. + * @typedef DebugLogEntry + * @property {String} message - The message that was passed to {@link jasmine.debugLog}. * @property {number} timestamp - The time when the entry was added, in * milliseconds from the spec's start time */ - this.result.trace.push({ message: msg, timestamp: this.timer.elapsed() }); + this.result.debugLogs.push({ + message: msg, + timestamp: this.timer.elapsed() + }); }; var extractCustomPendingMessage = function(e) { diff --git a/src/core/base.js b/src/core/base.js index c0a13503..2e953541 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -406,11 +406,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { * This method should be called only when a spec (including any associated * beforeEach or afterEach functions) is running. * @function - * @name jasmine.trace - * @since 3.10.0 + * @name jasmine.debugLog + * @since 4.0.0 * @param {String} msg - The message to log */ - j$.trace = function(msg) { - j$.getEnv().trace(msg); + j$.debugLog = function(msg) { + j$.getEnv().debugLog(msg); }; }; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 7a3afc41..840bbcf3 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -405,17 +405,17 @@ jasmineRequire.HtmlReporter = function(j$) { ); } - if (result.trace) { - messages.appendChild(traceTable(result.trace)); + if (result.debugLogs) { + messages.appendChild(debugLogTable(result.debugLogs)); } return failure; } - function traceTable(trace) { + function debugLogTable(debugLogs) { var tbody = createDom('tbody'); - trace.forEach(function(entry) { + debugLogs.forEach(function(entry) { tbody.appendChild( createDom( 'tr', @@ -428,11 +428,11 @@ jasmineRequire.HtmlReporter = function(j$) { return createDom( 'div', - { className: 'jasmine-trace' }, + { className: 'jasmine-debug-log' }, createDom( 'div', - { className: 'jasmine-trace-header' }, - 'Trace information' + { className: 'jasmine-debug-log-header' }, + 'Debug logs' ), createDom( 'table', diff --git a/src/html/_HTMLReporter.scss b/src/html/_HTMLReporter.scss index bd8537c4..712f6fbb 100644 --- a/src/html/_HTMLReporter.scss +++ b/src/html/_HTMLReporter.scss @@ -414,7 +414,7 @@ body { padding: 5px; } - .jasmine-trace { + .jasmine-debug-log { margin: 5px 0 0 0; padding: 5px; color: $light-text-color; From b8dabf96ff53670b94d7f3d16e6fefcf43b68a27 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 3 Dec 2021 08:18:18 -0800 Subject: [PATCH 52/71] HTML: Include top suite failures in the reported failure count --- lib/jasmine-core/jasmine-html.js | 7 ++++ spec/html/HtmlReporterSpec.js | 55 ++++++++++++++++++++++++++++++++ src/html/HtmlReporter.js | 7 ++++ 3 files changed, 69 insertions(+) diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 4b1454b5..64a8213a 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -72,6 +72,12 @@ jasmineRequire.HtmlReporter = function(j$) { } }; + ResultsStateBuilder.prototype.jasmineDone = function(result) { + if (result.failedExpectations) { + this.failureCount += result.failedExpectations.length; + } + }; + function HtmlReporter(options) { var config = function() { return (options.env && options.env.configuration()) || {}; @@ -187,6 +193,7 @@ jasmineRequire.HtmlReporter = function(j$) { }; this.jasmineDone = function(doneResult) { + stateBuilder.jasmineDone(doneResult); var banner = find('.jasmine-banner'); var alert = find('.jasmine-alert'); var order = doneResult && doneResult.order; diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index d31a3a35..8a8ae4f2 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -1653,6 +1653,61 @@ describe('HtmlReporter', function() { ); }); }); + + it('counts failures that are reported in the jasmineDone event', function() { + const container = document.createElement('div'); + function getContainer() { + return container; + } + const reporter = new jasmineUnderTest.HtmlReporter({ + env: env, + getContainer: getContainer, + createElement: function() { + return document.createElement.apply(document, arguments); + }, + createTextNode: function() { + return document.createTextNode.apply(document, arguments); + }, + addToExistingQueryString: function(key, value) { + return '?' + key + '=' + value; + } + }); + reporter.initialize(); + + reporter.jasmineStarted({ totalSpecsDefined: 1 }); + + const failingSpecResult = { + id: 124, + status: 'failed', + description: 'a failing spec', + fullName: 'a suite inner suite a failing spec', + passedExpectations: [], + failedExpectations: [ + { + message: 'a failure message', + stack: 'a stack trace' + } + ] + }; + + reporter.specStarted(failingSpecResult); + reporter.specDone(failingSpecResult); + reporter.jasmineDone({ + failedExpectations: [ + { + message: 'a failure message', + stack: 'a stack trace' + }, + { + message: 'a failure message', + stack: 'a stack trace' + } + ] + }); + + const alertBar = container.querySelector('.jasmine-alert .jasmine-bar'); + expect(alertBar.innerHTML).toMatch(/1 spec, 3 failures/); + }); }); describe('The overall result bar', function() { diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 840bbcf3..7f69cb57 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -41,6 +41,12 @@ jasmineRequire.HtmlReporter = function(j$) { } }; + ResultsStateBuilder.prototype.jasmineDone = function(result) { + if (result.failedExpectations) { + this.failureCount += result.failedExpectations.length; + } + }; + function HtmlReporter(options) { var config = function() { return (options.env && options.env.configuration()) || {}; @@ -156,6 +162,7 @@ jasmineRequire.HtmlReporter = function(j$) { }; this.jasmineDone = function(doneResult) { + stateBuilder.jasmineDone(doneResult); var banner = find('.jasmine-banner'); var alert = find('.jasmine-alert'); var order = doneResult && doneResult.order; From ce7460d8d4fda0cb10fb14957fcde40b6b8401c7 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 7 Dec 2021 16:50:07 -0800 Subject: [PATCH 53/71] Fixed stack trace filtering on Safari 15 --- README.md | 5 ++++- lib/jasmine-core/jasmine.js | 2 +- scripts/run-all-browsers | 1 + spec/core/StackTraceSpec.js | 29 ++++++++++++++++++++++++++++- src/core/StackTrace.js | 2 +- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f900383e..160ac27f 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed | Environment | Supported versions | |-------------------|--------------------| | Node | 10, 12, 14, 16 | -| Safari | 8-14 | +| Safari | 8-15 | | Chrome | Evergreen | | Firefox | Evergreen, 68, 78, 91 | | Edge | Evergreen | @@ -62,6 +62,9 @@ For evergreen browsers, each version of Jasmine is tested against the version of at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work. However, Jasmine isn't tested against them and they aren't actively supported. +See the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes) +for the supported environments for each Jasmine release. + ## Support * Search past discussions: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js). diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2ce7c15f..aacb163e 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -9460,7 +9460,7 @@ getJasmineRequireObj().StackTrace = function(j$) { // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27" // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27" { - re: /^(([^@\s]+)@)?([^\s]+)$/, + re: /^(?:(([^@\s]+)@)|@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index 45d74aaa..bc44db36 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -30,6 +30,7 @@ run_browser firefox latest run_browser firefox 91 run_browser firefox 78 run_browser firefox 68 +run_browser safari 15 run_browser safari 14 run_browser safari 13 run_browser safari 9 diff --git a/spec/core/StackTraceSpec.js b/spec/core/StackTraceSpec.js index d041c8e7..3685969c 100644 --- a/spec/core/StackTraceSpec.js +++ b/spec/core/StackTraceSpec.js @@ -95,7 +95,7 @@ describe('StackTrace', function() { ]); }); - it('understands Safari/Firefox/Phantom-OS X style traces', function() { + it('understands Safari <=14/Firefox/Phantom-OS X style traces', function() { var error = { message: 'nope', stack: @@ -122,6 +122,33 @@ describe('StackTrace', function() { ]); }); + it('understands Safari 15 style traces', function() { + var error = { + message: 'nope', + stack: + '@http://localhost:8888/__spec__/core/FooSpec.js:164:24\n' + + 'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44\n' + }; + var result = new jasmineUnderTest.StackTrace(error); + + expect(result.message).toBeFalsy(); + expect(result.style).toEqual('webkit'); + expect(result.frames).toEqual([ + { + raw: '@http://localhost:8888/__spec__/core/FooSpec.js:164:24', + func: undefined, + file: 'http://localhost:8888/__spec__/core/FooSpec.js', + line: 164 + }, + { + raw: 'attempt@http://localhost:8888/__jasmine__/jasmine.js:8074:44', + func: 'attempt', + file: 'http://localhost:8888/__jasmine__/jasmine.js', + line: 8074 + } + ]); + }); + it('does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces', function() { var error = { message: 'nope', diff --git a/src/core/StackTrace.js b/src/core/StackTrace.js index 44db4ff1..5183f2b7 100644 --- a/src/core/StackTrace.js +++ b/src/core/StackTrace.js @@ -36,7 +36,7 @@ getJasmineRequireObj().StackTrace = function(j$) { // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27" // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27" { - re: /^(([^@\s]+)@)?([^\s]+)$/, + re: /^(?:(([^@\s]+)@)|@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' From 89151d6e64c487e624520ebf4be57edc48919cc1 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 7 Dec 2021 17:04:19 -0800 Subject: [PATCH 54/71] Dropped Safari 13 from build matrix --- README.md | 2 +- scripts/run-all-browsers | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 326b8775..11afc05b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed | Environment | Supported versions | |-------------------|--------------------| | Node | 12.17+, 14, 16 | -| Safari | 13-15 | +| Safari | 14-15 | | Chrome | Evergreen | | Firefox | Evergreen, 68, 78, 91 | | Edge | Evergreen | diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index 5d6e254e..5e708a82 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -30,7 +30,6 @@ run_browser firefox 78 run_browser firefox 68 run_browser safari 15 run_browser safari 14 -run_browser safari 13 run_browser MicrosoftEdge latest echo From b37d989f136ddd259e8563c91fe2c34d9aa68d15 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 7 Dec 2021 18:16:00 -0800 Subject: [PATCH 55/71] Removed past-EOL Firefox versions --- README.md | 2 +- scripts/run-all-browsers | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 11afc05b..a33982bb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Ed | Node | 12.17+, 14, 16 | | Safari | 14-15 | | Chrome | Evergreen | -| Firefox | Evergreen, 68, 78, 91 | +| Firefox | Evergreen, 91 | | Edge | Evergreen | For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us diff --git a/scripts/run-all-browsers b/scripts/run-all-browsers index 5e708a82..d4fc6cce 100755 --- a/scripts/run-all-browsers +++ b/scripts/run-all-browsers @@ -26,8 +26,6 @@ failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1 run_browser chrome latest run_browser firefox latest run_browser firefox 91 -run_browser firefox 78 -run_browser firefox 68 run_browser safari 15 run_browser safari 14 run_browser MicrosoftEdge latest From f1cf6ee419990faffb4f7d5af8eebd799a1804fd Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 9 Dec 2021 18:18:36 -0800 Subject: [PATCH 56/71] Resolve the execute() promise to the entire JasmineDoneInfo This matches jasmine-npm. --- lib/jasmine-core/jasmine.js | 28 +++++++++---------- .../integration/CustomSpyStrategiesSpec.js | 16 +++++------ .../integration/DefaultSpyStrategySpec.js | 8 +++--- spec/core/integration/EnvSpec.js | 11 ++++++-- src/core/Env.js | 28 +++++++++---------- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 1fadad3f..9c5a8f47 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1900,12 +1900,12 @@ getJasmineRequireObj().Env = function(j$) { jasmineTimer.start(); return new Promise(function(resolve) { - runAll(function(overallStatus) { + runAll(function(jasmineDoneInfo) { if (onComplete) { onComplete(); } - resolve(overallStatus); + resolve(jasmineDoneInfo); }); }); @@ -1956,19 +1956,17 @@ getJasmineRequireObj().Env = function(j$) { * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. * @since 2.4.0 */ - reporter.jasmineDone( - { - overallStatus: overallStatus, - totalTime: jasmineTimer.elapsed(), - incompleteReason: incompleteReason, - order: order, - failedExpectations: topSuite.result.failedExpectations, - deprecationWarnings: topSuite.result.deprecationWarnings - }, - function() { - done(overallStatus); - } - ); + const jasmineDoneInfo = { + overallStatus: overallStatus, + totalTime: jasmineTimer.elapsed(), + incompleteReason: incompleteReason, + order: order, + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings + }; + reporter.jasmineDone(jasmineDoneInfo, function() { + done(jasmineDoneInfo); + }); }); } ); diff --git a/spec/core/integration/CustomSpyStrategiesSpec.js b/spec/core/integration/CustomSpyStrategiesSpec.js index 3581e96b..676b00a7 100644 --- a/spec/core/integration/CustomSpyStrategiesSpec.js +++ b/spec/core/integration/CustomSpyStrategiesSpec.js @@ -31,8 +31,8 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); }); it('allows adding more strategies local to a spec', async function() { @@ -51,8 +51,8 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); }); it('allows using custom strategies on a per-argument basis', async function() { @@ -77,8 +77,8 @@ describe('Custom Spy Strategies (Integration)', function() { expect(env.createSpy('something').and.frobnicate).toBeUndefined(); }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); }); it('allows multiple custom strategies to be used', async function() { @@ -112,8 +112,8 @@ describe('Custom Spy Strategies (Integration)', function() { }); env.addReporter({ specDone: specDone }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); expect(specDone.calls.count()).toBe(2); }); }); diff --git a/spec/core/integration/DefaultSpyStrategySpec.js b/spec/core/integration/DefaultSpyStrategySpec.js index bbe31a76..87325817 100644 --- a/spec/core/integration/DefaultSpyStrategySpec.js +++ b/spec/core/integration/DefaultSpyStrategySpec.js @@ -29,8 +29,8 @@ describe('Default Spy Strategy (Integration)', function() { expect(spy()).toBeUndefined(); }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); }); it('uses the default spy strategy defined when the spy is created', async function() { @@ -60,7 +60,7 @@ describe('Default Spy Strategy (Integration)', function() { expect(d.and.isConfigured()).toBe(false); }); - const overallStatus = await env.execute(); - expect(overallStatus).toEqual('passed'); + const result = await env.execute(); + expect(result.overallStatus).toEqual('passed'); }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index c46adbee..14d9e759 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -3229,14 +3229,21 @@ describe('Env integration', function() { }); }); - it('is resolved to the overall status', function() { + it('is resolved to the value of the jasmineDone event', async function() { env.describe('suite', function() { env.it('spec', function() { env.expect(true).toBe(false); }); }); - return expectAsync(env.execute(null)).toBeResolvedTo('failed'); + let event; + env.addReporter({ + jasmineDone: e => (event = e) + }); + const result = await env.execute(); + + expect(event.overallStatus).toEqual('failed'); + expect(result).toEqual(event); }); }); diff --git a/src/core/Env.js b/src/core/Env.js index 7de139b3..040f2ff5 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -749,12 +749,12 @@ getJasmineRequireObj().Env = function(j$) { jasmineTimer.start(); return new Promise(function(resolve) { - runAll(function(overallStatus) { + runAll(function(jasmineDoneInfo) { if (onComplete) { onComplete(); } - resolve(overallStatus); + resolve(jasmineDoneInfo); }); }); @@ -805,19 +805,17 @@ getJasmineRequireObj().Env = function(j$) { * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. * @since 2.4.0 */ - reporter.jasmineDone( - { - overallStatus: overallStatus, - totalTime: jasmineTimer.elapsed(), - incompleteReason: incompleteReason, - order: order, - failedExpectations: topSuite.result.failedExpectations, - deprecationWarnings: topSuite.result.deprecationWarnings - }, - function() { - done(overallStatus); - } - ); + const jasmineDoneInfo = { + overallStatus: overallStatus, + totalTime: jasmineTimer.elapsed(), + incompleteReason: incompleteReason, + order: order, + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings + }; + reporter.jasmineDone(jasmineDoneInfo, function() { + done(jasmineDoneInfo); + }); }); } ); From 0b1385c3d3e908a85adee3c0ffba88b953727ea4 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Dec 2021 12:34:23 -0800 Subject: [PATCH 57/71] Report start and end events for specs/suites that are skipped due to a beforeAll error This is noisier, but it maintains compatibility with reporters that assume (quite reasonably) that all specs and suites are either filtered out or reported. --- lib/jasmine-core/jasmine.js | 136 +++++++++----- .../core/SkipAfterBeforeAllErrorPolicySpec.js | 37 +++- spec/core/SuiteSpec.js | 15 +- spec/core/integration/SpecRunningSpec.js | 168 +++++++++++++++++- src/core/Env.js | 128 ++++++++----- src/core/SkipAfterBeforeAllErrorPolicy.js | 6 + src/core/Suite.js | 2 +- 7 files changed, 397 insertions(+), 95 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 9c5a8f47..154f89ef 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1880,7 +1880,14 @@ getJasmineRequireObj().Env = function(j$) { hasFailures = true; } suite.endTimer(); - reporter.suiteDone(result, next); + + if (suite.hadBeforeAllFailure) { + reportChildrenOfBeforeAllFailure(suite).then(function() { + reporter.suiteDone(result, next); + }); + } else { + reporter.suiteDone(result, next); + } }, orderChildren: function(node) { return order.sort(node.children); @@ -1926,51 +1933,92 @@ getJasmineRequireObj().Env = function(j$) { currentlyExecutingSuites.push(topSuite); processor.execute(function() { - clearResourcesForRunnable(topSuite.id); - currentlyExecutingSuites.pop(); - var overallStatus, incompleteReason; + (async function() { + if (topSuite.hadBeforeAllFailure) { + await reportChildrenOfBeforeAllFailure(topSuite); + } - if ( - hasFailures || - topSuite.result.failedExpectations.length > 0 - ) { - overallStatus = 'failed'; - } else if (focusedRunnables.length > 0) { - overallStatus = 'incomplete'; - incompleteReason = 'fit() or fdescribe() was found'; - } else if (totalSpecsDefined === 0) { - overallStatus = 'incomplete'; - incompleteReason = 'No specs found'; - } else { - overallStatus = 'passed'; - } + clearResourcesForRunnable(topSuite.id); + currentlyExecutingSuites.pop(); + var overallStatus, incompleteReason; - /** - * Information passed to the {@link Reporter#jasmineDone} event. - * @typedef JasmineDoneInfo - * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. - * @property {Int} totalTime - The total time (in ms) that it took to execute the suite - * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. - * @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 - */ - const jasmineDoneInfo = { - overallStatus: overallStatus, - totalTime: jasmineTimer.elapsed(), - incompleteReason: incompleteReason, - order: order, - failedExpectations: topSuite.result.failedExpectations, - deprecationWarnings: topSuite.result.deprecationWarnings - }; - reporter.jasmineDone(jasmineDoneInfo, function() { - done(jasmineDoneInfo); - }); + if ( + hasFailures || + topSuite.result.failedExpectations.length > 0 + ) { + overallStatus = 'failed'; + } else if (focusedRunnables.length > 0) { + overallStatus = 'incomplete'; + incompleteReason = 'fit() or fdescribe() was found'; + } else if (totalSpecsDefined === 0) { + overallStatus = 'incomplete'; + incompleteReason = 'No specs found'; + } else { + overallStatus = 'passed'; + } + + /** + * Information passed to the {@link Reporter#jasmineDone} event. + * @typedef JasmineDoneInfo + * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. + * @property {Int} totalTime - The total time (in ms) that it took to execute the suite + * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. + * @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 + */ + const jasmineDoneInfo = { + overallStatus: overallStatus, + totalTime: jasmineTimer.elapsed(), + incompleteReason: incompleteReason, + order: order, + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings + }; + reporter.jasmineDone(jasmineDoneInfo, function() { + done(jasmineDoneInfo); + }); + })(); }); } ); } + + async function reportChildrenOfBeforeAllFailure(suite) { + for (const child of suite.children) { + if (child instanceof j$.Suite) { + await new Promise(function(resolve) { + reporter.suiteStarted(child.result, resolve); + }); + await reportChildrenOfBeforeAllFailure(child); + markNotRun(child); + await new Promise(function(resolve) { + reporter.suiteDone(child.result, resolve); + }); + } /* a spec */ else { + await new Promise(function(resolve) { + reporter.specStarted(child.result, resolve); + }); + await new Promise(function(resolve) { + markNotRun(child); + reporter.specDone(child.result, resolve); + }); + } + } + + function markNotRun(runnable) { + runnable.addExpectationResult( + false, + { + passed: false, + message: 'Not run because a beforeAll function failed' + }, + true + ); + runnable.result.status = 'failed'; + } + } }; /** @@ -8636,6 +8684,12 @@ getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { if (this.queueableFns_[fnIx].type === 'beforeAll') { this.skipping_ = true; + // Failures need to be reported for each contained spec. But we can't do + // that from here because reporting is async. This function isn't async + // (and can't be without greatly complicating QueueRunner). Mark the + // failure so that the code that reports the suite result (which is + // already async) can detect the failure and report the specs. + this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true; } }; @@ -9604,7 +9658,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push({ ...fn, type: 'beforeAll' }); + this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); }; Suite.prototype.afterEach = function(fn) { diff --git a/spec/core/SkipAfterBeforeAllErrorPolicySpec.js b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js index 13a1e9ba..455f4381 100644 --- a/spec/core/SkipAfterBeforeAllErrorPolicySpec.js +++ b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js @@ -3,8 +3,7 @@ describe('SkipAfterBeforeAllErrorPolicy', function() { describe('When nothing has errored', function() { it('does not skip anything', function() { const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( - arrayOfArbitraryFns(4), - 2 + arrayOfArbitraryFns(4) ); expect(policy.skipTo(0)).toEqual(1); @@ -17,8 +16,7 @@ describe('SkipAfterBeforeAllErrorPolicy', function() { describe('When anything but a beforeAll has errored', function() { it('does not skip anything', function() { const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( - arrayOfArbitraryFns(4), - 2 + arrayOfArbitraryFns(4) ); policy.fnErrored(0); @@ -34,17 +32,15 @@ describe('SkipAfterBeforeAllErrorPolicy', function() { describe('When a beforeAll has errored', function() { it('skips subsequent functions other than afterAll', function() { + const suite = {}; const fns = [ - { type: 'beforeAll', fn: () => {} }, + { type: 'beforeAll', fn: () => {}, suite }, { fn: () => {} }, { fn: () => {} }, { type: 'afterAll', fn: () => {} }, { type: 'afterAll', fn: () => {} } ]; - const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( - fns, - 2 - ); + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(3); @@ -52,6 +48,29 @@ describe('SkipAfterBeforeAllErrorPolicy', function() { }); }); }); + + describe('#fnErrored', function() { + describe('When the fn is a beforeAll', function() { + it("sets the suite's hadBeforeAllFailure property to true", function() { + const suite = {}; + const fns = [{ type: 'beforeAll', fn: () => {}, suite }]; + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); + + policy.fnErrored(0); + + expect(suite.hadBeforeAllFailure).toBeTrue(); + }); + }); + + describe('When the fn is not a beforeAll', function() { + it('does not try to access the suite, which is probably not there', function() { + const fns = [{ fn: () => {} /* no suite */ }]; + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy(fns); + + expect(() => policy.fnErrored(0)).not.toThrow(); + }); + }); + }); }); function arrayOfArbitraryFns(n) { diff --git a/spec/core/SuiteSpec.js b/spec/core/SuiteSpec.js index 84fce87e..37317161 100644 --- a/spec/core/SuiteSpec.js +++ b/spec/core/SuiteSpec.js @@ -71,9 +71,20 @@ describe('Suite', function() { suite.beforeAll(outerBefore); suite.beforeAll(innerBefore); + function sameInstance(expected) { + return { + asymmetricMatch: function(actual) { + return actual === expected; + }, + jasmineToString: function() { + return ``; + } + }; + } + expect(suite.beforeAllFns).toEqual([ - { fn: outerBefore.fn, type: 'beforeAll' }, - { fn: innerBefore.fn, type: 'beforeAll' } + { fn: outerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) }, + { fn: innerBefore.fn, type: 'beforeAll', suite: sameInstance(suite) } ]); }); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index a7457d3b..4606e479 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1065,8 +1065,8 @@ describe('spec running', function() { }); }); - describe('When a beforeAll function fails', function() { - it('skips contained specs and suites', async function() { + describe('When a top-level beforeAll function fails', function() { + it('skips and reports contained specs', async function() { const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); const outerAfterEach = jasmine.createSpy('outerAfterEach'); @@ -1089,6 +1089,14 @@ describe('spec running', function() { }); env.afterEach(outerAfterEach); + const reporter = jasmine.createSpyObj('reporter', [ + 'suiteStarted', + 'suiteDone', + 'specStarted', + 'specDone' + ]); + env.addReporter(reporter); + await env.execute(); expect(outerBeforeEach).not.toHaveBeenCalled(); @@ -1098,6 +1106,162 @@ describe('spec running', function() { expect(nestedIt).not.toHaveBeenCalled(); expect(nestedAfterEach).not.toHaveBeenCalled(); expect(outerAfterEach).not.toHaveBeenCalled(); + + expect(reporter.suiteStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a nested suite' + }) + ); + + expect(reporter.suiteDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a nested suite', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); + + expect(reporter.specStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a spec' + }) + ); + expect(reporter.specDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a spec', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); + + expect(reporter.specStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a nested suite a nested spec' + }) + ); + expect(reporter.specDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a nested suite a nested spec', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); + }); + }); + + describe('When a suite beforeAll function fails', function() { + it('skips and reports contained specs', async function() { + const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); + const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); + const outerAfterEach = jasmine.createSpy('outerAfterEach'); + const nestedAfterEach = jasmine.createSpy('nestedAfterEach'); + const outerIt = jasmine.createSpy('outerIt'); + const nestedIt = jasmine.createSpy('nestedIt'); + const nestedBeforeAll = jasmine.createSpy('nestedBeforeAll'); + + env.describe('a suite', function() { + env.beforeAll(function() { + throw new Error('nope'); + }); + + env.beforeEach(outerBeforeEach); + env.it('a spec', outerIt); + env.describe('a nested suite', function() { + env.beforeAll(nestedBeforeAll); + env.beforeEach(nestedBeforeEach); + env.it('a nested spec', nestedIt); + env.afterEach(nestedAfterEach); + }); + env.afterEach(outerAfterEach); + }); + + const reporter = jasmine.createSpyObj('reporter', [ + 'suiteStarted', + 'suiteDone', + 'specStarted', + 'specDone' + ]); + env.addReporter(reporter); + + await env.execute(); + + expect(outerBeforeEach).not.toHaveBeenCalled(); + expect(outerIt).not.toHaveBeenCalled(); + expect(nestedBeforeAll).not.toHaveBeenCalled(); + expect(nestedBeforeEach).not.toHaveBeenCalled(); + expect(nestedIt).not.toHaveBeenCalled(); + expect(nestedAfterEach).not.toHaveBeenCalled(); + expect(outerAfterEach).not.toHaveBeenCalled(); + + expect(reporter.suiteStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a nested suite' + }) + ); + + expect(reporter.suiteDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a nested suite', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); + + expect(reporter.specStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a spec' + }) + ); + expect(reporter.specDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a spec', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); + + expect(reporter.specStarted).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a nested suite a nested spec' + }) + ); + expect(reporter.specDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'a suite a nested suite a nested spec', + status: 'failed', + failedExpectations: [ + jasmine.objectContaining({ + passed: false, + message: 'Not run because a beforeAll function failed' + }) + ] + }) + ); }); it('runs afterAll functions in the current suite and outer scopes', async function() { diff --git a/src/core/Env.js b/src/core/Env.js index 040f2ff5..3a41bc6f 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -729,7 +729,14 @@ getJasmineRequireObj().Env = function(j$) { hasFailures = true; } suite.endTimer(); - reporter.suiteDone(result, next); + + if (suite.hadBeforeAllFailure) { + reportChildrenOfBeforeAllFailure(suite).then(function() { + reporter.suiteDone(result, next); + }); + } else { + reporter.suiteDone(result, next); + } }, orderChildren: function(node) { return order.sort(node.children); @@ -775,51 +782,92 @@ getJasmineRequireObj().Env = function(j$) { currentlyExecutingSuites.push(topSuite); processor.execute(function() { - clearResourcesForRunnable(topSuite.id); - currentlyExecutingSuites.pop(); - var overallStatus, incompleteReason; + (async function() { + if (topSuite.hadBeforeAllFailure) { + await reportChildrenOfBeforeAllFailure(topSuite); + } - if ( - hasFailures || - topSuite.result.failedExpectations.length > 0 - ) { - overallStatus = 'failed'; - } else if (focusedRunnables.length > 0) { - overallStatus = 'incomplete'; - incompleteReason = 'fit() or fdescribe() was found'; - } else if (totalSpecsDefined === 0) { - overallStatus = 'incomplete'; - incompleteReason = 'No specs found'; - } else { - overallStatus = 'passed'; - } + clearResourcesForRunnable(topSuite.id); + currentlyExecutingSuites.pop(); + var overallStatus, incompleteReason; - /** - * Information passed to the {@link Reporter#jasmineDone} event. - * @typedef JasmineDoneInfo - * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. - * @property {Int} totalTime - The total time (in ms) that it took to execute the suite - * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. - * @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 - */ - const jasmineDoneInfo = { - overallStatus: overallStatus, - totalTime: jasmineTimer.elapsed(), - incompleteReason: incompleteReason, - order: order, - failedExpectations: topSuite.result.failedExpectations, - deprecationWarnings: topSuite.result.deprecationWarnings - }; - reporter.jasmineDone(jasmineDoneInfo, function() { - done(jasmineDoneInfo); - }); + if ( + hasFailures || + topSuite.result.failedExpectations.length > 0 + ) { + overallStatus = 'failed'; + } else if (focusedRunnables.length > 0) { + overallStatus = 'incomplete'; + incompleteReason = 'fit() or fdescribe() was found'; + } else if (totalSpecsDefined === 0) { + overallStatus = 'incomplete'; + incompleteReason = 'No specs found'; + } else { + overallStatus = 'passed'; + } + + /** + * Information passed to the {@link Reporter#jasmineDone} event. + * @typedef JasmineDoneInfo + * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'. + * @property {Int} totalTime - The total time (in ms) that it took to execute the suite + * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete. + * @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 + */ + const jasmineDoneInfo = { + overallStatus: overallStatus, + totalTime: jasmineTimer.elapsed(), + incompleteReason: incompleteReason, + order: order, + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings + }; + reporter.jasmineDone(jasmineDoneInfo, function() { + done(jasmineDoneInfo); + }); + })(); }); } ); } + + async function reportChildrenOfBeforeAllFailure(suite) { + for (const child of suite.children) { + if (child instanceof j$.Suite) { + await new Promise(function(resolve) { + reporter.suiteStarted(child.result, resolve); + }); + await reportChildrenOfBeforeAllFailure(child); + markNotRun(child); + await new Promise(function(resolve) { + reporter.suiteDone(child.result, resolve); + }); + } /* a spec */ else { + await new Promise(function(resolve) { + reporter.specStarted(child.result, resolve); + }); + await new Promise(function(resolve) { + markNotRun(child); + reporter.specDone(child.result, resolve); + }); + } + } + + function markNotRun(runnable) { + runnable.addExpectationResult( + false, + { + passed: false, + message: 'Not run because a beforeAll function failed' + }, + true + ); + runnable.result.status = 'failed'; + } + } }; /** diff --git a/src/core/SkipAfterBeforeAllErrorPolicy.js b/src/core/SkipAfterBeforeAllErrorPolicy.js index ce49a830..57d88127 100644 --- a/src/core/SkipAfterBeforeAllErrorPolicy.js +++ b/src/core/SkipAfterBeforeAllErrorPolicy.js @@ -25,6 +25,12 @@ getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { if (this.queueableFns_[fnIx].type === 'beforeAll') { this.skipping_ = true; + // Failures need to be reported for each contained spec. But we can't do + // that from here because reporting is async. This function isn't async + // (and can't be without greatly complicating QueueRunner). Mark the + // failure so that the code that reports the suite result (which is + // already async) can detect the failure and report the specs. + this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true; } }; diff --git a/src/core/Suite.js b/src/core/Suite.js index 2cb2e7ca..43e3ce22 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -103,7 +103,7 @@ getJasmineRequireObj().Suite = function(j$) { }; Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push({ ...fn, type: 'beforeAll' }); + this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); }; Suite.prototype.afterEach = function(fn) { From 067b91b3efcebab4180cdf1ba23b126a986dea02 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Dec 2021 13:58:11 -0800 Subject: [PATCH 58/71] Removed IE/PhantomJS support code --- lib/jasmine-core/jasmine.js | 18 ++++-------------- src/core/util.js | 18 ++++-------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 154f89ef..1feb18e8 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -676,20 +676,10 @@ getJasmineRequireObj().util = function(j$) { }; util.errorWithStack = function errorWithStack() { - // Don't throw and catch if we don't have to, because it makes it harder - // for users to debug their code with exception breakpoints. - var error = new Error(); - - if (error.stack) { - return error; - } - - // But some browsers (e.g. Phantom) only provide a stack trace if we throw. - try { - throw new Error(); - } catch (e) { - return e; - } + // Don't throw and catch. That makes it harder for users to debug their + // code with exception breakpoints, and it's unnecessary since all + // supported environments populate new Error().stack + return new Error(); }; function callerFile() { diff --git a/src/core/util.js b/src/core/util.js index cd4631f6..b65a1113 100644 --- a/src/core/util.js +++ b/src/core/util.js @@ -90,20 +90,10 @@ getJasmineRequireObj().util = function(j$) { }; util.errorWithStack = function errorWithStack() { - // Don't throw and catch if we don't have to, because it makes it harder - // for users to debug their code with exception breakpoints. - var error = new Error(); - - if (error.stack) { - return error; - } - - // But some browsers (e.g. Phantom) only provide a stack trace if we throw. - try { - throw new Error(); - } catch (e) { - return e; - } + // Don't throw and catch. That makes it harder for users to debug their + // code with exception breakpoints, and it's unnecessary since all + // supported environments populate new Error().stack + return new Error(); }; function callerFile() { From 30b93ccdbbd40c181e5af5fafddd46e8ddbf9b02 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Dec 2021 15:53:25 -0800 Subject: [PATCH 59/71] Updated jsdocs for Env#execute --- lib/jasmine-core/jasmine.js | 16 +++++++++------- src/core/Env.js | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 1feb18e8..f489f130 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1808,23 +1808,25 @@ getJasmineRequireObj().Env = function(j$) { * * Both parameters are optional, but a completion callback is only valid as * the second parameter. To specify a completion callback but not a list of - * specs/suites to run, pass null or undefined as the first parameter. + * specs/suites to run, pass null or undefined as the first parameter. The + * completion callback is supported for backward compatibility. In most + * cases it will be more convenient to use the returned promise instead. * * execute should not be called more than once unless the env has been * configured with `{autoCleanClosures: false}`. * - * If the environment supports promises, execute will return a promise that - * is resolved after the suite finishes executing. The promise will be - * resolved (not rejected) to the suite's overall status as long as the - * suite runs to completion. To determine whether the suite passed, check - * the value that the promise resolves to or use a {@link Reporter}. + * execute returns a promise. The promise will be resolved to the same + * {@link JasmineDoneInfo|overall result} that's passed to the reporter's + * `jasmineDone` method, even if the suite did not pass. To determine + * whether the suite passed, check the value that the promise resolves to + * or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run - * @return {Promise} + * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { diff --git a/src/core/Env.js b/src/core/Env.js index 3a41bc6f..23ef6b9d 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -667,23 +667,25 @@ getJasmineRequireObj().Env = function(j$) { * * Both parameters are optional, but a completion callback is only valid as * the second parameter. To specify a completion callback but not a list of - * specs/suites to run, pass null or undefined as the first parameter. + * specs/suites to run, pass null or undefined as the first parameter. The + * completion callback is supported for backward compatibility. In most + * cases it will be more convenient to use the returned promise instead. * * execute should not be called more than once unless the env has been * configured with `{autoCleanClosures: false}`. * - * If the environment supports promises, execute will return a promise that - * is resolved after the suite finishes executing. The promise will be - * resolved (not rejected) to the suite's overall status as long as the - * suite runs to completion. To determine whether the suite passed, check - * the value that the promise resolves to or use a {@link Reporter}. + * execute returns a promise. The promise will be resolved to the same + * {@link JasmineDoneInfo|overall result} that's passed to a reporter's + * `jasmineDone` method, even if the suite did not pass. To determine + * whether the suite passed, check the value that the promise resolves to + * or use a {@link Reporter}. * * @name Env#execute * @since 2.0.0 * @function * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run * @param {Function=} onComplete Function that will be called after all specs have run - * @return {Promise} + * @return {Promise} */ this.execute = function(runnablesToRun, onComplete) { if (this._executedBefore) { From 0411b0567d2166cf216dc9796a6e40851a0a3952 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 11 Dec 2021 16:13:51 -0800 Subject: [PATCH 60/71] Added a mention of 4.0 migration to the README --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a33982bb..f2d93f41 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Jasmine is a Behavior Driven Development testing framework for JavaScript. It do Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/) For a quick start guide of Jasmine, see the beginning of [http://jasmine.github.io/edge/introduction.html](http://jasmine.github.io/edge/introduction.html). +Upgrading from Jasmine 3.x? Check out the 4.0 release notes for a list of +what's new (including breaking changes). You can also read the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0). + ## Contributing Please read the [contributors' guide](https://github.com/jasmine/jasmine/blob/main/.github/CONTRIBUTING.md). @@ -44,7 +47,8 @@ Add the following to your HTML file: ## Supported environments -Jasmine tests itself across many browsers (Safari, Chrome, Firefox, Microsoft Edge, and Internet Explorer) as well as nodejs. +Jasmine tests itself across popular browsers (Safari, Chrome, Firefox, and +Microsoft Edge) as well as nodejs. | Environment | Supported versions | |-------------------|--------------------| From e73eb18753c771c34cb74b8d2b37cc987b4b2f7e Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 13 Dec 2021 21:41:09 -0800 Subject: [PATCH 61/71] Test against jasmine-browser-runner 1.0.0-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f8d3815..cd4b29c0 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "grunt-css-url-embed": "^1.11.1", "grunt-sass": "^3.0.2", "jasmine": "github:jasmine/jasmine-npm#4.0", - "jasmine-browser-runner": "github:jasmine/jasmine-browser#main", + "jasmine-browser-runner": "github:jasmine/jasmine-browser#1.0", "jsdom": "^15.0.0", "load-grunt-tasks": "^4.0.0", "prettier": "1.17.1", From 24408a16edbf01801d0459b1eca4f91e72279d55 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 15 Dec 2021 20:34:00 -0800 Subject: [PATCH 62/71] Removed initialization of unused Promise config property --- src/core/Env.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/core/Env.js b/src/core/Env.js index 23ef6b9d..14610429 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -110,18 +110,6 @@ getJasmineRequireObj().Env = function(j$) { * @default false */ hideDisabled: false, - /** - * Set to provide a custom promise library that Jasmine will use if it needs - * to create a promise. If not set, it will default to whatever global Promise - * library is available (if any). - * @name Configuration#Promise - * @since 3.5.0 - * @type function - * @default undefined - * @deprecated In a future version, Jasmine will ignore the Promise config - * property and always create native promises instead. - */ - Promise: undefined, /** * Clean closures when a suite is done running (done by clearing the stored function reference). * This prevents memory leaks, but you won't be able to run jasmine multiple times. From 656e6614da6016425551a4e2825056b6ccc12896 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Wed, 15 Dec 2021 20:36:44 -0800 Subject: [PATCH 63/71] Built distribution --- lib/jasmine-core/jasmine.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 7ee22b5e..ebd18505 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1251,18 +1251,6 @@ getJasmineRequireObj().Env = function(j$) { * @default false */ hideDisabled: false, - /** - * Set to provide a custom promise library that Jasmine will use if it needs - * to create a promise. If not set, it will default to whatever global Promise - * library is available (if any). - * @name Configuration#Promise - * @since 3.5.0 - * @type function - * @default undefined - * @deprecated In a future version, Jasmine will ignore the Promise config - * property and always create native promises instead. - */ - Promise: undefined, /** * Clean closures when a suite is done running (done by clearing the stored function reference). * This prevents memory leaks, but you won't be able to run jasmine multiple times. From c431590d659e36e18416de0bdfea8d22c9b94cf5 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 20 Dec 2021 13:39:24 -0800 Subject: [PATCH 64/71] Fixed reporting of suites that are skipped due to a beforeAll failure --- lib/jasmine-core/jasmine.js | 36 +++++++++++--------- spec/core/integration/SpecRunningSpec.js | 42 ++++++++++++++---------- src/core/Env.js | 36 +++++++++++--------- 3 files changed, 66 insertions(+), 48 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index ebd18505..f0f9deeb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1972,32 +1972,38 @@ getJasmineRequireObj().Env = function(j$) { reporter.suiteStarted(child.result, resolve); }); await reportChildrenOfBeforeAllFailure(child); - markNotRun(child); + + // Marking the suite passed is consistent with how suites that + // contain failed specs but no suite-level failures are reported. + child.result.status = 'passed'; + await new Promise(function(resolve) { reporter.suiteDone(child.result, resolve); }); - } /* a spec */ else { + } else { + /* a spec */ await new Promise(function(resolve) { reporter.specStarted(child.result, resolve); }); + + child.addExpectationResult( + false, + { + passed: false, + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' + }, + true + ); + child.result.status = 'failed'; + await new Promise(function(resolve) { - markNotRun(child); reporter.specDone(child.result, resolve); }); } } - - function markNotRun(runnable) { - runnable.addExpectationResult( - false, - { - passed: false, - message: 'Not run because a beforeAll function failed' - }, - true - ); - runnable.result.status = 'failed'; - } } }; diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 4606e479..2ce28901 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1113,16 +1113,13 @@ describe('spec running', function() { }) ); + // The child suite should be reported as passed, for consistency with + // suites that contain failing specs but no suite-level errors. expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a nested suite', - status: 'failed', - failedExpectations: [ - jasmine.objectContaining({ - passed: false, - message: 'Not run because a beforeAll function failed' - }) - ] + status: 'passed', + failedExpectations: [] }) ); @@ -1138,7 +1135,10 @@ describe('spec running', function() { failedExpectations: [ jasmine.objectContaining({ passed: false, - message: 'Not run because a beforeAll function failed' + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' }) ] }) @@ -1156,7 +1156,10 @@ describe('spec running', function() { failedExpectations: [ jasmine.objectContaining({ passed: false, - message: 'Not run because a beforeAll function failed' + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' }) ] }) @@ -1214,16 +1217,13 @@ describe('spec running', function() { }) ); + // The child suite should be reported as passed, for consistency with + // suites that contain failing specs but no suite-level errors. expect(reporter.suiteDone).toHaveBeenCalledWith( jasmine.objectContaining({ fullName: 'a suite a nested suite', - status: 'failed', - failedExpectations: [ - jasmine.objectContaining({ - passed: false, - message: 'Not run because a beforeAll function failed' - }) - ] + status: 'passed', + failedExpectations: [] }) ); @@ -1239,7 +1239,10 @@ describe('spec running', function() { failedExpectations: [ jasmine.objectContaining({ passed: false, - message: 'Not run because a beforeAll function failed' + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' }) ] }) @@ -1257,7 +1260,10 @@ describe('spec running', function() { failedExpectations: [ jasmine.objectContaining({ passed: false, - message: 'Not run because a beforeAll function failed' + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' }) ] }) diff --git a/src/core/Env.js b/src/core/Env.js index 14610429..677dacce 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -831,32 +831,38 @@ getJasmineRequireObj().Env = function(j$) { reporter.suiteStarted(child.result, resolve); }); await reportChildrenOfBeforeAllFailure(child); - markNotRun(child); + + // Marking the suite passed is consistent with how suites that + // contain failed specs but no suite-level failures are reported. + child.result.status = 'passed'; + await new Promise(function(resolve) { reporter.suiteDone(child.result, resolve); }); - } /* a spec */ else { + } else { + /* a spec */ await new Promise(function(resolve) { reporter.specStarted(child.result, resolve); }); + + child.addExpectationResult( + false, + { + passed: false, + message: + 'Not run because a beforeAll function failed. The ' + + 'beforeAll failure will be reported on the suite that ' + + 'caused it.' + }, + true + ); + child.result.status = 'failed'; + await new Promise(function(resolve) { - markNotRun(child); reporter.specDone(child.result, resolve); }); } } - - function markNotRun(runnable) { - runnable.addExpectationResult( - false, - { - passed: false, - message: 'Not run because a beforeAll function failed' - }, - true - ); - runnable.result.status = 'failed'; - } } }; From 5fd0e49ccf7da191cefe81b7647d5162d89700fe Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 21 Dec 2021 17:00:04 -0800 Subject: [PATCH 65/71] Removed unused ejs dev dependency --- package.json | 1 - spec/support/index.html.ejs | 12 ------------ 2 files changed, 13 deletions(-) delete mode 100644 spec/support/index.html.ejs diff --git a/package.json b/package.json index cd4b29c0..db92a42e 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "package.json" ], "devDependencies": { - "ejs": "^2.5.5", "eslint": "^6.8.0", "eslint-plugin-compat": "^3.8.0", "fast-glob": "^2.2.6", diff --git a/spec/support/index.html.ejs b/spec/support/index.html.ejs deleted file mode 100644 index 972f09be..00000000 --- a/spec/support/index.html.ejs +++ /dev/null @@ -1,12 +0,0 @@ - - - - Jasmine suite - - - <% files.forEach(function(file) { %> - - <% }) %> - - - From cef738966cec441e55cf328e9892b5709aa6d2b8 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 21 Dec 2021 17:03:29 -0800 Subject: [PATCH 66/71] Updated dev dependencies --- package.json | 16 ++++++++-------- spec/helpers/nodeDefineJasmineUnderTest.js | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index db92a42e..1bd0fdc8 100644 --- a/package.json +++ b/package.json @@ -34,21 +34,21 @@ "package.json" ], "devDependencies": { - "eslint": "^6.8.0", - "eslint-plugin-compat": "^3.8.0", - "fast-glob": "^2.2.6", + "eslint": "^7.32.0", + "eslint-plugin-compat": "^4.0.0", + "glob": "^7.2.0", "grunt": "^1.0.4", "grunt-cli": "^1.3.2", - "grunt-contrib-compress": "^1.3.0", - "grunt-contrib-concat": "^1.0.1", + "grunt-contrib-compress": "^2.0.0", + "grunt-contrib-concat": "^2.0.0", "grunt-css-url-embed": "^1.11.1", "grunt-sass": "^3.0.2", "jasmine": "github:jasmine/jasmine-npm#4.0", "jasmine-browser-runner": "github:jasmine/jasmine-browser#1.0", - "jsdom": "^15.0.0", - "load-grunt-tasks": "^4.0.0", + "jsdom": "^19.0.0", + "load-grunt-tasks": "^5.1.0", "prettier": "1.17.1", - "sass": "^1.32.12", + "sass": "^1.45.1", "shelljs": "^0.8.3", "temp": "^0.9.0" }, diff --git a/spec/helpers/nodeDefineJasmineUnderTest.js b/spec/helpers/nodeDefineJasmineUnderTest.js index 739c20af..c91bdc5f 100644 --- a/spec/helpers/nodeDefineJasmineUnderTest.js +++ b/spec/helpers/nodeDefineJasmineUnderTest.js @@ -1,6 +1,6 @@ (function() { var path = require('path'), - fg = require('fast-glob'); + glob = require('glob'); var jasmineUnderTestRequire = require(path.join( __dirname, @@ -16,7 +16,8 @@ return path.join(__dirname, '../../', 'src/', file); }); - fg.sync(src_files).forEach(function(resolvedFile) { + const files = src_files.flatMap(g => glob.sync(g)); + files.forEach(function(resolvedFile) { require(resolvedFile); }); } From c56631175fd5e91c13a8aced2162685b7e919d36 Mon Sep 17 00:00:00 2001 From: James Bromwell <943160+thw0rted@users.noreply.github.com> Date: Wed, 29 Dec 2021 17:50:48 +0100 Subject: [PATCH 67/71] Fix time-travel in delayed function scheduler --- lib/jasmine-core/jasmine.js | 16 ++++--- spec/core/DelayedFunctionSchedulerSpec.js | 54 +++++++++++++++++++++++ src/core/DelayedFunctionScheduler.js | 16 ++++--- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index f0f9deeb..8c01be21 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3565,7 +3565,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); - currentTime = endTime; }; self.scheduleFunction = function( @@ -3683,16 +3682,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { - tickDate(endTime - currentTime); + if (endTime >= currentTime) { + tickDate(endTime - currentTime); + currentTime = endTime; + } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); - tickDate(newCurrentTime - currentTime); - - currentTime = newCurrentTime; + if (newCurrentTime >= currentTime) { + tickDate(newCurrentTime - currentTime); + currentTime = newCurrentTime; + } var funcsToRun = scheduledFunctions[currentTime]; @@ -3721,8 +3724,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { ); // ran out of functions to call, but still time left on the clock - if (currentTime !== endTime) { + if (endTime >= currentTime) { tickDate(endTime - currentTime); + currentTime = endTime; } } } diff --git a/spec/core/DelayedFunctionSchedulerSpec.js b/spec/core/DelayedFunctionSchedulerSpec.js index d06a66c1..f5879e13 100644 --- a/spec/core/DelayedFunctionSchedulerSpec.js +++ b/spec/core/DelayedFunctionSchedulerSpec.js @@ -278,4 +278,58 @@ describe('DelayedFunctionScheduler', function() { expect(tickDate).toHaveBeenCalledWith(0); expect(tickDate).toHaveBeenCalledWith(1); }); + + describe('ticking inside a scheduled function', function() { + let clock; + + // Runner function calls the callback until it returns false + function runWork(workCallback) { + while (workCallback()) {} + } + + // Make a worker that takes a little time and tracks when it finished + function mockWork(times) { + return () => { + clock.tick(1); + const now = new Date().getTime(); + expect(lastWork) + .withContext('Previous function calls should always be in the past') + .toBeLessThan(now); + lastWork = now; + times--; + return times > 0; + }; + } + let lastWork = 0; + + beforeEach(() => { + clock = jasmine.clock(); + clock.install(); + clock.mockDate(new Date(1)); + }); + + afterEach(function() { + jasmine.clock().uninstall(); + }); + + it('preserves monotonically-increasing current time', () => { + const work1 = mockWork(3); + setTimeout(() => { + runWork(work1); + }, 1); + clock.tick(1); + expect(lastWork) + .withContext('tick should advance past last-scheduled function') + .toBeLessThanOrEqual(new Date().getTime()); + + const work2 = mockWork(3); + setTimeout(() => { + runWork(work2); + }, 1); + clock.tick(1); + expect(lastWork) + .withContext('tick should advance past last-scheduled function') + .toBeLessThanOrEqual(new Date().getTime()); + }); + }); }); diff --git a/src/core/DelayedFunctionScheduler.js b/src/core/DelayedFunctionScheduler.js index eb84c48a..aabdd911 100644 --- a/src/core/DelayedFunctionScheduler.js +++ b/src/core/DelayedFunctionScheduler.js @@ -12,7 +12,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); - currentTime = endTime; }; self.scheduleFunction = function( @@ -130,16 +129,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { - tickDate(endTime - currentTime); + if (endTime >= currentTime) { + tickDate(endTime - currentTime); + currentTime = endTime; + } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); - tickDate(newCurrentTime - currentTime); - - currentTime = newCurrentTime; + if (newCurrentTime >= currentTime) { + tickDate(newCurrentTime - currentTime); + currentTime = newCurrentTime; + } var funcsToRun = scheduledFunctions[currentTime]; @@ -168,8 +171,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { ); // ran out of functions to call, but still time left on the clock - if (currentTime !== endTime) { + if (endTime >= currentTime) { tickDate(endTime - currentTime); + currentTime = endTime; } } } From 5d0be2e6cfbf913d2293e024153044aa3282e207 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 31 Dec 2021 09:43:46 -0800 Subject: [PATCH 68/71] Updated the contributing guide for 4.0 * Moved "Before Submitting a Pull Request" to the top * Removed discussion of the standard Github PR workflow (Contributors who don't know how to create PRs on Github at all can find that information elsewhere. For the rest, it's just noise.) * Misc copy edits --- .github/CONTRIBUTING.md | 62 +++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 573b8866..3fed0f43 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -12,24 +12,23 @@ should have enough detail to get started. - [Jasmine Google Group](http://groups.google.com/group/jasmine-js) - [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev) -- [Jasmine on PivotalTracker](https://www.pivotaltracker.com/n/projects/10606) +- [Jasmine backlog](https://www.pivotaltracker.com/n/projects/10606) -## General Workflow +## Before Submitting a Pull Request -Please submit pull requests via feature branches using the semi-standard workflow of: +1. Ensure all specs are green in browsers *and* node. + * Use `npm test` to test in Node. + * Use `npm run serve` to test in browsers. +2. Fix any eslint or prettier errors reported at the end of `npm test`. Prettier + errors can be automatically fixed by running `npm run cleanup`. +3. Build `jasmine.js` with `npm run build` and run all specs again. This + ensures that your changes self-test well. +5. Revert your changes to `jasmine.js` and `jasmine-html.js`. When we accept + your pull request, we will generate these files as a separate commit and + merge the entire branch into master. -```bash -git clone git@github.com:yourUserName/jasmine.git # Clone your fork -cd jasmine # Change directory -git remote add upstream https://github.com/jasmine/jasmine.git # Assign original repository to a remote named 'upstream' -git fetch upstream # Fetch changes not present in your local repository -git merge upstream/main # Sync local main with upstream repository -git checkout -b my-new-feature # Create your feature branch -git commit -am 'Add some feature' # Commit your changes -git push origin my-new-feature # Push to the branch -``` - -Once you've pushed a feature branch to your forked repo, you're ready to open a pull request. We favor pull requests with very small, single commits with a single purpose. +We only accept green pull requests. If you see that the CI build failed, please +fix it. Feel free to ask for help if you're stuck. ## Background @@ -47,7 +46,7 @@ Once you've pushed a feature branch to your forked repo, you're ready to open a ### Self-testing -Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test. +Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test. The tests should always use `jasmineUnderTest` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa. @@ -61,9 +60,8 @@ is appropriate for browsers, projects may wish to customize this file. ### Compatibility -Jasmine runs in both Node and browsers, including some older browsers that do -not support the latest JavaScript features. See the README for the list of -currently supported environments. +Jasmine runs in both Node and a variety of browsers. See the README for the +list of currently supported environments. ## Development @@ -89,8 +87,8 @@ Or, How to make a successful pull request * _Do not change the public interface_. Lots of projects depend on Jasmine and if you aren't careful you'll break them. -* _Be environment agnostic_ - server-side developers are just as important as - browser developers. +* _Be environment agnostic_. Some people run their specs in browsers, others in + Node. Jasmine should support them all as much as possible. * _Be browser agnostic_ - if you must rely on browser-specific functionality, please write it in a way that degrades gracefully. * _Write specs_ - Jasmine's a testing framework. Don't add functionality @@ -98,13 +96,14 @@ Or, How to make a successful pull request * _Write code in the style of the rest of the repo_ - Jasmine should look like a cohesive whole. - **Key exceptions:** + Key exceptions: * Use `const` or `let` for new variable declarations, even if nearby code uses `var`. * New async specs should usually be async/await or promise-returning, not callback based. + * _Ensure the *entire* test suite is green_ in all the big browsers, Node, and - ESLint. Your contribution shouldn't break Jasmine for other users. + ESLint/Prettier. Your contribution shouldn't break Jasmine for other users. Follow these tips and your pull request, patch, or suggestion is much more likely to be integrated. @@ -115,19 +114,8 @@ couple of supported browsers. To run the tests in Node, simply use `npm test` as described above. To run the tests in a browser, run `npm run serve` and then visit `http://localhost:8888`. -If you have the necessary Selenium drivers installed, you can also use Jasmine's -CI tooling: +If you have the necessary Selenium drivers installed (e.g. geckodriver or +chromedriver), you can also use Jasmine's CI tooling: - $ JASMINE_BROWSER= node spec/support/ci.js - -## Before Committing or Submitting a Pull Request - -1. Ensure all specs are green in browser *and* node. -1. Ensure eslint and prettier are clean as part of your `npm test` command. You can run `npm run cleanup` to have prettier re-write the files. -1. Build `jasmine.js` with `npm run build` and run all specs again - this ensures that your changes self-test well. -1. Revert your changes to `jasmine.js` and `jasmine-html.js` - * We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches - * When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into main - -Note that we use Circle CI for Continuous Integration. We only accept green pull requests. + $ JASMINE_BROWSER= npm run ci From 3c16caa4137d04e130ed522689376331498d10f9 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 31 Dec 2021 09:47:46 -0800 Subject: [PATCH 69/71] Link to the CONTRIBUTING guide from the PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 68876a5f..55507cc0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -24,7 +24,7 @@ - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. -- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have read the [**CONTRIBUTING**](https://github.com/jasmine/jasmine/blob/main/.github/CONTRIBUTING.md) guide. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. From 8444faab72ba82b75e40afabc0ca04bfe2e8f898 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 31 Dec 2021 10:00:14 -0800 Subject: [PATCH 70/71] Use the clock from jasmineUnderTest in specs --- spec/core/DelayedFunctionSchedulerSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/core/DelayedFunctionSchedulerSpec.js b/spec/core/DelayedFunctionSchedulerSpec.js index f5879e13..caa585c6 100644 --- a/spec/core/DelayedFunctionSchedulerSpec.js +++ b/spec/core/DelayedFunctionSchedulerSpec.js @@ -303,13 +303,13 @@ describe('DelayedFunctionScheduler', function() { let lastWork = 0; beforeEach(() => { - clock = jasmine.clock(); + clock = jasmineUnderTest.getEnv().clock; clock.install(); clock.mockDate(new Date(1)); }); afterEach(function() { - jasmine.clock().uninstall(); + jasmineUnderTest.getEnv().clock.uninstall(); }); it('preserves monotonically-increasing current time', () => { From ff14c03a400d56df91c7213e9ac8f46e3a0db3fb Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 1 Jan 2022 08:44:28 -0800 Subject: [PATCH 71/71] Test against the latest Node 12 --- .circleci/config.yml | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c4cd7246..27551f34 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,11 @@ executors: docker: - image: circleci/node:14 working_directory: ~/workspace - node12: + node12_latest: + docker: + - image: circleci/node:12 + working_directory: ~/workspace + node12_17: docker: - image: circleci/node:12.17 working_directory: ~/workspace @@ -112,18 +116,26 @@ workflows: executor: node14 name: build_node_14 - build: - executor: node12 - name: build_node_12 + executor: node12_latest + name: build_node_12_latest + - build: + executor: node12_17 + name: build_node_12_17 - test_node: executor: node16 name: test_node_16 requires: - build_node_16 - test_node: - executor: node12 - name: test_node_12 + executor: node12_latest + name: test_node_12_latest requires: - - build_node_12 + - build_node_12_latest + - test_node: + executor: node12_17 + name: test_node_12_17 + requires: + - build_node_12_17 - test_browsers: requires: - build_node_14 @@ -140,8 +152,11 @@ workflows: executor: node14 name: build_node_14 - build: - executor: node12 - name: build_node_12 + executor: node12_latest + name: build_node_12_latest + - build: + executor: node12_17 + name: build_node_12_17 - test_node: executor: node16 name: test_node_16 @@ -153,10 +168,15 @@ workflows: requires: - build_node_14 - test_node: - executor: node12 - name: test_node_12 + executor: node12_latest + name: test_node_12_latest requires: - - build_node_12 + - build_node_12_latest + - test_node: + executor: node12_17 + name: test_node_12_17 + requires: + - build_node_12_17 - test_browsers: requires: - build_node_14