Compare commits

...

114 Commits

Author SHA1 Message Date
slackersoft
216b40439f Attempt to use selenium runner from source, to fix dependency loop 2014-11-14 12:41:50 -08:00
slackersoft
590a9d9d41 bump version to 2.1.0 2014-11-14 07:54:19 -08:00
Davis W. Frank
66c8624022 Updating links in release notes 2014-11-11 09:46:38 -08:00
Davis W. Frank
75e5a5c308 Fix for wayward underscore and Anchorman bug 2014-11-10 17:24:06 -08:00
Davis W. Frank
9b5c20cc19 Adding first crack at 2.1 release notes 2014-11-10 17:15:57 -08:00
slackersoft
cc720e7f56 Add release notes for previous releases, so they can be removed from the wiki
[#54582902]
2014-11-06 08:21:31 -08:00
Gregg Van Hove
1426416666 Merge pull request #700 from tkrotoff/patch-1
Simplifies SpecRunner.html
2014-11-04 13:20:55 -08:00
Tanguy Krotoff
197cb13817 Simplifies SpecRunner.html
No need to specify type="text/javascript" for script tag
No need to specify type="text/css" for link tag with rel="stylesheet"
2014-11-04 10:30:11 +01:00
slackersoft
816b7d701f Merge branch 'charleshansen-to_contain_array_like_objects' 2014-11-03 13:10:13 -08:00
Charles Hansen
da6813ef0d toContain works with array-like objects (Arguments, HTMLCollections, etc)
Fixes #699

Don't rely on Array.prototype.indexOf for testing containment (not in IE8)
2014-11-03 13:09:57 -08:00
slackersoft
a4d134521a Revert "toContain works with array-like objects (Arguments, HTMLCollections, etc)"
IE 8 doesn't have Array.prototype.indexOf so this breaks there.
Reverting until we can figure out a better way to solve across all
supported browsers.

This reverts commit 663fbd0cdb.
2014-11-01 14:28:32 -07:00
slackersoft
d4fc787ea7 Merge branch 'charleshansen-to_contain_array_like_objects' 2014-10-30 13:08:45 -07:00
Charles Hansen
663fbd0cdb toContain works with array-like objects (Arguments, HTMLCollections, etc)
Fix #699
2014-10-30 13:08:16 -07:00
Matt Parker
cf83ae474c Added Sheel to the Maintainers Emeritus list 2014-10-25 08:07:15 -07:00
Matt Parker
325c5a2288 Name / Email / Org updates in README 2014-10-25 07:51:18 -07:00
Gregg Van Hove
3ca687a9ad Merge pull request #691 from ertrzyiks/fix-spec-title
Fixed isPendingSpecException test title
2014-10-22 09:52:10 -07:00
Mateusz Derks
3b557f85c7 Fixed isPendingSpecException test title 2014-10-17 15:36:24 +02:00
slackersoft
b67a19507f Add notes for releasing new versions of the docs 2014-10-11 22:13:26 -07:00
slackersoft
ecae3d47a7 Use the jasmine-npm tarball, since that works on travis
[#80505862]
2014-10-11 15:04:04 -07:00
slackersoft
a76d6d1cd4 Pass in the current distribution when running node specs
- npm package spec can use beforeAll/afterAll now
- also depend on github repo directly instead of the tarball

[finish #80505862]
2014-10-11 14:54:08 -07:00
slackersoft
916dc03d9c build distribution with deprecated console
[#80410002]
2014-10-11 14:28:51 -07:00
slackersoft
2151a13705 Let's just use the print function that's passed in for deprecation messaging
[#80410002]
2014-10-11 14:20:19 -07:00
slackersoft
6cc09e00d3 Oh right, IE doesn't have console by default
[#80410002]
2014-10-11 13:54:41 -07:00
slackersoft
6d6c31328b Deprecate console reporter
- jasmine-npm has its own version so it's no longer dependent on this
  one.

[finish #80410002]
2014-10-11 13:34:45 -07:00
Gerg
c8cd2eabe5 Fixes console check for IE8
- Was causing IE8 to hang for some reason
- Also reverts previous commit, not that issue was resolved

[#79533268][fixes #80356450]
2014-10-09 00:41:17 -07:00
Gerg
f77071254a Fixes additional odd IE8 failure
[#79533268]
2014-10-08 23:14:40 -07:00
Gerg
8880729250 JsApiReporter suiteResults only includes suite results
- It was including suite starts also

[#79533268]
2014-10-08 22:33:36 -07:00
slackersoft
9ad15eeaba Merge branch 'akoptsov-patch-1' 2014-10-08 12:52:40 -07:00
Alexander Koptsov
10ca5f0246 Fixed path to src files in node_example
There's no such folder as 'jasmine_examples'
2014-10-07 16:35:38 +04:00
Gerg
a5cd2731b4 Fixes CI for IE8
For some reason, when you put this spec in a describe block, it causes
specs to hang on IE8. I tried to debug this for a while, and I have no
idea what is happening.

[#79533268]
2014-10-05 14:33:40 -07:00
Gerg
b12974db2e Adds suiteResults method to JsApiReporter
- Behaves similarly to to specResults
- Since suites were stored in an object instead of an array and the
  current interface exposes this object, we now must keep track of suites
  twice in the reporter. We cannot just construct the object lazily,
  because then the object will not update with new suite results
  like it does currently (see JsApiReporterSpec:148).

[#79533268]
2014-10-04 18:36:38 -07:00
slackersoft
f4e5573ee3 Add explicit fail and move on for async functions
- `done` now has a `fail` property which will call the global `fail`
  then continue to the next function in the queue

[finish #73744618] Fix #567 Fix #568
2014-10-02 08:10:29 -07:00
slackersoft
0c77c6cfb5 Use the Gemfile from the docs repo 2014-10-01 13:10:11 -07:00
slackersoft
cfc64a6f5c bundle exec the docs rake tasks 2014-10-01 09:59:39 -07:00
slackersoft
6ab70923b3 Use rake tasks in the docs repo to test it 2014-10-01 08:15:35 -07:00
slackersoft
d9c0b10be4 Remove type from queueableFns since we're not using it to determine afterAll anymore. 2014-09-30 18:28:41 -07:00
slackersoft
a58fd20d82 Build distribution for suite failed status changes 2014-09-26 18:35:06 -07:00
slackersoft
eefa716530 set suite status to failed when afterAll has failures 2014-09-26 09:12:48 -07:00
slackersoft
66c364564e Fix custom timeout specs for firefox 2014-09-26 08:21:54 -07:00
slackersoft
68ba5b6d48 Allow custom timeout for beforeEach, afterEach, beforeAll, afterAll and it
Fix #483
2014-09-25 22:31:00 -07:00
slackersoft
15ae0379ec Add fit and fdescribe to the public interface
They got lost in the merge
2014-09-25 13:19:13 -07:00
slackersoft
1fb0d2eefa Merge branch 'master' of https://github.com/chernetsov/jasmine into chernetsov-master
Fix #678 Close #679
2014-09-25 12:59:10 -07:00
slackersoft
ba0982d89f Merge branch 'beforeAll' into master
Conflicts:
	lib/jasmine-core/boot.js
	lib/jasmine-core/boot/boot.js
	lib/jasmine-core/jasmine.css
	lib/jasmine-core/jasmine.js
	spec/core/SpecSpec.js
	spec/core/SuiteSpec.js
	spec/core/integration/EnvSpec.js
	spec/node_suite.js
	src/core/Env.js
	src/core/requireCore.js
	src/core/util.js
2014-09-24 20:20:39 -07:00
slackersoft
f703539942 build distribution for toThrowError refactor 2014-09-24 18:27:40 -07:00
Misha Chernetsov
62840f72a6 when jasmine clock is installed and date is mocked new Date() instanceof Date should equal true 2014-09-24 15:07:22 -07:00
slackersoft
6d10f97151 Merge branch 'toThrowError_refactor' 2014-09-24 13:23:50 -07:00
slackersoft
15f3d0e9d7 update doc comment for boot.js to match current documentation 2014-09-23 08:22:05 -07:00
slackersoft
b1344d5c73 Add explicit fail function.
- Adds an expectation failure to the current spec

[finishes #70975468] Fix #563
2014-09-23 08:00:46 -07:00
slackersoft
59aaac026c Merge branch 'paladox2015-patch-1' 2014-09-22 13:10:12 -07:00
slackersoft
21f62c697a Merge branch 'patch-1' of https://github.com/paladox2015/jasmine into paladox2015-patch-1 2014-09-22 13:09:07 -07:00
slackersoft
dc93c33af6 Merge branch 'pimterry-trackReturnValues' 2014-09-22 13:04:18 -07:00
slackersoft
4889583d5c Merge branch 'trackReturnValues' of https://github.com/pimterry/jasmine into pimterry-trackReturnValues 2014-09-22 13:04:01 -07:00
slackersoft
41df058171 update contributing doc to indicate use of jasmine-npm 2014-09-20 20:54:45 -07:00
slackersoft
fa837ae90a Don't depend on debugger gem, we don't really have any ruby code here. 2014-09-20 20:17:55 -07:00
slackersoft
c82c958e0d Build distribution for earlier fixes 2014-09-16 13:05:11 -07:00
slackersoft
752e831b30 Merge branch 'mkhanal-chain_spy_andReturn'
Fix #669 #660
2014-09-15 13:10:40 -07:00
slackersoft
bd30065d66 Merge branch 'chain_spy_andReturn' of https://github.com/mkhanal/jasmine into mkhanal-chain_spy_andReturn 2014-09-15 13:10:24 -07:00
slackersoft
84dff421ea Use === when checking for circular dependencies for pretty printing. 2014-09-13 18:58:02 -07:00
Mridul
709e032d1c Added returnValues functionality to spy strategy 2014-09-13 12:41:20 +10:00
Greg Cobb
1290d93b6a Suite result status added when suite is complete
- This makes it easier to detect afterAll failures, because we can
  rely only complete runnables having statuses

[#78306786 & #73741654]
2014-09-09 11:26:32 -07:00
slackersoft
345903220c Refactor toThrowError to be less one huge if/else if/else if block
- This should also improve it's code climate score as well.
- It's also about 20 lines shorter now too :)

[#59524164]
2014-09-07 16:02:42 -07:00
Greg Cobb
3332f93a24 Only run focused runnables inside focused suites
- Focused runnables now walk up the tree to unfocus the first focused
  ancestor. Because of the way the tree is constructed, this makes sure
  that each focused runnable has no focused ancestors.

[#78289686]
2014-09-05 12:25:28 -07:00
slackersoft
3b19d66268 Check for afterAll failures in a more browser independent way.
- Only look at the message, so browsers that don't provide a stack don't
  blow up.
2014-09-04 18:49:14 -07:00
slackersoft
137c1a39f6 Check afterAll failure messages with regexp, since some browsers add more info 2014-09-04 08:15:23 -07:00
slackersoft
9402d59859 Suites report errors in afterAlls in the suiteDone event
- remove `afterAllEvent` from reporters
2014-09-03 22:18:20 -07:00
slackersoft
e8178d061b Merge branch 'tgirardi-issue655'
Fix #655 #658
2014-09-02 13:20:18 -07:00
slackersoft
dd75394ea8 Merge branch 'issue655' of https://github.com/tgirardi/jasmine into tgirardi-issue655 2014-09-02 13:19:31 -07:00
Greg Cobb and Tim Jarratt
6b857d11ce Factor out some common logic between fdesc and desc 2014-08-29 09:25:41 -07:00
Tomás Girardi
eb48c83649 Add specs for intervals that "clear themselves"
Add specs to test if issue #655 is present: the handler of an interval
cannot successfully clear the same interval that generated it's
invocation.

The most direct test consist in setting an interval with a handler that
calls clearInterval over that same interval and make the clock tick for
double of it's period. If the issue is present the interval's handler
will be called twice. If the issue is not present, the first invocation
of the handler will avoid a second one (because of the clearInterval).

Another test is included in order to check if recurring scheduled
functions are rescheduled before being called. Doing this in the reverse
order is the exact cause of the issue.
2014-08-28 20:58:30 -04:00
Greg Cobb and Tim Jarratt
08a35d134d Ensure focused tests are only run once
Required duplicating some of the logic for constructing a suite from
describe so that we could mark a suite as focused in fdescribe, but
otherwise this prevents focused tests from being run more than once.

[#73742944]
2014-08-28 17:54:42 -07:00
Greg Cobb and Tim Jarratt
14824b5f9e Expose fit and fdescribe in boot.js
* adds done() callbacks to existing specs (because we forgot, whoops!)

[Finishes #73742944]
2014-08-28 16:37:37 -07:00
Greg Cobb and Tim Jarratt
9afae3d978 Add a test documenting fits in fdescribes
Yo, this probably isn't the best behavior. Rspec and Ginkgo definitely
do not exhibit this behavior when you nest focused runnables inside
other focused runnables. We thought fixing it, but it seems like a
nontrivial refactoring would be necessary to clean this up.

[#73742944]
2014-08-28 16:19:31 -07:00
Greg Cobb and Tim Jarratt
64a67ed320 Trim extraneous whitespace 2014-08-28 15:55:39 -07:00
Greg Cobb and Tim Jarratt
dee1066652 Focused runnables play nicely with beforeAll/afterAll
[#73742944]
2014-08-28 15:54:27 -07:00
Greg Cobb and Tim Jarratt
d7ab9083be Add focused describe
[#73742944]
2014-08-28 15:43:59 -07:00
Greg Cobb and Tim Jarratt
caee1508d1 Adds a fit function to Env
[#73742944]
2014-08-28 15:37:18 -07:00
slackersoft
3b8326f1e6 Detect global object properly when getting the jasmine require obj
- Pull global detection into requireCore and pass the global to base

Fix #569
[fix #73684570]
2014-08-28 13:31:04 -07:00
Greg Cobb and Tim Jarratt
980509cd7b Preserve relative order of "alls" w.r.t. "eachs"
[Finishes #73742528]
2014-08-28 11:54:58 -07:00
Greg Cobb and Tim Jarratt
b984ff2fa6 Run before,afterAlls as 'eachs' when specifying runnablesToRun
- Fix bug where beforeAlls were being mutated in Suite#execute
- When Env.execute() receives a list of runnables, beforeAlls and
  afterAlls are collected as beforeEachs and afterEachs. This allows
  runnables to be specified in any order, regardless of if any of them
  have before/afterAlls.
- Spec constructor takes a single function that returns both before and
  afters, instead of two functions. This breaks the current interface
  for constructing a Spec.

[#73742528]
2014-08-28 11:54:54 -07:00
Greg Cobb and Tim Jarratt
61bf9ac7d7 Improve quality of async timeout for afterAll spec
We found that this test was always passing and had strange interactions
with the ordering of other specs. Rewriting it to explicitly finish the
afterAll after a specified interval makes it fail correctly.

[#73742528]
2014-08-28 11:54:46 -07:00
Greg Cobb and Tim Jarratt
5b397ff33e Revert "Deprecate suite/spec ordering hook ."
This reverts commit 76fafa0388.

[#73742528]
2014-08-28 11:54:27 -07:00
Greg Cobb and Tim Jarratt
cd4d5c2445 ConsoleReporter exits 1 when afterAll events occur
[Finishes #67068790]
2014-08-27 14:45:59 -07:00
Greg Cobb and Tim Jarratt
5b6edff3fd Report AfterAll failures as they occur
There didn't seem to be a valid reason to wait until the very end to
report these.
2014-08-27 14:01:28 -07:00
Greg Cobb and Tim Jarratt
cc3678f033 Refactor suite to share reportExpectationFailure func
This was shared between our suite factory and the suite factory.
Sweet.
2014-08-27 13:50:56 -07:00
Greg Cobb and Tim Jarratt
35f52bcb24 Rewrite an incorrect suite spec 2014-08-27 12:27:11 -07:00
slackersoft
f8bccabf03 Move afterAll reporting into Suite since that's where they're being tracked 2014-08-27 08:13:17 -07:00
Greg Cobb and Tim Jarratt
97867b2bf5 Reports expectation failures in afterAlls
This makes the specs green and appears to work for most cases. I have a
number of concerns about the implementation and would appreciate
ideas/feedback.

- Suite#addExpecationResult infers if it is coming from an afterAll fn
  based on if the first child of the suite is finished. This assumes
  that the first child of the suite is a spec (this appears to be true
  as long as there is at least one spec in the suite)
  - Suites behave like unfinished specs. Because suites will propagate
    expectation failures to their children suites, the afterAll
    expectation reporting appears to work for suites without specs
    unless you have:
    1) An otherwise empty suite with an afterAll
    2) An afterAll'd suite whose first suite is empty (or whose first
    suite's first suite is empty (and so on))
- Changed afterAllError to afterAllEvent, so it can accommodate both
  errors and expectation failures. The reporter now receives a string
  instead of the actual error object. The loss of the object doesn't
  affect our reporters, but may be a nice-to-have for other reporters/
  the future.
- The gap between the expectations caught in Suite and QueueRunner (who
  triggers reporting via an injected callback) is an array injected into
  QR by the Suite. The array is then flushed at some point (currently
  after the attempt… functions). This works, but is a bit goofy.

[#73741654]
2014-08-26 18:04:12 -07:00
slackersoft
18eb6e2f36 Don't run npm package specs in browsers 2014-08-26 13:18:16 -07:00
Tomás Girardi
51462f369b Allow clearInterval to clear it's own interval
As described in issue #655, the handler of an interval cannot
successfully clear the same interval that generated it's invocation.

Solve this issue by changing the order in which interval's handlers are
called and then rescheduled to: first reschedule it and then call it.

The actual order (call first then reschedule) produces that, during the
execution of the interval's handler, the handler is not registered as
a function to run after a timeout or interval ("scheduledFunctions"),
because it was previously unregistered. Consequently, if the handler
calls clearInterval, that function wont be able to find the handler and
remove it completely.
2014-08-26 12:01:49 -04:00
slackersoft
ea57ad97cf Add some tests to make sure we're packaging up the npm properly 2014-08-26 08:08:04 -07:00
slackersoft
3132d98f23 Bump version to 2.0.4 now that I think npm files are sorted 2014-08-24 21:14:11 -07:00
slackersoft
b799f54bc9 Remove runtime dependency on 'glob' so we have no runtime deps
- Clean up .npmignore a bit more
2014-08-24 21:11:50 -07:00
slackersoft
3c051fc291 bump to 2.0.3 to fix npm dependencies 2014-08-22 22:50:46 -07:00
slackersoft
6b937da863 Fix npm dependencies 2014-08-22 22:47:43 -07:00
paladox2015
ae94dd1bfa Update json2.js 2014-06-27 10:51:02 +01:00
slackersoft
1bad048c15 Extract afterAll checking from queueRunner 2014-06-20 08:16:42 -07:00
slackersoft
f0892a55aa report when an async afterAll doesn't call in time 2014-06-06 18:41:06 -07:00
Gregg Van Hove
6066c71966 Add failing specs for expectation failures in afterAll 2014-04-18 16:37:27 -07:00
Gregg Van Hove
0d4b04d37c rename afterAllException to afterAllError
It should also handle expectation failures
2014-04-18 16:00:02 -07:00
Christopher Amavisca and Greg Cobb
668846147c Fix issues with displaying error messages for afterAll (browser compatibility)
- Switch from showing error stack to showing message/description since only chrome/ff support stack
- Fallback to error.description if error.message is undefined
- Made exceptionList variable name consistent between both reporters
2014-03-06 18:25:49 -08:00
Christopher Amavisca and Greg Cobb
76fafa0388 Deprecate suite/spec ordering hook .
- Remove parameter from env.execute()
- Remove deprecated test
- Set runnablesToRun to always start with the topSuite

[#66789174]
2014-03-06 16:54:53 -08:00
Christopher Amavisca and Greg Cobb
bed1c15ea4 HtmlReporter shows error alerts for afterAllExceptions
-Add list of exceptions in HtmlReporter to push to on error
-Create alerts for each exception in the list (with stack trace)

[#67055688]
2014-03-06 15:39:04 -08:00
Christopher Amavisca and Greg Cobb
6caf4c5de2 Print afterAllExceptions to the console.
- Add afterAllException function to ConsoleReporter
- Print the stack traces of the errors at the end of the console output

[#67055730]
2014-03-06 15:02:55 -08:00
Christopher Amavisca and Greg Cobb
97ae9a2d88 After all exceptions dispatch to reporter hook
- Add 'afterAllException' hook to reporter dispatch, we might want to make this more generic in the future
- Add afterAllException function to HtmlReporter

[#66789174]
2014-03-06 12:01:37 -08:00
Christopher Amavisca and Greg Cobb
a3c3505086 beforeAll can have expectations and passes expectation failures to its children
[#66789174]
2014-03-05 16:27:58 -08:00
Christopher Amavisca and Greg Cobb
a9e0112a9b Throw error if you add a custom matcher or equality outside of a runnable
[#66789174]
2014-03-05 14:37:17 -08:00
Christopher Amavisca and Greg Cobb
a2ac5ef3b6 Throw error if you define a spy outside of a runnable
[#66789174]
2014-03-05 14:27:19 -08:00
Christopher Amavisca and Greg Cobb
b200952195 Only clear resources if suite is not disabled
[#66789174]
2014-03-05 14:00:57 -08:00
Christopher Amavisca, Greg Cobb and Sheel Choksi
752a36d3ff Manage spys/matchers/custom equalities for beforeAll
- Refactor expectations to take list of matchers
- Add spyRegistry to manage runnables' spies
- Add clone util

[#66789174]
2014-03-05 10:28:37 -08:00
Gregg Van Hove and Sheel Choksi
52026fb0f7 beforeAll/afterAll can be timed out and errors are applied to all children specs 2014-03-03 16:13:59 -08:00
Gregg Van Hove and Sheel Choksi
e17a2cb1e0 share usercontext for full suite 2014-03-03 11:57:32 -08:00
Gregg Van Hove and Sheel Choksi
ec5695acc1 first (naive) pass at beforeAll/afterAll 2014-03-03 09:26:39 -08:00
pimterry
b1d4ab09af Add tests for call return value tracking 2013-12-08 13:40:25 +00:00
pimterry
3b52d015ea Track return values of spy functions 2013-12-08 13:40:24 +00:00
69 changed files with 4001 additions and 1289 deletions

View File

@@ -1,6 +1,5 @@
dist/
grunt/
images/
node_modules
release_notes/
spec/
@@ -15,6 +14,8 @@ jasmine-core.gemspec
.gitignore
*.sh
Gruntfile.js
lib/jasmine-core.rb
lib/jasmine-core/boot/
lib/jasmine-core/spec
lib/jasmine-core/version.rb
lib/jasmine-core/*.py

View File

@@ -100,7 +100,7 @@ Jasmine uses the [Jasmine Ruby gem](http://github.com/pivotal/jasmine-gem) to te
...and then visit `http://localhost:8888` to run specs.
Jasmine uses Node.js with a custom runner to test outside of a browser.
Jasmine uses the [Jasmine NPM package](http://github.com/pivotal/jasmine-npm) to test itself in a Node.js/npm environment.
$ grunt execSpecsInNode

View File

@@ -1,12 +1,9 @@
source 'https://rubygems.org'
gem "jasmine", :git => 'https://github.com/pivotal/jasmine-gem.git'
# gem "jasmine", path: "/Users/pivotal/workspace/jasmine-gem"
unless ENV["TRAVIS"]
group :debug do
gem 'debugger'
end
end
# gem "jasmine", path: "../jasmine-gem"
gemspec
gem "jasmine_selenium_runner", :github => 'jasmine/jasmine_selenium_runner'
gem "anchorman"

View File

@@ -37,10 +37,19 @@ module.exports = function(grunt) {
grunt.registerTask("execSpecsInNode",
"Run Jasmine core specs in Node.js",
function() {
var exitInfo = require("shelljs").exec("node_modules/.bin/jasmine");
if (exitInfo.code !== 0) {
grunt.fail.fatal("Specs Failed", exitInfo.code);
}
var done = this.async(),
Jasmine = require('jasmine'),
jasmineCore = require('./lib/jasmine-core.js'),
jasmine = new Jasmine({jasmineCore: jasmineCore});
jasmine.loadConfigFile('./spec/support/jasmine.json');
jasmine.configureDefaultReporter({
onComplete: function(passed) {
done(passed);
}
});
jasmine.execute();
}
);

View File

@@ -53,12 +53,13 @@ For the Jasmine Python Egg:<br>
## Maintainers
* [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
* [Davis W. Frank](mailto:dwfrank@pivotal.io), Pivotal Labs
* [Rajan Agaskar](mailto:rajan@pivotal.io), Pivotal Labs
* [Gregg Van Hove](mailto:ghove@pivotal.io), Pivotal Labs
### Maintainers Emeritus
* [Christian Williams](mailto:antixian666@gmail.com), Square
* [Christian Williams](mailto:antixian666@gmail.com), Cloud Foundry
* Sheel Choksi
Copyright (c) 2008-2014 Pivotal Labs. This software is licensed under the MIT License.

View File

@@ -33,7 +33,7 @@ When ready to release - specs are all green and the stories are done:
1. Build the standalone distribution with `grunt buildStandaloneDist`
1. Make sure you add the new ZIP file to git
1. Should we still do this? Given we want to use guthub releases...
1. Should we still do this? Given we want to use github releases...
### Release the Python egg
@@ -52,6 +52,13 @@ When ready to release - specs are all green and the stories are done:
1. `npm adduser` to save your credentials locally
1. `npm publish .` to publish what's in `package.json`
### Release the docs
Probably only need to do this when releasing a minor version, and not a patch version.
1. `cp edge ${version}` to copy the current edge docs to the new version
1. Add a link to the new version in `index.html`
### Finally
1. Visit the [Releases page for Jasmine](https://github.com/pivotal/jasmine/releases), find the tag just pushed.

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

Binary file not shown.

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

Binary file not shown.

View File

@@ -1,23 +1,23 @@
<!DOCTYPE HTML>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Jasmine Spec Runner v<%= jasmineVersion %></title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-<%= jasmineVersion %>/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="lib/jasmine-<%= jasmineVersion %>/jasmine.css">
<link rel="stylesheet" href="lib/jasmine-<%= jasmineVersion %>/jasmine.css">
<script type="text/javascript" src="lib/jasmine-<%= jasmineVersion %>/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-<%= jasmineVersion %>/jasmine-html.js"></script>
<script type="text/javascript" src="lib/jasmine-<%= jasmineVersion %>/boot.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/jasmine.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/jasmine-html.js"></script>
<script src="lib/jasmine-<%= jasmineVersion %>/boot.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="src/Player.js"></script>
<script type="text/javascript" src="src/Song.js"></script>
<script src="src/Player.js"></script>
<script src="src/Song.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/SpecHelper.js"></script>
<script type="text/javascript" src="spec/PlayerSpec.js"></script>
<script src="spec/SpecHelper.js"></script>
<script src="spec/PlayerSpec.js"></script>
</head>

View File

@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
s.name = "jasmine-core"
s.version = Jasmine::Core::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Rajan Agaskar", "Davis W. Frank", "Christian Williams"]
s.authors = ["Rajan Agaskar", "Davis W. Frank", "Gregg Van Hove"]
s.summary = %q{JavaScript BDD framework}
s.description = %q{Test your JavaScript without any framework dependencies, in any environment, and with a nice descriptive syntax.}
s.email = %q{jasmine-js@googlegroups.com}

View File

@@ -54,7 +54,10 @@ getJasmineRequireObj().ConsoleReporter = function() {
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
};
},
failedSuites = [];
print('ConsoleReporter is deprecated and will be removed in a future version.');
this.jasmineStarted = function() {
specCount = 0;
@@ -89,9 +92,12 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline();
var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0);
};
@@ -116,6 +122,13 @@ getJasmineRequireObj().ConsoleReporter = function() {
}
};
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this;
function printNewline() {
@@ -160,6 +173,17 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline();
}
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
}
return ConsoleReporter;

View File

@@ -1,29 +1,37 @@
module.exports = require("./jasmine-core/jasmine.js");
module.exports.boot = require('./jasmine-core/node_boot.js');
module.exports.files = (function() {
var path = require('path'),
fs = require('fs'),
glob = require('glob');
var path = require('path'),
fs = require('fs');
var rootPath = path.join(__dirname, "jasmine-core"),
bootFiles = ['boot.js'],
nodeBootFiles = ['node_boot.js'];
var rootPath = path.join(__dirname, "jasmine-core"),
bootFiles = ['boot.js'],
nodeBootFiles = ['node_boot.js'],
cssFiles = [],
jsFiles = [],
jsFilesToSkip = ['jasmine.js'].concat(bootFiles, nodeBootFiles);
var cssFiles = glob.sync(path.join(rootPath, '*.css')).map(path.basename);
var jsFiles = glob.sync(path.join(rootPath, '*.js')).map(path.basename);
fs.readdirSync(rootPath).forEach(function(file) {
if(fs.statSync(path.join(rootPath, file)).isFile()) {
switch(path.extname(file)) {
case '.css':
cssFiles.push(file);
break;
case '.js':
if (jsFilesToSkip.indexOf(file) < 0) {
jsFiles.push(file);
}
break;
}
}
});
['jasmine.js'].concat(bootFiles, nodeBootFiles).forEach(function(file) {
jsFiles.splice(jsFiles.indexOf(file), 1);
});
return {
path: rootPath,
bootDir: rootPath,
bootFiles: bootFiles,
nodeBootFiles: nodeBootFiles,
cssFiles: cssFiles,
jsFiles: ['jasmine.js'].concat(jsFiles),
imagesDir: path.join(__dirname, '../images')
};
}());
module.exports.files = {
path: rootPath,
bootDir: rootPath,
bootFiles: bootFiles,
nodeBootFiles: nodeBootFiles,
cssFiles: cssFiles,
jsFiles: ['jasmine.js'].concat(jsFiles),
imagesDir: path.join(__dirname, '../images')
};

View File

@@ -21,7 +21,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
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.
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` and `jasmine_html.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.

View File

@@ -1,5 +1,5 @@
/**
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.
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` and `jasmine_html.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.

View File

@@ -1,6 +1,6 @@
describe("Player", function() {
var Player = require('../../jasmine_examples/Player.js');
var Song = require('../../jasmine_examples/Song.js');
var Player = require('../src/Player.js');
var Song = require('../src/Song.js');
var player;
var song;

View File

@@ -46,7 +46,8 @@ jasmineRequire.HtmlReporter = function(j$) {
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols;
symbols,
failedSuites = [];
this.initialize = function() {
clearPrior();
@@ -83,6 +84,10 @@ jasmineRequire.HtmlReporter = function(j$) {
};
this.suiteDone = function(result) {
if (result.status == 'failed') {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
@@ -96,7 +101,7 @@ jasmineRequire.HtmlReporter = function(j$) {
var failures = [];
this.specDone = function(result) {
if(noExpectations(result) && console && console.error) {
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
@@ -178,6 +183,15 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
for(i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message;
var errorBarClassName = 'bar errored';
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage));
}
}
var results = find('.results');
results.appendChild(summary);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
http://www.JSON.org/json2.js
2009-08-17
json2.js
2014-02-04
Public Domain.
@@ -8,6 +8,14 @@
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
@@ -136,15 +144,9 @@
This is a reference implementation. You are free to copy, modify, or
redistribute.
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
*/
/*jslint evil: true */
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
@@ -153,16 +155,16 @@
test, toJSON, toString, valueOf
*/
"use strict";
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (!this.JSON) {
this.JSON = {};
if (typeof JSON !== 'object') {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
@@ -171,37 +173,30 @@ if (!this.JSON) {
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function () {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
var cx,
escapable,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
meta,
rep;
@@ -213,17 +208,17 @@ if (!this.JSON) {
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
@@ -301,11 +296,11 @@ if (!this.JSON) {
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
@@ -315,8 +310,8 @@ if (!this.JSON) {
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
@@ -328,7 +323,7 @@ if (!this.JSON) {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
@@ -340,9 +335,11 @@ if (!this.JSON) {
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
@@ -351,7 +348,18 @@ if (!this.JSON) {
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
};
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
@@ -382,7 +390,7 @@ if (!this.JSON) {
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
@@ -397,6 +405,7 @@ if (!this.JSON) {
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
@@ -412,7 +421,7 @@ if (!this.JSON) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
@@ -430,6 +439,7 @@ if (!this.JSON) {
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
@@ -451,10 +461,10 @@ if (!this.JSON) {
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
@@ -466,8 +476,9 @@ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.

View File

@@ -4,6 +4,6 @@
#
module Jasmine
module Core
VERSION = "2.0.2"
VERSION = "2.1.0"
end
end

View File

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

22
release_notes/1.3.0.md Normal file
View File

@@ -0,0 +1,22 @@
# Jasmine Core 1.3.0 Release Notes
## Summary
This version was a very incremental release that merged in some pull requests for bug fixes.
## Features
* HTML Runner exposes UI to not swallow Exceptions, instead raising as soon as thrown
* Migrated homepage content to Wiki
* Made a far more useful [tutorial page](http://pivotal.github.com/jasmine)
* Added a `toBeNaN` matcher
## Fixes
* Better detection of in-browser vs. not
* `afterEach` functions will run now even when there is a timeout
* `toBeCloseTo` matcher is more accurate
* More explicit matcher messages for spies
* Better equality comparisons for regular expressions
* Improvements to the Pretty Printer: controllable recursion depth, don't include inherited properties
* Fix where `for` was being used as a property on an object (failed on IE)

12
release_notes/1.3.1.md Normal file
View File

@@ -0,0 +1,12 @@
# Jasmine Core 1.3.1 Release Notes
## Summary
This release is for browser compatibility fixes
## Changes
### Features
Fixing test runner failures in IE 6/7/8

83
release_notes/2.1.0.md Normal file
View File

@@ -0,0 +1,83 @@
# Jasmine Core 2.1.0 Release Notes
## Summary
This is the release of Jasmine 2.1.
## Features
- Support for focused specs via `fit` and `fdescribe`
- Support for `beforeAll` and `afterAll`
- Support for an explicit `fail` function, both in synchronous and asynchronous specs
- Allow custom timeout for `beforeEach`, `afterEach`, `beforeAll`, `afterAll` and `it`
- Spies now track return values
- Specs can now specify their own timeouts
- Testing in Node.js via the official Jasmine Node Module
- Spec results now have `suiteResults` method that behaves similarly to to `specResults`
- HtmlReporter shows error alerts for afterAllExceptions
## Bugs
- CI now works for IE8 (this was releated to `ConsoleReporter` below)
- Detect global object properly when getting the jasmine require obj
- Fixes Issue #[569][issue_569] - [Tracker Story #73684570](http://www.pivotaltracker.com/story/73684570)
## Deprecations
### `ConsoleReporter` as part of Jasmine core
The Console Reporter exists nearly entirely for the old manner of running Jasmine's own specs in node.js. As we are now supporting node.js officially, this reporter code no longer needs to be in this repo and instead will be in the Jasmine npm.
For now you will see a deprecation message. It will be removed entirely in Jasmine 3.0.
## Documentation
- Release Notes from previous releases now live at [Jasmine's GitHub release page][releases]. See Tracker Story #[54582902][tracker_1]
- Better instructions for releasing new documentation
[releases]: https://github.com/pivotal/jasmine/releases
[tracker_1]: http://www.pivotaltracker.com/story/54582902
## Pull Requests and Issues
- Simplification of HTMLtags in SpecRunner.html
- Merges #[700][issue_700] from @tkrotoff
- `toContain` works with array-like objects (Arguments, HTMLCollections, etc)
- Merges #[699][issue_699] from @charleshansen
- Fixed isPendingSpecException test title
- Merges #[691][issue_691] from @ertrzyiks
- Fixed an issue with example code in the npm
- Merges #[686][issue_686] from @akoptsov
- When the Jasmine clock is installed and date is mocked, `new Date() instanceof Date` should equal `true` Issue #[678][issue_678] & Issue #[679][issue_679] from @chernetsov
- Support for an explicit `fail` function, both in synchronous and asynchronous specs
- Fixes Issue #[567][issue_567], Issue #[568][issue_568], and Issue #[563][issue_563]
- Allow custom timeout for `beforeEach`, `afterEach`, `beforeAll`, `afterAll` and `it`
- Fixes Issue #[483][issue_483] - specs can now specify their own timeouts
- Spies can track return values
- Fixes Issue #[660][issue_660], Merged Issue #[669][issue_669] from @mkhanal
- Interval handlers can now clear their interval
- Fixes Issue #[655][issue_655] Merged Issue #[658][issue_658] from @tgirardi
- Updated to the latest `json2.js`
- Merges #[616][issue_616] from @apaladox2015
------
_Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_
[issue_569]: http://github.com/pivotal/jasmine/issues/569
[issue_700]: http://github.com/pivotal/jasmine/issues/700
[issue_699]: http://github.com/pivotal/jasmine/issues/699
[issue_691]: http://github.com/pivotal/jasmine/issues/691
[issue_678]: http://github.com/pivotal/jasmine/issues/678
[issue_679]: http://github.com/pivotal/jasmine/issues/679
[issue_567]: http://github.com/pivotal/jasmine/issues/567
[issue_568]: http://github.com/pivotal/jasmine/issues/568
[issue_563]: http://github.com/pivotal/jasmine/issues/563
[issue_483]: http://github.com/pivotal/jasmine/issues/483
[issue_660]: http://github.com/pivotal/jasmine/issues/660
[issue_669]: http://github.com/pivotal/jasmine/issues/669
[issue_655]: http://github.com/pivotal/jasmine/issues/655
[issue_658]: http://github.com/pivotal/jasmine/issues/658
[issue_616]: http://github.com/pivotal/jasmine/issues/616
[issue_686]: http://github.com/pivotal/jasmine/issues/686

View File

@@ -0,0 +1,110 @@
# Release 1.0.1.1 — November 9, 2010
## Jasmine Gem
## Bugs fixed
* Rails 3.0 and RSpec 2.0 are now supported.
## Known issues
* Rails 3 generators are not yet implemented -- coming soon!
-----
# Release 1.0.1 — October 5, 2010
-----
## Jasmine Core
## Bugs fixed
* Bug fixes for Internet Explorer (thanks fschwiet, fabiomcosta, and jfirebaugh).
## Jasmine Gem
## Bugs fixed
* Bug fix for Windows (thanks jfirebaugh).
-----
# Release 1.0 — September 14, 2010
-----
## Jasmine Core
## Features
* `waitsFor()` arguments can now be specified in any order. Timeout and message are optional.
* The default `waitsFor()` timeout period is now specified in `env.defaultTimeoutInterval`; the default value is 5 seconds.
* Added link to jasmine site from html runner.
* Added license file to standalone distribution.
* New friendly version number.
## Bugs fixed
* `waitsFor()` hanged forever if latch function never returned true.
* The `not.toThrow()` matcher threw an exception when used with no args.
* The `toThrow()` matcher, when inverted, gave misleading failure messages.
* Spy matchers, when inverted, gave misleading failure messages.
## Deprecations
* Deprecated `waits()` block in favor of `waitsFor()`; `waits()` will be removed in a future release.
* Deprecated `toNotBe()`, `toNotEqual()`, `toNotMatch()`, and `toNotContain()` matchers; they will be removed in a future release.
* Console X was removed from the distribution as it was no longer used.
* To give us some flexibility for future features, wrapped matcher functions now return `undefined` (they previously returned `true` or `false`, but this was undocumented).
## Jasmine Gem
## Features
* Jasmine now supports JRuby.
* Jasmine now supports Ruby 1.9.
## Bugs fixed
* Various generator issues fixed.
## Known issues
* Rails 3 and RSpec 2 are not yet fully supported.
-----
# Release 0.11.1 — June 25, 2010
-----
## Jasmine Core
### Features
* Jasmine no longer logs "Jasmine Running…" messages to the log by default. This can be enabled in runner.html by adding 'trivialReporter.logRunningSpecs = true;'.
* The `wasCalled()`, `wasCalledWith()`, `wasNotCalled()` and `wasNotCalledWith()` matchers have been deprecated. The new matchers `toHaveBeenCalled()` and `toHaveBeenCalledWith()` have been added. You can use the `not` prefix to achieve equivalent of the `wasNot…()` expectation (e.g. `not.toHaveBeenCalled()`).
## Notables
* A barebones version of Jasmine is now available on <a href="http://pivotal.github.com/jasmine/">http://pivotal.github.com/jasmine/</a>.
-----
# Release 0.11.0 — June 23, 2010
-----
## Jasmine Core
## Features
* The version number has been removed from the generated single-file /lib/jasmine.js. We're also now uploading this file, with the version number in the filename, to github's Downloads page.
* Old-style matchers (those using this.report(), from before 0.10.x) are no longer supported. See the <span class="caps">README</span> for instructions on writing new-style matchers.
* <strong>jasmine.log</strong> pretty-prints its parameters to the spec's output.
* Jasmine no longer depends on 'window'.
* <span class="caps">HTML</span> runner should show number of passes/fails by spec, not expectation.
* Small modification to JsApiReporter data format.
## Bugs fixed:
* If multiple beforeEach blocks were declared, they were executed in reverse order.
* Specs with duplicate names confused TrivialReporter output.
* Errors in describe functions caused later tests to be weirdly nested.
* Nested specs weren't reported properly by the JsApiReporter.
## Known issues:
* If you turn on the mock clock, you'll get a spurious log message at the end of your spec.

View File

@@ -9,7 +9,7 @@ describe("ConsoleReporter", function() {
output += str;
},
getOutput: function() {
return output;
return output.replace('ConsoleReporter is deprecated and will be removed in a future version.', '');
},
clear: function() {
output = "";
@@ -171,27 +171,44 @@ describe("ConsoleReporter", function() {
out.clear();
reporter.jasmineDone({});
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/true to be false/);
expect(out.getOutput()).toMatch(/foo bar baz/);
});
it("calls the onComplete callback when the suite is done", function() {
var onComplete = jasmine.createSpy('onComplete'),
describe('onComplete callback', function(){
var onComplete, reporter;
beforeEach(function() {
onComplete = jasmine.createSpy('onComplete');
reporter = new j$.ConsoleReporter({
print: out.print,
onComplete: onComplete
});
reporter.jasmineStarted();
});
reporter.jasmineDone({});
it("is called when the suite is done", function() {
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(true);
});
expect(onComplete).toHaveBeenCalled();
it('calls it with false if there are spec failures', function() {
reporter.specDone({status: "failed", failedExpectations: []});
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(false);
});
it('calls it with false if there are suite failures', function() {
reporter.specDone({status: "passed"});
reporter.suiteDone({failedExpectations: [{ message: 'bananas' }] });
reporter.jasmineDone();
expect(onComplete).toHaveBeenCalledWith(false);
});
});
describe("with color", function() {
it("reports that the suite has started to the console", function() {
var reporter = new j$.ConsoleReporter({
print: out.print,
@@ -235,5 +252,19 @@ describe("ConsoleReporter", function() {
expect(out.getOutput()).toEqual("\x1B[31mF\x1B[0m");
});
it("displays all afterAll exceptions", function() {
var reporter = new j$.ConsoleReporter({
print: out.print,
showColors: true
});
reporter.suiteDone({ failedExpectations: [{ message: 'After All Exception' }] });
reporter.suiteDone({ failedExpectations: [{ message: 'Some Other Exception' }] });
reporter.jasmineDone();
expect(out.getOutput()).toMatch(/After All Exception/);
expect(out.getOutput()).toMatch(/Some Other Exception/);
});
});
});

View File

@@ -323,6 +323,24 @@ describe("Clock (acceptance)", function() {
expect(clearedFn).not.toHaveBeenCalled();
});
it("can clear a previously set interval using that interval's handler", function() {
var spy = jasmine.createSpy('spy'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setInterval: function() {}}, delayedFunctionScheduler, mockDate),
intervalId;
clock.install();
intervalId = clock.setInterval(function() {
spy();
clock.clearInterval(intervalId);
}, 100);
clock.tick(200);
expect(spy.calls.count()).toEqual(1);
});
it("correctly schedules functions after the Clock has advanced", function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
@@ -371,7 +389,7 @@ describe("Clock (acceptance)", function() {
clock.tick(6);
expect(delayedFn1).toHaveBeenCalled();
expect(delayedFn2).toHaveBeenCalled();
expect(delayedFn2).toHaveBeenCalled();
});
it("does not mock the Date object by default", function() {

View File

@@ -242,5 +242,18 @@ describe("DelayedFunctionScheduler", function() {
expect(innerFn).toHaveBeenCalled();
});
it("executes recurring functions after rescheduling them", function () {
var scheduler = new j$.DelayedFunctionScheduler(),
recurring = function() {
expect(scheduler.scheduleFunction).toHaveBeenCalled();
};
scheduler.scheduleFunction(recurring, 10, [], true);
spyOn(scheduler, "scheduleFunction");
scheduler.tick(10);
});
});

View File

@@ -5,68 +5,6 @@ describe("Env", function() {
env = new j$.Env();
});
it('removes all spies when env is executed', function(done) {
var originalFoo = function() {},
testObj = {
foo: originalFoo
},
firstSpec = jasmine.createSpy('firstSpec').and.callFake(function() {
env.spyOn(testObj, 'foo');
}),
secondSpec = jasmine.createSpy('secondSpec').and.callFake(function() {
expect(testObj.foo).toBe(originalFoo);
});
env.describe('test suite', function() {
env.it('spec 0', firstSpec);
env.it('spec 1', secondSpec);
});
var assertions = function() {
expect(firstSpec).toHaveBeenCalled();
expect(secondSpec).toHaveBeenCalled();
done();
};
env.addReporter({ jasmineDone: assertions });
env.execute();
});
describe("#spyOn", 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 existence of the method", function() {
var subject = {};
expect(function() {
env.spyOn(subject, 'pants');
}).toThrowError(/method does not exist/);
});
it("checks if it has already been spied upon", function() {
var subject = { spiedFunc: function() {} };
env.spyOn(subject, 'spiedFunc');
expect(function() {
env.spyOn(subject, 'spiedFunc');
}).toThrowError(/has already been spied upon/);
});
it("overrides the method on the object and returns the spy", function() {
var originalFunctionWasCalled = false;
var subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
var spy = env.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
});
});
describe("#pending", function() {
it("throws the Pending Spec exception", function() {
expect(function() {
@@ -82,4 +20,3 @@ describe("Env", function() {
});
});
});

View File

@@ -1,14 +1,14 @@
describe("Expectation", function() {
it(".addMatchers makes matchers available to any expectation", function() {
it("makes custom matchers available to this expectation", function() {
var matchers = {
toFoo: function() {},
toBar: function() {}
},
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({});
expectation = new j$.Expectation({
customMatchers: matchers
});
expect(expectation.toFoo).toBeDefined();
expect(expectation.toBar).toBeDefined();
@@ -27,25 +27,6 @@ describe("Expectation", function() {
expect(expectation.toQuux).toBeDefined();
});
it(".resetMatchers should keep only core matchers", function() {
var matchers = {
toFoo: function() {}
},
coreMatchers = {
toQuux: function() {}
},
expectation;
j$.Expectation.addCoreMatchers(coreMatchers);
j$.Expectation.addMatchers(matchers);
j$.Expectation.resetMatchers();
expectation = new j$.Expectation({});
expect(expectation.toQuux).toBeDefined();
expect(expectation.toFoo).toBeUndefined();
});
it("Factory builds an expectation/negative expectation", function() {
var builtExpectation = j$.Expectation.Factory();
@@ -65,10 +46,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
util: util,
customMatchers: matchers,
customEqualityTesters: customEqualityTesters,
actual: "an actual",
addExpectationResult: addExpectationResult
@@ -94,10 +74,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
util: util,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult
});
@@ -121,10 +100,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
util: util,
actual: "an actual",
addExpectationResult: addExpectationResult
@@ -155,10 +132,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
util: util,
actual: "an actual",
addExpectationResult: addExpectationResult
@@ -191,10 +166,9 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
actual: "an actual",
customMatchers: matchers,
addExpectationResult: addExpectationResult
});
@@ -225,10 +199,8 @@ describe("Expectation", function() {
addExpectationResult = jasmine.createSpy("addExpectationResult"),
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult
});
@@ -259,10 +231,8 @@ describe("Expectation", function() {
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true
@@ -294,10 +264,8 @@ describe("Expectation", function() {
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
util: util,
addExpectationResult: addExpectationResult,
@@ -332,10 +300,8 @@ describe("Expectation", function() {
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true
@@ -365,10 +331,8 @@ describe("Expectation", function() {
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true
@@ -403,10 +367,8 @@ describe("Expectation", function() {
actual = "an actual",
expectation;
j$.Expectation.addMatchers(matchers);
expectation = new j$.Expectation({
matchers: matchers,
customMatchers: matchers,
actual: "an actual",
addExpectationResult: addExpectationResult,
isNot: true

View File

@@ -178,6 +178,43 @@ describe("JsApiReporter", function() {
});
});
describe("#suiteResults", function(){
var reporter, suiteResult1, suiteResult2;
beforeEach(function() {
reporter = new j$.JsApiReporter({});
suiteStarted1 = {
id: 1
};
suiteResult1 = {
id: 1,
status: 'failed',
failedExpectations: [{ message: 'My After All Exception' }]
};
suiteResult2 = {
id: 2,
status: 'finished'
};
reporter.suiteStarted(suiteStarted1);
reporter.suiteDone(suiteResult1);
reporter.suiteDone(suiteResult2);
});
it('should not include suite starts', function(){
expect(reporter.suiteResults(0,3).length).toEqual(2);
});
it("should return a slice of results", function() {
expect(reporter.suiteResults(0, 1)).toEqual([suiteResult1]);
expect(reporter.suiteResults(1, 1)).toEqual([suiteResult2]);
});
it("returns nothing for out of bounds indicies", function() {
expect(reporter.suiteResults(0, 3)).toEqual([suiteResult1, suiteResult2]);
expect(reporter.suiteResults(2, 3)).toEqual([]);
});
});
describe("#executionTime", function() {
it("should start the timer when jasmine starts", function() {
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),

View File

@@ -75,6 +75,7 @@ describe("FakeDate", function() {
mockDate.install();
expect(new fakeGlobal.Date()).toEqual(jasmine.any(Date));
expect(new fakeGlobal.Date() instanceof fakeGlobal.Date).toBe(true);
});
it("fakes current time when using Date.now()", function() {

View File

@@ -26,6 +26,11 @@ describe("j$.pp", function () {
expect(j$.pp(array1)).toEqual("[ 1, 2, [ <circular reference: Array> ] ]");
});
it("should not indicate circular references incorrectly", function() {
var array = [ [1] ];
expect(j$.pp(array)).toEqual("[ [ 1 ] ]");
});
it("should stringify objects properly", function() {
expect(j$.pp({foo: 'bar'})).toEqual("{ foo: 'bar' }");
expect(j$.pp({foo:'bar', baz:3, nullValue: null, undefinedValue: jasmine.undefined})).toEqual("{ foo: 'bar', baz: 3, nullValue: null, undefinedValue: undefined }");
@@ -130,7 +135,9 @@ describe("j$.pp", function () {
},
env = new j$.Env();
env.spyOn(TestObject, 'someFunction');
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {return [];}});
spyRegistry.spyOn(TestObject, 'someFunction');
expect(j$.pp(TestObject.someFunction)).toEqual("spy on someFunction");
expect(j$.pp(j$.createSpy("something"))).toEqual("spy on something");
@@ -153,4 +160,3 @@ describe("j$.pp", function () {
expect(j$.pp(obj)).toEqual("{ foo: 'bar' }");
});
});

View File

@@ -2,15 +2,15 @@ describe("QueueRunner", function() {
it("runs all the functions it's passed", function() {
var calls = [],
fn1 = jasmine.createSpy('fn1'),
fn2 = jasmine.createSpy('fn2'),
queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueRunner = new j$.QueueRunner({
fns: [fn1, fn2]
queueableFns: [queueableFn1, queueableFn2]
});
fn1.and.callFake(function() {
queueableFn1.fn.and.callFake(function() {
calls.push('fn1');
});
fn2.and.callFake(function() {
queueableFn2.fn.and.callFake(function() {
calls.push('fn2');
});
@@ -20,19 +20,19 @@ describe("QueueRunner", function() {
});
it("calls each function with a consistent 'this'-- an empty object", function() {
var fn1 = jasmine.createSpy('fn1'),
fn2 = jasmine.createSpy('fn2'),
fn3 = function(done) { asyncContext = this; done(); },
var queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueableFn3 = { fn: function(done) { asyncContext = this; done(); } },
queueRunner = new j$.QueueRunner({
fns: [fn1, fn2, fn3]
queueableFns: [queueableFn1, queueableFn2, queueableFn3]
}),
asyncContext;
queueRunner.execute();
var context = fn1.calls.first().object;
var context = queueableFn1.fn.calls.first().object;
expect(context).toEqual({});
expect(fn2.calls.first().object).toBe(context);
expect(queueableFn2.fn.calls.first().object).toBe(context);
expect(asyncContext).toBe(context);
});
@@ -53,20 +53,20 @@ describe("QueueRunner", function() {
beforeCallback = jasmine.createSpy('beforeCallback'),
fnCallback = jasmine.createSpy('fnCallback'),
afterCallback = jasmine.createSpy('afterCallback'),
fn1 = function(done) {
queueableFn1 = { fn: function(done) {
beforeCallback();
setTimeout(done, 100);
},
fn2 = function(done) {
} },
queueableFn2 = { fn: function(done) {
fnCallback();
setTimeout(done, 100);
},
fn3 = function(done) {
} },
queueableFn3 = { fn: function(done) {
afterCallback();
setTimeout(done, 100);
},
} },
queueRunner = new j$.QueueRunner({
fns: [fn1, fn2, fn3],
queueableFns: [queueableFn1, queueableFn2, queueableFn3],
onComplete: onComplete
});
@@ -93,55 +93,77 @@ describe("QueueRunner", function() {
expect(onComplete).toHaveBeenCalled();
});
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
var beforeFn = function(done) { },
fn = jasmine.createSpy('fn'),
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
it("explicitly fails an async function with a provided fail function and moves to the next function", function() {
var queueableFn1 = { fn: function(done) {
setTimeout(function() { done.fail('foo'); }, 100);
} },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new j$.QueueRunner({
fns: [beforeFn, fn],
onComplete: onComplete,
onException: onException,
enforceTimeout: function() { return true; }
queueableFns: [queueableFn1, queueableFn2],
fail: failFn
});
queueRunner.execute();
expect(fn).not.toHaveBeenCalled();
jasmine.clock().tick(j$.DEFAULT_TIMEOUT_INTERVAL);
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(failFn).toHaveBeenCalledWith('foo');
expect(queueableFn2.fn).toHaveBeenCalled();
});
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
var timeout = 3,
beforeFn = { fn: function(done) { }, type: 'before', timeout: function() { return timeout; } },
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({
queueableFns: [beforeFn, queueableFn],
onComplete: onComplete,
onException: onException
});
queueRunner.execute();
expect(queueableFn.fn).not.toHaveBeenCalled();
jasmine.clock().tick(timeout);
expect(onException).toHaveBeenCalledWith(jasmine.any(Error));
expect(fn).toHaveBeenCalled();
expect(queueableFn.fn).toHaveBeenCalled();
expect(onComplete).toHaveBeenCalled();
});
it("by default does not set a timeout for asynchronous functions", function() {
var beforeFn = function(done) { },
fn = jasmine.createSpy('fn'),
var beforeFn = { fn: function(done) { } },
queueableFn = { fn: jasmine.createSpy('fn') },
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({
fns: [beforeFn, fn],
queueableFns: [beforeFn, queueableFn],
onComplete: onComplete,
onException: onException,
});
queueRunner.execute();
expect(fn).not.toHaveBeenCalled();
expect(queueableFn.fn).not.toHaveBeenCalled();
jasmine.clock().tick(j$.DEFAULT_TIMEOUT_INTERVAL);
expect(onException).not.toHaveBeenCalled();
expect(fn).not.toHaveBeenCalled();
expect(queueableFn.fn).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
});
it("clears the timeout when an async function throws an exception, to prevent additional onException calls", function() {
var fn = function(done) { throw new Error("error!"); },
it("clears the timeout when an async function throws an exception, to prevent additional exception reporting", function() {
var queueableFn = { fn: function(done) { throw new Error("error!"); } },
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({
fns: [fn],
queueableFns: [queueableFn],
onComplete: onComplete,
onException: onException
});
@@ -156,11 +178,11 @@ describe("QueueRunner", function() {
});
it("clears the timeout when the done callback is called", function() {
var fn = function(done) { done(); },
var queueableFn = { fn: function(done) { done(); } },
onComplete = jasmine.createSpy('onComplete'),
onException = jasmine.createSpy('onException'),
queueRunner = new j$.QueueRunner({
fns: [fn],
queueableFns: [queueableFn],
onComplete: onComplete,
onException: onException
});
@@ -174,75 +196,78 @@ describe("QueueRunner", function() {
});
it("only moves to the next spec the first time you call done", function() {
var fn = function(done) {done(); done();},
nextFn = jasmine.createSpy('nextFn');
var queueableFn = { fn: function(done) {done(); done();} },
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new j$.QueueRunner({
fns: [fn, nextFn]
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
expect(nextFn.calls.count()).toEqual(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
});
it("does not move to the next spec if done is called after an exception has ended the spec", function() {
var fn = function(done) {
var queueableFn = { fn: function(done) {
setTimeout(done, 1);
throw new Error('error!');
},
nextFn = jasmine.createSpy('nextFn');
} },
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new j$.QueueRunner({
fns: [fn, nextFn]
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
jasmine.clock().tick(1);
expect(nextFn.calls.count()).toEqual(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
});
});
it("calls an exception handler when an exception is thrown in a fn", function() {
var fn = function() {
it("calls exception handlers when an exception is thrown in a fn", function() {
var queueableFn = { type: 'queueable',
fn: function() {
throw new Error('fake error');
},
exceptionCallback = jasmine.createSpy('exception callback'),
} },
onExceptionCallback = jasmine.createSpy('on exception callback'),
queueRunner = new j$.QueueRunner({
fns: [fn],
onException: exceptionCallback
queueableFns: [queueableFn],
onException: onExceptionCallback
});
queueRunner.execute();
expect(exceptionCallback).toHaveBeenCalledWith(jasmine.any(Error));
expect(onExceptionCallback).toHaveBeenCalledWith(jasmine.any(Error));
});
it("rethrows an exception if told to", function() {
var fn = function() {
var queueableFn = { fn: function() {
throw new Error('fake error');
},
} },
queueRunner = new j$.QueueRunner({
fns: [fn],
queueableFns: [queueableFn],
catchException: function(e) { return false; }
});
expect(queueRunner.execute).toThrow();
expect(function() {
queueRunner.execute();
}).toThrowError('fake error');
});
it("continues running the functions even after an exception is thrown in an async spec", function() {
var fn = function(done) { throw new Error("error"); },
nextFn = jasmine.createSpy("nextFunction"),
var queueableFn = { fn: function(done) { throw new Error("error"); } },
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
queueRunner = new j$.QueueRunner({
fns: [fn, nextFn]
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
expect(nextFn).toHaveBeenCalled();
expect(nextQueueableFn.fn).toHaveBeenCalled();
});
it("calls a provided complete callback when done", function() {
var fn = jasmine.createSpy('fn'),
var queueableFn = { fn: jasmine.createSpy('fn') },
completeCallback = jasmine.createSpy('completeCallback'),
queueRunner = new j$.QueueRunner({
fns: [fn],
queueableFns: [queueableFn],
onComplete: completeCallback
});
@@ -252,12 +277,12 @@ describe("QueueRunner", function() {
});
it("calls a provided stack clearing function when done", function() {
var asyncFn = function(done) { done() },
afterFn = jasmine.createSpy('afterFn'),
var asyncFn = { fn: function(done) { done() } },
afterFn = { fn: jasmine.createSpy('afterFn') },
completeCallback = jasmine.createSpy('completeCallback'),
clearStack = jasmine.createSpy('clearStack'),
queueRunner = new j$.QueueRunner({
fns: [asyncFn, afterFn],
queueableFns: [asyncFn, afterFn],
clearStack: clearStack,
onComplete: completeCallback
});
@@ -265,7 +290,7 @@ describe("QueueRunner", function() {
clearStack.and.callFake(function(fn) { fn(); });
queueRunner.execute();
expect(afterFn).toHaveBeenCalled();
expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalledWith(completeCallback);
});
});

View File

@@ -14,7 +14,7 @@ describe("Spec", function() {
expect(j$.Spec.isPendingSpecException(fakeError)).toBe(true);
});
it("#isPendingSpecException returns true for a pending spec exception", function() {
it("#isPendingSpecException returns false for not a pending spec exception", function() {
var e = new Error("foo");
expect(j$.Spec.isPendingSpecException(e)).toBe(false);
@@ -29,7 +29,7 @@ describe("Spec", function() {
spec = new j$.Spec({
description: 'my test',
id: 'some-id',
fn: function() {},
queueableFn: { fn: function() {} },
queueRunnerFactory: fakeQueueRunner
});
@@ -44,7 +44,7 @@ describe("Spec", function() {
spec = new j$.Spec({
id: 123,
description: 'foo bar',
fn: function() {},
queueableFn: { fn: function() {} },
onStart: startCallback,
queueRunnerFactory: fakeQueueRunner
});
@@ -66,7 +66,7 @@ describe("Spec", function() {
expect(beforesWereCalled).toBe(false);
}),
spec = new j$.Spec({
fn: function() {},
queueableFn: { fn: function() {} },
beforeFns: function() {
return [function() {
beforesWereCalled = true
@@ -85,25 +85,22 @@ describe("Spec", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
before = jasmine.createSpy('before'),
after = jasmine.createSpy('after'),
fn = jasmine.createSpy('test body').and.callFake(function() {
queueableFn = { fn: jasmine.createSpy('test body').and.callFake(function() {
expect(before).toHaveBeenCalled();
expect(after).not.toHaveBeenCalled();
}),
}) },
spec = new j$.Spec({
fn: fn,
beforeFns: function() {
return [before]
},
afterFns: function() {
return [after]
queueableFn: queueableFn,
beforeAndAfterFns: function() {
return {befores: [before], afters: [after]}
},
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].fns;
expect(allSpecFns).toEqual([before, fn, after]);
var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
expect(allSpecFns).toEqual([before, queueableFn, after]);
});
it("is marked pending if created without a function body", function() {
@@ -113,7 +110,7 @@ describe("Spec", function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({
onStart: startCallback,
fn: null,
queueableFn: { fn: null },
resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner
});
@@ -129,7 +126,7 @@ describe("Spec", function() {
resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({
onStart:startCallback,
fn: specBody,
queueableFn: { fn: specBody },
resultCallback: resultCallback,
queueRunnerFactory: fakeQueueRunner
});
@@ -158,7 +155,8 @@ describe("Spec", function() {
getSpecName: function() {
return "a suite with a spec"
},
queueRunnerFactory: fakeQueueRunner
queueRunnerFactory: fakeQueueRunner,
queueableFn: { fn: null }
});
spec.pend();
@@ -183,7 +181,7 @@ describe("Spec", function() {
it("should call the done callback on execution complete", function() {
var done = jasmine.createSpy('done callback'),
spec = new j$.Spec({
fn: function() {},
queueableFn: { fn: function() {} },
catchExceptions: function() { return false; },
resultCallback: function() {},
queueRunnerFactory: function(attrs) { attrs.onComplete(); }
@@ -194,19 +192,19 @@ describe("Spec", function() {
expect(done).toHaveBeenCalled();
});
it("#status returns passing by default", function(){
var spec = new j$.Spec({ fn: function () {} });
expect(spec.status()).toBe("passed");
it("#status returns passing by default", function() {
var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body")} });
expect(spec.status()).toBe('passed');
});
it("#status returns passed if all expectations in the spec have passed", function() {
var spec = new j$.Spec({fn: jasmine.createSpy("spec body")});
var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body")} });
spec.addExpectationResult(true);
expect(spec.status()).toBe('passed');
});
it("#status returns failed if any expectations in the spec have failed", function() {
var spec = new j$.Spec({ fn: jasmine.createSpy("spec body") });
var spec = new j$.Spec({queueableFn: { fn: jasmine.createSpy("spec body") } });
spec.addExpectationResult(true);
spec.addExpectationResult(false);
expect(spec.status()).toBe('failed');
@@ -215,7 +213,7 @@ describe("Spec", function() {
it("keeps track of passed and failed expectations", function() {
var resultCallback = jasmine.createSpy('resultCallback'),
spec = new j$.Spec({
fn: jasmine.createSpy("spec body"),
queueableFn: { fn: jasmine.createSpy("spec body") },
expectationResultFactory: function (data) { return data; },
queueRunnerFactory: function(attrs) { attrs.onComplete(); },
resultCallback: resultCallback
@@ -233,7 +231,8 @@ describe("Spec", function() {
var specNameSpy = jasmine.createSpy('specNameSpy').and.returnValue('expected val');
var spec = new j$.Spec({
getSpecName: specNameSpy
getSpecName: specNameSpy,
queueableFn: { fn: null }
});
expect(spec.getFullName()).toBe('expected val');
@@ -248,7 +247,7 @@ describe("Spec", function() {
spec = new j$.Spec({
description: 'my test',
id: 'some-id',
fn: function() { },
queueableFn: { fn: function() { } },
queueRunnerFactory: fakeQueueRunner
});

View File

@@ -0,0 +1,55 @@
describe("SpyRegistry", function() {
describe("#spyOn", function() {
it("checks for the existence of the object", function() {
var spyRegistry = new j$.SpyRegistry();
expect(function() {
spyRegistry.spyOn(void 0, 'pants');
}).toThrowError(/could not find an object/);
});
it("checks for the existence of the method", function() {
var spyRegistry = new j$.SpyRegistry(),
subject = {};
expect(function() {
spyRegistry.spyOn(subject, 'pants');
}).toThrowError(/method does not exist/);
});
it("checks if it has already been spied upon", function() {
var spies = [],
spyRegistry = new j$.SpyRegistry({currentSpies: function() { return spies; }}),
subject = { spiedFunc: function() {} };
spyRegistry.spyOn(subject, 'spiedFunc');
expect(function() {
spyRegistry.spyOn(subject, 'spiedFunc');
}).toThrowError(/has already been spied upon/);
});
it("overrides the method on the object and returns the spy", function() {
var originalFunctionWasCalled = false,
spyRegistry = new j$.SpyRegistry(),
subject = { spiedFunc: function() { originalFunctionWasCalled = true; } };
var spy = spyRegistry.spyOn(subject, 'spiedFunc');
expect(subject.spiedFunc).toEqual(spy);
});
});
describe("#clearSpies", function() {
it("restores the original functions on the spied-upon objects", function() {
var spies = [],
spyRegistry = new j$.SpyRegistry({currentSpies: function() { return spies; }}),
originalFunction = function() {},
subject = { spiedFunc: originalFunction };
spyRegistry.spyOn(subject, 'spiedFunc');
spyRegistry.clearSpies();
expect(subject.spiedFunc).toBe(originalFunction);
});
});
});

View File

@@ -47,6 +47,16 @@ describe('Spies', function () {
expect(trackSpy.calls.mostRecent().args[0].object).toEqual(contextObject);
});
it("tracks the return value of calls", function () {
var spy = j$.createSpy(TestClass.prototype, TestClass.prototype.someFunction);
var trackSpy = spyOn(spy.calls, "track");
spy.and.returnValue("return value");
spy();
expect(trackSpy.calls.mostRecent().args[0].returnValue).toEqual("return value");
});
});
describe("createSpyObj", function() {

View File

@@ -46,6 +46,19 @@ describe("SpyStrategy", function() {
expect(returnValue).toEqual(17);
});
it("can return specified values in order specified when executed", function() {
var originalFn = jasmine.createSpy("original"),
spyStrategy = new j$.SpyStrategy({fn: originalFn});
spyStrategy.returnValues('value1', 'value2', 'value3');
expect(spyStrategy.exec()).toEqual('value1');
expect(spyStrategy.exec()).toEqual('value2');
expect(spyStrategy.exec()).toBe('value3');
expect(spyStrategy.exec()).toBeUndefined();
expect(originalFn).not.toHaveBeenCalled();
});
it("allows an exception to be thrown when executed", function() {
var originalFn = jasmine.createSpy("original"),
spyStrategy = new j$.SpyStrategy({fn: originalFn});

View File

@@ -52,6 +52,31 @@ describe("Suite", function() {
expect(suite.beforeFns).toEqual([innerBefore, outerBefore]);
});
it("runs beforeAll functions in order of needed execution", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunner
}),
firstBefore = jasmine.createSpy('outerBeforeAll'),
lastBefore = jasmine.createSpy('insideBeforeAll'),
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
suite.beforeAll(firstBefore);
suite.beforeAll(lastBefore);
suite.addChild(fakeIt);
suite.execute();
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
suiteFns[0]();
expect(firstBefore).toHaveBeenCalled();
suiteFns[1]();
expect(lastBefore).toHaveBeenCalled();
});
it("adds after functions in order of needed execution", function() {
var env = new j$.Env(),
suite = new j$.Suite({
@@ -67,6 +92,31 @@ describe("Suite", function() {
expect(suite.afterFns).toEqual([innerAfter, outerAfter]);
});
it("runs afterAll functions in order of needed execution", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
suite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunner
}),
firstAfter = jasmine.createSpy('outerAfterAll'),
lastAfter = jasmine.createSpy('insideAfterAll'),
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
suite.afterAll(firstAfter);
suite.afterAll(lastAfter);
suite.addChild(fakeIt);
suite.execute();
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
suiteFns[1]();
expect(firstAfter).toHaveBeenCalled();
suiteFns[2]();
expect(lastAfter).toHaveBeenCalled();
});
it("can be disabled, but still calls callbacks", function() {
var env = new j$.Env(),
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
@@ -93,7 +143,7 @@ describe("Suite", function() {
expect(onComplete).toHaveBeenCalled();
});
it("delegates execution of its specs and suites", function() {
it("delegates execution of its specs, suites, beforeAlls, and afterAlls", function() {
var env = new j$.Env(),
parentSuiteDone = jasmine.createSpy('parent suite done'),
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
@@ -109,22 +159,57 @@ describe("Suite", function() {
queueRunner: fakeQueueRunner
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
};
execute: jasmine.createSpy('fakeSpec1'),
isExecutable: function() { return true; }
},
beforeAllFn = { fn: jasmine.createSpy('beforeAll') },
afterAllFn = { fn: jasmine.createSpy('afterAll') };
spyOn(suite, "execute");
parentSuite.addChild(fakeSpec1);
parentSuite.addChild(suite);
parentSuite.beforeAll(beforeAllFn);
parentSuite.afterAll(afterAllFn);
parentSuite.execute(parentSuiteDone);
var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].fns;
var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].queueableFns;
parentSuiteFns[0]();
parentSuiteFns[0].fn();
expect(beforeAllFn.fn).toHaveBeenCalled();
parentSuiteFns[1].fn();
expect(fakeSpec1.execute).toHaveBeenCalled();
parentSuiteFns[1]();
parentSuiteFns[2].fn();
expect(suite.execute).toHaveBeenCalled();
parentSuiteFns[3].fn();
expect(afterAllFn.fn).toHaveBeenCalled();
});
it("does not run beforeAll or afterAll if there are no child specs to run", function() {
var env = new j$.Env(),
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
fakeQueueRunnerForChild = jasmine.createSpy('fake child queue runner'),
parentSuite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunnerForParent
}),
childSuite = new j$.Suite({
env: env,
description: "I am a suite",
queueRunner: fakeQueueRunnerForChild,
parentSuite: parentSuite
}),
beforeAllFn = jasmine.createSpy('beforeAll'),
afterAllFn = jasmine.createSpy('afterAll');
parentSuite.addChild(childSuite);
parentSuite.beforeAll(beforeAllFn);
parentSuite.afterAll(afterAllFn);
parentSuite.execute();
expect(fakeQueueRunnerForParent).toHaveBeenCalledWith(jasmine.objectContaining({queueableFns: []}));
});
it("calls a provided onStart callback when starting", function() {
@@ -138,7 +223,8 @@ describe("Suite", function() {
queueRunner: fakeQueueRunner
}),
fakeSpec1 = {
execute: jasmine.createSpy('fakeSpec1')
execute: jasmine.createSpy('fakeSpec1'),
isExecutable: function() { return true; }
};
suite.execute();
@@ -182,9 +268,10 @@ describe("Suite", function() {
expect(suiteResultsCallback).toHaveBeenCalledWith({
id: suite.id,
status: '',
status: 'finished',
description: "with a child suite",
fullName: "with a child suite"
fullName: "with a child suite",
failedExpectations: []
});
});
@@ -210,7 +297,18 @@ describe("Suite", function() {
id: suite.id,
status: 'disabled',
description: "with a child suite",
fullName: "with a child suite"
fullName: "with a child suite",
failedExpectations: []
});
});
it('has a status of failed if any afterAll expectations have failed', function() {
var suite = new j$.Suite({
expectationResultFactory: function() { return 'hi'; }
});
suite.addChild({ result: { status: 'done' } });
suite.addExpectationResult(false);
expect(suite.status()).toBe('failed');
});
});

View File

@@ -38,13 +38,13 @@ describe("Custom Matchers (Integration)", function() {
});
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.addMatchers({
toBeReal: function() {
return { compare: function() { return { pass: true }; } };
}
});
env.expect(true).toBeReal();
});
@@ -57,16 +57,16 @@ describe("Custom Matchers (Integration)", function() {
});
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.addMatchers({
toBeReal: function() {
return {
compare: function() { return { pass: true }; },
negativeCompare: function() { return { pass: true }; }
};
}
});
env.expect(true).not.toBeReal();
});
@@ -79,17 +79,17 @@ describe("Custom Matchers (Integration)", function() {
});
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.addMatchers({
toBeReal: function() {
return {
compare: function() {
return { pass: false };
}
}
}
}
});
});
env.it('spec with an expectation', function() {
env.expect("a").toBeReal();
});
@@ -103,13 +103,14 @@ describe("Custom Matchers (Integration)", function() {
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.addMatchers({
toBeReal: function() {
return { compare: argumentSpy };
}
});
env.expect(true).toBeReal();
env.expect(true).toBeReal("arg");
env.expect(true).toBeReal("arg1", "arg2");
@@ -130,12 +131,13 @@ describe("Custom Matchers (Integration)", function() {
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.addCustomEqualityTester(customEqualityFn);
env.addMatchers({
toBeReal: argumentSpy
});
env.expect(true).toBeReal();
});

File diff suppressed because it is too large Load Diff

View File

@@ -159,7 +159,7 @@ describe("jasmine spec running", function () {
];
expect(actions).toEqual(expected);
done();
}
};
env.addReporter({jasmineDone: assertions});
@@ -228,6 +228,257 @@ describe("jasmine spec running", function () {
env.execute();
});
it('should run beforeAlls before beforeEachs and afterAlls after afterEachs', function() {
var actions = [];
env.beforeAll(function() {
actions.push('runner beforeAll');
});
env.afterAll(function() {
actions.push('runner afterAll');
});
env.beforeEach(function () {
actions.push('runner beforeEach');
});
env.afterEach(function () {
actions.push('runner afterEach');
});
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('inner beforeEach');
});
env.afterEach(function() {
actions.push('inner afterEach');
});
env.beforeAll(function() {
actions.push('inner beforeAll');
});
env.afterAll(function() {
actions.push('inner afterAll');
});
env.it('does something or other', function() {
actions.push('it');
});
});
var assertions = function() {
var expected = [
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll"
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('should run beforeAlls and afterAlls as beforeEachs and afterEachs in the order declared when runnablesToRun is provided', function() {
var actions = [],
spec,
spec2;
env.beforeAll(function() {
actions.push('runner beforeAll');
});
env.afterAll(function() {
actions.push('runner afterAll');
});
env.beforeEach(function () {
actions.push('runner beforeEach');
});
env.afterEach(function () {
actions.push('runner afterEach');
});
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('inner beforeEach');
});
env.afterEach(function() {
actions.push('inner afterEach');
});
env.beforeAll(function() {
actions.push('inner beforeAll');
});
env.afterAll(function() {
actions.push('inner afterAll');
});
spec = env.it('does something', function() {
actions.push('it');
});
spec2 = env.it('does something or other', function() {
actions.push('it2');
});
});
var assertions = function() {
var expected = [
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll",
"runner beforeAll",
"inner beforeAll",
"runner beforeEach",
"inner beforeEach",
"it2",
"inner afterEach",
"runner afterEach",
"inner afterAll",
"runner afterAll"
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute([spec.id, spec2.id]);
});
describe('focused runnables', function() {
it('runs the relevant alls and eachs for each runnable', function(done) {
var actions = [];
env.beforeAll(function() {actions.push('beforeAll')});
env.afterAll(function() {actions.push('afterAll')});
env.beforeEach(function() {actions.push('beforeEach')});
env.afterEach(function() {actions.push('afterEach')});
env.fdescribe('a focused suite', function() {
env.it('is run', function() {
actions.push('spec in fdescribe')
});
});
env.describe('an unfocused suite', function() {
env.fit('has a focused spec', function() {
actions.push('focused spec')
});
});
var assertions = function() {
var expected = [
'beforeAll',
'beforeEach',
'spec in fdescribe',
'afterEach',
'afterAll',
'beforeAll',
'beforeEach',
'focused spec',
'afterEach',
'afterAll'
];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused specs in focused suites cause non-focused siblings to not run', function(done){
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.fit('focused spec', function() {
actions.push('focused spec')
});
});
var assertions = function() {
var expected = ['focused spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused suites in focused suites cause non-focused siblings to not run', function(done){
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.fdescribe('inner focused suite', function() {
env.it('inner spec', function() {
actions.push('inner spec');
});
});
});
var assertions = function() {
var expected = ['inner spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it('focused runnables unfocus ancestor focused suites', function() {
var actions = [];
env.fdescribe('focused suite', function() {
env.it('unfocused spec', function() {
actions.push('unfocused spec')
});
env.describe('inner focused suite', function() {
env.fit('focused spec', function() {
actions.push('focused spec');
});
});
});
var assertions = function() {
var expected = ['focused spec'];
expect(actions).toEqual(expected);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
});
it("shouldn't run disabled suites", function(done) {
var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"),
suite = env.describe('A Suite', function() {
@@ -236,10 +487,36 @@ describe("jasmine spec running", function () {
});
});
suite.execute(function() {
var assertions = function() {
expect(specInADisabledSuite).not.toHaveBeenCalled();
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it("should allow top level suites to be disabled", function() {
var specInADisabledSuite = jasmine.createSpy("specInADisabledSuite"),
otherSpec = jasmine.createSpy("otherSpec");
env.xdescribe('A disabled suite', function() {
env.it('spec inside a disabled suite', specInADisabledSuite);
});
env.describe('Another suite', function() {
env.it('another spec', otherSpec);
});
var assertions = function() {
expect(specInADisabledSuite).not.toHaveBeenCalled();
expect(otherSpec).toHaveBeenCalled();
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it("should set all pending specs to pending when a suite is run", function(done) {
@@ -254,7 +531,6 @@ describe("jasmine spec running", function () {
});
});
// TODO: is this useful? It doesn't catch syntax errors
xit("should recover gracefully when there are errors in describe functions", function() {
var specs = [];

View File

@@ -174,7 +174,7 @@ describe("matchersUtil", function() {
describe("contains", function() {
it("passes when expected is a substring of actual", function() {
expect(j$.matchersUtil.contains("ABC", "B")).toBe(true);
expect(j$.matchersUtil.contains("ABC", "BC")).toBe(true);
});
it("fails when expected is a not substring of actual", function() {
@@ -207,6 +207,15 @@ describe("matchersUtil", function() {
it("fails when actual is null", function() {
expect(j$.matchersUtil.contains(null, 'A')).toBe(false);
});
it("passes with array-like objects", function() {
var capturedArgs = null;
function testFunction(){
capturedArgs = arguments;
}
testFunction('foo', 'bar');
expect(j$.matchersUtil.contains(capturedArgs, 'bar')).toBe(true);
});
});
describe("buildMessage", function() {

View File

@@ -155,7 +155,7 @@ describe("toThrowError", function() {
result = matcher.compare(fn, Error);
expect(result.pass).toBe(true);
expect(result.message).toEqual("Expected function not to throw Error.");
expect(result.message()).toEqual("Expected function not to throw Error.");
});
it("passes if thrown is a custom error that takes arguments and the expected is the same error", function() {
@@ -175,7 +175,7 @@ describe("toThrowError", function() {
result = matcher.compare(fn, CustomError);
expect(result.pass).toBe(true);
expect(result.message).toEqual("Expected function not to throw CustomError.");
expect(result.message()).toEqual("Expected function not to throw CustomError.");
});
it("fails if thrown is an Error and the expected is a different Error", function() {
@@ -191,7 +191,7 @@ describe("toThrowError", function() {
result = matcher.compare(fn, TypeError);
expect(result.pass).toBe(false);
expect(result.message).toEqual("Expected function to throw TypeError, but it threw Error.");
expect(result.message()).toEqual("Expected function to throw TypeError, but it threw Error.");
});
it("passes if thrown is a type of Error and it is equal to the expected Error and message", function() {
@@ -259,7 +259,7 @@ describe("toThrowError", function() {
result = matcher.compare(fn, TypeError, /foo/);
expect(result.pass).toBe(true);
expect(result.message()).toEqual("Expected function not to throw TypeError with message matching /foo/.");
expect(result.message()).toEqual("Expected function not to throw TypeError with a message matching /foo/.");
});
it("fails if thrown is a type of Error and the expected is a different Error", function() {
@@ -275,6 +275,6 @@ describe("toThrowError", function() {
result = matcher.compare(fn, TypeError, /bar/);
expect(result.pass).toBe(false);
expect(result.message()).toEqual("Expected function to throw TypeError with message matching /bar/, but it threw TypeError with message 'foo'.");
expect(result.message()).toEqual("Expected function to throw TypeError with a message matching /bar/, but it threw TypeError with message 'foo'.");
});
});

View File

@@ -65,8 +65,8 @@ describe("New HtmlReporter", function() {
describe("when a spec is done", function() {
it("logs errors to the console and prints a special symbol if it is an empty spec", function() {
if (!window.console) {
window.console = { error: function(){} };
if (typeof console === "undefined") {
console = { error: function(){} };
}
var env = new j$.Env(),
@@ -179,6 +179,34 @@ describe("New HtmlReporter", function() {
});
});
describe("when there are suite failures", function () {
it("displays the exceptions in their own alert bars", function(){
var env = new j$.Env(),
container = document.createElement("div"),
getContainer = function() { return container; },
reporter = new j$.HtmlReporter({
env: env,
getContainer: getContainer,
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({});
reporter.suiteDone({ status: 'failed', failedExpectations: [{ message: 'My After All Exception' }] });
reporter.suiteDone({ status: 'failed', failedExpectations: [{ message: 'My Other Exception' }] });
reporter.jasmineDone({});
var alertBars = container.querySelectorAll(".alert .bar");
expect(alertBars.length).toEqual(3);
expect(alertBars[1].innerHTML).toMatch(/My After All Exception/);
expect(alertBars[1].getAttribute("class")).toEqual('bar errored');
expect(alertBars[2].innerHTML).toMatch(/My Other Exception/);
});
});
describe("when Jasmine is done", function() {
it("adds EMPTY to the link title of specs that have no expectations", function() {
if (!window.console) {

195
spec/node_suite.js Normal file
View File

@@ -0,0 +1,195 @@
var fs = require('fs');
var util = require('util');
var path = require('path');
// boot code for jasmine
var jasmineRequire = require('../lib/jasmine-core/jasmine.js');
var jasmine = jasmineRequire.core(jasmineRequire);
var consoleFns = require('../lib/console/console.js');
extend(jasmineRequire, consoleFns);
jasmineRequire.console(jasmineRequire, jasmine);
var env = jasmine.getEnv();
var jasmineInterface = {
describe: function(description, specDefinitions) {
return env.describe(description, specDefinitions);
},
xdescribe: function(description, specDefinitions) {
return env.xdescribe(description, specDefinitions);
},
it: function(desc, func) {
return env.it(desc, func);
},
xit: function(desc, func) {
return env.xit(desc, func);
},
beforeEach: function(beforeEachFunction) {
return env.beforeEach(beforeEachFunction);
},
afterEach: function(afterEachFunction) {
return env.afterEach(afterEachFunction);
},
expect: function(actual) {
return env.expect(actual);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},
jsApiReporter: new jasmine.JsApiReporter({
timer: new jasmine.Timer()
}),
beforeAll: function(beforeAllFunction) {
return env.beforeAll(beforeAllFunction);
},
afterAll: function(afterAllFunction) {
return env.afterAll(afterAllFunction);
}
};
extend(global, jasmineInterface);
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
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;
for (var i = 0; i < specs.length; i++) {
var filename = specs[i];
require(filename.replace(/\.\w+$/, ""));
}
var env = jasmine.getEnv();
var consoleReporter = new jasmine.ConsoleReporter({
print: util.print,
onComplete: done,
showColors: showColors,
timer: new jasmine.Timer()
});
env.addReporter(consoleReporter);
env.execute();
}
function getFiles(dir, matcher) {
var allFiles = [];
if (fs.statSync(dir).isFile() && dir.match(matcher)) {
allFiles.push(dir);
} else {
var files = fs.readdirSync(dir);
for (var i = 0, len = files.length; i < len; ++i) {
var filename = dir + '/' + files[i];
if (fs.statSync(filename).isFile() && filename.match(matcher)) {
allFiles.push(filename);
} else if (fs.statSync(filename).isDirectory()) {
var subfiles = getFiles(filename);
subfiles.forEach(function(result) {
allFiles.push(result);
});
}
}
}
return allFiles;
}
function getSpecFiles(dir) {
return getFiles(dir, new RegExp("Spec.js$"));
}
var j$require = (function() {
var exported = {},
j$req;
global.getJasmineRequireObj = getJasmineRequireObj;
j$req = require(__dirname + "/../src/core/requireCore.js");
extend(j$req, require(__dirname + "/../src/console/requireConsole.js"));
var srcFiles = getFiles(__dirname + "/../src/core");
srcFiles.push(__dirname + "/../src/version.js");
srcFiles.push(__dirname + "/../src/console/ConsoleReporter.js");
for (var i = 0; i < srcFiles.length; i++) {
require(srcFiles[i]);
}
extend(j$req, exported);
delete global.getJasmineRequireObj;
return j$req;
function getJasmineRequireObj() {
return exported;
}
}());
j$ = j$require.core(j$require);
j$require.console(j$require, j$);
// options from command line
var isVerbose = false;
var showColors = true;
var perfSuite = false;
process.argv.forEach(function(arg) {
switch (arg) {
case '--color':
showColors = true;
break;
case '--noColor':
showColors = false;
break;
case '--verbose':
isVerbose = true;
break;
case '--perf':
perfSuite = true;
break;
}
});
specs = [];
if (perfSuite) {
specs = getFiles(__dirname + '/performance', new RegExp("test.js$"));
} else {
var consoleSpecs = getSpecFiles(__dirname + "/console"),
coreSpecs = getSpecFiles(__dirname + "/core"),
specs = consoleSpecs.concat(coreSpecs);
}
executeSpecs(specs, function(passed) {
if (passed) {
process.exit(0);
} else {
process.exit(1);
}
}, isVerbose, showColors);

View File

@@ -0,0 +1,104 @@
describe('npm package', function() {
var path = require('path'),
fs = require('fs');
beforeAll(function() {
var shell = require('shelljs'),
pack = shell.exec('npm pack', { silent: true });
this.tarball = pack.output.split('\n')[0];
this.tmpDir = '/tmp/jasmine-core';
fs.mkdirSync(this.tmpDir);
var untar = shell.exec('tar -xzf ' + this.tarball + ' -C ' + this.tmpDir, { silent: true });
expect(untar.code).toBe(0);
this.packagedCore = require(path.join(this.tmpDir, 'package/lib/jasmine-core.js'));
});
beforeEach(function() {
jasmine.addMatchers({
toExistInPath: function(util, customEquality) {
return {
compare: function(actual, expected) {
var fullPath = path.resolve(expected, actual);
return {
pass: fs.existsSync(fullPath)
};
}
};
}
});
});
afterAll(function() {
var cleanup = function (parent, fileOrFolder) {
var fullPath = path.join(parent, fileOrFolder);
if (fs.statSync(fullPath).isFile()) {
fs.unlinkSync(fullPath);
} else {
fs.readdirSync(fullPath).forEach(cleanup.bind(null, fullPath));
fs.rmdirSync(fullPath);
}
};
fs.unlink(this.tarball);
fs.readdirSync(this.tmpDir).forEach(cleanup.bind(null, this.tmpDir));
fs.rmdirSync(this.tmpDir);
});
it('has a root path', function() {
expect(this.packagedCore.files.path).toEqual(fs.realpathSync(path.resolve(this.tmpDir, 'package/lib/jasmine-core')));
});
it('has a bootDir', function() {
expect(this.packagedCore.files.bootDir).toEqual(fs.realpathSync(path.resolve(this.tmpDir, 'package/lib/jasmine-core')));
});
it('has jsFiles', function() {
expect(this.packagedCore.files.jsFiles).toEqual([
'jasmine.js',
'jasmine-html.js',
'json2.js'
]);
var packagedCore = this.packagedCore;
this.packagedCore.files.jsFiles.forEach(function(fileName) {
expect(fileName).toExistInPath(packagedCore.files.path);
});
});
it('has cssFiles', function() {
expect(this.packagedCore.files.cssFiles).toEqual(['jasmine.css']);
var packagedCore = this.packagedCore;
this.packagedCore.files.cssFiles.forEach(function(fileName) {
expect(fileName).toExistInPath(packagedCore.files.path);
});
});
it('has bootFiles', function() {
expect(this.packagedCore.files.bootFiles).toEqual(['boot.js']);
expect(this.packagedCore.files.nodeBootFiles).toEqual(['node_boot.js']);
var packagedCore = this.packagedCore;
this.packagedCore.files.bootFiles.forEach(function(fileName) {
expect(fileName).toExistInPath(packagedCore.files.bootDir);
});
var packagedCore = this.packagedCore;
this.packagedCore.files.nodeBootFiles.forEach(function(fileName) {
expect(fileName).toExistInPath(packagedCore.files.bootDir);
});
});
it('has an imagesDir', function() {
expect(this.packagedCore.files.imagesDir).toEqual(fs.realpathSync(path.resolve(this.tmpDir, 'package/images')));
var images = fs.readdirSync(path.resolve(this.tmpDir, 'package/images'));
expect(images).toContain('jasmine-horizontal.png');
expect(images).toContain('jasmine-horizontal.svg');
expect(images).toContain('jasmine_favicon.png');
});
});

View File

@@ -2,7 +2,8 @@
"spec_dir": "spec",
"spec_files": [
"core/**/*.js",
"console/**/*.js"
"console/**/*.js",
"npmPackage/**/*.js"
],
"helpers": [
"helpers/nodeDefineJasmineUnderTest.js"

View File

@@ -20,6 +20,7 @@ helpers:
- 'helpers/defineJasmineUnderTest.js'
spec_files:
- '**/*[Ss]pec.js'
- '!npmPackage/**/*'
spec_dir: spec

View File

@@ -19,7 +19,10 @@ getJasmineRequireObj().ConsoleReporter = function() {
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
};
},
failedSuites = [];
print('ConsoleReporter is deprecated and will be removed in a future version.');
this.jasmineStarted = function() {
specCount = 0;
@@ -54,9 +57,12 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline();
var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0);
};
@@ -81,6 +87,13 @@ getJasmineRequireObj().ConsoleReporter = function() {
}
};
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this;
function printNewline() {
@@ -125,6 +138,17 @@ getJasmineRequireObj().ConsoleReporter = function() {
printNewline();
}
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
}
return ConsoleReporter;

View File

@@ -127,11 +127,12 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
for (var i = 0; i < funcsToRun.length; ++i) {
var funcToRun = funcsToRun[i];
funcToRun.funcToCall.apply(null, funcToRun.params || []);
if (funcToRun.recurring) {
reschedule(funcToRun);
}
funcToRun.funcToCall.apply(null, funcToRun.params || []);
}
} while (scheduledLookup.length > 0 &&
// checking first if we're out of time prevents setTimeout(0)

View File

@@ -14,11 +14,19 @@ getJasmineRequireObj().Env = function(j$) {
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
var runnableLookupTable = {};
var spies = [];
var runnableResources = {};
var currentSpec = null;
var currentSuite = null;
var currentlyExecutingSuites = [];
var currentDeclarationSuite = null;
var currentSuite = function() {
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
};
var currentRunnable = function() {
return currentSpec || currentSuite();
};
var reporter = new j$.ReportDispatcher([
'jasmineStarted',
@@ -33,11 +41,21 @@ getJasmineRequireObj().Env = function(j$) {
return true;
};
var equalityTesters = [];
var customEqualityTesters = [];
this.addCustomEqualityTester = function(tester) {
customEqualityTesters.push(tester);
if(!currentRunnable()) {
throw new Error('Custom Equalities must be added in a before function or a spec');
}
runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
};
this.addMatchers = function(matchersToAdd) {
if(!currentRunnable()) {
throw new Error('Matchers must be added in a before function or a spec');
}
var customMatchers = runnableResources[currentRunnable().id].customMatchers;
for (var matcherName in matchersToAdd) {
customMatchers[matcherName] = matchersToAdd[matcherName];
}
};
j$.Expectation.addCoreMatchers(j$.matchers);
@@ -55,7 +73,8 @@ getJasmineRequireObj().Env = function(j$) {
var expectationFactory = function(actual, spec) {
return j$.Expectation.Factory({
util: j$.matchersUtil,
customEqualityTesters: customEqualityTesters,
customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
customMatchers: runnableResources[spec.id].customMatchers,
actual: actual,
addExpectationResult: addExpectationResult
});
@@ -65,30 +84,44 @@ getJasmineRequireObj().Env = function(j$) {
}
};
var specStarted = function(spec) {
currentSpec = spec;
reporter.specStarted(spec.result);
var defaultResourcesForRunnable = function(id, parentRunnableId) {
var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
if(runnableResources[parentRunnableId]){
resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
}
runnableResources[id] = resources;
};
var beforeFns = function(suite) {
var clearResourcesForRunnable = function(id) {
spyRegistry.clearSpies();
delete runnableResources[id];
};
var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
return function() {
var befores = [];
var befores = [],
afters = [],
beforeAlls = [],
afterAlls = [];
while(suite) {
befores = befores.concat(suite.beforeFns);
suite = suite.parentSuite;
}
return befores.reverse();
};
};
var afterFns = function(suite) {
return function() {
var afters = [];
while(suite) {
afters = afters.concat(suite.afterFns);
if (runnablesExplictlySet()) {
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
afterAlls = afterAlls.concat(suite.afterAllFns);
}
suite = suite.parentSuite;
}
return afters;
return {
befores: beforeAlls.reverse().concat(befores.reverse()),
afters: afters.concat(afterAlls)
};
};
};
@@ -137,6 +170,7 @@ getJasmineRequireObj().Env = function(j$) {
options.catchException = catchException;
options.clearStack = options.clearStack || clearStack;
options.timer = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
new j$.QueueRunner(options).execute();
};
@@ -146,65 +180,54 @@ getJasmineRequireObj().Env = function(j$) {
id: getNextSuiteId(),
description: 'Jasmine__TopLevel__Suite',
queueRunner: queueRunnerFactory,
resultCallback: function() {} // TODO - hook this up
resultCallback: function(attrs) {
reporter.suiteDone(attrs);
}
});
runnableLookupTable[topSuite.id] = topSuite;
currentSuite = topSuite;
defaultResourcesForRunnable(topSuite.id);
currentDeclarationSuite = topSuite;
this.topSuite = function() {
return topSuite;
};
this.execute = function(runnablesToRun) {
runnablesToRun = runnablesToRun || [topSuite.id];
if(runnablesToRun) {
runnablesExplictlySet = true;
} else if (focusedRunnables.length) {
runnablesExplictlySet = true;
runnablesToRun = focusedRunnables;
} else {
runnablesToRun = [topSuite.id];
}
var allFns = [];
for(var i = 0; i < runnablesToRun.length; i++) {
var runnable = runnableLookupTable[runnablesToRun[i]];
allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
}
reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined
});
queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
};
this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd);
};
this.addMatchers = function(matchersToAdd) {
j$.Expectation.addMatchers(matchersToAdd);
};
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
if(!currentRunnable()) {
throw new Error('Spies must be created in a before function or a spec');
}
return runnableResources[currentRunnable().id].spies;
}});
if (j$.util.isUndefined(obj[methodName])) {
throw new Error(methodName + '() method does not exist');
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
spies.push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
this.spyOn = function() {
return spyRegistry.spyOn.apply(spyRegistry, arguments);
};
var suiteFactory = function(description) {
@@ -212,40 +235,33 @@ getJasmineRequireObj().Env = function(j$) {
env: self,
id: getNextSuiteId(),
description: description,
parentSuite: currentSuite,
parentSuite: currentDeclarationSuite,
queueRunner: queueRunnerFactory,
onStart: suiteStarted,
expectationFactory: expectationFactory,
expectationResultFactory: expectationResultFactory,
resultCallback: function(attrs) {
if (!suite.disabled) {
clearResourcesForRunnable(suite.id);
currentlyExecutingSuites.pop();
}
reporter.suiteDone(attrs);
}
});
runnableLookupTable[suite.id] = suite;
return suite;
function suiteStarted(suite) {
currentlyExecutingSuites.push(suite);
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
reporter.suiteStarted(suite.result);
}
};
this.describe = function(description, specDefinitions) {
var suite = suiteFactory(description);
var parentSuite = currentSuite;
parentSuite.addChild(suite);
currentSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
this.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentSuite = parentSuite;
addSpecsToSuite(suite, specDefinitions);
return suite;
};
@@ -255,15 +271,75 @@ getJasmineRequireObj().Env = function(j$) {
return suite;
};
var specFactory = function(description, fn, suite) {
totalSpecsDefined++;
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
var suite = suiteFactory(description);
suite.isFocused = true;
focusedRunnables.push(suite.id);
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
function addSpecsToSuite(suite, specDefinitions) {
var parentSuite = currentDeclarationSuite;
parentSuite.addChild(suite);
currentDeclarationSuite = suite;
var declarationError = null;
try {
specDefinitions.call(suite);
} catch (e) {
declarationError = e;
}
if (declarationError) {
self.it('encountered a declaration exception', function() {
throw declarationError;
});
}
currentDeclarationSuite = parentSuite;
}
function findFocusedAncestor(suite) {
while (suite) {
if (suite.isFocused) {
return suite.id;
}
suite = suite.parentSuite;
}
return null;
}
function unfocusAncestor() {
var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
if (focusedAncestor) {
for (var i = 0; i < focusedRunnables.length; i++) {
if (focusedRunnables[i] === focusedAncestor) {
focusedRunnables.splice(i, 1);
break;
}
}
}
}
var runnablesExplictlySet = false;
var runnablesExplictlySetGetter = function(){
return runnablesExplictlySet;
};
var specFactory = function(description, fn, suite, timeout) {
totalSpecsDefined++;
var spec = new j$.Spec({
id: getNextSpecId(),
beforeFns: beforeFns(suite),
afterFns: afterFns(suite),
beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
expectationFactory: expectationFactory,
exceptionFormatter: exceptionFormatter,
resultCallback: specResultCallback,
getSpecName: function(spec) {
return getSpecName(spec, suite);
@@ -272,7 +348,11 @@ getJasmineRequireObj().Env = function(j$) {
description: description,
expectationResultFactory: expectationResultFactory,
queueRunnerFactory: queueRunnerFactory,
fn: fn
userContext: function() { return suite.clonedSharedUserContext(); },
queueableFn: {
fn: fn,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
}
});
runnableLookupTable[spec.id] = spec;
@@ -283,58 +363,94 @@ getJasmineRequireObj().Env = function(j$) {
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 = [];
clearResourcesForRunnable(spec.id);
currentSpec = null;
reporter.specDone(result);
}
function specStarted(spec) {
currentSpec = spec;
defaultResourcesForRunnable(spec.id, suite.id);
reporter.specStarted(spec.result);
}
};
var suiteStarted = function(suite) {
reporter.suiteStarted(suite.result);
};
this.it = function(description, fn) {
var spec = specFactory(description, fn, currentSuite);
currentSuite.addChild(spec);
this.it = function(description, fn, timeout) {
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
return spec;
};
this.xit = function(description, fn) {
var spec = this.it(description, fn);
this.xit = function() {
var spec = this.it.apply(this, arguments);
spec.pend();
return spec;
};
this.fit = function(){
var spec = this.it.apply(this, arguments);
focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
};
this.expect = function(actual) {
if (!currentSpec) {
if (!currentRunnable()) {
throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
}
return currentSpec.expect(actual);
return currentRunnable().expect(actual);
};
this.beforeEach = function(beforeEachFunction) {
currentSuite.beforeEach(beforeEachFunction);
this.beforeEach = function(beforeEachFunction, timeout) {
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
});
};
this.afterEach = function(afterEachFunction) {
currentSuite.afterEach(afterEachFunction);
this.beforeAll = function(beforeAllFunction, timeout) {
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
});
};
this.afterEach = function(afterEachFunction, timeout) {
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
});
};
this.afterAll = function(afterAllFunction, timeout) {
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
});
};
this.pending = function() {
throw j$.Spec.pendingSpecExceptionMessage;
};
this.fail = function(error) {
var message = 'Failed';
if (error) {
message += ': ';
message += error.message || error;
}
currentRunnable().addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
message: message
});
};
}
return Env;

View File

@@ -1,7 +1,5 @@
getJasmineRequireObj().Expectation = function() {
var matchers = {};
function Expectation(options) {
this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || [];
@@ -9,8 +7,9 @@ getJasmineRequireObj().Expectation = function() {
this.addExpectationResult = options.addExpectationResult || function(){};
this.isNot = options.isNot;
for (var matcherName in matchers) {
this[matcherName] = matchers[matcherName];
var customMatchers = options.customMatchers || {};
for (var matcherName in customMatchers) {
this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
}
}
@@ -77,19 +76,6 @@ getJasmineRequireObj().Expectation = function() {
}
};
Expectation.addMatchers = function(matchersToAdd) {
for (var name in matchersToAdd) {
var matcher = matchersToAdd[name];
matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
}
};
Expectation.resetMatchers = function() {
for (var name in matchers) {
delete matchers[name];
}
};
Expectation.Factory = function(options) {
options = options || {};

View File

@@ -30,26 +30,31 @@ getJasmineRequireObj().JsApiReporter = function() {
return status;
};
var suites = {};
var suites = [],
suites_hash = {};
this.suiteStarted = function(result) {
storeSuite(result);
suites_hash[result.id] = result;
};
this.suiteDone = function(result) {
storeSuite(result);
};
this.suiteResults = function(index, length) {
return suites.slice(index, index + length);
};
function storeSuite(result) {
suites[result.id] = result;
suites.push(result);
suites_hash[result.id] = result;
}
this.suites = function() {
return suites;
return suites_hash;
};
var specs = [];
this.specStarted = function(result) { };
this.specDone = function(result) {
specs.push(result);

View File

@@ -61,6 +61,7 @@ getJasmineRequireObj().MockDate = function() {
}
function createDateProperties() {
FakeDate.prototype = GlobalDate.prototype;
FakeDate.now = function() {
if (GlobalDate.now) {

View File

@@ -11,31 +11,32 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
function QueueRunner(attrs) {
this.fns = attrs.fns || [];
this.queueableFns = attrs.queueableFns || [];
this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; };
this.enforceTimeout = attrs.enforceTimeout || function() { return false; };
this.userContext = {};
this.userContext = attrs.userContext || {};
this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
}
QueueRunner.prototype.execute = function() {
this.run(this.fns, 0);
this.run(this.queueableFns, 0);
};
QueueRunner.prototype.run = function(fns, recursiveIndex) {
var length = fns.length,
self = this,
iterativeIndex;
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = queueableFns.length,
self = this,
iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var fn = fns[iterativeIndex];
if (fn.length > 0) {
return attemptAsync(fn);
var queueableFn = queueableFns[iterativeIndex];
if (queueableFn.fn.length > 0) {
return attemptAsync(queueableFn);
} else {
attemptSync(fn);
attemptSync(queueableFn);
}
}
@@ -45,41 +46,51 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.clearStack(this.onComplete);
}
function attemptSync(fn) {
function attemptSync(queueableFn) {
try {
fn.call(self.userContext);
queueableFn.fn.call(self.userContext);
} catch (e) {
handleException(e);
handleException(e, queueableFn);
}
}
function attemptAsync(fn) {
function attemptAsync(queueableFn) {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
next = once(function () {
clearTimeout(timeoutId);
self.run(fns, iterativeIndex + 1);
self.run(queueableFns, iterativeIndex + 1);
}),
timeoutId;
if (self.enforceTimeout()) {
next.fail = function() {
self.fail.apply(null, arguments);
next();
};
if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
self.onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
onException(error, queueableFn);
next();
}, j$.DEFAULT_TIMEOUT_INTERVAL]]);
}, queueableFn.timeout()]]);
}
try {
fn.call(self.userContext, next);
queueableFn.fn.call(self.userContext, next);
} catch (e) {
handleException(e);
handleException(e, queueableFn);
next();
}
}
function handleException(e) {
function onException(e, queueableFn) {
self.onException(e);
}
function handleException(e, queueableFn) {
onException(e, queueableFn);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..

View File

@@ -4,17 +4,16 @@ getJasmineRequireObj().Spec = function(j$) {
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.description = attrs.description || '';
this.fn = attrs.fn;
this.beforeFns = attrs.beforeFns || function() { return []; };
this.afterFns = attrs.afterFns || function() { return []; };
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
this.userContext = attrs.userContext || function() { return {}; };
this.onStart = attrs.onStart || function() {};
this.exceptionFormatter = attrs.exceptionFormatter || function() {};
this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() { };
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
if (!this.fn) {
if (!this.queueableFn.fn) {
this.pend();
}
@@ -50,30 +49,16 @@ getJasmineRequireObj().Spec = function(j$) {
return;
}
var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns());
var fns = this.beforeAndAfterFns();
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
this.queueRunnerFactory({
fns: allFns,
onException: onException,
queueableFns: allFns,
onException: function() { self.onException.apply(self, arguments); },
onComplete: complete,
enforceTimeout: function() { return true; }
userContext: this.userContext()
});
function onException(e) {
if (Spec.isPendingSpecException(e)) {
self.pend();
return;
}
self.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
}
function complete() {
self.result.status = self.status();
self.resultCallback(self.result);
@@ -84,6 +69,21 @@ getJasmineRequireObj().Spec = function(j$) {
}
};
Spec.prototype.onException = function onException(e) {
if (Spec.isPendingSpecException(e)) {
this.pend();
return;
}
this.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
});
};
Spec.prototype.disable = function() {
this.disabled = true;
};
@@ -108,6 +108,10 @@ getJasmineRequireObj().Spec = function(j$) {
}
};
Spec.prototype.isExecutable = function() {
return !this.disabled && !this.markedPending;
};
Spec.prototype.getFullName = function() {
return this.getSpecName(this);
};

45
src/core/SpyRegistry.js Normal file
View File

@@ -0,0 +1,45 @@
getJasmineRequireObj().SpyRegistry = function(j$) {
function SpyRegistry(options) {
options = options || {};
var currentSpies = options.currentSpies || function() { return []; };
this.spyOn = function(obj, methodName) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
}
if (j$.util.isUndefined(obj[methodName])) {
throw new Error(methodName + '() method does not exist');
}
if (obj[methodName] && j$.isSpy(obj[methodName])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(methodName + ' has already been spied upon');
}
var spy = j$.createSpy(methodName, obj[methodName]);
currentSpies().push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
return spy;
};
this.clearSpies = function() {
var spies = currentSpies();
for (var i = 0; i < spies.length; i++) {
var spyEntry = spies[i];
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
}
};
}
return SpyRegistry;
};

View File

@@ -28,6 +28,14 @@ getJasmineRequireObj().SpyStrategy = function() {
return getSpy();
};
this.returnValues = function() {
var values = Array.prototype.slice.call(arguments);
plan = function () {
return values.shift();
};
return getSpy();
};
this.throwError = function(something) {
var error = (something instanceof Error) ? something : new Error(something);
plan = function() {

View File

@@ -7,9 +7,13 @@ getJasmineRequireObj().Suite = function() {
this.onStart = attrs.onStart || function() {};
this.resultCallback = attrs.resultCallback || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.expectationFactory = attrs.expectationFactory;
this.expectationResultFactory = attrs.expectationResultFactory;
this.beforeFns = [];
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.queueRunner = attrs.queueRunner || function() {};
this.disabled = false;
@@ -17,12 +21,16 @@ getJasmineRequireObj().Suite = function() {
this.result = {
id: this.id,
status: this.disabled ? 'disabled' : '',
description: this.description,
fullName: this.getFullName()
fullName: this.getFullName(),
failedExpectations: []
};
}
Suite.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
Suite.prototype.getFullName = function() {
var fullName = this.description;
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -35,21 +43,40 @@ getJasmineRequireObj().Suite = function() {
Suite.prototype.disable = function() {
this.disabled = true;
this.result.status = 'disabled';
};
Suite.prototype.beforeEach = function(fn) {
this.beforeFns.unshift(fn);
};
Suite.prototype.beforeAll = function(fn) {
this.beforeAllFns.push(fn);
};
Suite.prototype.afterEach = function(fn) {
this.afterFns.unshift(fn);
};
Suite.prototype.afterAll = function(fn) {
this.afterAllFns.push(fn);
};
Suite.prototype.addChild = function(child) {
this.children.push(child);
};
Suite.prototype.status = function() {
if (this.disabled) {
return 'disabled';
}
if (this.result.failedExpectations.length > 0) {
return 'failed';
} else {
return 'finished';
}
};
Suite.prototype.execute = function(onComplete) {
var self = this;
@@ -62,16 +89,25 @@ getJasmineRequireObj().Suite = function() {
var allFns = [];
for (var i = 0; i < this.children.length; i++) {
allFns.push(wrapChildAsAsync(this.children[i]));
if (this.isExecutable()) {
allFns = allFns.concat(this.beforeAllFns);
for (var i = 0; i < this.children.length; i++) {
allFns.push(wrapChildAsAsync(this.children[i]));
}
allFns = allFns.concat(this.afterAllFns);
}
this.queueRunner({
fns: allFns,
onComplete: complete
queueableFns: allFns,
onComplete: complete,
userContext: this.sharedUserContext(),
onException: function() { self.onException.apply(self, arguments); }
});
function complete() {
self.result.status = self.status();
self.resultCallback(self.result);
if (onComplete) {
@@ -80,10 +116,82 @@ getJasmineRequireObj().Suite = function() {
}
function wrapChildAsAsync(child) {
return function(done) { child.execute(done); };
return { fn: function(done) { child.execute(done); } };
}
};
Suite.prototype.isExecutable = function() {
var foundActive = false;
for(var i = 0; i < this.children.length; i++) {
if(this.children[i].isExecutable()) {
foundActive = true;
break;
}
}
return foundActive;
};
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
}
return this.sharedContext;
};
Suite.prototype.clonedSharedUserContext = function() {
return clone(this.sharedUserContext());
};
Suite.prototype.onException = function() {
if(isAfterAll(this.children)) {
var data = {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: arguments[0]
};
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.onException.apply(child, arguments);
}
}
};
Suite.prototype.addExpectationResult = function () {
if(isAfterAll(this.children) && isFailure(arguments)){
var data = arguments[1];
this.result.failedExpectations.push(this.expectationResultFactory(data));
} else {
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.addExpectationResult.apply(child, arguments);
}
}
};
function isAfterAll(children) {
return children && children[0].result.status;
}
function isFailure(args) {
return !args[0];
}
function clone(obj) {
var clonedObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
clonedObj[prop] = obj[prop];
}
}
return clonedObj;
}
return Suite;
};

View File

@@ -1,102 +1,101 @@
getJasmineRequireObj().base = (function (jasmineGlobal) {
if (typeof module !== 'undefined' && module.exports) {
jasmineGlobal = global;
}
getJasmineRequireObj().base = function(j$, jasmineGlobal) {
j$.unimplementedMethod_ = function() {
throw new Error('unimplemented method');
};
return function(j$) {
j$.unimplementedMethod_ = function() {
throw new Error('unimplemented method');
};
j$.MAX_PRETTY_PRINT_DEPTH = 40;
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
j$.MAX_PRETTY_PRINT_DEPTH = 40;
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
j$.getGlobal = function() {
return jasmineGlobal;
};
j$.getGlobal = function() {
return jasmineGlobal;
};
j$.getEnv = function(options) {
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
//jasmine. singletons in here (setTimeout blah blah).
return env;
};
j$.getEnv = function(options) {
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
//jasmine. singletons in here (setTimeout blah blah).
return env;
};
j$.isArray_ = function(value) {
return j$.isA_('Array', value);
};
j$.isArray_ = function(value) {
return j$.isA_('Array', value);
};
j$.isString_ = function(value) {
return j$.isA_('String', value);
};
j$.isString_ = function(value) {
return j$.isA_('String', value);
};
j$.isNumber_ = function(value) {
return j$.isA_('Number', value);
};
j$.isNumber_ = function(value) {
return j$.isA_('Number', value);
};
j$.isA_ = function(typeName, value) {
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
};
j$.isA_ = function(typeName, value) {
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
};
j$.isDomNode = function(obj) {
return obj.nodeType > 0;
};
j$.isDomNode = function(obj) {
return obj.nodeType > 0;
};
j$.any = function(clazz) {
return new j$.Any(clazz);
};
j$.any = function(clazz) {
return new j$.Any(clazz);
};
j$.objectContaining = function(sample) {
return new j$.ObjectContaining(sample);
};
j$.objectContaining = function(sample) {
return new j$.ObjectContaining(sample);
};
j$.createSpy = function(name, originalFn) {
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);
var spyStrategy = new j$.SpyStrategy({
name: name,
fn: originalFn,
getSpy: function() { return spy; }
}),
callTracker = new j$.CallTracker(),
spy = function() {
var callData = {
object: this,
args: Array.prototype.slice.apply(arguments)
};
for (var prop in originalFn) {
if (prop === 'and' || prop === 'calls') {
throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
}
callTracker.track(callData);
var returnValue = spyStrategy.exec.apply(this, arguments);
callData.returnValue = returnValue;
spy[prop] = originalFn[prop];
return returnValue;
};
for (var prop in originalFn) {
if (prop === 'and' || prop === 'calls') {
throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
}
spy.and = spyStrategy;
spy.calls = callTracker;
spy[prop] = originalFn[prop];
}
return spy;
};
spy.and = spyStrategy;
spy.calls = callTracker;
j$.isSpy = function(putativeSpy) {
if (!putativeSpy) {
return false;
}
return putativeSpy.and instanceof j$.SpyStrategy &&
putativeSpy.calls instanceof j$.CallTracker;
};
j$.createSpyObj = function(baseName, methodNames) {
if (!j$.isArray_(methodNames) || methodNames.length === 0) {
throw 'createSpyObj requires a non-empty array of method names to create spies for';
}
var obj = {};
for (var i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
}
return obj;
};
return spy;
};
})(this);
j$.isSpy = function(putativeSpy) {
if (!putativeSpy) {
return false;
}
return putativeSpy.and instanceof j$.SpyStrategy &&
putativeSpy.calls instanceof j$.CallTracker;
};
j$.createSpyObj = function(baseName, methodNames) {
if (!j$.isArray_(methodNames) || methodNames.length === 0) {
throw 'createSpyObj requires a non-empty array of method names to create spies for';
}
var obj = {};
for (var i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
}
return obj;
};
};

View File

@@ -11,7 +11,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
contains: function(haystack, needle, customTesters) {
customTesters = customTesters || [];
if (Object.prototype.toString.apply(haystack) === '[object Array]') {
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (eq(haystack[i], needle, [], [], customTesters)) {
return true;
@@ -19,6 +21,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}
return false;
}
return !!haystack && haystack.indexOf(needle) >= 0;
},

View File

@@ -5,18 +5,13 @@ getJasmineRequireObj().toThrowError = function(j$) {
var threw = false,
pass = {pass: true},
fail = {pass: false},
thrown,
errorType,
message,
regexp,
name,
constructorName;
thrown;
if (typeof actual != 'function') {
throw new Error('Actual is not a Function');
}
extractExpectedParams.apply(null, arguments);
var errorMatcher = getMatcher.apply(null, arguments);
try {
actual();
@@ -35,121 +30,108 @@ getJasmineRequireObj().toThrowError = function(j$) {
return fail;
}
if (arguments.length == 1) {
if (errorMatcher.hasNoSpecifics()) {
pass.message = 'Expected function not to throw an Error, but it threw ' + fnNameFor(thrown) + '.';
return pass;
}
if (errorType) {
name = fnNameFor(errorType);
constructorName = fnNameFor(thrown.constructor);
}
if (errorType && message) {
if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
pass.message = function() { return 'Expected function not to throw ' + name + ' with message ' + j$.pp(message) + '.'; };
return pass;
} else {
fail.message = function() { return 'Expected function to throw ' + name + ' with message ' + j$.pp(message) +
', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; };
return fail;
}
}
if (errorType && regexp) {
if (thrown.constructor == errorType && regexp.test(thrown.message)) {
pass.message = function() { return 'Expected function not to throw ' + name + ' with message matching ' + j$.pp(regexp) + '.'; };
return pass;
} else {
fail.message = function() { return 'Expected function to throw ' + name + ' with message matching ' + j$.pp(regexp) +
', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; };
return fail;
}
}
if (errorType) {
if (thrown.constructor == errorType) {
pass.message = 'Expected function not to throw ' + name + '.';
return pass;
} else {
fail.message = 'Expected function to throw ' + name + ', but it threw ' + constructorName + '.';
return fail;
}
}
if (message) {
if (thrown.message == message) {
pass.message = function() { return 'Expected function not to throw an exception with message ' + j$.pp(message) + '.'; };
return pass;
} else {
fail.message = function() { return 'Expected function to throw an exception with message ' + j$.pp(message) +
', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; };
return fail;
}
}
if (regexp) {
if (regexp.test(thrown.message)) {
pass.message = function() { return 'Expected function not to throw an exception with a message matching ' + j$.pp(regexp) + '.'; };
return pass;
} else {
fail.message = function() { return 'Expected function to throw an exception with a message matching ' + j$.pp(regexp) +
', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; };
return fail;
}
}
function fnNameFor(func) {
return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
}
function extractExpectedParams() {
if (arguments.length == 1) {
return;
}
if (arguments.length == 2) {
var expected = arguments[1];
if (expected instanceof RegExp) {
regexp = expected;
} else if (typeof expected == 'string') {
message = expected;
} else if (checkForAnErrorType(expected)) {
errorType = expected;
}
if (!(errorType || message || regexp)) {
throw new Error('Expected is not an Error, string, or RegExp.');
}
} else {
if (checkForAnErrorType(arguments[1])) {
errorType = arguments[1];
} else {
throw new Error('Expected error type is not an Error.');
}
if (arguments[2] instanceof RegExp) {
regexp = arguments[2];
} else if (typeof arguments[2] == 'string') {
message = arguments[2];
} else {
throw new Error('Expected error message is not a string or RegExp.');
}
}
}
function checkForAnErrorType(type) {
if (typeof type !== 'function') {
return false;
}
var Surrogate = function() {};
Surrogate.prototype = type.prototype;
return (new Surrogate()) instanceof Error;
if (errorMatcher.matches(thrown)) {
pass.message = function() {
return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
};
return pass;
} else {
fail.message = function() {
return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
};
return fail;
}
}
};
function getMatcher() {
var expected = null,
errorType = null;
if (arguments.length == 2) {
expected = arguments[1];
if (isAnErrorType(expected)) {
errorType = expected;
expected = null;
}
} else if (arguments.length > 2) {
errorType = arguments[1];
expected = arguments[2];
if (!isAnErrorType(errorType)) {
throw new Error('Expected error type is not an Error.');
}
}
if (expected && !isStringOrRegExp(expected)) {
if (errorType) {
throw new Error('Expected error message is not a string or RegExp.');
} else {
throw new Error('Expected is not an Error, string, or RegExp.');
}
}
function messageMatch(message) {
if (typeof expected == 'string') {
return expected == message;
} else {
return expected.test(message);
}
}
return {
errorTypeDescription: errorType ? fnNameFor(errorType) : 'an exception',
thrownDescription: function(thrown) {
var thrownName = errorType ? fnNameFor(thrown.constructor) : 'an exception',
thrownMessage = '';
if (expected) {
thrownMessage = ' with message ' + j$.pp(thrown.message);
}
return thrownName + thrownMessage;
},
messageDescription: function() {
if (expected === null) {
return '';
} else if (expected instanceof RegExp) {
return ' with a message matching ' + j$.pp(expected);
} else {
return ' with message ' + j$.pp(expected);
}
},
hasNoSpecifics: function() {
return expected === null && errorType === null;
},
matches: function(error) {
return (errorType === null || error.constructor === errorType) &&
(expected === null || messageMatch(error.message));
}
};
}
function fnNameFor(func) {
return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
}
function isStringOrRegExp(potential) {
return potential instanceof RegExp || (typeof potential == 'string');
}
function isAnErrorType(type) {
if (typeof type !== 'function') {
return false;
}
var Surrogate = function() {};
Surrogate.prototype = type.prototype;
return (new Surrogate()) instanceof Error;
}
}
return toThrowError;

View File

@@ -1,39 +1,48 @@
function getJasmineRequireObj() {
getJasmineRequireObj = (function (jasmineGlobal) {
var jasmineRequire;
if (typeof module !== 'undefined' && module.exports) {
return exports;
jasmineGlobal = global;
jasmineRequire = exports;
} else {
window.jasmineRequire = window.jasmineRequire || {};
return window.jasmineRequire;
jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {};
}
}
getJasmineRequireObj().core = function(jRequire) {
var j$ = {};
function getJasmineRequire() {
return jasmineRequire;
}
jRequire.base(j$);
j$.util = jRequire.util();
j$.Any = jRequire.Any();
j$.CallTracker = jRequire.CallTracker();
j$.MockDate = jRequire.MockDate();
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
j$.Env = jRequire.Env(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
j$.Expectation = jRequire.Expectation();
j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.JsApiReporter = jRequire.JsApiReporter();
j$.matchersUtil = jRequire.matchersUtil(j$);
j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.Spec = jRequire.Spec(j$);
j$.SpyStrategy = jRequire.SpyStrategy();
j$.Suite = jRequire.Suite();
j$.Timer = jRequire.Timer();
j$.version = jRequire.version();
getJasmineRequire().core = function(jRequire) {
var j$ = {};
j$.matchers = jRequire.requireMatchers(jRequire, j$);
jRequire.base(j$, jasmineGlobal);
j$.util = jRequire.util();
j$.Any = jRequire.Any();
j$.CallTracker = jRequire.CallTracker();
j$.MockDate = jRequire.MockDate();
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
j$.Env = jRequire.Env(j$);
j$.ExceptionFormatter = jRequire.ExceptionFormatter();
j$.Expectation = jRequire.Expectation();
j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.JsApiReporter = jRequire.JsApiReporter();
j$.matchersUtil = jRequire.matchersUtil(j$);
j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.Spec = jRequire.Spec(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy();
j$.Suite = jRequire.Suite();
j$.Timer = jRequire.Timer();
j$.version = jRequire.version();
return j$;
};
j$.matchers = jRequire.requireMatchers(jRequire, j$);
return j$;
};
return getJasmineRequire;
})(this);

View File

@@ -8,6 +8,10 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.xdescribe(description, specDefinitions);
},
fdescribe: function(description, specDefinitions) {
return env.fdescribe(description, specDefinitions);
},
it: function(desc, func) {
return env.it(desc, func);
},
@@ -16,6 +20,10 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.xit(desc, func);
},
fit: function(desc, func) {
return env.fit(desc, func);
},
beforeEach: function(beforeEachFunction) {
return env.beforeEach(beforeEachFunction);
},
@@ -24,6 +32,14 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.afterEach(afterEachFunction);
},
beforeAll: function(beforeAllFunction) {
return env.beforeAll(beforeAllFunction);
},
afterAll: function(afterAllFunction) {
return env.afterAll(afterAllFunction);
},
expect: function(actual) {
return env.expect(actual);
},
@@ -32,6 +48,10 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.pending();
},
fail: function() {
return env.fail.apply(env, arguments);
},
spyOn: function(obj, methodName) {
return env.spyOn(obj, methodName);
},

View File

@@ -33,12 +33,27 @@ getJasmineRequireObj().util = function() {
util.arrayContains = function(array, search) {
var i = array.length;
while (i--) {
if (array[i] == search) {
if (array[i] === search) {
return true;
}
}
return false;
};
util.clone = function(obj) {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
return obj.slice();
}
var cloned = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
cloned[prop] = obj[prop];
}
}
return cloned;
};
return util;
};

View File

@@ -17,7 +17,8 @@ jasmineRequire.HtmlReporter = function(j$) {
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols;
symbols,
failedSuites = [];
this.initialize = function() {
clearPrior();
@@ -54,6 +55,10 @@ jasmineRequire.HtmlReporter = function(j$) {
};
this.suiteDone = function(result) {
if (result.status == 'failed') {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
@@ -67,7 +72,7 @@ jasmineRequire.HtmlReporter = function(j$) {
var failures = [];
this.specDone = function(result) {
if(noExpectations(result) && console && console.error) {
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
@@ -149,6 +154,15 @@ jasmineRequire.HtmlReporter = function(j$) {
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
for(i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message;
var errorBarClassName = 'bar errored';
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage));
}
}
var results = find('.results');
results.appendChild(summary);

View File

@@ -194,6 +194,10 @@ body {
background-color: $neutral-color;
}
&.errored {
background-color: $failing-color;
}
&.menu {
background-color: #fff;
color: $faint-text-color;

View File

@@ -1,5 +1,12 @@
#!/bin/bash -e
set -e
git clone https://github.com/jasmine/jasmine.github.io.git
bundle exec rake jasmine:ci JASMINE_CONFIG_PATH=jasmine.github.io/edge/spec/support/jasmine.yml
cd jasmine.github.io
export BUNDLE_GEMFILE=$PWD/Gemfile
bundle
bundle exec rake update_edge_jasmine
bundle exec rake phantom