Compare commits
36 Commits
v5.0.0-bet
...
v5.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d06dce4614 | ||
|
|
03098e81f8 | ||
|
|
726c152f6e | ||
|
|
409d2e29e5 | ||
|
|
01e2bd5050 | ||
|
|
96033e38ea | ||
|
|
ed75290ef7 | ||
|
|
a14dbf012a | ||
|
|
17c11ba7b9 | ||
|
|
2a1daca1ca | ||
|
|
f0db5ce350 | ||
|
|
39f9c2e1a0 | ||
|
|
bff612a169 | ||
|
|
4ba42f3746 | ||
|
|
58bee05c36 | ||
|
|
c1871b0f0c | ||
|
|
c16974b091 | ||
|
|
bfedda9764 | ||
|
|
a67b7276be | ||
|
|
47f3105ef0 | ||
|
|
aeb56539c9 | ||
|
|
75d45efa16 | ||
|
|
59d1c5bebb | ||
|
|
040983c979 | ||
|
|
2ddb344bac | ||
|
|
e56bd3918b | ||
|
|
59600a1c29 | ||
|
|
f8e4ea868f | ||
|
|
0ff56c53b1 | ||
|
|
b617d983de | ||
|
|
8e0f0e8e8c | ||
|
|
d745d6b5f0 | ||
|
|
fc2c2a477d | ||
|
|
ff93277c0f | ||
|
|
90741b3cee | ||
|
|
d1de59f0ed |
@@ -80,7 +80,7 @@ jobs:
|
||||
# cleanly if we kill it from a different step than it started in.
|
||||
|
||||
export PATH=$PATH:$HOME/workspace/bin
|
||||
export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_BUILD_NUM
|
||||
export SAUCE_TUNNEL_IDENTIFIER=$CIRCLE_WORKFLOW_JOB_ID
|
||||
scripts/start-sauce-connect sauce-pidfile
|
||||
set +o errexit
|
||||
scripts/run-all-browsers
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: I think I've found a bug in Jasmine
|
||||
labels: ["unconfirmed bug"]
|
||||
labels: ["bug report"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2023 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
13
README.md
13
README.md
@@ -1,13 +1,10 @@
|
||||
<a name="README">[<img src="https://rawgithub.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" />](http://jasmine.github.io)</a>
|
||||
|
||||
[](https://circleci.com/gh/jasmine/jasmine)
|
||||
[](https://www.codetriage.com/jasmine/jasmine)
|
||||
|
||||
# A JavaScript Testing Framework
|
||||
|
||||
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.
|
||||
|
||||
Upgrading from Jasmine 3.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0).
|
||||
Upgrading from Jasmine 4.x? Check out the [upgrade guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -33,9 +30,9 @@ Microsoft Edge) as well as Node.
|
||||
| Environment | Supported versions |
|
||||
|-------------------|---------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | Evergreen |
|
||||
| Firefox | Evergreen, 102 |
|
||||
| Firefox | Evergreen, 102, 115 |
|
||||
| Edge | Evergreen |
|
||||
|
||||
For evergreen browsers, each version of Jasmine is tested against the version of the browser that is available to us
|
||||
@@ -58,4 +55,6 @@ To find out what environments work with a particular Jasmine release, see the [r
|
||||
* [Christian Williams](mailto:antixian666@gmail.com)
|
||||
* Sheel Choksi
|
||||
|
||||
Copyright (c) 2008-2022 Jasmine Maintainers. This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/MIT.LICENSE).
|
||||
Copyright (c) 2008-2019 Pivotal Labs<br>
|
||||
Copyright (c) 2008-2023 The Jasmine developers<br>
|
||||
This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE).
|
||||
|
||||
@@ -11,7 +11,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
files: [
|
||||
{ src: [ root("MIT.LICENSE") ] },
|
||||
{ src: [ root("LICENSE") ] },
|
||||
{
|
||||
src: [ "jasmine_favicon.png"],
|
||||
dest: standaloneLibDir,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-<%= currentYear %> Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-<%= currentYear %> The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
const jasmineRequire = require('./jasmine-core/jasmine.js');
|
||||
module.exports = jasmineRequire;
|
||||
|
||||
const bootOnce = (function() {
|
||||
const boot = (function() {
|
||||
let jasmine, jasmineInterface;
|
||||
|
||||
return function bootWithoutGlobals() {
|
||||
if (!jasmineInterface) {
|
||||
return function bootWithoutGlobals(reinitialize) {
|
||||
if (!jasmineInterface || reinitialize === true) {
|
||||
jasmine = jasmineRequire.core(jasmineRequire);
|
||||
const env = jasmine.getEnv({ suppressLoadErrors: true });
|
||||
jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
@@ -22,12 +22,14 @@ const bootOnce = (function() {
|
||||
|
||||
/**
|
||||
* Boots a copy of Jasmine and returns an object as described in {@link jasmine}.
|
||||
* If boot is called multiple times, the same object is returned every time.
|
||||
* If boot is called multiple times, the same object is returned every time
|
||||
* unless true is passed.
|
||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
||||
* @type {function}
|
||||
* @return {jasmine}
|
||||
*/
|
||||
module.exports.boot = function() {
|
||||
const {jasmine, jasmineInterface} = bootOnce();
|
||||
module.exports.boot = function(reinitialize) {
|
||||
const {jasmine, jasmineInterface} = boot(reinitialize);
|
||||
|
||||
for (const k in jasmineInterface) {
|
||||
global[k] = jasmineInterface[k];
|
||||
@@ -39,13 +41,14 @@ module.exports.boot = function() {
|
||||
/**
|
||||
* 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.
|
||||
* multiple times, the same object is returned every time unless true is passed.
|
||||
*
|
||||
* @param {boolean} [reinitialize=false] Whether to create a new copy of Jasmine if one already exists
|
||||
* @example
|
||||
* const {describe, beforeEach, it, expect, jasmine} = require('jasmine-core').noGlobals();
|
||||
*/
|
||||
module.exports.noGlobals = function() {
|
||||
const {jasmineInterface} = bootOnce();
|
||||
module.exports.noGlobals = function(reinitialize) {
|
||||
const {jasmineInterface} = boot(reinitialize);
|
||||
return jasmineInterface;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -530,14 +531,13 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
if (noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
if (
|
||||
resultNode.result.status === 'pending' &&
|
||||
resultNode.result.pendingReason !== ''
|
||||
) {
|
||||
specDescription =
|
||||
specDescription +
|
||||
' PENDING WITH MESSAGE: ' +
|
||||
resultNode.result.pendingReason;
|
||||
if (resultNode.result.status === 'pending') {
|
||||
if (resultNode.result.pendingReason !== '') {
|
||||
specDescription +=
|
||||
' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
|
||||
} else {
|
||||
specDescription += ' PENDING';
|
||||
}
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom(
|
||||
|
||||
@@ -55,9 +55,6 @@ body {
|
||||
position: fixed;
|
||||
right: 100%;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-version {
|
||||
color: #aaa;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-banner {
|
||||
margin-top: 14px;
|
||||
}
|
||||
@@ -169,10 +166,11 @@ body {
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar.jasmine-menu {
|
||||
background-color: #fff;
|
||||
color: #aaa;
|
||||
color: #000;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar.jasmine-menu a {
|
||||
color: #333;
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.jasmine_html-reporter .jasmine-bar a {
|
||||
color: white;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2008-2023 Pivotal Labs
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
Copyright (c) 2008-2024 The Jasmine developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -809,14 +810,6 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
this.result.properties[key] = value;
|
||||
};
|
||||
|
||||
Spec.prototype.expect = function(actual) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.expectAsync = function(actual) {
|
||||
return this.asyncExpectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.execute = function(
|
||||
queueRunnerFactory,
|
||||
onComplete,
|
||||
@@ -1401,6 +1394,49 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleThrowUnlessFailure = function(passed, result) {
|
||||
if (!passed) {
|
||||
/**
|
||||
* @interface
|
||||
* @name ThrowUnlessFailure
|
||||
* @extends Error
|
||||
* @description Represents a failure of an expectation evaluated with
|
||||
* {@link throwUnless}. Properties of this error are a subset of the
|
||||
* properties of {@link Expectation} and have the same values.
|
||||
* @property {String} matcherName - The name of the matcher that was executed for this expectation.
|
||||
* @property {String} message - The failure message for the expectation.
|
||||
* @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.
|
||||
*/
|
||||
const error = new Error(result.message);
|
||||
error.passed = result.passed;
|
||||
error.message = result.message;
|
||||
error.expected = result.expected;
|
||||
error.actual = result.actual;
|
||||
error.matcherName = result.matcherName;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const throwUnlessFactory = function(actual, spec) {
|
||||
return j$.Expectation.factory({
|
||||
matchersUtil: runableResources.makeMatchersUtil(),
|
||||
customMatchers: runableResources.customMatchers(),
|
||||
actual: actual,
|
||||
addExpectationResult: handleThrowUnlessFailure
|
||||
});
|
||||
};
|
||||
|
||||
const throwUnlessAsyncFactory = function(actual, spec) {
|
||||
return j$.Expectation.asyncFactory({
|
||||
matchersUtil: runableResources.makeMatchersUtil(),
|
||||
customAsyncMatchers: runableResources.customAsyncMatchers(),
|
||||
actual: actual,
|
||||
addExpectationResult: handleThrowUnlessFailure
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
||||
// diagnostic info added by the latter is probably useful in most cases.
|
||||
function recordLateError(error) {
|
||||
@@ -1904,23 +1940,37 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.expect = function(actual) {
|
||||
if (!runner.currentRunable()) {
|
||||
const runable = runner.currentRunable();
|
||||
|
||||
if (!runable) {
|
||||
throw new Error(
|
||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||
);
|
||||
}
|
||||
|
||||
return runner.currentRunable().expect(actual);
|
||||
return runable.expectationFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.expectAsync = function(actual) {
|
||||
if (!runner.currentRunable()) {
|
||||
const runable = runner.currentRunable();
|
||||
|
||||
if (!runable) {
|
||||
throw new Error(
|
||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||
);
|
||||
}
|
||||
|
||||
return runner.currentRunable().expectAsync(actual);
|
||||
return runable.asyncExpectationFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.throwUnless = function(actual) {
|
||||
const runable = runner.currentRunable();
|
||||
return throwUnlessFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.throwUnlessAsync = function(actual) {
|
||||
const runable = runner.currentRunable();
|
||||
return throwUnlessAsyncFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||
@@ -2651,11 +2701,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
||||
} else if (options.stack) {
|
||||
error = options;
|
||||
} else {
|
||||
try {
|
||||
throw new Error(message());
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
error = new Error(message());
|
||||
}
|
||||
}
|
||||
// Omit the message from the stack trace because it will be
|
||||
@@ -3179,6 +3225,9 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) {
|
||||
return CompleteOnFirstErrorSkipPolicy;
|
||||
};
|
||||
|
||||
// Warning: don't add "use strict" to this file. Doing so potentially changes
|
||||
// the behavior of user code that does things like setTimeout("var x = 1;")
|
||||
// while the mock clock is installed.
|
||||
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
function DelayedFunctionScheduler() {
|
||||
this.scheduledLookup_ = [];
|
||||
@@ -3204,6 +3253,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
) {
|
||||
let f;
|
||||
if (typeof funcToCall === 'string') {
|
||||
// setTimeout("some code") and setInterval("some code") are legal, if
|
||||
// not recommended. We don't do that ourselves, but user code might.
|
||||
// This allows such code to work when the mock clock is installed.
|
||||
f = function() {
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(funcToCall);
|
||||
@@ -3531,7 +3583,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
lines.unshift(stackTrace.message);
|
||||
}
|
||||
|
||||
if (error.cause) {
|
||||
if (error.cause && error.cause instanceof Error) {
|
||||
const substack = this.stack_(error.cause, {
|
||||
messageHandling: 'require'
|
||||
});
|
||||
@@ -3566,7 +3618,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
const result = {};
|
||||
let empty = true;
|
||||
|
||||
for (const prop in error) {
|
||||
for (const prop of Object.keys(error)) {
|
||||
if (ignoredProperties.includes(prop)) {
|
||||
continue;
|
||||
}
|
||||
@@ -7110,6 +7162,8 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @class ParallelReportDispatcher
|
||||
* @implements Reporter
|
||||
@@ -7128,7 +7182,7 @@ getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||
const dispatcher = ReportDispatcher(
|
||||
const dispatcher = new ReportDispatcher(
|
||||
j$.reporterEvents,
|
||||
function(queueRunnerOptions) {
|
||||
queueRunnerOptions = {
|
||||
@@ -7854,6 +7908,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().ReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
function ReportDispatcher(methods, queueRunnerFactory, onLateError) {
|
||||
const dispatchedMethods = methods || [];
|
||||
|
||||
@@ -8232,6 +8288,54 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.expectAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an asynchronous expectation for a spec and throw an error if it fails.
|
||||
*
|
||||
* This is intended to allow Jasmine matchers to be used with tools like
|
||||
* testing-library's `waitFor`, which expect matcher failures to throw
|
||||
* exceptions and not trigger a spec failure if the exception is caught.
|
||||
* It can also be used to integration-test custom matchers.
|
||||
*
|
||||
* If the resulting expectation fails, a {@link ThrowUnlessFailure} will be
|
||||
* thrown. A failed expectation will not result in a spec failure unless the
|
||||
* exception propagates back to Jasmine, either via the call stack or via
|
||||
* the global unhandled exception/unhandled promise rejection events.
|
||||
* @name throwUnlessAsync
|
||||
* @since 5.1.0
|
||||
* @function
|
||||
* @param actual
|
||||
* @global
|
||||
* @param {Object} actual - Actual computed value to test expectations against.
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnlessAsync: function(actual) {
|
||||
return env.throwUnlessAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an expectation for a spec and throw an error if it fails.
|
||||
*
|
||||
* This is intended to allow Jasmine matchers to be used with tools like
|
||||
* testing-library's `waitFor`, which expect matcher failures to throw
|
||||
* exceptions and not trigger a spec failure if the exception is caught.
|
||||
* It can also be used to integration-test custom matchers.
|
||||
*
|
||||
* If the resulting expectation fails, a {@link ThrowUnlessFailure} will be
|
||||
* thrown. A failed expectation will not result in a spec failure unless the
|
||||
* exception propagates back to Jasmine, either via the call stack or via
|
||||
* the global unhandled exception/unhandled promise rejection events.
|
||||
* @name throwUnless
|
||||
* @since 5.1.0
|
||||
* @function
|
||||
* @param actual
|
||||
* @global
|
||||
* @param {Object} actual - Actual computed value to test expectations against.
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnless: function(actual) {
|
||||
return env.throwUnless(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark a spec as pending, expectation results will be ignored.
|
||||
* @name pending
|
||||
@@ -8382,7 +8486,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @param {Function} [originalFn] - The "real" function. This will
|
||||
* be used for subsequent calls to the spy after you call
|
||||
* `mySpy.and.callThrough()`. In most cases you should omit this parameter.
|
||||
* The usual way to supply an original function is to call {@link spyOn}
|
||||
* instead of createSpy.
|
||||
* @return {Spy}
|
||||
*/
|
||||
jasmine.createSpy = function(name, originalFn) {
|
||||
@@ -9755,14 +9863,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
this.result.properties[key] = value;
|
||||
};
|
||||
|
||||
Suite.prototype.expect = function(actual) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Suite.prototype.expectAsync = function(actual) {
|
||||
return this.asyncExpectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Suite.prototype.getFullName = function() {
|
||||
const fullName = [];
|
||||
for (
|
||||
@@ -10713,5 +10813,5 @@ getJasmineRequireObj().UserContext = function(j$) {
|
||||
};
|
||||
|
||||
getJasmineRequireObj().version = function() {
|
||||
return '5.0.0-beta.0';
|
||||
return '5.1.2';
|
||||
};
|
||||
|
||||
15
package.json
15
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "5.0.0-beta.0",
|
||||
"version": "5.1.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
@@ -27,7 +27,7 @@
|
||||
"homepage": "https://jasmine.github.io",
|
||||
"main": "./lib/jasmine-core.js",
|
||||
"files": [
|
||||
"MIT.LICENSE",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"images/*.{png,svg}",
|
||||
"lib/**/*.{js,css}",
|
||||
@@ -36,16 +36,16 @@
|
||||
"devDependencies": {
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-plugin-compat": "^4.0.0",
|
||||
"glob": "^9.3.1",
|
||||
"glob": "^10.2.3",
|
||||
"grunt": "^1.0.4",
|
||||
"grunt-cli": "^1.3.2",
|
||||
"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#5.0",
|
||||
"jasmine-browser-runner": "^1.0.0",
|
||||
"jsdom": "^21.1.1",
|
||||
"jasmine": "^5.0.0",
|
||||
"jasmine-browser-runner": "github:jasmine/jasmine-browser-runner",
|
||||
"jsdom": "^22.0.0",
|
||||
"load-grunt-tasks": "^5.1.0",
|
||||
"prettier": "1.17.1",
|
||||
"sass": "^1.58.3",
|
||||
@@ -97,7 +97,8 @@
|
||||
],
|
||||
"space-before-blocks": "error",
|
||||
"no-eval": "error",
|
||||
"no-var": "error"
|
||||
"no-var": "error",
|
||||
"no-debugger": "error"
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
|
||||
55
release_notes/5.0.0.md
Normal file
55
release_notes/5.0.0.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Jasmine Core 5.0.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a major release that includes breaking changes. It primarily adds
|
||||
support for parallel execution in Node via the `jasmine` package. Most users
|
||||
should be able to upgrade without changes, but please read the list of breaking
|
||||
changes below and see the [migration guide](https://jasmine.github.io/tutorials/upgrading_to_Jasmine_5.0)
|
||||
for more information.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
* Dropped support for Node 12, 14, and 16
|
||||
* Dropped support for Safari 14 and Firefox 91
|
||||
* Made Env#execute async and removed the callback parameter
|
||||
* Global errors are detected via addEventListener rather than setting window.onerror
|
||||
* The `boot` function exported by the core module returns the same object
|
||||
every time it's called.
|
||||
* Removed node_boot.js. Use the exported `boot` function instead.
|
||||
|
||||
## New features
|
||||
|
||||
* Support for parallel execution in Node via the `jasmine` package
|
||||
See the [parallel guide](https://jasmine.github.io/tutorials/running_specs_in_parallel)
|
||||
for more information.
|
||||
* Added Node 20 to supported environments
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Accessibility: Always provide a non-color indication that a spec is pending
|
||||
* Accessibility: Improved contrast of version number and inactive tab links
|
||||
* Uninstall the global error handler at the end of env execution
|
||||
|
||||
## Internal improvements
|
||||
|
||||
* Updated dev dependencies
|
||||
* Dogfood parallel execution feature in CI
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 113 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
25
release_notes/5.0.1.md
Normal file
25
release_notes/5.0.1.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Jasmine Core 5.0.1 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Optionally restore the pre-5.0 behavior of boot() always creating a new instance
|
||||
|
||||
This is needed by jasmine-npm (and likely other tools like it) that may
|
||||
need to create and use multiple envs in sequence.
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.0.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 114 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
39
release_notes/5.1.0.md
Normal file
39
release_notes/5.1.0.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Jasmine Core 5.1.0 Release Notes
|
||||
|
||||
## Changes
|
||||
|
||||
* Exclude inherited Error properties from stack trace
|
||||
|
||||
* Fixed error when formatting Error object with non-Error cause property
|
||||
|
||||
Merges [#2013](https://github.com/jasmine/jasmine/pull/2013) from @angrycat9000.
|
||||
|
||||
Fixes [#2011](https://github.com/jasmine/jasmine/issues/2011).
|
||||
|
||||
* Added `throwUnless` and `throwUnlessAsync`
|
||||
|
||||
These are similar to `expect` and `expectAsync` except that they throw
|
||||
exceptions rather than recording matcher failures as spec/suite failures.
|
||||
They're intended to support using Jasmine matchers in [testing-library's](https://testing-library.com/)
|
||||
`waitFor`, and also provide a way to integration-test custom matchers.
|
||||
|
||||
Fixes [#2003](https://github.com/jasmine/jasmine/issues/2003).
|
||||
|
||||
Fixes [#1980](https://github.com/jasmine/jasmine/issues/1980).
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.1.0 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 114 |
|
||||
| Firefox | 102, 113 |
|
||||
| Edge | 113 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
28
release_notes/5.1.1.md
Normal file
28
release_notes/5.1.1.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Jasmine Core 5.1.1 Release Notes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fixed global variable leak in the main process when running in parallel mode
|
||||
* Removed unnecessary throw when building expectation results
|
||||
|
||||
## Documentation Improvements
|
||||
|
||||
* Improved jsdocs for originalFn argument to createSpy
|
||||
* Link to 5.0 upgrade guide in README, not 4.0
|
||||
|
||||
## Supported environments
|
||||
|
||||
jasmine-core 5.1.1 has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-16 |
|
||||
| Chrome | 116 |
|
||||
| Firefox | 102, 116 |
|
||||
| Edge | 115 |
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
27
release_notes/5.1.2.md
Normal file
27
release_notes/5.1.2.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Jasmine Core 5.1.2 Release Notes
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fixed `throwUnlessAsync`
|
||||
* Fixes [#2026](https://github.com/jasmine/jasmine/issues/2026)
|
||||
|
||||
# Documentation improvements
|
||||
|
||||
* Added Safari 17 to supported browsers
|
||||
* Added Firefox 115 (current ESR) to supported browsers
|
||||
|
||||
## Supported environments
|
||||
|
||||
This version has been tested in the following environments.
|
||||
|
||||
| Environment | Supported versions |
|
||||
|-------------------|--------------------|
|
||||
| Node | 18, 20 |
|
||||
| Safari | 15-17 |
|
||||
| Chrome | 121 |
|
||||
| Firefox | 102, 115, 122 |
|
||||
| Edge | 121 |
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
@@ -3,6 +3,7 @@
|
||||
run_browser() {
|
||||
browser=$1
|
||||
version=$2
|
||||
os="$3"
|
||||
description="$browser $version"
|
||||
if [ $version = "latest" ]; then
|
||||
version=""
|
||||
@@ -12,7 +13,7 @@ run_browser() {
|
||||
echo
|
||||
echo "Running $description"
|
||||
echo
|
||||
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version npm run ci
|
||||
USE_SAUCE=true JASMINE_BROWSER=$browser SAUCE_BROWSER_VERSION=$version SAUCE_OS="$os" npm run ci
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "PASS: $description" >> "$passfile"
|
||||
@@ -23,9 +24,21 @@ run_browser() {
|
||||
|
||||
passfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
failfile=`mktemp -t jasmine-results.XXXXXX` || exit 1
|
||||
run_browser chrome latest
|
||||
|
||||
# As of 2023-09-30, Sauce Connect doesn't work with the latest Chrome version
|
||||
# on the default Linux. Run on Mac OS instead. The OS specification may need to
|
||||
# be updated or removed when new Chrome versions stop being available on Mac OS
|
||||
# 12, although historically this has taken several major OS versions.
|
||||
# See <https://saucelabs.com/products/supported-browsers-devices>.
|
||||
# On Saucelabs, the test suite frequently runs ~30s slower on Mac OS than it
|
||||
# does on Linux, so it's probably worth removing the OS specification once Sauce
|
||||
# Connect works with Chrome latest on Linux again.
|
||||
run_browser chrome latest "macOS 12"
|
||||
|
||||
run_browser firefox latest
|
||||
run_browser firefox 115
|
||||
run_browser firefox 102
|
||||
run_browser safari 17
|
||||
run_browser safari 16
|
||||
run_browser safari 15
|
||||
run_browser MicrosoftEdge latest
|
||||
|
||||
@@ -197,7 +197,7 @@ describe('ExceptionFormatter', function() {
|
||||
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
|
||||
});
|
||||
|
||||
it('includes error properties in stack', function() {
|
||||
it("includes the error's own properties in stack", function() {
|
||||
const error = new Error('an error');
|
||||
error.someProperty = 'hello there';
|
||||
|
||||
@@ -206,6 +206,19 @@ describe('ExceptionFormatter', function() {
|
||||
expect(result).toMatch(/error properties:.*someProperty.*hello there/);
|
||||
});
|
||||
|
||||
it('does not include inherited error properties', function() {
|
||||
function CustomError(msg) {
|
||||
Error.call(this, msg);
|
||||
}
|
||||
|
||||
CustomError.prototype = new Error();
|
||||
CustomError.prototype.anInheritedProp = 'something';
|
||||
const error = new CustomError('nope');
|
||||
|
||||
const result = new jasmineUnderTest.ExceptionFormatter().stack(error);
|
||||
expect(result).not.toContain('anInheritedProp');
|
||||
});
|
||||
|
||||
describe('When omitMessage is true', function() {
|
||||
it('filters the message from V8-style stack traces', function() {
|
||||
const error = {
|
||||
@@ -291,6 +304,26 @@ describe('ExceptionFormatter', function() {
|
||||
.withContext('first root cause stack frame')
|
||||
.toContain('ExceptionFormatterSpec.js');
|
||||
});
|
||||
|
||||
it('does not throw if cause is a non Error', function() {
|
||||
const formatter = new jasmineUnderTest.ExceptionFormatter();
|
||||
|
||||
expect(function() {
|
||||
formatter.stack(
|
||||
new Error('error', {
|
||||
cause: function() {}
|
||||
})
|
||||
);
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(function() {
|
||||
formatter.stack(
|
||||
new Error('error', {
|
||||
cause: 'another error'
|
||||
})
|
||||
);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ describe('Env integration', function() {
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.getEnv().registerIntegrationMatchers();
|
||||
specHelpers.registerIntegrationMatchers();
|
||||
env = new jasmineUnderTest.Env();
|
||||
});
|
||||
|
||||
@@ -4334,6 +4334,115 @@ describe('Env integration', function() {
|
||||
}
|
||||
});
|
||||
|
||||
describe('throwUnless', function() {
|
||||
it('throws when the matcher fails', async function() {
|
||||
let thrown;
|
||||
|
||||
env.it('a spec', function() {
|
||||
try {
|
||||
env.throwUnless(1).toEqual(2);
|
||||
} catch (e) {
|
||||
thrown = e;
|
||||
}
|
||||
});
|
||||
|
||||
await env.execute();
|
||||
expect(thrown).toBeInstanceOf(Error);
|
||||
expect(thrown.passed).toEqual(false);
|
||||
expect(thrown.matcherName).toEqual('toEqual');
|
||||
expect(thrown.message).toEqual('Expected 1 to equal 2.');
|
||||
expect(thrown.actual).toEqual(1);
|
||||
expect(thrown.expected).toEqual(2);
|
||||
});
|
||||
|
||||
it('does not throw when the matcher passes', async function() {
|
||||
let threw = false;
|
||||
|
||||
env.it('a spec', function() {
|
||||
try {
|
||||
env.throwUnless(1).toEqual(1);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
});
|
||||
|
||||
await env.execute();
|
||||
expect(threw).toBe(false);
|
||||
});
|
||||
|
||||
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
||||
env.it('a spec', function() {
|
||||
try {
|
||||
env.throwUnless(1).toEqual(2);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||
env.addReporter(reporter);
|
||||
|
||||
await env.execute();
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({ status: 'passed' })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('throwUnlessAsync', function() {
|
||||
it('throws when the matcher fails', async function() {
|
||||
const promise = Promise.resolve('a');
|
||||
let thrown;
|
||||
|
||||
env.it('a spec', async function() {
|
||||
try {
|
||||
await env.throwUnlessAsync(promise).toBeResolvedTo('b');
|
||||
} catch (e) {
|
||||
thrown = e;
|
||||
}
|
||||
});
|
||||
|
||||
await env.execute();
|
||||
expect(thrown).toBeInstanceOf(Error);
|
||||
expect(thrown.passed).toEqual(false);
|
||||
expect(thrown.matcherName).toEqual('toBeResolvedTo');
|
||||
expect(thrown.message).toEqual(
|
||||
"Expected a promise to be resolved to 'b' but it was resolved to 'a'."
|
||||
);
|
||||
expect(thrown.actual).toBe(promise);
|
||||
expect(thrown.expected).toEqual('b');
|
||||
});
|
||||
|
||||
it('does not throw when the matcher passes', async function() {
|
||||
let threw = false;
|
||||
|
||||
env.it('a spec', async function() {
|
||||
try {
|
||||
await env.throwUnlessAsync(Promise.resolve()).toBeResolved();
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
});
|
||||
|
||||
await env.execute();
|
||||
expect(threw).toBe(false);
|
||||
});
|
||||
|
||||
it('does not cause a failure if the error does not propagate back to jasmine', async function() {
|
||||
env.it('a spec', async function() {
|
||||
try {
|
||||
await env.throwUnlessAsync(Promise.resolve()).toBeRejected();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||
env.addReporter(reporter);
|
||||
|
||||
await env.execute();
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({ status: 'passed' })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function browserEventMethods() {
|
||||
return {
|
||||
listeners_: { error: [], unhandledrejection: [] },
|
||||
|
||||
@@ -610,19 +610,13 @@ describe('Matchers (Integration)', function() {
|
||||
});
|
||||
|
||||
describe('toHaveClass', function() {
|
||||
beforeEach(function() {
|
||||
this.domHelpers = jasmine.getEnv().domHelpers();
|
||||
});
|
||||
|
||||
verifyPasses(function(env) {
|
||||
const domHelpers = jasmine.getEnv().domHelpers();
|
||||
const el = domHelpers.createElementWithClassName('foo');
|
||||
const el = specHelpers.domHelpers.createElementWithClassName('foo');
|
||||
env.expect(el).toHaveClass('foo');
|
||||
});
|
||||
|
||||
verifyFails(function(env) {
|
||||
const domHelpers = jasmine.getEnv().domHelpers();
|
||||
const el = domHelpers.createElementWithClassName('foo');
|
||||
const el = specHelpers.domHelpers.createElementWithClassName('foo');
|
||||
env.expect(el).toHaveClass('bar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ describe('spec running', function() {
|
||||
let env;
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.getEnv().registerIntegrationMatchers();
|
||||
specHelpers.registerIntegrationMatchers();
|
||||
env = new jasmineUnderTest.Env();
|
||||
env.configure({ random: false });
|
||||
});
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
describe('toHaveClass', function() {
|
||||
beforeEach(function() {
|
||||
this.domHelpers = jasmine.getEnv().domHelpers();
|
||||
});
|
||||
|
||||
it('fails for a DOM element that lacks the expected class', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
result = matcher.compare(
|
||||
this.domHelpers.createElementWithClassName(''),
|
||||
specHelpers.domHelpers.createElementWithClassName(''),
|
||||
'foo'
|
||||
);
|
||||
|
||||
@@ -15,7 +11,7 @@ describe('toHaveClass', function() {
|
||||
|
||||
it('passes for a DOM element that has the expected class', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
el = this.domHelpers.createElementWithClassName('foo bar baz');
|
||||
el = specHelpers.domHelpers.createElementWithClassName('foo bar baz');
|
||||
|
||||
expect(matcher.compare(el, 'foo').pass).toBe(true);
|
||||
expect(matcher.compare(el, 'bar').pass).toBe(true);
|
||||
@@ -24,7 +20,7 @@ describe('toHaveClass', function() {
|
||||
|
||||
it('fails for a DOM element that only has other classes', function() {
|
||||
const matcher = jasmineUnderTest.matchers.toHaveClass(),
|
||||
el = this.domHelpers.createElementWithClassName('foo bar');
|
||||
el = specHelpers.domHelpers.createElementWithClassName('foo bar');
|
||||
|
||||
expect(matcher.compare(el, 'fo').pass).toBe(false);
|
||||
});
|
||||
@@ -42,7 +38,7 @@ describe('toHaveClass', function() {
|
||||
matcher.compare(undefined, 'foo');
|
||||
}).toThrowError('undefined is not a DOM element');
|
||||
|
||||
const textNode = this.domHelpers.document.createTextNode('');
|
||||
const textNode = specHelpers.domHelpers.document.createTextNode('');
|
||||
expect(function() {
|
||||
matcher.compare(textNode, 'foo');
|
||||
}).toThrowError('HTMLNode is not a DOM element');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function(env) {
|
||||
(function() {
|
||||
function browserVersion(matchFn) {
|
||||
const userAgent = jasmine.getGlobal().navigator.userAgent;
|
||||
if (!userAgent) {
|
||||
@@ -10,7 +10,7 @@
|
||||
return match ? parseFloat(match[1]) : void 0;
|
||||
}
|
||||
|
||||
env.firefoxVersion = browserVersion(function(userAgent) {
|
||||
specHelpers.firefoxVersion = browserVersion(function(userAgent) {
|
||||
return /Firefox\/([0-9]{0,})/.exec(userAgent);
|
||||
});
|
||||
})(jasmine.getEnv());
|
||||
})();
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
(function(env) {
|
||||
function domHelpers() {
|
||||
let doc;
|
||||
(function() {
|
||||
let doc;
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
doc = document;
|
||||
} else {
|
||||
const JSDOM = require('jsdom').JSDOM;
|
||||
const dom = new JSDOM();
|
||||
doc = dom.window.document;
|
||||
}
|
||||
|
||||
return {
|
||||
document: doc,
|
||||
createElementWithClassName: function(className) {
|
||||
const el = this.document.createElement('div');
|
||||
el.className = className;
|
||||
return el;
|
||||
}
|
||||
};
|
||||
if (typeof document !== 'undefined') {
|
||||
doc = document;
|
||||
} else {
|
||||
const JSDOM = require('jsdom').JSDOM;
|
||||
const dom = new JSDOM();
|
||||
doc = dom.window.document;
|
||||
}
|
||||
|
||||
env.domHelpers = domHelpers;
|
||||
})(jasmine.getEnv());
|
||||
specHelpers.domHelpers = {
|
||||
document: doc,
|
||||
createElementWithClassName(className) {
|
||||
const el = this.document.createElement('div');
|
||||
el.className = className;
|
||||
return el;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
1
spec/helpers/init.js
Normal file
1
spec/helpers/init.js
Normal file
@@ -0,0 +1 @@
|
||||
globalThis.specHelpers = {};
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(env) {
|
||||
env.registerIntegrationMatchers = function() {
|
||||
(function() {
|
||||
specHelpers.registerIntegrationMatchers = function() {
|
||||
jasmine.addMatchers({
|
||||
toHaveFailedExpectationsForRunnable: function() {
|
||||
return {
|
||||
@@ -51,4 +51,4 @@
|
||||
}
|
||||
});
|
||||
};
|
||||
})(jasmine.getEnv());
|
||||
})();
|
||||
|
||||
@@ -1411,6 +1411,23 @@ describe('HtmlReporter', function() {
|
||||
describe('and there are pending specs', function() {
|
||||
let container, reporter;
|
||||
|
||||
function pendingSpecStatus() {
|
||||
return {
|
||||
id: 123,
|
||||
description: 'with a spec',
|
||||
fullName: 'A Suite with a spec',
|
||||
status: 'pending',
|
||||
passedExpectations: [],
|
||||
failedExpectations: []
|
||||
};
|
||||
}
|
||||
|
||||
function reportWithSpecStatus(specStatus) {
|
||||
reporter.specStarted(specStatus);
|
||||
reporter.specDone(specStatus);
|
||||
reporter.jasmineDone({});
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
container = document.createElement('div');
|
||||
const getContainer = function() {
|
||||
@@ -1429,21 +1446,10 @@ describe('HtmlReporter', function() {
|
||||
reporter.initialize();
|
||||
|
||||
reporter.jasmineStarted({ totalSpecsDefined: 1 });
|
||||
const specStatus = {
|
||||
id: 123,
|
||||
description: 'with a spec',
|
||||
fullName: 'A Suite with a spec',
|
||||
status: 'pending',
|
||||
passedExpectations: [],
|
||||
failedExpectations: [],
|
||||
pendingReason: 'my custom pending reason'
|
||||
};
|
||||
reporter.specStarted(specStatus);
|
||||
reporter.specDone(specStatus);
|
||||
reporter.jasmineDone({});
|
||||
});
|
||||
|
||||
it('reports the pending specs count', function() {
|
||||
reportWithSpecStatus(pendingSpecStatus());
|
||||
const alertBar = container.querySelector('.jasmine-alert .jasmine-bar');
|
||||
|
||||
expect(alertBar.innerHTML).toMatch(
|
||||
@@ -1452,17 +1458,36 @@ describe('HtmlReporter', function() {
|
||||
});
|
||||
|
||||
it('reports no failure details', function() {
|
||||
reportWithSpecStatus(pendingSpecStatus());
|
||||
const specFailure = container.querySelector('.jasmine-failures');
|
||||
|
||||
expect(specFailure.childNodes.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('displays the custom pending reason', function() {
|
||||
reportWithSpecStatus({
|
||||
...pendingSpecStatus(),
|
||||
pendingReason: 'my custom pending reason'
|
||||
});
|
||||
const pendingDetails = container.querySelector(
|
||||
'.jasmine-summary .jasmine-pending'
|
||||
);
|
||||
|
||||
expect(pendingDetails.innerHTML).toContain('my custom pending reason');
|
||||
expect(pendingDetails.innerHTML).toContain(
|
||||
'PENDING WITH MESSAGE: my custom pending reason'
|
||||
);
|
||||
});
|
||||
|
||||
it('indicates that the spec is pending even if there is no reason', function() {
|
||||
reportWithSpecStatus({
|
||||
...pendingSpecStatus(),
|
||||
pendingReason: ''
|
||||
});
|
||||
const pendingDetails = container.querySelector(
|
||||
'.jasmine-summary .jasmine-pending'
|
||||
);
|
||||
|
||||
expect(pendingDetails.innerHTML).toContain('PENDING');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('PrettyPrinter (HTML Dependent)', function() {
|
||||
});
|
||||
|
||||
it("should print Firefox's wrapped native objects correctly", function() {
|
||||
if (jasmine.getEnv().firefoxVersion) {
|
||||
if (specHelpers.firefoxVersion) {
|
||||
const pp = jasmineUnderTest.makePrettyPrinter();
|
||||
let err;
|
||||
try {
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('npm package', function() {
|
||||
const files = fs.readdirSync(path.resolve(this.tmpDir, 'package'));
|
||||
files.sort();
|
||||
expect(files).toEqual([
|
||||
'MIT.LICENSE',
|
||||
'LICENSE',
|
||||
'README.md',
|
||||
'images',
|
||||
'lib',
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
specDir: 'spec',
|
||||
specFiles: ['**/*[Ss]pec.js', '!npmPackage/**/*'],
|
||||
helpers: [
|
||||
'helpers/init.js',
|
||||
'helpers/generator.js',
|
||||
'helpers/BrowserFlags.js',
|
||||
'helpers/domHelpers.js',
|
||||
@@ -28,16 +29,19 @@ module.exports = {
|
||||
random: true,
|
||||
browser: {
|
||||
name: process.env.JASMINE_BROWSER || 'firefox',
|
||||
useSauce: process.env.USE_SAUCE === 'true',
|
||||
sauce: {
|
||||
name: `jasmine-core ${new Date().toISOString()}`,
|
||||
os: process.env.SAUCE_OS,
|
||||
useRemoteSeleniumGrid: process.env.USE_SAUCE === 'true',
|
||||
remoteSeleniumGrid: {
|
||||
url: 'https://ondemand.saucelabs.com/wd/hub',
|
||||
browserVersion: process.env.SAUCE_BROWSER_VERSION,
|
||||
build: `Core ${process.env.TRAVIS_BUILD_NUMBER || 'Ran locally'}`,
|
||||
tags: ['Jasmine-Core'],
|
||||
tunnelIdentifier: process.env.SAUCE_TUNNEL_IDENTIFIER,
|
||||
username: process.env.SAUCE_USERNAME,
|
||||
accessKey: process.env.SAUCE_ACCESS_KEY
|
||||
platformName: process.env.SAUCE_OS,
|
||||
'sauce:options': {
|
||||
name: `jasmine-core ${new Date().toISOString()}`,
|
||||
build: `Core ${process.env.CIRCLE_BUILD_NUM || 'Ran locally'}`,
|
||||
tags: ['Jasmine-Core'],
|
||||
tunnelIdentifier: process.env.SAUCE_TUNNEL_IDENTIFIER,
|
||||
username: process.env.SAUCE_USERNAME,
|
||||
accessKey: process.env.SAUCE_ACCESS_KEY
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"npmPackage/**/*[Ss]pec.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/init.js",
|
||||
"helpers/domHelpers.js",
|
||||
"helpers/integrationMatchers.js",
|
||||
"helpers/overrideConsoleLogForCircleCi.js",
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Warning: don't add "use strict" to this file. Doing so potentially changes
|
||||
// the behavior of user code that does things like setTimeout("var x = 1;")
|
||||
// while the mock clock is installed.
|
||||
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
function DelayedFunctionScheduler() {
|
||||
this.scheduledLookup_ = [];
|
||||
@@ -23,6 +26,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
|
||||
) {
|
||||
let f;
|
||||
if (typeof funcToCall === 'string') {
|
||||
// setTimeout("some code") and setInterval("some code") are legal, if
|
||||
// not recommended. We don't do that ourselves, but user code might.
|
||||
// This allows such code to work when the mock clock is installed.
|
||||
f = function() {
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(funcToCall);
|
||||
|
||||
@@ -264,6 +264,49 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleThrowUnlessFailure = function(passed, result) {
|
||||
if (!passed) {
|
||||
/**
|
||||
* @interface
|
||||
* @name ThrowUnlessFailure
|
||||
* @extends Error
|
||||
* @description Represents a failure of an expectation evaluated with
|
||||
* {@link throwUnless}. Properties of this error are a subset of the
|
||||
* properties of {@link Expectation} and have the same values.
|
||||
* @property {String} matcherName - The name of the matcher that was executed for this expectation.
|
||||
* @property {String} message - The failure message for the expectation.
|
||||
* @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.
|
||||
*/
|
||||
const error = new Error(result.message);
|
||||
error.passed = result.passed;
|
||||
error.message = result.message;
|
||||
error.expected = result.expected;
|
||||
error.actual = result.actual;
|
||||
error.matcherName = result.matcherName;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const throwUnlessFactory = function(actual, spec) {
|
||||
return j$.Expectation.factory({
|
||||
matchersUtil: runableResources.makeMatchersUtil(),
|
||||
customMatchers: runableResources.customMatchers(),
|
||||
actual: actual,
|
||||
addExpectationResult: handleThrowUnlessFailure
|
||||
});
|
||||
};
|
||||
|
||||
const throwUnlessAsyncFactory = function(actual, spec) {
|
||||
return j$.Expectation.asyncFactory({
|
||||
matchersUtil: runableResources.makeMatchersUtil(),
|
||||
customAsyncMatchers: runableResources.customAsyncMatchers(),
|
||||
actual: actual,
|
||||
addExpectationResult: handleThrowUnlessFailure
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: Unify recordLateError with recordLateExpectation? The extra
|
||||
// diagnostic info added by the latter is probably useful in most cases.
|
||||
function recordLateError(error) {
|
||||
@@ -767,23 +810,37 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.expect = function(actual) {
|
||||
if (!runner.currentRunable()) {
|
||||
const runable = runner.currentRunable();
|
||||
|
||||
if (!runable) {
|
||||
throw new Error(
|
||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||
);
|
||||
}
|
||||
|
||||
return runner.currentRunable().expect(actual);
|
||||
return runable.expectationFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.expectAsync = function(actual) {
|
||||
if (!runner.currentRunable()) {
|
||||
const runable = runner.currentRunable();
|
||||
|
||||
if (!runable) {
|
||||
throw new Error(
|
||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||
);
|
||||
}
|
||||
|
||||
return runner.currentRunable().expectAsync(actual);
|
||||
return runable.asyncExpectationFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.throwUnless = function(actual) {
|
||||
const runable = runner.currentRunable();
|
||||
return throwUnlessFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.throwUnlessAsync = function(actual) {
|
||||
const runable = runner.currentRunable();
|
||||
return throwUnlessAsyncFactory(actual, runable);
|
||||
};
|
||||
|
||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||
|
||||
@@ -67,7 +67,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
lines.unshift(stackTrace.message);
|
||||
}
|
||||
|
||||
if (error.cause) {
|
||||
if (error.cause && error.cause instanceof Error) {
|
||||
const substack = this.stack_(error.cause, {
|
||||
messageHandling: 'require'
|
||||
});
|
||||
@@ -102,7 +102,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
|
||||
const result = {};
|
||||
let empty = true;
|
||||
|
||||
for (const prop in error) {
|
||||
for (const prop of Object.keys(error)) {
|
||||
if (ignoredProperties.includes(prop)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @class ParallelReportDispatcher
|
||||
* @implements Reporter
|
||||
@@ -17,7 +19,7 @@ getJasmineRequireObj().ParallelReportDispatcher = function(j$) {
|
||||
const ReportDispatcher = deps.ReportDispatcher || j$.ReportDispatcher;
|
||||
const QueueRunner = deps.QueueRunner || j$.QueueRunner;
|
||||
const globalErrors = deps.globalErrors || new j$.GlobalErrors();
|
||||
const dispatcher = ReportDispatcher(
|
||||
const dispatcher = new ReportDispatcher(
|
||||
j$.reporterEvents,
|
||||
function(queueRunnerOptions) {
|
||||
queueRunnerOptions = {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
getJasmineRequireObj().ReportDispatcher = function(j$) {
|
||||
'use strict';
|
||||
|
||||
function ReportDispatcher(methods, queueRunnerFactory, onLateError) {
|
||||
const dispatchedMethods = methods || [];
|
||||
|
||||
|
||||
@@ -70,14 +70,6 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
this.result.properties[key] = value;
|
||||
};
|
||||
|
||||
Spec.prototype.expect = function(actual) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.expectAsync = function(actual) {
|
||||
return this.asyncExpectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.execute = function(
|
||||
queueRunnerFactory,
|
||||
onComplete,
|
||||
|
||||
@@ -28,14 +28,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
this.result.properties[key] = value;
|
||||
};
|
||||
|
||||
Suite.prototype.expect = function(actual) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Suite.prototype.expectAsync = function(actual) {
|
||||
return this.asyncExpectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Suite.prototype.getFullName = function() {
|
||||
const fullName = [];
|
||||
for (
|
||||
|
||||
@@ -69,11 +69,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
|
||||
} else if (options.stack) {
|
||||
error = options;
|
||||
} else {
|
||||
try {
|
||||
throw new Error(message());
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
error = new Error(message());
|
||||
}
|
||||
}
|
||||
// Omit the message from the stack trace because it will be
|
||||
|
||||
@@ -225,6 +225,54 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
return env.expectAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an asynchronous expectation for a spec and throw an error if it fails.
|
||||
*
|
||||
* This is intended to allow Jasmine matchers to be used with tools like
|
||||
* testing-library's `waitFor`, which expect matcher failures to throw
|
||||
* exceptions and not trigger a spec failure if the exception is caught.
|
||||
* It can also be used to integration-test custom matchers.
|
||||
*
|
||||
* If the resulting expectation fails, a {@link ThrowUnlessFailure} will be
|
||||
* thrown. A failed expectation will not result in a spec failure unless the
|
||||
* exception propagates back to Jasmine, either via the call stack or via
|
||||
* the global unhandled exception/unhandled promise rejection events.
|
||||
* @name throwUnlessAsync
|
||||
* @since 5.1.0
|
||||
* @function
|
||||
* @param actual
|
||||
* @global
|
||||
* @param {Object} actual - Actual computed value to test expectations against.
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnlessAsync: function(actual) {
|
||||
return env.throwUnlessAsync(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an expectation for a spec and throw an error if it fails.
|
||||
*
|
||||
* This is intended to allow Jasmine matchers to be used with tools like
|
||||
* testing-library's `waitFor`, which expect matcher failures to throw
|
||||
* exceptions and not trigger a spec failure if the exception is caught.
|
||||
* It can also be used to integration-test custom matchers.
|
||||
*
|
||||
* If the resulting expectation fails, a {@link ThrowUnlessFailure} will be
|
||||
* thrown. A failed expectation will not result in a spec failure unless the
|
||||
* exception propagates back to Jasmine, either via the call stack or via
|
||||
* the global unhandled exception/unhandled promise rejection events.
|
||||
* @name throwUnless
|
||||
* @since 5.1.0
|
||||
* @function
|
||||
* @param actual
|
||||
* @global
|
||||
* @param {Object} actual - Actual computed value to test expectations against.
|
||||
* @return {matchers}
|
||||
*/
|
||||
throwUnless: function(actual) {
|
||||
return env.throwUnless(actual);
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark a spec as pending, expectation results will be ignored.
|
||||
* @name pending
|
||||
@@ -375,7 +423,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
||||
* @since 1.3.0
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @param {Function} [originalFn] - The "real" function. This will
|
||||
* be used for subsequent calls to the spy after you call
|
||||
* `mySpy.and.callThrough()`. In most cases you should omit this parameter.
|
||||
* The usual way to supply an original function is to call {@link spyOn}
|
||||
* instead of createSpy.
|
||||
* @return {Spy}
|
||||
*/
|
||||
jasmine.createSpy = function(name, originalFn) {
|
||||
|
||||
@@ -498,14 +498,13 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
if (noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
if (
|
||||
resultNode.result.status === 'pending' &&
|
||||
resultNode.result.pendingReason !== ''
|
||||
) {
|
||||
specDescription =
|
||||
specDescription +
|
||||
' PENDING WITH MESSAGE: ' +
|
||||
resultNode.result.pendingReason;
|
||||
if (resultNode.result.status === 'pending') {
|
||||
if (resultNode.result.pendingReason !== '') {
|
||||
specDescription +=
|
||||
' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
|
||||
} else {
|
||||
specDescription += ' PENDING';
|
||||
}
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom(
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
$line-height: 14px;
|
||||
$margin-unit: 14px;
|
||||
|
||||
$faint-text-color: #aaa;
|
||||
$light-text-color: #666;
|
||||
$text-color: #333;
|
||||
$inactive-tab-text-color: blue;
|
||||
$active-tab-text-color: #000;
|
||||
|
||||
$page-background-color: #eee;
|
||||
$menu-background-color: #aaa;
|
||||
|
||||
$passing-color: #007069;
|
||||
$failing-color: #ca3a11;
|
||||
@@ -91,10 +93,6 @@ body {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.jasmine-version {
|
||||
color: $faint-text-color;
|
||||
}
|
||||
|
||||
//--- Banner ---//
|
||||
|
||||
.jasmine-banner {
|
||||
@@ -238,10 +236,11 @@ body {
|
||||
|
||||
&.jasmine-menu {
|
||||
background-color: #fff;
|
||||
color: $faint-text-color;
|
||||
color: $active-tab-text-color;
|
||||
|
||||
a {
|
||||
color: $text-color;
|
||||
color: $inactive-tab-text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user