Compare commits

...

72 Commits

Author SHA1 Message Date
Gregg Van Hove
4e5d947faa Also lock for selenium runner 2018-02-07 14:58:14 -08:00
Gregg Van Hove
c2603efeb4 Specify Jasmine Gem 2.99 tag for bundle install 2018-02-07 14:55:28 -08:00
Gregg Van Hove
fbec3cc230 Only show deprecation for catch exceptions if you tell Jasmine not to catch
- Fixes #1497
2018-02-07 14:47:10 -08:00
Gregg Van Hove
4530f9431f Generate combined file with new version numbers 2018-02-06 10:33:39 -08:00
Gregg Van Hove
9911d37f06 bump version to 2.99 2018-02-05 16:57:51 -08:00
Gregg Van Hove
32f99ef99d Use Jasmine's arrayContains to look for duplicate deprecations
[#154746527]
2018-02-05 14:24:14 -08:00
Gregg Van Hove
c142490c69 Add deprecation messages for things that will change/break in 3.0
[#154746527]
2018-02-05 14:01:46 -08:00
Gregg Van Hove
24bf3489dc Display deprecation warnings in HTML reporter
- Also no longer check for stack since IE doesn't do that

[#154746527]
2018-02-05 12:11:36 -08:00
Gregg Van Hove
5afe1222f4 Add ability to report deprecation warnings from within the suite
[#154746527]
2018-02-05 11:19:15 -08:00
Gregg Van Hove
70bce55721 Bump version to 2.9.1 2018-01-19 17:51:18 -08:00
Gregg Van Hove
53529bdc9a Clear timeouts when starting to process a milli instead of at the end
- Fixes #1482
2018-01-19 17:47:28 -08:00
Gregg Van Hove
c82e5947f5 Version bump to 2.9.0 2018-01-16 17:29:34 -08:00
Gregg Van Hove
f76b452816 Correctly check for Symbols, not Sets in AnythingSpec 2018-01-12 17:45:00 -08:00
Gregg Van Hove
91aab8e1b8 Merge branch 'Volox-ie11-sets-support'
- Merges #1478 from @Volox
- Fixes #1355
2018-01-12 17:33:51 -08:00
Volonterio Riccardo
486a64658f Added complete support for Set also for IE11.
Fixes 1355
2018-01-12 12:18:35 +01:00
Gregg Van Hove
1dfdc89ba9 Merge branch 'ie11-maps-support' of https://github.com/Volox/jasmine into Volox-ie11-maps-support
- Merges #1477 from @Volox
- Fixes #1472
2018-01-11 17:50:56 -08:00
Volonterio Riccardo
085a1f8a16 Added complete support for Map also for IE11.
Fixes 1472
2018-01-11 18:13:24 +01:00
Steve Gravrock
aeeb5b7107 Bumped copyright dates 2018-01-10 10:16:02 -08:00
Steve Gravrock
cb6de64e58 Fixed DelayedFunctionScheduler IE 8 compatibility issue 2018-01-02 18:17:23 -08:00
Steve Gravrock
f69949ebc0 Merge branch 'fix-1426' of https://github.com/leahciMic/jasmine
- Merges #1427 from @eahciMic
- Fixes #1426
2018-01-02 08:18:32 -08:00
Michael Leaney
1136fddcde Remove .sort() and fix logic in test 2018-01-02 14:51:51 +08:00
Steve Gravrock
b943f6b736 Fixed SPEC HAS NO EXPECTATIONS warning in HTML reporter
[Finishes #153891435]
2017-12-23 11:14:37 -08:00
Steve Gravrock
b439e2fb37 Extracted results state management out of the HTML reporter
[#153891435]
2017-12-23 11:12:38 -08:00
Steve Gravrock
c79ce125c0 Merge branch 'node-timeouts' of https://github.com/chris--young/jasmine
- Merges #1470 from @chris--young
- Fixes #1469
2017-12-21 13:24:21 -08:00
Chris Young
62b815c485 Use timeout objects when in node
Fixes: https://github.com/jasmine/jasmine/issues/1469
2017-12-21 10:51:07 -08:00
Steve Gravrock
65b4499dec In Jasmine's own tests, don't leak between jasmine and jasmineUnderTest 2017-12-20 12:08:22 -08:00
Steve Gravrock
b6cc34d9e9 Correctly remove spies of window.onerror on IE 2017-12-18 16:34:37 -08:00
Steve Gravrock
d3a3cf1ff3 Collapsed StringPrettyPrinter into PrettyPrinter
We never really took advantage of the potential extensibility that the
split provided, and the boundary between the two was getting muddied
over time.
2017-12-18 09:43:25 -08:00
Steve Gravrock
c0d0513199 Stop serializing objects after hitting jasmine.MAX_PRETTY_PRINT_CHARS 2017-12-15 13:23:59 -08:00
Steve Gravrock
86a38fceb9 Truncate pretty printer output that is more than j$.MAX_PRETTY_PRINT_CHARS long 2017-12-13 08:09:22 -08:00
Steve Gravrock
c74af1d900 Reduced pretty printer limits to much smaller values
This should help prevent out of memory errors when printing large object
graphs. See #1291 and #1422.

[#153257532]
2017-12-13 08:07:43 -08:00
Gregg Van Hove
8ea4c6d3a1 Update contributing for new naming of jasmineUnderTest 2017-12-11 17:25:27 -08:00
Steve Gravrock
0b5dce7d84 Removed CodeClimate badge & configuration
CodeClimate's recommendations have been a mix of irrelevant and
actively harmful for some time. The latest problem is that it applies
length and complexity requirements equally to all functions whether
they act as privacy scopes, namespaces, classes or just regular old
functions.

Static analysis tools are only worthwhile if their recommendations add
enough value to offset the cost of slogging through them -- in other
words, if the signal to noise ratio is high enough. CodeClimate hasn't
carried its own weight for a long time, and it's only gotten worse with
each recent update.
2017-12-07 21:29:59 -08:00
Steve Gravrock
0183b1642d Removed stray debugger statement 2017-11-30 07:53:59 -08:00
Steve Gravrock
18ed34e9be Fixed failing specs 2017-11-29 09:32:12 -08:00
Steve Gravrock
f4caf27208 Fixed pending() for async/promise-returning specs
Fixes #1449.
Fixes #1450.
2017-11-29 08:57:29 -08:00
Steve Gravrock
13b9e669bd Merge branch 'feature/allow-callfake-to-be-async' of https://github.com/mrlannigan/jasmine into merge-test
- Merges #1448 from @mrlannigan
2017-11-10 10:01:45 -08:00
Julian Lannigan
2eef0747a0 Added test steps for other major node versions
addresses https://www.pivotaltracker.com/story/show/152685778
2017-11-10 10:23:02 -05:00
Julian Lannigan
7ac1244f58 changed tests to work in environments that dont support async/await 2017-11-10 10:17:48 -05:00
Steve Gravrock
6ef0e93880 Revert "Removed IE 8 and 9 from the testing matrix"
In case we end doing another 2.x release.

This reverts commit 0e95b04900.
2017-11-09 20:57:01 -08:00
Julian Lannigan
2be5e0a962 Allowed async functions to be passed into spy#callFake 2017-11-09 19:59:23 -05:00
Steve Gravrock
285f06d5c4 Merge branch 'promise-matching-1314' of https://github.com/sderickson/jasmine 2017-11-02 17:18:24 -07:00
Steve Gravrock
3aece2ac74 Merge branch 'master' of https://github.com/b-3-n/jasmine
- Merges #1445 from @b-3-n
- Fixes #1444
2017-11-02 08:17:27 -07:00
sgravrock
3a9d4ee08d Merge pull request #1440 from aaronang/patch-1
Add instruction to sync local master with upstream
2017-11-02 08:11:47 -07:00
Benjamin Mularczyk
b4dfdd7a48 Fix equality computation for ES6 Sets. 2017-11-01 01:01:26 +01:00
Aaron Ang
c260c67e7e Add instruction to sync local master with upstream 2017-10-26 04:56:44 -07:00
sgravrock
554d0efab7 Point CodeClimate at the right repo 2017-10-25 11:28:47 -07:00
Steve Gravrock
ea3cf14ef8 Exclude specs from CodeClimate ratings
CodeClimate makes recommendations that, while helpful for production
code, can be harmful for test code. In particular, following its
recommendations would lead us to aggressively de-duplicate even small
amounts of test setup code. That can create unwanted coupling, obscure
the intent of the tests, and make it harder to maintain tests as their
setup needs diverge.
2017-10-25 09:25:52 -07:00
Steve Gravrock
a4bdd47a8a Merge branch 'unittests' of https://github.com/voithos/jasmine
- Merges #1437 from @voithos
2017-10-25 08:49:58 -07:00
Zaven Muradyan
89306551a0 Add some unit tests that exercise jasmine.anything() and Map matching.
Follow-up to some recent commits that fixed issues around
jasmine.anything() matching. This simply adds some extra tests that
exercise usage of Symbols with jasmine.anything() and as Map keys.
2017-10-24 22:39:31 -07:00
Steve Gravrock
0e95b04900 Removed IE 8 and 9 from the testing matrix
[#150527985]
2017-10-24 08:39:00 -07:00
Steve Gravrock
da91294182 Merge branch 'anything-fix' of https://github.com/voithos/jasmine
- Merges #1436 from @voithos
2017-10-24 08:26:13 -07:00
Steve Gravrock
bd41a97cd5 Merge branch 'anysymbol-fix' of https://github.com/voithos/jasmine
- Merge #1435 from @voithos
2017-10-24 08:18:42 -07:00
Zaven Muradyan
6d3953356d Add special handling of asymmetric matcher objects as keys in Maps.
The previous Map equality code was assuming that the set of keys would
be identical between the two Maps. This change adds insertion-order
tracking for each key with its corresponding key. If one of the two keys
is an asymmetric equality obj, the keys are eq()'d, and if it succeeds,
the corresponding values are compared. Otherwise, the "main" key is
looked up directly in the other object; this is to prevent
similar-looking obj keys with different obj identities from comparing
equal.

Fixes #1432.
2017-10-23 23:01:50 -07:00
Zaven Muradyan
62f769767a Add support for jasmine.any(Symbol).
The original asymmetric matcher code for Any did not work with symbols
since `symbolInstance instanceof Symbol` is actually `false` (but,
`symbolInstance.constructor` is `Symbol). This simply adds an extra
clause that explicitly checks for symbol (if available) like the other
primitive types.

Also added some missing specs for other types, like Map, Set, etc.

Fixes #1431.
2017-10-23 20:07:56 -07:00
Steve Gravrock
03f7f76bca Removed Safari 6 from the test matrix
Sauce Labs no longer supports Safari <7.
2017-10-23 12:05:52 -07:00
Steve Gravrock
4c6dadb9b1 Merge branch 'github-1295' of https://github.com/ksvitkovsky/jasmine
- Merges #1411 from @ksvitkovsky
2017-10-23 11:58:30 -07:00
Gregg Van Hove
8973e4e44f Ignore package-lock.json
We want to make sure that Travis checks against the latest version of
our dependencies, and also maintain compatibility across multiple
versions of Node.

Signed-off-by: Steve Gravrock <sgravrock@pivotal.io>
2017-10-23 11:53:48 -07:00
Steve Gravrock
b7e9594c86 Merge branch 'jasmine-deep-clone-args' of https://github.com/aj-dev/jasmine
- Merges #1424 from @aj-dev
2017-10-23 11:32:58 -07:00
Steve Gravrock
6c363f11b3 Merge branch 'lintfix' of https://github.com/voithos/jasmine
- Merges #1428 from @voithos
2017-10-23 11:01:18 -07:00
sgravrock
0f650e1d03 Merge pull request #1429 from voithos/docfix
Fix "Before Committing" section of CONTRIBUTING.md.
2017-10-23 10:46:06 -07:00
Zaven Muradyan
78fe42ac2d Fix "Before Committing" section of CONTRIBUTING.md.
The old contributing docs had a misaligned nested unordered-list, which
resulted in it creating a new list instead of being nested under its
parent.

It also seems like it would be useful to have the "revert your changes"
prose as part of the "Before Committing" section, since otherwise people
may miss it and have to amend.
2017-10-15 22:48:57 -07:00
Zaven Muradyan
20d86b2a00 Fix lint warning in CallTracker.
The previous code was using `== null` to handle both `null` and
`undefined`, resulting in a jshint warning. The conditional is meant to
check for non-primitive values, and it happens to be the case that a
falsey value in JS is always a primitive, or `null` or `undefined`.
2017-10-15 12:31:54 -07:00
Michael Leaney
516e00d7ba Fix #1426 clearTimeout not correctly clearing a timeout
clearTimeout was not correctly handling the case of clearing a
timeout that is also scheduled to run at the same tick.

This fix adds a deletedKeys array that is checked whilst we are
running the scheduled functions for the current clock tick. If
a function exists in deletedKeys it will not be ran. deletedKeys
is then reset to an empty array.
2017-10-11 20:54:56 +08:00
Michael Leaney
c1957ecd7c Add test 2017-10-11 20:29:27 +08:00
Audrius Jakumavicius
1f6c91de7c Deep clone args before passing them to reporters 2017-10-07 01:32:39 +02:00
Gregg Van Hove
f6342ad4fe Add a note about defineProperty for spyOnProperty
- Fixes #1415
2017-08-24 12:22:11 -07:00
ksvitkovsky
7ca571a746 Remove runnable parameter for simplicity 2017-08-10 23:08:59 +04:00
ksvitkovsky
4240b3514b Check runnable instead of suite 2017-08-10 22:58:30 +04:00
ksvitkovsky
ab116fbd0f Throw an error on nested methods 2017-08-10 22:05:13 +04:00
ksvitkovsky
da2673e02f Test nested methods to throw an error 2017-08-10 22:05:13 +04:00
Scott Erickson
6ddf64568e Add Promise checking to eq
Fixes #1314
2017-06-26 19:10:19 -07:00
57 changed files with 1760 additions and 438 deletions

View File

@@ -1,16 +0,0 @@
languages:
JavaScript: true
ratings:
paths:
- "src/**/*.js"
exclude_paths:
- "lib/**"
- "dist/*"
- "grunt/**"
- "images/*"
- "**/*.md"
- "**/*.yml"
- "**/*.json"
- "**/*.scss"
- "**/*.erb"
- "*.sh"

View File

@@ -16,7 +16,8 @@ Please submit pull requests via feature branches using the semi-standard workflo
git clone git@github.com:yourUserName/jasmine.git # Clone your fork
cd jasmine # Change directory
git remote add upstream https://github.com/jasmine/jasmine.git # Assign original repository to a remote named 'upstream'
git fetch upstream # Pull in changes not present in your local repository
git fetch upstream # Fetch changes not present in your local repository
git merge upstream/master # Sync local master with upstream repository
git checkout -b my-new-feature # Create your feature branch
git commit -am 'Add some feature' # Commit your changes
git push origin my-new-feature # Push to the branch
@@ -40,9 +41,9 @@ Once you've pushed a feature branch to your forked repo, you're ready to open a
### Self-testing
Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `j$`. So there are two copies of the code loaded under test.
Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `jasmineUnderTest`. So there are two copies of the code loaded under test.
The tests should always use `j$` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa.
The tests should always use `jasmineUnderTest` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa.
### `boot.js`
@@ -129,11 +130,9 @@ The easiest way to run the tests in **Internet Explorer** is to run a VM that ha
1. Ensure all specs are green in browser *and* node
1. Ensure JSHint is green with `grunt jshint`
1. Build `jasmine.js` with `grunt buildDistribution` and run all specs again - this ensures that your changes self-test well
## Submitting a Pull Request
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches
1. When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches
* When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master
Note that we use Travis for Continuous Integration. We only accept green pull requests.

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ site/
.bundle
tags
Gemfile.lock
package-lock.json
pkg/*
.sass-cache/*
src/html/.sass-cache/*

View File

@@ -24,7 +24,16 @@ matrix:
include:
- env:
- USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh"
- TEST_COMMAND="bash travis-node-script.sh v0.12.18"
- env:
- USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh v4"
- env:
- USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh v8"
- env:
- USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh v9"
- env:
- JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.11"
@@ -37,10 +46,6 @@ matrix:
- JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.9"
- SAUCE_BROWSER_VERSION=7
- env:
- JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.8"
- SAUCE_BROWSER_VERSION=6
- env:
- JASMINE_BROWSER="internet explorer"
- SAUCE_OS="Windows 8.1"

View File

@@ -1,9 +1,9 @@
source 'https://rubygems.org'
gem "jasmine", :git => 'https://github.com/jasmine/jasmine-gem.git'
gem "jasmine", :git => 'https://github.com/jasmine/jasmine-gem.git', :tag => 'v2.99.0'
# gem "jasmine", path: "../jasmine-gem"
gemspec
gem "jasmine_selenium_runner", :github => 'jasmine/jasmine_selenium_runner'
gem "jasmine_selenium_runner", :github => 'jasmine/jasmine_selenium_runner', :tag => 'v2.4.0'
gem "anchorman"

View File

@@ -1,7 +1,6 @@
<a name="README">[<img src="https://rawgithub.com/jasmine/jasmine/master/images/jasmine-horizontal.svg" width="400px" />](http://jasmine.github.io)</a>
[![Build Status](https://travis-ci.org/jasmine/jasmine.svg?branch=master)](https://travis-ci.org/jasmine/jasmine)
[![Code Climate](https://codeclimate.com/github/pivotal/jasmine.svg)](https://codeclimate.com/github/pivotal/jasmine)
=======

View File

@@ -7,9 +7,7 @@ Follow the instructions in `CONTRIBUTING.md` during development.
### Git Rules
Please work on feature branches.
Please attempt to keep commits to `master` small, but cohesive. If a feature is contained in a bunch of small commits (e.g., it has several wip commits or small work), please squash them when merging back to `master`.
Please attempt to keep commits to `master` small, but cohesive. If a feature is contained in a bunch of small commits (e.g., it has several wip commits or small work), please squash them when pushing to `master`.
### Version

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -34,6 +34,46 @@ jasmineRequire.HtmlReporter = function(j$) {
elapsed: function() { return 0; }
};
function ResultsStateBuilder() {
this.topResults = new j$.ResultsNode({}, '', null);
this.currentParent = this.topResults;
this.specsExecuted = 0;
this.failureCount = 0;
this.pendingSpecCount = 0;
}
ResultsStateBuilder.prototype.suiteStarted = function(result) {
this.currentParent.addChild(result, 'suite');
this.currentParent = this.currentParent.last();
};
ResultsStateBuilder.prototype.suiteDone = function(result) {
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent;
}
};
ResultsStateBuilder.prototype.specStarted = function(result) {
};
ResultsStateBuilder.prototype.specDone = function(result) {
this.currentParent.addChild(result, 'spec');
if (result.status !== 'disabled') {
this.specsExecuted++;
}
if (result.status === 'failed') {
this.failureCount++;
}
if (result.status == 'pending') {
this.pendingSpecCount++;
}
};
function HtmlReporter(options) {
var env = options.env || {},
getContainer = options.getContainer,
@@ -46,12 +86,10 @@ jasmineRequire.HtmlReporter = function(j$) {
filterSpecs = options.filterSpecs,
timer = options.timer || noopTimer,
results = [],
specsExecuted = 0,
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols,
failedSuites = [];
failedSuites = [],
deprecationWarnings = [];
this.initialize = function() {
clearPrior();
@@ -77,12 +115,10 @@ jasmineRequire.HtmlReporter = function(j$) {
var summary = createDom('div', {className: 'jasmine-summary'});
var topResults = new j$.ResultsNode({}, '', null),
currentParent = topResults;
var stateBuilder = new ResultsStateBuilder();
this.suiteStarted = function(result) {
currentParent.addChild(result, 'suite');
currentParent = currentParent.last();
stateBuilder.suiteStarted(result);
};
this.suiteDone = function(result) {
@@ -90,27 +126,22 @@ jasmineRequire.HtmlReporter = function(j$) {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
currentParent = currentParent.parent;
stateBuilder.suiteDone(result);
addDeprecationWarnings(result);
};
this.specStarted = function(result) {
currentParent.addChild(result, 'spec');
stateBuilder.specStarted(result);
};
var failures = [];
this.specDone = function(result) {
stateBuilder.specDone(result);
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
if (result.status != 'disabled') {
specsExecuted++;
}
if (!symbols){
symbols = find('.jasmine-symbol-summary');
}
@@ -123,8 +154,6 @@ jasmineRequire.HtmlReporter = function(j$) {
));
if (result.status == 'failed') {
failureCount++;
var failure =
createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
createDom('div', {className: 'jasmine-description'},
@@ -143,9 +172,7 @@ jasmineRequire.HtmlReporter = function(j$) {
failures.push(failure);
}
if (result.status == 'pending') {
pendingSpecCount++;
}
addDeprecationWarnings(result);
};
this.jasmineDone = function(doneResult) {
@@ -208,8 +235,8 @@ jasmineRequire.HtmlReporter = function(j$) {
}
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
if (stateBuilder.specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = addToExistingQueryString('spec', '');
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
@@ -221,9 +248,9 @@ jasmineRequire.HtmlReporter = function(j$) {
var statusBarClassName = 'jasmine-bar ';
if (totalSpecsDefined > 0) {
statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); }
statusBarClassName += (stateBuilder.failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
} else {
statusBarClassName += 'jasmine-skipped';
statusBarMessage += 'No specs found';
@@ -255,10 +282,18 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message));
}
addDeprecationWarnings(doneResult);
var warningBarClassName = 'jasmine-bar jasmine-warning';
for(i = 0; i < deprecationWarnings.length; i++) {
var warning = deprecationWarnings[i];
alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning));
}
var results = find('.jasmine-results');
results.appendChild(summary);
summaryList(topResults, summary);
summaryList(stateBuilder.topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
@@ -329,6 +364,17 @@ jasmineRequire.HtmlReporter = function(j$) {
return this;
function addDeprecationWarnings(result) {
if (result && result.deprecationWarnings) {
for(var i = 0; i < result.deprecationWarnings.length; i++) {
var warning = result.deprecationWarnings[i].message;
if (!j$.util.arrayContains(warning)) {
deprecationWarnings.push(warning);
}
}
}
}
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}

View File

@@ -33,6 +33,7 @@ body { overflow-y: scroll; }
.jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; }
.jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; }
.jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; }
.jasmine_html-reporter .jasmine-bar.jasmine-warning { background-color: #ba9d37; color: #333; }
.jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; }
.jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; }
.jasmine_html-reporter .jasmine-bar a { color: white; }

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -34,7 +34,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
jasmineGlobal = window;
}
jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {};
jasmineRequire = jasmineGlobal.jasmineRequire = {};
}
function getJasmineRequire() {
@@ -45,7 +45,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
var j$ = {};
jRequire.base(j$, jasmineGlobal);
j$.util = jRequire.util();
j$.util = jRequire.util(j$);
j$.errors = jRequire.errors();
j$.formatErrorMsg = jRequire.formatErrorMsg();
j$.Any = jRequire.Any(j$);
@@ -54,7 +54,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.MockDate = jRequire.MockDate();
j$.getClearStack = jRequire.clearStack(j$);
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.Env = jRequire.Env(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
j$.Expectation = jRequire.Expectation();
@@ -66,7 +66,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
j$.Spec = jRequire.Spec(j$);
j$.Spy = jRequire.Spy(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);
@@ -138,14 +138,20 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Set this to a lower value to speed up pretty printing if you have large objects.
* @name jasmine.MAX_PRETTY_PRINT_DEPTH
*/
j$.MAX_PRETTY_PRINT_DEPTH = 40;
j$.MAX_PRETTY_PRINT_DEPTH = 8;
/**
* Maximum number of array elements to display when pretty printing objects.
* This will also limit the number of keys and values displayed for an object.
* Elements past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
*/
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
/**
* Maximum number of charasters to display when pretty printing objects.
* Characters past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_CHARS
*/
j$.MAX_PRETTY_PRINT_CHARS = 1000;
/**
* Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
* @name jasmine.DEFAULT_TIMEOUT_INTERVAL
@@ -217,6 +223,18 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return obj.nodeType > 0;
};
j$.isMap = function(obj) {
return typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map;
};
j$.isSet = function(obj) {
return typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set;
};
j$.isPromise = function(obj) {
return typeof jasmineGlobal.Promise !== 'undefined' && obj.constructor === jasmineGlobal.Promise;
};
j$.fnNameFor = function(func) {
if (func.name) {
return func.name;
@@ -355,7 +373,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
};
getJasmineRequireObj().util = function() {
getJasmineRequireObj().util = function(j$) {
var util = {};
@@ -412,6 +430,23 @@ getJasmineRequireObj().util = function() {
return cloned;
};
util.cloneArgs = function(args) {
var clonedArgs = [];
var argsAsArray = j$.util.argsToArray(args);
for(var i = 0; i < argsAsArray.length; i++) {
var str = Object.prototype.toString.apply(argsAsArray[i]),
primitives = /^\[object (Boolean|String|RegExp|Number)/;
// All falsey values are either primitives, `null`, or `undefined.
if (!argsAsArray[i] || str.match(primitives)) {
clonedArgs.push(argsAsArray[i]);
} else {
clonedArgs.push(j$.util.clone(argsAsArray[i]));
}
}
return clonedArgs;
};
util.getPropertyDescriptor = function(obj, methodName) {
var descriptor,
proto = obj;
@@ -470,6 +505,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} fullName - The full description including all ancestors of this spec.
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
* @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
* @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
* @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
*/
@@ -479,6 +515,7 @@ getJasmineRequireObj().Spec = function(j$) {
fullName: this.getFullName(),
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: ''
};
}
@@ -594,6 +631,10 @@ getJasmineRequireObj().Spec = function(j$) {
return this.getSpecName(this);
};
Spec.prototype.addDeprecationWarning = function(msg) {
this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
};
var extractCustomPendingMessage = function(e) {
var fullMessage = e.toString(),
boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
@@ -675,6 +716,8 @@ getJasmineRequireObj().Env = function(j$) {
var self = this;
var global = options.global || j$.getGlobal();
var hasExecuted = false;
var totalSpecsDefined = 0;
var catchExceptions = true;
@@ -861,6 +904,9 @@ getJasmineRequireObj().Env = function(j$) {
// TODO: fix this naming, and here's where the value comes in
this.catchExceptions = function(value) {
catchExceptions = !!value;
if (!catchExceptions) {
this.deprecated('The catchExceptions option is deprecated and will be replaced with stopOnSpecFailure in Jasmine 3.0');
}
return catchExceptions;
};
@@ -898,6 +944,14 @@ getJasmineRequireObj().Env = function(j$) {
return seed;
};
this.deprecated = function(msg) {
var runnable = currentRunnable() || topSuite;
runnable.addDeprecationWarning(msg);
if(typeof console !== 'undefined' && typeof console.warn !== 'undefined') {
console.error('DEPRECATION: ' + msg);
}
};
var queueRunnerFactory = function(options) {
options.catchException = catchException;
options.clearStack = options.clearStack || clearStack;
@@ -905,6 +959,7 @@ getJasmineRequireObj().Env = function(j$) {
options.fail = self.fail;
options.globalErrors = globalErrors;
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
options.deprecated = self.deprecated;
new j$.QueueRunner(options).execute();
};
@@ -924,6 +979,12 @@ getJasmineRequireObj().Env = function(j$) {
};
this.execute = function(runnablesToRun) {
if (hasExecuted) {
this.deprecated('Executing the same Jasmine multiple times will no longer work in Jasmine 3.0');
}
hasExecuted = true;
if(!runnablesToRun) {
if (focusedRunnables.length) {
runnablesToRun = focusedRunnables;
@@ -990,10 +1051,12 @@ getJasmineRequireObj().Env = function(j$) {
* @typedef JasmineDoneInfo
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
*/
reporter.jasmineDone({
order: order,
failedExpectations: topSuite.result.failedExpectations
failedExpectations: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
});
});
};
@@ -1048,6 +1111,13 @@ getJasmineRequireObj().Env = function(j$) {
}
};
function ensureIsNotNested(method) {
var runnable = currentRunnable();
if (runnable !== null && runnable !== undefined) {
throw new Error('\'' + method + '\' should only be used in \'describe\' function');
}
}
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
@@ -1063,6 +1133,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.describe = function(description, specDefinitions) {
ensureIsNotNested('describe');
ensureIsFunction(specDefinitions, 'describe');
var suite = suiteFactory(description);
if (specDefinitions.length > 0) {
@@ -1076,6 +1147,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.xdescribe = function(description, specDefinitions) {
ensureIsNotNested('xdescribe');
ensureIsFunction(specDefinitions, 'xdescribe');
var suite = suiteFactory(description);
suite.pend();
@@ -1086,6 +1158,8 @@ getJasmineRequireObj().Env = function(j$) {
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
ensureIsNotNested('fdescribe');
ensureIsFunction(specDefinitions, 'fdescribe');
var suite = suiteFactory(description);
suite.isFocused = true;
@@ -1183,6 +1257,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.it = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
if (arguments.length > 1 && typeof fn !== 'undefined') {
@@ -1197,6 +1272,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
// xit(), like it(), doesn't always have a fn argument, so only check the
// type when needed.
if (arguments.length > 1 && typeof fn !== 'undefined') {
@@ -1208,6 +1284,8 @@ getJasmineRequireObj().Env = function(j$) {
};
this.fit = function(description, fn, timeout){
this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
ensureIsNotNested('fit');
ensureIsFunctionOrAsync(fn, 'fit');
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
@@ -1225,6 +1303,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsNotNested('beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
@@ -1233,6 +1312,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeAll = function(beforeAllFunction, timeout) {
ensureIsNotNested('beforeAll');
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
@@ -1241,6 +1321,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterEach = function(afterEachFunction, timeout) {
ensureIsNotNested('afterEach');
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({
@@ -1250,6 +1331,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterAll = function(afterAllFunction, timeout) {
ensureIsNotNested('afterAll');
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
@@ -1458,6 +1540,9 @@ getJasmineRequireObj().Any = function(j$) {
}
if (this.expectedObject == Object) {
if (other === null) {
j$.getEnv().deprecated('jasmine.Any(Object) will no longer match null in Jasmine 3.0');
}
return typeof other == 'object';
}
@@ -1465,6 +1550,12 @@ getJasmineRequireObj().Any = function(j$) {
return typeof other == 'boolean';
}
/* jshint -W122 */
if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
return typeof other == 'symbol';
}
/* jshint +W122 */
return other instanceof this.expectedObject;
};
@@ -1629,25 +1720,9 @@ getJasmineRequireObj().CallTracker = function(j$) {
var calls = [];
var opts = {};
function argCloner(context) {
var clonedArgs = [];
var argsAsArray = j$.util.argsToArray(context.args);
for(var i = 0; i < argsAsArray.length; i++) {
var str = Object.prototype.toString.apply(argsAsArray[i]),
primitives = /^\[object (Boolean|String|RegExp|Number)/;
if (argsAsArray[i] == null || str.match(primitives)) {
clonedArgs.push(argsAsArray[i]);
} else {
clonedArgs.push(j$.util.clone(argsAsArray[i]));
}
}
context.args = clonedArgs;
}
this.track = function(context) {
if(opts.cloneArgs) {
argCloner(context);
context.args = j$.util.cloneArgs(context.args);
}
calls.push(context);
};
@@ -1823,6 +1898,9 @@ getJasmineRequireObj().clearStack = function(j$) {
};
getJasmineRequireObj().Clock = function() {
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
/**
* _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
* @class Clock
@@ -1846,6 +1924,7 @@ getJasmineRequireObj().Clock = function() {
delayedFunctionScheduler,
timer;
self.FakeTimeout = FakeTimeout;
/**
* Install the mock clock over the built-in methods.
@@ -1969,7 +2048,15 @@ getJasmineRequireObj().Clock = function() {
}
function setTimeout(fn, delay) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2), false, timeout);
return timeout;
}
function clearTimeout(id) {
@@ -1977,7 +2064,15 @@ getJasmineRequireObj().Clock = function() {
}
function setInterval(fn, interval) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true, timeout);
return timeout;
}
function clearInterval(id) {
@@ -1989,16 +2084,30 @@ getJasmineRequireObj().Clock = function() {
}
}
/**
* Mocks Node.js Timeout class
*/
function FakeTimeout() {}
FakeTimeout.prototype.ref = function () {
return this;
};
FakeTimeout.prototype.unref = function () {
return this;
};
return Clock;
};
getJasmineRequireObj().DelayedFunctionScheduler = function() {
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
function DelayedFunctionScheduler() {
var self = this;
var scheduledLookup = [];
var scheduledFunctions = {};
var currentTime = 0;
var delayedFnCount = 0;
var deletedKeys = [];
self.tick = function(millis, tickDate) {
millis = millis || 0;
@@ -2045,6 +2154,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
};
self.removeFunctionWithId = function(timeoutKey) {
deletedKeys.push(timeoutKey);
for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) {
@@ -2115,12 +2226,14 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}
do {
deletedKeys = [];
var newCurrentTime = scheduledLookup.shift();
tickDate(newCurrentTime - currentTime);
currentTime = newCurrentTime;
var funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime];
forEachFunction(funcsToRun, function(funcToRun) {
@@ -2130,6 +2243,10 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
});
forEachFunction(funcsToRun, function(funcToRun) {
if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
// skip a timeoutKey deleted whilst we were running
return;
}
funcToRun.funcToCall.apply(null, funcToRun.params || []);
});
} while (scheduledLookup.length > 0 &&
@@ -2660,6 +2777,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return false;
}
var aIsPromise = j$.isPromise(a);
var bIsPromise = j$.isPromise(b);
if (aIsPromise && bIsPromise) {
return a === b;
}
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = aStack.length;
@@ -2693,22 +2816,46 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (!result) {
return false;
}
} else if (className == '[object Map]') {
} else if (j$.isMap(a) && j$.isMap(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
// For both sets of keys, check they map to equal values in both maps
var mapKeys = [a.keys(), b.keys()];
var mapIter, mapKeyIt, mapKey;
var keysA = [];
var keysB = [];
a.forEach( function( valueA, keyA ) {
keysA.push( keyA );
});
b.forEach( function( valueB, keyB ) {
keysB.push( keyB );
});
// For both sets of keys, check they map to equal values in both maps.
// Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
var mapKeys = [keysA, keysB];
var cmpKeys = [keysB, keysA];
var mapIter, mapKey, mapValueA, mapValueB;
var cmpIter, cmpKey;
for (i = 0; result && i < mapKeys.length; i++) {
mapIter = mapKeys[i];
mapKeyIt = mapIter.next();
while (result && !mapKeyIt.done) {
mapKey = mapKeyIt.value;
result = eq(a.get(mapKey), b.get(mapKey), aStack, bStack, customTesters, j$.NullDiffBuilder());
mapKeyIt = mapIter.next();
cmpIter = cmpKeys[i];
for (var j = 0; result && j < mapIter.length; j++) {
mapKey = mapIter[j];
cmpKey = cmpIter[j];
mapValueA = a.get(mapKey);
// Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
// otherwise explicitly look up the mapKey in the other Map since we want keys with unique
// obj identity (that are otherwise equal) to not match.
if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
mapValueB = b.get(cmpKey);
} else {
mapValueB = b.get(mapKey);
}
result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
}
}
@@ -2716,36 +2863,49 @@ getJasmineRequireObj().matchersUtil = function(j$) {
diffBuilder.record(a, b);
return false;
}
} else if (className == '[object Set]') {
} else if (j$.isSet(a) && j$.isSet(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
var valuesA = [];
a.forEach( function( valueA ) {
valuesA.push( valueA );
});
var valuesB = [];
b.forEach( function( valueB ) {
valuesB.push( valueB );
});
// For both sets, check they are all contained in the other set
var setPairs = [[a, b], [b, a]];
var baseIter, baseValueIt, baseValue;
var otherSet, otherIter, otherValueIt, otherValue, found;
var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
var stackPairs = [[aStack, bStack], [bStack, aStack]];
var baseValues, baseValue, baseStack;
var otherValues, otherValue, otherStack;
var found;
var prevStackSize;
for (i = 0; result && i < setPairs.length; i++) {
baseIter = setPairs[i][0].values();
otherSet = setPairs[i][1];
baseValues = setPairs[i][0];
otherValues = setPairs[i][1];
baseStack = stackPairs[i][0];
otherStack = stackPairs[i][1];
// For each value in the base set...
baseValueIt = baseIter.next();
while (result && !baseValueIt.done) {
baseValue = baseValueIt.value;
for (var k = 0; result && k < baseValues.length; k++) {
baseValue = baseValues[k];
found = false;
// ... test that it is present in the other set
otherIter = otherSet.values();
otherValueIt = otherIter.next();
// Optimisation: start looking for value by object identity
found = otherSet.has(baseValue);
// If not found, compare by value equality
while (!found && !otherValueIt.done) {
otherValue = otherValueIt.value;
found = eq(baseValue, otherValue, aStack, bStack, customTesters, j$.NullDiffBuilder());
otherValueIt = otherIter.next();
for (var l = 0; !found && l < otherValues.length; l++) {
otherValue = otherValues[l];
prevStackSize = baseStack.length;
// compare by value equality
found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize);
}
}
result = result && found;
baseValueIt = baseIter.next();
}
}
@@ -3891,6 +4051,8 @@ getJasmineRequireObj().pp = function(j$) {
function PrettyPrinter() {
this.ppNestLevel_ = 0;
this.seen = [];
this.length = 0;
this.stringParts = [];
}
function hasCustomToString(value) {
@@ -3924,9 +4086,9 @@ getJasmineRequireObj().pp = function(j$) {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.getType_(value) == '[object Set]') {
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.getType_(value) == '[object Map]') {
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
@@ -3945,6 +4107,10 @@ getJasmineRequireObj().pp = function(j$) {
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
@@ -3970,30 +4136,15 @@ getJasmineRequireObj().pp = function(j$) {
return objKeys.length > length;
};
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitMap = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
function StringPrettyPrinter() {
PrettyPrinter.call(this);
this.stringParts = [];
}
j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
StringPrettyPrinter.prototype.emitScalar = function(value) {
PrettyPrinter.prototype.emitScalar = function(value) {
this.append(value);
};
StringPrettyPrinter.prototype.emitString = function(value) {
PrettyPrinter.prototype.emitString = function(value) {
this.append('\'' + value + '\'');
};
StringPrettyPrinter.prototype.emitArray = function(array) {
PrettyPrinter.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
@@ -4027,47 +4178,57 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' ]');
};
StringPrettyPrinter.prototype.emitSet = function(set) {
PrettyPrinter.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = set.values();
for (var i = 0; i < size; i++) {
var i = 0;
set.forEach( function( value, key ) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
this.format(value);
i++;
}, this );
if (set.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitMap = function(map) {
PrettyPrinter.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = map.entries();
for (var i = 0; i < size; i++) {
var i = 0;
map.forEach( function( value, key ) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
this.format([key,value]);
i++;
}, this );
if (map.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitObject = function(obj) {
PrettyPrinter.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
@@ -4100,7 +4261,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' })');
};
StringPrettyPrinter.prototype.emitTypedArray = function(arr) {
PrettyPrinter.prototype.emitTypedArray = function(arr) {
var constructorName = j$.fnNameFor(arr.constructor),
limitedArray = Array.prototype.slice.call(arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH),
itemsString = Array.prototype.join.call(limitedArray, ', ');
@@ -4112,7 +4273,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
StringPrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
this.append(property);
this.append(': ');
if (isGetter) {
@@ -4122,10 +4283,33 @@ getJasmineRequireObj().pp = function(j$) {
}
};
StringPrettyPrinter.prototype.append = function(value) {
this.stringParts.push(value);
PrettyPrinter.prototype.append = function(value) {
var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
};
function truncate(s, maxlen) {
if (s.length <= maxlen) {
return { value: s, truncated: false };
}
s = s.substring(0, maxlen - 4) + ' ...';
return { value: s, truncated: true };
}
function MaxCharsReachedError() {
this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS +
' characters while pretty-printing a value';
}
MaxCharsReachedError.prototype = new Error();
function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) :
(function(o) {
@@ -4156,9 +4340,9 @@ getJasmineRequireObj().pp = function(j$) {
return extraKeys;
}
return function(value) {
var stringPrettyPrinter = new StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.stringParts.join('');
var prettyPrinter = new PrettyPrinter();
prettyPrinter.format(value);
return prettyPrinter.stringParts.join('');
};
};
@@ -4169,7 +4353,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return function() {
if (!called) {
called = true;
fn();
fn.apply(null, arguments);
}
return null;
};
@@ -4188,6 +4372,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
this.completeOnFirstError = !!attrs.completeOnFirstError;
this.deprecated = attrs.deprecated;
}
QueueRunner.prototype.execute = function() {
@@ -4247,9 +4432,13 @@ getJasmineRequireObj().QueueRunner = function(j$) {
clearTimeout(timeoutId);
self.globalErrors.popListener(handleError);
}),
next = once(function () {
next = once(function (err) {
cleanup();
if (err instanceof Error) {
self.deprecated('done callback received an Error object. Jasmine 3.0 will treat this as a failure');
}
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
@@ -4289,7 +4478,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, next.fail);
maybeThenable.then(next, onPromiseRejection);
completedSynchronously = false;
return { completedSynchronously: false };
}
@@ -4311,6 +4500,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
errored = true;
}
function onPromiseRejection(e) {
onException(e);
next();
}
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
@@ -4325,7 +4519,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return QueueRunner;
};
getJasmineRequireObj().ReportDispatcher = function() {
getJasmineRequireObj().ReportDispatcher = function(j$) {
function ReportDispatcher(methods) {
var dispatchedMethods = methods || [];
@@ -4363,7 +4557,7 @@ getJasmineRequireObj().ReportDispatcher = function() {
for (var i = 0; i < reporters.length; i++) {
var reporter = reporters[i];
if (reporter[method]) {
reporter[method].apply(reporter, args);
reporter[method].apply(reporter, j$.util.cloneArgs(args));
}
}
}
@@ -4572,7 +4766,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
},
/**
* Install a spy on a property onto an existing object.
* Install a spy on a property installed with `Object.defineProperty` onto an existing object.
* @name spyOnProperty
* @function
* @global
@@ -4720,6 +4914,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
function SpyRegistry(options) {
options = options || {};
var global = options.global || j$.getGlobal();
var currentSpies = options.currentSpies || function() { return []; };
this.allowRespy = function(allow){
@@ -4763,7 +4958,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
spiedMethod = j$.createSpy(methodName, originalMethod),
restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, methodName)) {
if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
restoreStrategy = function() {
obj[methodName] = originalMethod;
};
@@ -4946,7 +5141,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
* @param {Function} fn The function to invoke with the passed parameters.
*/
this.callFake = function(fn) {
if(!j$.isFunction_(fn)) {
if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
throw new Error('Argument passed to callFake should be a function, got ' + fn);
}
plan = fn;
@@ -4990,13 +5185,15 @@ getJasmineRequireObj().Suite = function(j$) {
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
*/
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: []
failedExpectations: [],
deprecationWarnings: []
};
}
@@ -5116,6 +5313,10 @@ getJasmineRequireObj().Suite = function(j$) {
}
};
Suite.prototype.addDeprecationWarning = function(msg) {
this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
};
function isAfterAll(children) {
return children && children[0].result.status;
}
@@ -5381,5 +5582,5 @@ getJasmineRequireObj().UserContext = function(j$) {
};
getJasmineRequireObj().version = function() {
return '2.8.0';
return '2.99.0';
};

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -4,6 +4,6 @@
#
module Jasmine
module Core
VERSION = "2.8.0"
VERSION = "2.99.1"
end
end

View File

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

99
release_notes/2.9.0.md Normal file
View File

@@ -0,0 +1,99 @@
# Jasmine 2.9 Release Notes
## Summary
This release contains a number of fixes and pull requests.
## Changes
* Fixed DelayedFunctionScheduler IE 8 compatibility issue
* Fixed SPEC HAS NO EXPECTATIONS warning in HTML reporter
* Correctly remove spies of window.onerror on IE
* Truncate pretty printer output that is more than j$.MAX_PRETTY_PRINT_CHARS long
* Reduced pretty printer limits to much smaller values
* Update contributing for new naming of `jasmineUnderTest`
* Allowed async functions to be passed into spy#callFake
## Pull Requests & Issues
* Added complete support for Set also for IE11.
- Merges [#1478](https://github.com/jasmine/jasmine/issues/1478) from @Volox
- Fixes [#1355](https://github.com/jasmine/jasmine/issues/1355)
* Added complete support for Map also for IE11.
- Merges [#1477](https://github.com/jasmine/jasmine/issues/1477) from @Volox
- Fixes [#1472](https://github.com/jasmine/jasmine/issues/1472)
* Use timeout objects when in node
- Merges [#1470](https://github.com/jasmine/jasmine/issues/1470) from @chris--young
- Fixes [#1469](https://github.com/jasmine/jasmine/issues/1469)
* Fixed `pending()` for `async`/promise-returning specs
- Fixes [#1449](https://github.com/jasmine/jasmine/issues/1449)
- Fixes [#1450](https://github.com/jasmine/jasmine/issues/1450)
* Added test steps for other major node versions
- Merges [#1448](https://github.com/jasmine/jasmine/issues/1448) from @mrlannigan
* Fix equality computation for ES6 Sets.
- Merges [#1445](https://github.com/jasmine/jasmine/issues/1445) from @b-3-n
- Fixes [#1444](https://github.com/jasmine/jasmine/issues/1444)
* Add instruction to sync local master with upstream
- Merges [#1440](https://github.com/jasmine/jasmine/issues/1440) from aaronang
* Add some unit tests that exercise jasmine.anything() and Map matching.
- Merges [#1437](https://github.com/jasmine/jasmine/issues/1437) from @voithos
* Add special handling of asymmetric matcher objects as keys in Maps.
- Merges [#1436](https://github.com/jasmine/jasmine/issues/1436) from @voithos
- Fixes [#1432](https://github.com/jasmine/jasmine/issues/1432)
* Add support for jasmine.any(Symbol).
- Merge [#1435](https://github.com/jasmine/jasmine/issues/1435) from @voithos
- Fixes [#1431](https://github.com/jasmine/jasmine/issues/1431)
* Throw an error for invalid nesting of a suite functions
- Merges [#1411](https://github.com/jasmine/jasmine/issues/1411) from @ksvitkovsky
- Fixes [#1295](https://github.com/jasmine/jasmine/issues/1295)
* Deep clone args before passing them to reporters
- Merges [#1424](https://github.com/jasmine/jasmine/issues/1424) from @aj-dev
* Fix "Before Committing" section of CONTRIBUTING.md.
- Merges [#1429](https://github.com/jasmine/jasmine/issues/1429) from @voithos
* Fix lint warning in CallTracker.
- Merges [#1428](https://github.com/jasmine/jasmine/issues/1428) from @voithos
* clearTimeout should now correctly clear a timeout that is also scheduled to run at the same tick.
- Merges [#1427](https://github.com/jasmine/jasmine/issues/1427) from @leahciMic
- Fixes [#1426](https://github.com/jasmine/jasmine/issues/1426)
* Add a note about `defineProperty` for `spyOnProperty`
- Fixes [#1415](https://github.com/jasmine/jasmine/issues/1415)
* Add Promise checking to eq
- Merges [#1386](https://github.com/jasmine/jasmine/issues/1386) from @sderickson
- Fixes [#1314](https://github.com/jasmine/jasmine/issues/1314)
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

15
release_notes/2.9.1.md Normal file
View File

@@ -0,0 +1,15 @@
# Jasmine Core 2.9.1 Release Notes
## Summary
This is a hotfix release to fix a breaking change from the 2.9.0 release
## Changes
* Clear timeouts when starting to process a milli instead of at the end
- Fixes #1482
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

19
release_notes/2.99.md Normal file
View File

@@ -0,0 +1,19 @@
# Jasmine-Core 2.99 Release Notes
## Summary
This release is part of the upgrade path to Jasmine 3.0. It deprecates some functionality that will change.
## Changes
* Add ability to report deprecation warnings from within the suite and display them in the HTML reporter
* Add deprecation messages for things that will change/break in 3.0
* * done for async functionality will now add a failure if it is invoked with an Error
* * Env.catchExceptions and the query param are going away, in favor of a more fully functional fail fast handler
* * jasmine.Any(Object) will no longer match null
* * Unhandled errors during suite load will be caught and reported as failures by Jasmine
* * Calling execute more than once on the same spec will definitely fail in 3.0
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -1,5 +1,7 @@
describe("Clock", function() {
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
it("does not replace setTimeout until it is installed", function() {
var fakeSetTimeout = jasmine.createSpy("global setTimeout"),
fakeGlobal = { setTimeout: fakeSetTimeout },
@@ -294,13 +296,19 @@ describe("Clock", function() {
fakeGlobal = { setTimeout: fakeSetTimeout },
delayedFn = jasmine.createSpy('delayedFn'),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate);
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate),
timeout = new clock.FakeTimeout();
clock.install();
clock.setTimeout(delayedFn, 0, 'a', 'b');
expect(fakeSetTimeout).not.toHaveBeenCalled();
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b']);
if (!NODE_JS) {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b']);
} else {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b'], false, timeout);
}
});
it("returns an id for the delayed function", function() {
@@ -312,12 +320,16 @@ describe("Clock", function() {
delayedFn = jasmine.createSpy('delayedFn'),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate),
timeoutId;
timeout;
clock.install();
timeoutId = clock.setTimeout(delayedFn, 0);
timeout = clock.setTimeout(delayedFn, 0);
expect(timeoutId).toEqual(123);
if (!NODE_JS) {
expect(timeout).toEqual(123);
} else {
expect(timeout.constructor.name).toEqual('FakeTimeout');
}
});
it("clears the scheduled function with the scheduler", function() {
@@ -342,13 +354,19 @@ describe("Clock", function() {
fakeGlobal = { setInterval: fakeSetInterval },
delayedFn = jasmine.createSpy('delayedFn'),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate);
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate),
timeout = new clock.FakeTimeout;
clock.install();
clock.setInterval(delayedFn, 0, 'a', 'b');
expect(fakeSetInterval).not.toHaveBeenCalled();
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b'], true);
if (!NODE_JS) {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b'], true);
} else {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b'], true, timeout);
}
});
it("returns an id for the delayed function", function() {
@@ -360,12 +378,16 @@ describe("Clock", function() {
delayedFn = jasmine.createSpy('delayedFn'),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate),
intervalId;
interval;
clock.install();
intervalId = clock.setInterval(delayedFn, 0);
interval = clock.setInterval(delayedFn, 0);
expect(intervalId).toEqual(123);
if (!NODE_JS) {
expect(interval).toEqual(123);
} else {
expect(interval.constructor.name).toEqual('FakeTimeout');
}
});
it("clears the scheduled function with the scheduler", function() {
@@ -401,7 +423,8 @@ describe("Clock", function() {
setInterval: fakeSetInterval
},
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate);
clock = new jasmineUnderTest.Clock(fakeGlobal, function () { return delayedFunctionScheduler; }, mockDate),
timeout = new clock.FakeTimeout();
fakeSetTimeout.apply = null;
fakeSetInterval.apply = null;
@@ -409,13 +432,25 @@ describe("Clock", function() {
clock.install();
clock.setTimeout(fn, 0);
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, []);
if (!NODE_JS) {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, []);
} else {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, [], false, timeout);
}
expect(function() {
clock.setTimeout(fn, 0, 'extra');
}).toThrow();
clock.setInterval(fn, 0);
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, [], true);
if (!NODE_JS) {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, [], true);
} else {
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, [], true, timeout);
}
expect(function() {
clock.setInterval(fn, 0, 'extra');
}).toThrow();
@@ -679,4 +714,41 @@ describe("Clock (acceptance)", function() {
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]);
})
it('correctly clears a scheduled timeout while the Clock is advancing', function () {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = {Date: Date, setTimeout: undefined},
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(global, function () { return delayedFunctionScheduler; }, mockDate);
clock.install();
var timerId2;
global.setTimeout(function () {
global.clearTimeout(timerId2);
}, 100);
timerId2 = global.setTimeout(fail, 100);
clock.tick(100);
});
it('correctly clears a scheduled interval while the Clock is advancing', function () {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = {Date: Date, setTimeout: undefined},
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(global, function () { return delayedFunctionScheduler; }, mockDate);
clock.install();
var timerId2;
var timerId1 = global.setInterval(function () {
global.clearInterval(timerId2);
}, 100);
timerId2 = global.setInterval(fail, 100);
clock.tick(400);
});
});

View File

@@ -216,21 +216,23 @@ describe("DelayedFunctionScheduler", function() {
it("removes functions during a tick that runs the function", function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
spy = jasmine.createSpy('fn'),
spyAndRemove = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true);
scheduler.scheduleFunction(function () {
spyAndRemove.and.callFake(function() {
scheduler.removeFunctionWithId(timeoutKey);
}, 2 * fnDelay);
});
expect(fn).not.toHaveBeenCalled();
scheduler.scheduleFunction(spyAndRemove, fnDelay);
scheduler.tick(3 * fnDelay);
timeoutKey = scheduler.scheduleFunction(spy, fnDelay, [], true);
expect(fn).toHaveBeenCalled();
expect(fn.calls.count()).toBe(2);
scheduler.tick(2 * fnDelay);
expect(spy).not.toHaveBeenCalled();
expect(spyAndRemove).toHaveBeenCalled();
});
it("removes functions during the first tick that runs the function", function() {
@@ -252,6 +254,22 @@ describe("DelayedFunctionScheduler", function() {
expect(fn.calls.count()).toBe(1);
});
it("does not remove a function that hasn't been added yet", function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
scheduler.removeFunctionWithId('foo');
scheduler.scheduleFunction(fn, fnDelay, [], false, 'foo');
expect(fn).not.toHaveBeenCalled();
scheduler.tick(fnDelay + 1);
expect(fn).toHaveBeenCalled();
});
it("updates the mockDate per scheduled time", function () {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
tickDate = jasmine.createSpy('tickDate');

View File

@@ -17,7 +17,10 @@ describe("jasmineUnderTest.pp", function () {
describe('stringify sets', function() {
it("should stringify sets properly", function() {
jasmine.getEnv().requireFunctioningSets();
expect(jasmineUnderTest.pp(new Set([1, 2]))).toEqual("Set( 1, 2 )");
var set = new Set();
set.add(1);
set.add(2);
expect(jasmineUnderTest.pp(set)).toEqual("Set( 1, 2 )");
});
it("should truncate sets with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
@@ -26,7 +29,11 @@ describe("jasmineUnderTest.pp", function () {
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(new Set(["a", "b", "c"]))).toEqual("Set( 'a', 'b', ... )");
var set = new Set();
set.add('a');
set.add('b');
set.add('c');
expect(jasmineUnderTest.pp(set)).toEqual("Set( 'a', 'b', ... )");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
}
@@ -36,7 +43,9 @@ describe("jasmineUnderTest.pp", function () {
describe('stringify maps', function() {
it("should stringify maps properly", function() {
jasmine.getEnv().requireFunctioningMaps();
expect(jasmineUnderTest.pp(new Map([[1, 2]]))).toEqual("Map( [ 1, 2 ] )");
var map = new Map();
map.set(1,2);
expect(jasmineUnderTest.pp(map)).toEqual("Map( [ 1, 2 ] )");
});
it("should truncate maps with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
@@ -45,7 +54,11 @@ describe("jasmineUnderTest.pp", function () {
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(new Map([["a", 1], ["b", 2], ["c", 3]]))).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )");
var map = new Map();
map.set("a",1);
map.set("b",2);
map.set("c",3);
expect(jasmineUnderTest.pp(map)).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
}
@@ -120,15 +133,50 @@ describe("jasmineUnderTest.pp", function () {
});
it("should truncate objects with too many keys", function () {
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var long = {a: 1, b: 2, c: 3};
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var long = {a: 1, b: 2, c: 3};
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(long)).toEqual("Object({ a: 1, b: 2, ... })");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength;
}
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(long)).toEqual("Object({ a: 1, b: 2, ... })");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength;
}
});
function withMaxChars(maxChars, fn) {
var originalMaxChars = jasmineUnderTest.MAX_PRETTY_PRINT_CHARS;
try {
jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = maxChars;
fn();
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = originalMaxChars;
}
}
it("should truncate outputs that are too long", function() {
var big = [
{ a: 1, b: "a long string" },
{}
];
withMaxChars(34, function() {
expect(jasmineUnderTest.pp(big)).toEqual("[ Object({ a: 1, b: 'a long st ...");
});
});
it("should not serialize more objects after hitting MAX_PRETTY_PRINT_CHARS", function() {
var a = { jasmineToString: function() { return 'object a'; } },
b = { jasmineToString: function() { return 'object b'; } },
c = { jasmineToString: jasmine.createSpy('c jasmineToString').and.returnValue('') },
d = { jasmineToString: jasmine.createSpy('d jasmineToString').and.returnValue('') };
withMaxChars(30, function() {
jasmineUnderTest.pp([{a: a, b: b, c: c}, d]);
expect(c.jasmineToString).not.toHaveBeenCalled();
expect(d.jasmineToString).not.toHaveBeenCalled();
});
});
it("should print 'null' as the constructor of an object with its own constructor property", function() {
@@ -216,9 +264,9 @@ describe("jasmineUnderTest.pp", function () {
it("should stringify spy objects properly", function() {
var TestObject = {
someFunction: function() {}
},
env = new jasmineUnderTest.Env();
someFunction: function() {}
},
env = new jasmineUnderTest.Env();
var spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() {return [];}});

View File

@@ -375,27 +375,30 @@ describe("QueueRunner", function() {
expect(onComplete).toHaveBeenCalled();
});
it("fails the function when the promise is rejected", function() {
it("handles a rejected promise like an unhandled exception", function() {
var promise = new StubPromise(),
queueableFn1 = { fn: function() {
setTimeout(function() { promise.rejectHandler('foo'); }, 100);
setTimeout(function() {
promise.rejectHandler('foo')
}, 100);
return promise;
} },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
onExceptionCallback = jasmine.createSpy('on exception callback'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn
onException: onExceptionCallback
});
queueRunner.execute();
expect(failFn).not.toHaveBeenCalled();
expect(onExceptionCallback).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(failFn).toHaveBeenCalledWith('foo');
expect(onExceptionCallback).toHaveBeenCalledWith('foo');
expect(queueableFn2.fn).toHaveBeenCalled();
});
});

View File

@@ -222,6 +222,7 @@ describe("Spec", function() {
fullName: 'a suite with a spec',
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: ''
});
});

View File

@@ -287,6 +287,24 @@ describe("SpyRegistry", function() {
expect(jasmineUnderTest.isSpy(subject.spiedFunc)).toBe(false);
});
it("restores window.onerror by overwriting, not deleting", function() {
function FakeWindow() {
}
FakeWindow.prototype.onerror = function() {};
var spies = [],
global = new FakeWindow(),
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() { return spies; },
global: global
});
spyRegistry.spyOn(global, 'onerror');
spyRegistry.clearSpies();
expect(global.onerror).toBe(FakeWindow.prototype.onerror);
expect(global.hasOwnProperty('onerror')).toBe(true);
});
});
describe('spying on properties', function() {

View File

@@ -92,12 +92,35 @@ describe("SpyStrategy", function() {
expect(returnValue).toEqual(67);
});
it("allows a fake async function to be called instead", function(done) {
jasmine.getEnv().requireAsyncAwait();
var originalFn = jasmine.createSpy("original"),
fakeFn = jasmine.createSpy("fake").and.callFake(eval("async () => { return 67; }")),
spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}),
returnValue;
spyStrategy.callFake(fakeFn);
spyStrategy.exec().then(function (returnValue) {
expect(originalFn).not.toHaveBeenCalled();
expect(fakeFn).toHaveBeenCalled();
expect(returnValue).toEqual(67);
done();
}).catch(function (err) {
done.fail(err);
})
});
it('throws an error when a non-function is passed to callFake strategy', function() {
var originalFn = jasmine.createSpy('original'),
spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn}),
invalidFakes = [5, 'foo', {}, true, false, null, void 0, new Date(), /.*/];
spyOn(jasmineUnderTest, 'isFunction_').and.returnValue(false);
spyOn(jasmineUnderTest, 'isAsyncFunction_').and.returnValue(false);
expect(function () {
spyStrategy.callFake(function() {});
}).toThrowError(/^Argument passed to callFake should be a function, got/);
expect(function () {
spyStrategy.callFake(function() {});

View File

@@ -29,6 +29,38 @@ describe("Any", function() {
expect(any.asymmetricMatch(true)).toBe(true);
});
it("matches a Map", function() {
jasmine.getEnv().requireFunctioningMaps();
var any = new jasmineUnderTest.Any(Map);
expect(any.asymmetricMatch(new Map())).toBe(true);
});
it("matches a Set", function() {
jasmine.getEnv().requireFunctioningSets();
var any = new jasmineUnderTest.Any(Set);
expect(any.asymmetricMatch(new Set())).toBe(true);
});
it("matches a TypedArray", function() {
jasmine.getEnv().requireFunctioningTypedArrays();
var any = new jasmineUnderTest.Any(Uint32Array);
expect(any.asymmetricMatch(new Uint32Array([]))).toBe(true);
});
it("matches a Symbol", function() {
jasmine.getEnv().requireFunctioningSymbols();
var any = new jasmineUnderTest.Any(Symbol);
expect(any.asymmetricMatch(Symbol())).toBe(true);
});
it("matches another constructed object", function() {
var Thing = function() {},
any = new jasmineUnderTest.Any(Thing);

View File

@@ -23,6 +23,38 @@ describe("Anything", function() {
expect(anything.asymmetricMatch([1,2,3])).toBe(true);
});
it("matches a Map", function() {
jasmine.getEnv().requireFunctioningMaps();
var anything = new jasmineUnderTest.Anything();
expect(anything.asymmetricMatch(new Map())).toBe(true);
});
it("matches a Set", function() {
jasmine.getEnv().requireFunctioningSets();
var anything = new jasmineUnderTest.Anything();
expect(anything.asymmetricMatch(new Set())).toBe(true);
});
it("matches a TypedArray", function() {
jasmine.getEnv().requireFunctioningTypedArrays();
var anything = new jasmineUnderTest.Anything();
expect(anything.asymmetricMatch(new Uint32Array([]))).toBe(true);
});
it("matches a Symbol", function() {
jasmine.getEnv().requireFunctioningSymbols();
var anything = new jasmineUnderTest.Anything();
expect(anything.asymmetricMatch(Symbol())).toBe(true);
});
it("doesn't match undefined", function() {
var anything = new jasmineUnderTest.Anything();

View File

@@ -1485,6 +1485,7 @@ describe("Env integration", function() {
reporter.jasmineDone.and.callFake(function() {
var specStatus = reporter.specDone.calls.argsFor(0)[0];
expect(specStatus.status).toBe('pending');
expect(specStatus.pendingReason).toBe('with a message');
done();
@@ -1499,6 +1500,45 @@ describe("Env integration", function() {
env.execute();
});
it('should report pending spec messages from promise-returning functions', function(done) {
function StubPromise(fn) {
try {
fn();
} catch (e) {
this.exception = e;
}
}
StubPromise.prototype.then = function(resolve, reject) {
reject(this.exception);
};
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
'specDone',
'jasmineDone'
]);
reporter.jasmineDone.and.callFake(function() {
var specStatus = reporter.specDone.calls.argsFor(0)[0];
expect(specStatus.status).toBe('pending');
expect(specStatus.pendingReason).toBe('with a message');
done();
});
env.addReporter(reporter);
env.it('will be pending', function() {
return new StubPromise(function() {
env.pending('with a message');
});
});
env.execute();
});
it('should report using fallback reporter', function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
@@ -1903,4 +1943,108 @@ describe("Env integration", function() {
env.execute();
});
it('should throw on suites/specs/befores/afters nested in methods other than \'describe\'', function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']);
reporter.jasmineDone.and.callFake(function() {
var msg = /\'.*\' should only be used in \'describe\' function/;
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite describe', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite xdescribe', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite fdescribe', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('spec it', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('spec xit', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('spec fit', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('beforeAll spec', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('beforeEach spec', [msg]);
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('afterAll', [msg]);
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('afterEach spec', [msg]);
done();
});
env.addReporter(reporter);
env.describe('suite', function() {
env.it('describe', function() { env.describe('inner suite', function() {}); });
env.it('xdescribe', function() { env.xdescribe('inner suite', function() {}); });
env.it('fdescribe', function() { env.fdescribe('inner suite', function() {}); });
});
env.describe('spec', function() {
env.it('it', function() { env.it('inner spec', function() {}); });
env.it('xit', function() { env.xit('inner spec', function() {}); });
env.it('fit', function() { env.fit('inner spec', function() {}); });
});
env.describe('beforeAll', function() {
env.beforeAll(function() { env.beforeAll(function() {}); });
env.it('spec', function() {});
});
env.describe('beforeEach', function() {
env.beforeEach(function() { env.beforeEach(function() {}); });
env.it('spec', function() {});
});
env.describe('afterAll', function() {
env.afterAll(function() { env.afterAll(function() {}); });
env.it('spec', function() {});
});
env.describe('afterEach', function() {
env.afterEach(function() { env.afterEach(function() {}); });
env.it('spec', function() {});
});
env.execute();
});
it('should report deprecation warnings on the correct specs and suites', function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']);
reporter.jasmineDone.and.callFake(function(result) {
expect(result.deprecationWarnings).toEqual([
jasmine.objectContaining({ message: 'top level deprecation' })
]);
expect(reporter.suiteDone).toHaveBeenCalledWith(jasmine.objectContaining({
fullName: 'suite',
deprecationWarnings: [
jasmine.objectContaining({ message: 'suite level deprecation' })
]
}));
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({
fullName: 'suite spec',
deprecationWarnings: [
jasmine.objectContaining({ message: 'spec level deprecation' })
]
}));
done();
});
env.addReporter(reporter);
env.deprecated('top level deprecation');
env.describe('suite', function() {
env.beforeAll(function() {
env.deprecated('suite level deprecation');
});
env.it('spec', function() {
env.deprecated('spec level deprecation');
});
});
env.execute();
});
});

View File

@@ -71,7 +71,7 @@ describe("matchersUtil", function() {
it("fails for Arrays whose contents are equivalent, but have differing properties", function() {
var one = [1,2,3],
two = [1,2,3];
two = [1,2,3];
one.foo = 'bar';
two.foo = 'baz';
@@ -81,7 +81,7 @@ describe("matchersUtil", function() {
it("passes for Arrays with equivalent contents and properties", function() {
var one = [1,2,3],
two = [1,2,3];
two = [1,2,3];
one.foo = 'bar';
two.foo = 'bar';
@@ -122,7 +122,7 @@ describe("matchersUtil", function() {
it("passes for Objects that are equivalent (with cycles)", function() {
var actual = { a: "foo" },
expected = { a: "foo" };
expected = { a: "foo" };
actual.b = actual;
expected.b = actual;
@@ -166,6 +166,16 @@ describe("matchersUtil", function() {
expect(jasmineUnderTest.matchersUtil.equals(a,b)).toBe(true);
});
it("passes for equivalent Promises (GitHub issue #1314)", function() {
if (typeof Promise === 'undefined') { return; }
var p1 = new Promise(function () {}),
p2 = new Promise(function () {});
expect(jasmineUnderTest.matchersUtil.equals(p1, p1)).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(p1, p2)).toBe(false);
});
describe("when running in a browser", function() {
function isNotRunningInBrowser() {
@@ -332,7 +342,7 @@ describe("matchersUtil", function() {
it("passes for an asymmetric equality tester that returns true when a custom equality tester return false", function() {
var asymmetricTester = { asymmetricMatch: function(other) { return true; } },
symmetricTester = function(a, b) { return false; };
symmetricTester = function(a, b) { return false; };
expect(jasmineUnderTest.matchersUtil.equals(asymmetricTester, true, [symmetricTester])).toBe(true);
expect(jasmineUnderTest.matchersUtil.equals(true, asymmetricTester, [symmetricTester])).toBe(true);
@@ -350,7 +360,7 @@ describe("matchersUtil", function() {
it("passes when an Any is compared to an Any that checks for the same type", function() {
var any1 = new jasmineUnderTest.Any(Function),
any2 = new jasmineUnderTest.Any(Function);
any2 = new jasmineUnderTest.Any(Function);
expect(jasmineUnderTest.matchersUtil.equals(any1, any2)).toBe(true);
});
@@ -359,7 +369,7 @@ describe("matchersUtil", function() {
if (jasmine.getEnv().ieVersion < 9) { return; }
var objA = Object.create(null),
objB = Object.create(null);
objB = Object.create(null);
objA.name = 'test';
objB.name = 'test';
@@ -371,7 +381,7 @@ describe("matchersUtil", function() {
if (jasmine.getEnv().ieVersion < 9) { return; }
var objA = Object.create(null),
objB = Object.create(null);
objB = Object.create(null);
objA.name = 'test';
objB.test = 'name';
@@ -386,31 +396,94 @@ describe("matchersUtil", function() {
it("passes when comparing identical sets", function() {
jasmine.getEnv().requireFunctioningSets();
var setA = new Set([6, 5]);
var setA = new Set();
setA.add(6);
setA.add(5);
var setB = new Set();
setB.add(6);
setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true);
});
it("passes when comparing identical sets with different insertion order", function() {
it("passes when comparing identical sets with different insertion order and simple elements", function() {
jasmine.getEnv().requireFunctioningSets();
var setA = new Set([3, 6]);
var setB = new Set([6, 3]);
var setA = new Set();
setA.add(3);
setA.add(6);
var setB = new Set();
setB.add(6);
setB.add(3);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true);
});
it("passes when comparing identical sets with different insertion order and complex elements 1", function() {
jasmine.getEnv().requireFunctioningSets();
var setA1 = new Set();
setA1.add(['a',3]);
setA1.add([6,1]);
var setA2 = new Set();
setA1.add(['y',3]);
setA1.add([6,1]);
var setA = new Set();
setA.add(setA1);
setA.add(setA2);
var setB1 = new Set();
setB1.add([6,1]);
setB1.add(['a',3]);
var setB2 = new Set();
setB1.add([6,1]);
setB1.add(['y',3]);
var setB = new Set();
setB.add(setB1);
setB.add(setB2);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true);
});
it("passes when comparing identical sets with different insertion order and complex elements 2", function() {
jasmine.getEnv().requireFunctioningSets();
var setA = new Set();
setA.add([[1,2], [3,4]]);
setA.add([[5,6], [7,8]]);
var setB = new Set();
setB.add([[5,6], [7,8]]);
setB.add([[1,2], [3,4]]);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(true);
});
it("fails for sets with different elements", function() {
jasmine.getEnv().requireFunctioningSets();
var setA = new Set([6, 3, 5]);
var setB = new Set([6, 4, 5]);
var setA = new Set();
setA.add(6);
setA.add(3);
setA.add(5);
var setB = new Set();
setB.add(6);
setB.add(4);
setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false);
});
it("fails for sets of different size", function() {
jasmine.getEnv().requireFunctioningSets();
var setA = new Set([6, 3]);
var setB = new Set([6, 4, 5]);
var setA = new Set();
setA.add(6);
setA.add(3);
var setB = new Set();
setB.add(6);
setB.add(4);
setB.add(5);
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false);
});
@@ -421,7 +494,8 @@ describe("matchersUtil", function() {
it("passes when comparing identical maps", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 5]]);
var mapA = new Map();
mapA.set(6, 5);
var mapB = new Map();
mapB.set(6, 5);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(true);
@@ -429,22 +503,34 @@ describe("matchersUtil", function() {
it("passes when comparing identical maps with different insertion order", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([['a', 3], [6, 1]]);
var mapB = new Map([[6, 1], ['a', 3]]);
var mapA = new Map();
mapA.set("a", 3);
mapA.set(6, 1);
var mapB = new Map();
mapB.set(6, 1);
mapB.set("a", 3);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(true);
});
it("fails for maps with different elements", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 3], [5, 1]]);
var mapB = new Map([[6, 4], [5, 1]]);
var mapA = new Map();
mapA.set(6, 3);
mapA.set(5, 1);
var mapB = new Map();
mapB.set(6, 4);
mapB.set(5, 1);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
});
it("fails for maps of different size", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 3]]);
var mapB = new Map([[6, 4], [5, 1]]);
var mapA = new Map();
mapA.set(6, 3);
var mapB = new Map();
mapB.set(6, 4);
mapB.set(5, 1);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
});
@@ -461,28 +547,28 @@ describe("matchersUtil", function() {
Object.defineProperty(Array.prototype, 'findIndex', {
enumerable: true,
value: function (predicate) {
if (this === null) {
throw new TypeError('Array.prototype.findIndex called on null or undefined');
}
if (this === null) {
throw new TypeError('Array.prototype.findIndex called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return i;
}
}
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return i;
}
}
return -1;
}
return -1;
}
});
});

View File

@@ -374,9 +374,11 @@ describe("toEqual", function() {
it("reports mismatches between Sets", function() {
jasmine.getEnv().requireFunctioningSets();
var actual = new Set([1]),
expected = new Set([2]),
message = 'Expected Set( 1 ) to equal Set( 2 ).';
var actual = new Set();
actual.add(1);
var expected = new Set();
expected.add(2);
var message = 'Expected Set( 1 ) to equal Set( 2 ).';
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -384,9 +386,11 @@ describe("toEqual", function() {
it("reports deep mismatches within Sets", function() {
jasmine.getEnv().requireFunctioningSets();
var actual = new Set([{x: 1}]),
expected = new Set([{x: 2}]),
message = 'Expected Set( Object({ x: 1 }) ) to equal Set( Object({ x: 2 }) ).';
var actual = new Set();
actual.add({x: 1});
var expected = new Set();
expected.add({x: 2});
var message = 'Expected Set( Object({ x: 1 }) ) to equal Set( Object({ x: 2 }) ).';
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -394,9 +398,14 @@ describe("toEqual", function() {
it("reports mismatches between Sets nested in objects", function() {
jasmine.getEnv().requireFunctioningSets();
var actual = {sets: [new Set([1])]},
expected = {sets: [new Set([2])]},
message = "Expected $.sets[0] = Set( 1 ) to equal Set( 2 ).";
var actualSet = new Set();
actualSet.add(1);
var expectedSet = new Set();
expectedSet.add(2);
var actual = { sets: [actualSet] };
var expected = { sets: [expectedSet] };
var message = "Expected $.sets[0] = Set( 1 ) to equal Set( 2 ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -404,9 +413,12 @@ describe("toEqual", function() {
it("reports mismatches between Sets of different lengths", function() {
jasmine.getEnv().requireFunctioningSets();
var actual = new Set([1, 2]),
expected = new Set([2]),
message = 'Expected Set( 1, 2 ) to equal Set( 2 ).';
var actual = new Set();
actual.add(1);
actual.add(2);
var expected = new Set();
expected.add(2);
var message = 'Expected Set( 1, 2 ) to equal Set( 2 ).';
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -415,9 +427,13 @@ describe("toEqual", function() {
jasmine.getEnv().requireFunctioningSets();
// Use 'duplicate' object in actual so sizes match
var actual = new Set([{x: 1}, {x: 1}]),
expected = new Set([{x: 1}, {x: 2}]),
message = 'Expected Set( Object({ x: 1 }), Object({ x: 1 }) ) to equal Set( Object({ x: 1 }), Object({ x: 2 }) ).';
var actual = new Set();
actual.add({x: 1});
actual.add({x: 1});
var expected = new Set();
expected.add({x: 1});
expected.add({x: 2});
var message = 'Expected Set( Object({ x: 1 }), Object({ x: 1 }) ) to equal Set( Object({ x: 1 }), Object({ x: 2 }) ).';
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -426,9 +442,13 @@ describe("toEqual", function() {
jasmine.getEnv().requireFunctioningSets();
// Use 'duplicate' object in expected so sizes match
var actual = new Set([{x: 1}, {x: 2}]),
expected = new Set([{x: 1}, {x: 1}]),
message = 'Expected Set( Object({ x: 1 }), Object({ x: 2 }) ) to equal Set( Object({ x: 1 }), Object({ x: 1 }) ).';
var actual = new Set();
actual.add({x: 1});
actual.add({x: 2});
var expected = new Set();
expected.add({x: 1});
expected.add({x: 1});
var message = 'Expected Set( Object({ x: 1 }), Object({ x: 2 }) ) to equal Set( Object({ x: 1 }), Object({ x: 1 }) ).';
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -436,11 +456,13 @@ describe("toEqual", function() {
// == Maps ==
it("does not report mismatches between deep equal Maps", function() {
jasmine.getEnv().requireFunctioningSets();
jasmine.getEnv().requireFunctioningMaps();
// values are the same but with different object identity
var actual = new Map([['a', {x: 1}]]),
expected = new Map([['a', {x: 1}]]);
var actual = new Map();
actual.set('a',{x:1});
var expected = new Map();
expected.set('a',{x:1});
expect(compareEquals(actual, expected).pass).toBe(true);
});
@@ -448,9 +470,11 @@ describe("toEqual", function() {
it("reports deep mismatches within Maps", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([['a', {x: 1}]]),
expected = new Map([['a', {x: 2}]]),
message = "Expected Map( [ 'a', Object({ x: 1 }) ] ) to equal Map( [ 'a', Object({ x: 2 }) ] ).";
var actual = new Map();
actual.set('a',{x:1});
var expected = new Map();
expected.set('a',{x:2});
var message = "Expected Map( [ 'a', Object({ x: 1 }) ] ) to equal Map( [ 'a', Object({ x: 2 }) ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -458,9 +482,12 @@ describe("toEqual", function() {
it("reports mismatches between Maps nested in objects", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = {Maps: [new Map([['a', 1]])]},
expected = {Maps: [new Map([['a', 2]])]},
message = "Expected $.Maps[0] = Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
var actual = {Maps:[new Map()]};
actual.Maps[0].set('a',1);
var expected = {Maps:[new Map()]};
expected.Maps[0].set('a',2);
var message = "Expected $.Maps[0] = Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -468,9 +495,12 @@ describe("toEqual", function() {
it("reports mismatches between Maps of different lengths", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([['a', 1]]),
expected = new Map([['a', 2], ['b', 1]]),
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ], [ 'b', 1 ] ).";
var actual = new Map();
actual.set('a',1);
var expected = new Map();
expected.set('a',2);
expected.set('b',1);
var message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ], [ 'b', 1 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
@@ -478,18 +508,22 @@ describe("toEqual", function() {
it("reports mismatches between Maps with equal values but differing keys", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([['a', 1]]),
expected = new Map([['b', 1]]),
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'b', 1 ] ).";
var actual = new Map();
actual.set('a',1);
var expected = new Map();
expected.set('b',1);
var message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'b', 1 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("does not report mismatches between Maps with keys with same object identity", function() {
jasmine.getEnv().requireFunctioningMaps();
var key = {x: 1},
actual = new Map([[key, 2]]),
expected = new Map([[key, 2]]);
var key = {x: 1};
var actual = new Map();
actual.set(key,2);
var expected = new Map();
expected.set(key,2);
expect(compareEquals(actual, expected).pass).toBe(true);
});
@@ -497,13 +531,64 @@ describe("toEqual", function() {
it("reports mismatches between Maps with identical keys with different object identity", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([[{x: 1}, 2]]),
expected = new Map([[{x: 1}, 2]]),
message = "Expected Map( [ Object({ x: 1 }), 2 ] ) to equal Map( [ Object({ x: 1 }), 2 ] ).";
var actual = new Map();
actual.set({x:1},2);
var expected = new Map();
expected.set({x:1},2);
var message = "Expected Map( [ Object({ x: 1 }), 2 ] ) to equal Map( [ Object({ x: 1 }), 2 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("does not report mismatches when comparing Map key to jasmine.anything()", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map();
actual.set('a',1);
var expected = new Map();
expected.set(jasmineUnderTest.anything(),1);
expect(compareEquals(actual, expected).pass).toBe(true);
});
it("does not report mismatches when comparing Maps with the same symbol keys", function() {
jasmine.getEnv().requireFunctioningMaps();
jasmine.getEnv().requireFunctioningSymbols();
var key = Symbol();
var actual = new Map();
actual.set(key,1);
var expected = new Map();
expected.set(key,1);
expect(compareEquals(actual, expected).pass).toBe(true);
});
it("reports mismatches between Maps with different symbol keys", function() {
jasmine.getEnv().requireFunctioningMaps();
jasmine.getEnv().requireFunctioningSymbols();
var actual = new Map();
actual.set(Symbol(),1);
var expected = new Map();
expected.set(Symbol(),1);
var message = "Expected Map( [ Symbol(), 1 ] ) to equal Map( [ Symbol(), 1 ] ).";
expect(compareEquals(actual, expected).message).toBe(message);
});
it("does not report mismatches when comparing Map symbol key to jasmine.anything()", function() {
jasmine.getEnv().requireFunctioningMaps();
jasmine.getEnv().requireFunctioningSymbols();
var actual = new Map();
actual.set(Symbol(),1);
var expected = new Map();
expected.set(jasmineUnderTest.anything(),1);
expect(compareEquals(actual, expected).pass).toBe(true);
});
function isNotRunningInBrowser() {
return typeof document === 'undefined'
}

View File

@@ -3,10 +3,25 @@
if (typeof Map === 'undefined') { return false; }
try {
var s = new Map([['a', 4]]);
if (s.size !== 1) { return false; }
if (s.keys().next().value !== 'a') { return false; }
if (s.values().next().value !== 4) { return false; }
var s = new Map();
s.set('a',1);
s.set('b',2);
if (s.size !== 2) { return false; }
if (s.has('a') !== true) { return false; }
var iterations = 0;
var ifForEachWorking = true;
s.forEach(function(value, key, map) {
ifForEachWorking = ifForEachWorking && map === s;
if (key==='a') {
ifForEachWorking = ifForEachWorking && value===1;
}
iterations++;
});
if (iterations !== 2) { return false; }
if (ifForEachWorking !== true) { return false; }
return true;
} catch(e) {
return false;

View File

@@ -3,9 +3,29 @@
if (typeof Set === 'undefined') { return false; }
try {
var s = new Set([4]);
if (s.size !== 1) { return false; }
if (s.values().next().value !== 4) { return false; }
var s = new Set();
s.add(1);
s.add(2);
if (s.size !== 2) { return false; }
if (s.has(1) !== true) { return false; }
var iterations = 0;
var isForEachWorking = true;
s.forEach(function(value, key, set) {
isForEachWorking = isForEachWorking && set === s;
if (iterations===0) {
isForEachWorking = isForEachWorking && (key===value) && value===1;
} else if (iterations===1) {
isForEachWorking = isForEachWorking && (key===value) && value===2;
}
iterations++;
});
if (iterations !== 2) { return false; }
if (isForEachWorking !== true) { return false; }
return true;
} catch(e) {
return false;

View File

@@ -0,0 +1,28 @@
(function(env) {
function hasFunctioningSymbols() {
if (typeof Symbol === 'undefined') {
return false;
}
try {
var s1 = Symbol();
var s2 = Symbol();
if (typeof s1 !== 'symbol') {
return false;
}
if (s1 === s2) {
return false;
}
return true;
} catch (e) {
return false;
}
}
env.requireFunctioningSymbols = function() {
if (!hasFunctioningSymbols()) {
env.pending("Browser has incomplete or missing support for Symbols");
}
};
})(jasmine.getEnv());

View File

@@ -208,8 +208,49 @@ describe("New HtmlReporter", function() {
});
});
describe('when there are deprecation warnings', function() {
it('displays the messages in their own alert bars', 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); }
});
reporter.initialize();
reporter.jasmineStarted({});
reporter.specDone({
status: 'passed',
deprecationWarnings: [{ message: 'spec deprecation' }],
failedExpectations: [],
passedExpectations: []
});
reporter.suiteDone({
status: 'passed',
deprecationWarnings: [{ message: 'suite deprecation' }],
failedExpectations: []
});
reporter.jasmineDone({
deprecationWarnings: [{ message: 'global deprecation' }],
failedExpectations: []
});
var alertBars = container.querySelectorAll(".jasmine-alert .jasmine-bar");
expect(alertBars.length).toEqual(4);
expect(alertBars[1].innerHTML).toMatch(/spec deprecation/);
expect(alertBars[1].getAttribute("class")).toEqual('jasmine-bar jasmine-warning');
expect(alertBars[2].innerHTML).toMatch(/suite deprecation/);
expect(alertBars[3].innerHTML).toMatch(/global deprecation/);
});
});
describe("when Jasmine is done", function() {
it("adds EMPTY to the link title of specs that have no expectations", function() {
it("adds a warning to the link title of specs that have no expectations", function() {
if (!window.console) {
window.console = { error: function(){} };
}
@@ -228,7 +269,7 @@ describe("New HtmlReporter", function() {
reporter.initialize();
reporter.jasmineStarted({});
reporter.suiteStarted({id: 1});
reporter.specStarted({id: 1, status: 'passed', passedExpectations: [], failedExpectations: []});
reporter.specStarted({id: 1, passedExpectations: [], failedExpectations: []});
reporter.specDone({
id: 1,
status: 'passed',

View File

@@ -0,0 +1,34 @@
describe('Spy Registry browser-specific behavior', function() {
it('can spy on and unspy window.onerror', function() {
requireWriteableOnerror();
var spies = [],
spyRegistry = new jasmineUnderTest.SpyRegistry({
currentSpies: function() { return spies; },
global: window
}),
originalHandler = window.onerror;
try {
spyRegistry.spyOn(window, 'onerror');
spyRegistry.clearSpies();
expect(window.onerror).toBe(originalHandler);
} finally {
window.onerror = originalHandler;
}
});
function requireWriteableOnerror() {
var descriptor;
try {
descriptor = Object.getOwnPropertyDescriptor(window, 'onerror');
} catch(e) {
// IE 8 doesn't support `definePropery` on non-DOM nodes
}
if (descriptor && !(descriptor.writable || descriptor.set)) {
pending('Browser declares window.onerror to be readonly');
}
}
});

View File

@@ -7,8 +7,9 @@
],
"helpers": [
"helpers/asyncAwait.js",
"helpers/checkForSet.js",
"helpers/checkForMap.js",
"helpers/checkForSet.js",
"helpers/checkForSymbol.js",
"helpers/checkForTypedArrays.js",
"helpers/nodeDefineJasmineUnderTest.js"
],

View File

@@ -3,6 +3,7 @@
src_dir:
- 'src'
src_files:
- 'core/requireCore.js'
- 'core/base.js'
- 'core/util.js'
#end of known dependencies
@@ -18,8 +19,9 @@ stylesheets:
helpers:
- 'helpers/asyncAwait.js'
- 'helpers/BrowserFlags.js'
- 'helpers/checkForSet.js'
- 'helpers/checkForMap.js'
- 'helpers/checkForSet.js'
- 'helpers/checkForSymbol.js'
- 'helpers/checkForTypedArrays.js'
- 'helpers/defineJasmineUnderTest.js'
spec_files:

View File

@@ -7,25 +7,9 @@ getJasmineRequireObj().CallTracker = function(j$) {
var calls = [];
var opts = {};
function argCloner(context) {
var clonedArgs = [];
var argsAsArray = j$.util.argsToArray(context.args);
for(var i = 0; i < argsAsArray.length; i++) {
var str = Object.prototype.toString.apply(argsAsArray[i]),
primitives = /^\[object (Boolean|String|RegExp|Number)/;
if (argsAsArray[i] == null || str.match(primitives)) {
clonedArgs.push(argsAsArray[i]);
} else {
clonedArgs.push(j$.util.clone(argsAsArray[i]));
}
}
context.args = clonedArgs;
}
this.track = function(context) {
if(opts.cloneArgs) {
argCloner(context);
context.args = j$.util.cloneArgs(context.args);
}
calls.push(context);
};

View File

@@ -1,4 +1,7 @@
getJasmineRequireObj().Clock = function() {
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
/**
* _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
* @class Clock
@@ -22,6 +25,7 @@ getJasmineRequireObj().Clock = function() {
delayedFunctionScheduler,
timer;
self.FakeTimeout = FakeTimeout;
/**
* Install the mock clock over the built-in methods.
@@ -145,7 +149,15 @@ getJasmineRequireObj().Clock = function() {
}
function setTimeout(fn, delay) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2), false, timeout);
return timeout;
}
function clearTimeout(id) {
@@ -153,7 +165,15 @@ getJasmineRequireObj().Clock = function() {
}
function setInterval(fn, interval) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true, timeout);
return timeout;
}
function clearInterval(id) {
@@ -165,5 +185,18 @@ getJasmineRequireObj().Clock = function() {
}
}
/**
* Mocks Node.js Timeout class
*/
function FakeTimeout() {}
FakeTimeout.prototype.ref = function () {
return this;
};
FakeTimeout.prototype.unref = function () {
return this;
};
return Clock;
};

View File

@@ -1,10 +1,11 @@
getJasmineRequireObj().DelayedFunctionScheduler = function() {
getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
function DelayedFunctionScheduler() {
var self = this;
var scheduledLookup = [];
var scheduledFunctions = {};
var currentTime = 0;
var delayedFnCount = 0;
var deletedKeys = [];
self.tick = function(millis, tickDate) {
millis = millis || 0;
@@ -51,6 +52,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
};
self.removeFunctionWithId = function(timeoutKey) {
deletedKeys.push(timeoutKey);
for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) {
@@ -121,12 +124,14 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}
do {
deletedKeys = [];
var newCurrentTime = scheduledLookup.shift();
tickDate(newCurrentTime - currentTime);
currentTime = newCurrentTime;
var funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime];
forEachFunction(funcsToRun, function(funcToRun) {
@@ -136,6 +141,10 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
});
forEachFunction(funcsToRun, function(funcToRun) {
if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
// skip a timeoutKey deleted whilst we were running
return;
}
funcToRun.funcToCall.apply(null, funcToRun.params || []);
});
} while (scheduledLookup.length > 0 &&

View File

@@ -11,6 +11,8 @@ getJasmineRequireObj().Env = function(j$) {
var self = this;
var global = options.global || j$.getGlobal();
var hasExecuted = false;
var totalSpecsDefined = 0;
var catchExceptions = true;
@@ -197,6 +199,9 @@ getJasmineRequireObj().Env = function(j$) {
// TODO: fix this naming, and here's where the value comes in
this.catchExceptions = function(value) {
catchExceptions = !!value;
if (!catchExceptions) {
this.deprecated('The catchExceptions option is deprecated and will be replaced with stopOnSpecFailure in Jasmine 3.0');
}
return catchExceptions;
};
@@ -234,6 +239,14 @@ getJasmineRequireObj().Env = function(j$) {
return seed;
};
this.deprecated = function(msg) {
var runnable = currentRunnable() || topSuite;
runnable.addDeprecationWarning(msg);
if(typeof console !== 'undefined' && typeof console.warn !== 'undefined') {
console.error('DEPRECATION: ' + msg);
}
};
var queueRunnerFactory = function(options) {
options.catchException = catchException;
options.clearStack = options.clearStack || clearStack;
@@ -241,6 +254,7 @@ getJasmineRequireObj().Env = function(j$) {
options.fail = self.fail;
options.globalErrors = globalErrors;
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
options.deprecated = self.deprecated;
new j$.QueueRunner(options).execute();
};
@@ -260,6 +274,12 @@ getJasmineRequireObj().Env = function(j$) {
};
this.execute = function(runnablesToRun) {
if (hasExecuted) {
this.deprecated('Executing the same Jasmine multiple times will no longer work in Jasmine 3.0');
}
hasExecuted = true;
if(!runnablesToRun) {
if (focusedRunnables.length) {
runnablesToRun = focusedRunnables;
@@ -326,10 +346,12 @@ getJasmineRequireObj().Env = function(j$) {
* @typedef JasmineDoneInfo
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
*/
reporter.jasmineDone({
order: order,
failedExpectations: topSuite.result.failedExpectations
failedExpectations: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
});
});
};
@@ -384,6 +406,13 @@ getJasmineRequireObj().Env = function(j$) {
}
};
function ensureIsNotNested(method) {
var runnable = currentRunnable();
if (runnable !== null && runnable !== undefined) {
throw new Error('\'' + method + '\' should only be used in \'describe\' function');
}
}
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
@@ -399,6 +428,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.describe = function(description, specDefinitions) {
ensureIsNotNested('describe');
ensureIsFunction(specDefinitions, 'describe');
var suite = suiteFactory(description);
if (specDefinitions.length > 0) {
@@ -412,6 +442,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.xdescribe = function(description, specDefinitions) {
ensureIsNotNested('xdescribe');
ensureIsFunction(specDefinitions, 'xdescribe');
var suite = suiteFactory(description);
suite.pend();
@@ -422,6 +453,8 @@ getJasmineRequireObj().Env = function(j$) {
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
ensureIsNotNested('fdescribe');
ensureIsFunction(specDefinitions, 'fdescribe');
var suite = suiteFactory(description);
suite.isFocused = true;
@@ -519,6 +552,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.it = function(description, fn, timeout) {
ensureIsNotNested('it');
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
if (arguments.length > 1 && typeof fn !== 'undefined') {
@@ -533,6 +567,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.xit = function(description, fn, timeout) {
ensureIsNotNested('xit');
// xit(), like it(), doesn't always have a fn argument, so only check the
// type when needed.
if (arguments.length > 1 && typeof fn !== 'undefined') {
@@ -544,6 +579,8 @@ getJasmineRequireObj().Env = function(j$) {
};
this.fit = function(description, fn, timeout){
this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
ensureIsNotNested('fit');
ensureIsFunctionOrAsync(fn, 'fit');
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
@@ -561,6 +598,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsNotNested('beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
@@ -569,6 +607,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeAll = function(beforeAllFunction, timeout) {
ensureIsNotNested('beforeAll');
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
@@ -577,6 +616,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterEach = function(afterEachFunction, timeout) {
ensureIsNotNested('afterEach');
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({
@@ -586,6 +626,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterAll = function(afterAllFunction, timeout) {
ensureIsNotNested('afterAll');
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({
fn: afterAllFunction,

View File

@@ -3,6 +3,8 @@ getJasmineRequireObj().pp = function(j$) {
function PrettyPrinter() {
this.ppNestLevel_ = 0;
this.seen = [];
this.length = 0;
this.stringParts = [];
}
function hasCustomToString(value) {
@@ -36,9 +38,9 @@ getJasmineRequireObj().pp = function(j$) {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.getType_(value) == '[object Set]') {
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.getType_(value) == '[object Map]') {
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
@@ -57,6 +59,10 @@ getJasmineRequireObj().pp = function(j$) {
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
@@ -82,30 +88,15 @@ getJasmineRequireObj().pp = function(j$) {
return objKeys.length > length;
};
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitMap = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
function StringPrettyPrinter() {
PrettyPrinter.call(this);
this.stringParts = [];
}
j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
StringPrettyPrinter.prototype.emitScalar = function(value) {
PrettyPrinter.prototype.emitScalar = function(value) {
this.append(value);
};
StringPrettyPrinter.prototype.emitString = function(value) {
PrettyPrinter.prototype.emitString = function(value) {
this.append('\'' + value + '\'');
};
StringPrettyPrinter.prototype.emitArray = function(array) {
PrettyPrinter.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
@@ -139,47 +130,57 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' ]');
};
StringPrettyPrinter.prototype.emitSet = function(set) {
PrettyPrinter.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = set.values();
for (var i = 0; i < size; i++) {
var i = 0;
set.forEach( function( value, key ) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
this.format(value);
i++;
}, this );
if (set.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitMap = function(map) {
PrettyPrinter.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = map.entries();
for (var i = 0; i < size; i++) {
var i = 0;
map.forEach( function( value, key ) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
this.format([key,value]);
i++;
}, this );
if (map.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitObject = function(obj) {
PrettyPrinter.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
@@ -212,7 +213,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' })');
};
StringPrettyPrinter.prototype.emitTypedArray = function(arr) {
PrettyPrinter.prototype.emitTypedArray = function(arr) {
var constructorName = j$.fnNameFor(arr.constructor),
limitedArray = Array.prototype.slice.call(arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH),
itemsString = Array.prototype.join.call(limitedArray, ', ');
@@ -224,7 +225,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
StringPrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
this.append(property);
this.append(': ');
if (isGetter) {
@@ -234,10 +235,33 @@ getJasmineRequireObj().pp = function(j$) {
}
};
StringPrettyPrinter.prototype.append = function(value) {
this.stringParts.push(value);
PrettyPrinter.prototype.append = function(value) {
var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
};
function truncate(s, maxlen) {
if (s.length <= maxlen) {
return { value: s, truncated: false };
}
s = s.substring(0, maxlen - 4) + ' ...';
return { value: s, truncated: true };
}
function MaxCharsReachedError() {
this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS +
' characters while pretty-printing a value';
}
MaxCharsReachedError.prototype = new Error();
function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) :
(function(o) {
@@ -268,8 +292,8 @@ getJasmineRequireObj().pp = function(j$) {
return extraKeys;
}
return function(value) {
var stringPrettyPrinter = new StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.stringParts.join('');
var prettyPrinter = new PrettyPrinter();
prettyPrinter.format(value);
return prettyPrinter.stringParts.join('');
};
};

View File

@@ -5,7 +5,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return function() {
if (!called) {
called = true;
fn();
fn.apply(null, arguments);
}
return null;
};
@@ -24,6 +24,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
this.completeOnFirstError = !!attrs.completeOnFirstError;
this.deprecated = attrs.deprecated;
}
QueueRunner.prototype.execute = function() {
@@ -83,9 +84,13 @@ getJasmineRequireObj().QueueRunner = function(j$) {
clearTimeout(timeoutId);
self.globalErrors.popListener(handleError);
}),
next = once(function () {
next = once(function (err) {
cleanup();
if (err instanceof Error) {
self.deprecated('done callback received an Error object. Jasmine 3.0 will treat this as a failure');
}
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
@@ -125,7 +130,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, next.fail);
maybeThenable.then(next, onPromiseRejection);
completedSynchronously = false;
return { completedSynchronously: false };
}
@@ -147,6 +152,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
errored = true;
}
function onPromiseRejection(e) {
onException(e);
next();
}
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {

View File

@@ -1,4 +1,4 @@
getJasmineRequireObj().ReportDispatcher = function() {
getJasmineRequireObj().ReportDispatcher = function(j$) {
function ReportDispatcher(methods) {
var dispatchedMethods = methods || [];
@@ -36,7 +36,7 @@ getJasmineRequireObj().ReportDispatcher = function() {
for (var i = 0; i < reporters.length; i++) {
var reporter = reporters[i];
if (reporter[method]) {
reporter[method].apply(reporter, args);
reporter[method].apply(reporter, j$.util.cloneArgs(args));
}
}
}

View File

@@ -25,6 +25,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} fullName - The full description including all ancestors of this spec.
* @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
* @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
* @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
* @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
*/
@@ -34,6 +35,7 @@ getJasmineRequireObj().Spec = function(j$) {
fullName: this.getFullName(),
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: ''
};
}
@@ -149,6 +151,10 @@ getJasmineRequireObj().Spec = function(j$) {
return this.getSpecName(this);
};
Spec.prototype.addDeprecationWarning = function(msg) {
this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
};
var extractCustomPendingMessage = function(e) {
var fullMessage = e.toString(),
boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),

View File

@@ -4,6 +4,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
function SpyRegistry(options) {
options = options || {};
var global = options.global || j$.getGlobal();
var currentSpies = options.currentSpies || function() { return []; };
this.allowRespy = function(allow){
@@ -47,7 +48,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
spiedMethod = j$.createSpy(methodName, originalMethod),
restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, methodName)) {
if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
restoreStrategy = function() {
obj[methodName] = originalMethod;
};

View File

@@ -88,7 +88,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
* @param {Function} fn The function to invoke with the passed parameters.
*/
this.callFake = function(fn) {
if(!j$.isFunction_(fn)) {
if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
throw new Error('Argument passed to callFake should be a function, got ' + fn);
}
plan = fn;

View File

@@ -21,13 +21,15 @@ getJasmineRequireObj().Suite = function(j$) {
* @property {String} description - The description text passed to the {@link describe} that made this suite.
* @property {String} fullName - The full description including all ancestors of this suite.
* @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
*/
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: []
failedExpectations: [],
deprecationWarnings: []
};
}
@@ -147,6 +149,10 @@ getJasmineRequireObj().Suite = function(j$) {
}
};
Suite.prototype.addDeprecationWarning = function(msg) {
this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
};
function isAfterAll(children) {
return children && children[0].result.status;
}

View File

@@ -24,6 +24,9 @@ getJasmineRequireObj().Any = function(j$) {
}
if (this.expectedObject == Object) {
if (other === null) {
j$.getEnv().deprecated('jasmine.Any(Object) will no longer match null in Jasmine 3.0');
}
return typeof other == 'object';
}
@@ -31,6 +34,12 @@ getJasmineRequireObj().Any = function(j$) {
return typeof other == 'boolean';
}
/* jshint -W122 */
if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
return typeof other == 'symbol';
}
/* jshint +W122 */
return other instanceof this.expectedObject;
};

View File

@@ -8,14 +8,20 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Set this to a lower value to speed up pretty printing if you have large objects.
* @name jasmine.MAX_PRETTY_PRINT_DEPTH
*/
j$.MAX_PRETTY_PRINT_DEPTH = 40;
j$.MAX_PRETTY_PRINT_DEPTH = 8;
/**
* Maximum number of array elements to display when pretty printing objects.
* This will also limit the number of keys and values displayed for an object.
* Elements past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
*/
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
/**
* Maximum number of charasters to display when pretty printing objects.
* Characters past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_CHARS
*/
j$.MAX_PRETTY_PRINT_CHARS = 1000;
/**
* Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
* @name jasmine.DEFAULT_TIMEOUT_INTERVAL
@@ -87,6 +93,18 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return obj.nodeType > 0;
};
j$.isMap = function(obj) {
return typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map;
};
j$.isSet = function(obj) {
return typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set;
};
j$.isPromise = function(obj) {
return typeof jasmineGlobal.Promise !== 'undefined' && obj.constructor === jasmineGlobal.Promise;
};
j$.fnNameFor = function(func) {
if (func.name) {
return func.name;

View File

@@ -214,6 +214,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return false;
}
var aIsPromise = j$.isPromise(a);
var bIsPromise = j$.isPromise(b);
if (aIsPromise && bIsPromise) {
return a === b;
}
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = aStack.length;
@@ -247,22 +253,46 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (!result) {
return false;
}
} else if (className == '[object Map]') {
} else if (j$.isMap(a) && j$.isMap(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
// For both sets of keys, check they map to equal values in both maps
var mapKeys = [a.keys(), b.keys()];
var mapIter, mapKeyIt, mapKey;
var keysA = [];
var keysB = [];
a.forEach( function( valueA, keyA ) {
keysA.push( keyA );
});
b.forEach( function( valueB, keyB ) {
keysB.push( keyB );
});
// For both sets of keys, check they map to equal values in both maps.
// Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
var mapKeys = [keysA, keysB];
var cmpKeys = [keysB, keysA];
var mapIter, mapKey, mapValueA, mapValueB;
var cmpIter, cmpKey;
for (i = 0; result && i < mapKeys.length; i++) {
mapIter = mapKeys[i];
mapKeyIt = mapIter.next();
while (result && !mapKeyIt.done) {
mapKey = mapKeyIt.value;
result = eq(a.get(mapKey), b.get(mapKey), aStack, bStack, customTesters, j$.NullDiffBuilder());
mapKeyIt = mapIter.next();
cmpIter = cmpKeys[i];
for (var j = 0; result && j < mapIter.length; j++) {
mapKey = mapIter[j];
cmpKey = cmpIter[j];
mapValueA = a.get(mapKey);
// Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
// otherwise explicitly look up the mapKey in the other Map since we want keys with unique
// obj identity (that are otherwise equal) to not match.
if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
mapValueB = b.get(cmpKey);
} else {
mapValueB = b.get(mapKey);
}
result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
}
}
@@ -270,36 +300,49 @@ getJasmineRequireObj().matchersUtil = function(j$) {
diffBuilder.record(a, b);
return false;
}
} else if (className == '[object Set]') {
} else if (j$.isSet(a) && j$.isSet(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
var valuesA = [];
a.forEach( function( valueA ) {
valuesA.push( valueA );
});
var valuesB = [];
b.forEach( function( valueB ) {
valuesB.push( valueB );
});
// For both sets, check they are all contained in the other set
var setPairs = [[a, b], [b, a]];
var baseIter, baseValueIt, baseValue;
var otherSet, otherIter, otherValueIt, otherValue, found;
var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
var stackPairs = [[aStack, bStack], [bStack, aStack]];
var baseValues, baseValue, baseStack;
var otherValues, otherValue, otherStack;
var found;
var prevStackSize;
for (i = 0; result && i < setPairs.length; i++) {
baseIter = setPairs[i][0].values();
otherSet = setPairs[i][1];
baseValues = setPairs[i][0];
otherValues = setPairs[i][1];
baseStack = stackPairs[i][0];
otherStack = stackPairs[i][1];
// For each value in the base set...
baseValueIt = baseIter.next();
while (result && !baseValueIt.done) {
baseValue = baseValueIt.value;
for (var k = 0; result && k < baseValues.length; k++) {
baseValue = baseValues[k];
found = false;
// ... test that it is present in the other set
otherIter = otherSet.values();
otherValueIt = otherIter.next();
// Optimisation: start looking for value by object identity
found = otherSet.has(baseValue);
// If not found, compare by value equality
while (!found && !otherValueIt.done) {
otherValue = otherValueIt.value;
found = eq(baseValue, otherValue, aStack, bStack, customTesters, j$.NullDiffBuilder());
otherValueIt = otherIter.next();
for (var l = 0; !found && l < otherValues.length; l++) {
otherValue = otherValues[l];
prevStackSize = baseStack.length;
// compare by value equality
found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize);
}
}
result = result && found;
baseValueIt = baseIter.next();
}
}

View File

@@ -12,7 +12,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
jasmineGlobal = window;
}
jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {};
jasmineRequire = jasmineGlobal.jasmineRequire = {};
}
function getJasmineRequire() {
@@ -23,7 +23,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
var j$ = {};
jRequire.base(j$, jasmineGlobal);
j$.util = jRequire.util();
j$.util = jRequire.util(j$);
j$.errors = jRequire.errors();
j$.formatErrorMsg = jRequire.formatErrorMsg();
j$.Any = jRequire.Any(j$);
@@ -32,7 +32,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.MockDate = jRequire.MockDate();
j$.getClearStack = jRequire.clearStack(j$);
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.Env = jRequire.Env(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
j$.Expectation = jRequire.Expectation();
@@ -44,7 +44,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
j$.Spec = jRequire.Spec(j$);
j$.Spy = jRequire.Spy(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);

View File

@@ -197,7 +197,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
},
/**
* Install a spy on a property onto an existing object.
* Install a spy on a property installed with `Object.defineProperty` onto an existing object.
* @name spyOnProperty
* @function
* @global

View File

@@ -1,4 +1,4 @@
getJasmineRequireObj().util = function() {
getJasmineRequireObj().util = function(j$) {
var util = {};
@@ -55,6 +55,23 @@ getJasmineRequireObj().util = function() {
return cloned;
};
util.cloneArgs = function(args) {
var clonedArgs = [];
var argsAsArray = j$.util.argsToArray(args);
for(var i = 0; i < argsAsArray.length; i++) {
var str = Object.prototype.toString.apply(argsAsArray[i]),
primitives = /^\[object (Boolean|String|RegExp|Number)/;
// All falsey values are either primitives, `null`, or `undefined.
if (!argsAsArray[i] || str.match(primitives)) {
clonedArgs.push(argsAsArray[i]);
} else {
clonedArgs.push(j$.util.clone(argsAsArray[i]));
}
}
return clonedArgs;
};
util.getPropertyDescriptor = function(obj, methodName) {
var descriptor,
proto = obj;

View File

@@ -5,6 +5,46 @@ jasmineRequire.HtmlReporter = function(j$) {
elapsed: function() { return 0; }
};
function ResultsStateBuilder() {
this.topResults = new j$.ResultsNode({}, '', null);
this.currentParent = this.topResults;
this.specsExecuted = 0;
this.failureCount = 0;
this.pendingSpecCount = 0;
}
ResultsStateBuilder.prototype.suiteStarted = function(result) {
this.currentParent.addChild(result, 'suite');
this.currentParent = this.currentParent.last();
};
ResultsStateBuilder.prototype.suiteDone = function(result) {
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent;
}
};
ResultsStateBuilder.prototype.specStarted = function(result) {
};
ResultsStateBuilder.prototype.specDone = function(result) {
this.currentParent.addChild(result, 'spec');
if (result.status !== 'disabled') {
this.specsExecuted++;
}
if (result.status === 'failed') {
this.failureCount++;
}
if (result.status == 'pending') {
this.pendingSpecCount++;
}
};
function HtmlReporter(options) {
var env = options.env || {},
getContainer = options.getContainer,
@@ -17,12 +57,10 @@ jasmineRequire.HtmlReporter = function(j$) {
filterSpecs = options.filterSpecs,
timer = options.timer || noopTimer,
results = [],
specsExecuted = 0,
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols,
failedSuites = [];
failedSuites = [],
deprecationWarnings = [];
this.initialize = function() {
clearPrior();
@@ -48,12 +86,10 @@ jasmineRequire.HtmlReporter = function(j$) {
var summary = createDom('div', {className: 'jasmine-summary'});
var topResults = new j$.ResultsNode({}, '', null),
currentParent = topResults;
var stateBuilder = new ResultsStateBuilder();
this.suiteStarted = function(result) {
currentParent.addChild(result, 'suite');
currentParent = currentParent.last();
stateBuilder.suiteStarted(result);
};
this.suiteDone = function(result) {
@@ -61,27 +97,22 @@ jasmineRequire.HtmlReporter = function(j$) {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
currentParent = currentParent.parent;
stateBuilder.suiteDone(result);
addDeprecationWarnings(result);
};
this.specStarted = function(result) {
currentParent.addChild(result, 'spec');
stateBuilder.specStarted(result);
};
var failures = [];
this.specDone = function(result) {
stateBuilder.specDone(result);
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
if (result.status != 'disabled') {
specsExecuted++;
}
if (!symbols){
symbols = find('.jasmine-symbol-summary');
}
@@ -94,8 +125,6 @@ jasmineRequire.HtmlReporter = function(j$) {
));
if (result.status == 'failed') {
failureCount++;
var failure =
createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
createDom('div', {className: 'jasmine-description'},
@@ -114,9 +143,7 @@ jasmineRequire.HtmlReporter = function(j$) {
failures.push(failure);
}
if (result.status == 'pending') {
pendingSpecCount++;
}
addDeprecationWarnings(result);
};
this.jasmineDone = function(doneResult) {
@@ -179,8 +206,8 @@ jasmineRequire.HtmlReporter = function(j$) {
}
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
if (stateBuilder.specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = addToExistingQueryString('spec', '');
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
@@ -192,9 +219,9 @@ jasmineRequire.HtmlReporter = function(j$) {
var statusBarClassName = 'jasmine-bar ';
if (totalSpecsDefined > 0) {
statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); }
statusBarClassName += (stateBuilder.failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
} else {
statusBarClassName += 'jasmine-skipped';
statusBarMessage += 'No specs found';
@@ -226,10 +253,18 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message));
}
addDeprecationWarnings(doneResult);
var warningBarClassName = 'jasmine-bar jasmine-warning';
for(i = 0; i < deprecationWarnings.length; i++) {
var warning = deprecationWarnings[i];
alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning));
}
var results = find('.jasmine-results');
results.appendChild(summary);
summaryList(topResults, summary);
summaryList(stateBuilder.topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
@@ -300,6 +335,17 @@ jasmineRequire.HtmlReporter = function(j$) {
return this;
function addDeprecationWarnings(result) {
if (result && result.deprecationWarnings) {
for(var i = 0; i < result.deprecationWarnings.length; i++) {
var warning = result.deprecationWarnings[i].message;
if (!j$.util.arrayContains(warning)) {
deprecationWarnings.push(warning);
}
}
}
}
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}

View File

@@ -216,6 +216,11 @@ body {
background-color: $failing-color;
}
&.jasmine-warning {
background-color: $pending-color;
color: $text-color;
}
&.jasmine-menu {
background-color: #fff;
color: $faint-text-color;

View File

@@ -4,7 +4,7 @@ rm -rf ~/.nvm
git clone https://github.com/creationix/nvm.git ~/.nvm
(cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`)
source ~/.nvm/nvm.sh
nvm install v0.12.18
nvm install ${1:-"v0.12.18"}
npm install
npm test