diff --git a/RELEASE.md b/RELEASE.md index 347c6b3a..517752c2 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -18,12 +18,11 @@ 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: +Note that Jasmine should only use the "patch" version number if the new release +contains only bug fixes. -* 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. +When `jasmine-core` revs its major or minor version, the `jasmine` NPM package +should also rev to that version. ## Release @@ -61,20 +60,13 @@ for instructions. 1. `rake release[${version}]` to copy the current edge docs to the new version 1. Commit and push. -### Release the binding libraries +### Release the `jasmine` NPM package -#### NPM +See . -1. Create release notes using Anchorman as above -1. In `package.json`, update both the package version and the jasmine-core dependency version -1. Commit and push. -1. Wait for Circle CI to go green again. -1. `grunt release `. (Note: This will publish the package by running `npm publish`.) +### Publish the GitHub release -### Finally - -For each of the above GitHub repos: 1. Visit the releases page and find the tag just published. -1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes. -1. If it is a pre-release, mark it as such. -1. For core, attach the standalone zipfile. +2. Paste in a link to the correct release notes for this release. +3. If it is a pre-release, mark it as such. +4. Attach the standalone zipfile. diff --git a/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js b/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js index fe95f894..8a7bfbdc 100644 --- a/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js +++ b/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js @@ -1,24 +1,24 @@ -function Player() { -} -Player.prototype.play = function(song) { - this.currentlyPlayingSong = song; - this.isPlaying = true; -}; - -Player.prototype.pause = function() { - this.isPlaying = false; -}; - -Player.prototype.resume = function() { - if (this.isPlaying) { - throw new Error("song is already playing"); +class Player { + play(song) { + this.currentlyPlayingSong = song; + this.isPlaying = true; } - this.isPlaying = true; -}; + pause() { + this.isPlaying = false; + } -Player.prototype.makeFavorite = function() { - this.currentlyPlayingSong.persistFavoriteStatus(true); -}; + resume() { + if (this.isPlaying) { + throw new Error('song is already playing'); + } + + this.isPlaying = true; + } + + makeFavorite() { + this.currentlyPlayingSong.persistFavoriteStatus(true); + } +} module.exports = Player; diff --git a/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js b/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js index 3415bb82..f2757786 100644 --- a/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js +++ b/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js @@ -1,9 +1,8 @@ -function Song() { +class Song { + persistFavoriteStatus(value) { + // something complicated + throw new Error('not yet implemented'); + } } -Song.prototype.persistFavoriteStatus = function(value) { - // something complicated - throw new Error("not yet implemented"); -}; - module.exports = Song; diff --git a/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/SpecHelper.js b/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/SpecHelper.js index 578b3e86..cc04bd8d 100644 --- a/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/SpecHelper.js +++ b/lib/jasmine-core/example/node_example/spec/helpers/jasmine_examples/SpecHelper.js @@ -3,11 +3,11 @@ beforeEach(function () { toBePlaying: function () { return { compare: function (actual, expected) { - var player = actual; + const player = actual; return { pass: player.currentlyPlayingSong === expected && player.isPlaying - } + }; } }; } diff --git a/lib/jasmine-core/example/node_example/spec/jasmine_examples/PlayerSpec.js b/lib/jasmine-core/example/node_example/spec/jasmine_examples/PlayerSpec.js index 80f149e3..fa96ccc4 100644 --- a/lib/jasmine-core/example/node_example/spec/jasmine_examples/PlayerSpec.js +++ b/lib/jasmine-core/example/node_example/spec/jasmine_examples/PlayerSpec.js @@ -1,36 +1,37 @@ -describe("Player", function() { - var Player = require('../../lib/jasmine_examples/Player'); - var Song = require('../../lib/jasmine_examples/Song'); - var player; - var song; +const Player = require('../../lib/jasmine_examples/Player'); +const Song = require('../../lib/jasmine_examples/Song'); + +describe('Player', function() { + let player; + let song; beforeEach(function() { player = new Player(); song = new Song(); }); - it("should be able to play a Song", function() { + it('should be able to play a Song', function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); - //demonstrates use of custom matcher + // demonstrates use of custom matcher expect(player).toBePlaying(song); }); - describe("when song has been paused", function() { + describe('when song has been paused', function() { beforeEach(function() { player.play(song); player.pause(); }); - it("should indicate that the song is currently paused", function() { + it('should indicate that the song is currently paused', function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); - it("should be possible to resume", function() { + it('should be possible to resume', function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); @@ -38,7 +39,7 @@ describe("Player", function() { }); // demonstrates use of spies to intercept and test method calls - it("tells the current song if the user has made it a favorite", function() { + it('tells the current song if the user has made it a favorite', function() { spyOn(song, 'persistFavoriteStatus'); player.play(song); @@ -48,13 +49,13 @@ describe("Player", function() { }); //demonstrates use of expected exceptions - describe("#resume", function() { - it("should throw an exception if song is already playing", function() { + describe('#resume', function() { + it('should throw an exception if song is already playing', function() { player.play(song); expect(function() { player.resume(); - }).toThrowError("song is already playing"); + }).toThrowError('song is already playing'); }); }); }); diff --git a/lib/jasmine-core/example/spec/PlayerSpec.js b/lib/jasmine-core/example/spec/PlayerSpec.js index f17521fd..9617c4f4 100644 --- a/lib/jasmine-core/example/spec/PlayerSpec.js +++ b/lib/jasmine-core/example/spec/PlayerSpec.js @@ -1,34 +1,34 @@ -describe("Player", function() { - var player; - var song; +describe('Player', function() { + let player; + let song; beforeEach(function() { player = new Player(); song = new Song(); }); - it("should be able to play a Song", function() { + it('should be able to play a Song', function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); - //demonstrates use of custom matcher + // demonstrates use of custom matcher expect(player).toBePlaying(song); }); - describe("when song has been paused", function() { + describe('when song has been paused', function() { beforeEach(function() { player.play(song); player.pause(); }); - it("should indicate that the song is currently paused", function() { + it('should indicate that the song is currently paused', function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); - it("should be possible to resume", function() { + it('should be possible to resume', function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); @@ -36,7 +36,7 @@ describe("Player", function() { }); // demonstrates use of spies to intercept and test method calls - it("tells the current song if the user has made it a favorite", function() { + it('tells the current song if the user has made it a favorite', function() { spyOn(song, 'persistFavoriteStatus'); player.play(song); @@ -46,13 +46,13 @@ describe("Player", function() { }); //demonstrates use of expected exceptions - describe("#resume", function() { - it("should throw an exception if song is already playing", function() { + describe('#resume', function() { + it('should throw an exception if song is already playing', function() { player.play(song); expect(function() { player.resume(); - }).toThrowError("song is already playing"); + }).toThrowError('song is already playing'); }); }); }); diff --git a/lib/jasmine-core/example/spec/SpecHelper.js b/lib/jasmine-core/example/spec/SpecHelper.js index 126752d1..cc04bd8d 100644 --- a/lib/jasmine-core/example/spec/SpecHelper.js +++ b/lib/jasmine-core/example/spec/SpecHelper.js @@ -3,7 +3,7 @@ beforeEach(function () { toBePlaying: function () { return { compare: function (actual, expected) { - var player = actual; + const player = actual; return { pass: player.currentlyPlayingSong === expected && player.isPlaying diff --git a/lib/jasmine-core/example/src/Player.js b/lib/jasmine-core/example/src/Player.js index 11851966..f2fae6f7 100644 --- a/lib/jasmine-core/example/src/Player.js +++ b/lib/jasmine-core/example/src/Player.js @@ -1,22 +1,22 @@ -function Player() { -} -Player.prototype.play = function(song) { - this.currentlyPlayingSong = song; - this.isPlaying = true; -}; - -Player.prototype.pause = function() { - this.isPlaying = false; -}; - -Player.prototype.resume = function() { - if (this.isPlaying) { - throw new Error("song is already playing"); +class Player { + play(song) { + this.currentlyPlayingSong = song; + this.isPlaying = true; } - this.isPlaying = true; -}; + pause() { + this.isPlaying = false; + } -Player.prototype.makeFavorite = function() { - this.currentlyPlayingSong.persistFavoriteStatus(true); -}; + resume() { + if (this.isPlaying) { + throw new Error('song is already playing'); + } + + this.isPlaying = true; + } + + makeFavorite() { + this.currentlyPlayingSong.persistFavoriteStatus(true); + } +} diff --git a/lib/jasmine-core/example/src/Song.js b/lib/jasmine-core/example/src/Song.js index 02527cb1..8914793b 100644 --- a/lib/jasmine-core/example/src/Song.js +++ b/lib/jasmine-core/example/src/Song.js @@ -1,7 +1,6 @@ -function Song() { +class Song { + persistFavoriteStatus(value) { + // something complicated + throw new Error('not yet implemented'); + } } - -Song.prototype.persistFavoriteStatus = function(value) { - // something complicated - throw new Error("not yet implemented"); -}; diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2954f8b2..67cbd179 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -8454,7 +8454,7 @@ getJasmineRequireObj().Runner = function(j$) { const order = new j$.Order({ random: config.random, - seed: config.seed + seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed }); const processor = new j$.TreeProcessor({ @@ -9904,11 +9904,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { suite.exclude(); } this.addSpecsToSuite_(suite, definitionFn); - if (suite.parentSuite && !suite.children.length) { - throw new Error( - `describe with no children (describe() or it()): ${suite.getFullName()}` - ); - } return suite; } @@ -10055,11 +10050,19 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { const parentSuite = this.currentDeclarationSuite_; parentSuite.addChild(suite); this.currentDeclarationSuite_ = suite; + let threw = false; try { definitionFn(); } catch (e) { suite.handleException(e); + threw = true; + } + + if (suite.parentSuite && !suite.children.length && !threw) { + throw new Error( + `describe with no children (describe() or it()): ${suite.getFullName()}` + ); } this.currentDeclarationSuite_ = parentSuite; diff --git a/release_notes/4.4.0.md b/release_notes/4.4.0.md new file mode 100644 index 00000000..0674f02b --- /dev/null +++ b/release_notes/4.4.0.md @@ -0,0 +1,28 @@ +# Jasmine 4.4.0 Release Notes + +## Changes + +* Optimized the process of transitioning between specs in Node, Safari, and + Edge. This change reduces the run time of jasmine-core's own test suite by + 50-70% in Node, about 20% in Edge, and 75-90% in Safari. Your results may + vary. In general, suites with many fast specs will see the greatest + performance improvement. + +* Removed old code to support browsers that don't provide + addEventListener/removeEventListener. + +## Supported environments + +jasmine-core 4.4.0 has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------| +| Node | 12.17+, 14, 16, 18 | +| Safari | 14-15 | +| Chrome | 105 | +| Firefox | 91, 102, 104 | +| Edge | 104 | + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index cd5206a4..88fbbbb9 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -2026,6 +2026,29 @@ describe('Env integration', function() { expect(doneArg.order.seed).toEqual('123456'); }); + it('coerces the random seed to a string if it is a number', async function() { + const reporter = jasmine.createSpyObj('fakeReporter', [ + 'jasmineStarted', + 'jasmineDone', + 'suiteStarted', + 'suiteDone', + 'specStarted', + 'specDone' + ]); + env.configure({ random: true, seed: 123456 }); + + env.addReporter(reporter); + env.configure({ random: true }); + await env.execute(); + + expect(reporter.jasmineStarted).toHaveBeenCalled(); + const startedArg = reporter.jasmineStarted.calls.argsFor(0)[0]; + expect(startedArg.order.seed).toEqual('123456'); + + const doneArg = reporter.jasmineDone.calls.argsFor(0)[0]; + expect(doneArg.order.seed).toEqual('123456'); + }); + it('should report pending spec messages', async function() { const reporter = jasmine.createSpyObj('fakeReporter', ['specDone']); @@ -3947,6 +3970,44 @@ describe('Env integration', function() { }); }); + it('reports a suite level error when a describe fn throws', async function() { + const reporter = jasmine.createSpyObj('reporter', ['suiteDone']); + env.addReporter(reporter); + + env.describe('throws before defining specs', function() { + throw new Error('nope'); + }); + + env.describe('throws after defining specs', function() { + env.it('is a spec'); + throw new Error('nope'); + }); + + await env.execute(); + + expect(reporter.suiteDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'throws after defining specs', + failedExpectations: [ + jasmine.objectContaining({ + message: jasmine.stringContaining('Error: nope') + }) + ] + }) + ); + + expect(reporter.suiteDone).toHaveBeenCalledWith( + jasmine.objectContaining({ + fullName: 'throws after defining specs', + failedExpectations: [ + jasmine.objectContaining({ + message: jasmine.stringContaining('Error: nope') + }) + ] + }) + ); + }); + function browserEventMethods() { return { addEventListener() {}, diff --git a/src/core/Runner.js b/src/core/Runner.js index 55ad10cf..c01bcf16 100644 --- a/src/core/Runner.js +++ b/src/core/Runner.js @@ -51,7 +51,7 @@ getJasmineRequireObj().Runner = function(j$) { const order = new j$.Order({ random: config.random, - seed: config.seed + seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed }); const processor = new j$.TreeProcessor({ diff --git a/src/core/SuiteBuilder.js b/src/core/SuiteBuilder.js index 1115e7a8..50ed5c7d 100644 --- a/src/core/SuiteBuilder.js +++ b/src/core/SuiteBuilder.js @@ -38,11 +38,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { suite.exclude(); } this.addSpecsToSuite_(suite, definitionFn); - if (suite.parentSuite && !suite.children.length) { - throw new Error( - `describe with no children (describe() or it()): ${suite.getFullName()}` - ); - } return suite; } @@ -189,11 +184,19 @@ getJasmineRequireObj().SuiteBuilder = function(j$) { const parentSuite = this.currentDeclarationSuite_; parentSuite.addChild(suite); this.currentDeclarationSuite_ = suite; + let threw = false; try { definitionFn(); } catch (e) { suite.handleException(e); + threw = true; + } + + if (suite.parentSuite && !suite.children.length && !threw) { + throw new Error( + `describe with no children (describe() or it()): ${suite.getFullName()}` + ); } this.currentDeclarationSuite_ = parentSuite;