Compare commits

..

96 Commits

Author SHA1 Message Date
Christopher Jobst and Sheel Choksi
812b14d000 Update README and remove rc release notes
RC release notes have been merged into release_notes/20.md
2013-12-16 12:42:17 -08:00
Christopher Jobst and Sheel Choksi
a2a8b5dde2 Create a 2.0 distribution 2013-12-16 12:33:34 -08:00
Christopher Jobst
78bed99ba3 Add in 2.0 release notes 2013-12-16 11:17:51 -08:00
Sheel Choksi
f9191d7b0d Merge pull request #473 from pimterry/callTrackingTests
Refactored the createSpy tests, to add unit tests for its part of call tracking
2013-12-07 16:57:57 -08:00
pimterry
83a692d5a8 Use the correct Jasmine version in the spy integration tests 2013-12-07 22:16:24 +00:00
pimterry
14a8c2ca09 Move spy integration tests out of the unit test suite 2013-12-07 20:52:02 +00:00
pimterry
b2e8de7bcd Mock callTracker in spy tests for better test isolation 2013-12-07 20:43:38 +00:00
pimterry
1d98a23b14 Add tests for call tracking in createSpy 2013-12-07 20:27:08 +00:00
Sheel Choksi
16ffd3b3fb Fix up specs that failed when maximumSpecCallbackDepth is set to 1 2013-11-22 23:04:42 -08:00
Sheel Choksi
6bc87ad223 Merge pull request #466 from
maciej-filip-sz:DelayedFunctionScheduler-patch

Sets and executes timeouts set during a tick.
2013-11-17 17:17:31 -08:00
Maciej Filip Szkodziński
555d328cf2 Moved last currentTime assignment to tick. 2013-11-17 17:14:29 -08:00
Maciej Filip Szkodziński
c78fba4b13 Sets and executes timeouts set during a tick.
All timeouts and intervals set during a tick were being scheduled to run
at delay + end-of-tick, instead of delay + time-of-outer-timeout.

Scheduled run-at times were shifted because currentTime was being
incremented before executing scheduled functions.

Additionally, the execute loop was iterating over a functions-to-run
array, created from scheduledFunctions before starting. Any changes to
scheduledFunctions were being ignored during the tick, and the next tick
would ignore any functions which should have been executed in the past.

The commit is a rewrite of DelayedFunctionScheduler, preserving the
public interface. Execution of scheduled functions updates currentTime
on each iteration, and each time takes the functions with the lowest
runAtMillis from the schedule, if they aren't higher than endTime.
2013-11-17 17:14:29 -08:00
Sheel Choksi
8a6d7828c6 Make all async functions be subject to the timeout
[finishes #60798058]
2013-11-14 23:01:43 -08:00
Sheel Choksi
c888b0c1b8 Slight refactoring of clearing timeouts when an exception is thrown 2013-11-14 20:48:28 -08:00
Sheel Choksi
72e9851217 Bumping built distribution 2013-11-14 18:16:32 -08:00
Sheel Choksi
7ee5073921 Fix bad merge 2013-11-11 21:01:36 -08:00
Sheel Choksi
614a18453e Rename Spec's queueRunner to more accurately be a queueRunnerFactory 2013-11-11 20:53:13 -08:00
Rajan Agaskar
916f889c01 Merge pull request #462 from tidoust/clear-timeout-async
Clears timeout timer even when async spec throws an exception
2013-11-07 09:40:43 -08:00
François Daoust
4a7b79ad0d Regression spec added for timeout timer in an async spec
The spec ensures that the timeout timer is properly cleared out
even when the async spec throws an exception.
2013-11-07 16:08:41 +01:00
François Daoust
775e2ff0a9 Clears timeout timer even when async spec throws an exception
When an async spec throws a (sync) exception for some reason, the
exception was correctly caught and reported by Jasmine but the timeout
timer continued to run in the background.

For instance, running the (rather stupid) example below would report
the exception immediately but would also make the process loop for 5s
(and report the exception depending on the reported being used).

describe('exception', function () {
  it('is caught but timer continues to run', function (done) {
    throw new Error('Oh no!');
  });
});

This happened because the timout timer is set in Spec while the
"try... catch" block is in the queue runner. The "callDone" function
of "timeoutable" that resets the timer was thus not called.

The commit simply introduces a "try... catch" block within the
`timeoutable` function to ensure that "callDone" gets called even
when an exception is thrown.
2013-11-07 14:51:46 +01:00
Sheel Choksi
1b6725ec25 Updating Spec#getFullName spec to work in IE 8
Forgot that the pretty printer is not functional in IE 8, which
subsequently brings down toHaveBeenCalledWith
2013-11-04 21:59:06 -08:00
Sheel Choksi
952eb59707 Change test for how a spy gets its full name
- Removes another TODO
- A spec uses its full name as soon as it is created (for the result
    object) and so it needed to be tested differently
2013-11-04 21:38:01 -08:00
Sheel Choksi
de6a305b44 Move the various integration specs into their own folder
- There is now an integration folder inside of spec/core
- Killed the TODOs about moving around integration specs
2013-11-03 16:48:35 -08:00
Sheel Choksi
8513201fa3 Add in missing repository field to package.json
Removes the following warning when doing a `npm install`: 'npm WARN
package.json jasmine-core@2.0.0-rc5 No repository field.'
2013-11-02 18:28:53 -07:00
JR and Sheel Choksi
6e07dccb68 Make getGlobal() work in strict mode
Slight modifications to implementation in pull #437
2013-11-01 11:06:57 -07:00
JR and Sheel Choksi
fcc50cc6f4 Rename Release.markdown to be more consistently named 2013-10-31 14:27:30 -07:00
Sheel Choksi
9e8466ba2b Merge pull request #458 from jsoref/readme
Rename README for consistency
2013-10-31 14:24:43 -07:00
Kristóf Marussy
4350045d61 Replaced deprecated octal literal with hexadecimal
Octal literals are deprecated in JavaScript 1.5 and Gjs were generating
warnings because of them.
2013-10-31 14:03:06 -07:00
Rajan Agaskar
666e9c341e Merge pull request #460 from jsoref/releasenotes
Improving Release note text
2013-10-30 20:52:30 -07:00
Josh Soref
5830d9f86b Improving Release note text 2013-10-30 23:14:57 -04:00
August Toman-Yih and Sheel Choksi
ea888e4c03 Fix triple/tripple spelling error 2013-10-30 17:30:25 -07:00
Josh Soref
c7e3ca6c8a Spelling: Fix spelling errors
* equal
* existence
* expectation
* expected
* intend
* message
* report
* singular
2013-10-30 20:12:05 -04:00
Josh Soref
06db4a8583 Rename README for consistency 2013-10-30 10:31:15 -04:00
Rajan Agaskar and Sheel Choksi
a2debf60b6 Use jasmine.addMatchers instead of reaching through jasmine.Expectation [finishes #59518946] 2013-10-29 18:35:17 -07:00
Sheel Choksi
04c7db9259 Update built distribution to include latest 2.0.0-rc5 fixes 2013-10-29 17:40:15 -07:00
Sheel Choksi
8585ef69a5 Update clock not installed message to reflect current boot installation process 2013-10-29 17:33:51 -07:00
Sheel Choksi
cb5aea1fcf Fix builds by working around browser timing functions not being successfully overridden 2013-10-29 17:32:04 -07:00
Sheel Choksi
966f76b481 Add in missing clock uninstall 2013-10-29 17:28:41 -07:00
Sheel Choksi
40e3020fdc Build distribution for 2.0.0-rc5 and associated standalone distribution 2013-10-29 14:03:02 -07:00
Sheel Choksi
69549a6ff3 Add in 2.0.0-rc5 release notes 2013-10-29 14:03:01 -07:00
Sheel Choksi
a03fad8911 Move built console.js into lib and include in standalone distribution
[finishes #59679110]
2013-10-29 14:03:01 -07:00
Sheel Choksi
61993cf1fc Expose Jasmine's topSuite [finishes #59774024] 2013-10-29 11:27:12 -07:00
Kyriacos Souroullas and Sheel Choksi
cd9d5284cd Matchers can have a negativeCompare
- Passing in a 'negativeCompare' will cause that function to be used when it is a 'not' assertion
- Otherwise, the reversal of the compare's result will be used instead

[finishes #59703824]
2013-10-28 17:13:18 -07:00
Kyriacos Souroullas and Sheel Choksi
e346e7dcc1 Revert removal of compare nesting
Since we want the user to be able to pass a negative comparison function, the extra layer of wrapping is now needed
2013-10-28 17:13:09 -07:00
Davis W. Frank
dd8a455f91 Adding Code Climate badge to README 2013-10-25 12:25:27 -07:00
Davis W. Frank
9e149d1e0f Move node dev deps forward, add .jshintrc to support latest grunt-contrib-jshint and Code Climate score 2013-10-25 12:23:57 -07:00
Sheel Choksi and Tim Jarratt
797984f173 Add newlines to end of files 2013-10-25 10:57:43 -07:00
Sheel Choksi and Tim Jarratt
29c5c127e5 Refactor Suite.addSpec and .addSuite to .addChild 2013-10-25 10:52:31 -07:00
Sheel Choksi and Tim Jarratt
26581b4c91 Rename Suite.children_ to .children
Also removed some unit tests that were brittle, and already tested by
better, more round-trip tests.
2013-10-25 10:25:50 -07:00
Davis W. Frank
243ff80196 Fixing global leak for 'timer' 2013-10-24 17:17:05 -07:00
Davis W. Frank
284bb0b608 Giving Sheel his due 2013-10-24 16:55:51 -07:00
Sheel Choksi
6453ed656b Suites just have children instead of separating into specs/suites 2013-10-24 16:35:00 -07:00
Sheel Choksi
a1a948b8df Remove completeCallback from suite as its unused 2013-10-24 16:34:34 -07:00
Sheel Choksi
7a4876ecfa Also move function to determine whether specs should catch exceptions into closure 2013-10-24 16:24:55 -07:00
Sheel Choksi
d9ece1f14f Remove version/versionString and currentRunner
- Instead of version/versionString, jasmine.version should be sufficient
- currentRunner was exposing Jasmine's internal top level suite
2013-10-24 15:42:46 -07:00
Sheel Choksi
f1613ce77c Move additional methods from Env prototype to env closure
- Users can no longer spelunk the spec tree from topSuite
- Users no longer have access to currentSuite/currentSpec
- Other miscellaneous (arguably less useful) methods have also been tucked
away into the closure, like suiteFactory
2013-10-24 15:28:01 -07:00
Sheel Choksi
a3424ea265 Remove addCustomEqualityTester and addMatchers from global
These functions are available on the jasmine namespace
2013-10-24 14:00:05 -07:00
Sheel Choksi
ab0b2b783c Move next spec/next suite ids into closure
No longer exposing these from the environment
2013-10-24 13:43:04 -07:00
Sheel Choksi
d0aff9ed02 Use toThrowError instead of toThrow in places where we are expecting an error 2013-10-24 12:15:17 -07:00
Sheel Choksi
a309117758 Remove TODO: should be easier to load polyfill for timeout functions as Jasmine does not get references to these functions until boot.js is loaded 2013-10-24 11:58:21 -07:00
Sheel Choksi
0c6e590a93 A spec without expectations is considered passing
- Specs are passing by default unless told otherwise
- Getting the result.status of a spec before the spec has run is now
  undefined instead of pending

[finishes #59422744]
2013-10-24 11:34:42 -07:00
Sheel Choksi
d06da150de Stop passing in queryString to HTMLReporter, it is unused 2013-10-23 11:06:42 -07:00
Sheel Choksi
39d7ebf28e Remove an extra layer of wrapping for matchers/custom matchers
Helps reduce how nested custom matchers have to be for users as well as
Jasmine internal matchers

[#59161378]
2013-10-20 22:21:56 -07:00
Sheel Choksi
5f429fcb37 Re-enable CustomMatchersSpec and update for current version of custom matchers 2013-10-20 21:58:16 -07:00
Sheel Choksi
b6eb9a4d5e Remove now unused updateInterval that was being set in specs 2013-10-20 17:12:40 -07:00
Sheel Choksi
fdb7df812c Improve error message when a spec doesn't call the async callback within the default time interval 2013-10-19 21:18:06 -07:00
Davis W. Frank
81299860aa Merge pull request #450 from slackersoft/manualClockUninstall
Env no longer automatically uninstalls the clock after each spec
2013-10-18 15:51:10 -07:00
slackersoft
ca6fa6f711 Env no longer automatically uninstalls the clock after each spec
- Behaves more like how we want plugins to behave

[#58281436]
2013-10-16 18:39:03 -07:00
Davis W. Frank
5aaafed4d8 Move clock from global to jasmine; provide a function to access the clock. 2013-10-10 16:24:58 -07:00
Davis W. Frank
c28c124f58 removed addMatchers from the global. This should have been in previous commit 2013-10-10 14:11:44 -07:00
Davis W. Frank
f0a1adb61c Continuing boot change with docs 2013-10-10 12:00:46 -07:00
Davis W. Frank
5ff2aecab8 Moving a documented-up boot.js from the website back into core 2013-10-10 11:59:59 -07:00
Davis W. Frank
8ca8197b4c Make exposure of addMatchers and addCustomEqualityTesters be on jasmine instead of inconsistent. 2013-10-10 11:32:21 -07:00
Davis W. Frank
55716723b5 Adding Compass as a dev dependency in order to build HTMLreporter CSS 2013-10-10 11:27:40 -07:00
Davis W. Frank
3973cc5a71 Merge pull request #443 from kryger/patch-1
Fixed broken link to contributing guide
2013-10-08 07:48:53 -07:00
Lukasz Kryger
95af58ade6 Fixed broken link to contributing guide 2013-10-08 11:33:55 +01:00
slackersoft
6641d64305 Make addCustomEqualityTester available on jasmine global
- User shouldn't have to `jasmine.getEnv()` to add one

[#54582648]
2013-10-06 11:32:38 -07:00
slackersoft
7c1fcd7bb5 Regenerate jasmine.js for QueueRunner fix 2013-10-06 11:32:19 -07:00
slackersoft
e91d0341a4 Revert "Make addCustomEqualityTester available on jasmine global"
Oops, this made it on global object, not `jasmnie`

This reverts commit 144ff174f6.
2013-10-06 11:11:46 -07:00
slackersoft
144ff174f6 Make addCustomEqualityTester available on jasmine global
- User shouldn't have to `jasmine.getEnv()` to add one
2013-10-06 11:05:35 -07:00
Gregg Van Hove and Tim Jarratt
af4bfa8bc4 Env should use the "public" QueueRunner interface 2013-10-04 17:04:22 -07:00
Gregg Van Hove and Tim Jarratt
620e3f5992 Run docs tests under phantomjs 2013-10-04 13:32:56 -07:00
Gregg Van Hove and Tim Jarratt
ea76a30d85 Update standalone distributions
[#30296755]
2013-10-04 12:28:27 -07:00
Gregg Van Hove and Tim Jarratt
adde1b4a5b Doc js files from jasmine.github.io should be part of CI build
[Finish #50572569]
2013-10-04 12:10:38 -07:00
Gregg Van Hove and Tim Jarratt
07e7ad2314 Update jasmine_favicon.png
Using the new image from google drive. It's 32x32px but browsers should
be able to downsize that to 16x16 if they need to

[Finish #57170588]
2013-10-04 10:55:01 -07:00
Davis W. Frank
706180ad01 2.0 rc3 release notes 2013-10-03 16:36:08 -07:00
Davis W. Frank
547c9cfde9 Adding Anchorman back in as a dependency 2013-10-03 16:35:56 -07:00
Gregg Van Hove and Tim Jarratt
d3ec12e62a buildStandaloneDist should also build jasmine.js 2013-10-03 15:28:42 -07:00
Gregg Van Hove and Tim Jarratt
749c15fe07 Bump version to rc3 in jasmine.js 2013-10-03 15:28:26 -07:00
Gregg Van Hove and Tim Jarratt
7e071547f5 Custom matchers fail to behave as expected
If they return false, that should be respected.

Submitted via @tjgrathwell

[Finish #58184156]
close #434
2013-10-03 15:13:27 -07:00
Gregg Van Hove
6354ee17e5 Merge pull request #439 from tjarratt/pull_request_travis
Don't try to use SauceLabs on pull request builds
2013-10-03 12:32:32 -07:00
Gregg Van Hove and Tim Jarratt
255a50baee Update contribution guidelines for pull requests
[Finish #45961121]
2013-10-03 12:30:07 -07:00
Tim Jarratt
520a8c85a2 Don't bother trying to still use firefox 2013-10-03 12:07:57 -07:00
Gregg Van Hove and Tim Jarratt
6de355544f Make firefox with Sauce explicitly the default test
Apparently Travis-ci will create a default test separate from your
matrix includes and this resulted in some testrun duplication.
2013-10-03 11:44:48 -07:00
Gregg Van Hove and Tim Jarratt
95572fb314 Don't try to use SauceLabs on pull request builds 2013-10-03 11:24:57 -07:00
Mike Stay
ffa6138d75 Make getGlobal() work in strict mode
An update of fb3e1acb09

ES5 strict mode does not promote an undefined 'this' to the global object.  The only way to get the global object in strict mode is to say 'this' while in the global scope.
2013-10-02 12:38:25 -06:00
75 changed files with 2183 additions and 1687 deletions

9
.jshintrc Normal file
View File

@@ -0,0 +1,9 @@
{
"bitwise": true,
"curly": true,
"freeze": true,
"immed": true,
"newcap": true,
"trailing": true,
"loopfunc": true
}

View File

@@ -7,6 +7,9 @@ env:
- USE_SAUCE=true
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
- TEST_COMMAND="bash travis-core-script.sh"
- JASMINE_BROWSER="firefox"
- SAUCE_OS="Linux"
- SAUCE_BROWSER_VERSION=''
- secure: WSPWhlnC4mWSnSPquX+m1/BCu5ch5NygkaHuM2Nea7lD8oS3XLX8QncZZAsQ4lnNfqoDDuBOizG0AESiqNvE4y6x5qvLLTS6q+ce255ZEMZ71TBdZgDEEvGMEjOPPsVXiXyTQOP1lwOPlrbZvaPgWV7e11KIBab6DfFcQpnvDgo=
- secure: SW7CJhZnwaNT749Gdnhvqb5rbXlAOsygUAzh9qhtyvbqXKkmJdBIEsO01YF6pbju1X2twE9JvWCOxeZju43NgQChJlPsGbjY2j3k/TdQeTAJesQe2K7ytwghunI30gjEovtRH0T3w1EmcKPH8yj5eBIcB2OYoJHx8KEC7e68q1g=
matrix:
@@ -14,11 +17,7 @@ matrix:
- env:
- USE_SAUCE=false
- TEST_COMMAND="bash travis-node-script.sh"
- env:
- JASMINE_BROWSER="firefox"
- SAUCE_OS="Linux"
- SAUCE_BROWSER_VERSION=''
- env:
- env:
- JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.8"
- SAUCE_BROWSER_VERSION=6
@@ -26,22 +25,26 @@ matrix:
- JASMINE_BROWSER="safari"
- SAUCE_OS="OS X 10.6"
- SAUCE_BROWSER_VERSION=5
- env:
- env:
- JASMINE_BROWSER="internet explorer"
- SAUCE_OS="Windows 8"
- SAUCE_BROWSER_VERSION=10
- env:
- env:
- JASMINE_BROWSER="internet explorer"
- SAUCE_OS="Windows 7"
- SAUCE_BROWSER_VERSION=9
- env:
- env:
- JASMINE_BROWSER="internet explorer"
- SAUCE_OS="Windows 7"
- SAUCE_BROWSER_VERSION=8
- env:
- env:
- JASMINE_BROWSER="chrome"
- SAUCE_OS="Linux"
- SAUCE_BROWSER_VERSION=''
- env:
- env:
- JASMINE_BROWSER="phantomjs"
- USE_SAUCE=false
- env:
- USE_SAUCE=false
- JASMINE_BROWSER="phantomjs"
- TEST_COMMAND="bash travis-docs-script.sh"

View File

@@ -107,5 +107,10 @@ Jasmine uses Node.js with a custom runner to test outside of a browser.
1. Ensure JSHint is green with `grunt jsHint`
1. Build `jasmine.js` with `grunt buildDistribution` and run all specs again - this ensures that your changes self-test well
## Submitting a Pull Request
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches.
1. When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master.
Note that we use Travis for Continuous Integration. We only accept green pull requests.

View File

@@ -10,3 +10,5 @@ end
gemspec
gem "jasmine_selenium_runner", :git => 'https://github.com/jasmine/jasmine_selenium_runner.git'
gem "anchorman"

View File

@@ -1,11 +1,11 @@
<a name="README">[Jasmine](http://pivotal.github.com/jasmine/)</a> [![Build Status](https://travis-ci.org/pivotal/jasmine.png?branch=master)](https://travis-ci.org/pivotal/jasmine)
<a name="README">[Jasmine](http://pivotal.github.com/jasmine/)</a> [![Build Status](https://travis-ci.org/pivotal/jasmine.png?branch=master)](https://travis-ci.org/pivotal/jasmine) [![Code Climate](https://codeclimate.com/repos/5269970a13d6374b6c01d632/badges/8bc25526da64e02065f4/gpa.png)](https://codeclimate.com/repos/5269970a13d6374b6c01d632/feed)
=======
**A JavaScript Testing Framework**
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
Documentation & guides live here: [http://pivotal.github.com/jasmine/](http://pivotal.github.com/jasmine/)
Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/)
## Contributing
@@ -22,6 +22,10 @@ Please read the [contributors' guide](https://github.com/pivotal/jasmine/blob/ma
* [Davis W. Frank](mailto:dwfrank@pivotallabs.com), Pivotal Labs
* [Rajan Agaskar](mailto:rajan@pivotallabs.com), Pivotal Labs
* [Sheel Choksi](mailto:schoksi@pivotallabs.com), Pivotal Labs
### Maintainers Emeritus
* [Christian Williams](mailto:antixian666@gmail.com), Square
Copyright (c) 2008-2013 Pivotal Labs. This software is licensed under the MIT License.

View File

@@ -9,7 +9,7 @@ load "jasmine/tasks/jasmine.rake"
namespace :jasmine do
task :set_env do
ENV['JASMINE_CONFIG_PATH'] = 'spec/support/jasmine.yml'
ENV['JASMINE_CONFIG_PATH'] ||= 'spec/support/jasmine.yml'
end
end

BIN
dist/jasmine-standalone-1.3.1.zip vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
dist/jasmine-standalone-2.0.0-rc5.zip vendored Normal file

Binary file not shown.

BIN
dist/jasmine-standalone-2.0.0.zip vendored Normal file

Binary file not shown.

View File

@@ -1,7 +1,8 @@
var standaloneLibDir = "lib/jasmine-" + jasmineVersion;
function root(path) { return "./" + path; }
function lib(path) { return root("lib/jasmine-core/" + path); }
function libJasmineCore(path) { return root("lib/jasmine-core/" + path); }
function libConsole() { return "lib/console/" }
function dist(path) { return root("dist/" + path); }
module.exports = {
@@ -26,13 +27,21 @@ module.exports = {
],
dest: standaloneLibDir,
expand: true,
cwd: lib("")
cwd: libJasmineCore("")
},
{
src: [
"console.js"
],
dest: standaloneLibDir,
expand: true,
cwd: libConsole()
},
{
src: [ "boot.js" ],
dest: standaloneLibDir,
expand: true,
cwd: lib("boot")
cwd: libJasmineCore("boot")
},
{
src: [ "SpecRunner.html" ],
@@ -44,13 +53,13 @@ module.exports = {
src: [ "*.js" ],
dest: "src",
expand: true,
cwd: lib("example/src/")
cwd: libJasmineCore("example/src/")
},
{
src: [ "*.js" ],
dest: "spec",
expand: true,
cwd: lib("example/spec/")
cwd: libJasmineCore("example/spec/")
}
]
}

View File

@@ -44,7 +44,7 @@ module.exports = {
'src/console/requireConsole.js',
'src/console/ConsoleReporter.js'
],
dest: 'src/console/console.js'
dest: 'lib/console/console.js'
},
options: {
banner: license(),
@@ -54,4 +54,4 @@ module.exports = {
}
}
}
};
};

View File

@@ -5,13 +5,7 @@ module.exports = {
'lib/jasmine-core/jasmine.js'
],
options: {
/* While it's possible that we could be considering unwanted prototype methods, mostly
* we're doing this because the objects are being used as maps.
*/
forin: false,
/* We're fine with functions defined inside loops (setTimeout functions, etc) */
loopfunc: true
jshintrc: '.jshintrc'
},
all: ['src/**/*.js']
};
};

View File

@@ -1,7 +1,7 @@
var grunt = require("grunt");
function standaloneTmpDir(path) { return "dist/tmp/" + path; }
grunt.registerTask("build:compileSpecRunner",
"Processes the spec runner template and writes to a tmp file",
function() {
@@ -23,6 +23,7 @@ grunt.registerTask("build:cleanSpecRunner",
grunt.registerTask("buildStandaloneDist",
"Builds a standalone distribution",
[
"buildDistribution",
"build:compileSpecRunner",
"compress:standalone",
"build:cleanSpecRunner"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
s.add_development_dependency "rake"
s.add_development_dependency "sauce-connect"
s.add_development_dependency "jasmine_selenium_runner"
s.add_development_dependency "compass"
end

View File

@@ -50,10 +50,10 @@ getJasmineRequireObj().ConsoleReporter = function() {
failedSpecs = [],
pendingCount,
ansi = {
green: '\033[32m',
red: '\033[31m',
yellow: '\033[33m',
none: '\033[0m'
green: '\x1B[32m',
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
};
this.jasmineStarted = function() {

View File

@@ -20,13 +20,40 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Jasmine boot.js for browser runners - exposes external/global interface, builds the Jasmine environment and executes it.
/**
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(function() {
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
window.jasmine = jasmineRequire.core(jasmineRequire);
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = {
describe: function(description, specDefinitions) {
return env.describe(description, specDefinitions);
@@ -60,37 +87,64 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
return env.pending();
},
addMatchers: function(matchers) {
return env.addMatchers(matchers);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
clock: env.clock,
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
})
};
/**
* Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
if (typeof window == "undefined" && typeof exports == "object") {
extend(exports, jasmineInterface);
} else {
extend(window, jasmineInterface);
}
/**
* Expose the interface for adding custom equality testers.
*/
jasmine.addCustomEqualityTester = function(tester) {
env.addCustomEqualityTester(tester);
};
/**
* Expose the interface for adding custom expectation matchers
*/
jasmine.addMatchers = function(matchers) {
return env.addMatchers(matchers);
};
/**
* Expose the mock interface for the JavaScript timeout functions
*/
jasmine.clock = function() {
return env.clock;
};
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
// TODO: move all of catching to raise so we don't break our brains
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
queryString: queryString,
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
@@ -98,9 +152,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
timer: new jasmine.Timer()
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
@@ -109,6 +169,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
return specFilter.matches(spec.getFullName());
};
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
@@ -119,6 +192,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;

View File

@@ -1,10 +1,37 @@
// Jasmine boot.js for browser runners - exposes external/global interface, builds the Jasmine environment and executes it.
/**
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(function() {
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
window.jasmine = jasmineRequire.core(jasmineRequire);
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = {
describe: function(description, specDefinitions) {
return env.describe(description, specDefinitions);
@@ -38,37 +65,64 @@
return env.pending();
},
addMatchers: function(matchers) {
return env.addMatchers(matchers);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
clock: env.clock,
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
})
};
/**
* Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
if (typeof window == "undefined" && typeof exports == "object") {
extend(exports, jasmineInterface);
} else {
extend(window, jasmineInterface);
}
/**
* Expose the interface for adding custom equality testers.
*/
jasmine.addCustomEqualityTester = function(tester) {
env.addCustomEqualityTester(tester);
};
/**
* Expose the interface for adding custom expectation matchers
*/
jasmine.addMatchers = function(matchers) {
return env.addMatchers(matchers);
};
/**
* Expose the mock interface for the JavaScript timeout functions
*/
jasmine.clock = function() {
return env.clock;
};
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
// TODO: move all of catching to raise so we don't break our brains
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
queryString: queryString,
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
@@ -76,9 +130,15 @@
timer: new jasmine.Timer()
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
@@ -87,6 +147,19 @@
return specFilter.matches(spec.getFullName());
};
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
@@ -97,6 +170,9 @@
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;

View File

@@ -1,15 +1,15 @@
beforeEach(function () {
jasmine.Expectation.addMatchers({
toBePlaying: function () {
return {
compare: function (actual, expected) {
var player = actual;
jasmine.addMatchers({
toBePlaying: function () {
return {
compare: function (actual, expected) {
var player = actual;
return {
pass: player.currentlyPlayingSong === expected && player.isPlaying
}
}
};
return {
pass: player.currentlyPlayingSong === expected && player.isPlaying
}
}
});
};
}
});
});

View File

@@ -26,11 +26,12 @@ jasmineRequire.html = function(j$) {
j$.QueryString = jasmineRequire.QueryString();
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
};
jasmineRequire.HtmlReporter = function(j$) {
var noopTimer = {
start: function(){},
elapsed: function(){ return 0; }
start: function() {},
elapsed: function() { return 0; }
};
function HtmlReporter(options) {
@@ -101,7 +102,8 @@ jasmineRequire.HtmlReporter = function(j$) {
symbols.appendChild(createDom("li", {
className: result.status,
id: "spec_" + result.id,
title: result.fullName}
title: result.fullName
}
));
if (result.status == "failed") {
@@ -307,6 +309,7 @@ jasmineRequire.ResultsNode = function() {
return ResultsNode;
};
jasmineRequire.QueryString = function() {
function QueryString(options) {

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,6 @@
#
module Jasmine
module Core
VERSION = "2.0.0.rc3"
VERSION = "2.0.0"
end
end

View File

@@ -1,13 +1,17 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "2.0.0-rc3",
"version": "2.0.0",
"repository": {
"type": "git",
"url": "https://github.com/pivotal/jasmine.git"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.2.0",
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-compass": "~0.1.3",
"grunt-contrib-compress": "~0.4.1",
"shelljs": "~0.1.2"
"grunt-contrib-jshint": "~0.7.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-compass": "~0.6.0",
"grunt-contrib-compress": "~0.5.2",
"shelljs": "~0.1.4"
}
}

179
release_notes/20.md Normal file
View File

@@ -0,0 +1,179 @@
# Jasmine Core 2.0 Release Notes
## Summary
These notes are for Jasmine Core 2.0.
## Breaking Changes
The [`introduction.js`][intro] page covers the current syntax, highlighting the changes. Here are the known interface changes that are not backwards compatible with 1.x.
* New syntax for asynchronous specs
* New syntax for spies
* New interface for reporters
* Better Equality testing
* Replaced custom matchers for ease of use
* Change to `toThrow` matcher
* Clock now remains installed when a spec finishes
* More Jasmine internal variables/functions have been moved into closures
### New syntax for asynchronous specs
Similar to [Mocha][mocha], Jasmine `before`s, `spec`s, and `after`s can take an optional `done` callback in order to force asynchronous tests. The next function, whether it's a `before`, `spec` or `after`, will wait until this function is called or until a timeout is reached.
### New syntax for spies
Spies have a slightly modified syntax. The idea came from a desire to preserve any of the properties on a spied-upon function and some better testing patterns.
### New interface for reporters
The reporter interface has been **replaced**. The callbacks are different and more consistent. The objects passed in should only provide what is needed to report results. This enforces an interface to result data so custom reporters will be less coupled to the Jasmine implementation. The Jasmine reporter API now includes a slot for a `timer` object.
### Better Equality testing
We removed the previous equality code and are now using new code for testing equality. We started with [Underscore.js][underscore]'s `isEqual`, refactored a bit and added some additional tests.
### Replaced custom matchers for ease of use
The interface for adding custom matchers has been **replaced**. It has always been possible to add custom matchers, but the API was barely documented and difficult to test. We've changed how matchers are added and tested. Jasmine adds its own matchers by the same mechanism that custom matchers use. Dogfooding FTW.
### Change to `toThrow` matcher
We've changed the behavior of the `toThrow` matcher, moving some functionality to the `toThrowError` matcher. This should allow more of the requested use cases.
### Clock now remains installed when a spec finishes
After installing the Jasmine Clock, it will stay installed until `uninstall` is called -- clearing up any ambiguity for when those timing functions will revert to using the global clock object.
## More Jasmine internal variables/functions have been moved into closures
Certain variables/functions like a function to get the next spec id have been moved into closures, making the Jasmine interface cleaner.
## Other Changes
* Massive refactoring and better testing
* Environment setup now in `boot.js`
* Development and Build moved to Grunt
* Changes to how Jasmine is loaded
* Changes to how Jasmine is tested
* Better node.js support
* Better Continuous Integration Environment at Travis
* Support matrix updated
* Removed JsDoc Pages
* Adding Code Climate for JavaScript
## Massive refactoring and better testing
This is the biggest set of changes. We've touched nearly every file and every object. We've merged objects together and factored out code. We styled the code more consistently. We've improved nearly every test.
In general, Jasmine is made of smaller, more-loosely-coupled objects, unit-tested with explicit dependencies injected. This made tests easier to read, write, and maintain. We know this has made Jasmine development easier for the core team. We expect (and hope) this makes it easier for the community to extend Jasmine and provide pull requests that make more sense the first time out.
## Environment setup now in `boot.js`
Instantiation and setup of the Jasmine environment, including building reporters, exposing the "global" functions, and executing tests has moved into its own file: `boot.js`. This should make it easier to add custom reporters, configure some objects, or just in general change how you use Jasmine from the outside.
For example, during development, Jasmine uses its own `devboot.js` to load itself twice - once from `jasmine.js` and once from the source directories.
## Development and Build moved to Grunt
We've moved away from Ruby and embraced [Node.js][node] and [Grunt.js][grunt] for the various command line tasks during development. Yes, it's a just a different set of dependencies. But it's less code for the team to maintain - it turns out that JavaScript tools are pretty good at building JavaScript projects. This will make it easier for the community to make sure contributions work in browsers and in Node.js before submitting Pull Requests. There is more detail in the [Contributor's Guide][contrib].
## Changes to how Jasmine is loaded
We did not want to add new run-time dependencies, yet we needed to be cleaner when loading Jasmine. So we wrote a custom "require" scheme that works in Node.js and in browsers. This only affects pull requests which add files - please be careful in these cases. Again, the [Contributor's Guide][contrib] should help.
## Changes to how Jasmine is tested with Jasmine
Writing a custom require system helped enforce self-testing - the built `jasmine.js` testing Jasmine from the source directories. Overall this has improved the stability of the code. When you look at Jasmine's tests, you'll see both `jasmine` and `j$` used. The former, `jasmine`, will always be used to test the code from source, which is loaded into the reference `j$`. Please adhere to this pattern when writing tests for contributions.
## Better node.js support
`Node.js` is now officially a first-class citizen. For a long time we've made sure tests were green in Node before releasing. But it is now officially part of Jasmine's CI build at [Travis][travis]. For the curious, the [`node_suite.js`][node_suite], is essentially a `boot.js` for Node. An official `npm` is coming.
## Better Continuous Integration Environment at Travis
The [CI build at Travis][travis_jasmine] now runs the core specs in a build matrix across browsers. It's far from complete on the operating system matrix, but you will see that Jasmine runs against: Firefox, Chrome, Safari 5, Safari 6, [Phantom.js][phantom], [Node.js][node], and IE versions 8, 9, and 10. Big thanks to [SauceLabs][sauce] for their support of open source projects. We will happily take pull requests for additional OS/Browser combos within the matrix.
## Support Matrix Updated
We're dropping support for IE < 8. [Jasmine 1.x][jasmine_downloads] remains for projects that need to support older browsers.
## Removed JsDoc Pages
Comments in code are lies waiting to happen. Jasmine's JsDoc comments were no exception. The comments were out of date, the generated pages were even more out of date, and frankly they were not helpful. So they're gone.
Last year saw the posting of the [`introduction.js`][intro] page to document the real, practical interface for projects to use. This page has received a lot of positive feedback so expect more pages like this one.
## Adding Code Climate for JavaScript
We are running Code Climate for Jasmine. We have some work to do here but it's helping us easily find code hotspots.
## Pull Requests and Issues
The following Pull Requests were merged:
* ObjectContaining wrong filed value error message #[394](https://github.com/pivotal/jasmine/issues/394) from albertandrejev
* Removed unnecessary parameter from `suiteFactory()` call #[397](https://github.com/pivotal/jasmine/issues/397) from valera-rozuvan
* `jasmine.Any` supports `Boolean` #[392](https://github.com/pivotal/jasmine/issues/392) from albertandrejev
* Reporters get execution time #[30](https://github.com/pivotal/jasmine/issues/30)
* `toThrow` matchers handle falsy exceptions #[317](https://github.com/pivotal/jasmine/issues/371)
* Removed deprecated `jasmine.Matchers.pp` #[363](https://github.com/pivotal/jasmine/issues/363) from robinboehm
* Fix for Clock ticking to default to 0 #[340](https://github.com/pivotal/jasmine/issues/340) from Caio Cunha
* Whitespace failures should be easier to understand #[332](https://github.com/pivotal/jasmine/issues/332) from bjornblomqvist
* Fix for more markdown-y image for Build status #[329](https://github.com/pivotal/jasmine/issues/329) from sunliwen
* UTF-8 encoding fixes #[333](https://github.com/pivotal/jasmine/issues/333) from bjornblomqvist
* Replaced deprecated octal literal with hexadecimal from kris7t
* Make getGlobal() work in strict mode from metaweta
* Clears timeout timer even when async spec throws an exception from tidoust
* Timeouts scheduled within a delayed function are correctly scheduled and executed from maciej-filip-sz
### Bug Fixes
* Improved the performance of the HTML output with a CSS change #[428](https://github.com/pivotal/jasmine/issues/428) - Thanks @tjgrathwell
* Removed an accidental global pollution of `j$` as a reference to Jasmine. Thanks to Morten Maxild from the mailing list
* There is now a consistent `this` between `beforeEach`, `it` and `afterEach` for a spec
* A spy's strategy now has properties `returnValue` and `throwError` because they are better names
* Make it easy to copy the title of failing specs from the HTML output
* Don't add periods to the full name of a spec fix #[427](https://github.com/pivotal/jasmine/issues/427)
* Allow Env to take optional spec/suite ids when asked to `execute`
* [Mock clock now less intrusive, replacing global timer functions only when clock is installed](http://www.pivotaltracker.com/story/54168708)
* Restore custom failure messages for `toHaveBeenCalledWith`
* Jasmine global object has a addCustomEqualityTester and addMatchers (no longer directly on global)
* Fixed a global leak of `timer`
* Remove currentRunner from Env (users can use topSuite from Env instead)
* [Specs without expectations are now considered passing](http://www.pivotaltracker.com/story/59422744)
* Improve error message when a spec does not call the async callback within the default time interval
* Allow passing a negativeCompare in a custom matcher for more custom implementations when `.not` is called
* Update favicon to be higher resolution
* Make all async functions be subject to the timeout
There were several other pull requests that either had already been fixed, or were good starting points for the various changes above. Thank you for all of the hard work to keep Jasmine awesome.
## Other Bugs and Features
There were a few small changes and fixes that didn't fit into any of the above categories:
* HTML Reporter refactored for simplicity and performance
* Default character encoding on the HTML runner page is UTF-8
* [Escape special regex characters from the spec param](http://www.pivotaltracker.com/story/52731407)
* Favicon returns
* [Clock supports `eval`'d strings as functions](http://www.pivotaltracker.com/story/40853563)
* There should always be stack traces on failures
* Removed references to unused `jasmine.VERBOSE`
* Removed references to unused `jasmine.XmlHttpRequest`
[mocha]: http://visionmedia.github.io/mocha/
[underscore]: http://underscorejs.org/
[grunt]: http://gruntjs.com
[node]: http://nodejs.org
[phantom]: http://phantomjs.org
[jasmine_downloads]: https://github.com/pivotal/jasmine/downloads
[contrib]: https://github.com/pivotal/jasmine/blob/master/CONTRIBUTING.md
[travis]: http://travis-ci.org
[travis_jasmine]: http://travis-ci.org/jasmine
[sauce]: http://saucelabs.com
[node_suite]: https://github.com/pivotal/jasmine/blob/master/spec/node_suite.js
[intro]: http://jasmine.github.io/2.0/introduction.html
------
_Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_

View File

@@ -1,138 +0,0 @@
# Jasmine Core 2.0 Release Notes
## Summary
These notes are for RC1 of Jasmine Core 2.0.
## Breaking Changes
These changes have breaking interface changes and are not backwards compatible with 1.x.
* New syntax for asynchronous specs
* New syntax for spies
* New interface for reporters
* Better Equality testing
* Easier custom matchers
* Change to `toThrow` matcher
### New syntax for asynchronous specs
Similar to [Mocha][mocha], Jasmine befores, specs, and afters can take an optional "done" callback in order to force asynchronous tests. The next function, whether it's a before, spec or after, will wait until this function is called or if a timeout is reached.
### New syntax for spies
Spies have a slightly modified syntax. The ideas came from a desire to preserve any of the properties on a spied-upon function and some better testing patterns.
### New interface for reporters
The reporter interface has changed. The callbacks are different and more consistent. The objects passed in should only provide what is needed to report results. This enforces an interface to result data so custom reporters will be less coupled to Jasmine implementation. The full suite execution time is also reported.
### Better Equality testing
We have tossed the previous equality code and are now using new code for testing equality. We started with [Underscore.js][underscore]'s `isEqual`, refactored a bit and added some additional tests.
### Easier custom matchers
Custom matchers have always been possible, but this was barely documented and clunky to test. We've changed how matchers are added and tested. Jasmine adds its own matchers by the same mechanism that as custom matchers use. Dogfooding FTW.
### Change to `toThrow` matcher
We've changed the behavior of the `toThrow` matcher, moving some functionality to the `toThrowError` matcher. This should allow more of the requested use cases.
## Other Changes
* Massive refactoring and better testing
* Environment setup now in `boot.js`
* Development & Build moved to Grunt
* Change in how Jasmine is loaded
* Change in how Jasmine is tested
* Better node.js support
* Better Continuous Integration Environment at Travis
* Support matrix updated
* Removed JsDoc Pages
## Massive refactoring and better testing
This is the biggest set of changes. We've touched nearly every file and every object. We've slammed objects back together and pulled out new extractions. We've made the code more consistently styled. We've improved the tests nearly everywhere.
In general, Jasmine is made of smaller, more-loosely-coupled objects, unit-tested with explicit dependencies injected. This made tests easier to write, read, and maintain. We know this has made Jasmine development easier for the core team. We expect (and hope) this makes it easier for the community to extend Jasmine and provide pull requests that make more sense the first time out.
## Environment setup now in `boot.js`
Instantiation and setup of the Jasmine environment, including building reporters, exposing the "global" functions, and executing tests has moved into its own file: `boot.js`. This should make it easier to add custom reporters, configure some objects, or just in general change how you use Jasmine from the outside.
For example, during development, Jasmine uses it's own `devboot.js` to load itself twice - once from `jasmine.js` and once from the source directories.
## Development & Build moved to Grunt
We've moved away from Ruby and embraced Node.js and [Grunt.js][grunt] for the various command line tasks during development. Yes, it's a just a different set of dependencies. But it's less code for the team to maintain - it turns out that JavaScript tools are pretty good at building JavaScript projects. This will make it easier for the community to make sure contributions work in browser and in Node.js before submitting Pull Requests. There is more detail in the [Contributor's Guide][contrib].
## Change in how Jasmine is loaded
We did not want to add new run-time dependencies, yet we needed to be cleaner when loading Jasmine. So we wrote a custom "require" scheme that works in Node.js and in browsers. This only affects pull requests that add files - please be careful in these cases. Again, the [Contributor's Guide][contrib] should help.
## Change in how Jasmine is tested with Jasmine
Writing a custom require system helped enforce self-testing - the built `jasmine.js` testing Jasmine from the source directories. Overall this has improved the stability of the code. When you look at Jasmine's tests, you'll see both `jasmine` and `j$` used. The former, `jasmine`, will always be used to test the code from source, which is loaded into the reference `j$`. Please adhere to this pattern when writing tests for contributions.
## Better node.js support
Node.js is now officially a first-class citizen. For a long time we've made sure tests were green in Node before releasing. But it is now officially part of Jasmine's CI build at [Travis][travis]. For the curious, the [`node_suite.js`][node_suite], is essentially a `boot.js` for Node. An official npm is coming.
## Better Continuous Integration Environment at Travis
The [CI build at Travis][travis_jasmine] now runs the core specs in a build matrix across browsers. It's far from complete on the operating system matrix, but you will see that Jasmine runs against: Firefox, Chrome, Safari 5, Safari 6, Phantom.js, Node.js, and IE versions 8, 9, and 10. Big thanks to [SauceLabs][sauce] for their support of open source projects. We will happily take pull requests for additional OS/Browser combos within the matrix.
## Support Matrix Updated
We're dropping support for IE < 8. Jasmine 1.x remains for projects supporting earlier versions of browsers.
## Removed JsDoc Pages
Comments in code are lies waiting to happen. Jasmine's JsDoc comments were no exception. The comments were out of date, the generated pages were even more out of date, and frankly they were not helpful. So they're gone.
Last year saw the posting of the [`introduction.js`][intro] page to document the real, practical interface for projects to use. This page has received a lot of positive feedback so expect more pages like this one.
## Pull Requests & Issues
The following Pull Requests were merged:
* ObjectContaining wrong filed value error message #[394](https://github.com/pivotal/jasmine/issues/394) from albertandrejev
* Removed unnecessary parameter from `suiteFactory()` call #[397](https://github.com/pivotal/jasmine/issues/397) from valera-rozuvan
* `jasmine.Any` supports `Boolean` #[392](https://github.com/pivotal/jasmine/issues/392) from albertandrejev
* Reporters get execution time #[30](https://github.com/pivotal/jasmine/issues/30)
* `toThrow` matchers handle falsy exceptions #[317](https://github.com/pivotal/jasmine/issues/371)
* Removed deprecated `jasmine.Matchers.pp` #[363](https://github.com/pivotal/jasmine/issues/363) from robinboehm
* Fix for Clock ticking to default to 0 #[340](https://github.com/pivotal/jasmine/issues/340) from Caio Cunha
* Whitespace failures should be easier to understand #[332](https://github.com/pivotal/jasmine/issues/332) from bjornblomqvist
* Fix for more markdown-y image for Build status #[329](https://github.com/pivotal/jasmine/issues/329) from sunliwen
* UTF-8 encoding fixes #[333](https://github.com/pivotal/jasmine/issues/333) from bjornblomqvist
There were several other pull requests that either had already been fixed, or were good starting points for the various changes above. Thank you for all of the hard work to keep Jasmine awesome.
## Other Bugs & Features
There were a few small changes and fixes that didn't fit into any of the above categories:
* HTML Reporter refactored for simplicity and performance
* Default character encoding on the HTML runner page is UTF-8
* [Escape special regex characters from the spec param](http://www.pivotaltracker.com/story/52731407)
* Favicon returns
* [Clock supports `eval`'d strings as functions](http://www.pivotaltracker.com/story/40853563)
* There should always be stack traces on failures
* Removed references to unused `jasmine.VERBOSE`
* Removed references to unused `jasmine.XmlHttpRequest`
------
_Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_
[mocha]: http://visionmedia.github.io/mocha/
[underscore]: http://underscorejs.org/
[grunt]: http://gruntjs.com
[contrib]: https://github.com/pivotal/jasmine/blob/master/Contribute.markdown
[travis]: http://travis-ci.org
[travis_jasmine]: http://travis-ci.org/jasmine
[sauce]: http://saucelabs.com
[node_suite]: https://github.com/pivotal/jasmine/blob/master/spec/node_suite.js
[intro]: http://pivotal.github.com/jasmine/

View File

@@ -80,7 +80,7 @@ describe("ConsoleReporter", function() {
expect(out.getOutput()).toEqual("*");
});
it("reports a summary when done (singluar spec and time)", function() {
it("reports a summary when done (singular spec and time)", function() {
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
reporter = new j$.ConsoleReporter({
print: out.print,
@@ -198,7 +198,7 @@ describe("ConsoleReporter", function() {
reporter.specDone({status: "passed"});
expect(out.getOutput()).toEqual("\033[32m.\033[0m");
expect(out.getOutput()).toEqual("\x1B[32m.\x1B[0m");
});
it("does not report a disabled spec", function() {
@@ -220,7 +220,7 @@ describe("ConsoleReporter", function() {
reporter.specDone({status: 'failed'});
expect(out.getOutput()).toEqual("\033[31mF\033[0m");
expect(out.getOutput()).toEqual("\x1B[31mF\x1B[0m");
});
});
});

View File

@@ -42,4 +42,4 @@ describe("Any", function() {
expect(any.jasmineToString()).toMatch('<jasmine.any');
});
});
});

View File

@@ -342,23 +342,18 @@ describe("Clock (acceptance)", function() {
expect(delayedFn2).toHaveBeenCalled();
});
it("calls the global clearTimeout correctly when not installed", function() {
var delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['clearTimeout']),
global = jasmine.getGlobal(),
clock = new j$.Clock(global, delayedFunctionScheduler);
it("correctly calls functions scheduled while the Clock is advancing", function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler);
expect(function() {
clock.clearTimeout(123)
}).not.toThrow();
});
delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 1); });
clock.install();
clock.setTimeout(delayedFn1, 5);
it("calls the global clearTimeout correctly when not installed", function() {
var delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['clearTimeout']),
global = jasmine.getGlobal(),
clock = new j$.Clock(global, delayedFunctionScheduler);
expect(function() {
clock.clearInterval(123)
}).not.toThrow();
clock.tick(6);
expect(delayedFn1).toHaveBeenCalled();
expect(delayedFn2).toHaveBeenCalled();
});
});

View File

@@ -1,96 +0,0 @@
////TODO: matchers should be add-able to the env, not to the spec.
//describe("Custom Matchers", function() {
// var env;
// var fakeTimer;
//
// beforeEach(function() {
// env = new jasmine.Env();
// env.updateInterval = 0;
// });
//
// it("should be easy to add more matchers local to a spec, suite, etc.", function() {
// var spec1, spec2, spec1Matcher, spec2Matcher;
// var suite = env.describe('some suite', function() {
// env.beforeEach(function() {
// this.addMatchers({
// matcherForSuite: function(expected) {
// this.message = "matcherForSuite: actual: " + this.actual + "; expected: " + expected;
// return true;
// }
// });
// });
//
// spec1 = env.it('spec with an expectation').runs(function () {
// this.addMatchers({
// matcherForSpec: function(expected) {
// this.message = "matcherForSpec: actual: " + this.actual + "; expected: " + expected;
// return true;
// }
// });
// spec1Matcher = this.expect("xxx");
// });
//
// spec2 = env.it('spec with failing expectation').runs(function () {
// spec2Matcher = this.expect("yyy");
// });
// });
//
// suite.execute();
//
// spec1Matcher.matcherForSuite("expected");
// expect(spec1Matcher.message).toEqual("matcherForSuite: actual: xxx; expected: expected");
// spec1Matcher.matcherForSpec("expected");
// expect(spec1Matcher.message).toEqual("matcherForSpec: actual: xxx; expected: expected");
//
// spec2Matcher.matcherForSuite("expected");
// expect(spec2Matcher.message).toEqual("matcherForSuite: actual: yyy; expected: expected");
// expect(spec2Matcher.matcherForSpec).toBe(jasmine.undefined);
// });
//
// it("should generate messages with the same rules as for regular matchers when this.report() is not called", function() {
// var spec;
// var suite = env.describe('some suite', function() {
// spec = env.it('spec with an expectation').runs(function () {
// this.addMatchers({
// toBeTrue: function() {
// return this.actual === true;
// }
// });
// this.expect(true).toBeTrue();
// this.expect(false).toBeTrue();
// });
// });
//
// suite.execute();
//
// var results = spec.results().getItems();
// expect(results[0].message).toEqual("Passed.");
// expect(results[1].message).toEqual("Expected false to be true.");
// });
//
// it("should pass args", function() {
// var matcherCallArgs = [];
// var spec;
// var suite = env.describe('some suite', function() {
// spec = env.it('spec with an expectation').runs(function () {
// this.addMatchers({
// toBeTrue: function() {
// matcherCallArgs.push(jasmine.util.argsToArray(arguments));
// return this.actual === true;
// }
// });
// this.expect(true).toBeTrue();
// this.expect(false).toBeTrue('arg');
// this.expect(true).toBeTrue('arg1', 'arg2');
// });
// });
//
// suite.execute();
// var results = spec.results().getItems();
// expect(results[0].expected).toEqual(jasmine.undefined);
// expect(results[1].expected).toEqual('arg');
// expect(results[2].expected).toEqual(['arg1', 'arg2']);
//
// expect(matcherCallArgs).toEqual([[], ['arg'], ['arg1', 'arg2']]);
// });
//});

View File

@@ -175,5 +175,72 @@ describe("DelayedFunctionScheduler", function() {
expect(fn).toHaveBeenCalled();
});
it("schedules a function for later execution during a tick", function () {
var scheduler = new j$.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10;
scheduler.scheduleFunction(function () {
scheduler.scheduleFunction(fn, fnDelay);
}, 0);
expect(fn).not.toHaveBeenCalled();
scheduler.tick(fnDelay);
expect(fn).toHaveBeenCalled();
});
it("#removeFunctionWithId removes a previously scheduled function with a given id during a tick", function () {
var scheduler = new j$.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
fnDelay = 10,
timeoutKey;
scheduler.scheduleFunction(function () {
scheduler.removeFunctionWithId(timeoutKey);
}, 0);
timeoutKey = scheduler.scheduleFunction(fn, fnDelay);
expect(fn).not.toHaveBeenCalled();
scheduler.tick(fnDelay);
expect(fn).not.toHaveBeenCalled();
});
it("executes recurring functions interleaved with regular functions and functions scheduled during a tick in the correct order", function () {
var scheduler = new j$.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'),
recurringCallCount = 0,
recurring = jasmine.createSpy('recurring').and.callFake(function() {
recurringCallCount++;
if (recurringCallCount < 5) {
expect(fn).not.toHaveBeenCalled();
}
}),
innerFn = jasmine.createSpy('innerFn').and.callFake(function() {
expect(recurring.calls.count()).toBe(4);
expect(fn).not.toHaveBeenCalled();
}),
scheduling = jasmine.createSpy('scheduling').and.callFake(function() {
expect(recurring.calls.count()).toBe(3);
expect(fn).not.toHaveBeenCalled();
scheduler.scheduleFunction(innerFn, 10); // 41ms absolute
});
scheduler.scheduleFunction(recurring, 10, [], true);
scheduler.scheduleFunction(fn, 50);
scheduler.scheduleFunction(scheduling, 31);
scheduler.tick(60);
expect(recurring).toHaveBeenCalled();
expect(recurring.calls.count()).toBe(6);
expect(fn).toHaveBeenCalled();
expect(scheduling).toHaveBeenCalled();
expect(innerFn).toHaveBeenCalled();
});
});

View File

@@ -3,29 +3,6 @@ describe("Env", function() {
var env;
beforeEach(function() {
env = new j$.Env();
env.updateInterval = 0;
});
describe('ids', function() {
it('nextSpecId should return consecutive integers, starting at 0', function() {
expect(env.nextSpecId()).toEqual('spec0');
expect(env.nextSpecId()).toEqual('spec1');
expect(env.nextSpecId()).toEqual('spec2');
});
});
describe("reporting", function() {
var fakeReporter;
beforeEach(function() {
fakeReporter = jasmine.createSpyObj("fakeReporter", ["jasmineStarted"]);
});
it("should allow reporters to be registered", function() {
env.addReporter(fakeReporter);
env.reporter.jasmineStarted();
expect(fakeReporter.jasmineStarted).toHaveBeenCalled();
});
});
it('removes all spies when env is executed', function(done) {
@@ -56,13 +33,13 @@ describe("Env", function() {
});
describe("#spyOn", function() {
it("checks for the existance of the object", function() {
it("checks for the existence of the object", function() {
expect(function() {
env.spyOn(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it("checks for the existance of the method", function() {
it("checks for the existence of the method", function() {
var subject = {};
expect(function() {
@@ -84,41 +61,9 @@ describe("Env", function() {
var originalFunctionWasCalled = false;
var subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
originalFunc = subject.spiedFunc;
var spy = env.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
expect(subject.spiedFunc.calls.any()).toEqual(false);
expect(subject.spiedFunc.calls.count()).toEqual(0);
subject.spiedFunc('foo');
expect(subject.spiedFunc.calls.any()).toEqual(true);
expect(subject.spiedFunc.calls.count()).toEqual(1);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['foo']);
expect(subject.spiedFunc.calls.mostRecent().object).toEqual(subject);
expect(originalFunctionWasCalled).toEqual(false);
subject.spiedFunc('bar');
expect(subject.spiedFunc.calls.count()).toEqual(2);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']);
});
});
describe("#catchException", function() {
it("returns true if the exception is a pending spec exception", function() {
env.catchExceptions(false);
expect(env.catchException(new Error(j$.Spec.pendingSpecExceptionMessage))).toBe(true);
});
it("returns false if the exception is not a pending spec exception and not catching exceptions", function() {
env.catchExceptions(false);
expect(env.catchException(new Error("external error"))).toBe(false);
expect(env.catchException(new Error(j$.Spec.pendingSpecExceptionMessage))).toBe(true);
});
});
@@ -130,467 +75,11 @@ describe("Env", function() {
});
});
describe("#topSuite", function() {
it("returns the Jasmine top suite for users to traverse the spec tree", function() {
var suite = env.topSuite();
expect(suite.description).toEqual('Jasmine__TopLevel__Suite');
});
});
});
// TODO: move these into a separate file
describe("Env integration", function() {
it("Suites execute as expected (no nesting)", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
"with a spec",
"and another spec"
]);
done();
};
env.addReporter({ jasmineDone: assertions});
env.describe("A Suite", function() {
env.it("with a spec", function() {
calls.push("with a spec");
});
env.it("and another spec", function() {
calls.push("and another spec");
});
});
env.execute();
});
it("Nested Suites execute as expected", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec'
]);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.execute();
});
it("Multiple top-level Suites execute as expected", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec',
'a 2nd outer spec'
]);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.describe("Another outer suite", function() {
env.it("a 2nd outer spec", function() {
calls.push('a 2nd outer spec')
});
});
env.execute();
});
it("calls associated befores/specs/afters with the same 'this'", function(done) {
var env = new j$.Env();
env.addReporter({jasmineDone: done});
env.describe("tests", function() {
var firstTimeThrough = true, firstSpecContext, secondSpecContext;
env.beforeEach(function() {
if (firstTimeThrough) {
firstSpecContext = this;
} else {
secondSpecContext = this;
}
expect(this).toEqual({});
});
env.it("sync spec", function() {
expect(this).toBe(firstSpecContext);
});
env.it("another sync spec", function() {
expect(this).toBe(secondSpecContext);
});
env.afterEach(function() {
if (firstTimeThrough) {
expect(this).toBe(firstSpecContext);
firstTimeThrough = false;
} else {
expect(this).toBe(secondSpecContext);
}
});
});
env.execute();
});
it("calls associated befores/its/afters with the same 'this' for an async spec", function(done) {
var env = new j$.Env();
env.addReporter({jasmineDone: done});
env.describe("with an async spec", function() {
var specContext;
env.beforeEach(function() {
specContext = this;
expect(this).toEqual({});
});
env.it("sync spec", function(underTestCallback) {
expect(this).toBe(specContext);
underTestCallback();
});
env.afterEach(function() {
expect(this).toBe(specContext);
});
});
env.execute();
});
it("Allows specifying which specs and suites to run", function(done) {
var env = new j$.Env(),
calls = [],
suiteCallback = jasmine.createSpy('suite callback'),
firstSpec,
secondSuite;
var assertions = function() {
expect(calls).toEqual([
'third spec',
'first spec'
]);
expect(suiteCallback).toHaveBeenCalled();
done();
};
env.addReporter({jasmineDone: assertions, suiteDone: suiteCallback});
env.describe("first suite", function() {
firstSpec = env.it("first spec", function() {
calls.push('first spec');
});
env.it("second spec", function() {
calls.push('second spec');
});
});
secondSuite = env.describe("second suite", function() {
env.it("third spec", function() {
calls.push('third spec');
});
});
env.execute([secondSuite.id, firstSpec.id]);
});
it("Mock clock can be installed and used in tests", function(done) {
var globalSetTimeout = jasmine.createSpy('globalSetTimeout'),
delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'),
delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'),
env = new j$.Env({global: { setTimeout: globalSetTimeout }});
var assertions = function() {
expect(delayedFunctionForMockClock).toHaveBeenCalled();
expect(globalSetTimeout).toHaveBeenCalledWith(delayedFunctionForGlobalClock, 100);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("tests", function() {
env.it("test with mock clock", function() {
env.clock.install();
env.clock.setTimeout(delayedFunctionForMockClock, 100);
env.clock.tick(100);
});
env.it("test without mock clock", function() {
env.clock.setTimeout(delayedFunctionForGlobalClock, 100);
});
});
expect(globalSetTimeout).not.toHaveBeenCalled();
expect(delayedFunctionForMockClock).not.toHaveBeenCalled();
env.execute();
});
it("should run async specs in order, waiting for them to complete", function(done) {
var env = new j$.Env(), mutatedVar;
env.describe("tests", function() {
env.beforeEach(function() {
mutatedVar = 2;
});
env.it("async spec", function(underTestCallback) {
setTimeout(function() {
expect(mutatedVar).toEqual(2);
underTestCallback();
done();
}, 0);
});
env.it("after async spec", function() {
mutatedVar = 3;
});
});
env.execute();
});
describe("with a mock clock", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = j$.DEFAULT_TIMEOUT_INTERVAL;
jasmine.getEnv().clock.install();
});
afterEach(function() {
jasmine.getEnv().clock.uninstall();
j$.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
it("should wait a specified interval before failing specs haven't called done yet", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone" ]);
reporter.specDone.and.callFake(function() {
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({status: 'failed'}));
done();
});
env.addReporter(reporter);
j$.DEFAULT_TIMEOUT_INTERVAL = 8414;
env.it("async spec that doesn't call done", function(underTestCallback) {
env.expect(true).toBeTruthy();
jasmine.getEnv().clock.tick(8414);
});
env.execute();
});
});
// TODO: something is wrong with this spec
it("should report as expected", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 3
});
var suiteResult = reporter.suiteStarted.calls.first().args[0];
expect(suiteResult.description).toEqual("A Suite");
expect(reporter.jasmineDone).toHaveBeenCalled();
done();
});
env.addReporter(reporter);
env.describe("A Suite", function() {
env.it("with a top level spec", function() {
env.expect(true).toBe(true);
});
env.describe("with a nested suite", function() {
env.xit("with a pending spec", function() {
env.expect(true).toBe(true);
});
env.it("with a spec", function() {
env.expect(true).toBe(false);
});
});
});
env.execute();
});
it("should be possible to get full name from a spec", function() {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
topLevelSpec, nestedSpec, doublyNestedSpec;
env.describe("my tests", function() {
topLevelSpec = env.it("are sometimes top level", function() {
});
env.describe("are sometimes", function() {
nestedSpec = env.it("singly nested", function() {
});
env.describe("even", function() {
doublyNestedSpec = env.it("doubly nested", function() {
});
});
});
});
expect(topLevelSpec.getFullName()).toBe("my tests are sometimes top level");
expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested");
expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested");
});
it("Custom equality testers should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReproter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter);
env.describe("testing custom equality testers", function() {
env.it("with a custom tester", function() {
env.addCustomEqualityTester(function(a, b) { return true; });
env.expect("a").toEqual("b");
});
env.it("without a custom tester", function() {
env.expect("a").toEqual("b");
});
});
env.execute();
});
it("Custom matchers should be per spec", function() {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
matchers = {
toFoo: function() {}
},
reporter = jasmine.createSpyObj('fakeReproter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
env.addReporter(reporter);
env.describe("testing custom matchers", function() {
env.it("with a custom matcher", function() {
env.addMatchers(matchers);
expect(env.expect().toFoo).toBeDefined();
});
env.it("without a custom matcher", function() {
expect(env.expect().toFoo).toBeUndefined();
});
});
env.execute();
});
it("Custom equality testers for toContain should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReproter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter);
env.describe("testing custom equality testers", function() {
env.it("with a custom tester", function() {
env.addCustomEqualityTester(function(a, b) { return true; });
env.expect(["a"]).toContain("b");
});
env.it("without a custom tester", function() {
env.expect("a").toContain("b");
});
});
env.execute();
});
});

View File

@@ -3,62 +3,66 @@ describe('Exceptions:', function() {
beforeEach(function() {
env = new j$.Env();
env.updateInterval = 0;
});
describe('with break on exception', function() {
it('should not catch the exception', function() {
env.catchExceptions(false);
var suite = env.describe('suite for break on exceptions', function() {
env.describe('suite for break on exceptions', function() {
env.it('should break when an exception is thrown', function() {
throw new Error('I should hit a breakpoint!');
});
});
var runner = env.currentRunner();
var dont_change = 'I will never change!';
var spy = jasmine.createSpy('spy');
try {
suite.execute();
dont_change = 'oops I changed';
env.execute();
spy();
}
catch (e) {}
expect(dont_change).toEqual('I will never change!');
expect(spy).not.toHaveBeenCalled();
});
});
describe("with catch on exception", function() {
it('should handle exceptions thrown, but continue', function() {
var ranSecondTest = false,
suite = env.describe('Suite for handles exceptions', function () {
it('should handle exceptions thrown, but continue', function(done) {
var secondTest = jasmine.createSpy('second test');
env.describe('Suite for handles exceptions', function () {
env.it('should be a test that fails because it throws an exception', function() {
throw new Error();
});
env.it('should be a passing test that runs after exceptions are thrown from a async test', function() {
ranSecondTest = true;
});
env.it('should be a passing test that runs after exceptions are thrown from a async test', secondTest);
});
suite.execute();
expect(ranSecondTest).toBe(true);
expectations = function() {
expect(secondTest).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: expectations });
env.execute();
});
it("should handle exceptions thrown directly in top-level describe blocks and continue", function () {
var ranSecondDescribe = false, suite, suite2, runner = env.currentRunner();
suite = env.describe("a suite that throws an exception", function () {
it("should handle exceptions thrown directly in top-level describe blocks and continue", function(done) {
var secondDescribe = jasmine.createSpy("second describe");
env.describe("a suite that throws an exception", function () {
env.it("is a test that should pass", function () {
this.expect(true).toEqual(true);
});
throw new Error("top level error");
});
suite2 = env.describe("a suite that doesn't throw an exception", function () {
ranSecondDescribe = true;
});
env.describe("a suite that doesn't throw an exception", secondDescribe);
runner.execute();
expect(ranSecondDescribe).toBe(true);
expectations = function() {
expect(secondDescribe).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: expectations });
env.execute();
});
});
});

View File

@@ -9,7 +9,7 @@ describe("buildExpectationResult", function() {
expect(result.message).toBe('Passed.');
});
it("message returns the message for failing expecations", function() {
it("message returns the message for failing expectations", function() {
var result = j$.buildExpectationResult({passed: false, message: 'some-value'});
expect(result.message).toBe('some-value');
});

View File

@@ -46,7 +46,7 @@ describe("Expectation", function() {
expect(expectation.toFoo).toBeUndefined();
});
it("Factory builds an expectaion/negative expectation", function() {
it("Factory builds an expectation/negative expectation", function() {
var builtExpectation = j$.Expectation.Factory();
expect(builtExpectation instanceof j$.Expectation).toBe(true);
@@ -254,7 +254,7 @@ describe("Expectation", function() {
}
},
util = {
buildFailureMessage: function() { return "default messge"; }
buildFailureMessage: function() { return "default message"; }
},
addExpectationResult = jasmine.createSpy("addExpectationResult"),
actual = "an actual",
@@ -277,7 +277,7 @@ describe("Expectation", function() {
passed: false,
expected: "hello",
actual: actual,
message: "default messge"
message: "default message"
});
});
@@ -317,4 +317,77 @@ describe("Expectation", function() {
message: "I am a custom message"
});
});
});
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
var matchers = {
toFoo: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() { return { pass: true }; }
};
}
},
addExpectationResult = jasmine.createSpy("addExpectationResult"),
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true
});
expectation.toFoo("hello");
expect(addExpectationResult).toHaveBeenCalledWith(true, {
matcherName: "toFoo",
passed: true,
expected: "hello",
actual: actual,
message: ""
});
});
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
var matchers = {
toFoo: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() {
return {
pass: false,
message: "I'm a custom message"
};
}
};
}
},
addExpectationResult = jasmine.createSpy("addExpectationResult"),
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true
});
expectation.toFoo("hello");
expect(addExpectationResult).toHaveBeenCalledWith(false, {
matcherName: "toFoo",
passed: false,
expected: "hello",
actual: actual,
message: "I'm a custom message"
});
});
});

View File

@@ -6,7 +6,6 @@ xdescribe('JsApiReporter (integration specs)', function() {
beforeEach(function() {
env = new j$.Env();
env.updateInterval = 0;
suite = env.describe("top-level suite", function() {
spec1 = env.it("spec 1", function() {

View File

@@ -61,4 +61,4 @@ describe("ObjectContaining", function() {
expect(containing.jasmineToString()).toMatch("<jasmine.objectContaining");
});
});
});

View File

@@ -36,11 +36,20 @@ describe("QueueRunner", function() {
expect(asyncContext).toBe(context);
});
it("supports asynchronous functions, only advancing to next function after a done() callback", function() {
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
//createSpy('asyncfn').and.callFake(function(done) {});
describe("with an asynchronous function", function() {
beforeEach(function() {
jasmine.clock().install();
});
var onComplete = jasmine.createSpy('onComplete'),
afterEach(function() {
jasmine.clock().uninstall();
});
it("supports asynchronous functions, only advancing to next function after a done() callback", function() {
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
//createSpy('asyncfn').and.callFake(function(done) {});
var onComplete = jasmine.createSpy('onComplete'),
beforeCallback = jasmine.createSpy('beforeCallback'),
fnCallback = jasmine.createSpy('fnCallback'),
afterCallback = jasmine.createSpy('afterCallback'),
@@ -67,29 +76,28 @@ describe("QueueRunner", function() {
onComplete: onComplete
});
clock.install();
queueRunner.execute();
queueRunner.execute();
expect(beforeCallback).toHaveBeenCalled();
expect(fnCallback).not.toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
expect(beforeCallback).toHaveBeenCalled();
expect(fnCallback).not.toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
jasmine.clock().tick(100);
clock.tick(100);
expect(fnCallback).toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
expect(fnCallback).toHaveBeenCalled();
expect(afterCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
jasmine.clock().tick(100);
clock.tick(100);
expect(afterCallback).toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
expect(afterCallback).toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
jasmine.clock().tick(100);
clock.tick(100);
expect(onComplete).toHaveBeenCalled();
expect(onComplete).toHaveBeenCalled();
});
});
it("calls an exception handler when an exception is thrown in a fn", function() {

View File

@@ -37,4 +37,4 @@ describe("ReportDispatcher", function() {
dispatcher.foo(123, 456);
}).not.toThrow();
});
});
});

View File

@@ -26,7 +26,7 @@ describe("Spec", function() {
description: 'my test',
id: 'some-id',
fn: function() {},
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
@@ -42,7 +42,7 @@ describe("Spec", function() {
description: 'foo bar',
fn: function() {},
onStart: startCallback,
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
@@ -69,7 +69,7 @@ describe("Spec", function() {
}]
},
onStart: startCallback,
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
@@ -93,7 +93,7 @@ describe("Spec", function() {
afterFns: function() {
return [after]
},
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
@@ -111,7 +111,7 @@ describe("Spec", function() {
onStart: startCallback,
fn: null,
resultCallback: resultCallback,
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
@@ -127,7 +127,7 @@ describe("Spec", function() {
onStart:startCallback,
fn: specBody,
resultCallback: resultCallback,
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.disable();
@@ -154,7 +154,7 @@ describe("Spec", function() {
getSpecName: function() {
return "a suite with a spec"
},
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.pend();
@@ -181,7 +181,7 @@ describe("Spec", function() {
fn: function() {},
catchExceptions: function() { return false; },
resultCallback: function() {},
queueRunner: function(attrs) { attrs.onComplete(); }
queueRunnerFactory: function(attrs) { attrs.onComplete(); }
});
spec.execute(done);
@@ -189,18 +189,9 @@ describe("Spec", function() {
expect(done).toHaveBeenCalled();
});
it("#status returns pending by default", function() {
it("#status returns passing by default", function() {
var spec = new j$.Spec({fn: jasmine.createSpy("spec body")});
expect(spec.status()).toEqual('pending');
});
it("#status returns pending if no expectations were encountered", function() {
var specBody = jasmine.createSpy("spec body"),
spec = new j$.Spec({fn: specBody});
spec.execute();
expect(spec.status()).toEqual('pending');
expect(spec.status()).toEqual('passed');
});
it("#status returns passed if all expectations in the spec have passed", function() {
@@ -217,17 +208,99 @@ describe("Spec", function() {
});
it("can return its full name", function() {
var spec;
spec = new j$.Spec({
getSpecName: function(passedVal) {
// expect(passedVal).toBe(spec); TODO: a exec time, spec is undefined WTF?
return 'expected val';
}
var specNameSpy = jasmine.createSpy('specNameSpy').and.returnValue('expected val');
var spec = new j$.Spec({
getSpecName: specNameSpy
});
expect(spec.getFullName()).toBe('expected val');
expect(specNameSpy.calls.mostRecent().args[0].id).toEqual(spec.id);
});
it("sets a timeout for async functions to keep them from running forever", function() {
var queueRunnerSpy = jasmine.createSpy('queue runner'),
setTimeoutSpy = jasmine.createSpy('setTimeout'),
spec = new j$.Spec({
beforeFns: function() { return [function(done) { }]; },
fn: function(done) { },
afterFns: function() { return [function(done) { }]; },
timer: {
setTimeout: setTimeoutSpy,
clearTimeout: function() {}
},
queueRunnerFactory: queueRunnerSpy
});
spec.execute();
var fns = queueRunnerSpy.calls.mostRecent().args[0].fns;
for (var i = 0; i < fns.length; i++) {
fns[i]();
}
expect(setTimeoutSpy.calls.count()).toEqual(3);
expect(setTimeoutSpy).toHaveBeenCalledWith(jasmine.any(Function), j$.DEFAULT_TIMEOUT_INTERVAL);
});
it("resets the timeout timer when an async before throws an exception", function() {
var queueRunnerSpy = jasmine.createSpy('queueRunner'),
clearTimeoutSpy = jasmine.createSpy('clear timeout'),
spec = new j$.Spec({
beforeFns: function() { return [function(done) {}]; },
fn: function() { },
timer: {
setTimeout: function () { return 920; },
clearTimeout: clearTimeoutSpy
},
queueRunnerFactory: queueRunnerSpy
});
spec.execute();
queueRunnerSpy.calls.mostRecent().args[0].fns[0]();
queueRunnerSpy.calls.mostRecent().args[0].onException(new Error());
expect(clearTimeoutSpy).toHaveBeenCalledWith(920);
});
it("resets the timeout timer when an async spec throws an exception", function() {
var queueRunnerSpy = jasmine.createSpy('queueRunner'),
clearTimeoutSpy = jasmine.createSpy('clear timeout'),
spec = new j$.Spec({
fn: function(done) { },
timer: {
setTimeout: function () { return 920; },
clearTimeout: clearTimeoutSpy
},
queueRunnerFactory: queueRunnerSpy
});
spec.execute();
queueRunnerSpy.calls.mostRecent().args[0].fns[0]();
queueRunnerSpy.calls.mostRecent().args[0].onException(new Error());
expect(clearTimeoutSpy).toHaveBeenCalledWith(920);
});
it("resets the timeout timer when an async after spec throws an exception", function() {
var queueRunnerSpy = jasmine.createSpy('queueRunner'),
clearTimeoutSpy = jasmine.createSpy('clear timeout'),
spec = new j$.Spec({
fn: function() { },
afterFns: function() { return [function(done) {}]; },
timer: {
setTimeout: function () { return 920; },
clearTimeout: clearTimeoutSpy
},
queueRunnerFactory: queueRunnerSpy
});
spec.execute();
queueRunnerSpy.calls.mostRecent().args[0].fns[1]();
queueRunnerSpy.calls.mostRecent().args[0].onException(new Error());
expect(clearTimeoutSpy).toHaveBeenCalledWith(920);
});
describe("when a spec is marked pending during execution", function() {
it("should mark the spec as pending", function() {
var fakeQueueRunner = function(opts) {
@@ -237,7 +310,7 @@ describe("Spec", function() {
description: 'my test',
id: 'some-id',
fn: function() { },
queueRunner: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner
});
spec.execute();

View File

@@ -14,7 +14,7 @@ describe('Spies', function () {
expect(spy.bob).toEqual("test");
});
it("warns the user that we indend to overwrite an existing property", function() {
it("warns the user that we intend to overwrite an existing property", function() {
TestClass.prototype.someFunction.and = "turkey";
expect(function() {
@@ -28,6 +28,25 @@ describe('Spies', function () {
expect(spy.and).toEqual(jasmine.any(j$.SpyStrategy));
expect(spy.calls).toEqual(jasmine.any(j$.CallTracker));
});
it("tracks the argument of calls", function () {
var spy = j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
var trackSpy = spyOn(spy.calls, "track");
spy("arg");
expect(trackSpy.calls.mostRecent().args[0].args).toEqual(["arg"]);
});
it("tracks the context of calls", function () {
var spy = j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
var trackSpy = spyOn(spy.calls, "track");
var contextObject = { spyMethod: spy };
contextObject.spyMethod();
expect(trackSpy.calls.mostRecent().args[0].object).toEqual(contextObject);
});
});
describe("createSpyObj", function() {

View File

@@ -67,54 +67,6 @@ describe("Suite", function() {
expect(suite.afterFns).toEqual([innerAfter, outerAfter]);
});
it("adds specs", function() {
var env = new j$.Env(),
fakeQueue = {
add: jasmine.createSpy()
},
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueFactory: function() {
return fakeQueue
}
}),
fakeSpec = {};
expect(suite.specs.length).toEqual(0);
suite.addSpec(fakeSpec);
expect(suite.specs.length).toEqual(1);
});
it("adds suites", function() {
var env = new j$.Env(),
fakeQueue = {
add: jasmine.createSpy()
},
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueFactory: function() {
return fakeQueue
}
}),
anotherSuite = new j$.Suite({
env: env,
description: "I am another suite",
queueFactory: function() {
return fakeQueue
}
});
expect(suite.suites.length).toEqual(0);
suite.addSuite(anotherSuite);
expect(suite.suites.length).toEqual(1);
});
it("can be disabled", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
@@ -154,8 +106,8 @@ describe("Suite", function() {
spyOn(suite, "execute");
parentSuite.addSpec(fakeSpec1);
parentSuite.addSuite(suite);
parentSuite.addChild(fakeSpec1);
parentSuite.addChild(suite);
parentSuite.execute(parentSuiteDone);

View File

@@ -0,0 +1,149 @@
describe("Custom Matchers (Integration)", function() {
var env;
var fakeTimer;
beforeEach(function() {
env = new j$.Env();
});
it("allows adding more matchers local to a spec", function(done) {
env.it('spec defining a custom matcher', function() {
env.addMatchers({
matcherForSpec: function() {
return {
compare: function(actual, expected) {
return { pass: false, message: "matcherForSpec: actual: " + actual + "; expected: " + expected };
}
}
}
});
env.expect("zzz").matcherForSpec("yyy");
});
env.it("spec without custom matcher defined", function() {
expect(env.expect("zzz").matcherForSpec).toBeUndefined();
});
var specDoneSpy = jasmine.createSpy("specDoneSpy");
var expectations = function() {
var firstSpecResult = specDoneSpy.calls.first().args[0];
expect(firstSpecResult.status).toEqual("failed");
expect(firstSpecResult.failedExpectations[0].message).toEqual("matcherForSpec: actual: zzz; expected: yyy");
done();
};
env.addReporter({ specDone:specDoneSpy, jasmineDone: expectations});
env.execute();
});
it("passes the spec if the custom matcher passes", function(done) {
env.addMatchers({
toBeReal: function() {
return { compare: function() { return { pass: true }; } };
}
});
env.it("spec using custom matcher", function() {
env.expect(true).toBeReal();
});
var specExpectations = function(result) {
expect(result.status).toEqual('passed');
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it("uses the negative compare function for a negative comparison, if provided", function(done) {
env.addMatchers({
toBeReal: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() { return { pass: true }; }
};
}
});
env.it("spec with custom negative comparison matcher", function() {
env.expect(true).not.toBeReal();
});
var specExpectations = function(result) {
expect(result.status).toEqual('passed');
}
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it("generates messages with the same rules as built in matchers absent a custom message", function(done) {
env.addMatchers({
toBeReal: function() {
return {
compare: function() {
return { pass: false };
}
}
}
});
env.it('spec with an expectation', function() {
env.expect("a").toBeReal();
});
var specExpectations = function(result) {
expect(result.failedExpectations[0].message).toEqual("Expected 'a' to be real.");
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it("passes the expected and actual arguments to the comparison function", function(done) {
var argumentSpy = jasmine.createSpy("argument spy").and.returnValue({ pass: true });
env.addMatchers({
toBeReal: function() {
return { compare: argumentSpy };
}
});
env.it('spec with an expectation', function () {
env.expect(true).toBeReal();
env.expect(true).toBeReal("arg");
env.expect(true).toBeReal("arg1", "arg2");
});
var specExpectations = function() {
expect(argumentSpy).toHaveBeenCalledWith(true);
expect(argumentSpy).toHaveBeenCalledWith(true, "arg");
expect(argumentSpy).toHaveBeenCalledWith(true, "arg1", "arg2");
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
it("passes the jasmine utility and current equality matchers to the expectation factory", function(done) {
var matcherFactory = function() { return { compare: function() { return {pass: true}; }}; },
argumentSpy = jasmine.createSpy("argument spy").and.returnValue(matcherFactory),
customEqualityFn = function() { return true; };
env.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: argumentSpy
});
env.it("spec with expectation", function() {
env.expect(true).toBeReal();
});
var specExpectations = function() {
expect(argumentSpy).toHaveBeenCalledWith(j$.matchersUtil, [customEqualityFn]);
};
env.addReporter({ specDone: specExpectations, jasmineDone: done });
env.execute();
});
});

View File

@@ -0,0 +1,488 @@
describe("Env integration", function() {
it("Suites execute as expected (no nesting)", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
"with a spec",
"and another spec"
]);
done();
};
env.addReporter({ jasmineDone: assertions});
env.describe("A Suite", function() {
env.it("with a spec", function() {
calls.push("with a spec");
});
env.it("and another spec", function() {
calls.push("and another spec");
});
});
env.execute();
});
it("Nested Suites execute as expected", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec'
]);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.execute();
});
it("Multiple top-level Suites execute as expected", function(done) {
var env = new j$.Env(),
calls = [];
var assertions = function() {
expect(calls).toEqual([
'an outer spec',
'an inner spec',
'another inner spec',
'a 2nd outer spec'
]);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("Outer suite", function() {
env.it("an outer spec", function() {
calls.push('an outer spec')
});
env.describe("Inner suite", function() {
env.it("an inner spec", function() {
calls.push('an inner spec');
});
env.it("another inner spec", function() {
calls.push('another inner spec');
});
});
});
env.describe("Another outer suite", function() {
env.it("a 2nd outer spec", function() {
calls.push('a 2nd outer spec')
});
});
env.execute();
});
it("calls associated befores/specs/afters with the same 'this'", function(done) {
var env = new j$.Env();
env.addReporter({jasmineDone: done});
env.describe("tests", function() {
var firstTimeThrough = true, firstSpecContext, secondSpecContext;
env.beforeEach(function() {
if (firstTimeThrough) {
firstSpecContext = this;
} else {
secondSpecContext = this;
}
expect(this).toEqual({});
});
env.it("sync spec", function() {
expect(this).toBe(firstSpecContext);
});
env.it("another sync spec", function() {
expect(this).toBe(secondSpecContext);
});
env.afterEach(function() {
if (firstTimeThrough) {
expect(this).toBe(firstSpecContext);
firstTimeThrough = false;
} else {
expect(this).toBe(secondSpecContext);
}
});
});
env.execute();
});
it("calls associated befores/its/afters with the same 'this' for an async spec", function(done) {
var env = new j$.Env();
env.addReporter({jasmineDone: done});
env.describe("with an async spec", function() {
var specContext;
env.beforeEach(function() {
specContext = this;
expect(this).toEqual({});
});
env.it("sync spec", function(underTestCallback) {
expect(this).toBe(specContext);
underTestCallback();
});
env.afterEach(function() {
expect(this).toBe(specContext);
});
});
env.execute();
});
it("Allows specifying which specs and suites to run", function(done) {
var env = new j$.Env(),
calls = [],
suiteCallback = jasmine.createSpy('suite callback'),
firstSpec,
secondSuite;
var assertions = function() {
expect(calls).toEqual([
'third spec',
'first spec'
]);
expect(suiteCallback).toHaveBeenCalled();
done();
};
env.addReporter({jasmineDone: assertions, suiteDone: suiteCallback});
env.describe("first suite", function() {
firstSpec = env.it("first spec", function() {
calls.push('first spec');
});
env.it("second spec", function() {
calls.push('second spec');
});
});
secondSuite = env.describe("second suite", function() {
env.it("third spec", function() {
calls.push('third spec');
});
});
env.execute([secondSuite.id, firstSpec.id]);
});
it("Functions can be spied on and have their calls tracked", function () {
var env = new j$.Env();
var originalFunctionWasCalled = false;
var subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
var spy = env.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
expect(subject.spiedFunc.calls.any()).toEqual(false);
expect(subject.spiedFunc.calls.count()).toEqual(0);
subject.spiedFunc('foo');
expect(subject.spiedFunc.calls.any()).toEqual(true);
expect(subject.spiedFunc.calls.count()).toEqual(1);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['foo']);
expect(subject.spiedFunc.calls.mostRecent().object).toEqual(subject);
expect(originalFunctionWasCalled).toEqual(false);
subject.spiedFunc('bar');
expect(subject.spiedFunc.calls.count()).toEqual(2);
expect(subject.spiedFunc.calls.mostRecent().args).toEqual(['bar']);
});
it("Mock clock can be installed and used in tests", function(done) {
var globalSetTimeout = jasmine.createSpy('globalSetTimeout'),
delayedFunctionForGlobalClock = jasmine.createSpy('delayedFunctionForGlobalClock'),
delayedFunctionForMockClock = jasmine.createSpy('delayedFunctionForMockClock'),
env = new j$.Env({global: { setTimeout: globalSetTimeout }});
var assertions = function() {
expect(delayedFunctionForMockClock).toHaveBeenCalled();
expect(globalSetTimeout).toHaveBeenCalledWith(delayedFunctionForGlobalClock, 100);
done();
};
env.addReporter({ jasmineDone: assertions });
env.describe("tests", function() {
env.it("test with mock clock", function() {
env.clock.install();
env.clock.setTimeout(delayedFunctionForMockClock, 100);
env.clock.tick(100);
env.clock.uninstall();
});
env.it("test without mock clock", function() {
env.clock.setTimeout(delayedFunctionForGlobalClock, 100);
});
});
expect(globalSetTimeout).not.toHaveBeenCalled();
expect(delayedFunctionForMockClock).not.toHaveBeenCalled();
env.execute();
});
it("should run async specs in order, waiting for them to complete", function(done) {
var env = new j$.Env(), mutatedVar;
env.describe("tests", function() {
env.beforeEach(function() {
mutatedVar = 2;
});
env.it("async spec", function(underTestCallback) {
setTimeout(function() {
expect(mutatedVar).toEqual(2);
underTestCallback();
done();
}, 0);
});
env.it("after async spec", function() {
mutatedVar = 3;
});
});
env.execute();
});
describe("with a mock clock", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = j$.DEFAULT_TIMEOUT_INTERVAL;
jasmine.getEnv().clock.install();
});
afterEach(function() {
jasmine.getEnv().clock.uninstall();
j$.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
it("should wait a specified interval before failing specs haven't called done yet", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone" ]);
reporter.specDone.and.callFake(function() {
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({status: 'failed'}));
done();
});
env.addReporter(reporter);
j$.DEFAULT_TIMEOUT_INTERVAL = 8414;
env.it("async spec that doesn't call done", function(underTestCallback) {
env.expect(true).toBeTruthy();
jasmine.getEnv().clock.tick(8415);
});
env.execute();
});
});
// TODO: something is wrong with this spec
it("should report as expected", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 3
});
var suiteResult = reporter.suiteStarted.calls.first().args[0];
expect(suiteResult.description).toEqual("A Suite");
done();
});
env.addReporter(reporter);
env.describe("A Suite", function() {
env.it("with a top level spec", function() {
env.expect(true).toBe(true);
});
env.describe("with a nested suite", function() {
env.xit("with a pending spec", function() {
env.expect(true).toBe(true);
});
env.it("with a spec", function() {
env.expect(true).toBe(false);
});
});
});
env.execute();
});
it("should be possible to get full name from a spec", function() {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
topLevelSpec, nestedSpec, doublyNestedSpec;
env.describe("my tests", function() {
topLevelSpec = env.it("are sometimes top level", function() {
});
env.describe("are sometimes", function() {
nestedSpec = env.it("singly nested", function() {
});
env.describe("even", function() {
doublyNestedSpec = env.it("doubly nested", function() {
});
});
});
});
expect(topLevelSpec.getFullName()).toBe("my tests are sometimes top level");
expect(nestedSpec.getFullName()).toBe("my tests are sometimes singly nested");
expect(doublyNestedSpec.getFullName()).toBe("my tests are sometimes even doubly nested");
});
it("Custom equality testers should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter);
env.describe("testing custom equality testers", function() {
env.it("with a custom tester", function() {
env.addCustomEqualityTester(function(a, b) { return true; });
env.expect("a").toEqual("b");
});
env.it("without a custom tester", function() {
env.expect("a").toEqual("b");
});
});
env.execute();
});
it("Custom matchers should be per spec", function() {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
matchers = {
toFoo: function() {}
},
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
env.addReporter(reporter);
env.describe("testing custom matchers", function() {
env.it("with a custom matcher", function() {
env.addMatchers(matchers);
expect(env.expect().toFoo).toBeDefined();
});
env.it("without a custom matcher", function() {
expect(env.expect().toFoo).toBeUndefined();
});
});
env.execute();
});
it("Custom equality testers for toContain should be per spec", function(done) {
var env = new j$.Env({global: { setTimeout: setTimeout }}),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
reporter.jasmineDone.and.callFake(function() {
var firstSpecResult = reporter.specDone.calls.first().args[0],
secondSpecResult = reporter.specDone.calls.mostRecent().args[0];
expect(firstSpecResult.status).toEqual("passed");
expect(secondSpecResult.status).toEqual("failed");
done();
});
env.addReporter(reporter);
env.describe("testing custom equality testers", function() {
env.it("with a custom tester", function() {
env.addCustomEqualityTester(function(a, b) { return true; });
env.expect(["a"]).toContain("b");
});
env.it("without a custom tester", function() {
env.expect("a").toContain("b");
});
});
env.execute();
});
});

View File

@@ -1,11 +1,9 @@
// TODO: This should really be part of the Env Integration Spec
describe("jasmine spec running", function () {
var env;
var fakeTimer;
beforeEach(function() {
env = new j$.Env();
env.updateInterval = 0;
});
it('should assign spec ids sequentially', function() {

View File

@@ -1,6 +1,6 @@
describe("matchersUtil", function() {
describe("equals", function() {
it("passes for literals that are threequal", function() {
it("passes for literals that are triple-equal", function() {
expect(j$.matchersUtil.equals(null, null)).toBe(true);
expect(j$.matchersUtil.equals(void 0, void 0)).toBe(true);
});
@@ -153,10 +153,22 @@ describe("matchersUtil", function() {
expect(j$.matchersUtil.equals(1, 2, [tester])).toBe(true);
});
it("passes for two empty Objects", function () {
expect(j$.matchersUtil.equals({}, {})).toBe(true);
});
describe("when a custom equality matcher is installed that returns 'undefined'", function () {
var tester = function(a, b) { return jasmine.undefined; };
it("passes for two empty Objects", function () {
expect(j$.matchersUtil.equals({}, {}, [tester])).toBe(true);
});
});
it("fails for equivalents when a custom equality matcher returns false", function() {
var tester = function(a, b) { return false; };
expect(j$.matchersUtil.equals(1, 2, [tester])).toBe(false);
expect(j$.matchersUtil.equals(1, 1, [tester])).toBe(false);
});
});

View File

@@ -4,7 +4,7 @@ describe("toThrowError", function() {
expect(function() {
matcher.compare({});
}).toThrow(new Error("Actual is not a Function")); // TODO: this needs to change for self-test
}).toThrowError("Actual is not a Function");
});
it("throws an error when the expected is not an Error, string, or RegExp", function() {
@@ -15,7 +15,7 @@ describe("toThrowError", function() {
expect(function() {
matcher.compare(fn, 1);
}).toThrow(new Error("Expected is not an Error, string, or RegExp.")); // TODO: this needs to change for self-test
}).toThrowError("Expected is not an Error, string, or RegExp.");
});
it("throws an error when the expected error type is not an Error", function() {
@@ -26,7 +26,7 @@ describe("toThrowError", function() {
expect(function() {
matcher.compare(fn, void 0, "foo");
}).toThrow(new Error("Expected error type is not an Error.")); // TODO: this needs to change for self-test
}).toThrowError("Expected error type is not an Error.");
});
it("throws an error when the expected error message is not a string or RegExp", function() {
@@ -37,7 +37,7 @@ describe("toThrowError", function() {
expect(function() {
matcher.compare(fn, Error, 1);
}).toThrow(new Error("Expected error message is not a string or RegExp.")); // TODO: this needs to change for self-test
}).toThrowError("Expected error message is not a string or RegExp.");
});
it("fails if actual does not throw at all", function() {
@@ -246,7 +246,7 @@ describe("toThrowError", function() {
expect(result.message).toEqual("Expected function to throw TypeError with message \"bar\", but it threw TypeError with message \"foo\".");
});
it("passes if thrown is a type of Error and has the same type as the expected Error and the message matches the exepcted message", function() {
it("passes if thrown is a type of Error and has the same type as the expected Error and the message matches the expected message", function() {
var util = {
equals: jasmine.createSpy('delegated-equal').and.returnValue(true)
},

View File

@@ -4,7 +4,8 @@ describe("toThrow", function() {
expect(function() {
matcher.compare({});
}).toThrow(new Error("Actual is not a Function")); // TODO: this needs to change for self-test
matcherComparator({});
}).toThrowError("Actual is not a Function");
});
it("fails if actual does not throw", function() {
@@ -95,4 +96,4 @@ describe("toThrow", function() {
expect(result.pass).toBe(false);
expect(result.message).toEqual("Expected function to throw undefined, but it threw 5.");
});
});
});

View File

@@ -15,4 +15,4 @@ describe("j$.HtmlSpecFilter", function() {
expect(specFilter.matches("foo")).toBe(true);
expect(specFilter.matches("bar")).toBe(false);
});
});
});

View File

@@ -3,7 +3,6 @@ describe("MatchersSpec - HTML Dependent", function () {
beforeEach(function() {
env = new j$.Env();
env.updateInterval = 0;
var suite = env.describe("suite", function() {
spec = env.it("spec", function() {

View File

@@ -40,4 +40,4 @@ describe("QueryString", function() {
expect(queryString.getParam("baz")).toBeFalsy();
});
});
});
});

View File

@@ -59,4 +59,4 @@ describe("ResultsNode", function() {
expect(node.last()).toBe(node.children[node.children.length - 1]);
});
});
});

View File

@@ -6,7 +6,7 @@ var path = require('path');
var jasmineRequire = require('../lib/jasmine-core/jasmine.js');
var jasmine = jasmineRequire.core(jasmineRequire);
var consoleFns = require('../src/console/console.js');
var consoleFns = require('../lib/console/console.js');
extend(jasmineRequire, consoleFns);
jasmineRequire.console(jasmineRequire, jasmine);
@@ -41,20 +41,10 @@ var jasmineInterface = {
return env.expect(actual);
},
addMatchers: function(matchers) {
return env.addMatchers(matchers);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
clock: env.clock,
setTimeout: env.clock.setTimeout,
clearTimeout: env.clock.clearTimeout,
setInterval: env.clock.setInterval,
clearInterval: env.clock.clearInterval,
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
})
@@ -67,6 +57,18 @@ function extend(destination, source) {
return destination;
}
jasmine.addCustomEqualityTester = function(tester) {
env.addCustomEqualityTester(tester);
};
jasmine.addMatchers = function(matchers) {
return env.addMatchers(matchers);
};
jasmine.clock = function() {
return env.clock;
};
// Jasmine "runner"
function executeSpecs(specs, done, isVerbose, showColors) {
global.jasmine = jasmine;

View File

@@ -39,15 +39,10 @@
return env.pending();
},
addMatchers: function(matchers) {
return env.addMatchers(matchers);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
clock: env.clock,
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
})
@@ -59,6 +54,18 @@
extend(window, jasmineInterface);
}
jasmine.addCustomEqualityTester = function(tester) {
env.addCustomEqualityTester(tester);
};
jasmine.addMatchers = function(matchers) {
return env.addMatchers(matchers);
};
jasmine.clock = function() {
return env.clock;
};
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
@@ -69,7 +76,6 @@
var htmlReporter = new jasmine.HtmlReporter({
env: env,
queryString: queryString,
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
@@ -88,6 +94,11 @@
return specFilter.matches(spec.getFullName());
};
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
var currentWindowOnload = window.onload;
window.onload = function() {

View File

@@ -15,10 +15,10 @@ getJasmineRequireObj().ConsoleReporter = function() {
failedSpecs = [],
pendingCount,
ansi = {
green: '\033[32m',
red: '\033[31m',
yellow: '\033[33m',
none: '\033[0m'
green: '\x1B[32m',
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
};
this.jasmineStarted = function() {

View File

@@ -33,4 +33,4 @@ getJasmineRequireObj().Any = function() {
};
return Any;
};
};

View File

@@ -13,7 +13,8 @@ getJasmineRequireObj().Clock = function() {
setInterval: setInterval,
clearInterval: clearInterval
},
installed = false;
installed = false,
timer;
self.install = function() {
replace(global, fakeTimingFunctions);
@@ -60,7 +61,7 @@ getJasmineRequireObj().Clock = function() {
if (installed) {
delayedFunctionScheduler.tick(millis);
} else {
throw new Error("Mock clock is not installed, use jasmine.getEnv().clock.install()");
throw new Error("Mock clock is not installed, use jasmine.clock().install()");
}
};
@@ -68,8 +69,6 @@ getJasmineRequireObj().Clock = function() {
function legacyIE() {
//if these methods are polyfilled, apply will be present
//TODO: it may be difficult to load the polyfill before jasmine loads
//(env should be new-ed inside of onload)
return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
}

View File

@@ -1,14 +1,17 @@
getJasmineRequireObj().DelayedFunctionScheduler = function() {
function DelayedFunctionScheduler() {
var self = this;
var scheduledLookup = [];
var scheduledFunctions = {};
var currentTime = 0;
var delayedFnCount = 0;
self.tick = function(millis) {
millis = millis || 0;
currentTime = currentTime + millis;
runFunctionsWithinRange(currentTime - millis, currentTime);
var endTime = currentTime + millis;
runScheduledFunctions(endTime);
currentTime = endTime;
};
self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
@@ -24,7 +27,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
millis = millis || 0;
timeoutKey = timeoutKey || ++delayedFnCount;
runAtMillis = runAtMillis || (currentTime + millis);
scheduledFunctions[timeoutKey] = {
var funcToSchedule = {
runAtMillis: runAtMillis,
funcToCall: f,
recurring: recurring,
@@ -32,58 +36,73 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
timeoutKey: timeoutKey,
millis: millis
};
if (runAtMillis in scheduledFunctions) {
scheduledFunctions[runAtMillis].push(funcToSchedule);
} else {
scheduledFunctions[runAtMillis] = [funcToSchedule];
scheduledLookup.push(runAtMillis);
scheduledLookup.sort(function (a, b) {
return a - b;
});
}
return timeoutKey;
};
self.removeFunctionWithId = function(timeoutKey) {
delete scheduledFunctions[timeoutKey];
for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) {
return func.timeoutKey === timeoutKey;
});
if (i > -1) {
if (funcs.length === 1) {
delete scheduledFunctions[runAtMillis];
deleteFromLookup(runAtMillis);
} else {
funcs.splice(i, 1);
}
// intervals get rescheduled when executed, so there's never more
// than a single scheduled function with a given timeoutKey
break;
}
}
};
self.reset = function() {
currentTime = 0;
scheduledLookup = [];
scheduledFunctions = {};
delayedFnCount = 0;
};
return self;
// finds/dupes functions within range and removes them.
function functionsWithinRange(startMillis, endMillis) {
var fnsToRun = [];
for (var timeoutKey in scheduledFunctions) {
var scheduledFunc = scheduledFunctions[timeoutKey];
if (scheduledFunc &&
scheduledFunc.runAtMillis >= startMillis &&
scheduledFunc.runAtMillis <= endMillis) {
function indexOfFirstToPass(array, testFn) {
var index = -1;
// remove fn -- we'll reschedule later if it is recurring.
self.removeFunctionWithId(timeoutKey);
if (!scheduledFunc.recurring) {
fnsToRun.push(scheduledFunc); // schedules each function only once
} else {
fnsToRun.push(buildNthInstanceOf(scheduledFunc, 0));
var additionalTimesFnRunsInRange =
Math.floor((endMillis - scheduledFunc.runAtMillis) / scheduledFunc.millis);
for (var i = 0; i < additionalTimesFnRunsInRange; i++) {
fnsToRun.push(buildNthInstanceOf(scheduledFunc, i + 1));
}
reschedule(buildNthInstanceOf(scheduledFunc, additionalTimesFnRunsInRange));
}
for (var i = 0; i < array.length; ++i) {
if (testFn(array[i])) {
index = i;
break;
}
}
return fnsToRun;
return index;
}
function buildNthInstanceOf(scheduledFunc, n) {
return {
runAtMillis: scheduledFunc.runAtMillis + (scheduledFunc.millis * n),
funcToCall: scheduledFunc.funcToCall,
params: scheduledFunc.params,
millis: scheduledFunc.millis,
recurring: scheduledFunc.recurring,
timeoutKey: scheduledFunc.timeoutKey
};
function deleteFromLookup(key) {
var value = Number(key);
var i = indexOfFirstToPass(scheduledLookup, function (millis) {
return millis === value;
});
if (i > -1) {
scheduledLookup.splice(i, 1);
}
}
function reschedule(scheduledFn) {
@@ -95,21 +114,30 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
scheduledFn.runAtMillis + scheduledFn.millis);
}
function runFunctionsWithinRange(startMillis, endMillis) {
var funcsToRun = functionsWithinRange(startMillis, endMillis);
if (funcsToRun.length === 0) {
function runScheduledFunctions(endTime) {
if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
return;
}
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
do {
currentTime = scheduledLookup.shift();
for (var i = 0; i < funcsToRun.length; ++i) {
var funcToRun = funcsToRun[i];
funcToRun.funcToCall.apply(null, funcToRun.params || []);
}
var funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime];
for (var i = 0; i < funcsToRun.length; ++i) {
var funcToRun = funcsToRun[i];
funcToRun.funcToCall.apply(null, funcToRun.params || []);
if (funcToRun.recurring) {
reschedule(funcToRun);
}
}
} while (scheduledLookup.length > 0 &&
// checking first if we're out of time prevents setTimeout(0)
// scheduled in a funcToRun from forcing an extra iteration
currentTime !== endTime &&
scheduledLookup[0] <= endTime);
}
}

View File

@@ -5,6 +5,8 @@ getJasmineRequireObj().Env = function(j$) {
var self = this;
var global = options.global || j$.getGlobal();
var totalSpecsDefined = 0;
var catchExceptions = true;
var realSetTimeout = j$.getGlobal().setTimeout;
@@ -15,9 +17,10 @@ getJasmineRequireObj().Env = function(j$) {
var spies = [];
this.currentSpec = null;
var currentSpec = null;
var currentSuite = null;
this.reporter = new j$.ReportDispatcher([
var reporter = new j$.ReportDispatcher([
"jasmineStarted",
"jasmineDone",
"suiteStarted",
@@ -26,14 +29,11 @@ getJasmineRequireObj().Env = function(j$) {
"specDone"
]);
this.lastUpdate = 0;
this.specFilter = function() {
return true;
};
this.nextSpecId_ = 0;
this.nextSuiteId_ = 0;
this.equalityTesters_ = [];
var equalityTesters = [];
var customEqualityTesters = [];
this.addCustomEqualityTester = function(tester) {
@@ -42,6 +42,16 @@ getJasmineRequireObj().Env = function(j$) {
j$.Expectation.addCoreMatchers(j$.matchers);
var nextSpecId = 0;
var getNextSpecId = function() {
return 'spec' + nextSpecId++;
};
var nextSuiteId = 0;
var getNextSuiteId = function() {
return 'suite' + nextSuiteId++;
};
var expectationFactory = function(actual, spec) {
return j$.Expectation.Factory({
util: j$.matchersUtil,
@@ -56,32 +66,34 @@ getJasmineRequireObj().Env = function(j$) {
};
var specStarted = function(spec) {
self.currentSpec = spec;
self.reporter.specStarted(spec.result);
currentSpec = spec;
reporter.specStarted(spec.result);
};
var beforeFns = function(currentSuite) {
var beforeFns = function(suite) {
return function() {
var befores = [];
for (var suite = currentSuite; suite; suite = suite.parentSuite) {
while(suite) {
befores = befores.concat(suite.beforeFns);
suite = suite.parentSuite;
}
return befores.reverse();
};
};
var afterFns = function(currentSuite) {
var afterFns = function(suite) {
return function() {
var afters = [];
for (var suite = currentSuite; suite; suite = suite.parentSuite) {
while(suite) {
afters = afters.concat(suite.afterFns);
suite = suite.parentSuite;
}
return afters;
};
};
var getSpecName = function(spec, currentSuite) {
return currentSuite.getFullName() + ' ' + spec.description;
var getSpecName = function(spec, suite) {
return suite.getFullName() + ' ' + spec.description;
};
// TODO: we may just be able to pass in the fn instead of wrapping here
@@ -104,10 +116,6 @@ getJasmineRequireObj().Env = function(j$) {
return catchExceptions;
};
this.catchException = function(e) {
return j$.Spec.isPendingSpecException(e) || catchExceptions;
};
var maximumSpecCallbackDepth = 20;
var currentSpecCallbackDepth = 0;
@@ -121,97 +129,33 @@ getJasmineRequireObj().Env = function(j$) {
}
}
var catchException = function(e) {
return j$.Spec.isPendingSpecException(e) || catchExceptions;
};
var queueRunnerFactory = function(options) {
options.catchException = self.catchException;
options.catchException = catchException;
options.clearStack = options.clearStack || clearStack;
new j$.QueueRunner(options).run(options.fns, 0);
new j$.QueueRunner(options).execute();
};
var totalSpecsDefined = 0;
this.specFactory = function(description, fn, suite) {
totalSpecsDefined++;
var spec = new j$.Spec({
id: self.nextSpecId(),
beforeFns: beforeFns(suite),
afterFns: afterFns(suite),
expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite);
},
onStart: specStarted,
description: description,
expectationResultFactory: expectationResultFactory,
queueRunner: queueRunnerFactory,
fn: fn,
timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
});
runnableLookupTable[spec.id] = spec;
if (!self.specFilter(spec)) {
spec.disable();
}
return spec;
function removeAllSpies() {
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
spies = [];
}
function specResultCallback(result) {
removeAllSpies();
j$.Expectation.resetMatchers();
customEqualityTesters.length = 0;
self.clock.uninstall();
self.currentSpec = null;
self.reporter.specDone(result);
}
};
var suiteStarted = function(suite) {
self.reporter.suiteStarted(suite.result);
};
var suiteConstructor = j$.Suite;
this.topSuite = new j$.Suite({
var topSuite = new j$.Suite({
env: this,
id: this.nextSuiteId(),
id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite',
queueRunner: queueRunnerFactory,
completeCallback: function() {}, // TODO - hook this up
resultCallback: function() {} // TODO - hook this up
});
runnableLookupTable[this.topSuite.id] = this.topSuite;
this.currentSuite = this.topSuite;
runnableLookupTable[topSuite.id] = topSuite;
currentSuite = topSuite;
this.suiteFactory = function(description) {
var suite = new suiteConstructor({
env: self,
id: self.nextSuiteId(),
description: description,
parentSuite: self.currentSuite,
queueRunner: queueRunnerFactory,
onStart: suiteStarted,
resultCallback: function(attrs) {
self.reporter.suiteDone(attrs);
}
});
runnableLookupTable[suite.id] = suite;
return suite;
this.topSuite = function() {
return topSuite;
};
this.execute = function(runnablesToRun) {
runnablesToRun = runnablesToRun || [this.topSuite.id];
runnablesToRun = runnablesToRun || [topSuite.id];
var allFns = [];
for(var i = 0; i < runnablesToRun.length; i++) {
@@ -219,11 +163,19 @@ getJasmineRequireObj().Env = function(j$) {
allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
}
this.reporter.jasmineStarted({
reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined
});
queueRunnerFactory({fns: allFns, onComplete: this.reporter.jasmineDone});
queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
};
this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd);
};
this.addMatchers = function(matchersToAdd) {
j$.Expectation.addMatchers(matchersToAdd);
};
this.spyOn = function(obj, methodName) {
@@ -253,108 +205,133 @@ getJasmineRequireObj().Env = function(j$) {
return spy;
};
}
Env.prototype.addMatchers = function(matchersToAdd) {
j$.Expectation.addMatchers(matchersToAdd);
};
Env.prototype.version = function() {
return j$.version;
};
Env.prototype.expect = function(actual) {
return this.currentSpec.expect(actual);
};
// TODO: move this to closure
Env.prototype.versionString = function() {
console.log("DEPRECATED == use j$.version");
return j$.version;
};
// TODO: move this to closure
Env.prototype.nextSpecId = function() {
return 'spec' + this.nextSpecId_++;
};
// TODO: move this to closure
Env.prototype.nextSuiteId = function() {
return 'suite' + this.nextSuiteId_++;
};
// TODO: move this to closure
Env.prototype.addReporter = function(reporter) {
this.reporter.addReporter(reporter);
};
// TODO: move this to closure
Env.prototype.describe = function(description, specDefinitions) {
var suite = this.suiteFactory(description);
var parentSuite = this.currentSuite;
parentSuite.addSuite(suite);
this.currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
id: getNextSuiteId(),
description: description,
parentSuite: currentSuite,
queueRunner: queueRunnerFactory,
onStart: suiteStarted,
resultCallback: function(attrs) {
reporter.suiteDone(attrs);
}
});
}
this.currentSuite = parentSuite;
runnableLookupTable[suite.id] = suite;
return suite;
};
return suite;
};
this.describe = function(description, specDefinitions) {
var suite = suiteFactory(description);
// TODO: move this to closure
Env.prototype.xdescribe = function(description, specDefinitions) {
var suite = this.describe(description, specDefinitions);
suite.disable();
return suite;
};
var parentSuite = currentSuite;
parentSuite.addChild(suite);
currentSuite = suite;
// TODO: move this to closure
Env.prototype.it = function(description, fn) {
var spec = this.specFactory(description, fn, this.currentSuite);
this.currentSuite.addSpec(spec);
return spec;
};
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
// TODO: move this to closure
Env.prototype.xit = function(description, fn) {
var spec = this.it(description, fn);
spec.pend();
return spec;
};
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
// TODO: move this to closure
Env.prototype.beforeEach = function(beforeEachFunction) {
this.currentSuite.beforeEach(beforeEachFunction);
};
currentSuite = parentSuite;
// TODO: move this to closure
Env.prototype.afterEach = function(afterEachFunction) {
this.currentSuite.afterEach(afterEachFunction);
};
return suite;
};
// TODO: move this to closure
Env.prototype.pending = function() {
throw j$.Spec.pendingSpecExceptionMessage;
};
this.xdescribe = function(description, specDefinitions) {
var suite = this.describe(description, specDefinitions);
suite.disable();
return suite;
};
// TODO: Still needed?
Env.prototype.currentRunner = function() {
return this.topSuite;
};
var specFactory = function(description, fn, suite) {
totalSpecsDefined++;
var spec = new j$.Spec({
id: getNextSpecId(),
beforeFns: beforeFns(suite),
afterFns: afterFns(suite),
expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite);
},
onStart: specStarted,
description: description,
expectationResultFactory: expectationResultFactory,
queueRunnerFactory: queueRunnerFactory,
fn: fn,
timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
});
runnableLookupTable[spec.id] = spec;
if (!self.specFilter(spec)) {
spec.disable();
}
return spec;
function removeAllSpies() {
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
spies = [];
}
function specResultCallback(result) {
removeAllSpies();
j$.Expectation.resetMatchers();
customEqualityTesters = [];
currentSpec = null;
reporter.specDone(result);
}
};
var suiteStarted = function(suite) {
reporter.suiteStarted(suite.result);
};
this.it = function(description, fn) {
var spec = specFactory(description, fn, currentSuite);
currentSuite.addChild(spec);
return spec;
};
this.xit = function(description, fn) {
var spec = this.it(description, fn);
spec.pend();
return spec;
};
this.expect = function(actual) {
return currentSpec.expect(actual);
};
this.beforeEach = function(beforeEachFunction) {
currentSuite.beforeEach(beforeEachFunction);
};
this.afterEach = function(afterEachFunction) {
currentSuite.afterEach(afterEachFunction);
};
this.pending = function() {
throw j$.Spec.pendingSpecExceptionMessage;
};
}
return Env;
};

View File

@@ -22,12 +22,21 @@ getJasmineRequireObj().Expectation = function() {
args.unshift(this.actual);
var result = matcherFactory(this.util, this.customEqualityTesters).compare.apply(null, args);
var matcher = matcherFactory(this.util, this.customEqualityTesters),
matcherCompare = matcher.compare;
function defaultNegativeCompare() {
var result = matcher.compare.apply(null, args);
result.pass = !result.pass;
return result;
}
if (this.isNot) {
result.pass = !result.pass;
matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
}
var result = matcherCompare.apply(null, args);
if (!result.pass) {
if (!result.message) {
args.unshift(this.isNot);

View File

@@ -47,8 +47,8 @@ getJasmineRequireObj().pp = function(j$) {
PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (!obj.hasOwnProperty(property)) continue;
if (property == '__Jasmine_been_here_before__') continue;
if (!obj.hasOwnProperty(property)) { continue; }
if (property == '__Jasmine_been_here_before__') { continue; }
fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
obj.__lookupGetter__(property) !== null) : false);
}

View File

@@ -5,11 +5,11 @@ getJasmineRequireObj().ReportDispatcher = function() {
for (var i = 0; i < dispatchedMethods.length; i++) {
var method = dispatchedMethods[i];
this[method] = function(m) {
this[method] = (function(m) {
return function() {
dispatch(m, arguments);
};
}(method);
}(method));
}
var reporters = [];

View File

@@ -1,19 +1,17 @@
getJasmineRequireObj().Spec = function(j$) {
function Spec(attrs) {
this.encounteredExpectations = false;
this.expectationFactory = attrs.expectationFactory;
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.description = attrs.description || '';
this.fn = attrs.fn;
this.beforeFns = attrs.beforeFns || function() {};
this.afterFns = attrs.afterFns || function() {};
this.catchingExceptions = attrs.catchingExceptions;
this.beforeFns = attrs.beforeFns || function() { return []; };
this.afterFns = attrs.afterFns || function() { return []; };
this.onStart = attrs.onStart || function() {};
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() { };
this.queueRunner = attrs.queueRunner || function() {};
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
@@ -26,13 +24,11 @@ getJasmineRequireObj().Spec = function(j$) {
id: this.id,
description: this.description,
fullName: this.getFullName(),
status: this.status(),
failedExpectations: []
};
}
Spec.prototype.addExpectationResult = function(passed, data) {
this.encounteredExpectations = true;
if (passed) {
return;
}
@@ -44,7 +40,8 @@ getJasmineRequireObj().Spec = function(j$) {
};
Spec.prototype.execute = function(onComplete) {
var self = this;
var self = this,
timeout;
this.onStart(this);
@@ -55,13 +52,13 @@ getJasmineRequireObj().Spec = function(j$) {
function timeoutable(fn) {
return function(done) {
var timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
onException(new Error('timeout'));
timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
done();
}, j$.DEFAULT_TIMEOUT_INTERVAL]]);
var callDone = function() {
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
clearTimeoutable();
done();
};
@@ -69,30 +66,38 @@ getJasmineRequireObj().Spec = function(j$) {
};
}
var befores = this.beforeFns() || [],
afters = this.afterFns() || [],
thisOne = (this.fn.length) ? timeoutable(this.fn) : this.fn;
var allFns = befores.concat(thisOne).concat(afters);
function clearTimeoutable() {
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
timeout = void 0;
}
this.queueRunner({
fns: allFns,
var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()),
allTimeoutableFns = [];
for (var i = 0; i < allFns.length; i++) {
var fn = allFns[i];
allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn);
}
this.queueRunnerFactory({
fns: allTimeoutableFns,
onException: onException,
onComplete: complete
});
function onException(e) {
if (Spec.isPendingSpecException(e)) {
self.pend();
return;
}
clearTimeoutable();
if (Spec.isPendingSpecException(e)) {
self.pend();
return;
}
self.addExpectationResult(false, {
matcherName: "",
passed: false,
expected: "",
actual: "",
error: e
});
self.addExpectationResult(false, {
matcherName: "",
passed: false,
expected: "",
actual: "",
error: e
});
}
function complete() {
@@ -118,7 +123,7 @@ getJasmineRequireObj().Spec = function(j$) {
return 'disabled';
}
if (this.markedPending || !this.encounteredExpectations) {
if (this.markedPending) {
return 'pending';
}

View File

@@ -5,7 +5,6 @@ getJasmineRequireObj().Suite = function() {
this.parentSuite = attrs.parentSuite;
this.description = attrs.description;
this.onStart = attrs.onStart || function() {};
this.completeCallback = attrs.completeCallback || function() {}; // TODO: this is unused
this.resultCallback = attrs.resultCallback || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
@@ -14,9 +13,7 @@ getJasmineRequireObj().Suite = function() {
this.queueRunner = attrs.queueRunner || function() {};
this.disabled = false;
this.children_ = []; // TODO: rename
this.suites = []; // TODO: needed?
this.specs = []; // TODO: needed?
this.children = [];
this.result = {
id: this.id,
@@ -48,19 +45,8 @@ getJasmineRequireObj().Suite = function() {
this.afterFns.unshift(fn);
};
Suite.prototype.addSpec = function(spec) {
this.children_.push(spec);
this.specs.push(spec); // TODO: needed?
};
Suite.prototype.addSuite = function(suite) {
suite.parentSuite = this;
this.children_.push(suite);
this.suites.push(suite); // TODO: needed?
};
Suite.prototype.children = function() {
return this.children_;
Suite.prototype.addChild = function(child) {
this.children.push(child);
};
Suite.prototype.execute = function(onComplete) {
@@ -70,11 +56,10 @@ getJasmineRequireObj().Suite = function() {
return;
}
var allFns = [],
children = this.children_;
var allFns = [];
for (var i = 0; i < children.length; i++) {
allFns.push(wrapChildAsAsync(children[i]));
for (var i = 0; i < this.children.length; i++) {
allFns.push(wrapChildAsAsync(this.children[i]));
}
this.onStart(this);
@@ -96,7 +81,7 @@ getJasmineRequireObj().Suite = function() {
return function(done) { child.execute(done); };
}
};
return Suite;
};

View File

@@ -15,4 +15,4 @@ getJasmineRequireObj().Timer = function() {
}
return Timer;
};
};

View File

@@ -6,13 +6,12 @@ getJasmineRequireObj().base = function(j$) {
j$.MAX_PRETTY_PRINT_DEPTH = 40;
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
j$.getGlobal = function() {
function getGlobal() {
return this;
}
return getGlobal();
};
j$.getGlobal = (function() {
var jasmineGlobal = eval.call(null, "this");
return function() {
return jasmineGlobal;
};
})();
j$.getEnv = function(options) {
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
@@ -51,18 +50,18 @@ getJasmineRequireObj().base = function(j$) {
j$.createSpy = function(name, originalFn) {
var spyStrategy = new j$.SpyStrategy({
name: name,
fn: originalFn,
getSpy: function() { return spy; }
}),
callTracker = new j$.CallTracker(),
spy = function() {
callTracker.track({
object: this,
args: Array.prototype.slice.apply(arguments)
});
return spyStrategy.exec.apply(this, arguments);
};
name: name,
fn: originalFn,
getSpy: function() { return spy; }
}),
callTracker = new j$.CallTracker(),
spy = function() {
callTracker.track({
object: this,
args: Array.prototype.slice.apply(arguments)
});
return spyStrategy.exec.apply(this, arguments);
};
for (var prop in originalFn) {
if (prop === 'and' || prop === 'calls') {
@@ -83,7 +82,7 @@ getJasmineRequireObj().base = function(j$) {
return false;
}
return putativeSpy.and instanceof j$.SpyStrategy &&
putativeSpy.calls instanceof j$.CallTracker;
putativeSpy.calls instanceof j$.CallTracker;
};
j$.createSpyObj = function(baseName, methodNames) {

View File

@@ -37,7 +37,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) message += ",";
if (i > 0) {
message += ",";
}
message += " " + j$.pp(expected[i]);
}
}
@@ -52,9 +54,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
var result = true;
for (var i = 0; i < customTesters.length; i++) {
result = customTesters[i](a, b);
if (result) {
return true;
var customTesterResult = customTesters[i](a, b);
if (!j$.util.isUndefined(customTesterResult)) {
return customTesterResult;
}
}
@@ -85,11 +87,11 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// 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) { return a !== 0 || 1 / a == 1 / b; }
// A strict comparison is necessary because `null == undefined`.
if (a === null || b === null) return a === b;
if (a === null || b === null) { return a === b; }
var className = Object.prototype.toString.call(a);
if (className != Object.prototype.toString.call(b)) return false;
if (className != Object.prototype.toString.call(b)) { return false; }
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
case '[object String]':
@@ -113,14 +115,14 @@ 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') { return false; }
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = aStack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] == a) return bStack[length] == b;
if (aStack[length] == a) { return bStack[length] == b; }
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
@@ -134,7 +136,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) break;
if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
}
}
} else {
@@ -151,13 +153,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) break;
if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
}
}
// Ensure that both objects contain the same number of properties.
if (result) {
for (key in b) {
if (has(b, key) && !(size--)) break;
if (has(b, key) && !(size--)) { break; }
}
result = !size;
}
@@ -176,4 +178,4 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return typeof obj === 'function';
}
}
};
};

View File

@@ -3,14 +3,16 @@ getJasmineRequireObj().util = function() {
var util = {};
util.inherit = function(childClass, parentClass) {
var subclass = function() {
var Subclass = function() {
};
subclass.prototype = parentClass.prototype;
childClass.prototype = new subclass();
Subclass.prototype = parentClass.prototype;
childClass.prototype = new Subclass();
};
util.htmlEscape = function(str) {
if (!str) return str;
if (!str) {
return str;
}
return str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
@@ -18,7 +20,9 @@ getJasmineRequireObj().util = function() {
util.argsToArray = function(args) {
var arrayOfArgs = [];
for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
for (var i = 0; i < args.length; i++) {
arrayOfArgs.push(args[i]);
}
return arrayOfArgs;
};

View File

@@ -1,8 +1,8 @@
jasmineRequire.HtmlReporter = function(j$) {
var noopTimer = {
start: function(){},
elapsed: function(){ return 0; }
start: function() {},
elapsed: function() { return 0; }
};
function HtmlReporter(options) {
@@ -73,7 +73,8 @@ jasmineRequire.HtmlReporter = function(j$) {
symbols.appendChild(createDom("li", {
className: result.status,
id: "spec_" + result.id,
title: result.fullName}
title: result.fullName
}
));
if (result.status == "failed") {

View File

@@ -16,4 +16,4 @@ jasmineRequire.ResultsNode = function() {
}
return ResultsNode;
};
};

View File

@@ -3,4 +3,4 @@ jasmineRequire.html = function(j$) {
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
j$.QueryString = jasmineRequire.QueryString();
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
};
};

View File

@@ -1,3 +1,3 @@
getJasmineRequireObj().version = function() {
return "<%= version %>";
};
};

View File

@@ -1,12 +1,14 @@
#!/bin/bash -e
export DISPLAY=:99.0
/etc/init.d/xvfb start
if [ $USE_SAUCE == true ]
then
if [ $TRAVIS_SECURE_ENV_VARS == true ]
then
curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
else
echo "skipping tests since we can't use sauce"
exit 0
fi
fi
bundle exec rake jasmine:ci

3
travis-docs-script.sh Normal file
View File

@@ -0,0 +1,3 @@
git clone https://github.com/jasmine/jasmine.github.io.git
bundle exec rake jasmine:ci JASMINE_CONFIG_PATH=jasmine.github.io/2.0/spec/support/jasmine.yml