Merge branch '3.99' into 4.0
This commit is contained in:
@@ -8,7 +8,18 @@ Gem::Specification.new do |s|
|
|||||||
s.platform = Gem::Platform::RUBY
|
s.platform = Gem::Platform::RUBY
|
||||||
s.authors = ["Gregg Van Hove"]
|
s.authors = ["Gregg Van Hove"]
|
||||||
s.summary = %q{JavaScript BDD framework}
|
s.summary = %q{JavaScript BDD framework}
|
||||||
s.description = %q{Test your JavaScript without any framework dependencies, in any environment, and with a nice descriptive syntax.}
|
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.email = %q{jasmine-js@googlegroups.com}
|
||||||
s.homepage = "http://jasmine.github.io"
|
s.homepage = "http://jasmine.github.io"
|
||||||
s.license = "MIT"
|
s.license = "MIT"
|
||||||
|
|||||||
@@ -1,3 +1,28 @@
|
|||||||
|
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 <https://jasmine.github.io/setup/browser.html> 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:
|
||||||
|
<https://github.com/jasmine/jasmine-npm>
|
||||||
|
* The standalone distribution to run specs in browsers with no additional
|
||||||
|
tools: <https://github.com/jasmine/jasmine#installation>
|
||||||
|
* The jasmine-core npm package if all you need is the Jasmine assets:
|
||||||
|
<https://github.com/jasmine/jasmine>. 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 Jasmine
|
||||||
module Core
|
module Core
|
||||||
class << self
|
class << self
|
||||||
|
|||||||
@@ -1096,6 +1096,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
* @type function
|
* @type function
|
||||||
* @default undefined
|
* @default undefined
|
||||||
|
* @deprecated In a future version, Jasmine will ignore the Promise config
|
||||||
|
* property and always create native promises instead.
|
||||||
*/
|
*/
|
||||||
Promise: undefined,
|
Promise: undefined,
|
||||||
/**
|
/**
|
||||||
@@ -1190,6 +1192,11 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
typeof configuration.Promise.reject === 'function'
|
typeof configuration.Promise.reject === 'function'
|
||||||
) {
|
) {
|
||||||
customPromise = configuration.Promise;
|
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 {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Custom promise library missing `resolve`/`reject` functions'
|
'Custom promise library missing `resolve`/`reject` functions'
|
||||||
@@ -1619,11 +1626,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
*
|
*
|
||||||
* execute should not be called more than once.
|
* execute should not be called more than once.
|
||||||
*
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @name Env#execute
|
* @name Env#execute
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
* @function
|
* @function
|
||||||
* @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
|
* @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
|
||||||
* @param {Function=} onComplete Function that will be called after all specs have run
|
* @param {Function=} onComplete Function that will be called after all specs have run
|
||||||
|
* @return {Promise<undefined>}
|
||||||
*/
|
*/
|
||||||
this.execute = function(runnablesToRun, onComplete) {
|
this.execute = function(runnablesToRun, onComplete) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
@@ -1683,65 +1696,86 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
var jasmineTimer = new j$.Timer();
|
var jasmineTimer = new j$.Timer();
|
||||||
jasmineTimer.start();
|
jasmineTimer.start();
|
||||||
|
|
||||||
/**
|
var Promise = customPromise || global.Promise;
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
|
||||||
* @typedef JasmineStartedInfo
|
|
||||||
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
*/
|
|
||||||
reporter.jasmineStarted(
|
|
||||||
{
|
|
||||||
totalSpecsDefined: totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
currentlyExecutingSuites.push(topSuite);
|
|
||||||
|
|
||||||
processor.execute(function() {
|
if (Promise) {
|
||||||
clearResourcesForRunnable(topSuite.id);
|
return new Promise(function(resolve) {
|
||||||
currentlyExecutingSuites.pop();
|
runAll(function() {
|
||||||
var overallStatus, incompleteReason;
|
if (onComplete) {
|
||||||
|
onComplete();
|
||||||
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';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
resolve();
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
reporter.jasmineDone(
|
|
||||||
{
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: topSuite.result.failedExpectations,
|
|
||||||
deprecationWarnings: topSuite.result.deprecationWarnings
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
if (onComplete) {
|
|
||||||
onComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
} else {
|
||||||
|
runAll(function() {
|
||||||
|
if (onComplete) {
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runAll(done) {
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
|
* @typedef JasmineStartedInfo
|
||||||
|
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
*/
|
||||||
|
reporter.jasmineStarted(
|
||||||
|
{
|
||||||
|
totalSpecsDefined: totalSpecsDefined,
|
||||||
|
order: order
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
currentlyExecutingSuites.push(topSuite);
|
||||||
|
|
||||||
|
processor.execute(function() {
|
||||||
|
clearResourcesForRunnable(topSuite.id);
|
||||||
|
currentlyExecutingSuites.pop();
|
||||||
|
var overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
reporter.jasmineDone(
|
||||||
|
{
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: topSuite.result.failedExpectations,
|
||||||
|
deprecationWarnings: topSuite.result.deprecationWarnings
|
||||||
|
},
|
||||||
|
done
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -4081,16 +4115,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
function taggedOnError(error) {
|
function taggedOnError(error) {
|
||||||
var substituteMsg;
|
var substituteMsg;
|
||||||
|
|
||||||
if (error) {
|
if (j$.isError_(error)) {
|
||||||
error.jasmineMessage = jasmineMessage + ': ' + error;
|
error.jasmineMessage = jasmineMessage + ': ' + error;
|
||||||
} else {
|
} else {
|
||||||
substituteMsg = jasmineMessage + ' with no error or message';
|
if (error) {
|
||||||
|
substituteMsg = jasmineMessage + ': ' + error;
|
||||||
|
} else {
|
||||||
|
substituteMsg = jasmineMessage + ' with no error or message';
|
||||||
|
}
|
||||||
|
|
||||||
if (errorType === 'unhandledRejection') {
|
if (errorType === 'unhandledRejection') {
|
||||||
substituteMsg +=
|
substituteMsg +=
|
||||||
'\n' +
|
'\n' +
|
||||||
'(Tip: to get a useful stack trace, use ' +
|
'(Tip: to get a useful stack trace, use ' +
|
||||||
'Promise.reject(new Error(...)) instead of Promise.reject().)';
|
'Promise.reject(new Error(...)) instead of Promise.reject(' +
|
||||||
|
(error ? '...' : '') +
|
||||||
|
').)';
|
||||||
}
|
}
|
||||||
|
|
||||||
error = new Error(substituteMsg);
|
error = new Error(substituteMsg);
|
||||||
@@ -9606,5 +9646,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().version = function() {
|
getJasmineRequireObj().version = function() {
|
||||||
return '3.8.0';
|
return '3.9.0';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
#
|
#
|
||||||
module Jasmine
|
module Jasmine
|
||||||
module Core
|
module Core
|
||||||
VERSION = "3.8.0"
|
VERSION = "3.9.0"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "jasmine-core",
|
"name": "jasmine-core",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "3.8.0",
|
"version": "3.9.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/jasmine/jasmine.git"
|
"url": "https://github.com/jasmine/jasmine.git"
|
||||||
|
|||||||
65
release_notes/3.9.0.md
Normal file
65
release_notes/3.9.0.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Jasmine Core 3.9 Release Notes
|
||||||
|
|
||||||
|
## New features and bug fixes
|
||||||
|
|
||||||
|
* Fixed Trusted Types error in `j$.isError_` in Chromium-based browsers
|
||||||
|
* Merges [#1921](https://github.com/jasmine/jasmine/pull/1921) from @bjarkler
|
||||||
|
* Fixes [#1910](https://github.com/jasmine/jasmine/issues/1910)
|
||||||
|
* Fixes [#1653](https://github.com/jasmine/jasmine/issues/1653)
|
||||||
|
|
||||||
|
* Better reporting of unhandled promise rejections with truthy but non-`Error`
|
||||||
|
reasons on Node
|
||||||
|
* `Env#execute` returns a promise in environments that support promises
|
||||||
|
* Renamed `failFast` and `oneFailurePerSpec` config props to `stopOnSpecFailure`
|
||||||
|
and `stopSpecOnExpectationFailure`
|
||||||
|
|
||||||
|
The new names are more self-explanatory and consistent with jasmine-npm. The
|
||||||
|
old names are deprecated but will still work until the next major release.
|
||||||
|
|
||||||
|
* Split `boot.js` into two files to allow the env to be configured in between
|
||||||
|
|
||||||
|
This is mainly intended to support jasmine-browser-runner, which will load
|
||||||
|
a script that configures the env in between the two boot files (`boot0.js` and
|
||||||
|
`boot1.js`). The single-file `boot.js` will still be included until the next
|
||||||
|
major release.
|
||||||
|
|
||||||
|
## Ruby deprecation
|
||||||
|
|
||||||
|
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](https://github.com/jasmine/jasmine-browser)
|
||||||
|
npm package, which is the direct replacement for the `jasmine` gem.
|
||||||
|
|
||||||
|
If `jasmine-browser-runner` doesn't meet your needs, one of these might:
|
||||||
|
|
||||||
|
* The [jasmine](https://github.com/jasmine/jasmine-npm) npm package to run
|
||||||
|
specs in Node.js.
|
||||||
|
* The [standalone distribution](https://github.com/jasmine/jasmine#installation)
|
||||||
|
to run specs in browsers with no additional tools.
|
||||||
|
* The [jasmine-core](https://github.com/jasmine/jasmine) npm package if all
|
||||||
|
you need is the Jasmine assets. This is the direct equivalent of the
|
||||||
|
`jasmine-core` Ruby gem.
|
||||||
|
|
||||||
|
## Documentation updates
|
||||||
|
|
||||||
|
* Added API docs for `Suite#id` and `Spec#id`
|
||||||
|
* Marked `Env#hideDisabled` deprecated in jsdocs
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
## Supported environments
|
||||||
|
|
||||||
|
jasmine-core 3.9.0 has been tested in the following environments.
|
||||||
|
|
||||||
|
| Environment | Supported versions |
|
||||||
|
|-------------------|--------------------|
|
||||||
|
| Node | 10, 12, 14, 16 |
|
||||||
|
| Safari | 8-14 |
|
||||||
|
| Chrome | 92 |
|
||||||
|
| Firefox | 91, 78, 68 |
|
||||||
|
| Edge | 92 |
|
||||||
|
| Internet Explorer | 10, 11 |
|
||||||
|
|
||||||
|
|
||||||
|
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||||
@@ -144,11 +144,17 @@ describe('Env', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can be configured with a custom library', function() {
|
it('can be configured with a custom library', function() {
|
||||||
|
spyOn(env, 'deprecated');
|
||||||
var myLibrary = {
|
var myLibrary = {
|
||||||
resolve: jasmine.createSpy(),
|
resolve: jasmine.createSpy(),
|
||||||
reject: jasmine.createSpy()
|
reject: jasmine.createSpy()
|
||||||
};
|
};
|
||||||
env.configure({ Promise: myLibrary });
|
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() {
|
it('cannot be configured with an invalid promise library', function() {
|
||||||
@@ -540,4 +546,10 @@ describe('Env', function() {
|
|||||||
|
|
||||||
expect(suiteThis).not.toBeInstanceOf(jasmineUnderTest.Suite);
|
expect(suiteThis).not.toBeInstanceOf(jasmineUnderTest.Suite);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#execute', function() {
|
||||||
|
it('returns a promise', function() {
|
||||||
|
expect(env.execute()).toBeInstanceOf(Promise);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -170,84 +170,118 @@ describe('GlobalErrors', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports unhandled promise rejections in node.js', function() {
|
describe('Reporting unhandled promise rejections in node.js', function() {
|
||||||
var fakeGlobal = {
|
it('reports rejections with `Error` reasons', function() {
|
||||||
process: {
|
var fakeGlobal = {
|
||||||
on: jasmine.createSpy('process.on'),
|
process: {
|
||||||
removeListener: jasmine.createSpy('process.removeListener'),
|
on: jasmine.createSpy('process.on'),
|
||||||
listeners: jasmine
|
removeListener: jasmine.createSpy('process.removeListener'),
|
||||||
.createSpy('process.listeners')
|
listeners: jasmine
|
||||||
.and.returnValue(['foo']),
|
.createSpy('process.listeners')
|
||||||
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
|
.and.returnValue(['foo']),
|
||||||
}
|
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
|
||||||
},
|
}
|
||||||
handler = jasmine.createSpy('errorHandler'),
|
},
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
|
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
|
||||||
'unhandledRejection',
|
'unhandledRejection',
|
||||||
jasmine.any(Function)
|
jasmine.any(Function)
|
||||||
);
|
);
|
||||||
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith(
|
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith(
|
||||||
'unhandledRejection'
|
'unhandledRejection'
|
||||||
);
|
);
|
||||||
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith(
|
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith(
|
||||||
'unhandledRejection'
|
'unhandledRejection'
|
||||||
);
|
);
|
||||||
|
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
|
|
||||||
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
|
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
|
||||||
addedListener(new Error('bar'));
|
addedListener(new Error('bar'));
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(new Error('bar'));
|
expect(handler).toHaveBeenCalledWith(new Error('bar'));
|
||||||
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
||||||
'Unhandled promise rejection: Error: bar'
|
'Unhandled promise rejection: Error: bar'
|
||||||
);
|
);
|
||||||
|
|
||||||
errors.uninstall();
|
errors.uninstall();
|
||||||
|
|
||||||
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith(
|
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith(
|
||||||
'unhandledRejection',
|
'unhandledRejection',
|
||||||
addedListener
|
addedListener
|
||||||
);
|
);
|
||||||
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
|
expect(fakeGlobal.process.on).toHaveBeenCalledWith(
|
||||||
'unhandledRejection',
|
'unhandledRejection',
|
||||||
'foo'
|
'foo'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports unhandled promise rejections in node.js when no error is provided', function() {
|
it('reports rejections with non-`Error` reasons', function() {
|
||||||
var fakeGlobal = {
|
var fakeGlobal = {
|
||||||
process: {
|
process: {
|
||||||
on: jasmine.createSpy('process.on'),
|
on: jasmine.createSpy('process.on'),
|
||||||
removeListener: function() {},
|
removeListener: function() {},
|
||||||
listeners: function() {
|
listeners: function() {
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
removeAllListeners: function() {}
|
removeAllListeners: function() {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler = jasmine.createSpy('errorHandler'),
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
errors.install();
|
errors.install();
|
||||||
errors.pushListener(handler);
|
errors.pushListener(handler);
|
||||||
|
|
||||||
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
|
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
|
||||||
'unhandledRejection'
|
'unhandledRejection'
|
||||||
);
|
);
|
||||||
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
|
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
|
||||||
addedListener(undefined);
|
addedListener(17);
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(
|
expect(handler).toHaveBeenCalledWith(
|
||||||
new Error(
|
new Error(
|
||||||
'Unhandled promise rejection with no error or message\n' +
|
'Unhandled promise rejection: 17\n' +
|
||||||
'(Tip: to get a useful stack trace, use ' +
|
'(Tip: to get a useful stack trace, use ' +
|
||||||
'Promise.reject(new Error(...)) instead of Promise.reject().)'
|
'Promise.reject(new Error(...)) instead of Promise.reject(...).)'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reports rejections with no reason provided', function() {
|
||||||
|
var fakeGlobal = {
|
||||||
|
process: {
|
||||||
|
on: jasmine.createSpy('process.on'),
|
||||||
|
removeListener: function() {},
|
||||||
|
listeners: function() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
removeAllListeners: function() {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler = jasmine.createSpy('errorHandler'),
|
||||||
|
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
|
||||||
|
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
|
||||||
|
'unhandledRejection'
|
||||||
|
);
|
||||||
|
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
|
||||||
|
addedListener(undefined);
|
||||||
|
|
||||||
|
expect(handler).toHaveBeenCalledWith(
|
||||||
|
new Error(
|
||||||
|
'Unhandled promise rejection with no error or message\n' +
|
||||||
|
'(Tip: to get a useful stack trace, use ' +
|
||||||
|
'Promise.reject(new Error(...)) instead of Promise.reject().)'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Reporting unhandled promise rejections in the browser', function() {
|
describe('Reporting unhandled promise rejections in the browser', function() {
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ describe('Spies', function() {
|
|||||||
reject: jasmine.createSpy()
|
reject: jasmine.createSpy()
|
||||||
};
|
};
|
||||||
customPromise.resolve.and.returnValue('resolved');
|
customPromise.resolve.and.returnValue('resolved');
|
||||||
|
spyOn(env, 'deprecated');
|
||||||
env.configure({ Promise: customPromise });
|
env.configure({ Promise: customPromise });
|
||||||
|
|
||||||
var spy = env.createSpy('foo').and.resolveTo(42);
|
var spy = env.createSpy('foo').and.resolveTo(42);
|
||||||
|
|||||||
@@ -2961,6 +2961,108 @@ describe('Env integration', function() {
|
|||||||
env.execute(null, done);
|
env.execute(null, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('The promise returned by #execute', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.savedInterval;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is resolved after reporter events are dispatched', function() {
|
||||||
|
var reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'specDone',
|
||||||
|
'suiteDone',
|
||||||
|
'jasmineDone'
|
||||||
|
]);
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
env.describe('suite', function() {
|
||||||
|
env.it('spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
return env.execute(null).then(function() {
|
||||||
|
expect(reporter.specDone).toHaveBeenCalled();
|
||||||
|
expect(reporter.suiteDone).toHaveBeenCalled();
|
||||||
|
expect(reporter.jasmineDone).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is resolved after the stack is cleared', function(done) {
|
||||||
|
var realClearStack = jasmineUnderTest.getClearStack(
|
||||||
|
jasmineUnderTest.getGlobal()
|
||||||
|
),
|
||||||
|
clearStackSpy = jasmine
|
||||||
|
.createSpy('clearStack')
|
||||||
|
.and.callFake(realClearStack);
|
||||||
|
spyOn(jasmineUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
|
||||||
|
|
||||||
|
// Create a new env that has the clearStack defined above
|
||||||
|
env.cleanup_();
|
||||||
|
env = new jasmineUnderTest.Env();
|
||||||
|
|
||||||
|
env.describe('suite', function() {
|
||||||
|
env.it('spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.execute(null).then(function() {
|
||||||
|
expect(clearStackSpy).toHaveBeenCalled(); // (many times)
|
||||||
|
clearStackSpy.calls.reset();
|
||||||
|
setTimeout(function() {
|
||||||
|
expect(clearStackSpy).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is resolved after QueueRunner timeouts are cleared', function() {
|
||||||
|
var setTimeoutSpy = spyOn(
|
||||||
|
jasmineUnderTest.getGlobal(),
|
||||||
|
'setTimeout'
|
||||||
|
).and.callThrough();
|
||||||
|
var clearTimeoutSpy = spyOn(
|
||||||
|
jasmineUnderTest.getGlobal(),
|
||||||
|
'clearTimeout'
|
||||||
|
).and.callThrough();
|
||||||
|
|
||||||
|
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 123456; // a distinctive value
|
||||||
|
|
||||||
|
env = new jasmineUnderTest.Env();
|
||||||
|
|
||||||
|
env.describe('suite', function() {
|
||||||
|
env.it('spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
return env.execute(null).then(function() {
|
||||||
|
var timeoutIds = setTimeoutSpy.calls
|
||||||
|
.all()
|
||||||
|
.filter(function(call) {
|
||||||
|
return call.args[1] === 123456;
|
||||||
|
})
|
||||||
|
.map(function(call) {
|
||||||
|
return call.returnValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(timeoutIds.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
timeoutIds.forEach(function(timeoutId) {
|
||||||
|
expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is resolved even if specs fail', function() {
|
||||||
|
env.describe('suite', function() {
|
||||||
|
env.it('spec', function() {
|
||||||
|
env.expect(true).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return expectAsync(env.execute(null)).toBeResolved();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('The optional callback argument to #execute', function() {
|
describe('The optional callback argument to #execute', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
this.savedInterval = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
|||||||
144
src/core/Env.js
144
src/core/Env.js
@@ -119,6 +119,8 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
* @type function
|
* @type function
|
||||||
* @default undefined
|
* @default undefined
|
||||||
|
* @deprecated In a future version, Jasmine will ignore the Promise config
|
||||||
|
* property and always create native promises instead.
|
||||||
*/
|
*/
|
||||||
Promise: undefined,
|
Promise: undefined,
|
||||||
/**
|
/**
|
||||||
@@ -213,6 +215,11 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
typeof configuration.Promise.reject === 'function'
|
typeof configuration.Promise.reject === 'function'
|
||||||
) {
|
) {
|
||||||
customPromise = configuration.Promise;
|
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 {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Custom promise library missing `resolve`/`reject` functions'
|
'Custom promise library missing `resolve`/`reject` functions'
|
||||||
@@ -642,11 +649,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
*
|
*
|
||||||
* execute should not be called more than once.
|
* execute should not be called more than once.
|
||||||
*
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* @name Env#execute
|
* @name Env#execute
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
* @function
|
* @function
|
||||||
* @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
|
* @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
|
||||||
* @param {Function=} onComplete Function that will be called after all specs have run
|
* @param {Function=} onComplete Function that will be called after all specs have run
|
||||||
|
* @return {Promise<undefined>}
|
||||||
*/
|
*/
|
||||||
this.execute = function(runnablesToRun, onComplete) {
|
this.execute = function(runnablesToRun, onComplete) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
@@ -706,65 +719,86 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
var jasmineTimer = new j$.Timer();
|
var jasmineTimer = new j$.Timer();
|
||||||
jasmineTimer.start();
|
jasmineTimer.start();
|
||||||
|
|
||||||
/**
|
var Promise = customPromise || global.Promise;
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
|
||||||
* @typedef JasmineStartedInfo
|
|
||||||
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
*/
|
|
||||||
reporter.jasmineStarted(
|
|
||||||
{
|
|
||||||
totalSpecsDefined: totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
currentlyExecutingSuites.push(topSuite);
|
|
||||||
|
|
||||||
processor.execute(function() {
|
if (Promise) {
|
||||||
clearResourcesForRunnable(topSuite.id);
|
return new Promise(function(resolve) {
|
||||||
currentlyExecutingSuites.pop();
|
runAll(function() {
|
||||||
var overallStatus, incompleteReason;
|
if (onComplete) {
|
||||||
|
onComplete();
|
||||||
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';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
resolve();
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
reporter.jasmineDone(
|
|
||||||
{
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: topSuite.result.failedExpectations,
|
|
||||||
deprecationWarnings: topSuite.result.deprecationWarnings
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
if (onComplete) {
|
|
||||||
onComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
} else {
|
||||||
|
runAll(function() {
|
||||||
|
if (onComplete) {
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runAll(done) {
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
|
* @typedef JasmineStartedInfo
|
||||||
|
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
*/
|
||||||
|
reporter.jasmineStarted(
|
||||||
|
{
|
||||||
|
totalSpecsDefined: totalSpecsDefined,
|
||||||
|
order: order
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
currentlyExecutingSuites.push(topSuite);
|
||||||
|
|
||||||
|
processor.execute(function() {
|
||||||
|
clearResourcesForRunnable(topSuite.id);
|
||||||
|
currentlyExecutingSuites.pop();
|
||||||
|
var overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
reporter.jasmineDone(
|
||||||
|
{
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: topSuite.result.failedExpectations,
|
||||||
|
deprecationWarnings: topSuite.result.deprecationWarnings
|
||||||
|
},
|
||||||
|
done
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,16 +19,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
function taggedOnError(error) {
|
function taggedOnError(error) {
|
||||||
var substituteMsg;
|
var substituteMsg;
|
||||||
|
|
||||||
if (error) {
|
if (j$.isError_(error)) {
|
||||||
error.jasmineMessage = jasmineMessage + ': ' + error;
|
error.jasmineMessage = jasmineMessage + ': ' + error;
|
||||||
} else {
|
} else {
|
||||||
substituteMsg = jasmineMessage + ' with no error or message';
|
if (error) {
|
||||||
|
substituteMsg = jasmineMessage + ': ' + error;
|
||||||
|
} else {
|
||||||
|
substituteMsg = jasmineMessage + ' with no error or message';
|
||||||
|
}
|
||||||
|
|
||||||
if (errorType === 'unhandledRejection') {
|
if (errorType === 'unhandledRejection') {
|
||||||
substituteMsg +=
|
substituteMsg +=
|
||||||
'\n' +
|
'\n' +
|
||||||
'(Tip: to get a useful stack trace, use ' +
|
'(Tip: to get a useful stack trace, use ' +
|
||||||
'Promise.reject(new Error(...)) instead of Promise.reject().)';
|
'Promise.reject(new Error(...)) instead of Promise.reject(' +
|
||||||
|
(error ? '...' : '') +
|
||||||
|
').)';
|
||||||
}
|
}
|
||||||
|
|
||||||
error = new Error(substituteMsg);
|
error = new Error(substituteMsg);
|
||||||
|
|||||||
Reference in New Issue
Block a user