Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02c18a3596 | ||
|
|
0c6397d802 | ||
|
|
eb4671452e | ||
|
|
b38decf050 | ||
|
|
ca5b1de2eb | ||
|
|
a3bc74776a | ||
|
|
5d1d19f494 | ||
|
|
4f49288f31 | ||
|
|
b9adc76dc7 | ||
|
|
5ac3e21abb | ||
|
|
b1e97cfb09 | ||
|
|
8e5823c0d2 | ||
|
|
10f1220e55 | ||
|
|
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 | ||
|
|
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"
|
||||
|
||||
17
.github/ISSUE_TEMPLATE.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
### 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 (Jasmine npm, karma, etc),
|
||||
consider filing an issue with that library if appropriate
|
||||
|
||||
### When submitting an issue, please answer the following:
|
||||
|
||||
- What version are you using?
|
||||
- What environment are you running Jasmine in (node, browser, etc)?
|
||||
- How are you running Jasmine (standalone, npm, karma, etc)?
|
||||
- If possible, include an example spec that demonstrates your issue.
|
||||
|
||||
Thanks for using Jasmine!
|
||||
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-core/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-core/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-core/jasmine.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-core/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-core/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.
|
||||
|
||||
@@ -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,
|
||||
@@ -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.1"
|
||||
VERSION = "2.6.4"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jasmine/jasmine.git"
|
||||
@@ -26,7 +26,7 @@
|
||||
"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"
|
||||
|
||||
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)_
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -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,113 @@ 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();
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
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)\]/);
|
||||
});
|
||||
});
|
||||
|
||||
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)\]/);
|
||||
});
|
||||
});
|
||||
|
||||
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)\]/);
|
||||
});
|
||||
});
|
||||
|
||||
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)\]/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,25 @@ 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 arrays', function() {
|
||||
it("should stringify arrays properly", function() {
|
||||
expect(jasmineUnderTest.pp([1, 2])).toEqual("[ 1, 2 ]");
|
||||
@@ -80,6 +99,11 @@ describe("jasmineUnderTest.pp", function () {
|
||||
}, bar: [1, 2, 3]})).toEqual("Object({ foo: Function, bar: [ 1, 2, 3 ] })");
|
||||
});
|
||||
|
||||
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 +169,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 +210,19 @@ 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 from anonymous constructors with custom toString", function () {
|
||||
|
||||
@@ -170,6 +170,7 @@ describe("QueueRunner", function() {
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
jasmine.clock().tick();
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
expect(onException).toHaveBeenCalled();
|
||||
|
||||
@@ -189,6 +190,7 @@ describe("QueueRunner", function() {
|
||||
|
||||
queueRunner.execute();
|
||||
|
||||
jasmine.clock().tick(1);
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
|
||||
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
|
||||
@@ -197,12 +199,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 +214,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 +237,70 @@ 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);
|
||||
});
|
||||
});
|
||||
|
||||
it("calls exception handlers when an exception is thrown in a fn", function() {
|
||||
@@ -269,11 +336,17 @@ describe("QueueRunner", function() {
|
||||
it("continues running the functions even after an exception is thrown in an async spec", function() {
|
||||
var queueableFn = { fn: function(done) { throw new Error("error"); } },
|
||||
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
|
||||
timeout = { setTimeout: jasmine.createSpy("setTimeout"),
|
||||
clearTimeout: jasmine.createSpy("setTimeout")
|
||||
},
|
||||
queueRunner = new jasmineUnderTest.QueueRunner({
|
||||
queueableFns: [queueableFn, nextQueueableFn]
|
||||
queueableFns: [queueableFn, nextQueueableFn],
|
||||
timeout: timeout
|
||||
});
|
||||
|
||||
queueRunner.execute();
|
||||
timeout.setTimeout.calls.argsFor(0)[0]();
|
||||
|
||||
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -290,21 +363,34 @@ 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 = [],
|
||||
@@ -152,4 +288,51 @@ describe("SpyRegistry", function() {
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -1006,15 +1069,18 @@ describe("Env integration", function() {
|
||||
env.afterAll(function(innerDone) {
|
||||
jasmine.clock().tick(3001);
|
||||
innerDone();
|
||||
jasmine.clock().tick(1);
|
||||
});
|
||||
});
|
||||
|
||||
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 +1110,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 +1201,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 +1210,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 +1227,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 +1261,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 = [];
|
||||
|
||||
@@ -1417,7 +1492,7 @@ describe("Env integration", function() {
|
||||
totalSpecsDefined: 1
|
||||
});
|
||||
|
||||
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 +1647,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 +1824,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");
|
||||
|
||||
|
||||
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,88 @@ 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);
|
||||
});
|
||||
|
||||
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() {
|
||||
|
||||
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,476 @@ 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);
|
||||
});
|
||||
|
||||
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());
|
||||
|
||||
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());
|
||||
@@ -804,6 +804,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,7 @@
|
||||
"npmPackage/**/*.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/checkForSet.js",
|
||||
"helpers/nodeDefineJasmineUnderTest.js"
|
||||
],
|
||||
"random": true
|
||||
|
||||
@@ -17,10 +17,12 @@ src_files:
|
||||
stylesheets:
|
||||
helpers:
|
||||
- 'helpers/BrowserFlags.js'
|
||||
- 'helpers/checkForSet.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); });
|
||||
|
||||
@@ -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,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
options.clearStack = options.clearStack || clearStack;
|
||||
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
|
||||
options.fail = self.fail;
|
||||
options.globalErrors = globalErrors;
|
||||
|
||||
new j$.QueueRunner(options).execute();
|
||||
};
|
||||
@@ -238,7 +238,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();
|
||||
@@ -259,9 +263,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
|
||||
currentlyExecutingSuites.push(topSuite);
|
||||
|
||||
globalErrors.install();
|
||||
processor.execute(function() {
|
||||
clearResourcesForRunnable(topSuite.id);
|
||||
currentlyExecutingSuites.pop();
|
||||
globalErrors.uninstall();
|
||||
|
||||
reporter.jasmineDone({
|
||||
order: order,
|
||||
@@ -270,6 +276,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 +290,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 +309,16 @@ 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 suiteFactory = function(description) {
|
||||
var suite = new j$.Suite({
|
||||
env: self,
|
||||
@@ -308,6 +334,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 +347,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.xdescribe = function(description, specDefinitions) {
|
||||
ensureIsFunction(specDefinitions, 'xdescribe');
|
||||
var suite = suiteFactory(description);
|
||||
suite.pend();
|
||||
addSpecsToSuite(suite, specDefinitions);
|
||||
@@ -329,6 +357,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var focusedRunnables = [];
|
||||
|
||||
this.fdescribe = function(description, specDefinitions) {
|
||||
ensureIsFunction(specDefinitions, 'fdescribe');
|
||||
var suite = suiteFactory(description);
|
||||
suite.isFocused = true;
|
||||
|
||||
@@ -425,6 +454,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') {
|
||||
ensureIsFunction(fn, 'it');
|
||||
}
|
||||
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
|
||||
if (currentDeclarationSuite.markedPending) {
|
||||
spec.pend();
|
||||
@@ -433,13 +467,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') {
|
||||
ensureIsFunction(fn, 'xit');
|
||||
}
|
||||
var spec = this.it.apply(this, arguments);
|
||||
spec.pend('Temporarily disabled with xit');
|
||||
return spec;
|
||||
};
|
||||
|
||||
this.fit = function(description, fn, timeout){
|
||||
ensureIsFunction(fn, 'fit');
|
||||
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
|
||||
currentDeclarationSuite.addChild(spec);
|
||||
focusedRunnables.push(spec.id);
|
||||
@@ -456,6 +496,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||
ensureIsFunction(beforeEachFunction, 'beforeEach');
|
||||
currentDeclarationSuite.beforeEach({
|
||||
fn: beforeEachFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -463,6 +504,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.beforeAll = function(beforeAllFunction, timeout) {
|
||||
ensureIsFunction(beforeAllFunction, 'beforeAll');
|
||||
currentDeclarationSuite.beforeAll({
|
||||
fn: beforeAllFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -470,6 +512,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.afterEach = function(afterEachFunction, timeout) {
|
||||
ensureIsFunction(afterEachFunction, 'afterEach');
|
||||
currentDeclarationSuite.afterEach({
|
||||
fn: afterEachFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -477,6 +520,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.afterAll = function(afterAllFunction, timeout) {
|
||||
ensureIsFunction(afterAllFunction, 'afterAll');
|
||||
currentDeclarationSuite.afterAll({
|
||||
fn: afterAllFunction,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
@@ -492,10 +536,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, {
|
||||
|
||||
@@ -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 value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
|
||||
}
|
||||
|
||||
PrettyPrinter.prototype.format = function(value) {
|
||||
this.ppNestLevel_++;
|
||||
try {
|
||||
@@ -30,7 +36,9 @@ 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 (value.toString && value.toString() == '[object Set]') {
|
||||
this.emitSet(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') + '>');
|
||||
@@ -59,6 +67,7 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
};
|
||||
|
||||
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
|
||||
PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
|
||||
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
|
||||
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
|
||||
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
|
||||
@@ -115,8 +124,34 @@ getJasmineRequireObj().pp = function(j$) {
|
||||
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.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) {
|
||||
|
||||
@@ -20,9 +20,15 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
this.userContext = attrs.userContext || {};
|
||||
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
|
||||
this.fail = attrs.fail || function() {};
|
||||
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
|
||||
}
|
||||
|
||||
QueueRunner.prototype.execute = function() {
|
||||
var self = this;
|
||||
this.handleFinalError = function(error) {
|
||||
self.onException(error);
|
||||
};
|
||||
this.globalErrors.pushListener(this.handleFinalError);
|
||||
this.run(this.queueableFns, 0);
|
||||
};
|
||||
|
||||
@@ -42,11 +48,10 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
}
|
||||
}
|
||||
|
||||
var runnerDone = iterativeIndex >= length;
|
||||
|
||||
if (runnerDone) {
|
||||
this.clearStack(this.onComplete);
|
||||
}
|
||||
this.clearStack(function() {
|
||||
self.globalErrors.popListener(self.handleFinalError);
|
||||
self.onComplete();
|
||||
});
|
||||
|
||||
function attemptSync(queueableFn) {
|
||||
try {
|
||||
@@ -60,9 +65,24 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
var clearTimeout = function () {
|
||||
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
|
||||
},
|
||||
completedSynchronously = true,
|
||||
setTimeout = function(delayedFn, delay) {
|
||||
return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
|
||||
},
|
||||
handleError = function(error) {
|
||||
onException(error);
|
||||
next();
|
||||
},
|
||||
next = once(function () {
|
||||
clearTimeout(timeoutId);
|
||||
self.run(queueableFns, iterativeIndex + 1);
|
||||
self.globalErrors.popListener(handleError);
|
||||
if (completedSynchronously) {
|
||||
setTimeout(function() {
|
||||
self.run(queueableFns, iterativeIndex + 1);
|
||||
});
|
||||
} else {
|
||||
self.run(queueableFns, iterativeIndex + 1);
|
||||
}
|
||||
}),
|
||||
timeoutId;
|
||||
|
||||
@@ -71,16 +91,19 @@ getJasmineRequireObj().QueueRunner = function(j$) {
|
||||
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);
|
||||
completedSynchronously = false;
|
||||
} catch (e) {
|
||||
handleException(e, queueableFn);
|
||||
next();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
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'));
|
||||
}
|
||||
|
||||
@@ -68,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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
147
src/core/base.js
147
src/core/base.js
@@ -3,14 +3,35 @@ 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.
|
||||
* 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 +42,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 +54,16 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return j$.isA_('Number', value);
|
||||
};
|
||||
|
||||
j$.isFunction_ = function(value) {
|
||||
return j$.isA_('Function', 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 +79,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 +153,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]') {
|
||||
if (a.size != b.size) {
|
||||
diffBuilder.record(a, b);
|
||||
return false;
|
||||
}
|
||||
var iterA = a.values(), iterB = b.values();
|
||||
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,52 +274,66 @@ 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 = [];
|
||||
if (allKeys.length === 0) {
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
for (var x = 0; x < allKeys.length; x++) {
|
||||
if (!allKeys[x].match(/^[0-9]+$/)) {
|
||||
extraKeys.push(allKeys[x]);
|
||||
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);
|
||||
|
||||
return extraKeys;
|
||||
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) {
|
||||
@@ -245,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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
getJasmineRequireObj().toBeNaN = function(j$) {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be `NaN` (Not a Number).
|
||||
* @function
|
||||
* @name matchers#toBeNaN
|
||||
* @example
|
||||
* expect(thing).toBeNaN();
|
||||
*/
|
||||
function toBeNaN() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
28
src/core/matchers/toBeNegativeInfinity.js
Normal file
28
src/core/matchers/toBeNegativeInfinity.js
Normal file
@@ -0,0 +1,28 @@
|
||||
getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
|
||||
/**
|
||||
* {@link expect} the actual value to be `-Infinity` (-infinity).
|
||||
* @function
|
||||
* @name matchers#toBeNegativeInfinity
|
||||
* @example
|
||||
* expect(thing).toBeNegativeInfinity();
|
||||
*/
|
||||
function toBeNegativeInfinity() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
var result = {
|
||||
pass: (actual === Number.NEGATIVE_INFINITY)
|
||||
};
|
||||
|
||||
if (result.pass) {
|
||||
result.message = 'Expected actual to be -Infinity.';
|
||||
} else {
|
||||
result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be -Infinity.'; };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return toBeNegativeInfinity;
|
||||
};
|
||||
@@ -1,5 +1,11 @@
|
||||
getJasmineRequireObj().toBeNull = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be `null`.
|
||||
* @function
|
||||
* @name matchers#toBeNull
|
||||
* @example
|
||||
* expect(result).toBeNull();
|
||||
*/
|
||||
function toBeNull() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
28
src/core/matchers/toBePositiveInfinity.js
Normal file
28
src/core/matchers/toBePositiveInfinity.js
Normal file
@@ -0,0 +1,28 @@
|
||||
getJasmineRequireObj().toBePositiveInfinity = function(j$) {
|
||||
/**
|
||||
* {@link expect} the actual value to be `Infinity` (infinity).
|
||||
* @function
|
||||
* @name matchers#toBePositiveInfinity
|
||||
* @example
|
||||
* expect(thing).toBePositiveInfinity();
|
||||
*/
|
||||
function toBePositiveInfinity() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
var result = {
|
||||
pass: (actual === Number.POSITIVE_INFINITY)
|
||||
};
|
||||
|
||||
if (result.pass) {
|
||||
result.message = 'Expected actual to be Infinity.';
|
||||
} else {
|
||||
result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be Infinity.'; };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return toBePositiveInfinity;
|
||||
};
|
||||
@@ -1,5 +1,11 @@
|
||||
getJasmineRequireObj().toBeTruthy = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be truthy.
|
||||
* @function
|
||||
* @name matchers#toBeTruthy
|
||||
* @example
|
||||
* expect(thing).toBeTruthy();
|
||||
*/
|
||||
function toBeTruthy() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
getJasmineRequireObj().toBeUndefined = function() {
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to be `undefined`.
|
||||
* @function
|
||||
* @name matchers#toBeUndefined
|
||||
* @example
|
||||
* expect(result).toBeUndefined():
|
||||
*/
|
||||
function toBeUndefined() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
getJasmineRequireObj().toContain = function() {
|
||||
/**
|
||||
* {@link expect} the actual value to contain a specific value.
|
||||
* @function
|
||||
* @name matchers#toContain
|
||||
* @param {Object} expected - The value to look for.
|
||||
* @example
|
||||
* expect(array).toContain(anElement);
|
||||
* expect(string).toContain(substring);
|
||||
*/
|
||||
function toContain(util, customEqualityTesters) {
|
||||
customEqualityTesters = customEqualityTesters || [];
|
||||
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
getJasmineRequireObj().toEqual = function() {
|
||||
|
||||
getJasmineRequireObj().toEqual = function(j$) {
|
||||
/**
|
||||
* {@link expect} the actual value to be equal to the expected, using deep equality comparison.
|
||||
* @function
|
||||
* @name matchers#toEqual
|
||||
* @param {Object} expected - Expected value
|
||||
* @example
|
||||
* expect(bigObject).toEqual({"foo": ['bar', 'baz']});
|
||||
*/
|
||||
function toEqual(util, customEqualityTesters) {
|
||||
customEqualityTesters = customEqualityTesters || [];
|
||||
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
var result = {
|
||||
pass: false
|
||||
};
|
||||
pass: false
|
||||
},
|
||||
diffBuilder = j$.DiffBuilder();
|
||||
|
||||
result.pass = util.equals(actual, expected, customEqualityTesters);
|
||||
result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
|
||||
|
||||
// TODO: only set error message if test fails
|
||||
result.message = diffBuilder.getMessage();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
|
||||
|
||||
/**
|
||||
* {@link expect} the actual (a {@link Spy}) to have been called.
|
||||
* @function
|
||||
* @name matchers#toHaveBeenCalled
|
||||
* @example
|
||||
* expect(mySpy).toHaveBeenCalled();
|
||||
* expect(mySpy).not.toHaveBeenCalled();
|
||||
*/
|
||||
function toHaveBeenCalled() {
|
||||
return {
|
||||
compare: function(actual) {
|
||||
|
||||
60
src/core/matchers/toHaveBeenCalledBefore.js
Normal file
60
src/core/matchers/toHaveBeenCalledBefore.js
Normal file
@@ -0,0 +1,60 @@
|
||||
getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledBefore>', 'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)');
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
|
||||
* @function
|
||||
* @name matchers#toHaveBeenCalledBefore
|
||||
* @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
|
||||
* @example
|
||||
* expect(mySpy).toHaveBeenCalledBefore(otherSpy);
|
||||
*/
|
||||
function toHaveBeenCalledBefore() {
|
||||
return {
|
||||
compare: function(firstSpy, latterSpy) {
|
||||
if (!j$.isSpy(firstSpy)) {
|
||||
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
|
||||
}
|
||||
if (!j$.isSpy(latterSpy)) {
|
||||
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
|
||||
}
|
||||
|
||||
var result = { pass: false };
|
||||
|
||||
if (!firstSpy.calls.count()) {
|
||||
result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called.';
|
||||
return result;
|
||||
}
|
||||
if (!latterSpy.calls.count()) {
|
||||
result.message = 'Expected spy ' + latterSpy.and.identity() + ' to have been called.';
|
||||
return result;
|
||||
}
|
||||
|
||||
var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
|
||||
var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
|
||||
|
||||
result.pass = latest1stSpyCall < first2ndSpyCall;
|
||||
|
||||
if (result.pass) {
|
||||
result.message = 'Expected spy ' + firstSpy.and.identity() + ' to not have been called before spy ' + latterSpy.and.identity() + ', but it was';
|
||||
} else {
|
||||
var first1stSpyCall = firstSpy.calls.first().invocationOrder;
|
||||
var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
|
||||
|
||||
if(first1stSpyCall < first2ndSpyCall) {
|
||||
result.message = 'Expected latest call to spy ' + firstSpy.and.identity() + ' to have been called before first call to spy ' + latterSpy.and.identity() + ' (no interleaved calls)';
|
||||
} else if (latest2ndSpyCall > latest1stSpyCall) {
|
||||
result.message = 'Expected first call to spy ' + latterSpy.and.identity() + ' to have been called after latest call to spy ' + firstSpy.and.identity() + ' (no interleaved calls)';
|
||||
} else {
|
||||
result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called before spy ' + latterSpy.and.identity();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return toHaveBeenCalledBefore;
|
||||
};
|
||||
@@ -2,6 +2,14 @@ getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
|
||||
|
||||
/**
|
||||
* {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
|
||||
* @function
|
||||
* @name matchers#toHaveBeenCalledTimes
|
||||
* @param {Number} expected - The number of invocations to look for.
|
||||
* @example
|
||||
* expect(mySpy).toHaveBeenCalledTimes(3);
|
||||
*/
|
||||
function toHaveBeenCalledTimes() {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
@@ -2,6 +2,14 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
|
||||
|
||||
/**
|
||||
* {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
|
||||
* @function
|
||||
* @name matchers#toHaveBeenCalledWith
|
||||
* @param {...Object} - The arguments to look for
|
||||
* @example
|
||||
* expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
|
||||
*/
|
||||
function toHaveBeenCalledWith(util, customEqualityTesters) {
|
||||
return {
|
||||
compare: function() {
|
||||
|
||||
@@ -2,6 +2,15 @@ getJasmineRequireObj().toMatch = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
|
||||
|
||||
/**
|
||||
* {@link expect} the actual value to match a regular expression
|
||||
* @function
|
||||
* @name matchers#toMatch
|
||||
* @param {RegExp|String} expected - Value to look for in the string.
|
||||
* @example
|
||||
* expect("my string").toMatch(/string$/);
|
||||
* expect("other string").toMatch("her");
|
||||
*/
|
||||
function toMatch() {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
@@ -2,6 +2,15 @@ getJasmineRequireObj().toThrow = function(j$) {
|
||||
|
||||
var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
|
||||
|
||||
/**
|
||||
* {@link expect} a function to `throw` something.
|
||||
* @function
|
||||
* @name matchers#toThrow
|
||||
* @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
|
||||
* @example
|
||||
* expect(function() { return 'things'; }).toThrow('foo');
|
||||
* expect(function() { return 'stuff'; }).toThrow();
|
||||
*/
|
||||
function toThrow(util) {
|
||||
return {
|
||||
compare: function(actual, expected) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user