Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b256741bec | ||
|
|
1d4a2b5c22 | ||
|
|
b0aac6b852 | ||
|
|
543e056056 | ||
|
|
7dfc5f506c | ||
|
|
4cce7263c4 | ||
|
|
31164106e5 | ||
|
|
f71218a44b | ||
|
|
22e9d6df20 | ||
|
|
aa72b0b7cf | ||
|
|
9f3952ff87 | ||
|
|
c604012793 | ||
|
|
6aa069d586 | ||
|
|
585287b9d6 | ||
|
|
de862f8133 | ||
|
|
4e3ae726aa | ||
|
|
9ee7b4ee0b | ||
|
|
2e737f50ca | ||
|
|
c60d669940 | ||
|
|
4c491b2dc0 | ||
|
|
f9d1e2f280 | ||
|
|
270475bc61 | ||
|
|
acb9989178 | ||
|
|
1fe1bbb6ed | ||
|
|
994878e6f6 | ||
|
|
f7c160d716 | ||
|
|
578f63b9bd | ||
|
|
b1190eefb9 | ||
|
|
271908a2c4 | ||
|
|
3372af1cf1 | ||
|
|
d355fa0806 | ||
|
|
56a79bef98 | ||
|
|
2ea4e9507c | ||
|
|
c848a66faa | ||
|
|
99fd7ddb88 | ||
|
|
5d1d19f494 | ||
|
|
4f49288f31 | ||
|
|
b9adc76dc7 | ||
|
|
9672689d40 | ||
|
|
a237ac5386 | ||
|
|
5ac3e21abb | ||
|
|
88763012e4 | ||
|
|
b1e97cfb09 | ||
|
|
8e5823c0d2 | ||
|
|
e6a7932ec1 | ||
|
|
10f1220e55 | ||
|
|
5ee03f02ed | ||
|
|
2835ca3cce | ||
|
|
120c484419 | ||
|
|
1d62504534 | ||
|
|
055d88eff8 | ||
|
|
d2b33e0c66 | ||
|
|
0c7f36a181 | ||
|
|
686d8157e5 | ||
|
|
b771c083cb | ||
|
|
fbd2ffc08b | ||
|
|
b3c8fb9797 | ||
|
|
ef3cfe7f44 | ||
|
|
0d6ecbec17 | ||
|
|
7e4b8d4531 | ||
|
|
4b696fbf26 | ||
|
|
74511f5425 | ||
|
|
3e912f7f4e | ||
|
|
19b83a7434 | ||
|
|
98569ba0f3 | ||
|
|
7f11ecb62e | ||
|
|
97f8db0616 | ||
|
|
50880fcff7 | ||
|
|
ddcae84480 | ||
|
|
9d6a95d9ba | ||
|
|
0d3b2b2f8e | ||
|
|
08f046c24c | ||
|
|
90c87140ac | ||
|
|
25d9a396aa | ||
|
|
c42b1972e2 | ||
|
|
7f8f2b5e7a | ||
|
|
9cb2f06aa6 | ||
|
|
a37b6c0d32 | ||
|
|
5533d1a920 | ||
|
|
75e652d6a7 | ||
|
|
e1f7ca51da | ||
|
|
538ae7b9ac | ||
|
|
2ea41d3e27 | ||
|
|
bd9ae3a25b | ||
|
|
1042c9a2dd | ||
|
|
92e7436db2 | ||
|
|
74fe7fb85b | ||
|
|
7e0fd79b3b | ||
|
|
8807bbb850 | ||
|
|
c93f35fbc8 | ||
|
|
4cfdd06700 | ||
|
|
19b89d437e | ||
|
|
43f96d3ecd | ||
|
|
ac42bd9b35 | ||
|
|
9fbd0ba551 | ||
|
|
52876a7bf2 | ||
|
|
2eec3427e8 | ||
|
|
ed23254865 | ||
|
|
137e7e94d3 | ||
|
|
923b8fe9c4 | ||
|
|
61cc1eec66 | ||
|
|
04be4c4583 | ||
|
|
b59ac96b51 | ||
|
|
be6ff8b24c | ||
|
|
da2005fe97 | ||
|
|
41a813521b | ||
|
|
54e7a82ef3 | ||
|
|
d5e6bf47ed | ||
|
|
5a76e59d5b | ||
|
|
f5cfa2a4c1 | ||
|
|
c21bdaf35d | ||
|
|
369e8cc08b | ||
|
|
0e9b9a11c3 | ||
|
|
9750ae59e7 | ||
|
|
2f01f64249 | ||
|
|
17c89c69d6 | ||
|
|
d85d6dd4b8 | ||
|
|
ff85714b24 | ||
|
|
0d1a9a72d9 | ||
|
|
63cc6687ff | ||
|
|
75a5681c5e | ||
|
|
9df1edbdc9 | ||
|
|
5279e7a8c4 | ||
|
|
c2e2bd7c91 | ||
|
|
bad9c63bf7 | ||
|
|
05097b3e42 | ||
|
|
1efed4c156 | ||
|
|
f4849f6401 | ||
|
|
ec2ae4d521 | ||
|
|
ac3d64cf84 | ||
|
|
2d3c8c9f26 | ||
|
|
6816bc4252 | ||
|
|
04bb56a5b5 | ||
|
|
ed31b9b844 | ||
|
|
4e47b78f1f | ||
|
|
8e23c26383 | ||
|
|
56191cfb2e | ||
|
|
8624a52ee0 | ||
|
|
a4b92b34f4 | ||
|
|
3486e8d166 | ||
|
|
8366ef9be5 | ||
|
|
ab0567c665 | ||
|
|
8676bbf11a | ||
|
|
c0a9d20a02 | ||
|
|
c7cc3b4a29 | ||
|
|
de7b7c029e | ||
|
|
7a62969a14 | ||
|
|
2710bdfc5e | ||
|
|
927cc011d6 | ||
|
|
d1a94bcf50 | ||
|
|
90dea9ab38 |
@@ -1,7 +1,16 @@
|
||||
languages:
|
||||
JavaScript: true
|
||||
ratings:
|
||||
paths:
|
||||
- "src/**/*.js"
|
||||
exclude_paths:
|
||||
- "lib/*"
|
||||
- "lib/**"
|
||||
- "dist/*"
|
||||
- "grunt/*"
|
||||
- "grunt/**"
|
||||
- "images/*"
|
||||
- "**/*.md"
|
||||
- "**/*.yml"
|
||||
- "**/*.json"
|
||||
- "**/*.scss"
|
||||
- "**/*.erb"
|
||||
- "*.sh"
|
||||
|
||||
44
.github/ISSUE_TEMPLATE.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
## Are you creating an issue in the correct repository?
|
||||
|
||||
- When in doubt, create an issue here.
|
||||
- If you have an issue with the Jasmine docs, file an issue in the docs repo
|
||||
here: https://github.com/jasmine/jasmine.github.io
|
||||
- This repository is for the core Jasmine framework
|
||||
- If you are using a test runner that wraps Jasmine, consider filing an issue with that library if appropriate:
|
||||
- [Jasmine npm](https://github.com/jasmine/jasmine-npm/issues)
|
||||
- [Jasmine gem](https://github.com/jasmine/jasmine-gem/issues)
|
||||
- [Jasmine py](https://github.com/jasmine/jasmine-py/issues)
|
||||
- [Gulp Jasmine Browser](https://github.com/jasmine/gulp-jasmine-browser/issues)
|
||||
- [Karma](https://github.com/karma-runner/karma/issues)
|
||||
- [Grunt Contrib Jasmine](https://github.com/gruntjs/grunt-contrib-jasmine/issues)
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
## Suite that reproduces the behavior (for bugs)
|
||||
<!--- Provide a sample suite that reproduces the bug. -->
|
||||
```javascript
|
||||
describe("sample", function() {
|
||||
});
|
||||
```
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* Version used:
|
||||
* Environment name and version (e.g. Chrome 39, node.js 5.4):
|
||||
* Operating System and version (desktop or mobile):
|
||||
* Link to your project:
|
||||
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--- Provide a general summary of your changes in the Title above -->
|
||||
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
## Motivation and Context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
## How Has This Been Tested?
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||
<!--- see how your change affects other areas of the code, etc. -->
|
||||
|
||||
## Types of changes
|
||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
|
||||
## Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] My code follows the code style of this project.
|
||||
- [ ] My change requires a change to the documentation.
|
||||
- [ ] I have updated the documentation accordingly.
|
||||
- [ ] I have read the **CONTRIBUTING** document.
|
||||
- [ ] I have added tests to cover my changes.
|
||||
- [ ] All new and existing tests passed.
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,3 +22,4 @@ build/
|
||||
*.egg-info/
|
||||
dist
|
||||
nbproject/
|
||||
*.iml
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
language: ruby
|
||||
|
||||
cache: bundler
|
||||
sudo: false
|
||||
|
||||
rvm: 2.2.2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
Copyright (c) 2008-2017 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
30
README.md
30
README.md
@@ -10,13 +10,13 @@
|
||||
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
|
||||
|
||||
Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/)
|
||||
For a quick start guide of Jasmine 2.0, see the beginning of [http://jasmine.github.io/2.0/introduction.html](http://jasmine.github.io/2.0/introduction.html)
|
||||
For a quick start guide of Jasmine 2.x, see the beginning of [http://jasmine.github.io/edge/introduction.html](http://jasmine.github.io/edge/introduction.html)
|
||||
|
||||
Upgrading from Jasmine 1.x? Check out the [2.0 release notes](https://github.com/jasmine/jasmine/blob/v2.0.0/release_notes/20.md) for a list of what's new (including breaking interface changes). You can also read the [upgrade guide](http://jasmine.github.io/2.0/upgrading.html).
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read the [contributors' guide](https://github.com/jasmine/jasmine/blob/master/CONTRIBUTING.md)
|
||||
Please read the [contributors' guide](https://github.com/jasmine/jasmine/blob/master/.github/CONTRIBUTING.md)
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -32,23 +32,23 @@ For the Jasmine Python Egg:<br>
|
||||
For the Jasmine headless browser gulp plugin:<br>
|
||||
[https://github.com/jasmine/gulp-jasmine-browser](https://github.com/jasmine/gulp-jasmine-browser)
|
||||
|
||||
To install Jasmine standalone on your local box:
|
||||
To install Jasmine standalone on your local box (where **_{#.#.#}_** below is substituted by the release number downloaded):
|
||||
|
||||
* Download the standalone distribution for your desired release from the [releases page](https://github.com/jasmine/jasmine/releases)
|
||||
* Create a Jasmine directory in your project - `mkdir my-project/jasmine`
|
||||
* Move the dist to your project directory - `mv jasmine/dist/jasmine-standalone-2.0.0.zip my-project/jasmine`
|
||||
* Move the dist to your project directory - `mv jasmine/dist/jasmine-standalone-{#.#.#}.zip my-project/jasmine`
|
||||
* Change directory - `cd my-project/jasmine`
|
||||
* Unzip the dist - `unzip jasmine-standalone-2.0.0.zip`
|
||||
* Unzip the dist - `unzip jasmine-standalone-{#.#.#}.zip`
|
||||
|
||||
Add the following to your HTML file:
|
||||
|
||||
```html
|
||||
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-2.0.0/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-2.0.0/jasmine.css">
|
||||
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-{#.#.#}/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-{#.#.#}/jasmine.css">
|
||||
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/boot.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/boot.js"></script>
|
||||
```
|
||||
|
||||
## Supported environments
|
||||
@@ -65,15 +65,15 @@ Jasmine tests itself across many browsers (Safari, Chrome, Firefox, PhantomJS, a
|
||||
|
||||
## Maintainers
|
||||
|
||||
* [Davis W. Frank](mailto:dwfrank@pivotal.io), Pivotal Labs
|
||||
* [Rajan Agaskar](mailto:rajan@pivotal.io), Pivotal Labs
|
||||
* [Gregg Van Hove](mailto:gvanhove@pivotal.io), Pivotal Labs
|
||||
* [Greg Cobb](mailto:gcobb@pivotal.io), Pivotal Labs
|
||||
* [Chris Amavisca](mailto:camavisca@pivotal.io), Pivotal Labs
|
||||
|
||||
### Maintainers Emeritus
|
||||
|
||||
* [Davis W. Frank](mailto:dwfrank@pivotal.io), Pivotal Labs
|
||||
* [Rajan Agaskar](mailto:rajan@pivotal.io), Pivotal Labs
|
||||
* [Greg Cobb](mailto:gcobb@pivotal.io), Pivotal Labs
|
||||
* [Chris Amavisca](mailto:camavisca@pivotal.io), Pivotal Labs
|
||||
* [Christian Williams](mailto:antixian666@gmail.com), Cloud Foundry
|
||||
* Sheel Choksi
|
||||
|
||||
Copyright (c) 2008-2016 Pivotal Labs. This software is licensed under the MIT License.
|
||||
Copyright (c) 2008-2017 Pivotal Labs. This software is licensed under the MIT License.
|
||||
|
||||
@@ -40,7 +40,10 @@ When ready to release - specs are all green and the stories are done:
|
||||
|
||||
### Release the Python egg
|
||||
|
||||
1. `python setup.py register sdist upload` You will need pypi credentials to upload the egg.
|
||||
Install [twine](https://github.com/pypa/twine)
|
||||
|
||||
1. `python setup.py sdist`
|
||||
1. `twine upload dist/jasmine-core-<version>.tar.gz` You will need pypi credentials to upload the egg.
|
||||
|
||||
### Release the Ruby gem
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"homepage": "http://jasmine.github.io",
|
||||
"homepage": "https://jasmine.github.io",
|
||||
"authors": [
|
||||
"slackersoft <gregg@slackersoft.net>"
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
||||
s.name = "jasmine-core"
|
||||
s.version = Jasmine::Core::VERSION
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ["Rajan Agaskar", "Davis W. Frank", "Gregg Van Hove"]
|
||||
s.authors = ["Gregg Van Hove"]
|
||||
s.summary = %q{JavaScript BDD framework}
|
||||
s.description = %q{Test your JavaScript without any framework dependencies, in any environment, and with a nice descriptive syntax.}
|
||||
s.email = %q{jasmine-js@googlegroups.com}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
Copyright (c) 2008-2017 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
Copyright (c) 2008-2017 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -71,6 +71,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
getWindowLocation: function() { return window.location; }
|
||||
});
|
||||
|
||||
var filterSpecs = !!queryString.getParam("spec");
|
||||
|
||||
var catchingExceptions = queryString.getParam("catch");
|
||||
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
|
||||
|
||||
@@ -98,7 +100,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
timer: new jasmine.Timer()
|
||||
timer: new jasmine.Timer(),
|
||||
filterSpecs: filterSpecs
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
getWindowLocation: function() { return window.location; }
|
||||
});
|
||||
|
||||
var filterSpecs = !!queryString.getParam("spec");
|
||||
|
||||
var catchingExceptions = queryString.getParam("catch");
|
||||
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
|
||||
|
||||
@@ -76,7 +78,8 @@
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
timer: new jasmine.Timer()
|
||||
timer: new jasmine.Timer(),
|
||||
filterSpecs: filterSpecs
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
Copyright (c) 2008-2017 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -43,6 +43,7 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
|
||||
onRandomClick = options.onRandomClick || function() {},
|
||||
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
|
||||
filterSpecs = options.filterSpecs,
|
||||
timer = options.timer || noopTimer,
|
||||
results = [],
|
||||
specsExecuted = 0,
|
||||
@@ -209,7 +210,7 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
|
||||
if (specsExecuted < totalSpecsDefined) {
|
||||
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
|
||||
var skippedLink = order && order.random ? '?random=true' : '?';
|
||||
var skippedLink = addToExistingQueryString('spec', '');
|
||||
alert.appendChild(
|
||||
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
|
||||
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
|
||||
@@ -263,6 +264,9 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
var specListNode;
|
||||
for (var i = 0; i < resultsTree.children.length; i++) {
|
||||
var resultNode = resultsTree.children[i];
|
||||
if (filterSpecs && !hasActiveSpec(resultNode)) {
|
||||
continue;
|
||||
}
|
||||
if (resultNode.type == 'suite') {
|
||||
var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
|
||||
createDom('li', {className: 'jasmine-suite-detail'},
|
||||
@@ -390,6 +394,20 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
|
||||
result.status === 'passed';
|
||||
}
|
||||
|
||||
function hasActiveSpec(resultNode) {
|
||||
if (resultNode.type == 'spec' && resultNode.result.status != 'disabled') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (resultNode.type == 'suite') {
|
||||
for (var i = 0, j = resultNode.children.length; i < j; i++) {
|
||||
if (hasActiveSpec(resultNode.children[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HtmlReporter;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
Copyright (c) 2008-2017 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
#
|
||||
module Jasmine
|
||||
module Core
|
||||
VERSION = "2.5.0"
|
||||
VERSION = "2.7.0"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "2.5.0",
|
||||
"version": "2.7.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
@@ -19,14 +19,14 @@
|
||||
"homepage": "http://jasmine.github.io",
|
||||
"main": "./lib/jasmine-core.js",
|
||||
"devDependencies": {
|
||||
"glob": "~7.0.5",
|
||||
"glob": "~7.1.2",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-compass": "^1.1.1",
|
||||
"grunt-contrib-compress": "^1.3.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"grunt-contrib-jshint": "^1.0.0",
|
||||
"jasmine": "^2.4.0",
|
||||
"jasmine": "^2.5.0",
|
||||
"load-grunt-tasks": "^0.4.0",
|
||||
"shelljs": "^0.7.0",
|
||||
"temp": "~0.8.1"
|
||||
|
||||
19
release_notes/2.5.1.md
Normal file
19
release_notes/2.5.1.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Jasmine 2.5.1 Release Notes
|
||||
|
||||
## Pull Requests & Issues
|
||||
|
||||
* fallback on assignment when a spy cannot be deleted
|
||||
- Merges [#1193](https://github.com/jasmine/jasmine/issues/1193) from @seanparmlee
|
||||
- Fixes [#1189](https://github.com/jasmine/jasmine/issues/1189)
|
||||
|
||||
* Fix issue with equality of Arrays in PhantomJS
|
||||
- Merges [#1192](https://github.com/jasmine/jasmine/issues/1192) from @logankd
|
||||
- Fixes [#1188](https://github.com/jasmine/jasmine/issues/1188)
|
||||
|
||||
* Properly tick date along with clock
|
||||
- Fixes [#1190](https://github.com/jasmine/jasmine/issues/1190)
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
14
release_notes/2.5.2.md
Normal file
14
release_notes/2.5.2.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Jasmine 2.5.2 Release Notes
|
||||
|
||||
## Pull Requests & Issues
|
||||
|
||||
* Allow currently registered reporters to be cleared
|
||||
- [jasmine/jasmine-npm#88](https://github.com/jasmine/jasmine-npm/issues/88)
|
||||
|
||||
|
||||
* Use `isFunction` to check for functionness in `callFake`
|
||||
- Fixes [#1191](https://github.com/jasmine/jasmine/issues/1191)
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
108
release_notes/2.6.0.md
Normal file
108
release_notes/2.6.0.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Jasmine 2.6.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This release contains a number of fixes and pull requests.
|
||||
|
||||
## Pull Requests & Issues
|
||||
|
||||
Updating introduction url to last version
|
||||
- Merges [#1316](https://github.com/jasmine/jasmine/issues/1316) from @rachelcarmena
|
||||
|
||||
* Throw a recognizable Error message when `fail` outside of a spec.
|
||||
- Fixes [#1017](https://github.com/jasmine/jasmine/issues/1017)
|
||||
|
||||
* Allow the matcher provide a custom error message
|
||||
- Merges [#1298](https://github.com/jasmine/jasmine/issues/1298) from @deckar01
|
||||
- Fixes [#1123](https://github.com/jasmine/jasmine/issues/1123)
|
||||
|
||||
* Fix the order in which afterAll hooks are run to match afterEach
|
||||
- Merges [#1312](https://github.com/jasmine/jasmine/issues/1312) from @gdborton
|
||||
- Fixes [#1311](https://github.com/jasmine/jasmine/issues/1311)
|
||||
|
||||
* Add matchers for positive and negative infinity
|
||||
- Merges [#1300](https://github.com/jasmine/jasmine/issues/1300) from @toubou91
|
||||
- Fixes [#1294](https://github.com/jasmine/jasmine/issues/1294)
|
||||
|
||||
* Add a first pass at JSDocs for the intended public API
|
||||
- Fixes [#596](https://github.com/jasmine/jasmine/issues/596)
|
||||
|
||||
* Pretty print objects passed to fail method
|
||||
- Merges [#1283](https://github.com/jasmine/jasmine/issues/1283) from @mmmichl
|
||||
- Fixes [#1090](https://github.com/jasmine/jasmine/issues/1090)
|
||||
|
||||
* Properly check for Error constructor from a different frame
|
||||
- Merges [#1275](https://github.com/jasmine/jasmine/issues/1275) from @anseki
|
||||
- Fixes [#1252](https://github.com/jasmine/jasmine/issues/1252)
|
||||
|
||||
* Add toHaveBeenCalledBefore matcher
|
||||
- Merges [#1242](https://github.com/jasmine/jasmine/issues/1242) from @DamienCassou
|
||||
|
||||
* Collect unhandled exceptions and pass them to the current runnable
|
||||
- Fixes [#529](https://github.com/jasmine/jasmine/issues/529)
|
||||
- Fixes [#937](https://github.com/jasmine/jasmine/issues/937)
|
||||
|
||||
* Nicer error messages for `spyOn` when `null` is provided
|
||||
- Fixes [#1258](https://github.com/jasmine/jasmine/issues/1258)
|
||||
|
||||
* Require arguments to beforeEach, it, etc, to be actual functions
|
||||
- Merges [#1222](https://github.com/jasmine/jasmine/issues/1222) from @voithos
|
||||
- Fixes [#1004](https://github.com/jasmine/jasmine/issues/1004)
|
||||
|
||||
* Update MIT.LICENSE for new year
|
||||
- Merges [#1249](https://github.com/jasmine/jasmine/issues/1249) from @Scottkao85
|
||||
|
||||
* Update README.md for new year
|
||||
- Merges [#1248](https://github.com/jasmine/jasmine/issues/1248) from @Nebojsaa
|
||||
|
||||
* Remove unused `message` param from Suite#pend
|
||||
- See [#1132](https://github.com/jasmine/jasmine/issues/1132)
|
||||
|
||||
* Fix bug where before/afterAll were being executed in disabled suites.
|
||||
- Merges [#1225](https://github.com/jasmine/jasmine/issues/1225) from @voithos
|
||||
- Fixes [#1175](https://github.com/jasmine/jasmine/issues/1175)
|
||||
|
||||
* Make toEqual matcher report the difference between objects
|
||||
- Merges [#1163](https://github.com/jasmine/jasmine/issues/1163) from @benchristel
|
||||
- Fixes [#675](https://github.com/jasmine/jasmine/issues/675)
|
||||
- Merges [#1236](https://github.com/jasmine/jasmine/issues/1236) from @benchristel
|
||||
|
||||
|
||||
* Implement spies for get/set functions on accessor properties
|
||||
- Merges [#1203](https://github.com/jasmine/jasmine/issues/1203) from @celluj34
|
||||
- Merges [#1008](https://github.com/jasmine/jasmine/issues/1008) from @smacker
|
||||
- Fixes [#943](https://github.com/jasmine/jasmine/issues/943)
|
||||
|
||||
* When the HtmlReporter has a 'spec' query param, the spec list only shows matching specs/suites
|
||||
- Merges [#1046](https://github.com/jasmine/jasmine/issues/1046) from @d-reinhold
|
||||
- Fixes [#510](https://github.com/jasmine/jasmine/issues/510)
|
||||
|
||||
* createSpyObj may use object for method/response shorthand
|
||||
- Merges [#1101](https://github.com/jasmine/jasmine/issues/1101) from @mbildner
|
||||
|
||||
* Separate clear stack and run it after each spec
|
||||
- Fixes [#985](https://github.com/jasmine/jasmine/issues/985)
|
||||
- Fixes [#945](https://github.com/jasmine/jasmine/issues/945)
|
||||
- Fixes [#366](https://github.com/jasmine/jasmine/issues/366)
|
||||
|
||||
* Now spies preserve original function arity
|
||||
- Merges [#1055](https://github.com/jasmine/jasmine/issues/1055) from @kapke
|
||||
- Fixes [#991](https://github.com/jasmine/jasmine/issues/991)
|
||||
|
||||
* Added support for ES6 sets to toContain and toEqual.
|
||||
- Merges [#1067](https://github.com/jasmine/jasmine/issues/1067) from @alur
|
||||
|
||||
* Correctly pretty print objects from other contexts (e.g. iframes) and which do not override toString
|
||||
- Merges [#1091](https://github.com/jasmine/jasmine/issues/1091) from @thatfulvioguy
|
||||
- Fixes [#1087](https://github.com/jasmine/jasmine/issues/1087)
|
||||
|
||||
* Pass custom testers to asymmetric testers
|
||||
- Merges [#1139](https://github.com/jasmine/jasmine/issues/1139) from @joeyparrish
|
||||
- Fixes [#1138](https://github.com/jasmine/jasmine/issues/1138)
|
||||
|
||||
* Fix bad url in README
|
||||
- Merges [#1215](https://github.com/jasmine/jasmine/issues/1215) from @mattc41190
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
31
release_notes/2.6.1.md
Normal file
31
release_notes/2.6.1.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Jasmine 2.6.1 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a patch release to fix some regressions in the 2.6.0 release
|
||||
|
||||
## Pull Requests & Issues
|
||||
|
||||
* Update README.md to make installation instructions more version-agnostic
|
||||
- Merges #1319 from @reinrl
|
||||
|
||||
* Check for `process.listeners` as well, for GlobalErrors
|
||||
- Fixes #1333
|
||||
|
||||
* allow explicit undefined as function for `it` and `xit`
|
||||
- Merges #1329 from @UziTech
|
||||
- Fixes #1328
|
||||
|
||||
* remove eval to create spy wrapper
|
||||
- Merges #1330 from @UziTech
|
||||
- Fixes #1325
|
||||
|
||||
* iterate through keys with a regular for loop
|
||||
- Merges #1326 from @seanparmelee
|
||||
- Fixes #1321
|
||||
- Fixes #1324
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
23
release_notes/2.6.2.md
Normal file
23
release_notes/2.6.2.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Jasmine 2.6.2 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
|
||||
|
||||
## Changes
|
||||
|
||||
* Clear the stack if onmessage is called before the previous invocation finishes
|
||||
- Fixes #1327
|
||||
- Fixes jasmine/gulp-jasmine-browser#48
|
||||
|
||||
* Correctly route errors that occur while a QueueRunner is clearing stack
|
||||
- Merges #1352 from @sgravrock
|
||||
- Fixes #1344
|
||||
- Fixes #1349
|
||||
|
||||
* Don't mask errors that occur when no handlers are installed
|
||||
- Merges #1347 from @sgravrock
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
17
release_notes/2.6.3.md
Normal file
17
release_notes/2.6.3.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Jasmine 2.6.3 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
|
||||
|
||||
## Changes
|
||||
|
||||
* Make sure the queue runner goes async for async specs
|
||||
- Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327)
|
||||
- Fixes [#1334](https://github.com/jasmine/jasmine/issues/1334)
|
||||
- Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48)
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
17
release_notes/2.6.4.md
Normal file
17
release_notes/2.6.4.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Jasmine 2.6.4 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
|
||||
|
||||
## Changes
|
||||
|
||||
* Break into a `setTimeout` every once in a while allowing the CPU to run other things that used the real `setTimeout`
|
||||
- Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327)
|
||||
- See [#1334](https://github.com/jasmine/jasmine/issues/1334)
|
||||
- Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48)
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
61
release_notes/2.7.0.md
Normal file
61
release_notes/2.7.0.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Jasmine 2.7.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This release contains a number of fixes and pull requests.
|
||||
|
||||
## Pull Requests & Issues
|
||||
|
||||
|
||||
* Add class UserContext
|
||||
- Merges [#1400](https://github.com/jasmine/jasmine/issues/1400) from @darthjee
|
||||
|
||||
* Send unfocused tests through the same queue as focused tests
|
||||
- Merges [#1399](https://github.com/jasmine/jasmine/issues/1399) from @jberney
|
||||
|
||||
* PrettyPrinter allows an object to have a `toString` that isn't a function
|
||||
- Fixes [#1389](https://github.com/jasmine/jasmine/issues/1389)
|
||||
|
||||
* Fix rounding in toBeCloseTo
|
||||
- Fixes [#1382](https://github.com/jasmine/jasmine/issues/1382)
|
||||
|
||||
* When stop on failure is enabled, skip subsequent it() and beforeEach(). Note: afterEach() functions are still run, because skipping them is highly likely to pollute specs that run after the failure.
|
||||
- Fixes [#577](https://github.com/jasmine/jasmine/issues/577)
|
||||
- Fixes [#807](https://github.com/jasmine/jasmine/issues/807)
|
||||
|
||||
* Only clear out the `spec` param for Run all link
|
||||
- Fixes [#1369](https://github.com/jasmine/jasmine/issues/1369)
|
||||
|
||||
* Pretty printer will now use MAX_PRETTY_PRINT_ARRAY_LENGTH for objects
|
||||
- Fixes [#1291](https://github.com/jasmine/jasmine/issues/1291)
|
||||
- Fixes [#1360](https://github.com/jasmine/jasmine/issues/1360)
|
||||
|
||||
* updated package glob from 7.0.5 to 7.1.2
|
||||
- Merges [#1368](https://github.com/jasmine/jasmine/issues/1368) from @EsrefDurna
|
||||
|
||||
* Fix bower.json url to be https instead of http
|
||||
- Merges [#1365](https://github.com/jasmine/jasmine/issues/1365) from @kant
|
||||
|
||||
* Fail when one of the arguments passed into toBeCloseTo matcher is null
|
||||
- Merges [#1362](https://github.com/jasmine/jasmine/issues/1362) from @beatrichartz
|
||||
|
||||
* Fixed HTML snippet in README
|
||||
- Closes [#1366](https://github.com/jasmine/jasmine/issues/1366).
|
||||
|
||||
* Report the random seed at the beginning and end of execution. This allows reporters to provide the seed to the user even in cases where Jasmine crashes before completing.
|
||||
- Merges [#1348](https://github.com/jasmine/jasmine/issues/1348) from @sgravrock
|
||||
|
||||
* Add ES6 map support to Jasmine
|
||||
- Merges [#1340](https://github.com/jasmine/jasmine/issues/1340) from @rmehlinger
|
||||
- Fixes [#1257](https://github.com/jasmine/jasmine/issues/1257)
|
||||
|
||||
* Added support for async before/it/after functions that return promises and added support for ES2017 async functions
|
||||
- Merges [#1356](https://github.com/jasmine/jasmine/issues/1356) from @sgravrock
|
||||
- Fixes [#1336](https://github.com/jasmine/jasmine/issues/1336)
|
||||
- Fixes [#1270](https://github.com/jasmine/jasmine/issues/1270)
|
||||
- Fixes [#1350](https://github.com/jasmine/jasmine/issues/1350)
|
||||
- Fixes [#1320](https://github.com/jasmine/jasmine/issues/1320)
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_
|
||||
137
spec/core/ClearStackSpec.js
Normal file
137
spec/core/ClearStackSpec.js
Normal file
@@ -0,0 +1,137 @@
|
||||
describe("ClearStack", function() {
|
||||
it("works in an integrationy way", function(done) {
|
||||
var clearStack = jasmineUnderTest.getClearStack(jasmineUnderTest.getGlobal());
|
||||
|
||||
clearStack(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("uses setImmediate when available", function() {
|
||||
var setImmediate = jasmine.createSpy('setImmediate').and.callFake(function(fn) { fn() }),
|
||||
global = { setImmediate: setImmediate },
|
||||
clearStack = jasmineUnderTest.getClearStack(global),
|
||||
called = false;
|
||||
|
||||
clearStack(function() {
|
||||
called = true;
|
||||
});
|
||||
|
||||
expect(called).toBe(true);
|
||||
expect(setImmediate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU", function() {
|
||||
var setImmediate = jasmine.createSpy('setImmediate'),
|
||||
setTimeout = jasmine.createSpy('setTimeout'),
|
||||
global = { setImmediate: setImmediate, setTimeout: setTimeout },
|
||||
clearStack = jasmineUnderTest.getClearStack(global);
|
||||
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
|
||||
expect(setImmediate).toHaveBeenCalled();
|
||||
expect(setTimeout).not.toHaveBeenCalled();
|
||||
|
||||
clearStack(function() { });
|
||||
expect(setImmediate.calls.count()).toEqual(9);
|
||||
expect(setTimeout.calls.count()).toEqual(1);
|
||||
|
||||
clearStack(function() { });
|
||||
expect(setImmediate.calls.count()).toEqual(10);
|
||||
expect(setTimeout.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it("uses MessageChannels when available", function() {
|
||||
var fakeChannel = {
|
||||
port1: {},
|
||||
port2: { postMessage: function() { fakeChannel.port1.onmessage(); } }
|
||||
},
|
||||
global = { MessageChannel: function() { return fakeChannel; } },
|
||||
clearStack = jasmineUnderTest.getClearStack(global),
|
||||
called = false;
|
||||
|
||||
clearStack(function() {
|
||||
called = true;
|
||||
});
|
||||
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
it("uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU", function() {
|
||||
var fakeChannel = {
|
||||
port1: {},
|
||||
port2: {
|
||||
postMessage: jasmine.createSpy('postMessage').and.callFake(function() {
|
||||
fakeChannel.port1.onmessage();
|
||||
})
|
||||
}
|
||||
},
|
||||
setTimeout = jasmine.createSpy('setTimeout'),
|
||||
global = { MessageChannel: function() { return fakeChannel; }, setTimeout: setTimeout },
|
||||
clearStack = jasmineUnderTest.getClearStack(global);
|
||||
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
clearStack(function() { });
|
||||
|
||||
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
|
||||
expect(setTimeout).not.toHaveBeenCalled();
|
||||
|
||||
clearStack(function() { });
|
||||
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9);
|
||||
expect(setTimeout.calls.count()).toEqual(1);
|
||||
|
||||
clearStack(function() { });
|
||||
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10);
|
||||
expect(setTimeout.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it("calls setTimeout when onmessage is called recursively", function() {
|
||||
var fakeChannel = {
|
||||
port1: {},
|
||||
port2: { postMessage: function() { fakeChannel.port1.onmessage(); } }
|
||||
},
|
||||
setTimeout = jasmine.createSpy('setTimeout'),
|
||||
global = {
|
||||
MessageChannel: function() { return fakeChannel; },
|
||||
setTimeout: setTimeout,
|
||||
},
|
||||
clearStack = jasmineUnderTest.getClearStack(global),
|
||||
fn = jasmine.createSpy("second clearStack function");
|
||||
|
||||
clearStack(function() {
|
||||
clearStack(fn);
|
||||
});
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
|
||||
});
|
||||
|
||||
it("falls back to setTimeout", function() {
|
||||
var setTimeout = jasmine.createSpy('setTimeout').and.callFake(function(fn) { fn() }),
|
||||
global = { setTimeout: setTimeout },
|
||||
clearStack = jasmineUnderTest.getClearStack(global),
|
||||
called = false;
|
||||
|
||||
clearStack(function() {
|
||||
called = true;
|
||||
});
|
||||
|
||||
expect(called).toBe(true);
|
||||
expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 0);
|
||||
});
|
||||
});
|
||||
@@ -666,9 +666,17 @@ describe("Clock (acceptance)", function() {
|
||||
var pushCurrentTime = function() { actualTimes.push(global.Date().getTime()); };
|
||||
delayedFunctionScheduler.scheduleFunction(pushCurrentTime);
|
||||
delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 1);
|
||||
delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 3);
|
||||
|
||||
clock.tick(1);
|
||||
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 1);
|
||||
|
||||
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1]);
|
||||
clock.tick(3);
|
||||
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 4);
|
||||
|
||||
clock.tick(1);
|
||||
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 5);
|
||||
|
||||
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]);
|
||||
})
|
||||
});
|
||||
|
||||
@@ -26,15 +26,6 @@ describe("Env", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#describe', function () {
|
||||
var spec = function(done){};
|
||||
it("throws the error", function() {
|
||||
expect(function() {
|
||||
env.describe('done method', spec);
|
||||
}).toThrow(new Error('describe does not expect any arguments'));
|
||||
});
|
||||
});
|
||||
|
||||
it('can configure specs to throw errors on expectation failures', function() {
|
||||
env.throwOnExpectationFailure(true);
|
||||
|
||||
@@ -55,14 +46,155 @@ describe("Env", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
describe('#describe', function () {
|
||||
it("throws an error when given arguments", function() {
|
||||
expect(function() {
|
||||
env.describe('done method', function(done) {});
|
||||
}).toThrowError('describe does not expect any arguments');
|
||||
});
|
||||
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
// Some versions of PhantomJS return [object DOMWindow] when
|
||||
// Object.prototype.toString.apply is called with `undefined` or `null`.
|
||||
// In a similar fashion, IE8 gives [object Object] for both `undefined`
|
||||
// and `null`. We mostly just want these tests to check that using
|
||||
// anything other than a function throws an error.
|
||||
expect(function() {
|
||||
env.describe('undefined arg', undefined);
|
||||
}).toThrowError(/describe expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
expect(function() {
|
||||
env.describe('null arg', null);
|
||||
}).toThrowError(/describe expects a function argument; received \[object (Null|DOMWindow|Object)\]/);
|
||||
|
||||
expect(function() {
|
||||
env.describe('array arg', []);
|
||||
}).toThrowError('describe expects a function argument; received [object Array]');
|
||||
expect(function() {
|
||||
env.describe('object arg', {});
|
||||
}).toThrowError('describe expects a function argument; received [object Object]');
|
||||
|
||||
expect(function() {
|
||||
env.describe('fn arg', function() {});
|
||||
}).not.toThrowError('describe expects a function argument; received [object Function]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#it', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.it('undefined arg', null);
|
||||
}).toThrowError(/it expects a function argument; received \[object (Null|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('does not throw when it is not given a fn argument', function() {
|
||||
expect(function() {
|
||||
env.it('pending spec');
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.it('async', jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#xit', function() {
|
||||
it('calls spec.pend with "Temporarily disabled with xit"', function() {
|
||||
var pendSpy = jasmine.createSpy();
|
||||
spyOn(env, 'it').and.returnValue({
|
||||
pend: pendSpy
|
||||
});
|
||||
env.xit();
|
||||
env.xit('foo', function() {});
|
||||
expect(pendSpy).toHaveBeenCalledWith('Temporarily disabled with xit');
|
||||
});
|
||||
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.xit('undefined arg', null);
|
||||
}).toThrowError(/xit expects a function argument; received \[object (Null|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('does not throw when it is not given a fn argument', function() {
|
||||
expect(function() {
|
||||
env.xit('pending spec');
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.xit('async', jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#fit', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.fit('undefined arg', undefined);
|
||||
}).toThrowError(/fit expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#beforeEach', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.beforeEach(undefined);
|
||||
}).toThrowError(/beforeEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#beforeAll', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.beforeAll(undefined);
|
||||
}).toThrowError(/beforeAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#afterEach', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.afterEach(undefined);
|
||||
}).toThrowError(/afterEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#afterAll', function () {
|
||||
it('throws an error when it receives a non-fn argument', function() {
|
||||
expect(function() {
|
||||
env.afterAll(undefined);
|
||||
}).toThrowError(/afterAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
|
||||
});
|
||||
|
||||
it('accepts an async function', function() {
|
||||
jasmine.getEnv().requireAsyncAwait();
|
||||
expect(function() {
|
||||
env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction());
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,6 +113,7 @@ describe("Expectation", function() {
|
||||
matcherName: "toFoo",
|
||||
passed: true,
|
||||
message: "",
|
||||
error: undefined,
|
||||
expected: "hello",
|
||||
actual: "an actual"
|
||||
});
|
||||
@@ -146,7 +147,8 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: ""
|
||||
message: "",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -179,7 +181,8 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: "I am a custom message"
|
||||
message: "I am a custom message",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -212,7 +215,8 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: "I am a custom message"
|
||||
message: "I am a custom message",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -244,6 +248,7 @@ describe("Expectation", function() {
|
||||
matcherName: "toFoo",
|
||||
passed: true,
|
||||
message: "",
|
||||
error: undefined,
|
||||
expected: "hello",
|
||||
actual: actual
|
||||
});
|
||||
@@ -279,7 +284,8 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "default message"
|
||||
message: "default message",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -314,7 +320,8 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "I am a custom message"
|
||||
message: "I am a custom message",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -345,7 +352,8 @@ describe("Expectation", function() {
|
||||
passed: true,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: ""
|
||||
message: "",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -381,7 +389,44 @@ describe("Expectation", function() {
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "I'm a custom message"
|
||||
message: "I'm a custom message",
|
||||
error: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a custom error message to the spec", function() {
|
||||
var customError = new Error("I am a custom error");
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return {
|
||||
pass: false,
|
||||
message: "I am a custom message",
|
||||
error: customError
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
expectation = new jasmineUnderTest.Expectation({
|
||||
actual: "an actual",
|
||||
customMatchers: matchers,
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: "I am a custom message",
|
||||
error: customError
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
110
spec/core/GlobalErrorsSpec.js
Normal file
110
spec/core/GlobalErrorsSpec.js
Normal file
@@ -0,0 +1,110 @@
|
||||
describe("GlobalErrors", function() {
|
||||
it("calls the added handler on error", function() {
|
||||
var fakeGlobal = { onerror: null },
|
||||
handler = jasmine.createSpy('errorHandler'),
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
errors.pushListener(handler);
|
||||
|
||||
fakeGlobal.onerror('foo');
|
||||
|
||||
expect(handler).toHaveBeenCalledWith('foo');
|
||||
});
|
||||
|
||||
it("only calls the most recent handler", function() {
|
||||
var fakeGlobal = { onerror: null },
|
||||
handler1 = jasmine.createSpy('errorHandler1'),
|
||||
handler2 = jasmine.createSpy('errorHandler2'),
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
errors.pushListener(handler1);
|
||||
errors.pushListener(handler2);
|
||||
|
||||
fakeGlobal.onerror('foo');
|
||||
|
||||
expect(handler1).not.toHaveBeenCalled();
|
||||
expect(handler2).toHaveBeenCalledWith('foo');
|
||||
});
|
||||
|
||||
it("calls previous handlers when one is removed", function() {
|
||||
var fakeGlobal = { onerror: null },
|
||||
handler1 = jasmine.createSpy('errorHandler1'),
|
||||
handler2 = jasmine.createSpy('errorHandler2'),
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
errors.pushListener(handler1);
|
||||
errors.pushListener(handler2);
|
||||
|
||||
errors.popListener();
|
||||
|
||||
fakeGlobal.onerror('foo');
|
||||
|
||||
expect(handler1).toHaveBeenCalledWith('foo');
|
||||
expect(handler2).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uninstalls itself, putting back a previous callback", function() {
|
||||
var originalCallback = jasmine.createSpy('error'),
|
||||
fakeGlobal = { onerror: originalCallback },
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
expect(fakeGlobal.onerror).toBe(originalCallback);
|
||||
|
||||
errors.install();
|
||||
|
||||
expect(fakeGlobal.onerror).not.toBe(originalCallback);
|
||||
|
||||
errors.uninstall();
|
||||
|
||||
expect(fakeGlobal.onerror).toBe(originalCallback);
|
||||
});
|
||||
|
||||
it("rethrows the original error when there is no handler", function() {
|
||||
var fakeGlobal = { },
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
|
||||
originalError = new Error('nope');
|
||||
|
||||
errors.install();
|
||||
|
||||
try {
|
||||
fakeGlobal.onerror(originalError);
|
||||
} catch (e) {
|
||||
expect(e).toBe(originalError);
|
||||
}
|
||||
|
||||
errors.uninstall();
|
||||
});
|
||||
|
||||
it("works in node.js", function() {
|
||||
var fakeGlobal = {
|
||||
process: {
|
||||
on: jasmine.createSpy('process.on'),
|
||||
removeListener: jasmine.createSpy('process.removeListener'),
|
||||
listeners: jasmine.createSpy('process.listeners').and.returnValue(['foo']),
|
||||
removeAllListeners: jasmine.createSpy('process.removeAllListeners')
|
||||
}
|
||||
},
|
||||
handler = jasmine.createSpy('errorHandler'),
|
||||
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||
|
||||
errors.install();
|
||||
expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', jasmine.any(Function));
|
||||
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith('uncaughtException');
|
||||
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith('uncaughtException');
|
||||
|
||||
errors.pushListener(handler);
|
||||
|
||||
var addedListener = fakeGlobal.process.on.calls.argsFor(0)[1];
|
||||
addedListener(new Error('bar'));
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(new Error('bar'));
|
||||
|
||||
errors.uninstall();
|
||||
|
||||
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith('uncaughtException', addedListener);
|
||||
expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', 'foo');
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,45 @@ describe("jasmineUnderTest.pp", function () {
|
||||
expect(jasmineUnderTest.pp(-0)).toEqual("-0");
|
||||
});
|
||||
|
||||
describe('stringify sets', function() {
|
||||
it("should stringify sets properly", function() {
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
expect(jasmineUnderTest.pp(new Set([1, 2]))).toEqual("Set( 1, 2 )");
|
||||
});
|
||||
|
||||
it("should truncate sets with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
|
||||
|
||||
try {
|
||||
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
|
||||
expect(jasmineUnderTest.pp(new Set(["a", "b", "c"]))).toEqual("Set( 'a', 'b', ... )");
|
||||
} finally {
|
||||
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
describe('stringify maps', function() {
|
||||
it("should stringify maps properly", function() {
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
expect(jasmineUnderTest.pp(new Map([[1, 2]]))).toEqual("Map( [ 1, 2 ] )");
|
||||
});
|
||||
|
||||
it("should truncate maps with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
|
||||
|
||||
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 ], ... )");
|
||||
} finally {
|
||||
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe('stringify arrays', function() {
|
||||
it("should stringify arrays properly", function() {
|
||||
expect(jasmineUnderTest.pp([1, 2])).toEqual("[ 1, 2 ]");
|
||||
@@ -80,6 +119,23 @@ describe("jasmineUnderTest.pp", function () {
|
||||
}, bar: [1, 2, 3]})).toEqual("Object({ foo: Function, bar: [ 1, 2, 3 ] })");
|
||||
});
|
||||
|
||||
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};
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
it("should print 'null' as the constructor of an object with its own constructor property", function() {
|
||||
expect(jasmineUnderTest.pp({constructor: function() {}})).toContain("null({");
|
||||
expect(jasmineUnderTest.pp({constructor: 'foo'})).toContain("null({");
|
||||
});
|
||||
|
||||
it("should not include inherited properties when stringifying an object", function() {
|
||||
var SomeClass = function SomeClass() {};
|
||||
SomeClass.prototype.foo = "inherited foo";
|
||||
@@ -145,7 +201,6 @@ describe("jasmineUnderTest.pp", function () {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it('should not do HTML escaping of strings', function() {
|
||||
expect(jasmineUnderTest.pp('some <b>html string</b> &', false)).toEqual('\'some <b>html string</b> &\'');
|
||||
});
|
||||
@@ -187,6 +242,31 @@ describe("jasmineUnderTest.pp", function () {
|
||||
};
|
||||
|
||||
expect(jasmineUnderTest.pp(obj)).toEqual("my toString");
|
||||
|
||||
// Simulate object from another global context (e.g. an iframe or Web Worker) that does not actually have a custom
|
||||
// toString despite obj.toString !== Object.prototype.toString
|
||||
var objFromOtherContext = {
|
||||
foo: 'bar',
|
||||
toString: function () { return Object.prototype.toString.call(this); }
|
||||
};
|
||||
|
||||
if (jasmine.getEnv().ieVersion < 9) {
|
||||
expect(jasmineUnderTest.pp(objFromOtherContext)).toEqual("Object({ foo: 'bar' })");
|
||||
} else {
|
||||
expect(jasmineUnderTest.pp(objFromOtherContext)).toEqual("Object({ foo: 'bar', toString: Function })");
|
||||
}
|
||||
});
|
||||
|
||||
it("should stringify objects have have a toString that isn't a function", function() {
|
||||
var obj = {
|
||||
toString: "foo"
|
||||
};
|
||||
|
||||
if (jasmine.getEnv().ieVersion < 9) {
|
||||
expect(jasmineUnderTest.pp(obj)).toEqual("Object({ })");
|
||||
} else {
|
||||
expect(jasmineUnderTest.pp(obj)).toEqual("Object({ toString: 'foo' })");
|
||||
}
|
||||
});
|
||||
|
||||
it("should stringify objects from anonymous constructors with custom toString", function () {
|
||||
|
||||
@@ -19,6 +19,26 @@ describe("QueueRunner", function() {
|
||||
expect(calls).toEqual(['fn1', 'fn2']);
|
||||
});
|
||||
|
||||
it("runs cleanup functions after the others", function() {
|
||||
var calls = [],
|
||||
queueableFn1 = { fn: jasmine.createSpy('fn1') },
|
||||
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn1],
|
||||
cleanupFns: [queueableFn2]
|
||||
});
|
||||
queueableFn1.fn.and.callFake(function() {
|
||||
calls.push('fn1');
|
||||
});
|
||||
queueableFn2.fn.and.callFake(function() {
|
||||
calls.push('fn2');
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
expect(calls).toEqual(['fn1', 'fn2']);
|
||||
});
|
||||
|
||||
it("calls each function with a consistent 'this'-- an empty object", function() {
|
||||
var queueableFn1 = { fn: jasmine.createSpy('fn1') },
|
||||
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
||||
@@ -31,7 +51,7 @@ describe("QueueRunner", function() {
|
||||
queueRunner.execute();
|
||||
|
||||
var context = queueableFn1.fn.calls.first().object;
|
||||
expect(context).toEqual({});
|
||||
expect(context).toEqual(new jasmineUnderTest.UserContext());
|
||||
expect(queueableFn2.fn.calls.first().object).toBe(context);
|
||||
expect(asyncContext).toBe(context);
|
||||
});
|
||||
@@ -189,6 +209,7 @@ describe("QueueRunner", function() {
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
jasmine.clock().tick(1);
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
|
||||
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
|
||||
@@ -197,12 +218,13 @@ describe("QueueRunner", function() {
|
||||
|
||||
it("only moves to the next spec the first time you call done", function() {
|
||||
var queueableFn = { fn: function(done) {done(); done();} },
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
});
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick(1);
|
||||
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
@@ -211,10 +233,10 @@ describe("QueueRunner", function() {
|
||||
setTimeout(done, 1);
|
||||
throw new Error('error!');
|
||||
} },
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
});
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick(1);
|
||||
@@ -234,6 +256,148 @@ describe("QueueRunner", function() {
|
||||
queueRunner.execute();
|
||||
expect(doneReturn).toBe(null);
|
||||
});
|
||||
|
||||
it("continues running functions when an exception is thrown in async code without timing out", function() {
|
||||
var queueableFn = { fn: function(done) { throwAsync(); }, timeout: function() { return 1; } },
|
||||
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
|
||||
onException = jasmine.createSpy('onException'),
|
||||
globalErrors = { pushListener: jasmine.createSpy('pushListener'), popListener: jasmine.createSpy('popListener') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn],
|
||||
onException: onException,
|
||||
globalErrors: globalErrors
|
||||
}),
|
||||
throwAsync = function() {
|
||||
globalErrors.pushListener.calls.mostRecent().args[0](new Error('foo'));
|
||||
jasmine.clock().tick(2);
|
||||
};
|
||||
|
||||
nextQueueableFn.fn.and.callFake(function() {
|
||||
// should remove the same function that was added
|
||||
expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(1)[0]);
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
function errorWithMessage(message) {
|
||||
return {
|
||||
asymmetricMatch: function(other) {
|
||||
return new RegExp(message).test(other.message);
|
||||
},
|
||||
toString: function() {
|
||||
return '<Error with message like "' + message + '">';
|
||||
}
|
||||
};
|
||||
}
|
||||
expect(onException).not.toHaveBeenCalledWith(errorWithMessage(/DEFAULT_TIMEOUT_INTERVAL/));
|
||||
expect(onException).toHaveBeenCalledWith(errorWithMessage(/^foo$/));
|
||||
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("handles exceptions thrown while waiting for the stack to clear", function() {
|
||||
var queueableFn = { fn: function(done) { done() } },
|
||||
global = {},
|
||||
errorListeners = [],
|
||||
globalErrors = {
|
||||
pushListener: function(f) { errorListeners.push(f); },
|
||||
popListener: function() { errorListeners.pop(); }
|
||||
},
|
||||
clearStack = jasmine.createSpy('clearStack'),
|
||||
onException = jasmine.createSpy('onException'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn],
|
||||
globalErrors: globalErrors,
|
||||
clearStack: clearStack,
|
||||
onException: onException
|
||||
}),
|
||||
error = new Error('nope');
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick();
|
||||
expect(clearStack).toHaveBeenCalled();
|
||||
expect(errorListeners.length).toEqual(1);
|
||||
errorListeners[0](error);
|
||||
clearStack.calls.argsFor(0)[0]();
|
||||
expect(onException).toHaveBeenCalledWith(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with a function that returns a promise", function() {
|
||||
function StubPromise() {}
|
||||
|
||||
StubPromise.prototype.then = function(resolve, reject) {
|
||||
this.resolveHandler = resolve;
|
||||
this.rejectHandler = reject;
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it("runs the function asynchronously, advancing once the promise is settled", function() {
|
||||
var onComplete = jasmine.createSpy('onComplete'),
|
||||
fnCallback = jasmine.createSpy('fnCallback'),
|
||||
p1 = new StubPromise(),
|
||||
p2 = new StubPromise(),
|
||||
queueableFn1 = { fn: function() {
|
||||
setTimeout(function() {
|
||||
p1.resolveHandler();
|
||||
}, 100);
|
||||
return p1;
|
||||
} };
|
||||
queueableFn2 = { fn: function() {
|
||||
fnCallback();
|
||||
setTimeout(function() {
|
||||
p2.resolveHandler();
|
||||
}, 100);
|
||||
return p2;
|
||||
} },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn1, queueableFn2],
|
||||
onComplete: onComplete
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
expect(fnCallback).not.toHaveBeenCalled();
|
||||
expect(onComplete).not.toHaveBeenCalled();
|
||||
|
||||
jasmine.clock().tick(100);
|
||||
|
||||
expect(fnCallback).toHaveBeenCalled();
|
||||
expect(onComplete).not.toHaveBeenCalled();
|
||||
|
||||
jasmine.clock().tick(100);
|
||||
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fails the function when the promise is rejected", function() {
|
||||
var promise = new StubPromise(),
|
||||
queueableFn1 = { fn: function() {
|
||||
setTimeout(function() { promise.rejectHandler('foo'); }, 100);
|
||||
return promise;
|
||||
} },
|
||||
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
||||
failFn = jasmine.createSpy('fail'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn1, queueableFn2],
|
||||
fail: failFn
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
expect(failFn).not.toHaveBeenCalled();
|
||||
expect(queueableFn2.fn).not.toHaveBeenCalled();
|
||||
|
||||
jasmine.clock().tick(100);
|
||||
|
||||
expect(failFn).toHaveBeenCalledWith('foo');
|
||||
expect(queueableFn2.fn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("calls exception handlers when an exception is thrown in a fn", function() {
|
||||
@@ -277,6 +441,87 @@ describe("QueueRunner", function() {
|
||||
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("When configured to complete on first error", function() {
|
||||
it("skips to cleanup functions on the first exception", function() {
|
||||
var queueableFn = { fn: function() { throw new Error("error"); } },
|
||||
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
|
||||
cleanupFn = { fn: jasmine.createSpy("cleanup") },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn],
|
||||
cleanupFns: [cleanupFn],
|
||||
completeOnFirstError: true
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
|
||||
expect(cleanupFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not skip when a cleanup function throws", function() {
|
||||
var queueableFn = { fn: function() { } },
|
||||
cleanupFn1 = { fn: function() { throw new Error("error"); } },
|
||||
cleanupFn2 = { fn: jasmine.createSpy("cleanupFn2") },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn],
|
||||
cleanupFns: [cleanupFn1, cleanupFn2],
|
||||
completeOnFirstError: true
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
expect(cleanupFn2.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("with an asynchronous function", function() {
|
||||
beforeEach(function() {
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
|
||||
it("skips to cleanup functions on the first exception", function() {
|
||||
var errorListeners = [],
|
||||
queueableFn = { fn: function(done) {} },
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
|
||||
cleanupFn = { fn: jasmine.createSpy('cleanup') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
globalErrors: {
|
||||
pushListener: function(f) { errorListeners.push(f); },
|
||||
popListener: function() { errorListeners.pop(); },
|
||||
},
|
||||
queueableFns: [queueableFn, nextQueueableFn],
|
||||
cleanupFns: [cleanupFn],
|
||||
completeOnFirstError: true,
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
errorListeners[errorListeners.length - 1](new Error('error'));
|
||||
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
|
||||
expect(cleanupFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips to cleanup functions when next.fail is called", function() {
|
||||
var queueableFn = { fn: function(done) {
|
||||
done.fail('nope');
|
||||
} },
|
||||
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
|
||||
cleanupFn = { fn: jasmine.createSpy('cleanup') },
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn],
|
||||
cleanupFns: [cleanupFn],
|
||||
completeOnFirstError: true,
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick();
|
||||
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
|
||||
expect(cleanupFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("calls a provided complete callback when done", function() {
|
||||
var queueableFn = { fn: jasmine.createSpy('fn') },
|
||||
completeCallback = jasmine.createSpy('completeCallback'),
|
||||
@@ -290,21 +535,83 @@ describe("QueueRunner", function() {
|
||||
expect(completeCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls a provided stack clearing function when done", function() {
|
||||
var asyncFn = { fn: function(done) { done() } },
|
||||
afterFn = { fn: jasmine.createSpy('afterFn') },
|
||||
completeCallback = jasmine.createSpy('completeCallback'),
|
||||
clearStack = jasmine.createSpy('clearStack'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [asyncFn, afterFn],
|
||||
clearStack: clearStack,
|
||||
onComplete: completeCallback
|
||||
});
|
||||
describe("clearing the stack", function() {
|
||||
beforeEach(function() {
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
clearStack.and.callFake(function(fn) { fn(); });
|
||||
afterEach(function() {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
expect(afterFn.fn).toHaveBeenCalled();
|
||||
expect(clearStack).toHaveBeenCalledWith(completeCallback);
|
||||
it("calls a provided stack clearing function when done", function() {
|
||||
var asyncFn = { fn: function(done) { done() } },
|
||||
afterFn = { fn: jasmine.createSpy('afterFn') },
|
||||
completeCallback = jasmine.createSpy('completeCallback'),
|
||||
clearStack = jasmine.createSpy('clearStack'),
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [asyncFn, afterFn],
|
||||
clearStack: clearStack,
|
||||
onComplete: completeCallback
|
||||
});
|
||||
|
||||
clearStack.and.callFake(function(fn) { fn(); });
|
||||
|
||||
queueRunner.execute();
|
||||
jasmine.clock().tick();
|
||||
expect(afterFn.fn).toHaveBeenCalled();
|
||||
expect(clearStack).toHaveBeenCalled();
|
||||
clearStack.calls.argsFor(0)[0]();
|
||||
expect(completeCallback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user context has not been defined', function() {
|
||||
beforeEach(function() {
|
||||
var fn;
|
||||
|
||||
this.fn = fn = jasmine.createSpy('fn1');
|
||||
this.queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [{ fn: fn }]
|
||||
});
|
||||
});
|
||||
|
||||
it('runs the functions on the scope of a UserContext', function() {
|
||||
var calls = [],
|
||||
context;
|
||||
|
||||
this.fn.and.callFake(function() {
|
||||
context = this;
|
||||
});
|
||||
|
||||
this.queueRunner.execute();
|
||||
|
||||
expect(context.constructor).toBe(jasmineUnderTest.UserContext);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user context has been defined', function() {
|
||||
beforeEach(function() {
|
||||
var fn, context;
|
||||
|
||||
this.fn = fn = jasmine.createSpy('fn1');
|
||||
this.context = context = new jasmineUnderTest.UserContext();
|
||||
this.queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [{ fn: fn }],
|
||||
userContext: context
|
||||
});
|
||||
});
|
||||
|
||||
it('runs the functions on the scope of a UserContext', function() {
|
||||
var calls = [],
|
||||
context;
|
||||
this.fn.and.callFake(function() {
|
||||
context = this;
|
||||
});
|
||||
|
||||
this.queueRunner.execute();
|
||||
|
||||
expect(context).toBe(this.context);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,6 @@ describe("ReportDispatcher", function() {
|
||||
dispatcher.provideFallbackReporter(reporter);
|
||||
dispatcher.foo(123, 456);
|
||||
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
|
||||
});
|
||||
|
||||
it("does not call fallback reporting methods when another report is provided", function() {
|
||||
@@ -59,6 +58,22 @@ describe("ReportDispatcher", function() {
|
||||
|
||||
expect(reporter.foo).toHaveBeenCalledWith(123, 456);
|
||||
expect(fallbackReporter.foo).not.toHaveBeenCalledWith(123, 456);
|
||||
});
|
||||
|
||||
it("allows registered reporters to be cleared", function() {
|
||||
var dispatcher = new jasmineUnderTest.ReportDispatcher(['foo', 'bar']),
|
||||
reporter1 = jasmine.createSpyObj('reporter1', ['foo', 'bar']),
|
||||
reporter2 = jasmine.createSpyObj('reporter2', ['foo', 'bar']);
|
||||
|
||||
dispatcher.addReporter(reporter1);
|
||||
dispatcher.foo(123);
|
||||
expect(reporter1.foo).toHaveBeenCalledWith(123);
|
||||
|
||||
dispatcher.clearReporters();
|
||||
dispatcher.addReporter(reporter2);
|
||||
dispatcher.bar(456);
|
||||
|
||||
expect(reporter1.bar).not.toHaveBeenCalled();
|
||||
expect(reporter2.bar).toHaveBeenCalledWith(456);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -103,8 +103,26 @@ describe("Spec", function() {
|
||||
|
||||
spec.execute();
|
||||
|
||||
var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(allSpecFns).toEqual([before, queueableFn, after]);
|
||||
var options = fakeQueueRunner.calls.mostRecent().args[0];
|
||||
expect(options.queueableFns).toEqual([before, queueableFn]);
|
||||
expect(options.cleanupFns).toEqual([after]);
|
||||
});
|
||||
|
||||
it("tells the queue runner that it's a leaf node", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
queueableFn: { fn: function() {} },
|
||||
beforeAndAfterFns: function() {
|
||||
return {befores: [], afters: []}
|
||||
},
|
||||
queueRunnerFactory: fakeQueueRunner
|
||||
});
|
||||
|
||||
spec.execute();
|
||||
|
||||
expect(fakeQueueRunner).toHaveBeenCalledWith(jasmine.objectContaining({
|
||||
isLeaf: true
|
||||
}));
|
||||
});
|
||||
|
||||
it("is marked pending if created without a function body", function() {
|
||||
@@ -123,7 +141,8 @@ describe("Spec", function() {
|
||||
});
|
||||
|
||||
it("can be disabled, but still calls callbacks", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
|
||||
.and.callFake(function(attrs) { attrs.onComplete(); }),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
specBody = jasmine.createSpy('specBody'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
@@ -140,7 +159,7 @@ describe("Spec", function() {
|
||||
|
||||
spec.execute();
|
||||
|
||||
expect(fakeQueueRunner).not.toHaveBeenCalled();
|
||||
expect(fakeQueueRunner).toHaveBeenCalled();
|
||||
expect(specBody).not.toHaveBeenCalled();
|
||||
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
@@ -148,7 +167,8 @@ describe("Spec", function() {
|
||||
});
|
||||
|
||||
it("can be disabled at execution time by a parent", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
|
||||
.and.callFake(function(attrs) { attrs.onComplete(); }),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
specBody = jasmine.createSpy('specBody'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
@@ -163,7 +183,7 @@ describe("Spec", function() {
|
||||
|
||||
expect(spec.result.status).toBe('disabled');
|
||||
|
||||
expect(fakeQueueRunner).not.toHaveBeenCalled();
|
||||
expect(fakeQueueRunner).toHaveBeenCalled();
|
||||
expect(specBody).not.toHaveBeenCalled();
|
||||
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
@@ -171,7 +191,8 @@ describe("Spec", function() {
|
||||
});
|
||||
|
||||
it("can be marked pending, but still calls callbacks when executed", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
|
||||
.and.callFake(function(attrs) { attrs.onComplete(); }),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new jasmineUnderTest.Spec({
|
||||
@@ -191,7 +212,7 @@ describe("Spec", function() {
|
||||
|
||||
spec.execute();
|
||||
|
||||
expect(fakeQueueRunner).not.toHaveBeenCalled();
|
||||
expect(fakeQueueRunner).toHaveBeenCalled();
|
||||
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
expect(resultCallback).toHaveBeenCalledWith({
|
||||
|
||||
@@ -16,6 +16,22 @@ describe("SpyRegistry", function() {
|
||||
}).toThrowError(/No method name supplied/);
|
||||
});
|
||||
|
||||
it("checks that the object is not `null`", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry();
|
||||
expect(function() {
|
||||
spyRegistry.spyOn(null, 'pants');
|
||||
}).toThrowError(/could not find an object/);
|
||||
});
|
||||
|
||||
it("checks that the method name is not `null`", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOn(subject, null);
|
||||
}).toThrowError(/No method name supplied/);
|
||||
});
|
||||
|
||||
it("checks for the existence of the method", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
@@ -77,6 +93,126 @@ describe("SpyRegistry", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#spyOnProperty", function() {
|
||||
// IE 8 doesn't support `definePropery` on non-DOM nodes
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
it("checks for the existence of the object", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry();
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(void 0, 'pants');
|
||||
}).toThrowError(/could not find an object/);
|
||||
});
|
||||
|
||||
it("checks that a property name was passed", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject);
|
||||
}).toThrowError(/No property name supplied/);
|
||||
});
|
||||
|
||||
it("checks for the existence of the method", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject, 'pants');
|
||||
}).toThrowError(/property does not exist/);
|
||||
});
|
||||
|
||||
it("checks for the existence of access type", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
|
||||
Object.defineProperty(subject, 'pants', {
|
||||
get: function() { return 1; },
|
||||
configurable: true
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject, 'pants', 'set');
|
||||
}).toThrowError(/does not have access type/);
|
||||
});
|
||||
|
||||
it("checks if it has already been spied upon", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {};
|
||||
|
||||
Object.defineProperty(subject, 'spiedProp', {
|
||||
get: function() { return 1; },
|
||||
configurable: true
|
||||
});
|
||||
|
||||
spyRegistry.spyOnProperty(subject, 'spiedProp');
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject, 'spiedProp');
|
||||
}).toThrowError(/has already been spied upon/);
|
||||
});
|
||||
|
||||
it("checks if it can be spied upon", function() {
|
||||
var subject = {};
|
||||
|
||||
Object.defineProperty(subject, 'myProp', {
|
||||
get: function() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(subject, 'spiedProp', {
|
||||
get: function() {},
|
||||
configurable: true
|
||||
});
|
||||
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry();
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject, 'myProp');
|
||||
}).toThrowError(/is not declared configurable/);
|
||||
|
||||
expect(function() {
|
||||
spyRegistry.spyOnProperty(subject, 'spiedProp');
|
||||
}).not.toThrowError(/is not declared configurable/);
|
||||
});
|
||||
|
||||
it("overrides the property getter on the object and returns the spy", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {},
|
||||
returnValue = 1;
|
||||
|
||||
Object.defineProperty(subject, 'spiedProperty', {
|
||||
get: function() { return returnValue; },
|
||||
configurable: true
|
||||
});
|
||||
|
||||
expect(subject.spiedProperty).toEqual(returnValue);
|
||||
|
||||
var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty');
|
||||
var getter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty').get;
|
||||
|
||||
expect(getter).toEqual(spy);
|
||||
expect(subject.spiedProperty).toBeUndefined();
|
||||
});
|
||||
|
||||
it("overrides the property setter on the object and returns the spy", function() {
|
||||
var spyRegistry = new jasmineUnderTest.SpyRegistry(),
|
||||
subject = {},
|
||||
returnValue = 1;
|
||||
|
||||
Object.defineProperty(subject, 'spiedProperty', {
|
||||
get: function() { return returnValue; },
|
||||
set: function() {},
|
||||
configurable: true
|
||||
});
|
||||
|
||||
var spy = spyRegistry.spyOnProperty(subject, 'spiedProperty', 'set');
|
||||
var setter = Object.getOwnPropertyDescriptor(subject, 'spiedProperty').set;
|
||||
|
||||
expect(subject.spiedProperty).toEqual(returnValue);
|
||||
expect(setter).toEqual(spy);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#clearSpies", function() {
|
||||
it("restores the original functions on the spied-upon objects", function() {
|
||||
var spies = [],
|
||||
@@ -127,6 +263,76 @@ describe("SpyRegistry", function() {
|
||||
|
||||
expect(subject.hasOwnProperty('spiedFunc')).toBe(false);
|
||||
expect(subject.spiedFunc).toBe(originalFunction);
|
||||
})
|
||||
});
|
||||
|
||||
it("restores the original function when it\'s inherited and cannot be deleted", function() {
|
||||
// IE 8 doesn't support `Object.create` or `Object.defineProperty`
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
var spies = [],
|
||||
spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() { return spies; }}),
|
||||
originalFunction = function() {},
|
||||
subjectParent = {spiedFunc: originalFunction};
|
||||
|
||||
var subject = Object.create(subjectParent);
|
||||
|
||||
spyRegistry.spyOn(subject, 'spiedFunc');
|
||||
|
||||
// simulate a spy that cannot be deleted
|
||||
Object.defineProperty(subject, 'spiedFunc', {
|
||||
configurable: false
|
||||
});
|
||||
|
||||
spyRegistry.clearSpies();
|
||||
|
||||
expect(jasmineUnderTest.isSpy(subject.spiedFunc)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('spying on properties', function() {
|
||||
it("restores the original properties on the spied-upon objects", function() {
|
||||
// IE 8 doesn't support `definePropery` on non-DOM nodes
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
var spies = [],
|
||||
spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() { return spies; }}),
|
||||
originalReturn = 1,
|
||||
subject = {};
|
||||
|
||||
Object.defineProperty(subject, 'spiedProp', {
|
||||
get: function() { return originalReturn; },
|
||||
configurable: true
|
||||
});
|
||||
|
||||
spyRegistry.spyOnProperty(subject, 'spiedProp');
|
||||
spyRegistry.clearSpies();
|
||||
|
||||
expect(subject.spiedProp).toBe(originalReturn);
|
||||
});
|
||||
|
||||
it("does not add a property that the spied-upon object didn't originally have", function() {
|
||||
// IE 8 doesn't support `Object.create`
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
var spies = [],
|
||||
spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() { return spies; }}),
|
||||
originalReturn = 1,
|
||||
subjectParent = {};
|
||||
|
||||
Object.defineProperty(subjectParent, 'spiedProp', {
|
||||
get: function() { return originalReturn; },
|
||||
configurable: true
|
||||
});
|
||||
|
||||
var subject = Object.create(subjectParent);
|
||||
|
||||
expect(subject.hasOwnProperty('spiedProp')).toBe(false);
|
||||
|
||||
spyRegistry.spyOnProperty(subject, 'spiedProp');
|
||||
spyRegistry.clearSpies();
|
||||
|
||||
expect(subject.hasOwnProperty('spiedProp')).toBe(false);
|
||||
expect(subject.spiedProp).toBe(originalReturn);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,9 +57,39 @@ describe('Spies', function () {
|
||||
|
||||
expect(trackSpy.calls.mostRecent().args[0].returnValue).toEqual("return value");
|
||||
});
|
||||
|
||||
it("preserves arity of original function", function () {
|
||||
var functions = [
|
||||
function nullary () {},
|
||||
function unary (arg) {},
|
||||
function binary (arg1, arg2) {},
|
||||
function ternary (arg1, arg2, arg3) {},
|
||||
function quaternary (arg1, arg2, arg3, arg4) {},
|
||||
function quinary (arg1, arg2, arg3, arg4, arg5) {},
|
||||
function senary (arg1, arg2, arg3, arg4, arg5, arg6) {}
|
||||
];
|
||||
|
||||
for (var arity = 0; arity < functions.length; arity++) {
|
||||
var someFunction = functions[arity],
|
||||
spy = jasmineUnderTest.createSpy(someFunction.name, someFunction);
|
||||
|
||||
expect(spy.length).toEqual(arity);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("createSpyObj", function() {
|
||||
it("should create an object with spy methods and corresponding return values when you call jasmine.createSpyObj() with an object", function () {
|
||||
var spyObj = jasmineUnderTest.createSpyObj('BaseName', {'method1': 42, 'method2': 'special sauce' });
|
||||
|
||||
expect(spyObj.method1()).toEqual(42);
|
||||
expect(spyObj.method1.and.identity()).toEqual('BaseName.method1');
|
||||
|
||||
expect(spyObj.method2()).toEqual('special sauce');
|
||||
expect(spyObj.method2.and.identity()).toEqual('BaseName.method2');
|
||||
});
|
||||
|
||||
|
||||
it("should create an object with a bunch of spy methods when you call jasmine.createSpyObj()", function() {
|
||||
var spyObj = jasmineUnderTest.createSpyObj('BaseName', ['method1', 'method2']);
|
||||
|
||||
@@ -76,10 +106,22 @@ describe('Spies', function () {
|
||||
expect(spyObj.method2.and.identity()).toEqual('unknown.method2');
|
||||
});
|
||||
|
||||
it("should throw if you do not pass an array argument", function() {
|
||||
it("should throw if you do not pass an array or object argument", function() {
|
||||
expect(function() {
|
||||
jasmineUnderTest.createSpyObj('BaseName');
|
||||
}).toThrow("createSpyObj requires a non-empty array of method names to create spies for");
|
||||
}).toThrow("createSpyObj requires a non-empty array or object of method names to create spies for");
|
||||
});
|
||||
|
||||
it("should throw if you pass an empty array argument", function() {
|
||||
expect(function() {
|
||||
jasmineUnderTest.createSpyObj('BaseName', []);
|
||||
}).toThrow("createSpyObj requires a non-empty array or object of method names to create spies for");
|
||||
});
|
||||
|
||||
it("should throw if you pass an empty object argument", function() {
|
||||
expect(function() {
|
||||
jasmineUnderTest.createSpyObj('BaseName', {});
|
||||
}).toThrow("createSpyObj requires a non-empty array or object of method names to create spies for");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -94,14 +94,14 @@ describe("SpyStrategy", function() {
|
||||
|
||||
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(), /.*/];
|
||||
|
||||
for (var i=0; i<invalidFakes.length; i++) {
|
||||
var invalidFake = invalidFakes[i],
|
||||
spyStrategy = new jasmineUnderTest.SpyStrategy({fn: originalFn});
|
||||
spyOn(jasmineUnderTest, 'isFunction_').and.returnValue(false);
|
||||
|
||||
expect(function() {spyStrategy.callFake(invalidFake);}).toThrowError('Argument passed to callFake should be a function, got ' + invalidFake);
|
||||
}
|
||||
expect(function () {
|
||||
spyStrategy.callFake(function() {});
|
||||
}).toThrowError(/^Argument passed to callFake should be a function, got/);
|
||||
});
|
||||
|
||||
it("allows a return to plan stubbing after another strategy", function() {
|
||||
|
||||
@@ -83,13 +83,6 @@ describe("Suite", function() {
|
||||
expect(suite.getResult().status).toBe('finished');
|
||||
});
|
||||
|
||||
it("retrieves a result with disabled status", function() {
|
||||
var suite = new jasmineUnderTest.Suite({});
|
||||
suite.disable();
|
||||
|
||||
expect(suite.getResult().status).toBe('disabled');
|
||||
});
|
||||
|
||||
it("retrieves a result with pending status", function() {
|
||||
var suite = new jasmineUnderTest.Suite({});
|
||||
suite.pend();
|
||||
@@ -97,23 +90,15 @@ describe("Suite", function() {
|
||||
expect(suite.getResult().status).toBe('pending');
|
||||
});
|
||||
|
||||
it("priviledges a disabled status over pending status", function() {
|
||||
var suite = new jasmineUnderTest.Suite({});
|
||||
suite.disable();
|
||||
suite.pend();
|
||||
|
||||
expect(suite.getResult().status).toBe('disabled');
|
||||
});
|
||||
|
||||
it("is executable if not disabled", function() {
|
||||
it("is executable if not pending", function() {
|
||||
var suite = new jasmineUnderTest.Suite({});
|
||||
|
||||
expect(suite.isExecutable()).toBe(true);
|
||||
});
|
||||
|
||||
it("is not executable if disabled", function() {
|
||||
it("is not executable if pending", function() {
|
||||
var suite = new jasmineUnderTest.Suite({});
|
||||
suite.disable();
|
||||
suite.pend();
|
||||
|
||||
expect(suite.isExecutable()).toBe(false);
|
||||
});
|
||||
@@ -156,5 +141,15 @@ describe("Suite", function() {
|
||||
suite.onException(new jasmineUnderTest.errors.ExpectationFailed());
|
||||
|
||||
expect(suite.getResult().failedExpectations).toEqual([]);
|
||||
})
|
||||
});
|
||||
|
||||
describe('#sharedUserContext', function() {
|
||||
beforeEach(function() {
|
||||
this.suite = new jasmineUnderTest.Suite({});
|
||||
});
|
||||
|
||||
it('returns a UserContext', function() {
|
||||
expect(this.suite.sharedUserContext().constructor).toBe(jasmineUnderTest.UserContext);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
54
spec/core/UserContextSpec.js
Normal file
54
spec/core/UserContextSpec.js
Normal file
@@ -0,0 +1,54 @@
|
||||
describe("UserContext", function() {
|
||||
it("Behaves just like an plain object", function() {
|
||||
var context = new jasmineUnderTest.UserContext(),
|
||||
properties = [];
|
||||
|
||||
for (var prop in context) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
properties.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
expect(properties).toEqual([]);
|
||||
});
|
||||
|
||||
describe('.fromExisting', function() {
|
||||
describe('when using an already built context as model', function() {
|
||||
beforeEach(function() {
|
||||
this.context = new jasmineUnderTest.UserContext();
|
||||
this.context.key = 'value';
|
||||
this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context);
|
||||
});
|
||||
|
||||
it('returns a cloned object', function() {
|
||||
expect(this.cloned).toEqual(this.context);
|
||||
});
|
||||
|
||||
it('does not return the same object', function() {
|
||||
expect(this.cloned).not.toBe(this.context);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using a regular object as parameter', function() {
|
||||
beforeEach(function() {
|
||||
this.context = {};
|
||||
this.value = 'value'
|
||||
this.context.key = this.value;
|
||||
this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context);
|
||||
});
|
||||
|
||||
it('returns an object with the same attributes', function() {
|
||||
expect(this.cloned.key).toEqual(this.value);
|
||||
});
|
||||
|
||||
it('does not return the same object', function() {
|
||||
expect(this.cloned).not.toBe(this.context);
|
||||
});
|
||||
|
||||
it('returns an UserContext', function() {
|
||||
expect(this.cloned.constructor).toBe(jasmineUnderTest.UserContext);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,22 @@ describe("jasmineUnderTest.util", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("isObject_", function() {
|
||||
it("should return true if the argument is an object", function() {
|
||||
expect(jasmineUnderTest.isObject_({})).toBe(true);
|
||||
expect(jasmineUnderTest.isObject_({an: "object"})).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if the argument is not an object", function() {
|
||||
expect(jasmineUnderTest.isObject_(undefined)).toBe(false);
|
||||
expect(jasmineUnderTest.isObject_([])).toBe(false);
|
||||
expect(jasmineUnderTest.isObject_(function() {})).toBe(false);
|
||||
expect(jasmineUnderTest.isObject_('foo')).toBe(false);
|
||||
expect(jasmineUnderTest.isObject_(5)).toBe(false);
|
||||
expect(jasmineUnderTest.isObject_(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isUndefined", function() {
|
||||
it("reports if a variable is defined", function() {
|
||||
var a;
|
||||
@@ -25,4 +41,59 @@ describe("jasmineUnderTest.util", function() {
|
||||
expect(jasmineUnderTest.util.isUndefined(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPropertyDescriptor", function() {
|
||||
// IE 8 doesn't support `definePropery` on non-DOM nodes
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
it("get property descriptor from object", function() {
|
||||
var obj = {prop: 1},
|
||||
actual = jasmineUnderTest.util.getPropertyDescriptor(obj, 'prop'),
|
||||
expected = Object.getOwnPropertyDescriptor(obj, 'prop');
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it("get property descriptor from object property", function() {
|
||||
var proto = {prop: 1},
|
||||
obj = Object.create(proto),
|
||||
actual = jasmineUnderTest.util.getPropertyDescriptor(proto, 'prop'),
|
||||
expected = Object.getOwnPropertyDescriptor(proto, 'prop');
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("objectDifference", function() {
|
||||
it("given two objects A and B, returns the properties in A not present in B", function() {
|
||||
var a = {
|
||||
foo: 3,
|
||||
bar: 4,
|
||||
baz: 5
|
||||
};
|
||||
|
||||
var b = {
|
||||
bar: 6,
|
||||
quux: 7
|
||||
};
|
||||
|
||||
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({foo: 3, baz: 5})
|
||||
});
|
||||
|
||||
it("only looks at own properties of both objects", function() {
|
||||
function Foo() {}
|
||||
|
||||
Foo.prototype.x = 1;
|
||||
Foo.prototype.y = 2;
|
||||
|
||||
var a = new Foo();
|
||||
a.x = 1;
|
||||
|
||||
var b = new Foo();
|
||||
b.y = 2;
|
||||
|
||||
expect(jasmineUnderTest.util.objectDifference(a, b)).toEqual({x: 1});
|
||||
expect(jasmineUnderTest.util.objectDifference(b, a)).toEqual({y: 2});
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@@ -36,4 +36,17 @@ describe("ArrayContaining", function() {
|
||||
|
||||
expect(containing.jasmineToString()).toMatch("<jasmine.arrayContaining");
|
||||
});
|
||||
|
||||
it("uses custom equality testers", function() {
|
||||
var tester = function(a, b) {
|
||||
// All "foo*" strings match each other.
|
||||
if (typeof a == "string" && typeof b == "string" &&
|
||||
a.substr(0, 3) == "foo" && b.substr(0, 3) == "foo") {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var containing = new jasmineUnderTest.ArrayContaining(["fooVal"]);
|
||||
|
||||
expect(containing.asymmetricMatch(["fooBar"], [tester])).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,4 +86,17 @@ describe("ObjectContaining", function() {
|
||||
|
||||
expect(containing.asymmetricMatch(obj)).toBe(true);
|
||||
});
|
||||
|
||||
it("uses custom equality testers", function() {
|
||||
var tester = function(a, b) {
|
||||
// All "foo*" strings match each other.
|
||||
if (typeof a == "string" && typeof b == "string" &&
|
||||
a.substr(0, 3) == "foo" && b.substr(0, 3) == "foo") {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var containing = new jasmineUnderTest.ObjectContaining({foo: "fooVal"});
|
||||
|
||||
expect(containing.asymmetricMatch({foo: "fooBar"}, [tester])).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,6 +56,53 @@ describe("Custom Matchers (Integration)", function() {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("passes the spec if the custom equality matcher passes for types nested inside asymmetric equality testers", function(done) {
|
||||
env.it("spec using custom equality matcher", function() {
|
||||
var customEqualityFn = function(a, b) {
|
||||
// All "foo*" strings match each other.
|
||||
if (typeof a == "string" && typeof b == "string" &&
|
||||
a.substr(0, 3) == "foo" && b.substr(0, 3) == "foo") {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
env.addCustomEqualityTester(customEqualityFn);
|
||||
env.expect({foo: 'fooValue'}).toEqual(jasmine.objectContaining({foo: 'fooBar'}));
|
||||
env.expect(['fooValue']).toEqual(jasmine.arrayContaining(['fooBar']));
|
||||
});
|
||||
|
||||
var specExpectations = function(result) {
|
||||
expect(result.status).toEqual('passed');
|
||||
};
|
||||
|
||||
env.addReporter({ specDone: specExpectations, jasmineDone: done });
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("displays an appropriate failure message if a custom equality matcher fails", function(done) {
|
||||
env.it("spec using custom equality matcher", function() {
|
||||
var customEqualityFn = function(a, b) {
|
||||
// "foo" is not equal to anything
|
||||
if (a === 'foo' || b === 'foo') {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
env.addCustomEqualityTester(customEqualityFn);
|
||||
env.expect({foo: 'foo'}).toEqual({foo: 'foo'});
|
||||
});
|
||||
|
||||
var specExpectations = function(result) {
|
||||
expect(result.status).toEqual('failed');
|
||||
expect(result.failedExpectations[0].message).toEqual(
|
||||
"Expected $.foo = 'foo' to equal 'foo'."
|
||||
);
|
||||
};
|
||||
|
||||
env.addReporter({ specDone: specExpectations, jasmineDone: done });
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("uses the negative compare function for a negative comparison, if provided", function(done) {
|
||||
env.it("spec with custom negative comparison matcher", function() {
|
||||
env.addMatchers({
|
||||
|
||||
@@ -181,6 +181,12 @@ describe("Env integration", function() {
|
||||
}
|
||||
})]
|
||||
}));
|
||||
expect(specDone).toHaveBeenCalledWith(jasmine.objectContaining({
|
||||
description: 'pretty prints objects',
|
||||
failedExpectations: [jasmine.objectContaining({
|
||||
message: 'Failed: Object({ prop: \'value\', arr: [ \'works\', true ] })'
|
||||
})]
|
||||
}));
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -197,6 +203,27 @@ describe("Env integration", function() {
|
||||
env.it('has a message and stack trace from an Error', function() {
|
||||
env.fail(new Error('error message'));
|
||||
});
|
||||
|
||||
env.it('pretty prints objects', function() {
|
||||
env.fail({prop: 'value', arr: ['works', true]});
|
||||
})
|
||||
});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("produces an understandable error message when 'fail' is used outside of a current spec", function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
|
||||
|
||||
reporter.jasmineDone.and.callFake(done);
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.describe("A Suite", function() {
|
||||
env.it("an async spec that is actually synchronous", function(underTestCallback) {
|
||||
underTestCallback();
|
||||
});
|
||||
expect(function() { env.fail(); }).toThrowError(/'fail' was used when there was no current spec/);
|
||||
});
|
||||
|
||||
env.execute();
|
||||
@@ -216,7 +243,7 @@ describe("Env integration", function() {
|
||||
} else {
|
||||
secondSpecContext = this;
|
||||
}
|
||||
expect(this).toEqual({});
|
||||
expect(this).toEqual(new jasmineUnderTest.UserContext());
|
||||
});
|
||||
|
||||
env.it("sync spec", function() {
|
||||
@@ -250,7 +277,7 @@ describe("Env integration", function() {
|
||||
|
||||
env.beforeEach(function() {
|
||||
specContext = this;
|
||||
expect(this).toEqual({});
|
||||
expect(this).toEqual(new jasmineUnderTest.UserContext());
|
||||
});
|
||||
|
||||
env.it("sync spec", function(underTestCallback) {
|
||||
@@ -429,6 +456,41 @@ describe("Env integration", function() {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("copes with async failures after done has been called", function(done) {
|
||||
var global = {
|
||||
setTimeout: function(fn, delay) { setTimeout(fn, delay) },
|
||||
clearTimeout: function(fn, delay) { clearTimeout(fn, delay) },
|
||||
};
|
||||
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone", "suiteDone" ]);
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.specDone).not.toHaveFailedExpecationsForRunnable('A suite fails', ['fail thrown']);
|
||||
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('A suite', ['fail thrown']);
|
||||
done();
|
||||
});
|
||||
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.fdescribe('A suite', function() {
|
||||
env.it('fails', function(specDone) {
|
||||
setTimeout(function() {
|
||||
specDone();
|
||||
setTimeout(function() {
|
||||
global.onerror('fail');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
env.describe('Ignored', function() {
|
||||
env.it('is not run', function() {});
|
||||
});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
describe('suiteDone reporting', function(){
|
||||
it("reports when an afterAll fails an expectation", function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
@@ -890,16 +952,15 @@ describe("Env integration", function() {
|
||||
});
|
||||
|
||||
describe("with a mock clock", function() {
|
||||
var originalTimeout;
|
||||
|
||||
beforeEach(function() {
|
||||
originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
||||
this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
|
||||
this.realSetTimeout = setTimeout;
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
jasmine.clock().uninstall();
|
||||
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.originalTimeout;
|
||||
});
|
||||
|
||||
it("should wait a specified interval before failing specs haven't called done yet", function(done) {
|
||||
@@ -940,8 +1001,8 @@ describe("Env integration", function() {
|
||||
env.addReporter(reporter);
|
||||
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 1290;
|
||||
|
||||
env.beforeAll(function(done) {
|
||||
jasmine.clock().tick(1290);
|
||||
env.beforeAll(function(innerDone) {
|
||||
jasmine.clock().tick(1291);
|
||||
});
|
||||
|
||||
env.it("spec that will be failed", function() {
|
||||
@@ -955,7 +1016,7 @@ describe("Env integration", function() {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should not use the mock clock for asynchronous timeouts", function(){
|
||||
it("should not use the mock clock for asynchronous timeouts", function(done){
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone" ]),
|
||||
clock = env.clock;
|
||||
@@ -963,6 +1024,7 @@ describe("Env integration", function() {
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.specDone.calls.count()).toEqual(1);
|
||||
expect(reporter.specDone.calls.argsFor(0)[0]).toEqual(jasmine.objectContaining({status: 'passed'}));
|
||||
done();
|
||||
});
|
||||
|
||||
env.addReporter(reporter);
|
||||
@@ -976,10 +1038,11 @@ describe("Env integration", function() {
|
||||
clock.uninstall();
|
||||
});
|
||||
|
||||
env.it("spec that should not time out", function(done) {
|
||||
env.it("spec that should not time out", function(innerDone) {
|
||||
clock.tick(6);
|
||||
expect(true).toEqual(true);
|
||||
done();
|
||||
innerDone();
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
|
||||
env.execute();
|
||||
@@ -1010,11 +1073,13 @@ describe("Env integration", function() {
|
||||
});
|
||||
|
||||
env.execute();
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
|
||||
it('should wait a custom interval before reporting async functions that fail to call done', function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']);
|
||||
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']),
|
||||
realSetTimeout = this.realSetTimeout;
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite beforeAll times out', [
|
||||
@@ -1044,6 +1109,11 @@ describe("Env integration", function() {
|
||||
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
||||
|
||||
env.describe('suite', function() {
|
||||
env.afterAll(function() {
|
||||
realSetTimeout(function() {
|
||||
jasmine.clock().tick(10);
|
||||
}, 100);
|
||||
});
|
||||
env.describe('beforeAll', function() {
|
||||
env.beforeAll(function(innerDone) {
|
||||
jasmine.clock().tick(5001);
|
||||
@@ -1130,6 +1200,8 @@ describe("Env integration", function() {
|
||||
env.fail();
|
||||
innerDone();
|
||||
}, 1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
|
||||
env.it('specifies a message', function(innerDone) {
|
||||
@@ -1137,12 +1209,16 @@ describe("Env integration", function() {
|
||||
env.fail('messy message');
|
||||
innerDone();
|
||||
}, 1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
|
||||
env.it('fails via the done callback', function(innerDone) {
|
||||
setTimeout(function() {
|
||||
innerDone.fail('done failed');
|
||||
}, 1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
|
||||
env.it('has a message from an Error', function(innerDone) {
|
||||
@@ -1150,14 +1226,12 @@ describe("Env integration", function() {
|
||||
env.fail(new Error('error message'));
|
||||
innerDone();
|
||||
}, 1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
});
|
||||
|
||||
env.execute();
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1186,7 +1260,7 @@ describe("Env integration", function() {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it('should only run focused suites', function(){
|
||||
it('should only run focused suites', function(done){
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
calls = [];
|
||||
|
||||
@@ -1225,7 +1299,8 @@ describe("Env integration", function() {
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||
totalSpecsDefined: 1
|
||||
totalSpecsDefined: 1,
|
||||
order: jasmine.any(jasmineUnderTest.Order)
|
||||
});
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({
|
||||
@@ -1260,7 +1335,8 @@ describe("Env integration", function() {
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||
totalSpecsDefined: 1
|
||||
totalSpecsDefined: 1,
|
||||
order: jasmine.any(jasmineUnderTest.Order)
|
||||
});
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({
|
||||
@@ -1298,7 +1374,8 @@ describe("Env integration", function() {
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||
totalSpecsDefined: 5
|
||||
totalSpecsDefined: 5,
|
||||
order: jasmine.any(jasmineUnderTest.Order)
|
||||
});
|
||||
|
||||
expect(reporter.specDone.calls.count()).toBe(5);
|
||||
@@ -1355,6 +1432,34 @@ describe("Env integration", function() {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should report the random seed at the beginning and end of execution", function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', [
|
||||
"jasmineStarted",
|
||||
"jasmineDone",
|
||||
"suiteStarted",
|
||||
"suiteDone",
|
||||
"specStarted",
|
||||
"specDone"
|
||||
]);
|
||||
env.randomizeTests(true);
|
||||
env.seed('123456');
|
||||
|
||||
reporter.jasmineDone.and.callFake(function(doneArg) {
|
||||
expect(reporter.jasmineStarted).toHaveBeenCalled();
|
||||
var startedArg = reporter.jasmineStarted.calls.argsFor(0)[0];
|
||||
expect(startedArg.order.random).toEqual(true);
|
||||
expect(startedArg.order.seed).toEqual('123456');
|
||||
|
||||
expect(doneArg.order.random).toEqual(true);
|
||||
expect(doneArg.order.seed).toEqual('123456');
|
||||
done();
|
||||
});
|
||||
|
||||
env.addReporter(reporter);
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it('should report pending spec messages', function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', [
|
||||
@@ -1414,10 +1519,11 @@ describe("Env integration", function() {
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
|
||||
totalSpecsDefined: 1
|
||||
totalSpecsDefined: 1,
|
||||
order: jasmine.any(jasmineUnderTest.Order)
|
||||
});
|
||||
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({ status: 'pending' }));
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({ status: 'disabled' }));
|
||||
expect(reporter.suiteDone).toHaveBeenCalledWith(jasmine.objectContaining({ description: 'xd out', status: 'pending' }));
|
||||
expect(reporter.suiteDone.calls.count()).toBe(4);
|
||||
|
||||
@@ -1572,14 +1678,17 @@ describe("Env integration", function() {
|
||||
});
|
||||
|
||||
it("produces an understandable error message when an 'expect' is used outside of a current spec", function(done) {
|
||||
var env = new jasmineUnderTest.Env();
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReporter', ['jasmineDone']);
|
||||
|
||||
reporter.jasmineDone.and.callFake(done);
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.describe("A Suite", function() {
|
||||
env.it("an async spec that is actually synchronous", function(underTestCallback) {
|
||||
underTestCallback();
|
||||
expect(function() { env.expect('a').toEqual('a'); }).toThrowError(/'expect' was used when there was no current spec/);
|
||||
done();
|
||||
});
|
||||
expect(function() { env.expect('a').toEqual('a'); }).toThrowError(/'expect' was used when there was no current spec/);
|
||||
});
|
||||
|
||||
env.execute();
|
||||
@@ -1746,4 +1855,37 @@ describe("Env integration", function() {
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should associate errors thrown from async code with the correct runnable", function(done) {
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone','suiteDone','specDone']);
|
||||
|
||||
reporter.jasmineDone.and.callFake(function() {
|
||||
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('async suite', [
|
||||
/^(((Uncaught )?Error: suite( thrown)?)|(suite thrown))$/
|
||||
]);
|
||||
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite async spec', [
|
||||
/^(((Uncaught )?Error: spec( thrown)?)|(spec thrown))$/
|
||||
]);
|
||||
done();
|
||||
});
|
||||
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.describe('async suite', function() {
|
||||
env.afterAll(function(innerDone) {
|
||||
setTimeout(function() { throw new Error('suite'); }, 1);
|
||||
}, 10);
|
||||
|
||||
env.it('spec', function() {});
|
||||
});
|
||||
|
||||
env.describe('suite', function() {
|
||||
env.it('async spec', function(innerDone) {
|
||||
setTimeout(function() { throw new Error('spec'); }, 1);
|
||||
}, 10);
|
||||
});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -172,6 +172,22 @@ describe("jasmine spec running", function () {
|
||||
it("should run multiple befores and afters ordered so functions declared later are treated as more specific", function(done) {
|
||||
var actions = [];
|
||||
|
||||
env.beforeAll(function() {
|
||||
actions.push('runner beforeAll1');
|
||||
});
|
||||
|
||||
env.afterAll(function() {
|
||||
actions.push('runner afterAll1');
|
||||
});
|
||||
|
||||
env.beforeAll(function() {
|
||||
actions.push('runner beforeAll2');
|
||||
});
|
||||
|
||||
env.afterAll(function() {
|
||||
actions.push('runner afterAll2');
|
||||
});
|
||||
|
||||
env.beforeEach(function () {
|
||||
actions.push('runner beforeEach1');
|
||||
});
|
||||
@@ -212,6 +228,8 @@ describe("jasmine spec running", function () {
|
||||
|
||||
var assertions = function() {
|
||||
var expected = [
|
||||
"runner beforeAll1",
|
||||
"runner beforeAll2",
|
||||
"runner beforeEach1",
|
||||
"runner beforeEach2",
|
||||
"beforeEach1",
|
||||
@@ -220,7 +238,9 @@ describe("jasmine spec running", function () {
|
||||
"afterEach2",
|
||||
"afterEach1",
|
||||
"runner afterEach2",
|
||||
"runner afterEach1"
|
||||
"runner afterEach1",
|
||||
"runner afterAll2",
|
||||
"runner afterAll1"
|
||||
];
|
||||
expect(actions).toEqual(expected);
|
||||
done();
|
||||
@@ -475,7 +495,7 @@ describe("jasmine spec running", function () {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it('focused runnables unfocus ancestor focused suites', function() {
|
||||
it('focused runnables unfocus ancestor focused suites', function(done) {
|
||||
var actions = [];
|
||||
|
||||
env.fdescribe('focused suite', function() {
|
||||
@@ -518,7 +538,29 @@ describe("jasmine spec running", function () {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should allow top level suites to be disabled", function() {
|
||||
it("shouldn't run before/after functions in disabled suites", function(done) {
|
||||
var shouldNotRun = jasmine.createSpy("shouldNotRun"),
|
||||
suite = env.xdescribe('A disabled Suite', function() {
|
||||
// None of the before/after functions should run.
|
||||
env.beforeAll(shouldNotRun);
|
||||
env.beforeEach(shouldNotRun);
|
||||
env.afterEach(shouldNotRun);
|
||||
env.afterAll(shouldNotRun);
|
||||
|
||||
env.it('spec inside a disabled suite', shouldNotRun);
|
||||
});
|
||||
|
||||
var assertions = function() {
|
||||
expect(shouldNotRun).not.toHaveBeenCalled();
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should allow top level suites to be disabled", function(done) {
|
||||
var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"),
|
||||
otherSpec = jasmine.createSpy("otherSpec");
|
||||
|
||||
@@ -794,4 +836,115 @@ describe("jasmine spec running", function () {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
describe("When throwOnExpectationFailure is set", function() {
|
||||
it("skips to cleanup functions after an error", function(done) {
|
||||
var actions = [];
|
||||
|
||||
env.describe('Something', function() {
|
||||
env.beforeEach(function() {
|
||||
actions.push('outer beforeEach');
|
||||
throw new Error("error");
|
||||
});
|
||||
|
||||
env.afterEach(function() {
|
||||
actions.push('outer afterEach');
|
||||
});
|
||||
|
||||
env.describe('Inner', function() {
|
||||
env.beforeEach(function() {
|
||||
actions.push('inner beforeEach');
|
||||
});
|
||||
|
||||
env.afterEach(function() {
|
||||
actions.push('inner afterEach');
|
||||
});
|
||||
|
||||
env.it('does it' , function() {
|
||||
actions.push('inner it');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
env.throwOnExpectationFailure(true);
|
||||
|
||||
var assertions = function() {
|
||||
expect(actions).toEqual([
|
||||
'outer beforeEach',
|
||||
'inner afterEach',
|
||||
'outer afterEach'
|
||||
]);
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("skips to cleanup functions after done.fail is called", function(done) {
|
||||
var actions = [];
|
||||
|
||||
env.describe('Something', function() {
|
||||
env.beforeEach(function(done) {
|
||||
actions.push('beforeEach');
|
||||
done.fail('error');
|
||||
actions.push('after done.fail');
|
||||
});
|
||||
|
||||
env.afterEach(function() {
|
||||
actions.push('afterEach');
|
||||
});
|
||||
|
||||
env.it('does it' , function() {
|
||||
actions.push('it');
|
||||
});
|
||||
});
|
||||
|
||||
env.throwOnExpectationFailure(true);
|
||||
|
||||
var assertions = function() {
|
||||
expect(actions).toEqual([
|
||||
'beforeEach',
|
||||
'afterEach'
|
||||
]);
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("skips to cleanup functions when an async function times out", function(done) {
|
||||
var actions = [];
|
||||
|
||||
env.describe('Something', function() {
|
||||
env.beforeEach(function(innerDone) {
|
||||
actions.push('beforeEach');
|
||||
}, 1);
|
||||
|
||||
env.afterEach(function() {
|
||||
actions.push('afterEach');
|
||||
});
|
||||
|
||||
env.it('does it' , function() {
|
||||
actions.push('it');
|
||||
});
|
||||
});
|
||||
|
||||
env.throwOnExpectationFailure(true);
|
||||
|
||||
var assertions = function() {
|
||||
expect(actions).toEqual([
|
||||
'beforeEach',
|
||||
'afterEach'
|
||||
]);
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
47
spec/core/matchers/DiffBuilderSpec.js
Normal file
47
spec/core/matchers/DiffBuilderSpec.js
Normal file
@@ -0,0 +1,47 @@
|
||||
describe("DiffBuilder", function() {
|
||||
it("records the actual and expected objects", function() {
|
||||
var diffBuilder = jasmineUnderTest.DiffBuilder();
|
||||
diffBuilder.record({x: 'actual'}, {x: 'expected'});
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual("Expected Object({ x: 'actual' }) to equal Object({ x: 'expected' }).");
|
||||
});
|
||||
|
||||
it("prints the path at which the difference was found", function() {
|
||||
var diffBuilder = jasmineUnderTest.DiffBuilder();
|
||||
|
||||
diffBuilder.withPath('foo', function() {
|
||||
diffBuilder.record({x: 'actual'}, {x: 'expected'});
|
||||
});
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual("Expected $.foo = Object({ x: 'actual' }) to equal Object({ x: 'expected' }).");
|
||||
});
|
||||
|
||||
it("prints multiple messages, separated by newlines", function() {
|
||||
var diffBuilder = jasmineUnderTest.DiffBuilder();
|
||||
|
||||
diffBuilder.withPath('foo', function() {
|
||||
diffBuilder.record(1, 2);
|
||||
});
|
||||
|
||||
var message =
|
||||
"Expected $.foo = 1 to equal 2.\n" +
|
||||
"Expected 3 to equal 4.";
|
||||
|
||||
diffBuilder.record(3, 4);
|
||||
expect(diffBuilder.getMessage()).toEqual(message);
|
||||
});
|
||||
|
||||
it("allows customization of the message", function() {
|
||||
var diffBuilder = jasmineUnderTest.DiffBuilder();
|
||||
|
||||
function darthVaderFormatter(actual, expected, path) {
|
||||
return "I find your lack of " + expected + " disturbing. (was " + actual + ", at " + path + ")"
|
||||
}
|
||||
|
||||
diffBuilder.withPath('x', function() {
|
||||
diffBuilder.record('bar', 'foo', darthVaderFormatter);
|
||||
});
|
||||
|
||||
expect(diffBuilder.getMessage()).toEqual("I find your lack of foo disturbing. (was bar, at $.x)");
|
||||
});
|
||||
});
|
||||
13
spec/core/matchers/NullDiffBuilderSpec.js
Normal file
13
spec/core/matchers/NullDiffBuilderSpec.js
Normal file
@@ -0,0 +1,13 @@
|
||||
describe('NullDiffBuilder', function() {
|
||||
it('responds to withPath() by calling the passed function', function() {
|
||||
var spy = jasmine.createSpy('callback');
|
||||
jasmineUnderTest.NullDiffBuilder().withPath('does not matter', spy);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('responds to record()', function() {
|
||||
expect(function() {
|
||||
jasmineUnderTest.NullDiffBuilder().record('does not matter');
|
||||
}).not.toThrow();
|
||||
})
|
||||
});
|
||||
43
spec/core/matchers/ObjectPathSpec.js
Normal file
43
spec/core/matchers/ObjectPathSpec.js
Normal file
@@ -0,0 +1,43 @@
|
||||
describe('ObjectPath', function() {
|
||||
var ObjectPath = jasmineUnderTest.ObjectPath;
|
||||
|
||||
it('represents the path to a node in an object tree', function() {
|
||||
expect(new ObjectPath(['foo', 'bar']).toString()).toEqual('$.foo.bar');
|
||||
});
|
||||
|
||||
it('has a depth', function() {
|
||||
expect(new ObjectPath().depth()).toEqual(0);
|
||||
expect(new ObjectPath(['foo']).depth()).toEqual(1);
|
||||
});
|
||||
|
||||
it('renders numbers as array access', function() {
|
||||
expect(new ObjectPath(['foo', 0]).toString()).toEqual('$.foo[0]');
|
||||
});
|
||||
|
||||
it('renders properties that are valid identifiers with dot notation', function() {
|
||||
expect(new ObjectPath(['foo123']).toString()).toEqual('$.foo123');
|
||||
expect(new ObjectPath(['x_y']).toString()).toEqual('$.x_y');
|
||||
expect(new ObjectPath(['A$B']).toString()).toEqual('$.A$B');
|
||||
});
|
||||
|
||||
it('renders properties with non-identifier-safe characters with square bracket notation', function() {
|
||||
expect(new ObjectPath(['a b c']).toString()).toEqual("$['a b c']");
|
||||
expect(new ObjectPath(['1hello']).toString()).toEqual("$['1hello']");
|
||||
});
|
||||
|
||||
it('renders as the empty string when empty', function() {
|
||||
expect(new ObjectPath().toString()).toEqual('');
|
||||
});
|
||||
|
||||
it('stringifies properties that are not strings or numbers', function() {
|
||||
expect(new ObjectPath([{}]).toString()).toEqual("$['[object Object]']");
|
||||
});
|
||||
|
||||
it('can be created based on another path', function() {
|
||||
var root = new ObjectPath();
|
||||
var path = root.add('foo');
|
||||
|
||||
expect(path.toString()).toEqual('$.foo');
|
||||
expect(root.toString()).toEqual('');
|
||||
})
|
||||
});
|
||||
@@ -61,10 +61,14 @@ describe("matchersUtil", function() {
|
||||
expect(jasmineUnderTest.matchersUtil.equals(foo, [undefined])).toBe(true);
|
||||
});
|
||||
|
||||
it("fails for Arrays that are not equivalent", function() {
|
||||
it("fails for Arrays that have different lengths", function() {
|
||||
expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for Arrays that have different elements", function() {
|
||||
expect(jasmineUnderTest.matchersUtil.equals([1, 2, 3], [1, 5, 3])).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for Arrays whose contents are equivalent, but have differing properties", function() {
|
||||
var one = [1,2,3],
|
||||
two = [1,2,3];
|
||||
@@ -136,6 +140,13 @@ describe("matchersUtil", function() {
|
||||
expect(jasmineUnderTest.matchersUtil.equals(actual, expected)).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for Objects that have the same number of keys, but different keys/values", function () {
|
||||
var expected = { a: undefined },
|
||||
actual = { b: 1 };
|
||||
|
||||
expect(jasmineUnderTest.matchersUtil.equals(actual, expected)).toBe(false);
|
||||
})
|
||||
|
||||
it("fails when comparing an empty object to an empty array (issue #114)", function() {
|
||||
var emptyObject = {},
|
||||
emptyArray = [];
|
||||
@@ -327,6 +338,16 @@ describe("matchersUtil", function() {
|
||||
expect(jasmineUnderTest.matchersUtil.equals(true, asymmetricTester, [symmetricTester])).toBe(true);
|
||||
});
|
||||
|
||||
it("passes custom equality matchers to asymmetric equality testers", function() {
|
||||
var tester = function(a, b) {};
|
||||
var asymmetricTester = { asymmetricMatch: jasmine.createSpy('asymmetricMatch') };
|
||||
asymmetricTester.asymmetricMatch.and.returnValue(true);
|
||||
var other = {};
|
||||
|
||||
expect(jasmineUnderTest.matchersUtil.equals(asymmetricTester, other, [tester])).toBe(true);
|
||||
expect(asymmetricTester.asymmetricMatch).toHaveBeenCalledWith(other, [tester]);
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -357,6 +378,122 @@ describe("matchersUtil", function() {
|
||||
|
||||
expect(jasmineUnderTest.matchersUtil.equals(objA, objB)).toBe(false);
|
||||
});
|
||||
|
||||
it("passes when comparing two empty sets", function() {
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
expect(jasmineUnderTest.matchersUtil.equals(new Set(), new Set())).toBe(true);
|
||||
});
|
||||
|
||||
it("passes when comparing identical sets", function() {
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
var setA = new Set([6, 5]);
|
||||
var setB = new Set();
|
||||
setB.add(6);
|
||||
setB.add(5);
|
||||
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]);
|
||||
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]);
|
||||
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for sets with different insertion order", function() {
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
var setA = new Set([3, 6]);
|
||||
var setB = new Set([6, 3]);
|
||||
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false);
|
||||
});
|
||||
|
||||
it("passes when comparing two empty maps", function() {
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
expect(jasmineUnderTest.matchersUtil.equals(new Map(), new Map())).toBe(true);
|
||||
});
|
||||
|
||||
it("passes when comparing identical maps", function() {
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
var mapA = new Map([[6, 5]]);
|
||||
var mapB = new Map();
|
||||
mapB.set(6, 5);
|
||||
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]]);
|
||||
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]]);
|
||||
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
|
||||
});
|
||||
|
||||
it("fails for 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]]);
|
||||
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
|
||||
});
|
||||
|
||||
describe("when running in an environment with array polyfills", function() {
|
||||
// IE 8 doesn't support `definePropery` on non-DOM nodes
|
||||
if (jasmine.getEnv().ieVersion < 9) { return; }
|
||||
|
||||
var findIndexDescriptor = Object.getOwnPropertyDescriptor(Array.prototype, 'findIndex');
|
||||
if (!findIndexDescriptor) {
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(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 (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;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
value = list[i];
|
||||
if (predicate.call(thisArg, value, i, list)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
Object.defineProperty(Array.prototype, 'findIndex', findIndexDescriptor);
|
||||
});
|
||||
|
||||
it("passes when there's an array polyfill", function() {
|
||||
expect(['foo']).toEqual(['foo']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("contains", function() {
|
||||
|
||||
@@ -8,6 +8,9 @@ describe("toBeCloseTo", function() {
|
||||
|
||||
result = matcher.compare(0, 0.001);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.005);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it("fails when not within two decimal places by default", function() {
|
||||
@@ -16,6 +19,9 @@ describe("toBeCloseTo", function() {
|
||||
|
||||
result = matcher.compare(0, 0.01);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(0, 0.05);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts an optional precision argument", function() {
|
||||
@@ -25,8 +31,36 @@ describe("toBeCloseTo", function() {
|
||||
result = matcher.compare(0, 0.1, 0);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.5, 0);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.0001, 3);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.0005, 3);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.00001, 4);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(0, 0.00005, 4);
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it("fails when one of the arguments is null", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBeCloseTo();
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(null, null);
|
||||
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(null).');
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(0, null);
|
||||
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(0).toBeCloseTo(null).');
|
||||
|
||||
expect(function() {
|
||||
matcher.compare(null, 0);
|
||||
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(0).');
|
||||
});
|
||||
|
||||
it("rounds expected values", function() {
|
||||
@@ -42,7 +76,15 @@ describe("toBeCloseTo", function() {
|
||||
result = matcher.compare(1.23, 1.225);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
result = matcher.compare(1.23, 1.235);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
// 1.2249999 will be rounded to 1.225
|
||||
result = matcher.compare(1.23, 1.2249999);
|
||||
expect(result.pass).toBe(true);
|
||||
|
||||
// 1.2249999 will be rounded to 1.224
|
||||
result = matcher.compare(1.23, 1.2244999);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(1.23, 1.234);
|
||||
|
||||
31
spec/core/matchers/toBeNegativeInfinitySpec.js
Normal file
31
spec/core/matchers/toBeNegativeInfinitySpec.js
Normal file
@@ -0,0 +1,31 @@
|
||||
describe("toBeNegativeInfinity", function() {
|
||||
it("fails for anything that isn't -Infinity", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity(),
|
||||
result;
|
||||
|
||||
result = matcher.compare(1);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(Number.NaN);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(null);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it("has a custom message on failure", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity(),
|
||||
result = matcher.compare(0);
|
||||
|
||||
expect(result.message()).toEqual("Expected 0 not to be -Infinity.")
|
||||
});
|
||||
|
||||
it("succeeds for -Infinity", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBeNegativeInfinity(),
|
||||
result = matcher.compare(Number.NEGATIVE_INFINITY);
|
||||
|
||||
expect(result.pass).toBe(true);
|
||||
expect(result.message).toEqual("Expected actual to be -Infinity.")
|
||||
});
|
||||
|
||||
});
|
||||
31
spec/core/matchers/toBePositiveInfinitySpec.js
Normal file
31
spec/core/matchers/toBePositiveInfinitySpec.js
Normal file
@@ -0,0 +1,31 @@
|
||||
describe("toBePositiveInfinity", function() {
|
||||
it("fails for anything that isn't Infinity", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBePositiveInfinity(),
|
||||
result;
|
||||
|
||||
result = matcher.compare(1);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(Number.NaN);
|
||||
expect(result.pass).toBe(false);
|
||||
|
||||
result = matcher.compare(null);
|
||||
expect(result.pass).toBe(false);
|
||||
});
|
||||
|
||||
it("has a custom message on failure", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBePositiveInfinity(),
|
||||
result = matcher.compare(0);
|
||||
|
||||
expect(result.message()).toEqual("Expected 0 not to be Infinity.")
|
||||
});
|
||||
|
||||
it("succeeds for Infinity", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toBePositiveInfinity(),
|
||||
result = matcher.compare(Number.POSITIVE_INFINITY);
|
||||
|
||||
expect(result.pass).toBe(true);
|
||||
expect(result.message).toEqual("Expected actual to be Infinity.")
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,20 +1,39 @@
|
||||
describe("toEqual", function() {
|
||||
"use strict";
|
||||
|
||||
function compareEquals(actual, expected) {
|
||||
var util = jasmineUnderTest.matchersUtil,
|
||||
matcher = jasmineUnderTest.matchers.toEqual(util);
|
||||
|
||||
var result = matcher.compare(actual, expected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
it("delegates to equals function", function() {
|
||||
var util = {
|
||||
equals: jasmine.createSpy('delegated-equals').and.returnValue(true)
|
||||
equals: jasmine.createSpy('delegated-equals').and.returnValue(true),
|
||||
buildFailureMessage: function() {
|
||||
return 'does not matter'
|
||||
},
|
||||
DiffBuilder: jasmineUnderTest.matchersUtil.DiffBuilder
|
||||
},
|
||||
matcher = jasmineUnderTest.matchers.toEqual(util),
|
||||
result;
|
||||
|
||||
result = matcher.compare(1, 1);
|
||||
|
||||
expect(util.equals).toHaveBeenCalledWith(1, 1, []);
|
||||
expect(util.equals).toHaveBeenCalledWith(1, 1, [], jasmine.anything());
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it("delegates custom equality testers, if present", function() {
|
||||
var util = {
|
||||
equals: jasmine.createSpy('delegated-equals').and.returnValue(true)
|
||||
equals: jasmine.createSpy('delegated-equals').and.returnValue(true),
|
||||
buildFailureMessage: function() {
|
||||
return 'does not matter'
|
||||
},
|
||||
DiffBuilder: jasmineUnderTest.matchersUtil.DiffBuilder
|
||||
},
|
||||
customEqualityTesters = ['a', 'b'],
|
||||
matcher = jasmineUnderTest.matchers.toEqual(util, customEqualityTesters),
|
||||
@@ -22,7 +41,507 @@ describe("toEqual", function() {
|
||||
|
||||
result = matcher.compare(1, 1);
|
||||
|
||||
expect(util.equals).toHaveBeenCalledWith(1, 1, ['a', 'b']);
|
||||
expect(util.equals).toHaveBeenCalledWith(1, 1, ['a', 'b'], jasmine.anything());
|
||||
expect(result.pass).toBe(true);
|
||||
});
|
||||
|
||||
it("reports the difference between objects that are not equal", function() {
|
||||
var actual = {x: 1, y: 3},
|
||||
expected = {x: 2, y: 3},
|
||||
message = "Expected $.x = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports the difference between nested objects that are not equal", function() {
|
||||
var actual = {x: {y: 1}},
|
||||
expected = {x: {y: 2}},
|
||||
message = "Expected $.x.y = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("formats property access so that it's valid JavaScript", function() {
|
||||
var actual = {'my prop': 1},
|
||||
expected = {'my prop': 2},
|
||||
message = "Expected $['my prop'] = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports missing properties", function() {
|
||||
var actual = {x: {}},
|
||||
expected = {x: {y: 1}},
|
||||
message =
|
||||
"Expected $.x to have properties\n" +
|
||||
" y: 1";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports extra properties", function() {
|
||||
var actual = {x: {y: 1, z: 2}},
|
||||
expected = {x: {}},
|
||||
message =
|
||||
"Expected $.x not to have properties\n" +
|
||||
" y: 1\n" +
|
||||
" z: 2";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("pretty-prints properties", function() {
|
||||
var actual = {x: {y: 'foo bar'}},
|
||||
expected = {x: {}},
|
||||
message =
|
||||
"Expected $.x not to have properties\n" +
|
||||
" y: 'foo bar'"
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports extra and missing properties together", function() {
|
||||
var actual = {x: {y: 1, z: 2, f: 4}},
|
||||
expected = {x: {y: 1, z: 2, g: 3}},
|
||||
message =
|
||||
"Expected $.x to have properties\n" +
|
||||
" g: 3\n" +
|
||||
"Expected $.x not to have properties\n" +
|
||||
" f: 4";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports extra and missing properties of the root-level object", function() {
|
||||
var actual = {x: 1},
|
||||
expected = {a: 1},
|
||||
message =
|
||||
"Expected object to have properties\n" +
|
||||
" a: 1\n" +
|
||||
"Expected object not to have properties\n" +
|
||||
" x: 1";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports multiple incorrect values", function() {
|
||||
var actual = {x: 1, y: 2},
|
||||
expected = {x: 3, y: 4},
|
||||
message =
|
||||
"Expected $.x = 1 to equal 3.\n" +
|
||||
"Expected $.y = 2 to equal 4.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatch between actual child object and expected child number", function() {
|
||||
var actual = {x: {y: 2}},
|
||||
expected = {x: 1},
|
||||
message = "Expected $.x = Object({ y: 2 }) to equal 1.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("uses the default failure message if actual is not an object", function() {
|
||||
var actual = 1,
|
||||
expected = {x: {}},
|
||||
message = "Expected 1 to equal Object({ x: Object({ }) }).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("uses the default failure message if expected is not an object", function() {
|
||||
var actual = {x: {}},
|
||||
expected = 1,
|
||||
message = "Expected Object({ x: Object({ }) }) to equal 1.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("uses the default failure message given arrays with different lengths", function() {
|
||||
var actual = [1, 2],
|
||||
expected = [1, 2, 3],
|
||||
message =
|
||||
"Expected [ 1, 2 ] to equal [ 1, 2, 3 ].";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports a mismatch between elements of equal-length arrays", function() {
|
||||
var actual = [1, 2, 5],
|
||||
expected = [1, 2, 3],
|
||||
message = "Expected $[2] = 5 to equal 3.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports a mismatch between multiple array elements", function() {
|
||||
var actual = [2, 2, 5],
|
||||
expected = [1, 2, 3],
|
||||
message =
|
||||
"Expected $[0] = 2 to equal 1.\n" +
|
||||
"Expected $[2] = 5 to equal 3.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports a mismatch between properties of objects in arrays", function() {
|
||||
var actual = [{x: 1}],
|
||||
expected = [{x: 2}],
|
||||
message = "Expected $[0].x = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports a mismatch between arrays in objects", function() {
|
||||
var actual = {x: [1]},
|
||||
expected = {x: [2]},
|
||||
message =
|
||||
"Expected $.x[0] = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between nested arrays", function() {
|
||||
var actual = [[1]],
|
||||
expected = [[2]],
|
||||
message =
|
||||
"Expected $[0][0] = 1 to equal 2.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving NaN", function() {
|
||||
var actual = {x: 0},
|
||||
expected = {x: 0/0},
|
||||
message = "Expected $.x = 0 to equal NaN.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving regular expressions", function() {
|
||||
var actual = {x: '1'},
|
||||
expected = {x: /1/},
|
||||
message = "Expected $.x = '1' to equal /1/.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving infinities", function() {
|
||||
var actual = {x: 0},
|
||||
expected = {x: 1/0},
|
||||
message = "Expected $.x = 0 to equal Infinity.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving booleans", function() {
|
||||
var actual = {x: false},
|
||||
expected = {x: true},
|
||||
message = "Expected $.x = false to equal true.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving strings", function() {
|
||||
var actual = {x: 'foo'},
|
||||
expected = {x: 'bar'},
|
||||
message = "Expected $.x = 'foo' to equal 'bar'.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving undefined", function() {
|
||||
var actual = {x: void 0},
|
||||
expected = {x: 0},
|
||||
message = "Expected $.x = undefined to equal 0.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches involving null", function() {
|
||||
var actual = {x: null},
|
||||
expected = {x: 0},
|
||||
message = "Expected $.x = null to equal 0.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between objects with different constructors", function () {
|
||||
function Foo() {}
|
||||
function Bar() {}
|
||||
|
||||
var actual = {x: new Foo()},
|
||||
expected = {x: new Bar()},
|
||||
message = "Expected $.x to be a kind of Bar, but was Foo({ }).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports type mismatches at the root level", function () {
|
||||
function Foo() {}
|
||||
function Bar() {}
|
||||
|
||||
var actual = new Foo(),
|
||||
expected = new Bar(),
|
||||
message = "Expected object to be a kind of Bar, but was Foo({ }).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
function constructorIsNotEnumerable() {
|
||||
// in IE8, the constructor property is not enumerable, even if it is an
|
||||
// own property of the object.
|
||||
// Objects that differ only by an own `constructor` property are thus
|
||||
// considered equal in IE8.
|
||||
for (var key in {constructor: 1}) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
it("reports mismatches between objects with their own constructor property", function () {
|
||||
if (constructorIsNotEnumerable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
function Foo() {}
|
||||
function Bar() {}
|
||||
|
||||
var actual = {x: {constructor: 'blerf'}},
|
||||
expected = {x: {constructor: 'ftarrh'}},
|
||||
message = "Expected $.x.constructor = 'blerf' to equal 'ftarrh'.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between an object with a real constructor and one with its own constructor property", function () {
|
||||
if (constructorIsNotEnumerable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
function Foo() {}
|
||||
function Bar() {}
|
||||
|
||||
var actual = {x: {}},
|
||||
expected = {x: {constructor: 'ftarrh'}},
|
||||
message =
|
||||
"Expected $.x to have properties\n" +
|
||||
" constructor: 'ftarrh'";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
expect(compareEquals(expected, actual).message).toEqual(
|
||||
"Expected $.x not to have properties\n constructor: 'ftarrh'"
|
||||
);
|
||||
});
|
||||
|
||||
it("reports mismatches between 0 and -0", function() {
|
||||
var actual = {x: 0},
|
||||
expected = {x: -0},
|
||||
message = "Expected $.x = 0 to equal -0.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between Errors", function() {
|
||||
var actual = {x: new Error("the error you got")},
|
||||
expected = {x: new Error("the error you want")},
|
||||
message = "Expected $.x = Error: the error you got to equal Error: the error you want.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between Functions", function() {
|
||||
var actual = {x: function() {}},
|
||||
expected = {x: function() {}},
|
||||
message = "Expected $.x = Function to equal Function.";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("does not report deep mismatches within Sets", function() {
|
||||
// TODO: implement deep comparison of set elements
|
||||
jasmine.getEnv().requireFunctioningSets();
|
||||
|
||||
var actual = new Set([1]),
|
||||
expected = new Set([2]),
|
||||
message = 'Expected Set( 1 ) to equal Set( 2 ).';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
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 ).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
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 ).';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("does not report deep mismatches within Maps", function() {
|
||||
// TODO: implement deep comparison of Map elements
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
|
||||
var actual = new Map([['a', 1]]),
|
||||
expected = new Map([['a', 2]]),
|
||||
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
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], ['b', 1]])]},
|
||||
message = "Expected $.Maps[0] = Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ], [ 'b', 1 ] ).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports mismatches between Maps of different lengths", function() {
|
||||
jasmine.getEnv().requireFunctioningMaps();
|
||||
|
||||
var actual = new Map([['a', 1]]),
|
||||
expected = new Map([['a', 2]]),
|
||||
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
function isNotRunningInBrowser() {
|
||||
return typeof document === 'undefined'
|
||||
}
|
||||
|
||||
it("reports mismatches between DOM nodes with different tags", function() {
|
||||
if(isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actual = {a: document.createElement('div')},
|
||||
expected = {a: document.createElement('p')},
|
||||
message = 'Expected $.a = HTMLNode to equal HTMLNode.';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it('reports mismatches between DOM nodes with different content', function() {
|
||||
if(isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeA = document.createElement('div'),
|
||||
nodeB = document.createElement('div');
|
||||
|
||||
nodeA.innerText = 'foo'
|
||||
nodeB.innerText = 'bar'
|
||||
|
||||
var actual = {a: nodeA},
|
||||
expected = {a: nodeB},
|
||||
message = 'Expected $.a = HTMLNode to equal HTMLNode.';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
})
|
||||
|
||||
it("reports mismatches between a DOM node and a bare Object", function() {
|
||||
if(isNotRunningInBrowser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actual = {a: document.createElement('div')},
|
||||
expected = {a: {}},
|
||||
message = 'Expected $.a = HTMLNode to equal Object({ }).';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
});
|
||||
|
||||
it("reports asymmetric mismatches", function() {
|
||||
var actual = {a: 1},
|
||||
expected = {a: jasmineUnderTest.any(String)},
|
||||
message = 'Expected $.a = 1 to equal <jasmine.any(String)>.';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
expect(compareEquals(actual, expected).pass).toBe(false)
|
||||
});
|
||||
|
||||
it("reports asymmetric mismatches when the asymmetric comparand is the actual value", function() {
|
||||
var actual = {a: jasmineUnderTest.any(String)},
|
||||
expected = {a: 1},
|
||||
message = 'Expected $.a = <jasmine.any(String)> to equal 1.';
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
expect(compareEquals(actual, expected).pass).toBe(false)
|
||||
});
|
||||
|
||||
it("does not report a mismatch when asymmetric matchers are satisfied", function() {
|
||||
var actual = {a: 'a'},
|
||||
expected = {a: jasmineUnderTest.any(String)},
|
||||
message = 'Expected $.a = 1 to equal <jasmine.any(String)>.';
|
||||
|
||||
expect(compareEquals(actual, expected).pass).toBe(true)
|
||||
});
|
||||
|
||||
it("works on big complex stuff", function() {
|
||||
var actual = {
|
||||
foo: [
|
||||
{bar: 1, things: ['a', 'b']},
|
||||
{bar: 2, things: ['a', 'b']}
|
||||
],
|
||||
baz: [
|
||||
{a: {b: 1}}
|
||||
],
|
||||
quux: 1,
|
||||
nan: 0,
|
||||
aRegexp: 'hi',
|
||||
inf: -1/0,
|
||||
boolean: false,
|
||||
notDefined: 0,
|
||||
aNull: void 0
|
||||
}
|
||||
|
||||
var expected = {
|
||||
foo: [
|
||||
{bar: 2, things: ['a', 'b', 'c']},
|
||||
{bar: 2, things: ['a', 'd']}
|
||||
],
|
||||
baz: [
|
||||
{a: {b: 1, c: 1}}
|
||||
],
|
||||
quux: [],
|
||||
nan: 0/0,
|
||||
aRegexp: /hi/,
|
||||
inf: 1/0,
|
||||
boolean: true,
|
||||
notDefined: void 0,
|
||||
aNull: null
|
||||
}
|
||||
|
||||
var message =
|
||||
'Expected $.foo[0].bar = 1 to equal 2.\n' +
|
||||
"Expected $.foo[0].things = [ 'a', 'b' ] to equal [ 'a', 'b', 'c' ].\n" +
|
||||
"Expected $.foo[1].things[1] = 'b' to equal 'd'.\n" +
|
||||
'Expected $.baz[0].a to have properties\n' +
|
||||
' c: 1\n' +
|
||||
'Expected $.quux = 1 to equal [ ].\n' +
|
||||
'Expected $.nan = 0 to equal NaN.\n' +
|
||||
"Expected $.aRegexp = 'hi' to equal /hi/.\n" +
|
||||
'Expected $.inf = -Infinity to equal Infinity.\n' +
|
||||
'Expected $.boolean = false to equal true.\n' +
|
||||
'Expected $.notDefined = 0 to equal undefined.\n' +
|
||||
'Expected $.aNull = undefined to equal null.'
|
||||
|
||||
expect(compareEquals(actual, expected).message).toEqual(message);
|
||||
})
|
||||
});
|
||||
|
||||
99
spec/core/matchers/toHaveBeenCalledBeforeSpec.js
Normal file
99
spec/core/matchers/toHaveBeenCalledBeforeSpec.js
Normal file
@@ -0,0 +1,99 @@
|
||||
describe("toHaveBeenCalledBefore", function() {
|
||||
it("throws an exception when the actual is not a spy", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
fn = function() {},
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy');
|
||||
|
||||
expect(function() { matcher.compare(fn, secondSpy) }).toThrowError(Error, /Expected a spy, but got Function./);
|
||||
});
|
||||
|
||||
it("throws an exception when the expected is not a spy", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
fn = function() {};
|
||||
|
||||
expect(function() { matcher.compare(firstSpy, fn) }).toThrowError(Error, /Expected a spy, but got Function./);
|
||||
});
|
||||
|
||||
it("fails when the actual was not called", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy');
|
||||
|
||||
secondSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toMatch(/Expected spy first spy to have been called./);
|
||||
});
|
||||
|
||||
it("fails when the expected was not called", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy');
|
||||
|
||||
firstSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toMatch(/Expected spy second spy to have been called./);
|
||||
});
|
||||
|
||||
it("fails when the actual is called after the expected", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy'),
|
||||
result;
|
||||
|
||||
secondSpy();
|
||||
firstSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toEqual('Expected spy first spy to have been called before spy second spy');
|
||||
});
|
||||
|
||||
it("fails when the actual is called before and after the expected", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy'),
|
||||
result;
|
||||
|
||||
firstSpy();
|
||||
secondSpy();
|
||||
firstSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toEqual('Expected latest call to spy first spy to have been called before first call to spy second spy (no interleaved calls)');
|
||||
});
|
||||
|
||||
it("fails when the expected is called before and after the actual", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy'),
|
||||
result;
|
||||
|
||||
secondSpy();
|
||||
firstSpy();
|
||||
secondSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(false);
|
||||
expect(result.message).toEqual('Expected first call to spy second spy to have been called after latest call to spy first spy (no interleaved calls)');
|
||||
});
|
||||
|
||||
it("passes when the actual is called before the expected", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toHaveBeenCalledBefore(),
|
||||
firstSpy = jasmineUnderTest.createSpy('first spy'),
|
||||
secondSpy = jasmineUnderTest.createSpy('second spy'),
|
||||
result;
|
||||
|
||||
firstSpy();
|
||||
secondSpy();
|
||||
|
||||
result = matcher.compare(firstSpy, secondSpy);
|
||||
expect(result.pass).toBe(true);
|
||||
expect(result.message).toEqual('Expected spy first spy to not have been called before spy second spy, but it was');
|
||||
});
|
||||
});
|
||||
@@ -65,6 +65,43 @@ describe("toThrowError", function() {
|
||||
expect(result.message()).toEqual("Expected function to throw an Error, but it threw 4.");
|
||||
});
|
||||
|
||||
describe("when error is from another frame", function() {
|
||||
function isNotRunningInBrowser() {
|
||||
return typeof document === 'undefined'
|
||||
}
|
||||
|
||||
var iframe = null;
|
||||
|
||||
afterEach(function() {
|
||||
if (iframe !== null) {
|
||||
document.body.removeChild(iframe);
|
||||
}
|
||||
});
|
||||
|
||||
it("passes if thrown is an instanceof Error regardless of global that contains its constructor", function() {
|
||||
if (isNotRunningInBrowser() || jasmine.getEnv().phantomVersion < 2 || jasmine.getEnv().ieVersion < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
var matcher = jasmineUnderTest.matchers.toThrowError();
|
||||
iframe = document.body.appendChild(document.createElement("iframe"));
|
||||
iframe.src = "about:blank";
|
||||
var iframeDocument = iframe.contentWindow.document;
|
||||
|
||||
if (iframeDocument.body) {
|
||||
iframeDocument.body.appendChild(iframeDocument.createElement("script"))
|
||||
.textContent = "function method() { throw new Error('foo'); }";
|
||||
} else {
|
||||
// older IE
|
||||
iframeDocument.write("<html><head><script>function method() { throw new Error('foo'); }</script></head></html>");
|
||||
}
|
||||
|
||||
var result = matcher.compare(iframe.contentWindow.method);
|
||||
expect(result.pass).toBe(true);
|
||||
expect(result.message).toEqual("Expected function not to throw an Error, but it threw Error.");
|
||||
});
|
||||
});
|
||||
|
||||
it("fails with the correct message if thrown is a falsy value", function() {
|
||||
var matcher = jasmineUnderTest.matchers.toThrowError(),
|
||||
fn = function() {
|
||||
|
||||
@@ -20,4 +20,8 @@
|
||||
return /Firefox\/([0-9]{0,})/.exec(userAgent);
|
||||
});
|
||||
|
||||
env.phantomVersion = browserVersion(function(userAgent) {
|
||||
return /PhantomJS\/([0-9]{0,})/.exec(userAgent);
|
||||
});
|
||||
|
||||
})(jasmine.getEnv());
|
||||
|
||||
27
spec/helpers/asyncAwait.js
Normal file
27
spec/helpers/asyncAwait.js
Normal file
@@ -0,0 +1,27 @@
|
||||
(function(env) {
|
||||
function getAsyncCtor() {
|
||||
try {
|
||||
eval("var func = async function(){};");
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.getPrototypeOf(func).constructor;
|
||||
}
|
||||
|
||||
function hasAsyncAwaitSupport() {
|
||||
return getAsyncCtor() !== null;
|
||||
}
|
||||
|
||||
env.makeAsyncAwaitFunction = function() {
|
||||
var AsyncFunction = getAsyncCtor();
|
||||
return new AsyncFunction("");
|
||||
};
|
||||
|
||||
env.requireAsyncAwait = function() {
|
||||
if (!hasAsyncAwaitSupport()) {
|
||||
env.pending("Environment does not support async/await functions");
|
||||
}
|
||||
};
|
||||
})(jasmine.getEnv());
|
||||
|
||||
22
spec/helpers/checkForMap.js
Normal file
22
spec/helpers/checkForMap.js
Normal file
@@ -0,0 +1,22 @@
|
||||
(function(env) {
|
||||
function hasFunctioningMaps() {
|
||||
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; }
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
env.requireFunctioningMaps = function() {
|
||||
if (!hasFunctioningMaps()) {
|
||||
env.pending("Browser has incomplete or missing support for Maps");
|
||||
}
|
||||
};
|
||||
|
||||
})(jasmine.getEnv());
|
||||
21
spec/helpers/checkForSet.js
Normal file
21
spec/helpers/checkForSet.js
Normal file
@@ -0,0 +1,21 @@
|
||||
(function(env) {
|
||||
function hasFunctioningSets() {
|
||||
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; }
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
env.requireFunctioningSets = function() {
|
||||
if (!hasFunctioningSets()) {
|
||||
env.pending("Browser has incomplete or missing support for Sets");
|
||||
}
|
||||
};
|
||||
|
||||
})(jasmine.getEnv());
|
||||
@@ -691,14 +691,15 @@ describe("New HtmlReporter", function() {
|
||||
expect(seedBar).toBeNull();
|
||||
});
|
||||
|
||||
it("should include the random query param in the jasmine-skipped link when randomizing", function(){
|
||||
it("should include non-spec query params in the jasmine-skipped link when present", function(){
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
container = document.createElement("div"),
|
||||
reporter = new jasmineUnderTest.HtmlReporter({
|
||||
env: env,
|
||||
getContainer: function() { return container; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
addToExistingQueryString: function(key, value) { return "?foo=bar&" + key + "=" + value; }
|
||||
});
|
||||
|
||||
reporter.initialize();
|
||||
@@ -706,25 +707,7 @@ describe("New HtmlReporter", function() {
|
||||
reporter.jasmineDone({ order: { random: true } });
|
||||
|
||||
var skippedLink = container.querySelector(".jasmine-skipped a");
|
||||
expect(skippedLink.getAttribute('href')).toEqual('?random=true');
|
||||
});
|
||||
|
||||
it("should not include the random query param in the jasmine-skipped link when not randomizing", function(){
|
||||
var env = new jasmineUnderTest.Env(),
|
||||
container = document.createElement("div"),
|
||||
reporter = new jasmineUnderTest.HtmlReporter({
|
||||
env: env,
|
||||
getContainer: function() { return container; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
|
||||
});
|
||||
|
||||
reporter.initialize();
|
||||
reporter.jasmineStarted({ totalSpecsDefined: 1 });
|
||||
reporter.jasmineDone();
|
||||
|
||||
var skippedLink = container.querySelector(".jasmine-skipped a");
|
||||
expect(skippedLink.getAttribute('href')).toEqual('?');
|
||||
expect(skippedLink.getAttribute('href')).toEqual('?foo=bar&spec=');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -804,6 +787,64 @@ describe("New HtmlReporter", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there are disabled specs", function() {
|
||||
var env, container, reporter, reporterConfig, specStatus;
|
||||
beforeEach(function() {
|
||||
env = new jasmineUnderTest.Env();
|
||||
container = document.createElement("div");
|
||||
reporterConfig = {
|
||||
env: env,
|
||||
getContainer: function() { return container; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
|
||||
};
|
||||
specStatus = {
|
||||
id: 123,
|
||||
description: "with a disabled spec",
|
||||
fullName: "A Suite with a disabled spec",
|
||||
status: "disabled",
|
||||
passedExpectations: [],
|
||||
failedExpectations: []
|
||||
};
|
||||
});
|
||||
|
||||
describe("when the specs are not filtered", function() {
|
||||
beforeEach(function() {
|
||||
reporterConfig.filterSpecs = false;
|
||||
reporter = new jasmineUnderTest.HtmlReporter(reporterConfig);
|
||||
reporter.initialize();
|
||||
reporter.jasmineStarted({ totalSpecsDefined: 1 });
|
||||
reporter.specStarted(specStatus);
|
||||
reporter.specDone(specStatus);
|
||||
reporter.jasmineDone({});
|
||||
});
|
||||
|
||||
it("shows the disabled spec in the spec list", function() {
|
||||
var specList = container.querySelector(".jasmine-summary");
|
||||
|
||||
expect(specList.innerHTML).toContain('with a disabled spec');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the specs are filtered", function() {
|
||||
beforeEach(function() {
|
||||
reporterConfig.filterSpecs = true;
|
||||
reporter = new jasmineUnderTest.HtmlReporter(reporterConfig);
|
||||
reporter.initialize();
|
||||
reporter.jasmineStarted({ totalSpecsDefined: 1 });
|
||||
reporter.specStarted(specStatus);
|
||||
reporter.specDone(specStatus);
|
||||
reporter.jasmineDone({});
|
||||
});
|
||||
|
||||
it("doesn't show the disabled spec in the spec list", function() {
|
||||
var specList = container.querySelector(".jasmine-summary");
|
||||
|
||||
expect(specList.innerHTML).toEqual('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there are pending specs", function() {
|
||||
var env, container, reporter;
|
||||
beforeEach(function() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use_sauce: <%= ENV['USE_SAUCE'] %>
|
||||
browser: <%= ENV['JASMINE_BROWSER'] %>
|
||||
sauce:
|
||||
sauce_connect_path: "/Users/gregg/Downloads/sc-4.3.11-osx/bin/sc"
|
||||
sauce_connect_path: <%= ENV['SAUCE_CONNECT_PATH'].inspect %>
|
||||
name: jasmine-core <%= Time.now.to_s %>
|
||||
username: <%= ENV['SAUCE_USERNAME'] %>
|
||||
access_key: <%= ENV['SAUCE_ACCESS_KEY'] %>
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('npm package', function() {
|
||||
}
|
||||
};
|
||||
|
||||
fs.unlink(this.tarball);
|
||||
fs.unlinkSync(this.tarball);
|
||||
});
|
||||
|
||||
it('has a root path', function() {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
"npmPackage/**/*.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/asyncAwait.js",
|
||||
"helpers/checkForSet.js",
|
||||
"helpers/checkForMap.js",
|
||||
"helpers/nodeDefineJasmineUnderTest.js"
|
||||
],
|
||||
"random": true
|
||||
|
||||
@@ -16,11 +16,15 @@ src_files:
|
||||
- '**/*.js'
|
||||
stylesheets:
|
||||
helpers:
|
||||
- 'helpers/asyncAwait.js'
|
||||
- 'helpers/BrowserFlags.js'
|
||||
- 'helpers/checkForSet.js'
|
||||
- 'helpers/checkForMap.js'
|
||||
- 'helpers/defineJasmineUnderTest.js'
|
||||
spec_files:
|
||||
- '**/*[Ss]pec.js'
|
||||
- '!npmPackage/**/*'
|
||||
spec_dir: spec
|
||||
random: true
|
||||
spec_helper: spec/support/jasmine_helper.rb
|
||||
|
||||
|
||||
3
spec/support/jasmine_helper.rb
Normal file
3
spec/support/jasmine_helper.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
Jasmine.configure do |config|
|
||||
config.prevent_phantom_js_auto_install = true
|
||||
end
|
||||
@@ -1,5 +1,8 @@
|
||||
getJasmineRequireObj().CallTracker = function(j$) {
|
||||
|
||||
/**
|
||||
* @namespace Spy#calls
|
||||
*/
|
||||
function CallTracker() {
|
||||
var calls = [];
|
||||
var opts = {};
|
||||
@@ -24,23 +27,54 @@ getJasmineRequireObj().CallTracker = function(j$) {
|
||||
calls.push(context);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether this spy has been invoked.
|
||||
* @name Spy#calls#any
|
||||
* @function
|
||||
* @return {Boolean}
|
||||
*/
|
||||
this.any = function() {
|
||||
return !!calls.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of invocations of this spy.
|
||||
* @name Spy#calls#count
|
||||
* @function
|
||||
* @return {Integer}
|
||||
*/
|
||||
this.count = function() {
|
||||
return calls.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the arguments that were passed to a specific invocation of this spy.
|
||||
* @name Spy#calls#argsFor
|
||||
* @function
|
||||
* @param {Integer} index The 0-based invocation index.
|
||||
* @return {Array}
|
||||
*/
|
||||
this.argsFor = function(index) {
|
||||
var call = calls[index];
|
||||
return call ? call.args : [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the raw calls array for this spy.
|
||||
* @name Spy#calls#all
|
||||
* @function
|
||||
* @return {Spy.callData[]}
|
||||
*/
|
||||
this.all = function() {
|
||||
return calls;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all of the arguments for each invocation of this spy in the order they were received.
|
||||
* @name Spy#calls#allArgs
|
||||
* @function
|
||||
* @return {Array}
|
||||
*/
|
||||
this.allArgs = function() {
|
||||
var callArgs = [];
|
||||
for(var i = 0; i < calls.length; i++){
|
||||
@@ -50,18 +84,40 @@ getJasmineRequireObj().CallTracker = function(j$) {
|
||||
return callArgs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the first invocation of this spy.
|
||||
* @name Spy#calls#first
|
||||
* @function
|
||||
* @return {ObjecSpy.callData}
|
||||
*/
|
||||
this.first = function() {
|
||||
return calls[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the most recent invocation of this spy.
|
||||
* @name Spy#calls#mostRecent
|
||||
* @function
|
||||
* @return {ObjecSpy.callData}
|
||||
*/
|
||||
this.mostRecent = function() {
|
||||
return calls[calls.length - 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset this spy as if it has never been called.
|
||||
* @name Spy#calls#reset
|
||||
* @function
|
||||
*/
|
||||
this.reset = function() {
|
||||
calls = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set this spy to do a shallow clone of arguments passed to each invocation.
|
||||
* @name Spy#calls#saveArgumentsByValue
|
||||
* @function
|
||||
*/
|
||||
this.saveArgumentsByValue = function() {
|
||||
opts.cloneArgs = true;
|
||||
};
|
||||
|
||||
69
src/core/ClearStack.js
Normal file
69
src/core/ClearStack.js
Normal file
@@ -0,0 +1,69 @@
|
||||
getJasmineRequireObj().clearStack = function(j$) {
|
||||
var maxInlineCallCount = 10;
|
||||
|
||||
function messageChannelImpl(global, setTimeout) {
|
||||
var channel = new global.MessageChannel(),
|
||||
head = {},
|
||||
tail = head;
|
||||
|
||||
var taskRunning = false;
|
||||
channel.port1.onmessage = function() {
|
||||
head = head.next;
|
||||
var task = head.task;
|
||||
delete head.task;
|
||||
|
||||
if (taskRunning) {
|
||||
global.setTimeout(task, 0);
|
||||
} else {
|
||||
try {
|
||||
taskRunning = true;
|
||||
task();
|
||||
} finally {
|
||||
taskRunning = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var currentCallCount = 0;
|
||||
return function clearStack(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
tail = tail.next = { task: fn };
|
||||
channel.port2.postMessage(0);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
setTimeout(fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getClearStack(global) {
|
||||
var currentCallCount = 0;
|
||||
var realSetTimeout = global.setTimeout;
|
||||
var setTimeoutImpl = function clearStack(fn) {
|
||||
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
|
||||
};
|
||||
|
||||
if (j$.isFunction_(global.setImmediate)) {
|
||||
var realSetImmediate = global.setImmediate;
|
||||
return function(fn) {
|
||||
currentCallCount++;
|
||||
|
||||
if (currentCallCount < maxInlineCallCount) {
|
||||
realSetImmediate(fn);
|
||||
} else {
|
||||
currentCallCount = 0;
|
||||
|
||||
setTimeoutImpl(fn);
|
||||
}
|
||||
};
|
||||
} else if (!j$.util.isUndefined(global.MessageChannel)) {
|
||||
return messageChannelImpl(global, setTimeoutImpl);
|
||||
} else {
|
||||
return setTimeoutImpl;
|
||||
}
|
||||
}
|
||||
|
||||
return getClearStack;
|
||||
};
|
||||
@@ -1,4 +1,9 @@
|
||||
getJasmineRequireObj().Clock = function() {
|
||||
/**
|
||||
* _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
|
||||
* @class Clock
|
||||
* @classdesc Jasmine's mock clock is used when testing time dependent code.
|
||||
*/
|
||||
function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
|
||||
var self = this,
|
||||
realTimingFunctions = {
|
||||
@@ -18,6 +23,12 @@ getJasmineRequireObj().Clock = function() {
|
||||
timer;
|
||||
|
||||
|
||||
/**
|
||||
* Install the mock clock over the built-in methods.
|
||||
* @name Clock#install
|
||||
* @function
|
||||
* @return {Clock}
|
||||
*/
|
||||
self.install = function() {
|
||||
if(!originalTimingFunctionsIntact()) {
|
||||
throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
|
||||
@@ -30,6 +41,11 @@ getJasmineRequireObj().Clock = function() {
|
||||
return self;
|
||||
};
|
||||
|
||||
/**
|
||||
* Uninstall the mock clock, returning the built-in methods to their places.
|
||||
* @name Clock#uninstall
|
||||
* @function
|
||||
*/
|
||||
self.uninstall = function() {
|
||||
delayedFunctionScheduler = null;
|
||||
mockDate.uninstall();
|
||||
@@ -39,6 +55,14 @@ getJasmineRequireObj().Clock = function() {
|
||||
installed = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a function with a mocked Clock
|
||||
*
|
||||
* The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
|
||||
* @name Clock#withMock
|
||||
* @function
|
||||
* @param {closure} Function The function to be called.
|
||||
*/
|
||||
self.withMock = function(closure) {
|
||||
this.install();
|
||||
try {
|
||||
@@ -48,6 +72,12 @@ getJasmineRequireObj().Clock = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instruct the installed Clock to also mock the date returned by `new Date()`
|
||||
* @name Clock#mockDate
|
||||
* @function
|
||||
* @param {Date} [initialDate=now] The `Date` to provide.
|
||||
*/
|
||||
self.mockDate = function(initialDate) {
|
||||
mockDate.install(initialDate);
|
||||
};
|
||||
@@ -80,6 +110,12 @@ getJasmineRequireObj().Clock = function() {
|
||||
return Function.prototype.call.apply(timer.clearInterval, [global, id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tick the Clock forward, running any enqueued timeouts along the way
|
||||
* @name Clock#tick
|
||||
* @function
|
||||
* @param {int} millis The number of milliseconds to tick.
|
||||
*/
|
||||
self.tick = function(millis) {
|
||||
if (installed) {
|
||||
delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
|
||||
|
||||
@@ -116,7 +116,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
||||
function runScheduledFunctions(endTime, tickDate) {
|
||||
tickDate = tickDate || function() {};
|
||||
if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
|
||||
tickDate(endTime);
|
||||
tickDate(endTime - currentTime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,11 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
|
||||
// scheduled in a funcToRun from forcing an extra iteration
|
||||
currentTime !== endTime &&
|
||||
scheduledLookup[0] <= endTime);
|
||||
|
||||
// ran out of functions to call, but still time left on the clock
|
||||
if (currentTime !== endTime) {
|
||||
tickDate(endTime - currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
getJasmineRequireObj().Env = function(j$) {
|
||||
/**
|
||||
* _Note:_ Do not construct this directly, Jasmine will make one during booting.
|
||||
* @name Env
|
||||
* @classdesc The Jasmine environment
|
||||
* @constructor
|
||||
*/
|
||||
function Env(options) {
|
||||
options = options || {};
|
||||
|
||||
@@ -11,6 +17,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
var realSetTimeout = j$.getGlobal().setTimeout;
|
||||
var realClearTimeout = j$.getGlobal().clearTimeout;
|
||||
var clearStack = j$.getClearStack(j$.getGlobal());
|
||||
this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
|
||||
|
||||
var runnableResources = {};
|
||||
@@ -39,6 +46,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
'specDone'
|
||||
]);
|
||||
|
||||
var globalErrors = new j$.GlobalErrors();
|
||||
|
||||
this.specFilter = function() {
|
||||
return true;
|
||||
};
|
||||
@@ -154,16 +163,6 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var maximumSpecCallbackDepth = 20;
|
||||
var currentSpecCallbackDepth = 0;
|
||||
|
||||
function clearStack(fn) {
|
||||
currentSpecCallbackDepth++;
|
||||
if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
|
||||
currentSpecCallbackDepth = 0;
|
||||
realSetTimeout(fn, 0);
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
var catchException = function(e) {
|
||||
return j$.Spec.isPendingSpecException(e) || catchExceptions;
|
||||
};
|
||||
@@ -196,6 +195,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
options.clearStack = options.clearStack || clearStack;
|
||||
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
|
||||
options.fail = self.fail;
|
||||
options.globalErrors = globalErrors;
|
||||
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
|
||||
|
||||
new j$.QueueRunner(options).execute();
|
||||
};
|
||||
@@ -238,7 +239,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
reporter.suiteStarted(suite.result);
|
||||
},
|
||||
nodeComplete: function(suite, result) {
|
||||
if (!suite.disabled) {
|
||||
if (suite !== currentSuite()) {
|
||||
throw new Error('Tried to complete the wrong suite');
|
||||
}
|
||||
|
||||
if (!suite.markedPending) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
@@ -254,14 +259,17 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
|
||||
reporter.jasmineStarted({
|
||||
totalSpecsDefined: totalSpecsDefined
|
||||
totalSpecsDefined: totalSpecsDefined,
|
||||
order: order
|
||||
});
|
||||
|
||||
currentlyExecutingSuites.push(topSuite);
|
||||
|
||||
globalErrors.install();
|
||||
processor.execute(function() {
|
||||
clearResourcesForRunnable(topSuite.id);
|
||||
currentlyExecutingSuites.pop();
|
||||
globalErrors.uninstall();
|
||||
|
||||
reporter.jasmineDone({
|
||||
order: order,
|
||||
@@ -270,6 +278,12 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a custom reporter to the Jasmine environment.
|
||||
* @name Env#addReporter
|
||||
* @function
|
||||
* @see custom_reporter
|
||||
*/
|
||||
this.addReporter = function(reporterToAdd) {
|
||||
reporter.addReporter(reporterToAdd);
|
||||
};
|
||||
@@ -278,6 +292,10 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
reporter.provideFallbackReporter(reporterToAdd);
|
||||
};
|
||||
|
||||
this.clearReporters = function() {
|
||||
reporter.clearReporters();
|
||||
};
|
||||
|
||||
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
|
||||
if(!currentRunnable()) {
|
||||
throw new Error('Spies must be created in a before function or a spec');
|
||||
@@ -293,6 +311,22 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return spyRegistry.spyOn.apply(spyRegistry, arguments);
|
||||
};
|
||||
|
||||
this.spyOnProperty = function() {
|
||||
return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
|
||||
};
|
||||
|
||||
var ensureIsFunction = function(fn, caller) {
|
||||
if (!j$.isFunction_(fn)) {
|
||||
throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
|
||||
}
|
||||
};
|
||||
|
||||
var ensureIsFunctionOrAsync = function(fn, caller) {
|
||||
if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
|
||||
throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
|
||||
}
|
||||
};
|
||||
|
||||
var suiteFactory = function(description) {
|
||||
var suite = new j$.Suite({
|
||||
env: self,
|
||||
@@ -308,6 +342,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.describe = function(description, specDefinitions) {
|
||||
ensureIsFunction(specDefinitions, 'describe');
|
||||
var suite = suiteFactory(description);
|
||||
if (specDefinitions.length > 0) {
|
||||
throw new Error('describe does not expect any arguments');
|
||||
@@ -320,6 +355,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.xdescribe = function(description, specDefinitions) {
|
||||
ensureIsFunction(specDefinitions, 'xdescribe');
|
||||
var suite = suiteFactory(description);
|
||||
suite.pend();
|
||||
addSpecsToSuite(suite, specDefinitions);
|
||||
@@ -329,6 +365,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var focusedRunnables = [];
|
||||
|
||||
this.fdescribe = function(description, specDefinitions) {
|
||||
ensureIsFunction(specDefinitions, 'fdescribe');
|
||||
var suite = suiteFactory(description);
|
||||
suite.isFocused = true;
|
||||
|
||||
@@ -425,6 +462,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.it = function(description, fn, timeout) {
|
||||
// it() sometimes doesn't have a fn argument, so only check the type if
|
||||
// it's given.
|
||||
if (arguments.length > 1 && typeof fn !== 'undefined') {
|
||||
ensureIsFunctionOrAsync(fn, 'it');
|
||||
}
|
||||
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
|
||||
if (currentDeclarationSuite.markedPending) {
|
||||
spec.pend();
|
||||
@@ -433,13 +475,19 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return spec;
|
||||
};
|
||||
|
||||
this.xit = function() {
|
||||
this.xit = function(description, fn, timeout) {
|
||||
// xit(), like it(), doesn't always have a fn argument, so only check the
|
||||
// type when needed.
|
||||
if (arguments.length > 1 && typeof fn !== 'undefined') {
|
||||
ensureIsFunctionOrAsync(fn, 'xit');
|
||||
}
|
||||
var spec = this.it.apply(this, arguments);
|
||||
spec.pend('Temporarily disabled with xit');
|
||||
return spec;
|
||||
};
|
||||
|
||||
this.fit = function(description, fn, timeout){
|
||||
ensureIsFunctionOrAsync(fn, 'fit');
|
||||
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
|
||||
currentDeclarationSuite.addChild(spec);
|
||||
focusedRunnables.push(spec.id);
|
||||
@@ -456,6 +504,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
|
||||
currentDeclarationSuite.beforeEach({
|
||||
fn: beforeEachFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -463,6 +512,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.beforeAll = function(beforeAllFunction, timeout) {
|
||||
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
|
||||
currentDeclarationSuite.beforeAll({
|
||||
fn: beforeAllFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -470,6 +520,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.afterEach = function(afterEachFunction, timeout) {
|
||||
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
|
||||
afterEachFunction.isCleanup = true;
|
||||
currentDeclarationSuite.afterEach({
|
||||
fn: afterEachFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -477,6 +529,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.afterAll = function(afterAllFunction, timeout) {
|
||||
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
|
||||
currentDeclarationSuite.afterAll({
|
||||
fn: afterAllFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -492,10 +545,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.fail = function(error) {
|
||||
if (!currentRunnable()) {
|
||||
throw new Error('\'fail\' was used when there was no current spec, this could be because an asynchronous test timed out');
|
||||
}
|
||||
|
||||
var message = 'Failed';
|
||||
if (error) {
|
||||
message += ': ';
|
||||
message += error.message || error;
|
||||
if (error.message) {
|
||||
message += error.message;
|
||||
} else if (jasmine.isString_(error)) {
|
||||
message += error;
|
||||
} else {
|
||||
// pretty print all kind of objects. This includes arrays.
|
||||
message += jasmine.pp(error);
|
||||
}
|
||||
}
|
||||
|
||||
currentRunnable().addExpectationResult(false, {
|
||||
@@ -506,6 +570,10 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
message: message,
|
||||
error: error && error.message ? error : null
|
||||
});
|
||||
|
||||
if (self.throwingExpectationFailures()) {
|
||||
throw new Error(message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
getJasmineRequireObj().Expectation = function() {
|
||||
|
||||
/**
|
||||
* Matchers that come with Jasmine out of the box.
|
||||
* @namespace matchers
|
||||
*/
|
||||
function Expectation(options) {
|
||||
this.util = options.util || { buildFailureMessage: function() {} };
|
||||
this.customEqualityTesters = options.customEqualityTesters || [];
|
||||
@@ -61,6 +65,7 @@ getJasmineRequireObj().Expectation = function() {
|
||||
matcherName: name,
|
||||
passed: result.pass,
|
||||
message: message,
|
||||
error: result.error,
|
||||
actual: this.actual,
|
||||
expected: expected // TODO: this may need to be arrayified/sliced
|
||||
}
|
||||
|
||||
50
src/core/GlobalErrors.js
Normal file
50
src/core/GlobalErrors.js
Normal file
@@ -0,0 +1,50 @@
|
||||
getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||
function GlobalErrors(global) {
|
||||
var handlers = [];
|
||||
global = global || j$.getGlobal();
|
||||
|
||||
var onerror = function onerror() {
|
||||
var handler = handlers[handlers.length - 1];
|
||||
|
||||
if (handler) {
|
||||
handler.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||
} else {
|
||||
throw arguments[0];
|
||||
}
|
||||
};
|
||||
|
||||
this.uninstall = function noop() {};
|
||||
|
||||
this.install = function install() {
|
||||
if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
|
||||
var originalHandlers = global.process.listeners('uncaughtException');
|
||||
global.process.removeAllListeners('uncaughtException');
|
||||
global.process.on('uncaughtException', onerror);
|
||||
|
||||
this.uninstall = function uninstall() {
|
||||
global.process.removeListener('uncaughtException', onerror);
|
||||
for (var i = 0; i < originalHandlers.length; i++) {
|
||||
global.process.on('uncaughtException', originalHandlers[i]);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var originalHandler = global.onerror;
|
||||
global.onerror = onerror;
|
||||
|
||||
this.uninstall = function uninstall() {
|
||||
global.onerror = originalHandler;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
this.pushListener = function pushListener(listener) {
|
||||
handlers.push(listener);
|
||||
};
|
||||
|
||||
this.popListener = function popListener() {
|
||||
handlers.pop();
|
||||
};
|
||||
}
|
||||
|
||||
return GlobalErrors;
|
||||
};
|
||||
@@ -5,6 +5,13 @@ getJasmineRequireObj().JsApiReporter = function() {
|
||||
elapsed: function(){ return 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
* _Note:_ Do not construct this directly, use the global `jsApiReporter` to retrieve the instantiated object.
|
||||
*
|
||||
* @name jsApiReporter
|
||||
* @classdesc Reporter added by default in `boot.js` to record results for retrieval in javascript code.
|
||||
* @class
|
||||
*/
|
||||
function JsApiReporter(options) {
|
||||
var timer = options.timer || noopTimer,
|
||||
status = 'loaded';
|
||||
@@ -28,6 +35,12 @@ getJasmineRequireObj().JsApiReporter = function() {
|
||||
status = 'done';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current status for the Jasmine environment.
|
||||
* @name jsApiReporter#status
|
||||
* @function
|
||||
* @return {String} - One of `loaded`, `started`, or `done`
|
||||
*/
|
||||
this.status = function() {
|
||||
return status;
|
||||
};
|
||||
@@ -43,6 +56,16 @@ getJasmineRequireObj().JsApiReporter = function() {
|
||||
storeSuite(result);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the results for a set of suites.
|
||||
*
|
||||
* Retrievable in slices for easier serialization.
|
||||
* @name jsApiReporter#suiteResults
|
||||
* @function
|
||||
* @param {Number} index - The position in the suites list to start from.
|
||||
* @param {Number} length - Maximum number of suite results to return.
|
||||
* @return {Object[]}
|
||||
*/
|
||||
this.suiteResults = function(index, length) {
|
||||
return suites.slice(index, index + length);
|
||||
};
|
||||
@@ -52,6 +75,12 @@ getJasmineRequireObj().JsApiReporter = function() {
|
||||
suites_hash[result.id] = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the suites in a single object, with their `id` as the key.
|
||||
* @name jsApiReporter#suites
|
||||
* @function
|
||||
* @return {Object}
|
||||
*/
|
||||
this.suites = function() {
|
||||
return suites_hash;
|
||||
};
|
||||
@@ -62,14 +91,36 @@ getJasmineRequireObj().JsApiReporter = function() {
|
||||
specs.push(result);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the results for a set of specs.
|
||||
*
|
||||
* Retrievable in slices for easier serialization.
|
||||
* @name jsApiReporter#specResults
|
||||
* @function
|
||||
* @param {Number} index - The position in the specs list to start from.
|
||||
* @param {Number} length - Maximum number of specs results to return.
|
||||
* @return {Object[]}
|
||||
*/
|
||||
this.specResults = function(index, length) {
|
||||
return specs.slice(index, index + length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all spec results.
|
||||
* @name jsApiReporter#specs
|
||||
* @function
|
||||
* @return {Object[]}
|
||||
*/
|
||||
this.specs = function() {
|
||||
return specs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of milliseconds it took for the full Jasmine suite to run.
|
||||
* @name jsApiReporter#executionTime
|
||||
* @function
|
||||
* @return {Number}
|
||||
*/
|
||||
this.executionTime = function() {
|
||||
return executionTime;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,12 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
this.seen = [];
|
||||
}
|
||||
|
||||
function hasCustomToString(value) {
|
||||
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
|
||||
// iframe, web worker)
|
||||
return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
|
||||
}
|
||||
|
||||
PrettyPrinter.prototype.format = function(value) {
|
||||
this.ppNestLevel_++;
|
||||
try {
|
||||
@@ -30,7 +36,11 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
this.emitScalar('HTMLNode');
|
||||
} else if (value instanceof Date) {
|
||||
this.emitScalar('Date(' + value + ')');
|
||||
} else if (value.toString && typeof value === 'object' && !(value instanceof Array) && value.toString !== Object.prototype.toString) {
|
||||
} else if (j$.getType_(value) == '[object Set]') {
|
||||
this.emitSet(value);
|
||||
} else if (j$.getType_(value) == '[object Map]') {
|
||||
this.emitMap(value);
|
||||
} else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
|
||||
this.emitScalar(value.toString());
|
||||
} else if (j$.util.arrayContains(this.seen, value)) {
|
||||
this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
|
||||
@@ -51,14 +61,28 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
};
|
||||
|
||||
PrettyPrinter.prototype.iterateObject = function(obj, fn) {
|
||||
for (var property in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
|
||||
fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
|
||||
obj.__lookupGetter__(property) !== null) : false);
|
||||
var objKeys = keys(obj, j$.isArray_(obj));
|
||||
var isGetter = function isGetter(prop) {};
|
||||
|
||||
if (obj.__lookupGetter__) {
|
||||
isGetter = function isGetter(prop) {
|
||||
var getter = obj.__lookupGetter__(prop);
|
||||
return !j$.util.isUndefined(getter) && getter !== null;
|
||||
};
|
||||
|
||||
}
|
||||
var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
|
||||
for (var i = 0; i < length; i++) {
|
||||
var property = objKeys[i];
|
||||
fn(property, isGetter(property));
|
||||
}
|
||||
|
||||
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_;
|
||||
@@ -66,7 +90,7 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
function StringPrettyPrinter() {
|
||||
PrettyPrinter.call(this);
|
||||
|
||||
this.string = '';
|
||||
this.stringParts = [];
|
||||
}
|
||||
|
||||
j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
|
||||
@@ -98,11 +122,7 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
|
||||
var self = this;
|
||||
var first = array.length === 0;
|
||||
this.iterateObject(array, function(property, isGetter) {
|
||||
if (property.match(/^\d+$/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var truncated = this.iterateObject(array, function(property, isGetter) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
@@ -112,11 +132,59 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
self.formatProperty(array, property, isGetter);
|
||||
});
|
||||
|
||||
if (truncated) { this.append(', ...'); }
|
||||
|
||||
this.append(' ]');
|
||||
};
|
||||
|
||||
StringPrettyPrinter.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++) {
|
||||
if (i > 0) {
|
||||
this.append(', ');
|
||||
}
|
||||
this.format(iter.next().value);
|
||||
}
|
||||
if (set.size > size){
|
||||
this.append(', ...');
|
||||
}
|
||||
this.append(' )');
|
||||
};
|
||||
|
||||
StringPrettyPrinter.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++) {
|
||||
if (i > 0) {
|
||||
this.append(', ');
|
||||
}
|
||||
this.format(iter.next().value);
|
||||
}
|
||||
if (map.size > size){
|
||||
this.append(', ...');
|
||||
}
|
||||
this.append(' )');
|
||||
};
|
||||
|
||||
StringPrettyPrinter.prototype.emitObject = function(obj) {
|
||||
var constructorName = obj.constructor ? j$.fnNameFor(obj.constructor) : 'null';
|
||||
var ctor = obj.constructor,
|
||||
constructorName;
|
||||
|
||||
constructorName = typeof ctor === 'function' && obj instanceof ctor ?
|
||||
j$.fnNameFor(obj.constructor) :
|
||||
'null';
|
||||
|
||||
this.append(constructorName);
|
||||
|
||||
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
|
||||
@@ -127,7 +195,7 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
this.append('({ ');
|
||||
var first = true;
|
||||
|
||||
this.iterateObject(obj, function(property, isGetter) {
|
||||
var truncated = this.iterateObject(obj, function(property, isGetter) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
@@ -137,6 +205,8 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
self.formatProperty(obj, property, isGetter);
|
||||
});
|
||||
|
||||
if (truncated) { this.append(', ...'); }
|
||||
|
||||
this.append(' })');
|
||||
};
|
||||
|
||||
@@ -151,12 +221,41 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
};
|
||||
|
||||
StringPrettyPrinter.prototype.append = function(value) {
|
||||
this.string += value;
|
||||
this.stringParts.push(value);
|
||||
};
|
||||
|
||||
function keys(obj, isArray) {
|
||||
var allKeys = Object.keys ? Object.keys(obj) :
|
||||
(function(o) {
|
||||
var keys = [];
|
||||
for (var key in o) {
|
||||
if (j$.util.has(o, key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
})(obj);
|
||||
|
||||
if (!isArray) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
if (allKeys.length === 0) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
var extraKeys = [];
|
||||
for (var i = 0; i < allKeys.length; i++) {
|
||||
if (!/^[0-9]+$/.test(allKeys[i])) {
|
||||
extraKeys.push(allKeys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return extraKeys;
|
||||
}
|
||||
return function(value) {
|
||||
var stringPrettyPrinter = new StringPrettyPrinter();
|
||||
stringPrettyPrinter.format(value);
|
||||
return stringPrettyPrinter.string;
|
||||
return stringPrettyPrinter.stringParts.join('');
|
||||
};
|
||||
};
|
||||
|
||||
@@ -12,91 +12,148 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
}
|
||||
|
||||
function QueueRunner(attrs) {
|
||||
this.queueableFns = attrs.queueableFns || [];
|
||||
var queueableFns = attrs.queueableFns || [];
|
||||
this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
|
||||
this.firstCleanupIx = queueableFns.length;
|
||||
this.onComplete = attrs.onComplete || function() {};
|
||||
this.clearStack = attrs.clearStack || function(fn) {fn();};
|
||||
this.onException = attrs.onException || function() {};
|
||||
this.catchException = attrs.catchException || function() { return true; };
|
||||
this.userContext = attrs.userContext || {};
|
||||
this.userContext = attrs.userContext || new j$.UserContext();
|
||||
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
|
||||
this.fail = attrs.fail || function() {};
|
||||
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
|
||||
this.completeOnFirstError = !!attrs.completeOnFirstError;
|
||||
}
|
||||
|
||||
QueueRunner.prototype.execute = function() {
|
||||
this.run(this.queueableFns, 0);
|
||||
var self = this;
|
||||
this.handleFinalError = function(error) {
|
||||
self.onException(error);
|
||||
};
|
||||
this.globalErrors.pushListener(this.handleFinalError);
|
||||
this.run(0);
|
||||
};
|
||||
|
||||
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
|
||||
var length = queueableFns.length,
|
||||
QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
|
||||
if (lastRanIndex < this.firstCleanupIx) {
|
||||
this.run(this.firstCleanupIx);
|
||||
} else {
|
||||
this.run(lastRanIndex + 1);
|
||||
}
|
||||
};
|
||||
|
||||
QueueRunner.prototype.run = function(recursiveIndex) {
|
||||
var length = this.queueableFns.length,
|
||||
self = this,
|
||||
iterativeIndex;
|
||||
|
||||
|
||||
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
|
||||
var queueableFn = queueableFns[iterativeIndex];
|
||||
if (queueableFn.fn.length > 0) {
|
||||
attemptAsync(queueableFn);
|
||||
var result = attempt(iterativeIndex);
|
||||
|
||||
if (!result.completedSynchronously) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.completeOnFirstError && result.errored) {
|
||||
this.skipToCleanup(iterativeIndex);
|
||||
return;
|
||||
} else {
|
||||
attemptSync(queueableFn);
|
||||
}
|
||||
}
|
||||
|
||||
var runnerDone = iterativeIndex >= length;
|
||||
this.clearStack(function() {
|
||||
self.globalErrors.popListener(self.handleFinalError);
|
||||
self.onComplete();
|
||||
});
|
||||
|
||||
if (runnerDone) {
|
||||
this.clearStack(this.onComplete);
|
||||
}
|
||||
|
||||
function attemptSync(queueableFn) {
|
||||
try {
|
||||
queueableFn.fn.call(self.userContext);
|
||||
} catch (e) {
|
||||
handleException(e, queueableFn);
|
||||
}
|
||||
}
|
||||
|
||||
function attemptAsync(queueableFn) {
|
||||
function attempt() {
|
||||
var clearTimeout = function () {
|
||||
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
|
||||
},
|
||||
next = once(function () {
|
||||
setTimeout = function(delayedFn, delay) {
|
||||
return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
|
||||
},
|
||||
completedSynchronously = true,
|
||||
handleError = function(error) {
|
||||
onException(error);
|
||||
next();
|
||||
},
|
||||
cleanup = once(function() {
|
||||
clearTimeout(timeoutId);
|
||||
self.run(queueableFns, iterativeIndex + 1);
|
||||
self.globalErrors.popListener(handleError);
|
||||
}),
|
||||
next = once(function () {
|
||||
cleanup();
|
||||
|
||||
function runNext() {
|
||||
if (self.completeOnFirstError && errored) {
|
||||
self.skipToCleanup(iterativeIndex);
|
||||
} else {
|
||||
self.run(iterativeIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (completedSynchronously) {
|
||||
setTimeout(runNext);
|
||||
} else {
|
||||
runNext();
|
||||
}
|
||||
}),
|
||||
errored = false,
|
||||
queueableFn = self.queueableFns[iterativeIndex],
|
||||
timeoutId;
|
||||
|
||||
next.fail = function() {
|
||||
self.fail.apply(null, arguments);
|
||||
errored = true;
|
||||
next();
|
||||
};
|
||||
|
||||
self.globalErrors.pushListener(handleError);
|
||||
|
||||
if (queueableFn.timeout) {
|
||||
timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
|
||||
timeoutId = setTimeout(function() {
|
||||
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
|
||||
onException(error);
|
||||
next();
|
||||
}, queueableFn.timeout()]]);
|
||||
}, queueableFn.timeout());
|
||||
}
|
||||
|
||||
try {
|
||||
queueableFn.fn.call(self.userContext, next);
|
||||
if (queueableFn.fn.length === 0) {
|
||||
var maybeThenable = queueableFn.fn.call(self.userContext);
|
||||
|
||||
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
|
||||
maybeThenable.then(next, next.fail);
|
||||
completedSynchronously = false;
|
||||
return { completedSynchronously: false };
|
||||
}
|
||||
} else {
|
||||
queueableFn.fn.call(self.userContext, next);
|
||||
completedSynchronously = false;
|
||||
return { completedSynchronously: false };
|
||||
}
|
||||
} catch (e) {
|
||||
handleException(e, queueableFn);
|
||||
next();
|
||||
errored = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onException(e) {
|
||||
self.onException(e);
|
||||
}
|
||||
cleanup();
|
||||
return { completedSynchronously: true, errored: errored };
|
||||
|
||||
function handleException(e, queueableFn) {
|
||||
onException(e);
|
||||
if (!self.catchException(e)) {
|
||||
//TODO: set a var when we catch an exception and
|
||||
//use a finally block to close the loop in a nice way..
|
||||
throw e;
|
||||
function onException(e) {
|
||||
self.onException(e);
|
||||
errored = true;
|
||||
}
|
||||
|
||||
function handleException(e, queueableFn) {
|
||||
onException(e);
|
||||
if (!self.catchException(e)) {
|
||||
//TODO: set a var when we catch an exception and
|
||||
//use a finally block to close the loop in a nice way..
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,11 +18,14 @@ getJasmineRequireObj().ReportDispatcher = function() {
|
||||
this.addReporter = function(reporter) {
|
||||
reporters.push(reporter);
|
||||
};
|
||||
|
||||
|
||||
this.provideFallbackReporter = function(reporter) {
|
||||
fallbackReporter = reporter;
|
||||
};
|
||||
|
||||
this.clearReporters = function() {
|
||||
reporters = [];
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
|
||||
@@ -50,20 +50,25 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
|
||||
this.onStart(this);
|
||||
|
||||
if (!this.isExecutable() || this.markedPending || enabled === false) {
|
||||
complete(enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
var fns = this.beforeAndAfterFns();
|
||||
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
|
||||
var regularFns = fns.befores.concat(this.queueableFn);
|
||||
|
||||
this.queueRunnerFactory({
|
||||
queueableFns: allFns,
|
||||
var runnerConfig = {
|
||||
isLeaf: true,
|
||||
queueableFns: regularFns,
|
||||
cleanupFns: fns.afters,
|
||||
onException: function() { self.onException.apply(self, arguments); },
|
||||
onComplete: complete,
|
||||
userContext: this.userContext()
|
||||
});
|
||||
};
|
||||
|
||||
if (!this.isExecutable() || this.markedPending || enabled === false) {
|
||||
runnerConfig.queueableFns = [];
|
||||
runnerConfig.cleanupFns = [];
|
||||
runnerConfig.onComplete = function() { complete(enabled); };
|
||||
}
|
||||
|
||||
this.queueRunnerFactory(runnerConfig);
|
||||
|
||||
function complete(enabledAgain) {
|
||||
self.result.status = self.status(enabledAgain);
|
||||
|
||||
79
src/core/Spy.js
Normal file
79
src/core/Spy.js
Normal file
@@ -0,0 +1,79 @@
|
||||
getJasmineRequireObj().Spy = function (j$) {
|
||||
|
||||
var nextOrder = (function() {
|
||||
var order = 0;
|
||||
|
||||
return function() {
|
||||
return order++;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
|
||||
* @constructor
|
||||
* @name Spy
|
||||
*/
|
||||
function Spy(name, originalFn) {
|
||||
var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
|
||||
wrapper = makeFunc(numArgs, function () {
|
||||
return spy.apply(this, Array.prototype.slice.call(arguments));
|
||||
}),
|
||||
spyStrategy = new j$.SpyStrategy({
|
||||
name: name,
|
||||
fn: originalFn,
|
||||
getSpy: function () {
|
||||
return wrapper;
|
||||
}
|
||||
}),
|
||||
callTracker = new j$.CallTracker(),
|
||||
spy = function () {
|
||||
/**
|
||||
* @name Spy.callData
|
||||
* @property {object} object - `this` context for the invocation.
|
||||
* @property {number} invocationOrder - Order of the invocation.
|
||||
* @property {Array} args - The arguments passed for this invocation.
|
||||
*/
|
||||
var callData = {
|
||||
object: this,
|
||||
invocationOrder: nextOrder(),
|
||||
args: Array.prototype.slice.apply(arguments)
|
||||
};
|
||||
|
||||
callTracker.track(callData);
|
||||
var returnValue = spyStrategy.exec.apply(this, arguments);
|
||||
callData.returnValue = returnValue;
|
||||
|
||||
return returnValue;
|
||||
};
|
||||
|
||||
function makeFunc(length, fn) {
|
||||
switch (length) {
|
||||
case 1 : return function (a) { return fn.apply(this, arguments); };
|
||||
case 2 : return function (a,b) { return fn.apply(this, arguments); };
|
||||
case 3 : return function (a,b,c) { return fn.apply(this, arguments); };
|
||||
case 4 : return function (a,b,c,d) { return fn.apply(this, arguments); };
|
||||
case 5 : return function (a,b,c,d,e) { return fn.apply(this, arguments); };
|
||||
case 6 : return function (a,b,c,d,e,f) { return fn.apply(this, arguments); };
|
||||
case 7 : return function (a,b,c,d,e,f,g) { return fn.apply(this, arguments); };
|
||||
case 8 : return function (a,b,c,d,e,f,g,h) { return fn.apply(this, arguments); };
|
||||
case 9 : return function (a,b,c,d,e,f,g,h,i) { return fn.apply(this, arguments); };
|
||||
default : return function () { return fn.apply(this, arguments); };
|
||||
}
|
||||
}
|
||||
|
||||
for (var prop in originalFn) {
|
||||
if (prop === 'and' || prop === 'calls') {
|
||||
throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
|
||||
}
|
||||
|
||||
wrapper[prop] = originalFn[prop];
|
||||
}
|
||||
|
||||
wrapper.and = spyStrategy;
|
||||
wrapper.calls = callTracker;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
return Spy;
|
||||
};
|
||||
@@ -12,11 +12,11 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
|
||||
this.spyOn = function(obj, methodName) {
|
||||
|
||||
if (j$.util.isUndefined(obj)) {
|
||||
if (j$.util.isUndefined(obj) || obj === null) {
|
||||
throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
|
||||
}
|
||||
|
||||
if (j$.util.isUndefined(methodName)) {
|
||||
if (j$.util.isUndefined(methodName) || methodName === null) {
|
||||
throw new Error(getErrorMsg('No method name supplied'));
|
||||
}
|
||||
|
||||
@@ -53,7 +53,9 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
};
|
||||
} else {
|
||||
restoreStrategy = function() {
|
||||
delete obj[methodName];
|
||||
if (!delete obj[methodName]) {
|
||||
obj[methodName] = originalMethod;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,6 +68,66 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
|
||||
return spiedMethod;
|
||||
};
|
||||
|
||||
this.spyOnProperty = function (obj, propertyName, accessType) {
|
||||
accessType = accessType || 'get';
|
||||
|
||||
if (j$.util.isUndefined(obj)) {
|
||||
throw new Error('spyOn could not find an object to spy upon for ' + propertyName + '');
|
||||
}
|
||||
|
||||
if (j$.util.isUndefined(propertyName)) {
|
||||
throw new Error('No property name supplied');
|
||||
}
|
||||
|
||||
var descriptor;
|
||||
try {
|
||||
descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
|
||||
} catch(e) {
|
||||
// IE 8 doesn't support `definePropery` on non-DOM nodes
|
||||
}
|
||||
|
||||
if (!descriptor) {
|
||||
throw new Error(propertyName + ' property does not exist');
|
||||
}
|
||||
|
||||
if (!descriptor.configurable) {
|
||||
throw new Error(propertyName + ' is not declared configurable');
|
||||
}
|
||||
|
||||
if(!descriptor[accessType]) {
|
||||
throw new Error('Property ' + propertyName + ' does not have access type ' + accessType);
|
||||
}
|
||||
|
||||
if (j$.isSpy(descriptor[accessType])) {
|
||||
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
|
||||
throw new Error(propertyName + ' has already been spied upon');
|
||||
}
|
||||
|
||||
var originalDescriptor = j$.util.clone(descriptor),
|
||||
spy = j$.createSpy(propertyName, descriptor[accessType]),
|
||||
restoreStrategy;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
|
||||
restoreStrategy = function() {
|
||||
Object.defineProperty(obj, propertyName, originalDescriptor);
|
||||
};
|
||||
} else {
|
||||
restoreStrategy = function() {
|
||||
delete obj[propertyName];
|
||||
};
|
||||
}
|
||||
|
||||
currentSpies().push({
|
||||
restoreObjectToOriginalState: restoreStrategy
|
||||
});
|
||||
|
||||
descriptor[accessType] = spy;
|
||||
|
||||
Object.defineProperty(obj, propertyName, descriptor);
|
||||
|
||||
return spy;
|
||||
};
|
||||
|
||||
this.clearSpies = function() {
|
||||
var spies = currentSpies();
|
||||
for (var i = spies.length - 1; i >= 0; i--) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
getJasmineRequireObj().SpyStrategy = function() {
|
||||
getJasmineRequireObj().SpyStrategy = function(j$) {
|
||||
|
||||
/**
|
||||
* @namespace Spy#and
|
||||
*/
|
||||
function SpyStrategy(options) {
|
||||
options = options || {};
|
||||
|
||||
@@ -8,19 +11,41 @@ getJasmineRequireObj().SpyStrategy = function() {
|
||||
getSpy = options.getSpy || function() {},
|
||||
plan = function() {};
|
||||
|
||||
/**
|
||||
* Return the identifying information for the spy.
|
||||
* @name Spy#and#identity
|
||||
* @function
|
||||
* @returns {String}
|
||||
*/
|
||||
this.identity = function() {
|
||||
return identity;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute the current spy strategy.
|
||||
* @name Spy#and#exec
|
||||
* @function
|
||||
*/
|
||||
this.exec = function() {
|
||||
return plan.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to call through to the real implementation when invoked.
|
||||
* @name Spy#and#callThrough
|
||||
* @function
|
||||
*/
|
||||
this.callThrough = function() {
|
||||
plan = originalFn;
|
||||
return getSpy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to return the value when invoked.
|
||||
* @name Spy#and#returnValue
|
||||
* @function
|
||||
* @param {*} value The value to return.
|
||||
*/
|
||||
this.returnValue = function(value) {
|
||||
plan = function() {
|
||||
return value;
|
||||
@@ -28,6 +53,12 @@ getJasmineRequireObj().SpyStrategy = function() {
|
||||
return getSpy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
|
||||
* @name Spy#and#returnValues
|
||||
* @function
|
||||
* @param {...*} values - Values to be returned on subsequent calls to the spy.
|
||||
*/
|
||||
this.returnValues = function() {
|
||||
var values = Array.prototype.slice.call(arguments);
|
||||
plan = function () {
|
||||
@@ -36,6 +67,12 @@ getJasmineRequireObj().SpyStrategy = function() {
|
||||
return getSpy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to throw an error when invoked.
|
||||
* @name Spy#and#throwError
|
||||
* @function
|
||||
* @param {Error|String} something Thing to throw
|
||||
*/
|
||||
this.throwError = function(something) {
|
||||
var error = (something instanceof Error) ? something : new Error(something);
|
||||
plan = function() {
|
||||
@@ -44,14 +81,25 @@ getJasmineRequireObj().SpyStrategy = function() {
|
||||
return getSpy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to call a fake implementation when invoked.
|
||||
* @name Spy#and#callFake
|
||||
* @function
|
||||
* @param {Function} fn The function to invoke with the passed parameters.
|
||||
*/
|
||||
this.callFake = function(fn) {
|
||||
if(!(fn instanceof Function)) {
|
||||
if(!j$.isFunction_(fn)) {
|
||||
throw new Error('Argument passed to callFake should be a function, got ' + fn);
|
||||
}
|
||||
plan = fn;
|
||||
return getSpy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell the spy to do nothing when invoked. This is the default.
|
||||
* @name Spy#and#stub
|
||||
* @function
|
||||
*/
|
||||
this.stub = function(fn) {
|
||||
plan = function() {};
|
||||
return getSpy();
|
||||
|
||||
@@ -12,7 +12,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
this.afterFns = [];
|
||||
this.beforeAllFns = [];
|
||||
this.afterAllFns = [];
|
||||
this.disabled = false;
|
||||
|
||||
this.children = [];
|
||||
|
||||
@@ -38,11 +37,7 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
return fullName.join(' ');
|
||||
};
|
||||
|
||||
Suite.prototype.disable = function() {
|
||||
this.disabled = true;
|
||||
};
|
||||
|
||||
Suite.prototype.pend = function(message) {
|
||||
Suite.prototype.pend = function() {
|
||||
this.markedPending = true;
|
||||
};
|
||||
|
||||
@@ -59,7 +54,7 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
};
|
||||
|
||||
Suite.prototype.afterAll = function(fn) {
|
||||
this.afterAllFns.push(fn);
|
||||
this.afterAllFns.unshift(fn);
|
||||
};
|
||||
|
||||
Suite.prototype.addChild = function(child) {
|
||||
@@ -67,10 +62,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
};
|
||||
|
||||
Suite.prototype.status = function() {
|
||||
if (this.disabled) {
|
||||
return 'disabled';
|
||||
}
|
||||
|
||||
if (this.markedPending) {
|
||||
return 'pending';
|
||||
}
|
||||
@@ -83,7 +74,7 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
};
|
||||
|
||||
Suite.prototype.isExecutable = function() {
|
||||
return !this.disabled;
|
||||
return !this.markedPending;
|
||||
};
|
||||
|
||||
Suite.prototype.canBeReentered = function() {
|
||||
@@ -97,14 +88,14 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
|
||||
Suite.prototype.sharedUserContext = function() {
|
||||
if (!this.sharedContext) {
|
||||
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
|
||||
this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
|
||||
}
|
||||
|
||||
return this.sharedContext;
|
||||
};
|
||||
|
||||
Suite.prototype.clonedSharedUserContext = function() {
|
||||
return clone(this.sharedUserContext());
|
||||
return j$.UserContext.fromExisting(this.sharedUserContext());
|
||||
};
|
||||
|
||||
Suite.prototype.onException = function() {
|
||||
@@ -156,17 +147,6 @@ getJasmineRequireObj().Suite = function(j$) {
|
||||
return !args[0];
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
var clonedObj = {};
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
clonedObj[prop] = obj[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return clonedObj;
|
||||
}
|
||||
|
||||
return Suite;
|
||||
};
|
||||
|
||||
|
||||
18
src/core/UserContext.js
Normal file
18
src/core/UserContext.js
Normal file
@@ -0,0 +1,18 @@
|
||||
getJasmineRequireObj().UserContext = function(j$) {
|
||||
function UserContext() {
|
||||
}
|
||||
|
||||
UserContext.fromExisting = function(oldContext) {
|
||||
var context = new UserContext();
|
||||
|
||||
for (var prop in oldContext) {
|
||||
if (oldContext.hasOwnProperty(prop)) {
|
||||
context[prop] = oldContext[prop];
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
return UserContext;
|
||||
};
|
||||
@@ -3,13 +3,13 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
|
||||
this.sample = sample;
|
||||
}
|
||||
|
||||
ArrayContaining.prototype.asymmetricMatch = function(other) {
|
||||
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
|
||||
var className = Object.prototype.toString.call(this.sample);
|
||||
if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
|
||||
|
||||
for (var i = 0; i < this.sample.length; i++) {
|
||||
var item = this.sample[i];
|
||||
if (!j$.matchersUtil.contains(other, item)) {
|
||||
if (!j$.matchersUtil.contains(other, item, customTesters)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
||||
return hasProperty(getPrototype(obj), property);
|
||||
}
|
||||
|
||||
ObjectContaining.prototype.asymmetricMatch = function(other) {
|
||||
ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
|
||||
if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
|
||||
|
||||
for (var property in this.sample) {
|
||||
if (!hasProperty(other, property) ||
|
||||
!j$.matchersUtil.equals(this.sample[property], other[property])) {
|
||||
!j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
152
src/core/base.js
152
src/core/base.js
@@ -3,14 +3,36 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
throw new Error('unimplemented method');
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum object depth the pretty printer will print to.
|
||||
* 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;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
|
||||
* @name jasmine.DEFAULT_TIMEOUT_INTERVAL
|
||||
*/
|
||||
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
|
||||
|
||||
j$.getGlobal = function() {
|
||||
return jasmineGlobal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the currently booted Jasmine Environment.
|
||||
*
|
||||
* @name jasmine.getEnv
|
||||
* @function
|
||||
* @return {Env}
|
||||
*/
|
||||
j$.getEnv = function(options) {
|
||||
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
|
||||
//jasmine. singletons in here (setTimeout blah blah).
|
||||
@@ -21,6 +43,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return j$.isA_('Array', value);
|
||||
};
|
||||
|
||||
j$.isObject_ = function(value) {
|
||||
return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value);
|
||||
};
|
||||
|
||||
j$.isString_ = function(value) {
|
||||
return j$.isA_('String', value);
|
||||
};
|
||||
@@ -29,8 +55,20 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return j$.isA_('Number', value);
|
||||
};
|
||||
|
||||
j$.isFunction_ = function(value) {
|
||||
return j$.isA_('Function', value);
|
||||
};
|
||||
|
||||
j$.isAsyncFunction_ = function(value) {
|
||||
return j$.isA_('AsyncFunction', value);
|
||||
};
|
||||
|
||||
j$.isA_ = function(typeName, value) {
|
||||
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
|
||||
return j$.getType_(value) === '[object ' + typeName + ']';
|
||||
};
|
||||
|
||||
j$.getType_ = function(value) {
|
||||
return Object.prototype.toString.apply(value);
|
||||
};
|
||||
|
||||
j$.isDomNode = function(obj) {
|
||||
@@ -46,59 +84,70 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return matches ? matches[1] : '<anonymous>';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is an instance of the specified class/constructor.
|
||||
* @name jasmine.any
|
||||
* @function
|
||||
* @param {Constructor} clazz - The constructor to check against.
|
||||
*/
|
||||
j$.any = function(clazz) {
|
||||
return new j$.Any(clazz);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared is not `null` and not `undefined`.
|
||||
* @name jasmine.anything
|
||||
* @function
|
||||
*/
|
||||
j$.anything = function() {
|
||||
return new j$.Anything();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value being compared contains at least the keys and values.
|
||||
* @name jasmine.objectContaining
|
||||
* @function
|
||||
* @param {Object} sample - The subset of properties that _must_ be in the actual.
|
||||
*/
|
||||
j$.objectContaining = function(sample) {
|
||||
return new j$.ObjectContaining(sample);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
|
||||
* @name jasmine.stringMatching
|
||||
* @function
|
||||
* @param {RegExp|String} expected
|
||||
*/
|
||||
j$.stringMatching = function(expected) {
|
||||
return new j$.StringMatching(expected);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
|
||||
* that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
|
||||
* @name jasmine.arrayContaining
|
||||
* @function
|
||||
* @param {Array} sample
|
||||
*/
|
||||
j$.arrayContaining = function(sample) {
|
||||
return new j$.ArrayContaining(sample);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
|
||||
* @name jasmine.createSpy
|
||||
* @function
|
||||
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
|
||||
* @param {Function} [originalFn] - Function to act as the real implementation.
|
||||
* @return {Spy}
|
||||
*/
|
||||
j$.createSpy = function(name, originalFn) {
|
||||
|
||||
var spyStrategy = new j$.SpyStrategy({
|
||||
name: name,
|
||||
fn: originalFn,
|
||||
getSpy: function() { return spy; }
|
||||
}),
|
||||
callTracker = new j$.CallTracker(),
|
||||
spy = function() {
|
||||
var callData = {
|
||||
object: this,
|
||||
args: Array.prototype.slice.apply(arguments)
|
||||
};
|
||||
|
||||
callTracker.track(callData);
|
||||
var returnValue = spyStrategy.exec.apply(this, arguments);
|
||||
callData.returnValue = returnValue;
|
||||
|
||||
return returnValue;
|
||||
};
|
||||
|
||||
for (var prop in originalFn) {
|
||||
if (prop === 'and' || prop === 'calls') {
|
||||
throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
|
||||
}
|
||||
|
||||
spy[prop] = originalFn[prop];
|
||||
}
|
||||
|
||||
spy.and = spyStrategy;
|
||||
spy.calls = callTracker;
|
||||
|
||||
return spy;
|
||||
return j$.Spy(name, originalFn);
|
||||
};
|
||||
|
||||
j$.isSpy = function(putativeSpy) {
|
||||
@@ -109,19 +158,44 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
putativeSpy.calls instanceof j$.CallTracker;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an object with multiple {@link Spy}s as its members.
|
||||
* @name jasmine.createSpyObj
|
||||
* @function
|
||||
* @param {String} [baseName] - Base name for the spies in the object.
|
||||
* @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
|
||||
* @return {Object}
|
||||
*/
|
||||
j$.createSpyObj = function(baseName, methodNames) {
|
||||
if (j$.isArray_(baseName) && j$.util.isUndefined(methodNames)) {
|
||||
var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
|
||||
|
||||
if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
|
||||
methodNames = baseName;
|
||||
baseName = 'unknown';
|
||||
}
|
||||
|
||||
if (!j$.isArray_(methodNames) || methodNames.length === 0) {
|
||||
throw 'createSpyObj requires a non-empty array of method names to create spies for';
|
||||
}
|
||||
var obj = {};
|
||||
for (var i = 0; i < methodNames.length; i++) {
|
||||
obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
|
||||
var spiesWereSet = false;
|
||||
|
||||
if (j$.isArray_(methodNames)) {
|
||||
for (var i = 0; i < methodNames.length; i++) {
|
||||
obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
} else if (j$.isObject_(methodNames)) {
|
||||
for (var key in methodNames) {
|
||||
if (methodNames.hasOwnProperty(key)) {
|
||||
obj[key] = j$.createSpy(baseName + '.' + key);
|
||||
obj[key].and.returnValue(methodNames[key]);
|
||||
spiesWereSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!spiesWereSet) {
|
||||
throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
};
|
||||
|
||||
33
src/core/matchers/DiffBuilder.js
Normal file
33
src/core/matchers/DiffBuilder.js
Normal file
@@ -0,0 +1,33 @@
|
||||
getJasmineRequireObj().DiffBuilder = function(j$) {
|
||||
return function DiffBuilder() {
|
||||
var path = new j$.ObjectPath(),
|
||||
mismatches = [];
|
||||
|
||||
return {
|
||||
record: function (actual, expected, formatter) {
|
||||
formatter = formatter || defaultFormatter;
|
||||
mismatches.push(formatter(actual, expected, path));
|
||||
},
|
||||
|
||||
getMessage: function () {
|
||||
return mismatches.join('\n');
|
||||
},
|
||||
|
||||
withPath: function (pathComponent, block) {
|
||||
var oldPath = path;
|
||||
path = path.add(pathComponent);
|
||||
block();
|
||||
path = oldPath;
|
||||
}
|
||||
};
|
||||
|
||||
function defaultFormatter (actual, expected, path) {
|
||||
return 'Expected ' +
|
||||
path + (path.depth() ? ' = ' : '') +
|
||||
j$.pp(actual) +
|
||||
' to equal ' +
|
||||
j$.pp(expected) +
|
||||
'.';
|
||||
}
|
||||
};
|
||||
};
|
||||
10
src/core/matchers/NullDiffBuilder.js
Normal file
10
src/core/matchers/NullDiffBuilder.js
Normal file
@@ -0,0 +1,10 @@
|
||||
getJasmineRequireObj().NullDiffBuilder = function(j$) {
|
||||
return function() {
|
||||
return {
|
||||
withPath: function(_, block) {
|
||||
block();
|
||||
},
|
||||
record: function() {}
|
||||
};
|
||||
};
|
||||
};
|
||||
47
src/core/matchers/ObjectPath.js
Normal file
47
src/core/matchers/ObjectPath.js
Normal file
@@ -0,0 +1,47 @@
|
||||
getJasmineRequireObj().ObjectPath = function(j$) {
|
||||
function ObjectPath(components) {
|
||||
this.components = components || [];
|
||||
}
|
||||
|
||||
ObjectPath.prototype.toString = function() {
|
||||
if (this.components.length) {
|
||||
return '$' + map(this.components, formatPropertyAccess).join('');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
ObjectPath.prototype.add = function(component) {
|
||||
return new ObjectPath(this.components.concat([component]));
|
||||
};
|
||||
|
||||
ObjectPath.prototype.depth = function() {
|
||||
return this.components.length;
|
||||
};
|
||||
|
||||
function formatPropertyAccess(prop) {
|
||||
if (typeof prop === 'number') {
|
||||
return '[' + prop + ']';
|
||||
}
|
||||
|
||||
if (isValidIdentifier(prop)) {
|
||||
return '.' + prop;
|
||||
}
|
||||
|
||||
return '[\'' + prop + '\']';
|
||||
}
|
||||
|
||||
function map(array, fn) {
|
||||
var results = [];
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
results.push(fn(array[i]));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function isValidIdentifier(string) {
|
||||
return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
|
||||
}
|
||||
|
||||
return ObjectPath;
|
||||
};
|
||||
@@ -2,20 +2,20 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
|
||||
|
||||
return {
|
||||
equals: function(a, b, customTesters) {
|
||||
customTesters = customTesters || [];
|
||||
|
||||
return eq(a, b, [], [], customTesters);
|
||||
},
|
||||
equals: equals,
|
||||
|
||||
contains: function(haystack, needle, customTesters) {
|
||||
customTesters = customTesters || [];
|
||||
|
||||
if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
|
||||
return haystack.has(needle);
|
||||
}
|
||||
|
||||
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
|
||||
(!!haystack && !haystack.indexOf))
|
||||
{
|
||||
for (var i = 0; i < haystack.length; i++) {
|
||||
if (eq(haystack[i], needle, [], [], customTesters)) {
|
||||
if (equals(haystack[i], needle, customTesters)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -55,67 +55,113 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
return obj && j$.isA_('Function', obj.asymmetricMatch);
|
||||
}
|
||||
|
||||
function asymmetricMatch(a, b) {
|
||||
function asymmetricMatch(a, b, customTesters, diffBuilder) {
|
||||
var asymmetricA = isAsymmetric(a),
|
||||
asymmetricB = isAsymmetric(b);
|
||||
asymmetricB = isAsymmetric(b),
|
||||
result;
|
||||
|
||||
if (asymmetricA && asymmetricB) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (asymmetricA) {
|
||||
return a.asymmetricMatch(b);
|
||||
result = a.asymmetricMatch(b, customTesters);
|
||||
diffBuilder.record(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (asymmetricB) {
|
||||
return b.asymmetricMatch(a);
|
||||
result = b.asymmetricMatch(a, customTesters);
|
||||
diffBuilder.record(a, b);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function equals(a, b, customTesters, diffBuilder) {
|
||||
customTesters = customTesters || [];
|
||||
diffBuilder = diffBuilder || j$.NullDiffBuilder();
|
||||
|
||||
return eq(a, b, [], [], customTesters, diffBuilder);
|
||||
}
|
||||
|
||||
// Equality function lovingly adapted from isEqual in
|
||||
// [Underscore](http://underscorejs.org)
|
||||
function eq(a, b, aStack, bStack, customTesters) {
|
||||
var result = true;
|
||||
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
|
||||
var result = true, i;
|
||||
|
||||
var asymmetricResult = asymmetricMatch(a, b);
|
||||
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
|
||||
if (!j$.util.isUndefined(asymmetricResult)) {
|
||||
return asymmetricResult;
|
||||
}
|
||||
|
||||
for (var i = 0; i < customTesters.length; i++) {
|
||||
for (i = 0; i < customTesters.length; i++) {
|
||||
var customTesterResult = customTesters[i](a, b);
|
||||
if (!j$.util.isUndefined(customTesterResult)) {
|
||||
if (!customTesterResult) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return customTesterResult;
|
||||
}
|
||||
}
|
||||
|
||||
if (a instanceof Error && b instanceof Error) {
|
||||
return a.message == b.message;
|
||||
result = a.message == b.message;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
||||
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||
if (a === b) { return a !== 0 || 1 / a == 1 / b; }
|
||||
if (a === b) {
|
||||
result = a !== 0 || 1 / a == 1 / b;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// A strict comparison is necessary because `null == undefined`.
|
||||
if (a === null || b === null) { return a === b; }
|
||||
if (a === null || b === null) {
|
||||
result = a === b;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
var className = Object.prototype.toString.call(a);
|
||||
if (className != Object.prototype.toString.call(b)) { return false; }
|
||||
if (className != Object.prototype.toString.call(b)) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
switch (className) {
|
||||
// Strings, numbers, dates, and booleans are compared by value.
|
||||
case '[object String]':
|
||||
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
||||
// equivalent to `new String("5")`.
|
||||
return a == String(b);
|
||||
result = a == String(b);
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
case '[object Number]':
|
||||
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
||||
// other numeric values.
|
||||
return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
|
||||
result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
case '[object Date]':
|
||||
case '[object Boolean]':
|
||||
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
||||
// millisecond representations. Note that invalid dates with millisecond representations
|
||||
// of `NaN` are not equivalent.
|
||||
return +a == +b;
|
||||
result = +a == +b;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
// RegExps are compared by their source patterns and flags.
|
||||
case '[object RegExp]':
|
||||
return a.source == b.source &&
|
||||
@@ -123,27 +169,44 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
a.multiline == b.multiline &&
|
||||
a.ignoreCase == b.ignoreCase;
|
||||
}
|
||||
if (typeof a != 'object' || typeof b != 'object') { return false; }
|
||||
if (typeof a != 'object' || typeof b != 'object') {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
|
||||
var aIsDomNode = j$.isDomNode(a);
|
||||
var bIsDomNode = j$.isDomNode(b);
|
||||
if (aIsDomNode && bIsDomNode) {
|
||||
// At first try to use DOM3 method isEqualNode
|
||||
if (a.isEqualNode) {
|
||||
return a.isEqualNode(b);
|
||||
result = a.isEqualNode(b);
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// IE8 doesn't support isEqualNode, try to use outerHTML && innerText
|
||||
var aIsElement = a instanceof Element;
|
||||
var bIsElement = b instanceof Element;
|
||||
if (aIsElement && bIsElement) {
|
||||
return a.outerHTML == b.outerHTML;
|
||||
result = a.outerHTML == b.outerHTML;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (aIsElement || bIsElement) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
return a.innerText == b.innerText && a.textContent == b.textContent;
|
||||
result = a.innerText == b.innerText && a.textContent == b.textContent;
|
||||
if (!result) {
|
||||
diffBuilder.record(a, b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (aIsDomNode || bIsDomNode) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -164,22 +227,44 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
if (className == '[object Array]') {
|
||||
size = a.length;
|
||||
if (size !== b.length) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (size--) {
|
||||
result = eq(a[size], b[size], aStack, bStack, customTesters);
|
||||
if (!result) {
|
||||
for (i = 0; i < size; i++) {
|
||||
diffBuilder.withPath(i, function() {
|
||||
result = eq(a[i], b[i], aStack, bStack, customTesters, diffBuilder) && result;
|
||||
});
|
||||
}
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
} else if (className == '[object Set]' || className == '[object Map]') {
|
||||
if (a.size != b.size) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
var iterA = a.entries(), iterB = b.entries();
|
||||
var valA, valB;
|
||||
do {
|
||||
valA = iterA.next();
|
||||
valB = iterB.next();
|
||||
if (!eq(valA.value, valB.value, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (!valA.done && !valB.done);
|
||||
} else {
|
||||
|
||||
// Objects with different constructors are not equivalent, but `Object`s
|
||||
// or `Array`s from different frames are.
|
||||
var aCtor = a.constructor, bCtor = b.constructor;
|
||||
if (aCtor !== bCtor && !(isObjectConstructor(aCtor) &&
|
||||
isObjectConstructor(bCtor))) {
|
||||
if (aCtor !== bCtor &&
|
||||
isFunction(aCtor) && isFunction(bCtor) &&
|
||||
a instanceof aCtor && b instanceof bCtor &&
|
||||
!(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
|
||||
|
||||
diffBuilder.record(a, b, constructorsAreDifferentFormatter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -189,50 +274,68 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
size = aKeys.length;
|
||||
|
||||
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
||||
if (keys(b, className == '[object Array]').length !== size) { return false; }
|
||||
|
||||
while (size--) {
|
||||
key = aKeys[size];
|
||||
// Deep compare each member
|
||||
result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters);
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
if (keys(b, className == '[object Array]').length !== size) {
|
||||
diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
key = aKeys[i];
|
||||
// Deep compare each member
|
||||
if (!j$.util.has(b, key)) {
|
||||
diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
diffBuilder.withPath(key, function() {
|
||||
if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the first object from the stack of traversed objects.
|
||||
aStack.pop();
|
||||
bStack.pop();
|
||||
|
||||
return result;
|
||||
|
||||
function keys(obj, isArray) {
|
||||
var allKeys = Object.keys ? Object.keys(obj) :
|
||||
(function(o) {
|
||||
var keys = [];
|
||||
for (var key in o) {
|
||||
if (has(o, key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
})(obj);
|
||||
|
||||
if (!isArray) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
var extraKeys = [];
|
||||
for (var i in allKeys) {
|
||||
if (!allKeys[i].match(/^[0-9]+$/)) {
|
||||
extraKeys.push(allKeys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return extraKeys;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function keys(obj, isArray) {
|
||||
var allKeys = Object.keys ? Object.keys(obj) :
|
||||
(function(o) {
|
||||
var keys = [];
|
||||
for (var key in o) {
|
||||
if (j$.util.has(o, key)) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
})(obj);
|
||||
|
||||
if (!isArray) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
if (allKeys.length === 0) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
var extraKeys = [];
|
||||
for (var i = 0; i < allKeys.length; i++) {
|
||||
if (!/^[0-9]+$/.test(allKeys[i])) {
|
||||
extraKeys.push(allKeys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return extraKeys;
|
||||
}
|
||||
|
||||
function has(obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
}
|
||||
@@ -241,11 +344,44 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
function isObjectConstructor(ctor) {
|
||||
// aCtor instanceof aCtor is true for the Object and Function
|
||||
// constructors (since a constructor is-a Function and a function is-a
|
||||
// Object). We don't just compare ctor === Object because the constructor
|
||||
// might come from a different frame with different globals.
|
||||
return isFunction(ctor) && ctor instanceof ctor;
|
||||
function objectKeysAreDifferentFormatter(actual, expected, path) {
|
||||
var missingProperties = j$.util.objectDifference(expected, actual),
|
||||
extraProperties = j$.util.objectDifference(actual, expected),
|
||||
missingPropertiesMessage = formatKeyValuePairs(missingProperties),
|
||||
extraPropertiesMessage = formatKeyValuePairs(extraProperties),
|
||||
messages = [];
|
||||
|
||||
if (!path.depth()) {
|
||||
path = 'object';
|
||||
}
|
||||
|
||||
if (missingPropertiesMessage.length) {
|
||||
messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
|
||||
}
|
||||
|
||||
if (extraPropertiesMessage.length) {
|
||||
messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
|
||||
}
|
||||
|
||||
return messages.join('\n');
|
||||
}
|
||||
|
||||
function constructorsAreDifferentFormatter(actual, expected, path) {
|
||||
if (!path.depth()) {
|
||||
path = 'object';
|
||||
}
|
||||
|
||||
return 'Expected ' +
|
||||
path + ' to be a kind of ' +
|
||||
j$.fnNameFor(expected.constructor) +
|
||||
', but was ' + j$.pp(actual) + '.';
|
||||
}
|
||||
|
||||
function formatKeyValuePairs(obj) {
|
||||
var formatted = '';
|
||||
for (var key in obj) {
|
||||
formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,17 +6,20 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
|
||||
'toBeFalsy',
|
||||
'toBeGreaterThan',
|
||||
'toBeGreaterThanOrEqual',
|
||||
'toBeLessThanOrEqual',
|
||||
'toBeLessThan',
|
||||
'toBeLessThanOrEqual',
|
||||
'toBeNaN',
|
||||
'toBeNegativeInfinity',
|
||||
'toBeNull',
|
||||
'toBePositiveInfinity',
|
||||
'toBeTruthy',
|
||||
'toBeUndefined',
|
||||
'toContain',
|
||||
'toEqual',
|
||||
'toHaveBeenCalled',
|
||||
'toHaveBeenCalledWith',
|
||||
'toHaveBeenCalledBefore',
|
||||
'toHaveBeenCalledTimes',
|
||||
'toHaveBeenCalledWith',
|
||||
'toMatch',
|
||||
'toThrow',
|
||||
'toThrowError'
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
getJasmineRequireObj().toBe = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to be `===` to the expected value.
|
||||
* @function
|
||||
* @name matchers#toBe
|
||||
* @param {Object} expected - The expected value to compare against.
|
||||
* @example
|
||||
* expect(thing).toBe(realThing);
|
||||
*/
|
||||
function toBe() {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
getJasmineRequireObj().toBeCloseTo = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be within a specified precision of the expected value.
|
||||
* @function
|
||||
* @name matchers#toBeCloseTo
|
||||
* @param {Object} expected - The expected value to compare against.
|
||||
* @param {Number} [precision=2] - The number of decimal points to check.
|
||||
* @example
|
||||
* expect(number).toBeCloseTo(42.2, 3);
|
||||
*/
|
||||
function toBeCloseTo() {
|
||||
return {
|
||||
compare: function(actual, expected, precision) {
|
||||
@@ -7,8 +15,18 @@ getJasmineRequireObj().toBeCloseTo = function() {
|
||||
precision = precision || 2;
|
||||
}
|
||||
|
||||
if (expected === null || actual === null) {
|
||||
throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
|
||||
'expect(' + actual + ').toBeCloseTo(' + expected + ').'
|
||||
);
|
||||
}
|
||||
|
||||
var pow = Math.pow(10, precision + 1);
|
||||
var delta = Math.abs(expected - actual);
|
||||
var maxDelta = Math.pow(10, -precision) / 2;
|
||||
|
||||
return {
|
||||
pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
|
||||
pass: Math.round(delta * pow) / pow <= maxDelta
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
getJasmineRequireObj().toBeDefined = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to be defined. (Not `undefined`)
|
||||
* @function
|
||||
* @name matchers#toBeDefined
|
||||
* @example
|
||||
* expect(result).toBeDefined();
|
||||
*/
|
||||
function toBeDefined() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
getJasmineRequireObj().toBeFalsy = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to be falsy
|
||||
* @function
|
||||
* @name matchers#toBeFalsy
|
||||
* @example
|
||||
* expect(result).toBeFalsy();
|
||||
*/
|
||||
function toBeFalsy() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
getJasmineRequireObj().toBeGreaterThan = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be greater than the expected value.
|
||||
* @function
|
||||
* @name matchers#toBeGreaterThan
|
||||
* @param {Number} expected - The value to compare against.
|
||||
* @example
|
||||
* expect(result).toBeGreaterThan(3);
|
||||
*/
|
||||
function toBeGreaterThan() {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be greater than or equal to the expected value.
|
||||
* @function
|
||||
* @name matchers#toBeGreaterThanOrEqual
|
||||
* @param {Number} expected - The expected value to compare against.
|
||||
* @example
|
||||
* expect(result).toBeGreaterThanOrEqual(25);
|
||||
*/
|
||||
function toBeGreaterThanOrEqual() {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
getJasmineRequireObj().toBeLessThan = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to be less than the expected value.
|
||||
* @function
|
||||
* @name matchers#toBeLessThan
|
||||
* @param {Number} expected - The expected value to compare against.
|
||||
* @example
|
||||
* expect(result).toBeLessThan(0);
|
||||
*/
|
||||
function toBeLessThan() {
|
||||
return {
|
||||
|
||||
@@ -11,4 +19,4 @@ getJasmineRequireObj().toBeLessThan = function() {
|
||||
}
|
||||
|
||||
return toBeLessThan;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
getJasmineRequireObj().toBeLessThanOrEqual = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to be less than or equal to the expected value.
|
||||
* @function
|
||||
* @name matchers#toBeLessThanOrEqual
|
||||
* @param {Number} expected - The expected value to compare against.
|
||||
* @example
|
||||
* expect(result).toBeLessThanOrEqual(123);
|
||||
*/
|
||||
function toBeLessThanOrEqual() {
|
||||
return {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user