Merge branch 'main' into 5.0

This commit is contained in:
Steve Gravrock
2022-09-18 09:41:45 -07:00
15 changed files with 206 additions and 129 deletions

View File

@@ -1,19 +1,10 @@
# Developing for Jasmine Core
# Contributing to Jasmine
We welcome your contributions! Thanks for helping make Jasmine a better project
for everyone. Please review the backlog and discussion lists before starting
work. What you're looking for may already have been done. If it hasn't, the
community can help make your contribution better. If you want to contribute but
don't know what to work on,
[issues tagged help needed](https://github.com/jasmine/jasmine/labels/help%20needed)
for everyone. If you want to contribute but don't know what to work on,
[issues tagged help needed](https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Ajasmine+label%3A%22help+needed%22+)
should have enough detail to get started.
## Links
- [Jasmine Google Group](http://groups.google.com/group/jasmine-js)
- [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev)
- [Jasmine backlog](https://www.pivotaltracker.com/n/projects/10606)
## Before Submitting a Pull Request
1. Ensure all specs are green in browsers *and* node.
@@ -94,14 +85,7 @@ Or, How to make a successful pull request
* _Write specs_ - Jasmine's a testing framework. Don't add functionality
without test-driving it.
* _Write code in the style of the rest of the repo_ - Jasmine should look like
a cohesive whole.
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.
a cohesive whole.
* _Ensure the *entire* test suite is green_ in all the big browsers, Node, and
ESLint/Prettier. Your contribution shouldn't break Jasmine for other users.
@@ -119,3 +103,10 @@ chromedriver), you can also use Jasmine's CI tooling:
$ JASMINE_BROWSER=<name of browser> npm run ci
### Submitting a Pull Requeset
Once you've done the steps listed under "Before Submitting a Pull Request"
above, you can submit a pull request via the
[standard GitHub process](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
TL;DR: Fork the repository, push your work up to your fork, and create a PR from
there.

View File

@@ -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 <https://github.com/jasmine/jasmine-npm/blob/main/RELEASE.md>.
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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
}
};
}
};
}

View File

@@ -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');
});
});
});

View File

@@ -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');
});
});
});

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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");
};

View File

@@ -8421,7 +8421,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({
@@ -9860,11 +9860,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;
}
@@ -10011,11 +10006,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;

28
release_notes/4.4.0.md Normal file
View File

@@ -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)_

View File

@@ -2035,6 +2035,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']);
@@ -4011,6 +4034,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 {
listeners_: { error: [], unhandledrejection: [] },

View File

@@ -47,7 +47,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({

View File

@@ -32,11 +32,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;
}
@@ -183,11 +178,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;