Compare commits

...

38 Commits

Author SHA1 Message Date
Gregg Van Hove
12f56fdb7d bump version to 3.2.1 2018-08-14 17:19:23 -07:00
Gregg Van Hove
afa18e554c Correctly expost spyOnAllFunctions
- See #1581
2018-08-14 17:11:50 -07:00
Gregg Van Hove
7205d07c67 Merge pull request #1588 from fossabot/master
Add license scan report and status
2018-08-08 19:04:21 -07:00
Gregg Van Hove
83ba2eb4d6 Link to the correct repo in release notes 2018-08-08 17:41:24 -07:00
Gregg Van Hove
87865f00a3 Add issue links to release notes 2018-08-08 17:39:10 -07:00
Gregg Van Hove
112672c4a9 bump version to 3.2.0 2018-08-08 17:33:50 -07:00
fossabot
f05ab79731 Add license scan report and status
Signed-off-by: fossabot <badges@fossa.io>
2018-08-07 17:47:31 -07:00
Gregg Van Hove
3a52c444f8 Merge branch 'aeisenberg-spy-all'
- Merges #1581 from @aeisenberg
- Fixes #1421
2018-07-24 17:55:44 -07:00
Andrew Eisenberg
f62eb3b1a8 Add spyOnAllFunctions function
This function will spy on all writable and configurable functionss of
an object that is passed in. It can be used like this:

    spyOnAllFunctions(obj);

This commit addresses https://github.com/jasmine/jasmine/issues/1421
2018-07-20 07:58:17 -07:00
Gregg Van Hove
110c092c9e Fix regular expressions for different browsers 2018-06-18 17:55:24 -07:00
Gregg Van Hove
8bb0e2d494 Merge branch 'ikonst-set-timeout-error-message'
- Merges #1567 from @ikonst
2018-06-18 17:37:39 -07:00
Ilya Konstantinov
8c1b80daae Improve Jasmine timeout error message 2018-06-18 17:36:43 -07:00
Gregg Van Hove
e2895a92dc Fix JSDoc naming for Env functions
- See #1565
2018-06-06 17:13:52 -07:00
Gregg Van Hove
03998c1b20 Add documentation for more public functions on Env
- Fixes #1565
2018-06-05 17:13:58 -07:00
Steve Gravrock
9472df0db4 Added a basic set of async matchers
- Fixes #1447
- Fixes #1547
2018-06-04 21:07:44 -07:00
Gregg Van Hove
8f7327cb4d Properly cascade StopExecutionError's up the tree
- Fixes #1563
2018-05-30 17:32:14 -07:00
Gregg Van Hove
3636014917 Merge branch 'hide-grey-specs' of https://github.com/SamFare/jasmine into SamFare-hide-grey-specs
- Merges #1561 from @SamFare
2018-05-23 17:15:40 -07:00
SamFare
92d33c79c7 Implemented hiding of disabled specs 2018-05-22 13:30:33 +01:00
Steve Gravrock
e2d9eefccd Line-break long expectation failure messages
This makes failures somewhat easier to read. We still preserve whitespace
within lines to make whitespace-only failures readable, e.g.
expect('foo  bar').toEqual('foo bar'). See #296.
2018-05-12 09:42:38 -07:00
Gregg Van Hove
ced2b114e4 Better detection of DOM Nodes for equality
- Also use JSDom if a real one isn't present to get some more coverage
  there

- Fixes #1172
2018-05-04 18:01:08 -07:00
Gregg Van Hove
f7097281c9 IE doesn't support .name on a function 2018-05-03 17:34:15 -07:00
Gregg Van Hove
01a1113387 Merge branch 'yinm-fix-typo'
- Merges #1555 from @yinm
2018-05-03 17:21:18 -07:00
yinm
4d0b47ac4c Fix typo from incimplete to incomplete 2018-05-03 17:46:49 +09:00
Gregg Van Hove
d6cfc4a9b5 Merge branch 'riophae-master'
- Merges #1551 from @riophae
2018-05-02 17:52:03 -07:00
Fangzhou Li
fbcdbf5ab1 Allow omitting the name argument: createSpy(func) 2018-04-29 06:07:22 +08:00
Gregg Van Hove
7e14a97371 Explicitly pass in timing functions in mock clock integration specs
- This way we can make sure that clear stack always works no matter
  how long the suite in the spec is

[fixes #153518103]
2018-04-23 17:25:11 -07:00
Gregg Van Hove
c440d13754 Use the same global for everything in Env
- No longer use `getGlobal` for clearStack and QueueRunner
2018-04-13 17:14:48 -07:00
Gregg Van Hove
8e8f09b41f Force reinstall bundler and include firefox again 2018-04-03 17:33:20 -07:00
Gregg Van Hove
1decb14807 Ensure rubygems is up-to-date on travis
- See travis-ci/travis-ci#8969
2018-04-03 17:13:27 -07:00
Gregg Van Hove
a978f50f1d name new global status stuff correctly in API docs 2018-04-02 17:20:39 -07:00
Steve Gravrock
74287c578c Check for accidental global variable creation 2018-03-25 12:01:50 -07:00
Steve Gravrock
7f1cdc2d02 Fixed global variable leak
- Fixes #1534
2018-03-25 12:00:56 -07:00
Steve Gravrock
847a959b13 Merge branch 'handle-rejection' of https://github.com/johnjbarton/jasmine
- Merges #1521 from @johnjbarton
2018-03-24 19:49:58 -07:00
Steve Gravrock
05015a8b3e Correctly format stack traces for errors with multiline messages
- Fixes #1526
2018-03-10 12:03:08 -08:00
Steve Gravrock
6f960d8662 Merge branch 'better-array-errors' of https://github.com/majidmade/jasmine
- Merges #1527 from @majidmade
- Fixes #1485
2018-03-10 07:42:34 -08:00
Majid Razvi
11b8b59e03 Change message for extra elements at end of actual array. #1485 2018-03-10 00:05:07 -07:00
johnjbarton
f1ebe05f1d Report unhandled rejections as globalErrors.
Extend existing support for uncaughtExceptions to unhandledRejections now that many tests are async.
2018-03-01 16:47:50 -08:00
Gregg Van Hove
85b2a8c6c4 add some links to more tutorials from the api docs 2018-03-01 10:48:18 -08:00
52 changed files with 1998 additions and 246 deletions

View File

@@ -1,9 +1,17 @@
{ {
"bitwise": true, "bitwise": true,
"curly": true, "curly": true,
"globals": {
"clearTimeout": false,
"console": false,
"getJasmineRequireObj": true,
"jasmineRequire": true,
"setTimeout": false
},
"immed": true, "immed": true,
"newcap": true, "newcap": true,
"trailing": true, "trailing": true,
"loopfunc": true, "loopfunc": true,
"quotmark": "single" "quotmark": "single",
} "undef": true
}

View File

@@ -4,6 +4,9 @@ sudo: false
rvm: 2.5 rvm: 2.5
before_install:
- gem update --system
- gem install bundler
script: $TEST_COMMAND script: $TEST_COMMAND
env: env:
@@ -11,9 +14,6 @@ env:
- USE_SAUCE=true - USE_SAUCE=true
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
- TEST_COMMAND="bash travis-core-script.sh" - TEST_COMMAND="bash travis-core-script.sh"
- JASMINE_BROWSER="firefox"
- SAUCE_OS="Linux"
- SAUCE_BROWSER_VERSION=''
- secure: WSPWhlnC4mWSnSPquX+m1/BCu5ch5NygkaHuM2Nea7lD8oS3XLX8QncZZAsQ4lnNfqoDDuBOizG0AESiqNvE4y6x5qvLLTS6q+ce255ZEMZ71TBdZgDEEvGMEjOPPsVXiXyTQOP1lwOPlrbZvaPgWV7e11KIBab6DfFcQpnvDgo= - secure: WSPWhlnC4mWSnSPquX+m1/BCu5ch5NygkaHuM2Nea7lD8oS3XLX8QncZZAsQ4lnNfqoDDuBOizG0AESiqNvE4y6x5qvLLTS6q+ce255ZEMZ71TBdZgDEEvGMEjOPPsVXiXyTQOP1lwOPlrbZvaPgWV7e11KIBab6DfFcQpnvDgo=
- secure: SW7CJhZnwaNT749Gdnhvqb5rbXlAOsygUAzh9qhtyvbqXKkmJdBIEsO01YF6pbju1X2twE9JvWCOxeZju43NgQChJlPsGbjY2j3k/TdQeTAJesQe2K7ytwghunI30gjEovtRH0T3w1EmcKPH8yj5eBIcB2OYoJHx8KEC7e68q1g= - secure: SW7CJhZnwaNT749Gdnhvqb5rbXlAOsygUAzh9qhtyvbqXKkmJdBIEsO01YF6pbju1X2twE9JvWCOxeZju43NgQChJlPsGbjY2j3k/TdQeTAJesQe2K7ytwghunI30gjEovtRH0T3w1EmcKPH8yj5eBIcB2OYoJHx8KEC7e68q1g=
@@ -31,6 +31,10 @@ matrix:
- env: - env:
- USE_SAUCE=false - USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh v9" - TEST_COMMAND="bash travis-node-script.sh v9"
- env:
- JASMINE_BROWSER="firefox"
- SAUCE_OS="Linux"
- SAUCE_BROWSER_VERSION=''
- env: - env:
- JASMINE_BROWSER="safari" - JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.12" - SAUCE_OS="OS X 10.12"

View File

@@ -2,6 +2,7 @@
[![Build Status](https://travis-ci.org/jasmine/jasmine.svg?branch=master)](https://travis-ci.org/jasmine/jasmine) [![Build Status](https://travis-ci.org/jasmine/jasmine.svg?branch=master)](https://travis-ci.org/jasmine/jasmine)
[![Open Source Helpers](https://www.codetriage.com/jasmine/jasmine/badges/users.svg)](https://www.codetriage.com/jasmine/jasmine) [![Open Source Helpers](https://www.codetriage.com/jasmine/jasmine/badges/users.svg)](https://www.codetriage.com/jasmine/jasmine)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_shield)
# A JavaScript Testing Framework # A JavaScript Testing Framework
@@ -75,3 +76,7 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, PhantomJS, M
* Sheel Choksi * Sheel Choksi
Copyright (c) 2008-2018 Pivotal Labs. This software is licensed under the MIT License. Copyright (c) 2008-2018 Pivotal Labs. This software is licensed under the MIT License.
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjasmine%2Fjasmine?ref=badge_large)

View File

@@ -78,6 +78,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var throwingExpectationFailures = queryString.getParam("throwFailures"); var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures); env.throwOnExpectationFailure(throwingExpectationFailures);
var hideDisabled = queryString.getParam("hideDisabled");
env.hideDisabled(hideDisabled);
var random = queryString.getParam("random"); var random = queryString.getParam("random");

View File

@@ -56,6 +56,9 @@
var throwingExpectationFailures = queryString.getParam("throwFailures"); var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures); env.throwOnExpectationFailure(throwingExpectationFailures);
var hideDisabled = queryString.getParam("hideDisabled");
env.hideDisabled(hideDisabled);
var random = queryString.getParam("random"); var random = queryString.getParam("random");

View File

@@ -148,7 +148,7 @@ jasmineRequire.HtmlReporter = function(j$) {
} }
symbols.appendChild(createDom('li', { symbols.appendChild(createDom('li', {
className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status, className: this.displaySpecInCorrectFormat(result),
id: 'spec_' + result.id, id: 'spec_' + result.id,
title: result.fullName title: result.fullName
} }
@@ -161,10 +161,22 @@ jasmineRequire.HtmlReporter = function(j$) {
addDeprecationWarnings(result); addDeprecationWarnings(result);
}; };
this.displaySpecInCorrectFormat = function(result) {
return noExpectations(result) ? 'jasmine-empty' : this.resultStatus(result.status);
};
this.resultStatus = function(status) {
if(status === 'excluded') {
return env.hidingDisabled() ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
}
return 'jasmine-' + status;
};
this.jasmineDone = function(doneResult) { this.jasmineDone = function(doneResult) {
var banner = find('.jasmine-banner'); var banner = find('.jasmine-banner');
var alert = find('.jasmine-alert'); var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order; var order = doneResult && doneResult.order;
var i;
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
banner.appendChild(optionsMenu(env)); banner.appendChild(optionsMenu(env));
@@ -351,7 +363,14 @@ jasmineRequire.HtmlReporter = function(j$) {
id: 'jasmine-random-order', id: 'jasmine-random-order',
type: 'checkbox' type: 'checkbox'
}), }),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')) createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')),
createDom('div', { className: 'jasmine-hide-disabled' },
createDom('input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-hide-disabled' }, 'hide disabled tests'))
) )
); );
@@ -373,6 +392,12 @@ jasmineRequire.HtmlReporter = function(j$) {
navigateWithNewParam('random', !env.randomTests()); navigateWithNewParam('random', !env.randomTests());
}; };
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
hideDisabled.checked = env.hidingDisabled();
hideDisabled.onclick = function() {
navigateWithNewParam('hideDisabled', !env.hidingDisabled());
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
isOpen = /\bjasmine-open\b/; isOpen = /\bjasmine-open\b/;

View File

@@ -20,6 +20,7 @@ body { overflow-y: scroll; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded { font-size: 14px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded { font-size: 14px; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before { color: #bababa; content: "\02022"; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before { color: #bababa; content: "\02022"; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded-no-display { font-size: 14px; display: none; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { line-height: 17px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { line-height: 17px; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { color: #ba9d37; content: "*"; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { color: #ba9d37; content: "*"; }
.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { font-size: 14px; } .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { font-size: 14px; }
@@ -54,6 +55,6 @@ body { overflow-y: scroll; }
.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { margin-bottom: 28px; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { margin-bottom: 28px; }
.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; color: white; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; color: white; }
.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { color: white; } .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { color: white; }
.jasmine_html-reporter .jasmine-result-message { padding-top: 14px; color: #333; white-space: pre; } .jasmine_html-reporter .jasmine-result-message { padding-top: 14px; color: #333; white-space: pre-wrap; }
.jasmine_html-reporter .jasmine-result-message span.jasmine-result { display: block; } .jasmine_html-reporter .jasmine-result-message span.jasmine-result { display: block; }
.jasmine_html-reporter .jasmine-stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666; border: 1px solid #ddd; background: white; white-space: pre; } .jasmine_html-reporter .jasmine-stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666; border: 1px solid #ddd; background: white; white-space: pre; }

View File

@@ -21,6 +21,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
var getJasmineRequireObj = (function (jasmineGlobal) { var getJasmineRequireObj = (function (jasmineGlobal) {
/* globals exports, global, module, window */
var jasmineRequire; var jasmineRequire;
if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
@@ -59,6 +60,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.StackTrace = jRequire.StackTrace(j$); j$.StackTrace = jRequire.StackTrace(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
j$.Expectation = jRequire.Expectation(); j$.Expectation = jRequire.Expectation();
j$.AsyncExpectation = jRequire.AsyncExpectation(j$);
j$.buildExpectationResult = jRequire.buildExpectationResult(); j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.JsApiReporter = jRequire.JsApiReporter(); j$.JsApiReporter = jRequire.JsApiReporter();
j$.matchersUtil = jRequire.matchersUtil(j$); j$.matchersUtil = jRequire.matchersUtil(j$);
@@ -240,7 +242,14 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
}; };
j$.isDomNode = function(obj) { j$.isDomNode = function(obj) {
return obj.nodeType > 0; // Node is a function, because constructors
return typeof jasmineGlobal.Node !== 'undefined' ?
obj instanceof jasmineGlobal.Node :
obj !== null &&
typeof obj === 'object' &&
typeof obj.nodeType === 'number' &&
typeof obj.nodeName === 'string';
// return obj.nodeType > 0;
}; };
j$.isMap = function(obj) { j$.isMap = function(obj) {
@@ -252,7 +261,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
}; };
j$.isPromise = function(obj) { j$.isPromise = function(obj) {
return typeof jasmineGlobal.Promise !== 'undefined' && obj.constructor === jasmineGlobal.Promise; return typeof jasmineGlobal.Promise !== 'undefined' && obj && obj.constructor === jasmineGlobal.Promise;
}; };
j$.fnNameFor = function(func) { j$.fnNameFor = function(func) {
@@ -486,7 +495,7 @@ getJasmineRequireObj().util = function(j$) {
return false; return false;
} }
function errorWithStack() { util.errorWithStack = function errorWithStack () {
// Don't throw and catch if we don't have to, because it makes it harder // Don't throw and catch if we don't have to, because it makes it harder
// for users to debug their code with exception breakpoints. // for users to debug their code with exception breakpoints.
var error = new Error(); var error = new Error();
@@ -501,10 +510,10 @@ getJasmineRequireObj().util = function(j$) {
} catch (e) { } catch (e) {
return e; return e;
} }
} };
function callerFile() { function callerFile() {
var trace = new j$.StackTrace(errorWithStack().stack); var trace = new j$.StackTrace(util.errorWithStack());
return trace.frames[2].file; return trace.frames[2].file;
} }
@@ -528,6 +537,7 @@ getJasmineRequireObj().util = function(j$) {
getJasmineRequireObj().Spec = function(j$) { getJasmineRequireObj().Spec = function(j$) {
function Spec(attrs) { function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id; this.id = attrs.id;
this.description = attrs.description || ''; this.description = attrs.description || '';
@@ -584,6 +594,10 @@ getJasmineRequireObj().Spec = function(j$) {
return this.expectationFactory(actual, this); return this.expectationFactory(actual, this);
}; };
Spec.prototype.expectAsync = function(actual) {
return this.asyncExpectationFactory(actual, this);
};
Spec.prototype.execute = function(onComplete, excluded) { Spec.prototype.execute = function(onComplete, excluded) {
var self = this; var self = this;
@@ -704,6 +718,7 @@ getJasmineRequireObj().Spec = function(j$) {
}; };
if (typeof window == void 0 && typeof exports == 'object') { if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Spec = jasmineRequire.Spec; exports.Spec = jasmineRequire.Spec;
} }
@@ -769,9 +784,9 @@ getJasmineRequireObj().Env = function(j$) {
var totalSpecsDefined = 0; var totalSpecsDefined = 0;
var realSetTimeout = j$.getGlobal().setTimeout; var realSetTimeout = global.setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout; var realClearTimeout = global.clearTimeout;
var clearStack = j$.getClearStack(j$.getGlobal()); var clearStack = j$.getClearStack(global);
this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global)); this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
var runnableResources = {}; var runnableResources = {};
@@ -782,6 +797,7 @@ getJasmineRequireObj().Env = function(j$) {
var throwOnExpectationFailure = false; var throwOnExpectationFailure = false;
var stopOnSpecFailure = false; var stopOnSpecFailure = false;
var random = true; var random = true;
var hidingDisabled = false;
var seed = null; var seed = null;
var handlingLoadErrors = true; var handlingLoadErrors = true;
var hasFailures = false; var hasFailures = false;
@@ -795,7 +811,7 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var globalErrors = null; var globalErrors = null;
var installGlobalErrors = function() { var installGlobalErrors = function() {
if (globalErrors) { if (globalErrors) {
return; return;
@@ -872,6 +888,19 @@ getJasmineRequireObj().Env = function(j$) {
} }
}; };
var asyncExpectationFactory = function(actual, spec) {
return j$.AsyncExpectation.factory({
util: j$.matchersUtil,
customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
actual: actual,
addExpectationResult: addExpectationResult
});
function addExpectationResult(passed, result) {
return spec.addExpectationResult(passed, result);
}
};
var defaultResourcesForRunnable = function(id, parentRunnableId) { var defaultResourcesForRunnable = function(id, parentRunnableId) {
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}}; var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}};
@@ -930,6 +959,13 @@ getJasmineRequireObj().Env = function(j$) {
var maximumSpecCallbackDepth = 20; var maximumSpecCallbackDepth = 20;
var currentSpecCallbackDepth = 0; var currentSpecCallbackDepth = 0;
/**
* Sets whether Jasmine should throw an Error when an expectation fails.
* This causes a spec to only have one expectation failure.
* @name Env#throwOnExpectationFailure
* @function
* @param {Boolean} value Whether to throw when a expectation fails
*/
this.throwOnExpectationFailure = function(value) { this.throwOnExpectationFailure = function(value) {
throwOnExpectationFailure = !!value; throwOnExpectationFailure = !!value;
}; };
@@ -938,6 +974,12 @@ getJasmineRequireObj().Env = function(j$) {
return throwOnExpectationFailure; return throwOnExpectationFailure;
}; };
/**
* Set whether to stop suite execution when a spec fails
* @name Env#stopOnSpecFailure
* @function
* @param {Boolean} value Whether to stop suite execution when a spec fails
*/
this.stopOnSpecFailure = function(value) { this.stopOnSpecFailure = function(value) {
stopOnSpecFailure = !!value; stopOnSpecFailure = !!value;
}; };
@@ -946,6 +988,12 @@ getJasmineRequireObj().Env = function(j$) {
return stopOnSpecFailure; return stopOnSpecFailure;
}; };
/**
* Set whether to randomize test execution order
* @name Env#randomizeTests
* @function
* @param {Boolean} value Whether to randomize execution order
*/
this.randomizeTests = function(value) { this.randomizeTests = function(value) {
random = !!value; random = !!value;
}; };
@@ -954,6 +1002,12 @@ getJasmineRequireObj().Env = function(j$) {
return random; return random;
}; };
/**
* Set the random number seed for spec randomization
* @name Env#seed
* @function
* @param {Number} value The seed value
*/
this.seed = function(value) { this.seed = function(value) {
if (value) { if (value) {
seed = value; seed = value;
@@ -961,6 +1015,18 @@ getJasmineRequireObj().Env = function(j$) {
return seed; return seed;
}; };
this.hidingDisabled = function(value) {
return hidingDisabled;
};
/**
* @name Env#hideDisabled
* @function
*/
this.hideDisabled = function(value) {
hidingDisabled = !!value;
};
this.deprecated = function(deprecation) { this.deprecated = function(deprecation) {
var runnable = currentRunnable() || topSuite; var runnable = currentRunnable() || topSuite;
runnable.addDeprecationWarning(deprecation); runnable.addDeprecationWarning(deprecation);
@@ -994,6 +1060,7 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSuiteId(), id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite', description: 'Jasmine__TopLevel__Suite',
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
expectationResultFactory: expectationResultFactory expectationResultFactory: expectationResultFactory
}); });
defaultResourcesForRunnable(topSuite.id); defaultResourcesForRunnable(topSuite.id);
@@ -1006,6 +1073,7 @@ getJasmineRequireObj().Env = function(j$) {
/** /**
* This represents the available reporter callback for an object passed to {@link Env#addReporter}. * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
* @interface Reporter * @interface Reporter
* @see custom_reporter
*/ */
var reporter = new j$.ReportDispatcher([ var reporter = new j$.ReportDispatcher([
/** /**
@@ -1015,6 +1083,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'jasmineStarted', 'jasmineStarted',
/** /**
@@ -1024,6 +1093,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running. * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'jasmineDone', 'jasmineDone',
/** /**
@@ -1033,6 +1103,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SuiteResult} result Information about the individual {@link describe} being run * @param {SuiteResult} result Information about the individual {@link describe} being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'suiteStarted', 'suiteStarted',
/** /**
@@ -1044,6 +1115,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SuiteResult} result * @param {SuiteResult} result
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'suiteDone', 'suiteDone',
/** /**
@@ -1053,6 +1125,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SpecResult} result Information about the individual {@link it} being run * @param {SpecResult} result Information about the individual {@link it} being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'specStarted', 'specStarted',
/** /**
@@ -1064,6 +1137,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SpecResult} result * @param {SpecResult} result
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'specDone' 'specDone'
], queueRunnerFactory); ], queueRunnerFactory);
@@ -1152,8 +1226,8 @@ getJasmineRequireObj().Env = function(j$) {
/** /**
* Information passed to the {@link Reporter#jasmineDone} event. * Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo * @typedef JasmineDoneInfo
* @property {OverallStatus} - The overall result of the sute: 'passed', 'failed', or 'incomplete'. * @property {OverallStatus} overallStatus - The overall result of the sute: 'passed', 'failed', or 'incomplete'.
* @property {IncompleteReason} - Explanation of why the suite was incimplete. * @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 {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[]} 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. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
@@ -1180,10 +1254,22 @@ getJasmineRequireObj().Env = function(j$) {
reporter.addReporter(reporterToAdd); reporter.addReporter(reporterToAdd);
}; };
/**
* Provide a fallback reporter if no other reporters have been specified.
* @name Env#provideFallbackReporter
* @function
* @param {Reporter} reporterToAdd The reporter
* @see custom_reporter
*/
this.provideFallbackReporter = function(reporterToAdd) { this.provideFallbackReporter = function(reporterToAdd) {
reporter.provideFallbackReporter(reporterToAdd); reporter.provideFallbackReporter(reporterToAdd);
}; };
/**
* Clear all registered reporters
* @name Env#clearReporters
* @function
*/
this.clearReporters = function() { this.clearReporters = function() {
reporter.clearReporters(); reporter.clearReporters();
}; };
@@ -1222,7 +1308,16 @@ getJasmineRequireObj().Env = function(j$) {
return spyRegistry.spyOnProperty.apply(spyRegistry, arguments); return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
}; };
this.spyOnAllFunctions = function() {
return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments);
};
this.createSpy = function(name, originalFn) { this.createSpy = function(name, originalFn) {
if (arguments.length === 1 && j$.isFunction_(name)) {
originalFn = name;
name = originalFn.name;
}
return spyFactory.createSpy(name, originalFn); return spyFactory.createSpy(name, originalFn);
}; };
@@ -1256,6 +1351,7 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
parentSuite: currentDeclarationSuite, parentSuite: currentDeclarationSuite,
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
throwOnExpectationFailure: throwOnExpectationFailure throwOnExpectationFailure: throwOnExpectationFailure
}); });
@@ -1349,6 +1445,7 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSpecId(), id: getNextSpecId(),
beforeAndAfterFns: beforeAndAfterFns(suite), beforeAndAfterFns: beforeAndAfterFns(suite),
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
resultCallback: specResultCallback, resultCallback: specResultCallback,
getSpecName: function(spec) { getSpecName: function(spec) {
return getSpecName(spec, suite); return getSpecName(spec, suite);
@@ -1360,7 +1457,7 @@ getJasmineRequireObj().Env = function(j$) {
userContext: function() { return suite.clonedSharedUserContext(); }, userContext: function() { return suite.clonedSharedUserContext(); },
queueableFn: { queueableFn: {
fn: fn, fn: fn,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}, },
throwOnExpectationFailure: throwOnExpectationFailure throwOnExpectationFailure: throwOnExpectationFailure
}); });
@@ -1430,12 +1527,20 @@ getJasmineRequireObj().Env = function(j$) {
return currentRunnable().expect(actual); return currentRunnable().expect(actual);
}; };
this.expectAsync = function(actual) {
if (!currentRunnable()) {
throw new Error('\'expectAsync\' was used when there was no current spec, this could be because an asynchronous test timed out');
}
return currentRunnable().expectAsync(actual);
};
this.beforeEach = function(beforeEachFunction, timeout) { this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsNotNested('beforeEach'); ensureIsNotNested('beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({ currentDeclarationSuite.beforeEach({
fn: beforeEachFunction, fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -1444,7 +1549,7 @@ getJasmineRequireObj().Env = function(j$) {
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({ currentDeclarationSuite.beforeAll({
fn: beforeAllFunction, fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -1454,7 +1559,7 @@ getJasmineRequireObj().Env = function(j$) {
afterEachFunction.isCleanup = true; afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({ currentDeclarationSuite.afterEach({
fn: afterEachFunction, fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -1463,7 +1568,7 @@ getJasmineRequireObj().Env = function(j$) {
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({ currentDeclarationSuite.afterAll({
fn: afterAllFunction, fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -1485,11 +1590,11 @@ getJasmineRequireObj().Env = function(j$) {
message += ': '; message += ': ';
if (error.message) { if (error.message) {
message += error.message; message += error.message;
} else if (jasmine.isString_(error)) { } else if (j$.isString_(error)) {
message += error; message += error;
} else { } else {
// pretty print all kind of objects. This includes arrays. // pretty print all kind of objects. This includes arrays.
message += jasmine.pp(error); message += j$.pp(error);
} }
} }
@@ -1676,6 +1781,7 @@ getJasmineRequireObj().Any = function(j$) {
} }
/* jshint -W122 */ /* jshint -W122 */
/* global Symbol */
if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) { if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
return typeof other == 'symbol'; return typeof other == 'symbol';
} }
@@ -1727,7 +1833,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
}; };
ArrayContaining.prototype.jasmineToString = function () { ArrayContaining.prototype.jasmineToString = function () {
return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>'; return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
}; };
return ArrayContaining; return ArrayContaining;
@@ -1919,6 +2025,160 @@ getJasmineRequireObj().Truthy = function(j$) {
return Truthy; return Truthy;
}; };
getJasmineRequireObj().AsyncExpectation = function(j$) {
var promiseForMessage = {
jasmineToString: function() { return 'a promise'; }
};
/**
* Asynchronous matchers.
* @namespace async-matchers
*/
function AsyncExpectation(options) {
var global = options.global || j$.getGlobal();
this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || [];
this.addExpectationResult = options.addExpectationResult || function(){};
this.actual = options.actual;
this.isNot = options.isNot;
if (!global.Promise) {
throw new Error('expectAsync is unavailable because the environment does not support promises.');
}
if (!j$.isPromise(this.actual)) {
throw new Error('Expected expectAsync to be called with a promise.');
}
['toBeResolved', 'toBeRejected', 'toBeResolvedTo'].forEach(wrapCompare.bind(this));
}
function wrapCompare(name) {
var compare = this[name];
this[name] = function() {
var self = this;
var args = Array.prototype.slice.call(arguments);
args.unshift(this.actual);
// Capture the call stack here, before we go async, so that it will
// contain frames that are relevant to the user instead of just parts
// of Jasmine.
var errorForStack = j$.util.errorWithStack();
return compare.apply(self, args).then(function(result) {
var message;
if (self.isNot) {
result.pass = !result.pass;
}
args[0] = promiseForMessage;
message = j$.Expectation.finalizeMessage(self.util, name, self.isNot, args, result);
self.addExpectationResult(result.pass, {
matcherName: name,
passed: result.pass,
message: message,
error: undefined,
errorForStack: errorForStack,
actual: self.actual
});
});
};
}
/**
* Expect a promise to be resolved.
* @function
* @async
* @name async-matchers#toBeResolved
* @example
* await expectAsync(aPromise).toBeResolved();
* @example
* return expectAsync(aPromise).toBeResolved();
*/
AsyncExpectation.prototype.toBeResolved = function(actual) {
return actual.then(
function() { return {pass: true}; },
function() { return {pass: false}; }
);
};
/**
* Expect a promise to be rejected.
* @function
* @async
* @name async-matchers#toBeRejected
* @example
* await expectAsync(aPromise).toBeRejected();
* @example
* return expectAsync(aPromise).toBeRejected();
*/
AsyncExpectation.prototype.toBeRejected = function(actual) {
return actual.then(
function() { return {pass: false}; },
function() { return {pass: true}; }
);
};
/**
* Expect a promise to be resolved to a value equal to the expected, using deep equality comparison.
* @function
* @async
* @name async-matchers#toBeResolvedTo
* @param {Object} expected - Value that the promise is expected to resolve to
* @example
* await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
* @example
* return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
*/
AsyncExpectation.prototype.toBeResolvedTo = function(actualPromise, expectedValue) {
var self = this;
function prefix(passed) {
return 'Expected a promise ' +
(passed ? 'not ' : '') +
'to be resolved to ' + j$.pp(expectedValue);
}
return actualPromise.then(
function(actualValue) {
if (self.util.equals(actualValue, expectedValue, self.customEqualityTesters)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
return {
pass: false,
message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
};
}
},
function() {
return {
pass: false,
message: prefix(false) + ' but it was rejected.'
};
}
);
};
AsyncExpectation.factory = function(options) {
var expect = new AsyncExpectation(options);
options = j$.util.clone(options);
options.isNot = true;
expect.not = new AsyncExpectation(options);
return expect;
};
return AsyncExpectation;
};
getJasmineRequireObj().CallTracker = function(j$) { getJasmineRequireObj().CallTracker = function(j$) {
/** /**
@@ -2107,6 +2367,7 @@ getJasmineRequireObj().clearStack = function(j$) {
getJasmineRequireObj().Clock = function() { getJasmineRequireObj().Clock = function() {
/* global process */
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string'; var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
/** /**
@@ -2496,7 +2757,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
return null; return null;
} }
var stackTrace = new j$.StackTrace(error.stack); var stackTrace = new j$.StackTrace(error);
var lines = filterJasmine(stackTrace); var lines = filterJasmine(stackTrace);
var result = ''; var result = '';
@@ -2576,7 +2837,7 @@ getJasmineRequireObj().Expectation = function() {
return function() { return function() {
var args = Array.prototype.slice.call(arguments, 0), var args = Array.prototype.slice.call(arguments, 0),
expected = args.slice(0), expected = args.slice(0),
message = ''; message;
args.unshift(this.actual); args.unshift(this.actual);
@@ -2594,20 +2855,7 @@ getJasmineRequireObj().Expectation = function() {
} }
var result = matcherCompare.apply(null, args); var result = matcherCompare.apply(null, args);
message = Expectation.finalizeMessage(this.util, name, this.isNot, args, result);
if (!result.pass) {
if (!result.message) {
args.unshift(this.isNot);
args.unshift(name);
message = this.util.buildFailureMessage.apply(null, args);
} else {
if (Object.prototype.toString.apply(result.message) === '[object Function]') {
message = result.message();
} else {
message = result.message;
}
}
}
if (expected.length == 1) { if (expected.length == 1) {
expected = expected[0]; expected = expected[0];
@@ -2628,6 +2876,23 @@ getJasmineRequireObj().Expectation = function() {
}; };
}; };
Expectation.finalizeMessage = function(util, name, isNot, args, result) {
if (result.pass) {
return '';
} else if (result.message) {
if (Object.prototype.toString.apply(result.message) === '[object Function]') {
return result.message();
} else {
return result.message;
}
} else {
args = args.slice();
args.unshift(isNot);
args.unshift(name);
return util.buildFailureMessage.apply(null, args);
}
};
Expectation.addCoreMatchers = function(matchers) { Expectation.addCoreMatchers = function(matchers) {
var prototype = Expectation.prototype; var prototype = Expectation.prototype;
for (var matcherName in matchers) { for (var matcherName in matchers) {
@@ -2699,7 +2964,9 @@ getJasmineRequireObj().buildExpectationResult = function() {
var error = options.error; var error = options.error;
if (!error) { if (!error) {
if (options.stack) { if (options.errorForStack) {
error = options.errorForStack;
} else if (options.stack) {
error = options; error = options;
} else { } else {
try { try {
@@ -2743,18 +3010,29 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
} }
}; };
this.originalHandlers = {};
this.installOne_ = function installOne_(errorType) {
this.originalHandlers[errorType] = global.process.listeners(errorType);
global.process.removeAllListeners(errorType);
global.process.on(errorType, onerror);
this.uninstall = function uninstall() {
var errorTypes = Object.keys(this.originalHandlers);
for (var iType = 0; iType < errorTypes.length; iType++) {
var errorType = errorTypes[iType];
global.process.removeListener(errorType, onerror);
for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
global.process.on(errorType, this.originalHandlers[errorType][i]);
}
delete this.originalHandlers[errorType];
}
};
};
this.install = function install() { this.install = function install() {
if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) { if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
var originalHandlers = global.process.listeners('uncaughtException'); this.installOne_('uncaughtException');
global.process.removeAllListeners('uncaughtException'); this.installOne_('unhandledRejection');
global.process.on('uncaughtException', onerror);
this.uninstall = function uninstall() {
global.process.removeListener('uncaughtException', onerror);
for (var i = 0; i < originalHandlers.length; i++) {
global.process.on('uncaughtException', originalHandlers[i]);
}
};
} else { } else {
var originalHandler = global.onerror; var originalHandler = global.onerror;
global.onerror = onerror; global.onerror = onerror;
@@ -3038,8 +3316,14 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}); });
for (i = 0; i < aLength || i < bLength; i++) { for (i = 0; i < aLength || i < bLength; i++) {
var formatter = false;
diffBuilder.withPath(i, function() { diffBuilder.withPath(i, function() {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result; if (i >= bLength) {
diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
result = false;
} else {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
}
}); });
} }
if (!result) { if (!result) {
@@ -3265,6 +3549,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
', but was ' + j$.pp(actual) + '.'; ', but was ' + j$.pp(actual) + '.';
} }
function actualArrayIsLongerFormatter(actual, expected, path) {
return 'Unexpected ' +
path + (path.depth() ? ' = ' : '') +
j$.pp(actual) +
' in array.';
}
function formatKeyValuePairs(obj) { function formatKeyValuePairs(obj) {
var formatted = ''; var formatted = '';
for (var key in obj) { for (var key in obj) {
@@ -4617,8 +4908,8 @@ getJasmineRequireObj().pp = function(j$) {
if (el.innerHTML === '') { if (el.innerHTML === '') {
this.append(el.outerHTML.replace(closingTag, '')); this.append(el.outerHTML.replace(closingTag, ''));
} else { } else {
var tagEnd = el.outerHTML.indexOf(el.innerHTML); var tagEnd = el.outerHTML.indexOf('>');
this.append(el.outerHTML.substring(0, tagEnd)); this.append(el.outerHTML.substring(0, tagEnd + 1));
this.append('...' + closingTag); this.append('...' + closingTag);
} }
}; };
@@ -4803,12 +5094,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.globalErrors.pushListener(handleError); self.globalErrors.pushListener(handleError);
if (queueableFn.timeout) { if (queueableFn.timeout !== undefined) {
var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
timeoutId = self.setTimeout(function() { timeoutId = self.setTimeout(function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); var error = new Error(
'Timeout - Async callback was not invoked within ' + timeoutInterval + 'ms ' +
(queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
);
onException(error); onException(error);
next(); next();
}, queueableFn.timeout()); }, timeoutInterval);
} }
try { try {
@@ -4857,7 +5152,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return; return;
} }
self.errored = result.errored; self.errored = self.errored || result.errored;
if (this.completeOnFirstError && result.errored) { if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex); this.skipToCleanup(iterativeIndex);
@@ -5017,6 +5312,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @param {String} description Textual description of what this spec is checking * @param {String} description Textual description of what this spec is checking
* @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
* @see async
*/ */
it: function() { it: function() {
return env.it.apply(env, arguments); return env.it.apply(env, arguments);
@@ -5046,6 +5342,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @param {String} description Textual description of what this spec is checking. * @param {String} description Textual description of what this spec is checking.
* @param {implementationCallback} testFunction Function that contains the code of your test. * @param {implementationCallback} testFunction Function that contains the code of your test.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
* @see async
*/ */
fit: function() { fit: function() {
return env.fit.apply(env, arguments); return env.fit.apply(env, arguments);
@@ -5058,6 +5355,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {implementationCallback} [function] Function that contains the code to setup your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
* @see async
*/ */
beforeEach: function() { beforeEach: function() {
return env.beforeEach.apply(env, arguments); return env.beforeEach.apply(env, arguments);
@@ -5070,6 +5368,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
* @see async
*/ */
afterEach: function() { afterEach: function() {
return env.afterEach.apply(env, arguments); return env.afterEach.apply(env, arguments);
@@ -5084,6 +5383,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {implementationCallback} [function] Function that contains the code to setup your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
* @see async
*/ */
beforeAll: function() { beforeAll: function() {
return env.beforeAll.apply(env, arguments); return env.beforeAll.apply(env, arguments);
@@ -5098,6 +5398,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
* @see async
*/ */
afterAll: function() { afterAll: function() {
return env.afterAll.apply(env, arguments); return env.afterAll.apply(env, arguments);
@@ -5115,6 +5416,25 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.expect(actual); return env.expect(actual);
}, },
/**
* Create an asynchronous expectation for a spec. Note that the matchers
* that are provided by an asynchronous expectation all return promises
* which must be either returned from the spec or waited for using `await`
* in order for Jasmine to associate them with the correct spec.
* @name expectAsync
* @function
* @global
* @param {Object} actual - Actual computed value to test expectations against.
* @return {async-matchers}
* @example
* await expectAsync(somePromise).toBeResolved();
* @example
* return expectAsync(somePromise).toBeResolved();
*/
expectAsync: function(actual) {
return env.expectAsync(actual);
},
/** /**
* Mark a spec as pending, expectation results will be ignored. * Mark a spec as pending, expectation results will be ignored.
* @name pending * @name pending
@@ -5164,6 +5484,18 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.spyOnProperty(obj, methodName, accessType); return env.spyOnProperty(obj, methodName, accessType);
}, },
/**
* Installs spies on all writable and configurable properties of an object.
* @name spyOnAllFunctions
* @function
* @global
* @param {Object} obj - The object upon which to install the {@link Spy}s
* @returns {Object} the spied object
*/
spyOnAllFunctions: function(obj) {
return env.spyOnAllFunctions(obj);
},
jsApiReporter: new jasmine.JsApiReporter({ jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer() timer: new jasmine.Timer()
}), }),
@@ -5582,6 +5914,23 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
return spy; return spy;
}; };
this.spyOnAllFunctions = function(obj) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOnAllFunctions could not find an object to spy upon');
}
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] instanceof Function) {
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
if ((descriptor.writable || descriptor.set) && descriptor.configurable) {
this.spyOn(obj, prop);
}
}
}
return obj;
};
this.clearSpies = function() { this.clearSpies = function() {
var spies = currentSpies(); var spies = currentSpies();
for (var i = spies.length - 1; i >= 0; i--) { for (var i = spies.length - 1; i >= 0; i--) {
@@ -5726,15 +6075,16 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
}; };
getJasmineRequireObj().StackTrace = function(j$) { getJasmineRequireObj().StackTrace = function(j$) {
function StackTrace(rawTrace) { function StackTrace(error) {
var lines = rawTrace var lines = error.stack
.split('\n') .split('\n')
.filter(function(line) { return line !== ''; }); .filter(function(line) { return line !== ''; });
if (lines[0].match(/^Error/)) { var extractResult = extractMessage(error.message, lines);
this.message = lines.shift();
} else { if (extractResult) {
this.message = undefined; this.message = extractResult.message;
lines = extractResult.remainder;
} }
var parseResult = tryParseFrames(lines); var parseResult = tryParseFrames(lines);
@@ -5802,6 +6152,34 @@ getJasmineRequireObj().StackTrace = function(j$) {
} }
} }
} }
function extractMessage(message, stackLines) {
var len = messagePrefixLength(message, stackLines);
if (len > 0) {
return {
message: stackLines.slice(0, len).join('\n'),
remainder: stackLines.slice(len)
};
}
}
function messagePrefixLength(message, stackLines) {
if (!stackLines[0].match(/^Error/)) {
return 0;
}
var messageLines = message.split('\n');
var i;
for (i = 1; i < messageLines.length; i++) {
if (messageLines[i] !== stackLines[i]) {
return 0;
}
}
return messageLines.length;
}
return StackTrace; return StackTrace;
}; };
@@ -5813,6 +6191,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.parentSuite = attrs.parentSuite; this.parentSuite = attrs.parentSuite;
this.description = attrs.description; this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory; this.expectationResultFactory = attrs.expectationResultFactory;
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
@@ -5845,6 +6224,10 @@ getJasmineRequireObj().Suite = function(j$) {
return this.expectationFactory(actual, this); return this.expectationFactory(actual, this);
}; };
Suite.prototype.expectAsync = function(actual) {
return this.asyncExpectationFactory(actual, this);
};
Suite.prototype.getFullName = function() { Suite.prototype.getFullName = function() {
var fullName = []; var fullName = [];
for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) { for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -5971,6 +6354,7 @@ getJasmineRequireObj().Suite = function(j$) {
}; };
if (typeof window == void 0 && typeof exports == 'object') { if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Suite = jasmineRequire.Suite; exports.Suite = jasmineRequire.Suite;
} }
@@ -6173,8 +6557,11 @@ getJasmineRequireObj().TreeProcessor = function() {
queueRunnerFactory({ queueRunnerFactory({
onComplete: function () { onComplete: function () {
var args = Array.prototype.slice.call(arguments, [0]);
node.cleanupBeforeAfter(); node.cleanupBeforeAfter();
nodeComplete(node, node.getResult(), done); nodeComplete(node, node.getResult(), function() {
done.apply(undefined, args);
});
}, },
queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)), queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
userContext: node.sharedUserContext(), userContext: node.sharedUserContext(),
@@ -6230,5 +6617,5 @@ getJasmineRequireObj().UserContext = function(j$) {
}; };
getJasmineRequireObj().version = function() { getJasmineRequireObj().version = function() {
return '3.1.0'; return '3.2.1';
}; };

View File

@@ -4,6 +4,6 @@
# #
module Jasmine module Jasmine
module Core module Core
VERSION = "3.1.0" VERSION = "3.2.1"
end end
end end

View File

@@ -1,7 +1,7 @@
{ {
"name": "jasmine-core", "name": "jasmine-core",
"license": "MIT", "license": "MIT",
"version": "3.1.0", "version": "3.2.1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/jasmine/jasmine.git" "url": "https://github.com/jasmine/jasmine.git"

83
release_notes/3.2.0.md Normal file
View File

@@ -0,0 +1,83 @@
# Jasmine-Core 3.2 Release Notes
## Summary
This release contains a number of fixes and pull requests
## Changes
* Add spyOnAllFunctions function
- Merges [#1581](https://github.com/jasmine/jasmine/issues/1581) from @aeisenberg
- Fixes [#1421](https://github.com/jasmine/jasmine/issues/1421)
* Improve timeout error message
- Merges [#1567](https://github.com/jasmine/jasmine/issues/1567) from @ikonst
* Fix JSDoc naming for Env functions
- See [#1565](https://github.com/jasmine/jasmine/issues/1565)
* Add documentation for more public functions on Env
- Fixes [#1565](https://github.com/jasmine/jasmine/issues/1565)
* Added a basic set of async matchers
- Fixes [#1447](https://github.com/jasmine/jasmine/issues/1447)
- Fixes [#1547](https://github.com/jasmine/jasmine/issues/1547)
* Properly cascade StopExecutionError's up the tree
- Fixes [#1563](https://github.com/jasmine/jasmine/issues/1563)
* Implemented hiding of disabled specs
- Merges [#1561](https://github.com/jasmine/jasmine/issues/1561) from @SamFare
* Line-break long expectation failure messages
- See [#296](https://github.com/jasmine/jasmine/issues/296)
* Better detection of DOM Nodes for equality
- Fixes [#1172](https://github.com/jasmine/jasmine/issues/1172)
* Fix typo from `incimplete` to `incomplete`
- Merges [#1555](https://github.com/jasmine/jasmine/issues/1555) from @yinm
* Allow omitting the name argument: `createSpy(func)`
- Merges [#1551](https://github.com/jasmine/jasmine/issues/1551) from @riophae
* name new global status stuff correctly in API docs
* Check for accidental global variable creation
* Fixed global variable leak
- Fixes [#1534](https://github.com/jasmine/jasmine/issues/1534)
* Correctly format stack traces for errors with multiline messages
- Fixes [#1526](https://github.com/jasmine/jasmine/issues/1526)
* Change message for extra elements at end of actual array
- Merges [#1527](https://github.com/jasmine/jasmine/issues/1527) from @majidmade
- Fixes [#1485](https://github.com/jasmine/jasmine/issues/1485)
* Report unhandled rejections as globalErrors.
- Merges [#1521](https://github.com/jasmine/jasmine/issues/1521) from @johnjbarton
* add some links to more tutorials from the api docs
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

11
release_notes/3.2.1.md Normal file
View File

@@ -0,0 +1,11 @@
# Jasmine-Core 3.2.1 Release Notes
## Changes
* Correctly expose `spyOnAllFunctions`
- See [#1581](https://github.com/jasmine/jasmine/issues/1581)
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -0,0 +1,288 @@
describe('AsyncExpectation', function() {
describe('Factory', function() {
it('throws an Error if promises are not available', function() {
var thenable = {then: function() {}},
options = {global: {}, actual: thenable}
function f() { jasmineUnderTest.AsyncExpectation.factory(options); }
expect(f).toThrowError('expectAsync is unavailable because the environment does not support promises.');
});
it('throws an Error if the argument is not a promise', function() {
jasmine.getEnv().requirePromises();
function f() {
jasmineUnderTest.AsyncExpectation.factory({actual: 'not a promise'});
}
expect(f).toThrowError('Expected expectAsync to be called with a promise.');
});
});
describe('#toBeResolved', function() {
it('passes if the actual is resolved', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolved().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toBeResolved',
passed: true,
message: '',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
it('fails if the actual is rejected', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject('AsyncExpectationSpec rejection'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolved().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toBeResolved',
passed: false,
message: 'Expected a promise to be resolved.',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
});
describe('#toBeRejected', function() {
it('passes if the actual is rejected', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject('AsyncExpectationSpec rejection'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeRejected().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toBeRejected',
passed: true,
message: '',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
it('fails if the actual is resolved', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeRejected().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toBeRejected',
passed: false,
message: 'Expected a promise to be rejected.',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
});
describe('#toBeResolvedTo', function() {
it('passes if the promise is resolved to the expected value', function() {
jasmine.getEnv().requirePromises();
var actual = Promise.resolve({foo: 42});
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolvedTo({foo: 42}).then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: 'toBeResolvedTo',
passed: true,
message: '',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
it('fails if the promise is rejected', function() {
jasmine.getEnv().requirePromises();
var actual = Promise.reject('AsyncExpectationSpec error');
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolvedTo('').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toBeResolvedTo',
passed: false,
message: "Expected a promise to be resolved to '' but it was rejected.",
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
it('fails if the promise is resolved to a different value', function() {
jasmine.getEnv().requirePromises();
var actual = Promise.resolve({foo: 17});
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolvedTo({foo: 42}).then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: 'toBeResolvedTo',
passed: false,
message: 'Expected a promise to be resolved to Object({ foo: 42 }) but it was resolved to Object({ foo: 17 }).',
error: undefined,
errorForStack: jasmine.any(Error),
actual: actual
});
});
});
it('builds its message correctly when negated', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = jasmineUnderTest.AsyncExpectation.factory({
util: jasmineUnderTest.matchersUtil,
actual: Promise.resolve(true),
addExpectationResult: addExpectationResult
});
return expectation.not.toBeResolvedTo(true).then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false,
jasmine.objectContaining({
passed: false,
message: 'Expected a promise not to be resolved to true.'
})
);
});
});
it('supports custom equality testers', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
expectation = new jasmineUnderTest.AsyncExpectation({
util: jasmineUnderTest.matchersUtil,
customEqualityTesters: [function() { return true; }],
actual: Promise.resolve('actual'),
addExpectationResult: addExpectationResult
});
return expectation.toBeResolvedTo('expected').then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true,
jasmine.objectContaining({passed: true}));
});
});
});
describe('#not', function() {
it('converts a pass to a fail', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.resolve(),
expectation = jasmineUnderTest.AsyncExpectation.factory({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.not.toBeResolved().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(false,
jasmine.objectContaining({
passed: false,
message: 'Expected a promise not to be resolved.'
})
);
});
});
it('converts a fail to a pass', function() {
jasmine.getEnv().requirePromises();
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = Promise.reject(),
expectation = jasmineUnderTest.AsyncExpectation.factory({
util: jasmineUnderTest.matchersUtil,
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.not.toBeResolved().then(function() {
expect(addExpectationResult).toHaveBeenCalledWith(true,
jasmine.objectContaining({
passed: true,
message: ''
})
);
});
});
});
it('propagates rejections from the comparison function', function() {
jasmine.getEnv().requirePromises();
var error = new Error('AsyncExpectationSpec failure');
spyOn(jasmineUnderTest.AsyncExpectation.prototype, 'toBeResolved')
.and.returnValue(Promise.reject(error));
var addExpectationResult = jasmine.createSpy('addExpectationResult'),
actual = dummyPromise(),
expectation = new jasmineUnderTest.AsyncExpectation({
actual: actual,
addExpectationResult: addExpectationResult
});
return expectation.toBeResolved()
.then(
function() { fail('Expected a rejection'); },
function(e) { expect(e).toBe(error); }
);
});
function dummyPromise() {
return new Promise(function(resolve, reject) {
});
}
});

View File

@@ -56,6 +56,7 @@ describe("ExceptionFormatter", function() {
it("filters Jasmine stack frames from V8 style traces", function() { it("filters Jasmine stack frames from V8 style traces", function() {
var error = { var error = {
message: 'nope',
stack: 'Error: nope\n' + stack: 'Error: nope\n' +
' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + ' at fn1 (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' + ' at fn2 (http://localhost:8888/__jasmine__/jasmine.js:4320:20)\n' +
@@ -113,6 +114,25 @@ describe("ExceptionFormatter", function() {
} }
}); });
it("handles multiline error messages in this environment", function() {
var error, i, msg = "an error\nwith two lines";
try { throw new Error(msg); } catch(e) { error = e; }
if (error.stack.indexOf(msg) === -1) {
pending("Stack traces don't have messages in this environment");
}
var subject = new jasmineUnderTest.ExceptionFormatter({
jasmineFile: jasmine.util.jasmineFile()
});
var result = subject.stack(error);
var lines = result.split('\n');
expect(lines[0]).toMatch(/an error/);
expect(lines[1]).toMatch(/with two lines/);
expect(lines[2]).toMatch(/ExceptionFormatterSpec.js/);
expect(lines[3]).toMatch(/<Jasmine>/);
});
it("returns null if no Error provided", function() { it("returns null if no Error provided", function() {
expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull(); expect(new jasmineUnderTest.ExceptionFormatter().stack()).toBeNull();
}); });

View File

@@ -44,6 +44,21 @@ describe("buildExpectationResult", function() {
expect(result.stack).toEqual('foo'); expect(result.stack).toEqual('foo');
}); });
it("delegates stack formatting to the provided formatter if there was a provided errorForStack", function() {
var fakeError = {stack: 'foo'},
stackFormatter = jasmine.createSpy("stack formatter").and.returnValue(fakeError.stack);
var result = jasmineUnderTest.buildExpectationResult(
{
passed: false,
errorForStack: fakeError,
stackFormatter: stackFormatter
});
expect(stackFormatter).toHaveBeenCalledWith(fakeError);
expect(result.stack).toEqual('foo');
});
it("matcherName returns passed matcherName", function() { it("matcherName returns passed matcherName", function() {
var result = jasmineUnderTest.buildExpectationResult({matcherName: 'some-value'}); var result = jasmineUnderTest.buildExpectationResult({matcherName: 'some-value'});
expect(result.matcherName).toBe('some-value'); expect(result.matcherName).toBe('some-value');

View File

@@ -78,7 +78,7 @@ describe("GlobalErrors", function() {
errors.uninstall(); errors.uninstall();
}); });
it("works in node.js", function() { it("reports uncaughtException in node.js", function() {
var fakeGlobal = { var fakeGlobal = {
process: { process: {
on: jasmine.createSpy('process.on'), on: jasmine.createSpy('process.on'),
@@ -107,4 +107,34 @@ describe("GlobalErrors", function() {
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith('uncaughtException', addedListener); expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith('uncaughtException', addedListener);
expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', 'foo'); expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', 'foo');
}); });
it("reports unhandledRejection in node.js", function() {
var fakeGlobal = {
process: {
on: jasmine.createSpy('process.on'),
removeListener: jasmine.createSpy('process.removeListener'),
listeners: jasmine.createSpy('process.listeners').and.returnValue(['foo']),
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
}
},
handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install();
expect(fakeGlobal.process.on).toHaveBeenCalledWith('unhandledRejection', jasmine.any(Function));
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith('unhandledRejection');
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith('unhandledRejection');
errors.pushListener(handler);
var addedListener = fakeGlobal.process.on.calls.argsFor(0)[1];
addedListener(new Error('bar'));
expect(handler).toHaveBeenCalledWith(new Error('bar'));
errors.uninstall();
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith('unhandledRejection', addedListener);
expect(fakeGlobal.process.on).toHaveBeenCalledWith('unhandledRejection', 'foo');
});
}); });

View File

@@ -183,7 +183,7 @@ describe("QueueRunner", function() {
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() { it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
var timeout = 3, var timeout = 3,
beforeFn = { fn: function(done) { }, type: 'before', timeout: function() { return timeout; } }, beforeFn = { fn: function(done) { }, type: 'before', timeout: timeout },
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' }, queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
onComplete = jasmine.createSpy('onComplete'), onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
@@ -304,7 +304,7 @@ describe("QueueRunner", function() {
}); });
it("continues running functions when an exception is thrown in async code without timing out", function() { it("continues running functions when an exception is thrown in async code without timing out", function() {
var queueableFn = { fn: function(done) { throwAsync(); }, timeout: function() { return 1; } }, var queueableFn = { fn: function(done) { throwAsync(); }, timeout: 1 },
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") }, nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
globalErrors = { pushListener: jasmine.createSpy('pushListener'), popListener: jasmine.createSpy('popListener') }, globalErrors = { pushListener: jasmine.createSpy('pushListener'), popListener: jasmine.createSpy('popListener') },
@@ -481,15 +481,18 @@ describe("QueueRunner", function() {
var queueableFn = { fn: function() { throw new Error("error"); } }, var queueableFn = { fn: function() { throw new Error("error"); } },
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") }, nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
cleanupFn = { fn: jasmine.createSpy("cleanup") }, cleanupFn = { fn: jasmine.createSpy("cleanup") },
onComplete = jasmine.createSpy("onComplete"),
queueRunner = new jasmineUnderTest.QueueRunner({ queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn], queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn], cleanupFns: [cleanupFn],
onComplete: onComplete,
completeOnFirstError: true completeOnFirstError: true
}); });
queueRunner.execute(); queueRunner.execute();
expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(nextQueueableFn.fn).not.toHaveBeenCalled();
expect(cleanupFn.fn).toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled();
expect(onComplete).toHaveBeenCalledWith(jasmine.any(jasmineUnderTest.StopExecutionError));
}); });
it("does not skip when a cleanup function throws", function() { it("does not skip when a cleanup function throws", function() {

View File

@@ -214,6 +214,97 @@ describe("SpyRegistry", function() {
}); });
}); });
describe("#spyOnAllFunctions", function() {
it("checks for the existence of the object", function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry();
expect(function() {
spyRegistry.spyOnAllFunctions(void 0);
}).toThrowError(/spyOnAllFunctions could not find an object to spy upon/);
});
it("overrides all writable and configurable functions of the object", function() {
var spyRegistry = new jasmineUnderTest.SpyRegistry({createSpy: function() {
return 'I am a spy';
}});
var createNoop = function() { return function() { /**/}; };
var noop1 = createNoop();
var noop2 = createNoop();
var noop3 = createNoop();
var noop4 = createNoop();
var noop5 = createNoop();
var parent = {
notSpied1: noop1
};
var subject = Object.create(parent);
Object.defineProperty(subject, 'spied1', {
value: noop1,
writable: true,
configurable: true,
enumerable: true
});
Object.defineProperty(subject, 'spied2', {
value: noop2,
writable: true,
configurable: true,
enumerable: true
});
var _spied3 = noop3;
Object.defineProperty(subject, 'spied3', {
configurable: true,
set: function (val) {
_spied3 = val;
},
get: function() {
return _spied3;
},
enumerable: true
});
subject.spied4 = noop4;
Object.defineProperty(subject, 'notSpied2', {
value: noop2,
writable: false,
configurable: true,
enumerable: true
});
Object.defineProperty(subject, 'notSpied3', {
value: noop3,
writable: true,
configurable: false,
enumerable: true
});
Object.defineProperty(subject, 'notSpied4', {
configurable: false,
set: function(val) { /**/ },
get: function() {
return noop4;
},
enumerable: true
});
Object.defineProperty(subject, 'notSpied5', {
value: noop5,
writable: true,
configurable: true,
enumerable: false
});
subject.notSpied6 = 6;
var spiedObject = spyRegistry.spyOnAllFunctions(subject);
expect(subject.notSpied1).toBe(noop1);
expect(subject.notSpied2).toBe(noop2);
expect(subject.notSpied3).toBe(noop3);
expect(subject.notSpied4).toBe(noop4);
expect(subject.notSpied5).toBe(noop5);
expect(subject.notSpied6).toBe(6);
expect(subject.spied1).toBe('I am a spy');
expect(subject.spied2).toBe('I am a spy');
expect(subject.spied3).toBe('I am a spy');
expect(subject.spied4).toBe('I am a spy');
expect(spiedObject).toBe(subject);
});
});
describe("#clearSpies", function() { describe("#clearSpies", function() {
it("restores the original functions on the spied-upon objects", function() { it("restores the original functions on the spied-upon objects", function() {
var spies = [], var spies = [],

View File

@@ -20,6 +20,18 @@ describe('Spies', function () {
expect(spy.bob).toEqual("test"); expect(spy.bob).toEqual("test");
}); });
it("should allow you to omit the name argument and only pass the originalFn argument", function() {
var fn = function test() {};
var spy = env.createSpy(fn);
// IE doesn't do `.name`
if (fn.name === "test") {
expect(spy.and.identity).toEqual("test");
} else {
expect(spy.and.identity).toEqual("unknown");
}
})
it("warns the user that we intend to overwrite an existing property", function() { it("warns the user that we intend to overwrite an existing property", function() {
TestClass.prototype.someFunction.and = "turkey"; TestClass.prototype.someFunction.and = "turkey";

View File

@@ -1,11 +1,14 @@
describe("StackTrace", function() { describe("StackTrace", function() {
it("understands Chrome/IE/Edge style traces", function() { it("understands Chrome/IE/Edge style traces", function() {
var raw = var error = {
'Error: nope\n' + message: 'nope',
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + stack:
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'; 'Error: nope\n' +
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(raw); var result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error: nope'); expect(result.message).toEqual('Error: nope');
expect(result.style).toEqual('v8'); expect(result.style).toEqual('v8');
@@ -25,13 +28,36 @@ describe("StackTrace", function() {
]); ]);
}); });
it("understands Chrome/IE/Edge style traces with multiline messages", function() {
var error = {
message: 'line 1\nline 2',
stack:
'Error: line 1\nline 2\n' +
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error: line 1\nline 2');
var rawFrames = result.frames.map(function(f) { return f.raw; });
expect(rawFrames).toEqual([
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)',
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)',
]);
});
it("understands Node style traces", function() { it("understands Node style traces", function() {
var raw = 'Error\n' + var error = {
' at /somewhere/jasmine/lib/jasmine-core/jasmine.js:4255:9\n' + message: 'nope',
' at QueueRunner.complete [as onComplete] (/somewhere/jasmine/lib/jasmine-core/jasmine.js:579:9)\n' + stack:
' at Immediate.<anonymous> (/somewhere/jasmine/lib/jasmine-core/jasmine.js:4314:12)\n' + 'Error\n' +
' at runCallback (timers.js:672:20)'; ' at /somewhere/jasmine/lib/jasmine-core/jasmine.js:4255:9\n' +
var result = new jasmineUnderTest.StackTrace(raw); ' at QueueRunner.complete [as onComplete] (/somewhere/jasmine/lib/jasmine-core/jasmine.js:579:9)\n' +
' at Immediate.<anonymous> (/somewhere/jasmine/lib/jasmine-core/jasmine.js:4314:12)\n' +
' at runCallback (timers.js:672:20)'
};
var result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toEqual('Error'); expect(result.message).toEqual('Error');
expect(result.style).toEqual('v8'); expect(result.style).toEqual('v8');
@@ -64,10 +90,13 @@ describe("StackTrace", function() {
}); });
it("understands Safari/Firefox/Phantom-OS X style traces", function() { it("understands Safari/Firefox/Phantom-OS X style traces", function() {
var raw = var error = {
'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' + message: 'nope',
'run@http://localhost:8888/__jasmine__/jasmine.js:4320:27'; stack:
var result = new jasmineUnderTest.StackTrace(raw); 'http://localhost:8888/__spec__/core/UtilSpec.js:115:28\n' +
'run@http://localhost:8888/__jasmine__/jasmine.js:4320:27'
};
var result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toBeFalsy(); expect(result.message).toBeFalsy();
expect(result.style).toEqual('webkit'); expect(result.style).toEqual('webkit');
@@ -88,20 +117,26 @@ describe("StackTrace", function() {
}); });
it("does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces", function() { it("does not mistake gibberish for Safari/Firefox/Phantom-OS X style traces", function() {
var raw = 'randomcharsnotincludingwhitespace'; var error = {
var result = new jasmineUnderTest.StackTrace(raw); message: 'nope',
stack: 'randomcharsnotincludingwhitespace'
};
var result = new jasmineUnderTest.StackTrace(error);
expect(result.style).toBeNull(); expect(result.style).toBeNull();
expect(result.frames).toEqual([ expect(result.frames).toEqual([
{ raw: raw } { raw: error.stack }
]); ]);
}); });
it("understands Phantom-Linux style traces", function() { it("understands Phantom-Linux style traces", function() {
var raw = var error = {
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + message: 'nope',
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'; stack:
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(raw); var result = new jasmineUnderTest.StackTrace(error);
expect(result.message).toBeFalsy(); expect(result.message).toBeFalsy();
expect(result.style).toEqual('v8'); expect(result.style).toEqual('v8');
@@ -122,10 +157,13 @@ describe("StackTrace", function() {
}); });
it("ignores blank lines", function() { it("ignores blank lines", function() {
var raw = var error = {
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n'; message: 'nope',
stack:
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n'
};
var result = new jasmineUnderTest.StackTrace(raw); var result = new jasmineUnderTest.StackTrace(error);
expect(result.frames).toEqual([ expect(result.frames).toEqual([
{ {
@@ -138,12 +176,15 @@ describe("StackTrace", function() {
}); });
it("omits properties except 'raw' for frames that are not understood", function() { it("omits properties except 'raw' for frames that are not understood", function() {
var raw = var error = {
' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' + message: 'nope',
' but this is quite unexpected\n' + stack:
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'; ' at UserContext.<anonymous> (http://localhost:8888/__spec__/core/UtilSpec.js:115:19)\n' +
' but this is quite unexpected\n' +
' at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)'
};
var result = new jasmineUnderTest.StackTrace(raw); var result = new jasmineUnderTest.StackTrace(error);
expect(result.style).toEqual('v8'); expect(result.style).toEqual('v8');
expect(result.frames).toEqual([ expect(result.frames).toEqual([
{ {

View File

@@ -297,7 +297,7 @@ describe("TreeProcessor", function() {
node.getResult.and.returnValue({ my: 'result' }); node.getResult.and.returnValue({ my: 'result' });
queueRunner.calls.mostRecent().args[0].onComplete(); queueRunner.calls.mostRecent().args[0].onComplete();
expect(nodeComplete).toHaveBeenCalledWith(node, { my: 'result' }, nodeDone); expect(nodeComplete).toHaveBeenCalledWith(node, { my: 'result' }, jasmine.any(Function));
}); });
it("runs a node with children", function() { it("runs a node with children", function() {
@@ -328,6 +328,37 @@ describe("TreeProcessor", function() {
expect(leaf2.execute).toHaveBeenCalledWith('bar', false); expect(leaf2.execute).toHaveBeenCalledWith('bar', false);
}); });
it("cascades errors up the tree", function() {
var leaf = new Leaf(),
node = new Node({ children: [leaf] }),
root = new Node({ children: [node] }),
queueRunner = jasmine.createSpy('queueRunner'),
nodeComplete = jasmine.createSpy('nodeComplete'),
processor = new jasmineUnderTest.TreeProcessor({
tree: root,
runnableIds: [node.id],
nodeComplete: nodeComplete,
queueRunnerFactory: queueRunner
}),
treeComplete = jasmine.createSpy('treeComplete'),
nodeDone = jasmine.createSpy('nodeDone');
processor.execute(treeComplete);
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
queueableFns[0].fn(nodeDone);
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
expect(queueableFns.length).toBe(2);
queueableFns[1].fn('foo');
expect(leaf.execute).toHaveBeenCalledWith('foo', false);
queueRunner.calls.mostRecent().args[0].onComplete('things');
expect(nodeComplete).toHaveBeenCalled();
nodeComplete.calls.mostRecent().args[2]();
expect(nodeDone).toHaveBeenCalledWith('things');
});
it("runs an excluded node with leaf", function() { it("runs an excluded node with leaf", function() {
var leaf1 = new Leaf(), var leaf1 = new Leaf(),
node = new Node({ children: [leaf1] }), node = new Node({ children: [leaf1] }),
@@ -361,7 +392,7 @@ describe("TreeProcessor", function() {
node.getResult.and.returnValue({ im: 'disabled' }); node.getResult.and.returnValue({ im: 'disabled' });
queueRunner.calls.mostRecent().args[0].onComplete(); queueRunner.calls.mostRecent().args[0].onComplete();
expect(nodeComplete).toHaveBeenCalledWith(node, { im: 'disabled' }, nodeDone); expect(nodeComplete).toHaveBeenCalledWith(node, { im: 'disabled' }, jasmine.any(Function));
}); });
it("runs beforeAlls for a node with children", function() { it("runs beforeAlls for a node with children", function() {

View File

@@ -940,10 +940,10 @@ describe("Env integration", function() {
}); });
it("Mock clock can be installed and used in tests", function(done) { it("Mock clock can be installed and used in tests", function(done) {
var globalSetTimeout = jasmine.createSpy('globalSetTimeout'), var globalSetTimeout = jasmine.createSpy('globalSetTimeout').and.callFake(function(cb, t) { setTimeout(cb, t); }),
delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'), delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'),
delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'), delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'),
env = new jasmineUnderTest.Env({global: { setTimeout: globalSetTimeout }}); env = new jasmineUnderTest.Env({global: { setTimeout: globalSetTimeout, clearTimeout: clearTimeout, setImmediate: function(cb) { setTimeout(cb, 0); } }});
var assertions = function() { var assertions = function() {
expect(delayedFunctionForMockClock).toHaveBeenCalled(); expect(delayedFunctionForMockClock).toHaveBeenCalled();
@@ -1005,6 +1005,25 @@ describe("Env integration", function() {
describe("with a mock clock", function() { describe("with a mock clock", function() {
var realSetTimeout; var realSetTimeout;
function createMockedEnv() {
// explicitly pass in timing functions so we can make sure that clear stack always works
// no matter how long the suite in the spec is
return new jasmineUnderTest.Env({ global: {
setTimeout: function(cb, t) {
var stack = jasmine.util.errorWithStack().stack;
if (stack.indexOf('ClearStack') >= 0) {
realSetTimeout(cb, t);
} else {
setTimeout(cb, t);
}
},
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
setImmediate: function(cb) { realSetTimeout(cb, 0); }
}});
}
beforeEach(function() { beforeEach(function() {
this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL; this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
realSetTimeout = setTimeout; realSetTimeout = setTimeout;
@@ -1019,7 +1038,7 @@ describe("Env integration", function() {
}); });
it("should wait a default interval before failing specs that haven't called done yet", function(done) { it("should wait a default interval before failing specs that haven't called done yet", function(done) {
var env = new jasmineUnderTest.Env(), var env = createMockedEnv(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]); reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]);
reporter.specDone.and.callFake(function(result) { reporter.specDone.and.callFake(function(result) {
@@ -1048,7 +1067,7 @@ describe("Env integration", function() {
}); });
it("should not use the mock clock for asynchronous timeouts", function(done){ it("should not use the mock clock for asynchronous timeouts", function(done){
var env = new jasmineUnderTest.Env(), var env = createMockedEnv(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]), reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]),
clock = env.clock; clock = env.clock;
@@ -1086,28 +1105,16 @@ describe("Env integration", function() {
}); });
it('should wait a custom interval before reporting async functions that fail to call done', function(done) { it('should wait a custom interval before reporting async functions that fail to call done', function(done) {
var env = new jasmineUnderTest.Env(), var env = createMockedEnv(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']), reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']);
timeoutFailure = (/^Error: Timeout - Async callback was not invoked within timeout specified by jasmine\.DEFAULT_TIMEOUT_INTERVAL\./);
reporter.specDone.and.callFake(function(r) { reporter.jasmineDone.and.callFake(function(r) {
realSetTimeout(function() { expect(r.failedExpectations).toEqual([]);
jasmine.clock().tick(1); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('suite beforeAll', [ /^Error: Timeout - Async callback was not invoked within 5000ms \(custom timeout\)/ ]);
}, 0); expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('suite afterAll', [ /^Error: Timeout - Async callback was not invoked within 2000ms \(custom timeout\)/ ]);
}); expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite beforeEach times out', [/^Error: Timeout - Async callback was not invoked within 1000ms \(custom timeout\)/]);
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite afterEach times out', [ /^Error: Timeout - Async callback was not invoked within 4000ms \(custom timeout\)/ ]);
reporter.suiteDone.and.callFake(function(r) { expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite it times out', [ /^Error: Timeout - Async callback was not invoked within 6000ms \(custom timeout\)/ ]);
realSetTimeout(function() {
jasmine.clock().tick(1);
}, 0);
});
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('suite beforeAll', [ timeoutFailure ]);
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable('suite afterAll', [ timeoutFailure ]);
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite beforeEach times out', [ timeoutFailure ]);
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite afterEach times out', [ timeoutFailure ]);
expect(reporter.specDone).toHaveFailedExpectationsForRunnable('suite it times out', [ timeoutFailure ]);
jasmine.clock().tick(1); jasmine.clock().tick(1);
realSetTimeout(done); realSetTimeout(done);
@@ -1616,7 +1623,7 @@ describe("Env integration", function() {
}); });
it("should be possible to get full name from a spec", function() { it("should be possible to get full name from a spec", function() {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
topLevelSpec, nestedSpec, doublyNestedSpec; topLevelSpec, nestedSpec, doublyNestedSpec;
env.describe("my tests", function() { env.describe("my tests", function() {
@@ -1638,7 +1645,7 @@ describe("Env integration", function() {
}); });
it("Custom equality testers should be per spec", function(done) { it("Custom equality testers should be per spec", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineDone", "jasmineDone",
"specDone" "specDone"
@@ -1672,7 +1679,7 @@ describe("Env integration", function() {
}); });
it("Custom equality testers should be per suite", function(done) { it("Custom equality testers should be per suite", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineDone", "jasmineDone",
"specDone" "specDone"
@@ -1715,7 +1722,7 @@ describe("Env integration", function() {
}); });
it("Custom equality testers for toContain should be per spec", function(done) { it("Custom equality testers for toContain should be per spec", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineDone", "jasmineDone",
"specDone" "specDone"
@@ -1766,7 +1773,7 @@ describe("Env integration", function() {
}); });
it("Custom equality testers for toContain should be per suite", function(done) { it("Custom equality testers for toContain should be per suite", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineDone", "jasmineDone",
"specDone" "specDone"
@@ -1809,7 +1816,7 @@ describe("Env integration", function() {
}); });
it("Custom matchers should be per spec", function(done) { it("Custom matchers should be per spec", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
matchers = { matchers = {
toFoo: function() {} toFoo: function() {}
}; };
@@ -1831,7 +1838,7 @@ describe("Env integration", function() {
}); });
it("Custom matchers should be per suite", function(done) { it("Custom matchers should be per suite", function(done) {
var env = new jasmineUnderTest.Env({global: { setTimeout: setTimeout }}), var env = new jasmineUnderTest.Env(),
matchers = { matchers = {
toFoo: function() {} toFoo: function() {}
}; };
@@ -2406,4 +2413,106 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
it('supports async matchers', function(done) {
jasmine.getEnv().requirePromises();
var env = new jasmineUnderTest.Env(),
specDone = jasmine.createSpy('specDone'),
suiteDone = jasmine.createSpy('suiteDone');
env.addReporter({
specDone: specDone,
suiteDone: suiteDone,
jasmineDone: function(result) {
expect(result.failedExpectations).toEqual([jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
})]);
expect(specDone).toHaveBeenCalledWith(jasmine.objectContaining({
description: 'has an async failure',
failedExpectations: [jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
})]
}));
expect(suiteDone).toHaveBeenCalledWith(jasmine.objectContaining({
description: 'a suite',
failedExpectations: [jasmine.objectContaining({
message: 'Expected a promise to be rejected.'
})]
}));
done();
}
});
function fail(innerDone) {
var resolve;
var p = new Promise(function(res, rej) { resolve = res });
env.expectAsync(p).toBeRejected().then(innerDone);
resolve();
}
env.afterAll(fail);
env.describe('a suite', function() {
env.afterAll(fail);
env.it('has an async failure', fail);
});
env.execute();
});
it('provides custom equality testers to async matchers', function(done) {
jasmine.getEnv().requirePromises();
var env = new jasmineUnderTest.Env(),
specDone = jasmine.createSpy('specDone');
env.addReporter({
specDone: specDone,
jasmineDone: function() {
expect(specDone).toHaveBeenCalledWith(jasmine.objectContaining({
description: 'has an async failure',
failedExpectations: []
}));
done();
}
});
env.it('has an async failure', function() {
env.addCustomEqualityTester(function() { return true; });
var p = Promise.resolve('something');
return env.expectAsync(p).toBeResolvedTo('something else');
});
env.execute();
});
it('includes useful stack frames in async matcher failures', function(done) {
jasmine.getEnv().requirePromises();
var env = new jasmineUnderTest.Env(),
specDone = jasmine.createSpy('specDone');
env.addReporter({
specDone: specDone,
jasmineDone: function() {
expect(specDone).toHaveBeenCalledWith(jasmine.objectContaining({
failedExpectations: [jasmine.objectContaining({
stack: jasmine.stringMatching('EnvSpec.js')
})]
}));
done();
}
});
env.it('has an async failure', function() {
env.addCustomEqualityTester(function() { return true; });
var p = Promise.resolve();
return env.expectAsync(p).toBeRejected();
});
env.execute();
});
}); });

View File

@@ -952,13 +952,17 @@ describe("spec running", function () {
it("does not run further specs when one fails", function(done) { it("does not run further specs when one fails", function(done) {
var actions = []; var actions = [];
env.it('fails', function() { env.describe('wrapper', function() {
actions.push('fails'); env.it('fails', function() {
env.expect(1).toBe(2); actions.push('fails');
env.expect(1).toBe(2);
});
}); });
env.it('does not run', function() { env.describe('holder', function() {
actions.push('does not run'); env.it('does not run', function() {
actions.push('does not run');
});
}); });
env.randomizeTests(false); env.randomizeTests(false);

View File

@@ -570,50 +570,67 @@ describe("toEqual", function() {
expect(compareEquals(actual, expected).pass).toBe(true); expect(compareEquals(actual, expected).pass).toBe(true);
}); });
function isNotRunningInBrowser() { describe('DOM nodes', function() {
return typeof document === 'undefined' function isNotRunningInBrowser() {
} return typeof document === 'undefined'
it("reports mismatches between DOM nodes with different tags", function() {
if(isNotRunningInBrowser()) {
return;
} }
var actual = {a: document.createElement('div')}, beforeEach(function(done) {
expected = {a: document.createElement('p')}, this.nonBrowser = isNotRunningInBrowser();
if (this.nonBrowser) {
var jsdom = require('jsdom');
var self = this;
jsdom.env('', function(err, win) {
if (err) {
done.fail(err);
} else {
jasmineUnderTest.getGlobal().Node = win.Node;
self.doc = win.document;
done();
}
});
} else {
this.doc = document;
done();
}
});
afterEach(function() {
if (this.nonBrowser) {
delete jasmineUnderTest.getGlobal().Node;
}
});
it("reports mismatches between DOM nodes with different tags", function() {
var actual = {a: this.doc.createElement('div')},
expected = {a: this.doc.createElement('p')},
message = 'Expected $.a = <div> to equal <p>.'; message = 'Expected $.a = <div> to equal <p>.';
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
}); });
it('reports mismatches between DOM nodes with different content', function() { it('reports mismatches between DOM nodes with different content', function() {
if(isNotRunningInBrowser()) { var nodeA = this.doc.createElement('div'),
return; nodeB = this.doc.createElement('div');
}
var nodeA = document.createElement('div'), nodeA.setAttribute('thing', 'foo');
nodeB = document.createElement('div'); nodeB.setAttribute('thing', 'bar');
nodeA.innerText = 'foo'; expect(nodeA.isEqualNode(nodeB)).toBe(false);
nodeB.innerText = 'bar'; var actual = {a: nodeA},
var actual = {a: nodeA},
expected = {a: nodeB}, expected = {a: nodeB},
message = 'Expected $.a = <div>...</div> to equal <div>...</div>.'; message = 'Expected $.a = <div thing="foo"> to equal <div thing="bar">.';
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
}); });
it("reports mismatches between a DOM node and a bare Object", function() { it("reports mismatches between a DOM node and a bare Object", function() {
if(isNotRunningInBrowser()) { var actual = {a: this.doc.createElement('div')},
return;
}
var actual = {a: document.createElement('div')},
expected = {a: {}}, expected = {a: {}},
message = 'Expected $.a = <div> to equal Object({ }).'; message = 'Expected $.a = <div> to equal Object({ }).';
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
});
}); });
it("reports asymmetric mismatches", function() { it("reports asymmetric mismatches", function() {
@@ -700,7 +717,7 @@ describe("toEqual", function() {
var actual = [1, 1, 2, 3, 5], var actual = [1, 1, 2, 3, 5],
expected = [1, 1, 2, 3], expected = [1, 1, 2, 3],
message = 'Expected $.length = 5 to equal 4.\n' + message = 'Expected $.length = 5 to equal 4.\n' +
'Expected $[4] = 5 to equal undefined.'; 'Unexpected $[4] = 5 in array.';
expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
@@ -716,6 +733,37 @@ describe("toEqual", function() {
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
}); });
it("undefined in middle of actual array", function() {
var actual = [1, void 0, 3],
expected = [1, 2, 3],
message = 'Expected $[1] = undefined to equal 2.';
expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("undefined in middle of expected array", function() {
var actual = [1, 2, 3],
expected = [1, void 0, 3],
message = 'Expected $[1] = 2 to equal undefined.';
expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("actual array is longer by 4 elements", function() {
var actual = [1, 1, 2, 3, 5, 8, 13],
expected = [1, 1, 2],
message = 'Expected $.length = 7 to equal 3.\n' +
'Unexpected $[3] = 3 in array.\n' +
'Unexpected $[4] = 5 in array.\n' +
'Unexpected $[5] = 8 in array.\n' +
'Unexpected $[6] = 13 in array.';
expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("expected array is longer by 4 elements", function() { it("expected array is longer by 4 elements", function() {
var actual = [1, 1, 2], var actual = [1, 1, 2],
expected = [1, 1, 2, 3, 5, 8, 13], expected = [1, 1, 2, 3, 5, 8, 13],
@@ -740,21 +788,41 @@ describe("toEqual", function() {
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
}); });
it("object with nested array", function() { it("object with nested array (actual longer than expected)", function() {
var actual = { values: [1, 1, 2, 3] }, var actual = { values: [1, 1, 2, 3] },
expected = { values: [1, 1, 2] }, expected = { values: [1, 1, 2] },
message = 'Expected $.values.length = 4 to equal 3.\n' + message = 'Expected $.values.length = 4 to equal 3.\n' +
'Expected $.values[3] = 3 to equal undefined.'; 'Unexpected $.values[3] = 3 in array.';
expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
}); });
it("array with nested object", function() { it("object with nested array (expected longer than actual)", function() {
var actual = { values: [1, 1, 2] },
expected = { values: [1, 1, 2, 3] },
message = 'Expected $.values.length = 3 to equal 4.\n' +
'Expected $.values[3] = undefined to equal 3.';
expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("array with unexpected nested object", function() {
var actual = [1, 1, 2, { value: 3 }], var actual = [1, 1, 2, { value: 3 }],
expected = [1, 1, 2], expected = [1, 1, 2],
message = 'Expected $.length = 4 to equal 3.\n' + message = 'Expected $.length = 4 to equal 3.\n' +
'Expected $[3] = Object({ value: 3 }) to equal undefined.'; 'Unexpected $[3] = Object({ value: 3 }) in array.';
expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("array with missing nested object", function() {
var actual = [1, 1, 2],
expected = [1, 1, 2, { value: 3 }],
message = 'Expected $.length = 3 to equal 4.\n' +
'Expected $[3] = undefined to equal Object({ value: 3 }).';
expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);
@@ -767,7 +835,7 @@ describe("toEqual", function() {
'Expected $[0][1] = undefined to equal 1.\n' + 'Expected $[0][1] = undefined to equal 1.\n' +
'Expected $[1].length = 2 to equal 1.\n' + 'Expected $[1].length = 2 to equal 1.\n' +
'Expected $[1][0] = 1 to equal 2.\n' + 'Expected $[1][0] = 1 to equal 2.\n' +
'Expected $[1][1] = 2 to equal undefined.'; 'Unexpected $[1][1] = 2 in array.';
expect(compareEquals(actual, expected).pass).toBe(false); expect(compareEquals(actual, expected).pass).toBe(false);
expect(compareEquals(actual, expected).message).toEqual(message); expect(compareEquals(actual, expected).message).toEqual(message);

8
spec/helpers/promises.js Normal file
View File

@@ -0,0 +1,8 @@
(function(env) {
env.requirePromises = function() {
if (typeof Promise !== 'function') {
env.pending("Environment does not support promises");
}
};
})(jasmine.getEnv());

View File

@@ -103,7 +103,6 @@ describe("HtmlReporter", function() {
createTextNode: function() { return document.createTextNode.apply(document, arguments); } createTextNode: function() { return document.createTextNode.apply(document, arguments); }
}); });
reporter.initialize(); reporter.initialize();
reporter.specDone({id: 789, status: "excluded", fullName: "symbols should have titles", passedExpectations: [], failedExpectations: []}); reporter.specDone({id: 789, status: "excluded", fullName: "symbols should have titles", passedExpectations: [], failedExpectations: []});
var specEl = container.querySelector('.jasmine-symbol-summary li'); var specEl = container.querySelector('.jasmine-symbol-summary li');
@@ -696,7 +695,85 @@ describe("HtmlReporter", function() {
expect(navigateHandler).toHaveBeenCalledWith('throwFailures', false); expect(navigateHandler).toHaveBeenCalledWith('throwFailures', false);
}); });
}); });
describe("UI for hiding disabled specs", function() {
it("should be unchecked if not hiding disabled specs", function() {
var env = new jasmineUnderTest.Env(),
container = document.createElement("div"),
getContainer = function() {
return container;
},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() {
return document.createElement.apply(document, arguments);
},
createTextNode: function() {
return document.createTextNode.apply(document, arguments);
}
});
env.hideDisabled(false);
reporter.initialize();
reporter.jasmineDone({});
var disabledUI = container.querySelector(".jasmine-disabled");
expect(disabledUI.checked).toBe(false);
});
it("should be checked if hiding disabled", function() {
var env = new jasmineUnderTest.Env(),
container = document.createElement("div"),
getContainer = function() {
return container;
},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() {
return document.createElement.apply(document, arguments);
},
createTextNode: function() {
return document.createTextNode.apply(document, arguments);
}
});
env.hideDisabled(true);
reporter.initialize();
reporter.jasmineDone({});
var disabledUI = container.querySelector(".jasmine-disabled");
expect(disabledUI.checked).toBe(true);
});
it("should not display specs that have been disabled", function() {
var env = new jasmineUnderTest.Env(),
container = document.createElement('div'),
getContainer = function() {return container;},
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
env.hideDisabled(true);
reporter.initialize();
reporter.specDone({
id: 789,
status: "excluded",
fullName: "symbols should have titles",
passedExpectations: [],
failedExpectations: []
});
var specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute("class")).toEqual("jasmine-excluded-no-display");
});
});
describe("UI for running tests in random order", function() { describe("UI for running tests in random order", function() {
it("should be unchecked if not randomizing", function() { it("should be unchecked if not randomizing", function() {
var env = new jasmineUnderTest.Env(), var env = new jasmineUnderTest.Env(),

View File

@@ -24,4 +24,11 @@ describe("jasmineUnderTest.pp (HTML Dependent)", function () {
expect(jasmineUnderTest.pp(err)).toMatch(/Not enough arguments/); expect(jasmineUnderTest.pp(err)).toMatch(/Not enough arguments/);
} }
}); });
it("should stringify HTML element with text and attributes", function() {
var el = document.createElement('div');
el.setAttribute('things', 'foo');
el.innerHTML = 'foo';
expect(jasmineUnderTest.pp(el)).toEqual('<div things="foo">...</div>');
});
}); });

View File

@@ -11,6 +11,7 @@
"helpers/checkForSymbol.js", "helpers/checkForSymbol.js",
"helpers/checkForTypedArrays.js", "helpers/checkForTypedArrays.js",
"helpers/integrationMatchers.js", "helpers/integrationMatchers.js",
"helpers/promises.js",
"helpers/nodeDefineJasmineUnderTest.js" "helpers/nodeDefineJasmineUnderTest.js"
], ],
"random": true "random": true

View File

@@ -24,6 +24,7 @@ helpers:
- 'helpers/checkForSymbol.js' - 'helpers/checkForSymbol.js'
- 'helpers/checkForTypedArrays.js' - 'helpers/checkForTypedArrays.js'
- 'helpers/integrationMatchers.js' - 'helpers/integrationMatchers.js'
- 'helpers/promises.js'
- 'helpers/defineJasmineUnderTest.js' - 'helpers/defineJasmineUnderTest.js'
spec_files: spec_files:
- '**/*[Ss]pec.js' - '**/*[Ss]pec.js'

View File

@@ -0,0 +1,153 @@
getJasmineRequireObj().AsyncExpectation = function(j$) {
var promiseForMessage = {
jasmineToString: function() { return 'a promise'; }
};
/**
* Asynchronous matchers.
* @namespace async-matchers
*/
function AsyncExpectation(options) {
var global = options.global || j$.getGlobal();
this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || [];
this.addExpectationResult = options.addExpectationResult || function(){};
this.actual = options.actual;
this.isNot = options.isNot;
if (!global.Promise) {
throw new Error('expectAsync is unavailable because the environment does not support promises.');
}
if (!j$.isPromise(this.actual)) {
throw new Error('Expected expectAsync to be called with a promise.');
}
['toBeResolved', 'toBeRejected', 'toBeResolvedTo'].forEach(wrapCompare.bind(this));
}
function wrapCompare(name) {
var compare = this[name];
this[name] = function() {
var self = this;
var args = Array.prototype.slice.call(arguments);
args.unshift(this.actual);
// Capture the call stack here, before we go async, so that it will
// contain frames that are relevant to the user instead of just parts
// of Jasmine.
var errorForStack = j$.util.errorWithStack();
return compare.apply(self, args).then(function(result) {
var message;
if (self.isNot) {
result.pass = !result.pass;
}
args[0] = promiseForMessage;
message = j$.Expectation.finalizeMessage(self.util, name, self.isNot, args, result);
self.addExpectationResult(result.pass, {
matcherName: name,
passed: result.pass,
message: message,
error: undefined,
errorForStack: errorForStack,
actual: self.actual
});
});
};
}
/**
* Expect a promise to be resolved.
* @function
* @async
* @name async-matchers#toBeResolved
* @example
* await expectAsync(aPromise).toBeResolved();
* @example
* return expectAsync(aPromise).toBeResolved();
*/
AsyncExpectation.prototype.toBeResolved = function(actual) {
return actual.then(
function() { return {pass: true}; },
function() { return {pass: false}; }
);
};
/**
* Expect a promise to be rejected.
* @function
* @async
* @name async-matchers#toBeRejected
* @example
* await expectAsync(aPromise).toBeRejected();
* @example
* return expectAsync(aPromise).toBeRejected();
*/
AsyncExpectation.prototype.toBeRejected = function(actual) {
return actual.then(
function() { return {pass: false}; },
function() { return {pass: true}; }
);
};
/**
* Expect a promise to be resolved to a value equal to the expected, using deep equality comparison.
* @function
* @async
* @name async-matchers#toBeResolvedTo
* @param {Object} expected - Value that the promise is expected to resolve to
* @example
* await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
* @example
* return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
*/
AsyncExpectation.prototype.toBeResolvedTo = function(actualPromise, expectedValue) {
var self = this;
function prefix(passed) {
return 'Expected a promise ' +
(passed ? 'not ' : '') +
'to be resolved to ' + j$.pp(expectedValue);
}
return actualPromise.then(
function(actualValue) {
if (self.util.equals(actualValue, expectedValue, self.customEqualityTesters)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
return {
pass: false,
message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
};
}
},
function() {
return {
pass: false,
message: prefix(false) + ' but it was rejected.'
};
}
);
};
AsyncExpectation.factory = function(options) {
var expect = new AsyncExpectation(options);
options = j$.util.clone(options);
options.isNot = true;
expect.not = new AsyncExpectation(options);
return expect;
};
return AsyncExpectation;
};

View File

@@ -1,5 +1,6 @@
getJasmineRequireObj().Clock = function() { getJasmineRequireObj().Clock = function() {
/* global process */
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string'; var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
/** /**

View File

@@ -13,9 +13,9 @@ getJasmineRequireObj().Env = function(j$) {
var totalSpecsDefined = 0; var totalSpecsDefined = 0;
var realSetTimeout = j$.getGlobal().setTimeout; var realSetTimeout = global.setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout; var realClearTimeout = global.clearTimeout;
var clearStack = j$.getClearStack(j$.getGlobal()); var clearStack = j$.getClearStack(global);
this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global)); this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
var runnableResources = {}; var runnableResources = {};
@@ -26,6 +26,7 @@ getJasmineRequireObj().Env = function(j$) {
var throwOnExpectationFailure = false; var throwOnExpectationFailure = false;
var stopOnSpecFailure = false; var stopOnSpecFailure = false;
var random = true; var random = true;
var hidingDisabled = false;
var seed = null; var seed = null;
var handlingLoadErrors = true; var handlingLoadErrors = true;
var hasFailures = false; var hasFailures = false;
@@ -39,7 +40,7 @@ getJasmineRequireObj().Env = function(j$) {
}; };
var globalErrors = null; var globalErrors = null;
var installGlobalErrors = function() { var installGlobalErrors = function() {
if (globalErrors) { if (globalErrors) {
return; return;
@@ -116,6 +117,19 @@ getJasmineRequireObj().Env = function(j$) {
} }
}; };
var asyncExpectationFactory = function(actual, spec) {
return j$.AsyncExpectation.factory({
util: j$.matchersUtil,
customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
actual: actual,
addExpectationResult: addExpectationResult
});
function addExpectationResult(passed, result) {
return spec.addExpectationResult(passed, result);
}
};
var defaultResourcesForRunnable = function(id, parentRunnableId) { var defaultResourcesForRunnable = function(id, parentRunnableId) {
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}}; var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}};
@@ -174,6 +188,13 @@ getJasmineRequireObj().Env = function(j$) {
var maximumSpecCallbackDepth = 20; var maximumSpecCallbackDepth = 20;
var currentSpecCallbackDepth = 0; var currentSpecCallbackDepth = 0;
/**
* Sets whether Jasmine should throw an Error when an expectation fails.
* This causes a spec to only have one expectation failure.
* @name Env#throwOnExpectationFailure
* @function
* @param {Boolean} value Whether to throw when a expectation fails
*/
this.throwOnExpectationFailure = function(value) { this.throwOnExpectationFailure = function(value) {
throwOnExpectationFailure = !!value; throwOnExpectationFailure = !!value;
}; };
@@ -182,6 +203,12 @@ getJasmineRequireObj().Env = function(j$) {
return throwOnExpectationFailure; return throwOnExpectationFailure;
}; };
/**
* Set whether to stop suite execution when a spec fails
* @name Env#stopOnSpecFailure
* @function
* @param {Boolean} value Whether to stop suite execution when a spec fails
*/
this.stopOnSpecFailure = function(value) { this.stopOnSpecFailure = function(value) {
stopOnSpecFailure = !!value; stopOnSpecFailure = !!value;
}; };
@@ -190,6 +217,12 @@ getJasmineRequireObj().Env = function(j$) {
return stopOnSpecFailure; return stopOnSpecFailure;
}; };
/**
* Set whether to randomize test execution order
* @name Env#randomizeTests
* @function
* @param {Boolean} value Whether to randomize execution order
*/
this.randomizeTests = function(value) { this.randomizeTests = function(value) {
random = !!value; random = !!value;
}; };
@@ -198,6 +231,12 @@ getJasmineRequireObj().Env = function(j$) {
return random; return random;
}; };
/**
* Set the random number seed for spec randomization
* @name Env#seed
* @function
* @param {Number} value The seed value
*/
this.seed = function(value) { this.seed = function(value) {
if (value) { if (value) {
seed = value; seed = value;
@@ -205,6 +244,18 @@ getJasmineRequireObj().Env = function(j$) {
return seed; return seed;
}; };
this.hidingDisabled = function(value) {
return hidingDisabled;
};
/**
* @name Env#hideDisabled
* @function
*/
this.hideDisabled = function(value) {
hidingDisabled = !!value;
};
this.deprecated = function(deprecation) { this.deprecated = function(deprecation) {
var runnable = currentRunnable() || topSuite; var runnable = currentRunnable() || topSuite;
runnable.addDeprecationWarning(deprecation); runnable.addDeprecationWarning(deprecation);
@@ -238,6 +289,7 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSuiteId(), id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite', description: 'Jasmine__TopLevel__Suite',
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
expectationResultFactory: expectationResultFactory expectationResultFactory: expectationResultFactory
}); });
defaultResourcesForRunnable(topSuite.id); defaultResourcesForRunnable(topSuite.id);
@@ -250,6 +302,7 @@ getJasmineRequireObj().Env = function(j$) {
/** /**
* This represents the available reporter callback for an object passed to {@link Env#addReporter}. * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
* @interface Reporter * @interface Reporter
* @see custom_reporter
*/ */
var reporter = new j$.ReportDispatcher([ var reporter = new j$.ReportDispatcher([
/** /**
@@ -259,6 +312,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'jasmineStarted', 'jasmineStarted',
/** /**
@@ -268,6 +322,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running. * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'jasmineDone', 'jasmineDone',
/** /**
@@ -277,6 +332,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SuiteResult} result Information about the individual {@link describe} being run * @param {SuiteResult} result Information about the individual {@link describe} being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'suiteStarted', 'suiteStarted',
/** /**
@@ -288,6 +344,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SuiteResult} result * @param {SuiteResult} result
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'suiteDone', 'suiteDone',
/** /**
@@ -297,6 +354,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SpecResult} result Information about the individual {@link it} being run * @param {SpecResult} result Information about the individual {@link it} being run
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'specStarted', 'specStarted',
/** /**
@@ -308,6 +366,7 @@ getJasmineRequireObj().Env = function(j$) {
* @param {SpecResult} result * @param {SpecResult} result
* @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
* @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion. * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
* @see async
*/ */
'specDone' 'specDone'
], queueRunnerFactory); ], queueRunnerFactory);
@@ -396,8 +455,8 @@ getJasmineRequireObj().Env = function(j$) {
/** /**
* Information passed to the {@link Reporter#jasmineDone} event. * Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo * @typedef JasmineDoneInfo
* @property {OverallStatus} - The overall result of the sute: 'passed', 'failed', or 'incomplete'. * @property {OverallStatus} overallStatus - The overall result of the sute: 'passed', 'failed', or 'incomplete'.
* @property {IncompleteReason} - Explanation of why the suite was incimplete. * @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 {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[]} 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. * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
@@ -424,10 +483,22 @@ getJasmineRequireObj().Env = function(j$) {
reporter.addReporter(reporterToAdd); reporter.addReporter(reporterToAdd);
}; };
/**
* Provide a fallback reporter if no other reporters have been specified.
* @name Env#provideFallbackReporter
* @function
* @param {Reporter} reporterToAdd The reporter
* @see custom_reporter
*/
this.provideFallbackReporter = function(reporterToAdd) { this.provideFallbackReporter = function(reporterToAdd) {
reporter.provideFallbackReporter(reporterToAdd); reporter.provideFallbackReporter(reporterToAdd);
}; };
/**
* Clear all registered reporters
* @name Env#clearReporters
* @function
*/
this.clearReporters = function() { this.clearReporters = function() {
reporter.clearReporters(); reporter.clearReporters();
}; };
@@ -466,7 +537,16 @@ getJasmineRequireObj().Env = function(j$) {
return spyRegistry.spyOnProperty.apply(spyRegistry, arguments); return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
}; };
this.spyOnAllFunctions = function() {
return spyRegistry.spyOnAllFunctions.apply(spyRegistry, arguments);
};
this.createSpy = function(name, originalFn) { this.createSpy = function(name, originalFn) {
if (arguments.length === 1 && j$.isFunction_(name)) {
originalFn = name;
name = originalFn.name;
}
return spyFactory.createSpy(name, originalFn); return spyFactory.createSpy(name, originalFn);
}; };
@@ -500,6 +580,7 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
parentSuite: currentDeclarationSuite, parentSuite: currentDeclarationSuite,
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
throwOnExpectationFailure: throwOnExpectationFailure throwOnExpectationFailure: throwOnExpectationFailure
}); });
@@ -593,6 +674,7 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSpecId(), id: getNextSpecId(),
beforeAndAfterFns: beforeAndAfterFns(suite), beforeAndAfterFns: beforeAndAfterFns(suite),
expectationFactory: expectationFactory, expectationFactory: expectationFactory,
asyncExpectationFactory: asyncExpectationFactory,
resultCallback: specResultCallback, resultCallback: specResultCallback,
getSpecName: function(spec) { getSpecName: function(spec) {
return getSpecName(spec, suite); return getSpecName(spec, suite);
@@ -604,7 +686,7 @@ getJasmineRequireObj().Env = function(j$) {
userContext: function() { return suite.clonedSharedUserContext(); }, userContext: function() { return suite.clonedSharedUserContext(); },
queueableFn: { queueableFn: {
fn: fn, fn: fn,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}, },
throwOnExpectationFailure: throwOnExpectationFailure throwOnExpectationFailure: throwOnExpectationFailure
}); });
@@ -674,12 +756,20 @@ getJasmineRequireObj().Env = function(j$) {
return currentRunnable().expect(actual); return currentRunnable().expect(actual);
}; };
this.expectAsync = function(actual) {
if (!currentRunnable()) {
throw new Error('\'expectAsync\' was used when there was no current spec, this could be because an asynchronous test timed out');
}
return currentRunnable().expectAsync(actual);
};
this.beforeEach = function(beforeEachFunction, timeout) { this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsNotNested('beforeEach'); ensureIsNotNested('beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach'); ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({ currentDeclarationSuite.beforeEach({
fn: beforeEachFunction, fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -688,7 +778,7 @@ getJasmineRequireObj().Env = function(j$) {
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll'); ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({ currentDeclarationSuite.beforeAll({
fn: beforeAllFunction, fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -698,7 +788,7 @@ getJasmineRequireObj().Env = function(j$) {
afterEachFunction.isCleanup = true; afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({ currentDeclarationSuite.afterEach({
fn: afterEachFunction, fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -707,7 +797,7 @@ getJasmineRequireObj().Env = function(j$) {
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll'); ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({ currentDeclarationSuite.afterAll({
fn: afterAllFunction, fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } timeout: timeout || 0
}); });
}; };
@@ -729,11 +819,11 @@ getJasmineRequireObj().Env = function(j$) {
message += ': '; message += ': ';
if (error.message) { if (error.message) {
message += error.message; message += error.message;
} else if (jasmine.isString_(error)) { } else if (j$.isString_(error)) {
message += error; message += error;
} else { } else {
// pretty print all kind of objects. This includes arrays. // pretty print all kind of objects. This includes arrays.
message += jasmine.pp(error); message += j$.pp(error);
} }
} }

View File

@@ -27,7 +27,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
return null; return null;
} }
var stackTrace = new j$.StackTrace(error.stack); var stackTrace = new j$.StackTrace(error);
var lines = filterJasmine(stackTrace); var lines = filterJasmine(stackTrace);
var result = ''; var result = '';

View File

@@ -21,7 +21,7 @@ getJasmineRequireObj().Expectation = function() {
return function() { return function() {
var args = Array.prototype.slice.call(arguments, 0), var args = Array.prototype.slice.call(arguments, 0),
expected = args.slice(0), expected = args.slice(0),
message = ''; message;
args.unshift(this.actual); args.unshift(this.actual);
@@ -39,20 +39,7 @@ getJasmineRequireObj().Expectation = function() {
} }
var result = matcherCompare.apply(null, args); var result = matcherCompare.apply(null, args);
message = Expectation.finalizeMessage(this.util, name, this.isNot, args, result);
if (!result.pass) {
if (!result.message) {
args.unshift(this.isNot);
args.unshift(name);
message = this.util.buildFailureMessage.apply(null, args);
} else {
if (Object.prototype.toString.apply(result.message) === '[object Function]') {
message = result.message();
} else {
message = result.message;
}
}
}
if (expected.length == 1) { if (expected.length == 1) {
expected = expected[0]; expected = expected[0];
@@ -73,6 +60,23 @@ getJasmineRequireObj().Expectation = function() {
}; };
}; };
Expectation.finalizeMessage = function(util, name, isNot, args, result) {
if (result.pass) {
return '';
} else if (result.message) {
if (Object.prototype.toString.apply(result.message) === '[object Function]') {
return result.message();
} else {
return result.message;
}
} else {
args = args.slice();
args.unshift(isNot);
args.unshift(name);
return util.buildFailureMessage.apply(null, args);
}
};
Expectation.addCoreMatchers = function(matchers) { Expectation.addCoreMatchers = function(matchers) {
var prototype = Expectation.prototype; var prototype = Expectation.prototype;
for (var matcherName in matchers) { for (var matcherName in matchers) {

View File

@@ -45,7 +45,9 @@ getJasmineRequireObj().buildExpectationResult = function() {
var error = options.error; var error = options.error;
if (!error) { if (!error) {
if (options.stack) { if (options.errorForStack) {
error = options.errorForStack;
} else if (options.stack) {
error = options; error = options;
} else { } else {
try { try {

View File

@@ -13,18 +13,29 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
} }
}; };
this.originalHandlers = {};
this.installOne_ = function installOne_(errorType) {
this.originalHandlers[errorType] = global.process.listeners(errorType);
global.process.removeAllListeners(errorType);
global.process.on(errorType, onerror);
this.uninstall = function uninstall() {
var errorTypes = Object.keys(this.originalHandlers);
for (var iType = 0; iType < errorTypes.length; iType++) {
var errorType = errorTypes[iType];
global.process.removeListener(errorType, onerror);
for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
global.process.on(errorType, this.originalHandlers[errorType][i]);
}
delete this.originalHandlers[errorType];
}
};
};
this.install = function install() { this.install = function install() {
if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) { if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
var originalHandlers = global.process.listeners('uncaughtException'); this.installOne_('uncaughtException');
global.process.removeAllListeners('uncaughtException'); this.installOne_('unhandledRejection');
global.process.on('uncaughtException', onerror);
this.uninstall = function uninstall() {
global.process.removeListener('uncaughtException', onerror);
for (var i = 0; i < originalHandlers.length; i++) {
global.process.on('uncaughtException', originalHandlers[i]);
}
};
} else { } else {
var originalHandler = global.onerror; var originalHandler = global.onerror;
global.onerror = onerror; global.onerror = onerror;

View File

@@ -233,8 +233,8 @@ getJasmineRequireObj().pp = function(j$) {
if (el.innerHTML === '') { if (el.innerHTML === '') {
this.append(el.outerHTML.replace(closingTag, '')); this.append(el.outerHTML.replace(closingTag, ''));
} else { } else {
var tagEnd = el.outerHTML.indexOf(el.innerHTML); var tagEnd = el.outerHTML.indexOf('>');
this.append(el.outerHTML.substring(0, tagEnd)); this.append(el.outerHTML.substring(0, tagEnd + 1));
this.append('...' + closingTag); this.append('...' + closingTag);
} }
}; };

View File

@@ -105,12 +105,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.globalErrors.pushListener(handleError); self.globalErrors.pushListener(handleError);
if (queueableFn.timeout) { if (queueableFn.timeout !== undefined) {
var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
timeoutId = self.setTimeout(function() { timeoutId = self.setTimeout(function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'); var error = new Error(
'Timeout - Async callback was not invoked within ' + timeoutInterval + 'ms ' +
(queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
);
onException(error); onException(error);
next(); next();
}, queueableFn.timeout()); }, timeoutInterval);
} }
try { try {
@@ -159,7 +163,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return; return;
} }
self.errored = result.errored; self.errored = self.errored || result.errored;
if (this.completeOnFirstError && result.errored) { if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex); this.skipToCleanup(iterativeIndex);

View File

@@ -1,6 +1,7 @@
getJasmineRequireObj().Spec = function(j$) { getJasmineRequireObj().Spec = function(j$) {
function Spec(attrs) { function Spec(attrs) {
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.resultCallback = attrs.resultCallback || function() {}; this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id; this.id = attrs.id;
this.description = attrs.description || ''; this.description = attrs.description || '';
@@ -57,6 +58,10 @@ getJasmineRequireObj().Spec = function(j$) {
return this.expectationFactory(actual, this); return this.expectationFactory(actual, this);
}; };
Spec.prototype.expectAsync = function(actual) {
return this.asyncExpectationFactory(actual, this);
};
Spec.prototype.execute = function(onComplete, excluded) { Spec.prototype.execute = function(onComplete, excluded) {
var self = this; var self = this;
@@ -177,5 +182,6 @@ getJasmineRequireObj().Spec = function(j$) {
}; };
if (typeof window == void 0 && typeof exports == 'object') { if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Spec = jasmineRequire.Spec; exports.Spec = jasmineRequire.Spec;
} }

View File

@@ -120,6 +120,23 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
return spy; return spy;
}; };
this.spyOnAllFunctions = function(obj) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOnAllFunctions could not find an object to spy upon');
}
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] instanceof Function) {
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
if ((descriptor.writable || descriptor.set) && descriptor.configurable) {
this.spyOn(obj, prop);
}
}
}
return obj;
};
this.clearSpies = function() { this.clearSpies = function() {
var spies = currentSpies(); var spies = currentSpies();
for (var i = spies.length - 1; i >= 0; i--) { for (var i = spies.length - 1; i >= 0; i--) {

View File

@@ -1,13 +1,14 @@
getJasmineRequireObj().StackTrace = function(j$) { getJasmineRequireObj().StackTrace = function(j$) {
function StackTrace(rawTrace) { function StackTrace(error) {
var lines = rawTrace var lines = error.stack
.split('\n') .split('\n')
.filter(function(line) { return line !== ''; }); .filter(function(line) { return line !== ''; });
if (lines[0].match(/^Error/)) { var extractResult = extractMessage(error.message, lines);
this.message = lines.shift();
} else { if (extractResult) {
this.message = undefined; this.message = extractResult.message;
lines = extractResult.remainder;
} }
var parseResult = tryParseFrames(lines); var parseResult = tryParseFrames(lines);
@@ -75,6 +76,34 @@ getJasmineRequireObj().StackTrace = function(j$) {
} }
} }
} }
function extractMessage(message, stackLines) {
var len = messagePrefixLength(message, stackLines);
if (len > 0) {
return {
message: stackLines.slice(0, len).join('\n'),
remainder: stackLines.slice(len)
};
}
}
function messagePrefixLength(message, stackLines) {
if (!stackLines[0].match(/^Error/)) {
return 0;
}
var messageLines = message.split('\n');
var i;
for (i = 1; i < messageLines.length; i++) {
if (messageLines[i] !== stackLines[i]) {
return 0;
}
}
return messageLines.length;
}
return StackTrace; return StackTrace;
}; };

View File

@@ -5,6 +5,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.parentSuite = attrs.parentSuite; this.parentSuite = attrs.parentSuite;
this.description = attrs.description; this.description = attrs.description;
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
this.asyncExpectationFactory = attrs.asyncExpectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory; this.expectationResultFactory = attrs.expectationResultFactory;
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
@@ -37,6 +38,10 @@ getJasmineRequireObj().Suite = function(j$) {
return this.expectationFactory(actual, this); return this.expectationFactory(actual, this);
}; };
Suite.prototype.expectAsync = function(actual) {
return this.asyncExpectationFactory(actual, this);
};
Suite.prototype.getFullName = function() { Suite.prototype.getFullName = function() {
var fullName = []; var fullName = [];
for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) { for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -163,5 +168,6 @@ getJasmineRequireObj().Suite = function(j$) {
}; };
if (typeof window == void 0 && typeof exports == 'object') { if (typeof window == void 0 && typeof exports == 'object') {
/* globals exports */
exports.Suite = jasmineRequire.Suite; exports.Suite = jasmineRequire.Suite;
} }

View File

@@ -174,8 +174,11 @@ getJasmineRequireObj().TreeProcessor = function() {
queueRunnerFactory({ queueRunnerFactory({
onComplete: function () { onComplete: function () {
var args = Array.prototype.slice.call(arguments, [0]);
node.cleanupBeforeAfter(); node.cleanupBeforeAfter();
nodeComplete(node, node.getResult(), done); nodeComplete(node, node.getResult(), function() {
done.apply(undefined, args);
});
}, },
queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)), queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
userContext: node.sharedUserContext(), userContext: node.sharedUserContext(),

View File

@@ -32,6 +32,7 @@ getJasmineRequireObj().Any = function(j$) {
} }
/* jshint -W122 */ /* jshint -W122 */
/* global Symbol */
if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) { if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
return typeof other == 'symbol'; return typeof other == 'symbol';
} }

View File

@@ -19,7 +19,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
}; };
ArrayContaining.prototype.jasmineToString = function () { ArrayContaining.prototype.jasmineToString = function () {
return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>'; return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
}; };
return ArrayContaining; return ArrayContaining;

View File

@@ -101,7 +101,14 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
}; };
j$.isDomNode = function(obj) { j$.isDomNode = function(obj) {
return obj.nodeType > 0; // Node is a function, because constructors
return typeof jasmineGlobal.Node !== 'undefined' ?
obj instanceof jasmineGlobal.Node :
obj !== null &&
typeof obj === 'object' &&
typeof obj.nodeType === 'number' &&
typeof obj.nodeName === 'string';
// return obj.nodeType > 0;
}; };
j$.isMap = function(obj) { j$.isMap = function(obj) {
@@ -113,7 +120,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
}; };
j$.isPromise = function(obj) { j$.isPromise = function(obj) {
return typeof jasmineGlobal.Promise !== 'undefined' && obj.constructor === jasmineGlobal.Promise; return typeof jasmineGlobal.Promise !== 'undefined' && obj && obj.constructor === jasmineGlobal.Promise;
}; };
j$.fnNameFor = function(func) { j$.fnNameFor = function(func) {

View File

@@ -225,8 +225,14 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}); });
for (i = 0; i < aLength || i < bLength; i++) { for (i = 0; i < aLength || i < bLength; i++) {
var formatter = false;
diffBuilder.withPath(i, function() { diffBuilder.withPath(i, function() {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result; if (i >= bLength) {
diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
result = false;
} else {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
}
}); });
} }
if (!result) { if (!result) {
@@ -452,6 +458,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
', but was ' + j$.pp(actual) + '.'; ', but was ' + j$.pp(actual) + '.';
} }
function actualArrayIsLongerFormatter(actual, expected, path) {
return 'Unexpected ' +
path + (path.depth() ? ' = ' : '') +
j$.pp(actual) +
' in array.';
}
function formatKeyValuePairs(obj) { function formatKeyValuePairs(obj) {
var formatted = ''; var formatted = '';
for (var key in obj) { for (var key in obj) {

View File

@@ -1,4 +1,5 @@
var getJasmineRequireObj = (function (jasmineGlobal) { var getJasmineRequireObj = (function (jasmineGlobal) {
/* globals exports, global, module, window */
var jasmineRequire; var jasmineRequire;
if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
@@ -37,6 +38,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.StackTrace = jRequire.StackTrace(j$); j$.StackTrace = jRequire.StackTrace(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
j$.Expectation = jRequire.Expectation(); j$.Expectation = jRequire.Expectation();
j$.AsyncExpectation = jRequire.AsyncExpectation(j$);
j$.buildExpectationResult = jRequire.buildExpectationResult(); j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.JsApiReporter = jRequire.JsApiReporter(); j$.JsApiReporter = jRequire.JsApiReporter();
j$.matchersUtil = jRequire.matchersUtil(j$); j$.matchersUtil = jRequire.matchersUtil(j$);

View File

@@ -63,6 +63,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @param {String} description Textual description of what this spec is checking * @param {String} description Textual description of what this spec is checking
* @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
* @see async
*/ */
it: function() { it: function() {
return env.it.apply(env, arguments); return env.it.apply(env, arguments);
@@ -92,6 +93,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @param {String} description Textual description of what this spec is checking. * @param {String} description Textual description of what this spec is checking.
* @param {implementationCallback} testFunction Function that contains the code of your test. * @param {implementationCallback} testFunction Function that contains the code of your test.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
* @see async
*/ */
fit: function() { fit: function() {
return env.fit.apply(env, arguments); return env.fit.apply(env, arguments);
@@ -104,6 +106,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {implementationCallback} [function] Function that contains the code to setup your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
* @see async
*/ */
beforeEach: function() { beforeEach: function() {
return env.beforeEach.apply(env, arguments); return env.beforeEach.apply(env, arguments);
@@ -116,6 +119,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
* @see async
*/ */
afterEach: function() { afterEach: function() {
return env.afterEach.apply(env, arguments); return env.afterEach.apply(env, arguments);
@@ -130,6 +134,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {implementationCallback} [function] Function that contains the code to setup your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
* @see async
*/ */
beforeAll: function() { beforeAll: function() {
return env.beforeAll.apply(env, arguments); return env.beforeAll.apply(env, arguments);
@@ -144,6 +149,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* @global * @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
* @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
* @see async
*/ */
afterAll: function() { afterAll: function() {
return env.afterAll.apply(env, arguments); return env.afterAll.apply(env, arguments);
@@ -161,6 +167,25 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.expect(actual); return env.expect(actual);
}, },
/**
* Create an asynchronous expectation for a spec. Note that the matchers
* that are provided by an asynchronous expectation all return promises
* which must be either returned from the spec or waited for using `await`
* in order for Jasmine to associate them with the correct spec.
* @name expectAsync
* @function
* @global
* @param {Object} actual - Actual computed value to test expectations against.
* @return {async-matchers}
* @example
* await expectAsync(somePromise).toBeResolved();
* @example
* return expectAsync(somePromise).toBeResolved();
*/
expectAsync: function(actual) {
return env.expectAsync(actual);
},
/** /**
* Mark a spec as pending, expectation results will be ignored. * Mark a spec as pending, expectation results will be ignored.
* @name pending * @name pending
@@ -210,6 +235,18 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.spyOnProperty(obj, methodName, accessType); return env.spyOnProperty(obj, methodName, accessType);
}, },
/**
* Installs spies on all writable and configurable properties of an object.
* @name spyOnAllFunctions
* @function
* @global
* @param {Object} obj - The object upon which to install the {@link Spy}s
* @returns {Object} the spied object
*/
spyOnAllFunctions: function(obj) {
return env.spyOnAllFunctions(obj);
},
jsApiReporter: new jasmine.JsApiReporter({ jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer() timer: new jasmine.Timer()
}), }),

View File

@@ -112,7 +112,7 @@ getJasmineRequireObj().util = function(j$) {
return false; return false;
} }
function errorWithStack() { util.errorWithStack = function errorWithStack () {
// Don't throw and catch if we don't have to, because it makes it harder // Don't throw and catch if we don't have to, because it makes it harder
// for users to debug their code with exception breakpoints. // for users to debug their code with exception breakpoints.
var error = new Error(); var error = new Error();
@@ -127,10 +127,10 @@ getJasmineRequireObj().util = function(j$) {
} catch (e) { } catch (e) {
return e; return e;
} }
} };
function callerFile() { function callerFile() {
var trace = new j$.StackTrace(errorWithStack().stack); var trace = new j$.StackTrace(util.errorWithStack());
return trace.frames[2].file; return trace.frames[2].file;
} }

View File

@@ -119,7 +119,7 @@ jasmineRequire.HtmlReporter = function(j$) {
} }
symbols.appendChild(createDom('li', { symbols.appendChild(createDom('li', {
className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status, className: this.displaySpecInCorrectFormat(result),
id: 'spec_' + result.id, id: 'spec_' + result.id,
title: result.fullName title: result.fullName
} }
@@ -132,10 +132,22 @@ jasmineRequire.HtmlReporter = function(j$) {
addDeprecationWarnings(result); addDeprecationWarnings(result);
}; };
this.displaySpecInCorrectFormat = function(result) {
return noExpectations(result) ? 'jasmine-empty' : this.resultStatus(result.status);
};
this.resultStatus = function(status) {
if(status === 'excluded') {
return env.hidingDisabled() ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
}
return 'jasmine-' + status;
};
this.jasmineDone = function(doneResult) { this.jasmineDone = function(doneResult) {
var banner = find('.jasmine-banner'); var banner = find('.jasmine-banner');
var alert = find('.jasmine-alert'); var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order; var order = doneResult && doneResult.order;
var i;
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
banner.appendChild(optionsMenu(env)); banner.appendChild(optionsMenu(env));
@@ -322,7 +334,14 @@ jasmineRequire.HtmlReporter = function(j$) {
id: 'jasmine-random-order', id: 'jasmine-random-order',
type: 'checkbox' type: 'checkbox'
}), }),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')) createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')),
createDom('div', { className: 'jasmine-hide-disabled' },
createDom('input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-hide-disabled' }, 'hide disabled tests'))
) )
); );
@@ -344,6 +363,12 @@ jasmineRequire.HtmlReporter = function(j$) {
navigateWithNewParam('random', !env.randomTests()); navigateWithNewParam('random', !env.randomTests());
}; };
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
hideDisabled.checked = env.hidingDisabled();
hideDisabled.onclick = function() {
navigateWithNewParam('hideDisabled', !env.hidingDisabled());
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
isOpen = /\bjasmine-open\b/; isOpen = /\bjasmine-open\b/;

View File

@@ -135,7 +135,7 @@ body {
} }
} }
&.jasmine-excluded { &.jasmine-excluded {
font-size: 14px; font-size: 14px;
&:before { &:before {
@@ -144,6 +144,11 @@ body {
} }
} }
&.jasmine-excluded-no-display {
font-size: 14px;
display: none;
}
&.jasmine-pending { &.jasmine-pending {
line-height: 17px; line-height: 17px;
&:before { &:before {
@@ -294,7 +299,7 @@ body {
&.jasmine-excluded a { &.jasmine-excluded a {
color: $neutral-color; color: $neutral-color;
} }
} }
} }
@@ -332,7 +337,7 @@ body {
color: $text-color; color: $text-color;
white-space: pre; white-space: pre-wrap;
} }
.jasmine-result-message span.jasmine-result { .jasmine-result-message span.jasmine-result {