mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-09-12 12:21:04 +08:00
merge from master
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "jasmine-fixture",
|
||||
"version": "1.2.0",
|
||||
"main": "dist/jasmine-fixture.js",
|
||||
"ignore": [
|
||||
"app",
|
||||
"config",
|
||||
"spec",
|
||||
"tasks",
|
||||
".travis.yml",
|
||||
"Gruntfile.js",
|
||||
"main.js",
|
||||
"package.json"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"homepage": "https://github.com/searls/jasmine-fixture",
|
||||
"_release": "1.2.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.2.0",
|
||||
"commit": "4796206e77d230c9802b10ff8d2d1db386b57d16"
|
||||
},
|
||||
"_source": "git://github.com/searls/jasmine-fixture.git",
|
||||
"_target": "~1.2.0",
|
||||
"_originalSource": "jasmine-fixture"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
|
||||
#ignore node_modules, as the node project is not "deployed" per se: http://www.mikealrogers.com/posts/nodemodules-in-git.html
|
||||
/node_modules
|
||||
|
||||
/generated
|
||||
|
||||
.sass-cache
|
||||
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
|
||||
#ignore node_modules, as the node project is not "deployed" per se: http://www.mikealrogers.com/posts/nodemodules-in-git.html
|
||||
/node_modules
|
||||
|
||||
/dist
|
||||
/generated
|
||||
|
||||
.sass-cache
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2013 Test Double, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,111 @@
|
||||
# jasmine-fixture
|
||||
|
||||
[](http://travis-ci.org/searls/jasmine-fixture)
|
||||
|
||||
jasmine-fixture helps you write specs that interact with the DOM by making it easier to inject (and then clean up) HTML fixtures using a syntax that's just like jQuery's selectors. (As a result, it requires jQuery.)
|
||||
|
||||
**[Download the latest version here](https://github.com/searls/jasmine-fixture/releases)**.
|
||||
|
||||
# The concept
|
||||
|
||||
Here's one way to think about it:
|
||||
|
||||
In *jQuery*, you give `$()` a CSS selector and it *finds* elements on the DOM.
|
||||
|
||||
In *jasmine-fixture*, you give `affix()` a CSS selector and it *adds* those elements to the DOM.
|
||||
|
||||
This is very useful for tests, because it means that after setting up the state of the DOM with `affix`, your subject code under test will have the elements it needs to do its work.
|
||||
|
||||
Finally, jasmine-fixture will help you avoid test pollution by tidying up and remove everything you affix to the DOM after each spec runs.
|
||||
|
||||
## affix() example
|
||||
|
||||
Let's say you want to write a Jasmine spec for some code that needs to select elements from the DOM with jQuery:
|
||||
|
||||
``` javascript
|
||||
$('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')
|
||||
```
|
||||
|
||||
In the good ol' days of manually crafting your HTML fixtures, you'd have to append some raw HTML to the DOM like this:
|
||||
|
||||
``` javascript
|
||||
beforeEach(function(){
|
||||
$('<div id="toddler"><div class="hidden toy"><input name="toyName" value="cuddle bunny"></div></div>').appendTo('body');
|
||||
});
|
||||
|
||||
afterEach(function(){
|
||||
$('#toddler').remove()
|
||||
});
|
||||
```
|
||||
|
||||
But jasmine-fixture's `affix` method lets you do this instead:
|
||||
|
||||
``` javascript
|
||||
beforeEach(function(){
|
||||
affix('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
That's right, the spec setup above was able to *re-use the exact same ugly jQuery selector* and everything just worked! That means:
|
||||
|
||||
* No external (or worse, shared) fixture files means no risk that they become dumping grounds
|
||||
* The spec can remain comprehensive (meaning that future readers can understand what the code does without referencing an external file)
|
||||
* Less temptation to couple your unit test to your server or client-side HTML templates
|
||||
* More one-line setup, fewer multi-line globs of HTML crowding out the behavior your spec is trying to describe
|
||||
|
||||
Bottom line: it's just like jQuery, but in reverse! (And, of course, it'll clean up after itself after your spec runs.)
|
||||
|
||||
## affixing the affixed by chaining invocations
|
||||
|
||||
`#affix` is both a globally available property on the `window` as well as a jQuery plugin that can be chained with existing jQuery objects (affixing itself beneath their results).
|
||||
|
||||
Let's say our subject has a `$container` element that's been added to the DOM like this:
|
||||
|
||||
``` javascript
|
||||
var $container = affix('.container')
|
||||
```
|
||||
|
||||
That means we can add things to the container by chaining a call to `affix`, like any other jQuery plugin:
|
||||
|
||||
``` javascript
|
||||
var $content = $container.affix('#content')
|
||||
```
|
||||
|
||||
Now our container with the class "container" has some content with the ID "content". Huzzah!
|
||||
|
||||
Note that for easy assignability, affix will always return the topmost element of the thing that it just appended, which in this example is `<div id="content"></div>` (which runs counter to most jQuery plugins, which return the original jQuery object).
|
||||
|
||||
## more examples
|
||||
|
||||
I heard you wanted more examples, so I pulled some from `affix`'s [specs](https://github.com/searls/jasmine-fixture/blob/master/spec/affix-spec.coffee).
|
||||
|
||||
``` coffeescript
|
||||
'span' #<span></span>
|
||||
'.foo' #<div class="foo"></div>
|
||||
'.foo-hah' #<div class="foo-hah"></div>
|
||||
'#baz' #<div id="baz"></div>
|
||||
'h1.foo' #<h1 class="foo"></h1>
|
||||
'h2#baz' #<h2 id="baz"></h2>
|
||||
'h3#zing.zoom' #<h3 id="zing" class="zoom"></h3>
|
||||
'h4.zoom#zing' #<h4 id="zing" class="zoom"></h4>
|
||||
'div span ul li' #<div><span><ul><li></li></ul></span></div>
|
||||
'a b c d e f g h i j k l m n o p q r s t u v w x y z' #<a><b><c><d><e><f><g><h><i><j><k><l><m><n><o><p><q><r><s><t><u><v><w><x><y><z></z></y></x></w></v></u></t></s></r></q></p></o></n></m></l></k></j></i></h></g></f></e></d></c></b></a>
|
||||
'.boom.bang.pow#whoosh' #<div id="whoosh" class="boom bang pow"></div>
|
||||
'#foo .panda' #<div id="foo"><div class="panda"></div></div>
|
||||
'input#man .restroom' #<input id="man"></input>
|
||||
'.pants.zipper' #<div class="pants zipper"></div>
|
||||
'foo > bar > baz' #<foo><bar><baz></baz></bar></foo>
|
||||
'input[value="12"]' #<input value="12">
|
||||
'div[class="class1 class2 class3"] span[div="div1 div2 div3"]' #<div class="class1 class2 class3"><span div="div1 div2 div3"></span></div>
|
||||
'form fieldset[name=ok] input#foo.sp1.sp1[foo="woo"][value="13"]' #<form><fieldset name="ok"><input foo="woo" value="13" id="foo" class="sp1 sp1"></fieldset></form>
|
||||
'[name="foo"][bar="baz"]' #<name name="foo" bar="baz"></name>
|
||||
'div[data-bind="my_item"]' #<div data-bind="my_item"></div>
|
||||
'.ui-dialog[style="width: 1px; height: 5px"]' #<div style="width: 1px; height: 5px" class="ui-dialog"></div>
|
||||
'#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]' #<div id="toddler"><div class="hidden toy"><input name="toyName" value="cuddle bunny"></div></div>
|
||||
'div h1+h2' #<div><h1></h1><h2></h2></div>
|
||||
```
|
||||
|
||||
# Thanks
|
||||
|
||||
I want to offer thanks to Mike Kent, whose [JavaScript port of ZenCoding](https://github.com/zodoz/jquery-ZenCoding) was the basis for parsing most of this (classes, ids, elements, etc.). I also want to thank [Peter Kananen](https://twitter.com/#!/pkananen), for pairing with me on the initial spike of the `affix` method.
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "jasmine-fixture",
|
||||
"version": "1.2.0",
|
||||
"main": "dist/jasmine-fixture.js",
|
||||
"ignore": [
|
||||
"app",
|
||||
"config",
|
||||
"spec",
|
||||
"tasks",
|
||||
".travis.yml",
|
||||
"Gruntfile.js",
|
||||
"main.js",
|
||||
"package.json"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
describe "jasmine-fixture", ->
|
||||
describe "affixing things", ->
|
||||
invariants.passingSpec()
|
||||
|
||||
describe "a simple div", ->
|
||||
Given -> createSpec """
|
||||
describe 'foo', ->
|
||||
Given -> @foo = 1
|
||||
When -> @foo++
|
||||
Then -> @foo == 2
|
||||
"""
|
||||
When (done) -> runSpec done, (result) ->
|
||||
@result = result
|
||||
Then -> expect(@result.stdout).toMatch(/ok.*- foo then this.foo === 2/)
|
||||
@@ -0,0 +1,17 @@
|
||||
root = global
|
||||
|
||||
root.invariants =
|
||||
passingSpec: ->
|
||||
Invariant -> @result.code == 0
|
||||
Invariant -> @result.stderr == ""
|
||||
Invariant -> expect(@result.stdout).toContain """
|
||||
# fail 0
|
||||
|
||||
# ok
|
||||
"""
|
||||
|
||||
failingSpecs: (numberOfFailures = 1) ->
|
||||
Invariant -> @result.code != 0
|
||||
Invariant -> expect(@result.stdout).toContain """
|
||||
# fail #{numberOfFailures}
|
||||
"""
|
||||
@@ -0,0 +1,24 @@
|
||||
root = global
|
||||
|
||||
grunt = require('grunt')
|
||||
|
||||
specPath = "spec-e2e/tmp/example-spec.coffee"
|
||||
|
||||
root.createSpec = (specSource) ->
|
||||
grunt.file.write(specPath, specSource)
|
||||
|
||||
root.readSpec = ->
|
||||
grunt.file.read(specPath, encoding: "UTF-8")
|
||||
|
||||
root.runSpec = (done, callback) ->
|
||||
grunt.util.spawn
|
||||
cmd: "node_modules/.bin/testem",
|
||||
args: ["ci", "-f", "spec-e2e/support/jasmine#{process.env.MAJOR_JASMINE_VERSION || 1}-testem-config.json"]
|
||||
, (error, result, code) ->
|
||||
callback.call jasmine.getEnv().currentSpec,
|
||||
error: error
|
||||
stdout: result.stdout
|
||||
stderr: result.stderr
|
||||
code: code
|
||||
done?()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
grunt = require('grunt')
|
||||
_ = grunt.util._
|
||||
|
||||
grunt.file.mkdir("spec-e2e/tmp")
|
||||
|
||||
afterEach ->
|
||||
_(grunt.file.expand("spec-e2e/tmp/**/*")).each (f) ->
|
||||
grunt.file.delete(f)
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"framework" : "jasmine",
|
||||
"launch_in_dev" : ["Chrome"],
|
||||
"launch_in_ci" : ["PhantomJS"],
|
||||
"before_tests": "node_modules/.bin/coffee -c spec-e2e/tmp/example-spec.coffee",
|
||||
"src_files" : [
|
||||
"generated/js/app.js",
|
||||
"spec/helpers/*.js",
|
||||
"spec-e2e/tmp/example-spec.js"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"framework" : "jasmine2",
|
||||
"launch_in_dev" : ["Chrome"],
|
||||
"launch_in_ci" : ["PhantomJS"],
|
||||
"before_tests": "node_modules/.bin/coffee -c spec-e2e/tmp/example-spec.coffee",
|
||||
"src_files" : [
|
||||
"generated/js/app.js",
|
||||
"spec/helpers/*.js",
|
||||
"spec-e2e/tmp/example-spec.js"
|
||||
]
|
||||
}
|
||||
+10337
File diff suppressed because it is too large
Load Diff
+9472
File diff suppressed because it is too large
Load Diff
+9111
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "jasmine-jquery",
|
||||
"version": "2.0.5",
|
||||
"main": "lib/jasmine-jquery.js",
|
||||
"ignore": [
|
||||
"test",
|
||||
"vendor",
|
||||
".*",
|
||||
"HISTORY.md",
|
||||
"SpecRunner.html"
|
||||
],
|
||||
"dependencies": {
|
||||
"jasmine": ">=2",
|
||||
"jquery": ">=2"
|
||||
},
|
||||
"homepage": "https://github.com/velesin/jasmine-jquery",
|
||||
"_release": "2.0.5",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "2.0.5",
|
||||
"commit": "6abe7e3a329c4332067db9d69b0cca43a605ff46"
|
||||
},
|
||||
"_source": "git://github.com/velesin/jasmine-jquery.git",
|
||||
"_target": "~2.0.3",
|
||||
"_originalSource": "jasmine-jquery"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Contributing to Jasmine-jQuery
|
||||
|
||||
Looking to contribute something to Jasmine-jQuery? **Here's how you can help.**
|
||||
|
||||
## Reporting issues
|
||||
|
||||
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems that we can fix within the Jasmine-jQuery. Please read the following guidelines before opening any issue.
|
||||
|
||||
1. **Search for existing issues.** Somemeone else may have reported the same issue. Moreover, the issue may have already been resolved with a fix available.
|
||||
2. **Create an isolated and reproducible test case.** Be sure the problem exists in Jasmine-jQuery's code with a [reduced test case](http://css-tricks.com/reduced-test-cases/) that should be included in each bug report.
|
||||
3. **Include a live example.** Make use of jsFiddle or jsBin to share your isolated test cases.
|
||||
4. **Share as much information as possible.** Include operating system and version, browser and version, version of Jasmine-jQuery. Also include steps to reproduce the bug.
|
||||
|
||||
## Pull requests
|
||||
|
||||
- Try not to pollute your pull request with unintended changes--keep them simple and small
|
||||
- Please squash your commits when appropriate. This simplifies future cherry picks, and also keeps the git log clean.
|
||||
- Include tests that fail without your code, and pass with it.
|
||||
- Update the documentation, examples elsewhere, and the guides: whatever is affected by your contribution.
|
||||
- If you can, have another developer sanity check your change.
|
||||
|
||||
## Coding standards
|
||||
|
||||
- No semicolons
|
||||
- Comma first
|
||||
- 2 spaces (no tabs)
|
||||
- strict mode
|
||||
- "Attractive"
|
||||
@@ -0,0 +1,33 @@
|
||||
/* jshint node: true */
|
||||
|
||||
module.exports = function (grunt) {
|
||||
"use strict";
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
, jshint: {
|
||||
all: [
|
||||
"Gruntfile.js"
|
||||
, "lib/**/*.js"
|
||||
, "spec/**/*.js"
|
||||
]
|
||||
, options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
}
|
||||
, jasmine: {
|
||||
src: "lib/**/*.js"
|
||||
, options: {
|
||||
specs: "spec/**/*.js"
|
||||
, vendor: "vendor/**/*.js"
|
||||
, version: '2.0.0'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint')
|
||||
grunt.loadNpmTasks('grunt-contrib-jasmine')
|
||||
|
||||
grunt.registerTask('test', ['jshint', 'jasmine'])
|
||||
grunt.registerTask('default', ['test'])
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2010-2014 Wojciech Zawistowski, Travis Jeffery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,362 @@
|
||||
# jasmine-jquery [](https://travis-ci.org/velesin/jasmine-jquery)
|
||||
|
||||
|
||||
jasmine-jquery provides two extensions for [Jasmine](http://pivotal.github.com/jasmine/) JavaScript Testing Framework:
|
||||
|
||||
- a set of custom matchers for jQuery framework
|
||||
- an API for handling HTML, CSS, and JSON fixtures in your specs
|
||||
|
||||
## Installation
|
||||
|
||||
Simply download _jasmine-jquery.js_ from [here](https://raw.github.com/velesin/jasmine-jquery/master/lib/jasmine-jquery.js) and include it in your Jasmine's test runner file (or add it to _jasmine.yml_ file if you're using Ruby with [jasmine-gem](http://github.com/pivotal/jasmine-gem)). Remember to include also jQuery library as jasmine-jquery relies on it.
|
||||
|
||||
For Ruby on Rails, use this [gem](https://github.com/travisjeffery/jasmine-jquery-rails) or I recommend to comply with the standard RSpec and Jasmine frameworks dir structure and keep your tests in `spec/javascripts/` dir. I put jasmine-jquery (and other libraries like jasmine-ajax) into `spec/javascripts/helpers` dir (so they are automatically loaded) and fixtures into `spec/javascripts/fixtures` dir.
|
||||
|
||||
## jQuery matchers
|
||||
|
||||
jasmine-jquery provides following custom matchers (in alphabetical order):
|
||||
|
||||
- `toBeChecked()`
|
||||
- only for tags that have checked attribute
|
||||
- e.g. `expect($('<input type="checkbox" checked="checked"/>')).toBeChecked()`
|
||||
- `toBeDisabled()`
|
||||
- e.g. `expect('<input type="submit" disabled="disabled"/>').toBeDisabled()`
|
||||
- `toBeEmpty()`
|
||||
- Checks for child DOM elements or text.
|
||||
- `toBeFocused()`
|
||||
- e.g. `expect($('<input type="text" />').focus()).toBeFocused()`
|
||||
- `toBeHidden()`
|
||||
Elements can be considered hidden for several reasons:
|
||||
- They have a CSS `display` value of `none`.
|
||||
- They are form elements with `type` equal to `hidden`.
|
||||
- Their `width` and `height` are explicitly set to `0`.
|
||||
- An ancestor element is hidden, so the element is not shown on the page.
|
||||
- `toBeInDOM()`
|
||||
- Checksto see if the matched element is attached to the DOM
|
||||
- e.g. `expect($('#id-name')[0]).toBeInDOM()`
|
||||
- `toBeMatchedBy(jQuerySelector)`
|
||||
- Check to see if the set of matched elements matches the given selector
|
||||
- e.g. `expect($('<span></span>').addClass('js-something')).toBeMatchedBy('.js-something')`
|
||||
- true if the dom contains the element
|
||||
- `toBeSelected()`
|
||||
- only for tags that have selected attribute
|
||||
- e.g. `expect($('<option selected="selected"></option>')).toBeSelected()`
|
||||
- `toBeVisible()`
|
||||
- Elements are considered visible if they consume space in the document. Visible elements have a width or height that is greater than zero.
|
||||
- `toContainElement(jQuerySelector)`
|
||||
- e.g. `expect($('<div><span class="some-class"></span></div>')).toContainElement('span.some-class')`
|
||||
- `toContainHtml(string)`
|
||||
- e.g. `expect($('<div><ul></ul><h1>header</h1></div>')).toContainHtml('<ul></ul>')`
|
||||
- `toContainText(string)`
|
||||
- e.g. `expect($('<div><ul></ul><h1>header</h1></div>')).toContainText('header')`
|
||||
- `toEqual(jQuerySelector)`
|
||||
- e.g. `expect($('<div id="some-id"></div>')).toEqual('div')`
|
||||
- e.g. `expect($('<div id="some-id"></div>')).toEqual('div#some-id')`
|
||||
- `toExist()`
|
||||
- true if element exists in or out of the dom
|
||||
- `toHandle(eventName)`
|
||||
- e.g. `expect($form).toHandle("submit")`
|
||||
- `toHandleWith(eventName, eventHandler)`
|
||||
- e.g. `expect($form).toHandleWith("submit", yourSubmitCallback)`
|
||||
- `toHaveAttr(attributeName, attributeValue)`
|
||||
- attribute value is optional, if omitted it will check only if attribute exists
|
||||
- `toHaveBeenTriggeredOn(selector)`
|
||||
- if event has been triggered on `selector` (see "Event Spies", below)
|
||||
- `toHaveBeenTriggered()`
|
||||
- if event has been triggered on `selector` (see "Event Spies", below)
|
||||
- `toHaveBeenTriggeredOnAndWith(selector, extraParameters)`
|
||||
- if event has been triggered on `selector` and with `extraParameters`
|
||||
- `toHaveBeenPreventedOn(selector)`
|
||||
- if event has been prevented on `selector` (see "Event Spies", below)
|
||||
- `toHaveBeenPrevented()`
|
||||
- if event has been prevented on `selector` (see "Event Spies", below)
|
||||
- `toHaveClass(className)`
|
||||
- e.g. `expect($('<div class="some-class"></div>')).toHaveClass("some-class")`
|
||||
- `toHaveCss(css)`
|
||||
- e.g. `expect($('<div style="display: none; margin: 10px;"></div>')).toHaveCss({display: "none", margin: "10px"})`
|
||||
- e.g. `expect($('<div style="display: none; margin: 10px;"></div>')).toHaveCss({margin: "10px"})`
|
||||
- `toHaveData(key, value)`
|
||||
- value is optional, if omitted it will check only if an entry for that key exists
|
||||
- `toHaveHtml(string)`
|
||||
- e.g. `expect($('<div><span></span></div>')).toHaveHtml('<span></span>')`
|
||||
- `toHaveId(id)`
|
||||
- e.g. `expect($('<div id="some-id"></div>')).toHaveId("some-id")`
|
||||
- `toHaveLength(value)`
|
||||
- e.g. `expect($('ul > li')).toHaveLength(3)`
|
||||
- `toHaveProp(propertyName, propertyValue)`
|
||||
- property value is optional, if omitted it will check only if property exists
|
||||
- `toHaveText(string)`
|
||||
- accepts a String or regular expression
|
||||
- e.g. `expect($('<div>some text</div>')).toHaveText('some text')`
|
||||
- `toHaveValue(value)`
|
||||
- only for elements on which `val` can be called (`input`, `textarea`, etc)
|
||||
- e.g. `expect($('<input type="text" value="some text"/>')).toHaveValue('some text')`
|
||||
|
||||
The same as with standard Jasmine matchers, all of above custom matchers may be inverted by using `.not` prefix, e.g.:
|
||||
|
||||
expect($('<div>some text</div>')).not.toHaveText(/other/)
|
||||
|
||||
## HTML Fixtures
|
||||
|
||||
The Fixture module of jasmine-jquery allows you to load HTML content to be used by your tests. The overall workflow is like follows:
|
||||
|
||||
In _myfixture.html_ file:
|
||||
|
||||
<div id="my-fixture">some complex content here</div>
|
||||
|
||||
Inside your test:
|
||||
|
||||
loadFixtures('myfixture.html')
|
||||
$('#my-fixture').myTestedPlugin()
|
||||
expect($('#my-fixture')).to...
|
||||
|
||||
By default, fixtures are loaded from `spec/javascripts/fixtures`. You can configure this path: `jasmine.getFixtures().fixturesPath = 'my/new/path';`.
|
||||
|
||||
Your fixture is being loaded into `<div id="jasmine-fixtures"></div>` container that is automatically added to the DOM by the Fixture module (If you _REALLY_ must change id of this container, try: `jasmine.getFixtures().containerId = 'my-new-id';` in your test runner). To make tests fully independent, fixtures container is automatically cleaned-up between tests, so you don't have to worry about left-overs from fixtures loaded in preceeding test. Also, fixtures are internally cached by the Fixture module, so you can load the same fixture file in several tests without penalty to your test suite's speed.
|
||||
|
||||
To invoke fixture related methods, obtain Fixtures singleton through a factory and invoke a method on it:
|
||||
|
||||
jasmine.getFixtures().load(...)
|
||||
|
||||
There are also global short cut functions available for the most used methods, so the above example can be rewritten to just:
|
||||
|
||||
loadFixtures(...)
|
||||
|
||||
Several methods for loading fixtures are provided:
|
||||
|
||||
- `load(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Loads fixture(s) from one or more files and automatically appends them to the DOM (to the fixtures container).
|
||||
- `appendLoad(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Same as load, but adds the fixtures to the pre-existing fixture container.
|
||||
- `read(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Loads fixture(s) from one or more files but instead of appending them to the DOM returns them as a string (useful if you want to process fixture's content directly in your test).
|
||||
- `set(html)`
|
||||
- Doesn't load fixture from file, but instead gets it directly as a parameter (html parameter may be a string or a jQuery element, so both `set('<div></div>')` and `set($('<div/>'))` will work). Automatically appends fixture to the DOM (to the fixtures container). It is useful if your fixture is too simple to keep it in an external file or is constructed procedurally, but you still want Fixture module to automatically handle DOM insertion and clean-up between tests for you.
|
||||
- `appendSet(html)`
|
||||
- Same as set, but adds the fixtures to the pre-existing fixture container.
|
||||
- `preload(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Pre-loads fixture(s) from one or more files and stores them into cache, without returning them or appending them to the DOM. All subsequent calls to `load` or `read` methods will then get fixtures content from cache, without making any AJAX calls (unless cache is manually purged by using `clearCache` method). Pre-loading all fixtures before a test suite is run may be useful when working with libraries like jasmine-ajax that block or otherwise modify the inner workings of JS or jQuery AJAX calls.
|
||||
|
||||
All of above methods have matching global short cuts:
|
||||
|
||||
- `loadFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
- `appendLoadFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
- `readFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
- `setFixtures(html)`
|
||||
- `appendSetFixtures(html)`
|
||||
|
||||
``` javascript
|
||||
var fixture = setFixtures('<div class="post">foo</div>')
|
||||
var post = fixture.find('.post')
|
||||
```
|
||||
|
||||
Also, a helper method for creating HTML elements for your tests is provided:
|
||||
|
||||
- `sandbox([{attributeName: value[, attributeName: value, ...]}])`
|
||||
|
||||
It creates an empty DIV element with a default id="sandbox". If a hash of attributes is provided, they will be set for this DIV tag. If a hash of attributes contains id attribute it will override the default value. Custom attributes can also be set. So e.g.:
|
||||
|
||||
sandbox()
|
||||
|
||||
Will return:
|
||||
|
||||
<div id="sandbox"></div>
|
||||
|
||||
And:
|
||||
|
||||
sandbox({
|
||||
id: 'my-id',
|
||||
class: 'my-class',
|
||||
myattr: 'my-attr'
|
||||
})
|
||||
|
||||
Will return:
|
||||
|
||||
<div id="my-id" class="my-class" myattr="my-attr"></div>
|
||||
|
||||
Sandbox method is useful if you want to quickly create simple fixtures in your tests without polluting them with HTML strings:
|
||||
|
||||
setFixtures(sandbox({class: 'my-class'}))
|
||||
$('#sandbox').myTestedClassRemoverPlugin()
|
||||
expect($('#sandbox')).not.toHaveClass('my-class')
|
||||
|
||||
This method also has a global short cut available:
|
||||
|
||||
- `sandbox([{attributeName: value[, attributeName: value, ...]}])`
|
||||
|
||||
Additionally, two clean up methods are provided:
|
||||
|
||||
- `clearCache()`
|
||||
- purges Fixture module internal cache (you should need it only in very special cases; typically, if you need to use it, it may indicate a smell in your test code)
|
||||
- `cleanUp()`
|
||||
- cleans-up fixtures container (this is done automatically between tests by Fixtures module, so there is no need to ever invoke this manually, unless you're testing a really fancy special case and need to clean-up fixtures in the middle of your test)
|
||||
|
||||
These two methods do not have global short cut functions.
|
||||
|
||||
## Style Fixtures
|
||||
|
||||
The StyleFixtures module is pretty much like the Fixtures module, but it allows you to load CSS content on the page while testing. It may be useful if your tests expect that certain css rules are applied to elements that you are testing. The overall workflow is typically the same:
|
||||
|
||||
In _mycssfixture.css_ file:
|
||||
|
||||
.elem { position: absolute }
|
||||
|
||||
Inside your test:
|
||||
|
||||
loadStyleFixtures('mycssfixture.css')
|
||||
$('#my-fixture').myTestedPlugin()
|
||||
expect($('#my-fixture .elem')).toHaveCss({left: "300px"})
|
||||
|
||||
Notice that if you haven't applied the `position: absolute` rule to the `.elem` and try to test its left position in some browsers (e.g. GoogleChrome) you will allways get the value `auto` even if your plugin did everything correct and applied positioning. So that's why you might need to load style fixtures. In Firefox though you will get the correct value even without the `position: absolute`.
|
||||
|
||||
By default, style fixtures are loaded from `spec/javascripts/fixtures`. You can configure this path: `jasmine.getStyleFixtures().fixturesPath = 'my/new/path';`.
|
||||
|
||||
Like in Fixtures module, StyleFixtures are also automatically cleaned-up between tests and are internally cached, so you can load the same fixture file in several tests without penalty to your test suite's speed.
|
||||
|
||||
To invoke fixture related methods, obtain StyleFixtures singleton through a factory and invoke a method on it:
|
||||
|
||||
jasmine.getStyleFixtures().load(...)
|
||||
|
||||
There are also global short cut functions available for the most used methods, so the above example can be rewritten to just:
|
||||
|
||||
loadStyleFixtures(...)
|
||||
|
||||
Several methods for loading fixtures are provided:
|
||||
|
||||
- `load(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Loads fixture(s) from one or more files and automatically appends them to the DOM into the HEAD element. This method will remove all existing fixtures loaded previously, if any.
|
||||
- `appendLoad(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Same as load, but it won't remove fixtures you added earlier.
|
||||
- `set(css)`
|
||||
- Doesn't load fixture from file, but instead gets it directly as a parameter (e.g. `set('body {background: red}')`). Automatically appends style to the DOM. It is useful if your css fixture is too simple to keep it in an external file. This method will remove all existing fixtures loaded previously, if any.
|
||||
- `appendSet(css)`
|
||||
- Same as set, but it won't remove fixtures you added earlier.
|
||||
- `preload(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Pre-loads fixture(s) from one or more files and stores them into cache, without returning them or appending them to the DOM. All subsequent calls to `load` methods will then get fixtures content from cache, without making any AJAX calls (unless cache is manually purged by using `clearCache` method).
|
||||
|
||||
All of above methods have matching global short cuts:
|
||||
|
||||
- `loadStyleFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
- `appendLoadStyleFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
- `setStyleFixtures(css)`
|
||||
- `appendSetStyleFixtures(css)`
|
||||
|
||||
Additionally, two clean up methods are provided:
|
||||
|
||||
- `clearCache()`
|
||||
- purges StyleFixture module internal cache (you should need it only in very special cases; typically, if you need to use it, it may indicate a smell in your test code)
|
||||
- `cleanUp()`
|
||||
- cleans-up all existing style fixtures (this is done automatically between tests, so there is no need to ever invoke this manually, unless you're testing a really fancy special case and need to clean-up fixtures in the middle of your test)
|
||||
|
||||
These two methods do not have global short cut functions.
|
||||
|
||||
## JSON Fixtures
|
||||
|
||||
The JSONFixtures modules allows you to load JSON data from file (instead of putting huge blocks of data in the spec files).
|
||||
|
||||
In _myjsonfixture.json_ file:
|
||||
|
||||
{"property1":"value1", "array1":[1,2,3]}
|
||||
|
||||
Inside your test:
|
||||
|
||||
var data = getJSONFixture('myjsonfixture.json')
|
||||
// or load and get the JSON two-step
|
||||
var fixtures = loadJSONFixtures('myjsonfixture.json')
|
||||
var data = fixtures['myjsonfixture.json']
|
||||
|
||||
expect(myDataManipulator.processData(test_data)).to...)
|
||||
|
||||
By default, fixtures are loaded from `spec/javascripts/fixtures/json`. You can configure this path: `jasmine.getJSONFixtures().fixturesPath = 'my/new/path';`.
|
||||
|
||||
Your fixture data is loaded into an object stashed by the JSONFixtures structure. You fetch the data using the filename as the key. This allows you to load multiple chunks of test data in a spec.
|
||||
|
||||
Because a deep copy of Javascript objects can be a little tricky, this module will refetch data each time you call `load`. If you modify the data within a spec, you must call `load` or `loadJSONFixtures` again to repopulate the data.
|
||||
|
||||
To invoke fixture related methods, obtain Fixtures singleton through a factory and invoke a method on it:
|
||||
|
||||
jasmine.getJSONFixtures().load(...)
|
||||
|
||||
There are also global short cut functions available for the most used methods, so the above example can be rewritten to just:
|
||||
|
||||
loadJSONFixtures(...)
|
||||
|
||||
Several methods for loading fixtures are provided:
|
||||
|
||||
- `load(fixtureUrl[, fixtureUrl, ...])`
|
||||
- Loads fixture(s) from one or more files and automatically adds them to the fixture list. This method returns the entire set of fixtures keyed by their filename.
|
||||
|
||||
All of above methods have matching global short cuts:
|
||||
|
||||
- `loadJSONFixtures(fixtureUrl[, fixtureUrl, ...])`
|
||||
|
||||
- `getJSONFixture(fixtureUrl)`
|
||||
- After you've loaded fixture files, this global helper will retrieve the fixture data given the fixtureUrl
|
||||
|
||||
|
||||
## Event Spies
|
||||
|
||||
Spying on jQuery events can be done with `spyOnEvent` and
|
||||
`expect(eventName).toHaveBeenTriggeredOn(selector)` or
|
||||
`expect(spyEvent).toHaveBeenTriggered()` . First, spy on the event:
|
||||
|
||||
var spyEvent = spyOnEvent('#some_element', 'click')
|
||||
$('#some_element').click()
|
||||
expect('click').toHaveBeenTriggeredOn('#some_element')
|
||||
expect(spyEvent).toHaveBeenTriggered()
|
||||
|
||||
You can reset spy events
|
||||
|
||||
var spyEvent = spyOnEvent('#some_element', 'click')
|
||||
$('#some_element').click()
|
||||
expect('click').toHaveBeenTriggeredOn('#some_element')
|
||||
expect(spyEvent).toHaveBeenTriggered()
|
||||
// reset spy events
|
||||
spyEvent.reset()
|
||||
expect('click').not.toHaveBeenTriggeredOn('#some_element')
|
||||
expect(spyEvent).not.toHaveBeenTriggered()
|
||||
|
||||
You can similarly check if triggered event was prevented:
|
||||
|
||||
var spyEvent = spyOnEvent('#some_element', 'click')
|
||||
$('#some_element').click(function (event){event.preventDefault();})
|
||||
$('#some_element').click()
|
||||
expect('click').toHaveBeenPreventedOn('#some_element')
|
||||
expect(spyEvent).toHaveBeenPrevented()
|
||||
|
||||
You can also check if the triggered event was stopped:
|
||||
|
||||
var spyEvent = spyOnEvent('#some_element', 'click')
|
||||
$('#some_element').click(function (event){event.stopPropagation();})
|
||||
$('#some_element').click()
|
||||
expect('click').toHaveBeenStoppedOn('#some_element')
|
||||
expect(spyEvent).toHaveBeenStopped()
|
||||
|
||||
Much thanks to Luiz Fernando Ribeiro for his
|
||||
[article on Jasmine event spies](http://luizfar.wordpress.com/2011/01/10/testing-events-on-jquery-objects-with-jasmine/).
|
||||
|
||||
## Dependencies
|
||||
|
||||
jasmine-jquery v2.0.0+ is to be used with jasmine v2.0.0+. jasmine-jquery v1.7.0 is to be used with jasmine < v2.0.0.
|
||||
|
||||
jasmine-jquery is tested with jQuery 2.0 on IE, FF, Chrome, and Safari. There is a high chance it will work with older versions and other browsers as well, but I don't typically run test suite against them when adding new features.
|
||||
|
||||
## Cross domain policy problems under Chrome
|
||||
|
||||
Newer versions of Chrome don't allow file:// URIs read other file:// URIs. In effect, jasmine-jquery cannot properly load fixtures under some versions of Chrome. An override for this is to run Chrome with a switch `--allow-file-access-from-files`. (https://github.com/velesin/jasmine-jquery/issues/4). Quit open Chromes before running Chrome with that switch. (https://github.com/velesin/jasmine-jquery/issues/179).
|
||||
|
||||
Under Windows 7, you have to launch `C:\Users\[UserName]\AppData\Local\Google\Chrome[ SxS]\Application\chrome.exe --allow-file-access-from-files`
|
||||
|
||||
## Mocking with jasmine-ajax
|
||||
|
||||
[jasmine-ajax](https://github.com/pivotal/jasmine-ajax) library doesn't let user to manually start / stop XMLHttpRequest mocking, but instead it overrides XMLHttpRequest automatically when loaded. This breaks jasmine-jquery fixtures as fixture loading mechanism uses jQuery.ajax, that stops to function the very moment jasmine-ajax is loaded. A workaround for this may be to invoke jasmine-jquery `preloadFixtures` function (specifying all required fixtures) before jasmine-ajax is loaded. This way subsequent calls to `loadFixtures` or `readFixtures` methods will get fixtures content from cache, without need to use jQuery.ajax and thus will work correctly even after jasmine-ajax is loaded.
|
||||
|
||||
## Testing with Javascript Test Driver
|
||||
|
||||
When using [jstd](http://code.google.com/p/js-test-driver/) and the jasmine adapter you will need to include jasmine-jquery.js after your jasmine-jstd-adapter files, otherwise jasmine-jquery matchers will not be available when tests are executed. Check out [this issue](https://github.com/velesin/jasmine-jquery/issues/95#issuecomment-9293180) for a thorough configuration example too.
|
||||
|
||||
## Maintainer
|
||||
|
||||
[Travis Jeffery](http://travisjeffery.com/): [Twitter](http://twitter.com/travisjeffery), [GitHub](http://github.com/travisjeffery).
|
||||
|
||||
## [Contributing](./CONTRIBUTING.md)
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "jasmine-jquery",
|
||||
"version": "2.0.5",
|
||||
"main": "lib/jasmine-jquery.js",
|
||||
"ignore": [
|
||||
"test",
|
||||
"vendor",
|
||||
".*",
|
||||
"HISTORY.md",
|
||||
"SpecRunner.html"
|
||||
],
|
||||
"dependencies": {
|
||||
"jasmine": ">=2",
|
||||
"jquery": ">=2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,813 @@
|
||||
/*!
|
||||
Jasmine-jQuery: a set of jQuery helpers for Jasmine tests.
|
||||
|
||||
Version 2.0.5
|
||||
|
||||
https://github.com/velesin/jasmine-jquery
|
||||
|
||||
Copyright (c) 2010-2014 Wojciech Zawistowski, Travis Jeffery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
+function (window, jasmine, $) { "use strict";
|
||||
|
||||
jasmine.spiedEventsKey = function (selector, eventName) {
|
||||
return [$(selector).selector, eventName].toString()
|
||||
}
|
||||
|
||||
jasmine.getFixtures = function () {
|
||||
return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
|
||||
}
|
||||
|
||||
jasmine.getStyleFixtures = function () {
|
||||
return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures()
|
||||
}
|
||||
|
||||
jasmine.Fixtures = function () {
|
||||
this.containerId = 'jasmine-fixtures'
|
||||
this.fixturesCache_ = {}
|
||||
this.fixturesPath = 'spec/javascripts/fixtures'
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.set = function (html) {
|
||||
this.cleanUp()
|
||||
return this.createContainer_(html)
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.appendSet= function (html) {
|
||||
this.addToContainer_(html)
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.preload = function () {
|
||||
this.read.apply(this, arguments)
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.load = function () {
|
||||
this.cleanUp()
|
||||
this.createContainer_(this.read.apply(this, arguments))
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.appendLoad = function () {
|
||||
this.addToContainer_(this.read.apply(this, arguments))
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.read = function () {
|
||||
var htmlChunks = []
|
||||
, fixtureUrls = arguments
|
||||
|
||||
for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
|
||||
htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
|
||||
}
|
||||
|
||||
return htmlChunks.join('')
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.clearCache = function () {
|
||||
this.fixturesCache_ = {}
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.cleanUp = function () {
|
||||
$('#' + this.containerId).remove()
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.sandbox = function (attributes) {
|
||||
var attributesToSet = attributes || {}
|
||||
return $('<div id="sandbox" />').attr(attributesToSet)
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.createContainer_ = function (html) {
|
||||
var container = $('<div>')
|
||||
.attr('id', this.containerId)
|
||||
.html(html)
|
||||
|
||||
$(document.body).append(container)
|
||||
return container
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.addToContainer_ = function (html){
|
||||
var container = $(document.body).find('#'+this.containerId).append(html)
|
||||
|
||||
if (!container.length) {
|
||||
this.createContainer_(html)
|
||||
}
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.getFixtureHtml_ = function (url) {
|
||||
if (typeof this.fixturesCache_[url] === 'undefined') {
|
||||
this.loadFixtureIntoCache_(url)
|
||||
}
|
||||
return this.fixturesCache_[url]
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
|
||||
var self = this
|
||||
, url = this.makeFixtureUrl_(relativeUrl)
|
||||
, htmlText = ''
|
||||
, request = $.ajax({
|
||||
async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
|
||||
cache: false,
|
||||
url: url,
|
||||
success: function (data, status, $xhr) {
|
||||
htmlText = $xhr.responseText
|
||||
}
|
||||
}).fail(function ($xhr, status, err) {
|
||||
throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
|
||||
})
|
||||
|
||||
var scripts = $($.parseHTML(htmlText, true)).find('script[src]') || [];
|
||||
|
||||
scripts.each(function(){
|
||||
$.ajax({
|
||||
async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
|
||||
cache: false,
|
||||
dataType: 'script',
|
||||
url: $(this).attr('src'),
|
||||
success: function (data, status, $xhr) {
|
||||
htmlText += '<script>' + $xhr.responseText + '</script>'
|
||||
},
|
||||
error: function ($xhr, status, err) {
|
||||
throw new Error('Script could not be loaded: ' + scriptSrc + ' (status: ' + status + ', message: ' + err.message + ')')
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
self.fixturesCache_[relativeUrl] = htmlText;
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.makeFixtureUrl_ = function (relativeUrl){
|
||||
return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
|
||||
}
|
||||
|
||||
jasmine.Fixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
|
||||
return this[methodName].apply(this, passedArguments)
|
||||
}
|
||||
|
||||
|
||||
jasmine.StyleFixtures = function () {
|
||||
this.fixturesCache_ = {}
|
||||
this.fixturesNodes_ = []
|
||||
this.fixturesPath = 'spec/javascripts/fixtures'
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.set = function (css) {
|
||||
this.cleanUp()
|
||||
this.createStyle_(css)
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.appendSet = function (css) {
|
||||
this.createStyle_(css)
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.preload = function () {
|
||||
this.read_.apply(this, arguments)
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.load = function () {
|
||||
this.cleanUp()
|
||||
this.createStyle_(this.read_.apply(this, arguments))
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.appendLoad = function () {
|
||||
this.createStyle_(this.read_.apply(this, arguments))
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.cleanUp = function () {
|
||||
while(this.fixturesNodes_.length) {
|
||||
this.fixturesNodes_.pop().remove()
|
||||
}
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.createStyle_ = function (html) {
|
||||
var styleText = $('<div></div>').html(html).text()
|
||||
, style = $('<style>' + styleText + '</style>')
|
||||
|
||||
this.fixturesNodes_.push(style)
|
||||
$('head').append(style)
|
||||
}
|
||||
|
||||
jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
|
||||
jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
|
||||
jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
|
||||
jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
|
||||
jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
|
||||
jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
|
||||
|
||||
jasmine.getJSONFixtures = function () {
|
||||
return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures = function () {
|
||||
this.fixturesCache_ = {}
|
||||
this.fixturesPath = 'spec/javascripts/fixtures/json'
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.load = function () {
|
||||
this.read.apply(this, arguments)
|
||||
return this.fixturesCache_
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.read = function () {
|
||||
var fixtureUrls = arguments
|
||||
|
||||
for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
|
||||
this.getFixtureData_(fixtureUrls[urlIndex])
|
||||
}
|
||||
|
||||
return this.fixturesCache_
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.clearCache = function () {
|
||||
this.fixturesCache_ = {}
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.getFixtureData_ = function (url) {
|
||||
if (!this.fixturesCache_[url]) this.loadFixtureIntoCache_(url)
|
||||
return this.fixturesCache_[url]
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
|
||||
var self = this
|
||||
, url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
|
||||
|
||||
$.ajax({
|
||||
async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
url: url,
|
||||
success: function (data) {
|
||||
self.fixturesCache_[relativeUrl] = data
|
||||
},
|
||||
error: function ($xhr, status, err) {
|
||||
throw new Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
jasmine.JSONFixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
|
||||
return this[methodName].apply(this, passedArguments)
|
||||
}
|
||||
|
||||
jasmine.jQuery = function () {}
|
||||
|
||||
jasmine.jQuery.browserTagCaseIndependentHtml = function (html) {
|
||||
return $('<div/>').append(html).html()
|
||||
}
|
||||
|
||||
jasmine.jQuery.elementToString = function (element) {
|
||||
return $(element).map(function () { return this.outerHTML; }).toArray().join(', ')
|
||||
}
|
||||
|
||||
var data = {
|
||||
spiedEvents: {}
|
||||
, handlers: []
|
||||
}
|
||||
|
||||
jasmine.jQuery.events = {
|
||||
spyOn: function (selector, eventName) {
|
||||
var handler = function (e) {
|
||||
data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
|
||||
}
|
||||
|
||||
$(selector).on(eventName, handler)
|
||||
data.handlers.push(handler)
|
||||
|
||||
return {
|
||||
selector: selector,
|
||||
eventName: eventName,
|
||||
handler: handler,
|
||||
reset: function (){
|
||||
delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
args: function (selector, eventName) {
|
||||
var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
|
||||
|
||||
if (!actualArgs) {
|
||||
throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."
|
||||
}
|
||||
|
||||
return actualArgs
|
||||
},
|
||||
|
||||
wasTriggered: function (selector, eventName) {
|
||||
return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
|
||||
},
|
||||
|
||||
wasTriggeredWith: function (selector, eventName, expectedArgs, util, customEqualityTesters) {
|
||||
var actualArgs = jasmine.jQuery.events.args(selector, eventName).slice(1)
|
||||
|
||||
if (Object.prototype.toString.call(expectedArgs) !== '[object Array]')
|
||||
actualArgs = actualArgs[0]
|
||||
|
||||
return util.equals(expectedArgs, actualArgs, customEqualityTesters)
|
||||
},
|
||||
|
||||
wasPrevented: function (selector, eventName) {
|
||||
var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
|
||||
, e = args ? args[0] : undefined
|
||||
|
||||
return e && e.isDefaultPrevented()
|
||||
},
|
||||
|
||||
wasStopped: function (selector, eventName) {
|
||||
var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
|
||||
, e = args ? args[0] : undefined
|
||||
return e && e.isPropagationStopped()
|
||||
},
|
||||
|
||||
cleanUp: function () {
|
||||
data.spiedEvents = {}
|
||||
data.handlers = []
|
||||
}
|
||||
}
|
||||
|
||||
var hasProperty = function (actualValue, expectedValue) {
|
||||
if (expectedValue === undefined)
|
||||
return actualValue !== undefined
|
||||
|
||||
return actualValue === expectedValue
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
jasmine.addMatchers({
|
||||
toHaveClass: function () {
|
||||
return {
|
||||
compare: function (actual, className) {
|
||||
return { pass: $(actual).hasClass(className) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveCss: function () {
|
||||
return {
|
||||
compare: function (actual, css) {
|
||||
for (var prop in css){
|
||||
var value = css[prop]
|
||||
// see issue #147 on gh
|
||||
;if (value === 'auto' && $(actual).get(0).style[prop] === 'auto') continue
|
||||
if ($(actual).css(prop) !== value) return { pass: false }
|
||||
}
|
||||
return { pass: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeVisible: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).is(':visible') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeHidden: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).is(':hidden') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeSelected: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).is(':selected') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeChecked: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).is(':checked') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeEmpty: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).is(':empty') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeInDOM: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $.contains(document.documentElement, $(actual)[0]) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toExist: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
return { pass: $(actual).length }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveLength: function () {
|
||||
return {
|
||||
compare: function (actual, length) {
|
||||
return { pass: $(actual).length === length }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveAttr: function () {
|
||||
return {
|
||||
compare: function (actual, attributeName, expectedAttributeValue) {
|
||||
return { pass: hasProperty($(actual).attr(attributeName), expectedAttributeValue) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveProp: function () {
|
||||
return {
|
||||
compare: function (actual, propertyName, expectedPropertyValue) {
|
||||
return { pass: hasProperty($(actual).prop(propertyName), expectedPropertyValue) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveId: function () {
|
||||
return {
|
||||
compare: function (actual, id) {
|
||||
return { pass: $(actual).attr('id') == id }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveHtml: function () {
|
||||
return {
|
||||
compare: function (actual, html) {
|
||||
return { pass: $(actual).html() == jasmine.jQuery.browserTagCaseIndependentHtml(html) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toContainHtml: function () {
|
||||
return {
|
||||
compare: function (actual, html) {
|
||||
var actualHtml = $(actual).html()
|
||||
, expectedHtml = jasmine.jQuery.browserTagCaseIndependentHtml(html)
|
||||
|
||||
return { pass: (actualHtml.indexOf(expectedHtml) >= 0) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveText: function () {
|
||||
return {
|
||||
compare: function (actual, text) {
|
||||
var actualText = $(actual).text()
|
||||
var trimmedText = $.trim(actualText)
|
||||
|
||||
if (text && $.isFunction(text.test)) {
|
||||
return { pass: text.test(actualText) || text.test(trimmedText) }
|
||||
} else {
|
||||
return { pass: (actualText == text || trimmedText == text) }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toContainText: function () {
|
||||
return {
|
||||
compare: function (actual, text) {
|
||||
var trimmedText = $.trim($(actual).text())
|
||||
|
||||
if (text && $.isFunction(text.test)) {
|
||||
return { pass: text.test(trimmedText) }
|
||||
} else {
|
||||
return { pass: trimmedText.indexOf(text) != -1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveValue: function () {
|
||||
return {
|
||||
compare: function (actual, value) {
|
||||
return { pass: $(actual).val() === value }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveData: function () {
|
||||
return {
|
||||
compare: function (actual, key, expectedValue) {
|
||||
return { pass: hasProperty($(actual).data(key), expectedValue) }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toContainElement: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
if (window.debug) debugger
|
||||
return { pass: $(actual).find(selector).length }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeMatchedBy: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
return { pass: $(actual).filter(selector).length }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeDisabled: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
return { pass: $(actual).is(':disabled') }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toBeFocused: function (selector) {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
return { pass: $(actual)[0] === $(actual)[0].ownerDocument.activeElement }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHandle: function () {
|
||||
return {
|
||||
compare: function (actual, event) {
|
||||
var events = $._data($(actual).get(0), "events")
|
||||
|
||||
if (!events || !event || typeof event !== "string") {
|
||||
return { pass: false }
|
||||
}
|
||||
|
||||
var namespaces = event.split(".")
|
||||
, eventType = namespaces.shift()
|
||||
, sortedNamespaces = namespaces.slice(0).sort()
|
||||
, namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
|
||||
|
||||
if (events[eventType] && namespaces.length) {
|
||||
for (var i = 0; i < events[eventType].length; i++) {
|
||||
var namespace = events[eventType][i].namespace
|
||||
|
||||
if (namespaceRegExp.test(namespace))
|
||||
return { pass: true }
|
||||
}
|
||||
} else {
|
||||
return { pass: (events[eventType] && events[eventType].length > 0) }
|
||||
}
|
||||
|
||||
return { pass: false }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHandleWith: function () {
|
||||
return {
|
||||
compare: function (actual, eventName, eventHandler) {
|
||||
var normalizedEventName = eventName.split('.')[0]
|
||||
, stack = $._data($(actual).get(0), "events")[normalizedEventName]
|
||||
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
if (stack[i].handler == eventHandler) return { pass: true }
|
||||
}
|
||||
|
||||
return { pass: false }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenTriggeredOn: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
var result = { pass: jasmine.jQuery.events.wasTriggered(selector, actual) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + $(actual) + " not to have been triggered on " + selector :
|
||||
"Expected event " + $(actual) + " to have been triggered on " + selector
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenTriggered: function (){
|
||||
return {
|
||||
compare: function (actual) {
|
||||
var eventName = actual.eventName
|
||||
, selector = actual.selector
|
||||
, result = { pass: jasmine.jQuery.events.wasTriggered(selector, eventName) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + eventName + " not to have been triggered on " + selector :
|
||||
"Expected event " + eventName + " to have been triggered on " + selector
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenTriggeredOnAndWith: function (j$, customEqualityTesters) {
|
||||
return {
|
||||
compare: function (actual, selector, expectedArgs) {
|
||||
var wasTriggered = jasmine.jQuery.events.wasTriggered(selector, actual)
|
||||
, result = { pass: wasTriggered && jasmine.jQuery.events.wasTriggeredWith(selector, actual, expectedArgs, j$, customEqualityTesters) }
|
||||
|
||||
if (wasTriggered) {
|
||||
var actualArgs = jasmine.jQuery.events.args(selector, actual, expectedArgs)[1]
|
||||
result.message = result.pass ?
|
||||
"Expected event " + actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs) :
|
||||
"Expected event " + actual + " to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
|
||||
|
||||
} else {
|
||||
// todo check on this
|
||||
result.message = result.pass ?
|
||||
"Expected event " + actual + " not to have been triggered on " + selector :
|
||||
"Expected event " + actual + " to have been triggered on " + selector
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenPreventedOn: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
var result = { pass: jasmine.jQuery.events.wasPrevented(selector, actual) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + actual + " not to have been prevented on " + selector :
|
||||
"Expected event " + actual + " to have been prevented on " + selector
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenPrevented: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
var eventName = actual.eventName
|
||||
, selector = actual.selector
|
||||
, result = { pass: jasmine.jQuery.events.wasPrevented(selector, eventName) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + eventName + " not to have been prevented on " + selector :
|
||||
"Expected event " + eventName + " to have been prevented on " + selector
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenStoppedOn: function () {
|
||||
return {
|
||||
compare: function (actual, selector) {
|
||||
var result = { pass: jasmine.jQuery.events.wasStopped(selector, actual) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + actual + " not to have been stopped on " + selector :
|
||||
"Expected event " + actual + " to have been stopped on " + selector
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toHaveBeenStopped: function () {
|
||||
return {
|
||||
compare: function (actual) {
|
||||
var eventName = actual.eventName
|
||||
, selector = actual.selector
|
||||
, result = { pass: jasmine.jQuery.events.wasStopped(selector, eventName) }
|
||||
|
||||
result.message = result.pass ?
|
||||
"Expected event " + eventName + " not to have been stopped on " + selector :
|
||||
"Expected event " + eventName + " to have been stopped on " + selector
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
jasmine.getEnv().addCustomEqualityTester(function(a, b) {
|
||||
if (a && b) {
|
||||
if (a instanceof $ || jasmine.isDomNode(a)) {
|
||||
var $a = $(a)
|
||||
|
||||
if (b instanceof $)
|
||||
return $a.length == b.length && a.is(b)
|
||||
|
||||
return $a.is(b);
|
||||
}
|
||||
|
||||
if (b instanceof $ || jasmine.isDomNode(b)) {
|
||||
var $b = $(b)
|
||||
|
||||
if (a instanceof $)
|
||||
return a.length == $b.length && $b.is(a)
|
||||
|
||||
return $(b).is(a);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
jasmine.getEnv().addCustomEqualityTester(function (a, b) {
|
||||
if (a instanceof $ && b instanceof $ && a.size() == b.size())
|
||||
return a.is(b)
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.getFixtures().cleanUp()
|
||||
jasmine.getStyleFixtures().cleanUp()
|
||||
jasmine.jQuery.events.cleanUp()
|
||||
})
|
||||
|
||||
window.readFixtures = function () {
|
||||
return jasmine.getFixtures().proxyCallTo_('read', arguments)
|
||||
}
|
||||
|
||||
window.preloadFixtures = function () {
|
||||
jasmine.getFixtures().proxyCallTo_('preload', arguments)
|
||||
}
|
||||
|
||||
window.loadFixtures = function () {
|
||||
jasmine.getFixtures().proxyCallTo_('load', arguments)
|
||||
}
|
||||
|
||||
window.appendLoadFixtures = function () {
|
||||
jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
|
||||
}
|
||||
|
||||
window.setFixtures = function (html) {
|
||||
return jasmine.getFixtures().proxyCallTo_('set', arguments)
|
||||
}
|
||||
|
||||
window.appendSetFixtures = function () {
|
||||
jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
|
||||
}
|
||||
|
||||
window.sandbox = function (attributes) {
|
||||
return jasmine.getFixtures().sandbox(attributes)
|
||||
}
|
||||
|
||||
window.spyOnEvent = function (selector, eventName) {
|
||||
return jasmine.jQuery.events.spyOn(selector, eventName)
|
||||
}
|
||||
|
||||
window.preloadStyleFixtures = function () {
|
||||
jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
|
||||
}
|
||||
|
||||
window.loadStyleFixtures = function () {
|
||||
jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
|
||||
}
|
||||
|
||||
window.appendLoadStyleFixtures = function () {
|
||||
jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
|
||||
}
|
||||
|
||||
window.setStyleFixtures = function (html) {
|
||||
jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
|
||||
}
|
||||
|
||||
window.appendSetStyleFixtures = function (html) {
|
||||
jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
|
||||
}
|
||||
|
||||
window.loadJSONFixtures = function () {
|
||||
return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
|
||||
}
|
||||
|
||||
window.getJSONFixture = function (url) {
|
||||
return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
|
||||
}
|
||||
}(window, window.jasmine, window.jQuery);
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "jasmine-jquery"
|
||||
, "description": "jQuery matchers and fixture loader for Jasmine framework"
|
||||
, "version": "2.0.5"
|
||||
, "keywords": ["jasmine", "jquery"]
|
||||
, "homepage": "http://github.com/velesin/jasmine-jquery"
|
||||
, "author": {
|
||||
"name": "Travis Jeffery"
|
||||
, "email": "tj@travisjeffery.com"
|
||||
, "url": "travisjeffery.com"
|
||||
}
|
||||
, "scripts": { "test": "grunt test" }
|
||||
, "repository": {
|
||||
"type": "git"
|
||||
, "url": "https://github.com/velesin/jasmine-jquery.git"
|
||||
}
|
||||
, "bugs": {
|
||||
"url": "http://github.com/velesin/jasmine-jquery/issues"
|
||||
}
|
||||
, "license": "MIT"
|
||||
, "devDependencies": {
|
||||
"grunt": "~0.4.1"
|
||||
, "grunt-contrib-jshint": "~0.6.0"
|
||||
, "grunt-contrib-jasmine": "git://github.com/travisjeffery/grunt-contrib-jasmine#9d5874dd592cf41e8268918fe9baeb261afd75b2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div id="anchor_01"><script src="spec/fixtures/javascripts/jasmine_javascript_click.js"></script><script src="spec/fixtures/javascripts/jasmine_javascript_hover.js"></script></div>
|
||||
@@ -0,0 +1 @@
|
||||
<div id="anchor_01"><script type="text/template">{{name}</script></div>
|
||||
@@ -0,0 +1 @@
|
||||
$(function (){ $('#anchor_01').click(function(){ $(this).addClass('foo'); }) });
|
||||
@@ -0,0 +1 @@
|
||||
$(function (){ $('#anchor_01').on('hover', function(){ $(this).addClass('bar'); }) });
|
||||
@@ -0,0 +1 @@
|
||||
[1,2,3]
|
||||
@@ -0,0 +1 @@
|
||||
<div id="real_non_mocked_fixture"></div>
|
||||
@@ -0,0 +1 @@
|
||||
body { background: red; }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "jasmine",
|
||||
"homepage": "https://github.com/pivotal/jasmine",
|
||||
"version": "2.0.1",
|
||||
"_release": "2.0.1",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v2.0.1",
|
||||
"commit": "77c84a860c90d88bd13540a6b8794ee34bde44e5"
|
||||
},
|
||||
"_source": "git://github.com/pivotal/jasmine.git",
|
||||
"_target": ">=2",
|
||||
"_originalSource": "jasmine"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
.idea/
|
||||
.svn/
|
||||
.DS_Store
|
||||
site/
|
||||
.bundle/
|
||||
.pairs
|
||||
.rvmrc
|
||||
.ruby-gemset
|
||||
.ruby-version
|
||||
*.gem
|
||||
.bundle
|
||||
tags
|
||||
Gemfile.lock
|
||||
pkg/*
|
||||
.sass-cache/*
|
||||
src/html/.sass-cache/*
|
||||
node_modules/
|
||||
*.pyc
|
||||
sauce_connect.log
|
||||
*.swp
|
||||
build/
|
||||
*.egg-info/
|
||||
dist/*.tar.gz
|
||||
nbproject/
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "pages"]
|
||||
path = pages
|
||||
url = https://github.com/pivotal/jasmine.git
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"bitwise": true,
|
||||
"curly": true,
|
||||
"immed": true,
|
||||
"newcap": true,
|
||||
"trailing": true,
|
||||
"loopfunc": true,
|
||||
"quotmark": "single"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
dist/
|
||||
grunt/
|
||||
images/
|
||||
node_modules
|
||||
release_notes/
|
||||
spec/
|
||||
src/
|
||||
Gemfile
|
||||
Gemfile.lock
|
||||
Rakefile
|
||||
jasmine-core.gemspec
|
||||
.rspec
|
||||
.travis.yml
|
||||
.jshintrc
|
||||
.gitignore
|
||||
*.sh
|
||||
Gruntfile.js
|
||||
lib/jasmine-core/boot/
|
||||
lib/jasmine-core/boot.js
|
||||
lib/jasmine-core/spec
|
||||
lib/jasmine-core/*.css
|
||||
lib/jasmine-core/jasmine-html.js
|
||||
lib/jasmine-core/version.rb
|
||||
@@ -0,0 +1 @@
|
||||
--color
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
script: $TEST_COMMAND
|
||||
language: ruby
|
||||
cache: bundler
|
||||
rvm: 1.9.3
|
||||
env:
|
||||
global:
|
||||
- USE_SAUCE=true
|
||||
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
||||
- TEST_COMMAND="bash travis-core-script.sh"
|
||||
- JASMINE_BROWSER="firefox"
|
||||
- SAUCE_OS="Linux"
|
||||
- SAUCE_BROWSER_VERSION=''
|
||||
- secure: WSPWhlnC4mWSnSPquX+m1/BCu5ch5NygkaHuM2Nea7lD8oS3XLX8QncZZAsQ4lnNfqoDDuBOizG0AESiqNvE4y6x5qvLLTS6q+ce255ZEMZ71TBdZgDEEvGMEjOPPsVXiXyTQOP1lwOPlrbZvaPgWV7e11KIBab6DfFcQpnvDgo=
|
||||
- secure: SW7CJhZnwaNT749Gdnhvqb5rbXlAOsygUAzh9qhtyvbqXKkmJdBIEsO01YF6pbju1X2twE9JvWCOxeZju43NgQChJlPsGbjY2j3k/TdQeTAJesQe2K7ytwghunI30gjEovtRH0T3w1EmcKPH8yj5eBIcB2OYoJHx8KEC7e68q1g=
|
||||
matrix:
|
||||
include:
|
||||
- env:
|
||||
- USE_SAUCE=false
|
||||
- TEST_COMMAND="bash travis-node-script.sh"
|
||||
- env:
|
||||
- JASMINE_BROWSER="safari"
|
||||
- SAUCE_OS="OS X 10.8"
|
||||
- SAUCE_BROWSER_VERSION=6
|
||||
- env:
|
||||
- JASMINE_BROWSER="safari"
|
||||
- SAUCE_OS="OS X 10.6"
|
||||
- SAUCE_BROWSER_VERSION=5
|
||||
- env:
|
||||
- JASMINE_BROWSER="internet explorer"
|
||||
- SAUCE_OS="Windows 8"
|
||||
- SAUCE_BROWSER_VERSION=10
|
||||
- env:
|
||||
- JASMINE_BROWSER="internet explorer"
|
||||
- SAUCE_OS="Windows 7"
|
||||
- SAUCE_BROWSER_VERSION=9
|
||||
- env:
|
||||
- JASMINE_BROWSER="internet explorer"
|
||||
- SAUCE_OS="Windows 7"
|
||||
- SAUCE_BROWSER_VERSION=8
|
||||
- env:
|
||||
- JASMINE_BROWSER="chrome"
|
||||
- SAUCE_OS="Linux"
|
||||
- SAUCE_BROWSER_VERSION=''
|
||||
- env:
|
||||
- JASMINE_BROWSER="phantomjs"
|
||||
- USE_SAUCE=false
|
||||
- env:
|
||||
- USE_SAUCE=false
|
||||
- JASMINE_BROWSER="phantomjs"
|
||||
- TEST_COMMAND="bash travis-docs-script.sh"
|
||||
@@ -0,0 +1,121 @@
|
||||
# Developing for Jasmine Core
|
||||
|
||||
We welcome your contributions - Thanks for helping make Jasmine a better project for everyone. Please review the backlog and discussion lists (the main group - [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js) and the developer's list - [http://groups.google.com/group/jasmine-js-dev](http://groups.google.com/group/jasmine-js-dev)) before starting work - what you're looking for may already have been done. If it hasn't, the community can help make your contribution better.
|
||||
|
||||
## General Workflow
|
||||
|
||||
Please submit pull requests via feature branches using the semi-standard workflow of:
|
||||
|
||||
1. Fork it
|
||||
1. Clone your fork: (`git clone git@github.com:yourUserName/jasmine.git`)
|
||||
1. Change directory: (`cd jasmine`)
|
||||
1. Asign original repository to a remote named 'upstream': (`git remote add
|
||||
upstream https://github.com/pivotal/jasmine.git`)
|
||||
1. Pull in changes not present in your local repository: (`git fetch upstream`)
|
||||
1. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
1. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
1. Push to the branch (`git push origin my-new-feature`)
|
||||
1. Create new Pull Request
|
||||
|
||||
We favor pull requests with very small, single commits with a single purpose.
|
||||
|
||||
## Background
|
||||
|
||||
### Directory Structure
|
||||
|
||||
* `/src` contains all of the source files
|
||||
* `/src/console` - Node.js-specific files
|
||||
* `/src/core` - generic source files
|
||||
* `/src/html` - browser-specific files
|
||||
* `/spec` contains all of the tests
|
||||
* mirrors the source directory
|
||||
* there are some additional files
|
||||
* `/dist` contains the standalone distributions as zip files
|
||||
* `/lib` contains the generated files for distribution as the Jasmine Rubygem and the Python package
|
||||
|
||||
### Self-testing
|
||||
|
||||
Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `j$`. So there are two copies of the code loaded under test.
|
||||
|
||||
The tests should always use `j$` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa.
|
||||
|
||||
### `boot.js`
|
||||
|
||||
__This is new for Jasmine 2.0.__
|
||||
|
||||
This file does all of the setup necessary for Jasmine to work. It loads all of the code, creates an `Env`, attaches the global functions, and builds the reporter. It also sets up the execution of the `Env` - for browsers this is in `window.onload`. While the default in `lib` is appropriate for browsers, projects may wish to customize this file.
|
||||
|
||||
For example, for Jasmine development there is a different `dev_boot.js` for Jasmine development that does more work.
|
||||
|
||||
### Compatibility
|
||||
|
||||
* Browser Minimum
|
||||
* IE8
|
||||
* Firefox 3.x
|
||||
* Chrome ??
|
||||
* Safari 5
|
||||
|
||||
## Development
|
||||
|
||||
All source code belongs in `src/`. The `core/` directory contains the bulk of Jasmine's functionality. This code should remain browser- and environment-agnostic. If your feature or fix cannot be, as mentioned above, please degrade gracefully. Any code that should only be in a non-browser environment should live in `src/console/`. Any code that depends on a browser (specifically, it expects `window` to be the global or `document` is present) should live in `src/html/`.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
Jasmine Core relies on Ruby and Node.js.
|
||||
|
||||
To install the Ruby dependencies, you will need Ruby, Rubygems, and Bundler available. Then:
|
||||
|
||||
$ bundle
|
||||
|
||||
...will install all of the Ruby dependencies.
|
||||
|
||||
To install the Node dependencies, you will need Node.js, Npm, and [Grunt](http://gruntjs.com/), the [grunt-cli](https://github.com/gruntjs/grunt-cli) and ensure that `grunt` is on your path.
|
||||
|
||||
$ npm install --local
|
||||
|
||||
...will install all of the node modules locally. If when you run
|
||||
|
||||
$ grunt
|
||||
|
||||
...you see that JSHint runs your system is ready.
|
||||
|
||||
### How to write new Jasmine code
|
||||
|
||||
Or, How to make a successful pull request
|
||||
|
||||
* _Do not change the public interface_. Lots of projects depend on Jasmine and if you aren't careful you'll break them
|
||||
* _Be environment agnostic_ - server-side developers are just as important as browser developers
|
||||
* _Be browser agnostic_ - if you must rely on browser-specific functionality, please write it in a way that degrades gracefully
|
||||
* _Write specs_ - Jasmine's a testing framework; don't add functionality without test-driving it
|
||||
* _Write code in the style of the rest of the repo_ - Jasmine should look like a cohesive whole
|
||||
* _Ensure the *entire* test suite is green_ in all the big browsers, Node, and JSHint - your contribution shouldn't break Jasmine for other users
|
||||
|
||||
Follow these tips and your pull request, patch, or suggestion is much more likely to be integrated.
|
||||
|
||||
### Running Specs
|
||||
|
||||
Jasmine uses the [Jasmine Ruby gem](http://github.com/pivotal/jasmine-gem) to test itself in browser.
|
||||
|
||||
$ rake jasmine
|
||||
|
||||
...and then visit `http://localhost:8888` to run specs.
|
||||
|
||||
Jasmine uses Node.js with a custom runner to test outside of a browser.
|
||||
|
||||
$ grunt execSpecsInNode
|
||||
|
||||
...and then the results will print to the console. All specs run except those that expect a browser (the specs in `spec/html` are ignored).
|
||||
|
||||
## Before Committing or Submitting a Pull Request
|
||||
|
||||
1. Ensure all specs are green in browser *and* node
|
||||
1. Ensure JSHint is green with `grunt jsHint`
|
||||
1. Build `jasmine.js` with `grunt buildDistribution` and run all specs again - this ensures that your changes self-test well
|
||||
|
||||
## Submitting a Pull Request
|
||||
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
|
||||
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches.
|
||||
1. When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master.
|
||||
|
||||
Note that we use Travis for Continuous Integration. We only accept green pull requests.
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# (Vague) Jasmine 2.0 Goals/(Guidelines)
|
||||
|
||||
1. No globals!
|
||||
* jasmine library is entirely inside `jasmine` namespace
|
||||
* globals required for backwards compatibility should be added in `boot.js` (EG, var describe = jasmine.getCurrentEnv().describe lives in boot.js)
|
||||
1. Don't use properties as getters. Use methods.
|
||||
* Properties aren't encapsulated -- can be mutated, unsafe.
|
||||
1. Reporters get data objects (no methods).
|
||||
* easier to refactor as needed
|
||||
1. More unit tests - fewer nasty integration tests
|
||||
|
||||
## Remaining non-story-able work:
|
||||
* Make a `TODO` list
|
||||
|
||||
### Hard
|
||||
* Finish killing Globals
|
||||
* Guidelines:
|
||||
* New objects can have constructors on `jasmine`
|
||||
* Top level functions can live on `jasmine`
|
||||
* Top level (i.e., any `jasmine` property) should only be referenced inside the `Env` constructor
|
||||
* should better allow any object to get jasmine code (Node-friendly)
|
||||
* review everything in base.js
|
||||
* Remove isA functions:
|
||||
* isArray_ - used in matchers and spies
|
||||
* isString_
|
||||
* isDOMNode_
|
||||
* isA_
|
||||
* unimplementedMethod_, used by PrettyPrinter
|
||||
* jasmine.util should be util closure inside of env or something
|
||||
* argsToArray is used for Spies and matching (and can be replaced)
|
||||
* inherit is only for PrettyPrinter now
|
||||
* formatException is used only inside Env/spec
|
||||
* htmlEscape is for messages in matchers - should this be HTML at all?
|
||||
* Pretty printing
|
||||
* move away from pretty printer and to a JSON.stringify implementation?
|
||||
* jasmineToString vs. custom toString ?
|
||||
|
||||
### Easy
|
||||
|
||||
* unify params to ctors: options vs. attrs.
|
||||
* This will be a lot of the TODOs, but clean up & simplify Env.js (is this a 2.1 task?)
|
||||
|
||||
### DONE
|
||||
* Matchers improvements
|
||||
* unit testable DONE
|
||||
* better equality (from Underscore) DONE
|
||||
* addCustomMatchers doesn't explode stack DONE
|
||||
* refactor equals function so that it just loops & recurses over a list of fns (custom and built-in) - 2.1? (Tracker story)
|
||||
* Spies
|
||||
* break these out into their own tests/file DONE
|
||||
|
||||
|
||||
## Other Topics
|
||||
|
||||
* Docs
|
||||
* Docco has gone over well. Should we annotate all the sources and then have Pages be more complex, having tutorials and annotated source like Backbone? Are we small enough?
|
||||
* Need examples for:
|
||||
* How to build a Custom Matcher
|
||||
* How to add a custom equality tester
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
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
|
||||
|
||||
gemspec
|
||||
|
||||
gem "anchorman"
|
||||
@@ -0,0 +1,53 @@
|
||||
module.exports = function(grunt) {
|
||||
var pkg = require("./package.json");
|
||||
global.jasmineVersion = pkg.version;
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: pkg,
|
||||
jshint: require('./grunt/config/jshint.js'),
|
||||
concat: require('./grunt/config/concat.js'),
|
||||
compass: require('./grunt/config/compass.js'),
|
||||
compress: require('./grunt/config/compress.js')
|
||||
});
|
||||
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
grunt.loadTasks('grunt/tasks');
|
||||
|
||||
grunt.registerTask('default', ['jshint:all']);
|
||||
|
||||
var version = require('./grunt/tasks/version.js');
|
||||
var standaloneBuilder = require('./grunt/tasks/build_standalone.js');
|
||||
|
||||
grunt.registerTask('build:copyVersionToGem',
|
||||
"Propagates the version from package.json to version.rb",
|
||||
version.copyToGem);
|
||||
|
||||
grunt.registerTask('buildDistribution',
|
||||
'Builds and lints jasmine.js, jasmine-html.js, jasmine.css',
|
||||
[
|
||||
'compass',
|
||||
'jshint:beforeConcat',
|
||||
'concat',
|
||||
'jshint:afterConcat',
|
||||
'build:copyVersionToGem'
|
||||
]
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("execSpecsInNode:performance",
|
||||
"Run Jasmine performance specs in Node.js",
|
||||
function() {
|
||||
require("shelljs").exec("node_modules/.bin/jasmine JASMINE_CONFIG_PATH=spec/support/jasmine-performance.json");
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
recursive-include . *.py
|
||||
include lib/jasmine-core/*.js
|
||||
include lib/jasmine-core/*.css
|
||||
include images/*.png
|
||||
include package.json
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,64 @@
|
||||
<a name="README">[<img src="https://rawgithub.com/pivotal/jasmine/master/images/jasmine-horizontal.svg" width="400px" />](http://jasmine.github.io)</a>
|
||||
|
||||
[](https://travis-ci.org/pivotal/jasmine) [](https://codeclimate.com/github/pivotal/jasmine)
|
||||
|
||||
=======
|
||||
|
||||
**A JavaScript Testing Framework**
|
||||
|
||||
Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on browsers, DOM, or any JavaScript framework. Thus it's suited for websites, [Node.js](http://nodejs.org) projects, or anywhere that JavaScript can run.
|
||||
|
||||
Documentation & guides live here: [http://jasmine.github.io](http://jasmine.github.io/)
|
||||
For a quick start guide of Jasmine 2.0, see the beginning of [http://jasmine.github.io/2.0/introduction.html](http://jasmine.github.io/2.0/introduction.html)
|
||||
|
||||
Upgrading from Jasmine 1.x? Check out the [2.0 release notes](https://github.com/pivotal/jasmine/blob/v2.0.0/release_notes/20.md) for a list of what's new (including breaking interface changes).
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read the [contributors' guide](https://github.com/pivotal/jasmine/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Installation
|
||||
|
||||
To install Jasmine on your local box:
|
||||
|
||||
* Clone Jasmine - `git clone https://github.com/pivotal/jasmine.git`
|
||||
* Create a Jasmine directory in your project - `mkdir my-project/jasmine`
|
||||
* Move latest dist to your project directory - `mv jasmine/dist/jasmine-standalone-2.0.0.zip my-project/jasmine`
|
||||
* Change directory - `cd my-project/jasmine`
|
||||
* Unzip the dist - `unzip jasmine-standalone-2.0.0.zip`
|
||||
|
||||
Add the following to your HTML file:
|
||||
|
||||
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-2.0.0/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-2.0.0/jasmine.css">
|
||||
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/boot.js"></script>
|
||||
|
||||
For the Jasmine Ruby Gem:<br>
|
||||
[https://github.com/pivotal/jasmine-gem](https://github.com/pivotal/jasmine-gem)
|
||||
|
||||
For the Jasmine Python Egg:<br>
|
||||
[https://github.com/pivotal/jasmine-py](https://github.com/pivotal/jasmine-py)
|
||||
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
* Search past discussions: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js)
|
||||
* Send an email to the list: [jasmine-js@googlegroups.com](mailto:jasmine-js@googlegroups.com)
|
||||
* View the project backlog at Pivotal Tracker: [http://www.pivotaltracker.com/projects/10606](http://www.pivotaltracker.com/projects/10606)
|
||||
* Follow us on Twitter: [@JasmineBDD](http://twitter.com/JasmineBDD)
|
||||
|
||||
## 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
|
||||
|
||||
### Maintainers Emeritus
|
||||
|
||||
* [Christian Williams](mailto:antixian666@gmail.com), Square
|
||||
|
||||
Copyright (c) 2008-2014 Pivotal Labs. This software is licensed under the MIT License.
|
||||
@@ -0,0 +1,66 @@
|
||||
# How to work on a Jasmine Release
|
||||
|
||||
## Development
|
||||
___Jasmine Core Maintainers Only___
|
||||
|
||||
Follow the instructions in `CONTRIBUTING.md` during development.
|
||||
|
||||
### Git Rules
|
||||
|
||||
Please work on feature branches.
|
||||
|
||||
Please attempt to keep commits to `master` small, but cohesive. If a feature is contained in a bunch of small commits (e.g., it has several wip commits or small work), please squash them when merging back to `master`.
|
||||
|
||||
### Version
|
||||
|
||||
We attempt to stick to [Semantic Versioning](http://semver.org/). Most of the time, development should be against a new minor version - fixing bugs and adding new features that are backwards compatible.
|
||||
|
||||
The current version lives in the file `/package.json`. This file should be set to the version that is _currently_ under development. That is, if version 1.0.0 is the current release then version should be incremented say, to 1.1.0.
|
||||
|
||||
This version is used by both `jasmine.js` and the `jasmine-core` Ruby gem.
|
||||
|
||||
Note that Jasmine should *not* use the "patch" version number. Let downstream projects rev their patch versions as needed, keeping their major and minor version numbers in sync with Jasmine core.
|
||||
|
||||
### Update the Github Pages (as needed)
|
||||
|
||||
___Note: This is going to change right after 2.0___
|
||||
|
||||
Github pages have to exist in a branch called `gh-pages` in order for their app to serve them. This repo adds that branch as a submodule under the `pages` directory. This is a bit of a hack, but it allows us to work with the pages and the source at the same time and with one set of rake tasks.
|
||||
|
||||
If you want to submit changes to this repo and aren't a Pivotal Labs employee, you can fork and work in the `gh-pages` branch. You won't be able to edit the pages in the submodule off of master.
|
||||
|
||||
## Release
|
||||
|
||||
When ready to release - specs are all green and the stories are done:
|
||||
|
||||
1. Update the release notes in `release_notes` - use the Anchorman gem to generate the markdown file and edit accordingly
|
||||
1. Update the version in `package.json` to a release candidate
|
||||
1. Update any links or top-level landing page for the Github Pages
|
||||
|
||||
### Build standalone distribution
|
||||
|
||||
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...
|
||||
|
||||
### Release the Python egg
|
||||
|
||||
1. `python setup.py register sdist upload` You will need pypi credentials to upload the egg.
|
||||
|
||||
### Release the Ruby gem
|
||||
|
||||
1. Copy version to the Ruby gem with `grunt build:copyVersionToGem`
|
||||
1. __NOTE__: You will likely need to point to a local jasmine gem in order to run tests locally. _Do not_ push this version of the Gemfile.
|
||||
1. __NOTE__: You will likely need to push a new jasmine gem with a dependent version right after this release.
|
||||
1. Push these changes to GitHub and verify that this SHA is green
|
||||
1. `rake release` - tags the repo with the version, builds the `jasmine-core` gem, pushes the gem to Rubygems.org. In order to release you will have to ensure you have rubygems creds locally.
|
||||
|
||||
### Finally
|
||||
|
||||
1. Visit the [Releases page for Jasmine](https://github.com/pivotal/jasmine/releases), find the tag just pushed.
|
||||
1. Paste in a link to the correct release notes for this release. The link should reference the blob and tag correctly, and the markdown file for the notes.
|
||||
1. If it is a pre-release, mark it as such.
|
||||
1. Attach the standalone zipfile
|
||||
|
||||
|
||||
There should be a post to Pivotal Labs blog and a tweet to that link.
|
||||
@@ -0,0 +1,18 @@
|
||||
require "bundler"
|
||||
Bundler::GemHelper.install_tasks
|
||||
require "json"
|
||||
require "jasmine"
|
||||
unless ENV["JASMINE_BROWSER"] == 'phantomjs'
|
||||
require "jasmine_selenium_runner"
|
||||
end
|
||||
load "jasmine/tasks/jasmine.rake"
|
||||
|
||||
namespace :jasmine do
|
||||
task :set_env do
|
||||
ENV['JASMINE_CONFIG_PATH'] ||= 'spec/support/jasmine.yml'
|
||||
end
|
||||
end
|
||||
|
||||
task "jasmine:configure" => "jasmine:set_env"
|
||||
|
||||
task :default => "jasmine:ci"
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
jasmine: {
|
||||
options: {
|
||||
cssDir: 'lib/jasmine-core/',
|
||||
sassDir: 'src/html',
|
||||
outputStyle: 'compact',
|
||||
noLineComments: true,
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
var standaloneLibDir = "lib/jasmine-" + jasmineVersion;
|
||||
|
||||
function root(path) { return "./" + path; }
|
||||
function libJasmineCore(path) { return root("lib/jasmine-core/" + path); }
|
||||
function libConsole() { return "lib/console/" }
|
||||
function dist(path) { return root("dist/" + path); }
|
||||
|
||||
module.exports = {
|
||||
standalone: {
|
||||
options: {
|
||||
archive: root("dist/jasmine-standalone-" + global.jasmineVersion + ".zip")
|
||||
},
|
||||
|
||||
files: [
|
||||
{ src: [ root("MIT.LICENSE") ] },
|
||||
{
|
||||
src: [ "jasmine_favicon.png"],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: root("images")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"jasmine.js",
|
||||
"jasmine-html.js",
|
||||
"jasmine.css"
|
||||
],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: libJasmineCore("")
|
||||
},
|
||||
{
|
||||
src: [
|
||||
"console.js"
|
||||
],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: libConsole()
|
||||
},
|
||||
{
|
||||
src: [ "boot.js" ],
|
||||
dest: standaloneLibDir,
|
||||
expand: true,
|
||||
cwd: libJasmineCore("boot")
|
||||
},
|
||||
{
|
||||
src: [ "SpecRunner.html" ],
|
||||
dest: root(""),
|
||||
expand: true,
|
||||
cwd: dist("tmp")
|
||||
},
|
||||
{
|
||||
src: [ "*.js" ],
|
||||
dest: "src",
|
||||
expand: true,
|
||||
cwd: libJasmineCore("example/src/")
|
||||
},
|
||||
{
|
||||
src: [ "*.js" ],
|
||||
dest: "spec",
|
||||
expand: true,
|
||||
cwd: libJasmineCore("example/spec/")
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
var grunt = require('grunt');
|
||||
|
||||
function license() {
|
||||
var currentYear = "" + new Date(Date.now()).getFullYear();
|
||||
|
||||
return grunt.template.process(
|
||||
grunt.file.read("grunt/templates/licenseBanner.js.jst"),
|
||||
{ data: { currentYear: currentYear}});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'jasmine-html': {
|
||||
src: [
|
||||
'src/html/requireHtml.js',
|
||||
'src/html/HtmlReporter.js',
|
||||
'src/html/HtmlSpecFilter.js',
|
||||
'src/html/ResultsNode.js',
|
||||
'src/html/QueryString.js'
|
||||
],
|
||||
dest: 'lib/jasmine-core/jasmine-html.js'
|
||||
},
|
||||
jasmine: {
|
||||
src: [
|
||||
'src/core/requireCore.js',
|
||||
'src/core/matchers/requireMatchers.js',
|
||||
'src/core/base.js',
|
||||
'src/core/util.js',
|
||||
'src/core/Spec.js',
|
||||
'src/core/Env.js',
|
||||
'src/core/JsApiReporter.js',
|
||||
'src/core/PrettyPrinter',
|
||||
'src/core/Suite',
|
||||
'src/core/**/*.js',
|
||||
'src/version.js'
|
||||
],
|
||||
dest: 'lib/jasmine-core/jasmine.js'
|
||||
},
|
||||
boot: {
|
||||
src: ['lib/jasmine-core/boot/boot.js'],
|
||||
dest: 'lib/jasmine-core/boot.js'
|
||||
},
|
||||
nodeBoot: {
|
||||
src: ['lib/jasmine-core/boot/node_boot.js'],
|
||||
dest: 'lib/jasmine-core/node_boot.js'
|
||||
},
|
||||
console: {
|
||||
src: [
|
||||
'src/console/requireConsole.js',
|
||||
'src/console/ConsoleReporter.js'
|
||||
],
|
||||
dest: 'lib/console/console.js'
|
||||
},
|
||||
options: {
|
||||
banner: license(),
|
||||
process: {
|
||||
data: {
|
||||
version: global.jasmineVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
beforeConcat: ['src/**/*.js'],
|
||||
afterConcat: [
|
||||
'lib/jasmine-core/jasmine-html.js',
|
||||
'lib/jasmine-core/jasmine.js'
|
||||
],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
all: ['src/**/*.js']
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
var grunt = require("grunt");
|
||||
|
||||
function standaloneTmpDir(path) { return "dist/tmp/" + path; }
|
||||
|
||||
grunt.registerTask("build:compileSpecRunner",
|
||||
"Processes the spec runner template and writes to a tmp file",
|
||||
function() {
|
||||
var runnerHtml = grunt.template.process(
|
||||
grunt.file.read("grunt/templates/SpecRunner.html.jst"),
|
||||
{ data: { jasmineVersion: global.jasmineVersion }});
|
||||
|
||||
grunt.file.write(standaloneTmpDir("SpecRunner.html"), runnerHtml);
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("build:cleanSpecRunner",
|
||||
"Deletes the tmp spec runner file",
|
||||
function() {
|
||||
grunt.file.delete(standaloneTmpDir(""));
|
||||
}
|
||||
);
|
||||
|
||||
grunt.registerTask("buildStandaloneDist",
|
||||
"Builds a standalone distribution",
|
||||
[
|
||||
"buildDistribution",
|
||||
"build:compileSpecRunner",
|
||||
"compress:standalone",
|
||||
"build:cleanSpecRunner"
|
||||
]
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
var grunt = require("grunt");
|
||||
|
||||
function gemLib(path) { return './lib/jasmine-core/' + path; }
|
||||
function nodeToRuby(version) { return version.replace('-', '.'); }
|
||||
|
||||
module.exports = {
|
||||
copyToGem: function() {
|
||||
var versionRb = grunt.template.process(
|
||||
grunt.file.read("grunt/templates/version.rb.jst"),
|
||||
{ data: { jasmineVersion: nodeToRuby(global.jasmineVersion) }});
|
||||
|
||||
grunt.file.write(gemLib("version.rb"), versionRb);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; 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">
|
||||
|
||||
<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>
|
||||
|
||||
<!-- include source files here... -->
|
||||
<script type="text/javascript" src="src/Player.js"></script>
|
||||
<script type="text/javascript" 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>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright (c) 2008-<%= currentYear %> Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated
|
||||
# by a grunt task when the standalone release is built.
|
||||
#
|
||||
module Jasmine
|
||||
module Core
|
||||
VERSION = "<%= jasmineVersion %>"
|
||||
end
|
||||
end
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="681.96252"
|
||||
height="187.5"
|
||||
id="svg2"
|
||||
xml:space="preserve"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath18"><path
|
||||
d="M 0,1500 0,0 l 5455.74,0 0,1500 L 0,1500 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path20" /></clipPath></defs><g
|
||||
transform="matrix(1.25,0,0,-1.25,0,187.5)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1,0.1)"
|
||||
id="g12"><g
|
||||
id="g14"><g
|
||||
clip-path="url(#clipPath18)"
|
||||
id="g16"><path
|
||||
d="m 1544,599.434 c 0.92,-40.352 25.68,-81.602 71.53,-81.602 27.51,0 47.68,12.832 61.44,35.754 12.83,22.93 12.83,56.852 12.83,82.527 l 0,329.184 -71.52,0 0,104.543 266.83,0 0,-104.543 -70.6,0 0,-344.77 c 0,-58.691 -3.68,-104.531 -44.93,-152.218 -36.68,-42.18 -96.28,-66.02 -153.14,-66.02 -117.37,0 -207.24,77.941 -202.64,197.145 l 130.2,0"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path22"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2301.4,662.695 c 0,80.703 -66.94,145.813 -147.63,145.813 -83.44,0 -147.63,-68.781 -147.63,-151.301 0,-79.785 66.94,-145.801 145.8,-145.801 84.35,0 149.46,67.852 149.46,151.289 z m -1.83,-181.547 c -35.77,-54.097 -93.53,-78.859 -157.72,-78.859 -140.3,0 -251.24,116.449 -251.24,254.918 0,142.129 113.7,260.41 256.74,260.41 63.27,0 118.29,-29.336 152.22,-82.523 l 0,69.687 175.14,0 0,-104.527 -61.44,0 0,-280.598 61.44,0 0,-104.527 -175.14,0 0,66.019"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path24"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2622.33,557.258 c 3.67,-44.016 33.01,-73.348 78.86,-73.348 33.93,0 66.93,23.824 66.93,60.504 0,48.606 -45.84,56.856 -83.44,66.941 -85.28,22.004 -178.81,48.606 -178.81,155.879 0,93.536 78.86,147.633 165.98,147.633 44,0 83.43,-9.176 110.94,-44.008 l 0,33.922 82.53,0 0,-132.965 -108.21,0 c -1.83,34.856 -28.42,57.774 -63.26,57.774 -30.26,0 -62.35,-17.422 -62.35,-51.348 0,-45.847 44.93,-55.93 80.69,-64.18 88.02,-20.175 182.47,-47.695 182.47,-157.734 0,-99.027 -83.44,-154.039 -175.13,-154.039 -49.53,0 -94.46,15.582 -126.55,53.18 l 0,-40.34 -85.27,0 0,142.129 114.62,0"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path26"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 2988.18,800.254 -63.26,0 0,104.527 165.05,0 0,-73.355 c 31.18,51.347 78.86,85.277 141.21,85.277 67.85,0 124.71,-41.258 152.21,-102.699 26.6,62.351 92.62,102.699 160.47,102.699 53.19,0 105.46,-22 141.21,-62.351 38.52,-44.938 38.52,-93.532 38.52,-149.457 l 0,-185.239 63.27,0 0,-104.527 -238.42,0 0,104.527 63.28,0 0,157.715 c 0,32.102 0,60.527 -14.67,88.957 -18.34,26.582 -48.61,40.344 -79.77,40.344 -30.26,0 -63.28,-12.844 -82.53,-36.672 -22.93,-29.355 -22.93,-56.863 -22.93,-92.629 l 0,-157.715 63.27,0 0,-104.527 -238.41,0 0,104.527 63.28,0 0,150.383 c 0,29.348 0,66.023 -14.67,91.699 -15.59,29.336 -47.69,44.934 -80.7,44.934 -31.18,0 -57.77,-11.008 -77.94,-35.774 -24.77,-30.253 -26.6,-62.343 -26.6,-99.941 l 0,-151.301 63.27,0 0,-104.527 -238.4,0 0,104.527 63.26,0 0,280.598"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path28"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 3998.66,951.547 -111.87,0 0,118.293 111.87,0 0,-118.293 z m 0,-431.891 63.27,0 0,-104.527 -239.33,0 0,104.527 64.19,0 0,280.598 -63.27,0 0,104.527 175.14,0 0,-385.125"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path30"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 4159.12,800.254 -63.27,0 0,104.527 175.14,0 0,-69.687 c 29.35,54.101 84.36,80.699 144.87,80.699 53.19,0 105.45,-22.016 141.22,-60.527 40.34,-44.934 41.26,-88.032 41.26,-143.957 l 0,-191.653 63.27,0 0,-104.527 -238.4,0 0,104.527 63.26,0 0,158.637 c 0,30.262 0,61.434 -19.26,88.035 -20.17,26.582 -53.18,39.414 -86.19,39.414 -33.93,0 -68.77,-13.75 -88.94,-41.25 -21.09,-27.5 -21.09,-69.687 -21.09,-102.707 l 0,-142.129 63.26,0 0,-104.527 -238.4,0 0,104.527 63.27,0 0,280.598"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path32"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 5082.48,703.965 c -19.24,70.605 -81.6,115.547 -154.04,115.547 -66.04,0 -129.3,-51.348 -143.05,-115.547 l 297.09,0 z m 85.27,-144.883 c -38.51,-93.523 -129.27,-156.793 -231.05,-156.793 -143.07,0 -257.68,111.871 -257.68,255.836 0,144.883 109.12,261.328 254.91,261.328 67.87,0 135.72,-30.258 183.39,-78.863 48.62,-51.344 68.79,-113.695 68.79,-183.383 l -3.67,-39.434 -396.13,0 c 14.67,-67.863 77.03,-117.363 146.72,-117.363 48.59,0 90.76,18.328 118.28,58.672 l 116.44,0"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path34"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 690.895,850.703 90.75,0 22.543,31.035 0,243.122 -135.829,0 0,-243.141 22.536,-31.016"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path36"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 632.395,742.258 28.039,86.304 -22.551,31.04 -231.223,75.128 -41.976,-129.183 231.257,-75.137 36.454,11.848"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path38"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 717.449,653.105 -73.41,53.36 -36.488,-11.875 -142.903,-196.692 109.883,-79.828 142.918,196.703 0,38.332"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path40"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 828.52,706.465 -73.426,-53.34 0.011,-38.359 L 898.004,418.07 1007.9,497.898 864.973,694.609 828.52,706.465"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path42"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 812.086,828.586 28.055,-86.32 36.484,-11.836 231.225,75.117 -41.97,129.183 -231.239,-75.14 -22.555,-31.004"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path44"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 736.301,1335.88 c -323.047,0 -585.875,-262.78 -585.875,-585.782 0,-323.118 262.828,-585.977 585.875,-585.977 323.019,0 585.809,262.859 585.809,585.977 0,323.002 -262.79,585.782 -585.809,585.782 l 0,0 z m 0,-118.61 c 257.972,0 467.189,-209.13 467.189,-467.172 0,-258.129 -209.217,-467.348 -467.189,-467.348 -258.074,0 -467.254,209.219 -467.254,467.348 0,258.042 209.18,467.172 467.254,467.172"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path46"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 1091.13,619.883 -175.771,57.121 11.629,35.808 175.762,-57.121 -11.62,-35.808"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path48"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="M 866.957,902.074 836.5,924.199 945.121,1073.73 975.586,1051.61 866.957,902.074"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path50"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="M 607.465,903.445 498.855,1052.97 529.32,1075.1 637.93,925.566 607.465,903.445"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path52"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 380.688,622.129 -11.626,35.801 175.758,57.09 11.621,-35.801 -175.753,-57.09"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path54"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
||||
d="m 716.289,376.59 37.6406,0 0,184.816 -37.6406,0 0,-184.816 z"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path56"
|
||||
style="fill:#8a4182;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,23 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
$:.push File.expand_path("../lib", __FILE__)
|
||||
require "jasmine-core/version"
|
||||
|
||||
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.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}
|
||||
s.homepage = "http://pivotal.github.com/jasmine"
|
||||
s.rubyforge_project = "jasmine-core"
|
||||
s.license = "MIT"
|
||||
|
||||
s.files = Dir.glob("./lib/**/*") + Dir.glob("./lib/jasmine-core/spec/**/*.js")
|
||||
s.require_paths = ["lib"]
|
||||
s.add_development_dependency "rake"
|
||||
s.add_development_dependency "sauce-connect"
|
||||
s.add_development_dependency "compass"
|
||||
s.add_development_dependency "jasmine_selenium_runner", ">= 0.2.0"
|
||||
end
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
function getJasmineRequireObj() {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
return exports;
|
||||
} else {
|
||||
window.jasmineRequire = window.jasmineRequire || {};
|
||||
return window.jasmineRequire;
|
||||
}
|
||||
}
|
||||
|
||||
getJasmineRequireObj().console = function(jRequire, j$) {
|
||||
j$.ConsoleReporter = jRequire.ConsoleReporter();
|
||||
};
|
||||
|
||||
getJasmineRequireObj().ConsoleReporter = function() {
|
||||
|
||||
var noopTimer = {
|
||||
start: function(){},
|
||||
elapsed: function(){ return 0; }
|
||||
};
|
||||
|
||||
function ConsoleReporter(options) {
|
||||
var print = options.print,
|
||||
showColors = options.showColors || false,
|
||||
onComplete = options.onComplete || function() {},
|
||||
timer = options.timer || noopTimer,
|
||||
specCount,
|
||||
failureCount,
|
||||
failedSpecs = [],
|
||||
pendingCount,
|
||||
ansi = {
|
||||
green: '\x1B[32m',
|
||||
red: '\x1B[31m',
|
||||
yellow: '\x1B[33m',
|
||||
none: '\x1B[0m'
|
||||
};
|
||||
|
||||
this.jasmineStarted = function() {
|
||||
specCount = 0;
|
||||
failureCount = 0;
|
||||
pendingCount = 0;
|
||||
print('Started');
|
||||
printNewline();
|
||||
timer.start();
|
||||
};
|
||||
|
||||
this.jasmineDone = function() {
|
||||
printNewline();
|
||||
for (var i = 0; i < failedSpecs.length; i++) {
|
||||
specFailureDetails(failedSpecs[i]);
|
||||
}
|
||||
|
||||
if(specCount > 0) {
|
||||
printNewline();
|
||||
|
||||
var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' +
|
||||
failureCount + ' ' + plural('failure', failureCount);
|
||||
|
||||
if (pendingCount) {
|
||||
specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount);
|
||||
}
|
||||
|
||||
print(specCounts);
|
||||
} else {
|
||||
print('No specs found');
|
||||
}
|
||||
|
||||
printNewline();
|
||||
var seconds = timer.elapsed() / 1000;
|
||||
print('Finished in ' + seconds + ' ' + plural('second', seconds));
|
||||
|
||||
printNewline();
|
||||
|
||||
onComplete(failureCount === 0);
|
||||
};
|
||||
|
||||
this.specDone = function(result) {
|
||||
specCount++;
|
||||
|
||||
if (result.status == 'pending') {
|
||||
pendingCount++;
|
||||
print(colored('yellow', '*'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status == 'passed') {
|
||||
print(colored('green', '.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status == 'failed') {
|
||||
failureCount++;
|
||||
failedSpecs.push(result);
|
||||
print(colored('red', 'F'));
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function printNewline() {
|
||||
print('\n');
|
||||
}
|
||||
|
||||
function colored(color, str) {
|
||||
return showColors ? (ansi[color] + str + ansi.none) : str;
|
||||
}
|
||||
|
||||
function plural(str, count) {
|
||||
return count == 1 ? str : str + 's';
|
||||
}
|
||||
|
||||
function repeat(thing, times) {
|
||||
var arr = [];
|
||||
for (var i = 0; i < times; i++) {
|
||||
arr.push(thing);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function indent(str, spaces) {
|
||||
var lines = (str || '').split('\n');
|
||||
var newArr = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
newArr.push(repeat(' ', spaces).join('') + lines[i]);
|
||||
}
|
||||
return newArr.join('\n');
|
||||
}
|
||||
|
||||
function specFailureDetails(result) {
|
||||
printNewline();
|
||||
print(result.fullName);
|
||||
|
||||
for (var i = 0; i < result.failedExpectations.length; i++) {
|
||||
var failedExpectation = result.failedExpectations[i];
|
||||
printNewline();
|
||||
print(indent(failedExpectation.stack, 2));
|
||||
}
|
||||
|
||||
printNewline();
|
||||
}
|
||||
}
|
||||
|
||||
return ConsoleReporter;
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
module.exports = require("./jasmine-core/jasmine.js");
|
||||
module.exports.boot = require('./jasmine-core/node_boot.js');
|
||||
@@ -0,0 +1,53 @@
|
||||
module Jasmine
|
||||
module Core
|
||||
class << self
|
||||
def path
|
||||
File.join(File.dirname(__FILE__), "jasmine-core")
|
||||
end
|
||||
|
||||
def js_files
|
||||
(["jasmine.js"] + Dir.glob(File.join(path, "*.js"))).map { |f| File.basename(f) }.uniq - boot_files - node_boot_files
|
||||
end
|
||||
|
||||
SPEC_TYPES = ["core", "html", "node"]
|
||||
|
||||
def core_spec_files
|
||||
spec_files("core")
|
||||
end
|
||||
|
||||
def html_spec_files
|
||||
spec_files("html")
|
||||
end
|
||||
|
||||
def node_spec_files
|
||||
spec_files("node")
|
||||
end
|
||||
|
||||
def boot_files
|
||||
["boot.js"]
|
||||
end
|
||||
|
||||
def node_boot_files
|
||||
["node_boot.js"]
|
||||
end
|
||||
|
||||
def boot_dir
|
||||
path
|
||||
end
|
||||
|
||||
def spec_files(type)
|
||||
raise ArgumentError.new("Unrecognized spec type") unless SPEC_TYPES.include?(type)
|
||||
(Dir.glob(File.join(path, "spec", type, "*.js"))).map { |f| File.join("spec", type, File.basename(f)) }.uniq
|
||||
end
|
||||
|
||||
def css_files
|
||||
Dir.glob(File.join(path, "*.css")).map { |f| File.basename(f) }
|
||||
end
|
||||
|
||||
def images_dir
|
||||
File.join(File.dirname(__FILE__), '../images')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
from .core import Core
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
|
||||
|
||||
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
|
||||
|
||||
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
|
||||
|
||||
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* ## Require & Instantiate
|
||||
*
|
||||
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
|
||||
*/
|
||||
window.jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
/**
|
||||
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
|
||||
*/
|
||||
jasmineRequire.html(jasmine);
|
||||
|
||||
/**
|
||||
* Create the Jasmine environment. This is used to run all specs in a project.
|
||||
*/
|
||||
var env = jasmine.getEnv();
|
||||
|
||||
/**
|
||||
* ## The Global Interface
|
||||
*
|
||||
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
|
||||
*/
|
||||
var jasmineInterface = {
|
||||
describe: function(description, specDefinitions) {
|
||||
return env.describe(description, specDefinitions);
|
||||
},
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
pending: function() {
|
||||
return env.pending();
|
||||
},
|
||||
|
||||
spyOn: function(obj, methodName) {
|
||||
return env.spyOn(obj, methodName);
|
||||
},
|
||||
|
||||
jsApiReporter: new jasmine.JsApiReporter({
|
||||
timer: new jasmine.Timer()
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
|
||||
*/
|
||||
if (typeof window == "undefined" && typeof exports == "object") {
|
||||
extend(exports, jasmineInterface);
|
||||
} else {
|
||||
extend(window, jasmineInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the interface for adding custom equality testers.
|
||||
*/
|
||||
jasmine.addCustomEqualityTester = function(tester) {
|
||||
env.addCustomEqualityTester(tester);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the interface for adding custom expectation matchers
|
||||
*/
|
||||
jasmine.addMatchers = function(matchers) {
|
||||
return env.addMatchers(matchers);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the mock interface for the JavaScript timeout functions
|
||||
*/
|
||||
jasmine.clock = function() {
|
||||
return env.clock;
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Runner Parameters
|
||||
*
|
||||
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
|
||||
*/
|
||||
|
||||
var queryString = new jasmine.QueryString({
|
||||
getWindowLocation: function() { return window.location; }
|
||||
});
|
||||
|
||||
var catchingExceptions = queryString.getParam("catch");
|
||||
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
*/
|
||||
var htmlReporter = new jasmine.HtmlReporter({
|
||||
env: env,
|
||||
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
timer: new jasmine.Timer()
|
||||
});
|
||||
|
||||
/**
|
||||
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
|
||||
*/
|
||||
env.addReporter(jasmineInterface.jsApiReporter);
|
||||
env.addReporter(htmlReporter);
|
||||
|
||||
/**
|
||||
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
|
||||
*/
|
||||
var specFilter = new jasmine.HtmlSpecFilter({
|
||||
filterString: function() { return queryString.getParam("spec"); }
|
||||
});
|
||||
|
||||
env.specFilter = function(spec) {
|
||||
return specFilter.matches(spec.getFullName());
|
||||
};
|
||||
|
||||
/**
|
||||
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
|
||||
*/
|
||||
window.setTimeout = window.setTimeout;
|
||||
window.setInterval = window.setInterval;
|
||||
window.clearTimeout = window.clearTimeout;
|
||||
window.clearInterval = window.clearInterval;
|
||||
|
||||
/**
|
||||
* ## Execution
|
||||
*
|
||||
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||
*/
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
htmlReporter.initialize();
|
||||
env.execute();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for readability above.
|
||||
*/
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
}());
|
||||
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
|
||||
|
||||
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
|
||||
|
||||
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
|
||||
|
||||
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* ## Require & Instantiate
|
||||
*
|
||||
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
|
||||
*/
|
||||
window.jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
/**
|
||||
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
|
||||
*/
|
||||
jasmineRequire.html(jasmine);
|
||||
|
||||
/**
|
||||
* Create the Jasmine environment. This is used to run all specs in a project.
|
||||
*/
|
||||
var env = jasmine.getEnv();
|
||||
|
||||
/**
|
||||
* ## The Global Interface
|
||||
*
|
||||
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
|
||||
*/
|
||||
var jasmineInterface = {
|
||||
describe: function(description, specDefinitions) {
|
||||
return env.describe(description, specDefinitions);
|
||||
},
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
pending: function() {
|
||||
return env.pending();
|
||||
},
|
||||
|
||||
spyOn: function(obj, methodName) {
|
||||
return env.spyOn(obj, methodName);
|
||||
},
|
||||
|
||||
jsApiReporter: new jasmine.JsApiReporter({
|
||||
timer: new jasmine.Timer()
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
|
||||
*/
|
||||
if (typeof window == "undefined" && typeof exports == "object") {
|
||||
extend(exports, jasmineInterface);
|
||||
} else {
|
||||
extend(window, jasmineInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the interface for adding custom equality testers.
|
||||
*/
|
||||
jasmine.addCustomEqualityTester = function(tester) {
|
||||
env.addCustomEqualityTester(tester);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the interface for adding custom expectation matchers
|
||||
*/
|
||||
jasmine.addMatchers = function(matchers) {
|
||||
return env.addMatchers(matchers);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the mock interface for the JavaScript timeout functions
|
||||
*/
|
||||
jasmine.clock = function() {
|
||||
return env.clock;
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Runner Parameters
|
||||
*
|
||||
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
|
||||
*/
|
||||
|
||||
var queryString = new jasmine.QueryString({
|
||||
getWindowLocation: function() { return window.location; }
|
||||
});
|
||||
|
||||
var catchingExceptions = queryString.getParam("catch");
|
||||
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
*/
|
||||
var htmlReporter = new jasmine.HtmlReporter({
|
||||
env: env,
|
||||
onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
timer: new jasmine.Timer()
|
||||
});
|
||||
|
||||
/**
|
||||
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
|
||||
*/
|
||||
env.addReporter(jasmineInterface.jsApiReporter);
|
||||
env.addReporter(htmlReporter);
|
||||
|
||||
/**
|
||||
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
|
||||
*/
|
||||
var specFilter = new jasmine.HtmlSpecFilter({
|
||||
filterString: function() { return queryString.getParam("spec"); }
|
||||
});
|
||||
|
||||
env.specFilter = function(spec) {
|
||||
return specFilter.matches(spec.getFullName());
|
||||
};
|
||||
|
||||
/**
|
||||
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
|
||||
*/
|
||||
window.setTimeout = window.setTimeout;
|
||||
window.setInterval = window.setInterval;
|
||||
window.clearTimeout = window.clearTimeout;
|
||||
window.clearInterval = window.clearInterval;
|
||||
|
||||
/**
|
||||
* ## Execution
|
||||
*
|
||||
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||
*/
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
htmlReporter.initialize();
|
||||
env.execute();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for readability above.
|
||||
*/
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
}());
|
||||
@@ -0,0 +1,71 @@
|
||||
module.exports = function(jasmineRequire) {
|
||||
var jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
var consoleFns = require('../console/console.js');
|
||||
consoleFns.console(consoleFns, 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()
|
||||
}),
|
||||
|
||||
|
||||
jasmine: jasmine
|
||||
};
|
||||
|
||||
extend(global, jasmineInterface);
|
||||
|
||||
jasmine.addCustomEqualityTester = function(tester) {
|
||||
env.addCustomEqualityTester(tester);
|
||||
};
|
||||
|
||||
jasmine.addMatchers = function(matchers) {
|
||||
return env.addMatchers(matchers);
|
||||
};
|
||||
|
||||
jasmine.clock = function() {
|
||||
return env.clock;
|
||||
};
|
||||
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
|
||||
return jasmine;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
import pkg_resources
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict
|
||||
|
||||
class Core(object):
|
||||
@classmethod
|
||||
def js_package(cls):
|
||||
return __package__
|
||||
|
||||
@classmethod
|
||||
def css_package(cls):
|
||||
return __package__
|
||||
|
||||
@classmethod
|
||||
def image_package(cls):
|
||||
return __package__ + ".images"
|
||||
|
||||
@classmethod
|
||||
def js_files(cls):
|
||||
js_files = sorted(list(filter(lambda x: '.js' in x, pkg_resources.resource_listdir(cls.js_package(), '.'))))
|
||||
|
||||
# jasmine.js needs to be first
|
||||
js_files.insert(0, 'jasmine.js')
|
||||
|
||||
# boot needs to be last
|
||||
js_files.remove('boot.js')
|
||||
js_files.append('boot.js')
|
||||
|
||||
return cls._uniq(js_files)
|
||||
|
||||
@classmethod
|
||||
def css_files(cls):
|
||||
return cls._uniq(sorted(filter(lambda x: '.css' in x, pkg_resources.resource_listdir(cls.css_package(), '.'))))
|
||||
|
||||
@classmethod
|
||||
def favicon(cls):
|
||||
return 'jasmine_favicon.png'
|
||||
|
||||
@classmethod
|
||||
def _uniq(self, items, idfun=None):
|
||||
# order preserving
|
||||
|
||||
if idfun is None:
|
||||
def idfun(x): return x
|
||||
seen = {}
|
||||
result = []
|
||||
for item in items:
|
||||
marker = idfun(item)
|
||||
# in old Python versions:
|
||||
# if seen.has_key(marker)
|
||||
# but in new ones:
|
||||
if marker in seen:
|
||||
continue
|
||||
|
||||
seen[marker] = 1
|
||||
result.append(item)
|
||||
return result
|
||||
@@ -0,0 +1,60 @@
|
||||
describe("Player", function() {
|
||||
var Player = require('../../jasmine_examples/Player.js');
|
||||
var Song = require('../../jasmine_examples/Song.js');
|
||||
var player;
|
||||
var song;
|
||||
|
||||
beforeEach(function() {
|
||||
player = new Player();
|
||||
song = new Song();
|
||||
});
|
||||
|
||||
it("should be able to play a Song", function() {
|
||||
player.play(song);
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
|
||||
//demonstrates use of custom matcher
|
||||
expect(player).toBePlaying(song);
|
||||
});
|
||||
|
||||
describe("when song has been paused", function() {
|
||||
beforeEach(function() {
|
||||
player.play(song);
|
||||
player.pause();
|
||||
});
|
||||
|
||||
it("should indicate that the song is currently paused", function() {
|
||||
expect(player.isPlaying).toBeFalsy();
|
||||
|
||||
// demonstrates use of 'not' with a custom matcher
|
||||
expect(player).not.toBePlaying(song);
|
||||
});
|
||||
|
||||
it("should be possible to resume", function() {
|
||||
player.resume();
|
||||
expect(player.isPlaying).toBeTruthy();
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
});
|
||||
});
|
||||
|
||||
// demonstrates use of spies to intercept and test method calls
|
||||
it("tells the current song if the user has made it a favorite", function() {
|
||||
spyOn(song, 'persistFavoriteStatus');
|
||||
|
||||
player.play(song);
|
||||
player.makeFavorite();
|
||||
|
||||
expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
//demonstrates use of expected exceptions
|
||||
describe("#resume", function() {
|
||||
it("should throw an exception if song is already playing", function() {
|
||||
player.play(song);
|
||||
|
||||
expect(function() {
|
||||
player.resume();
|
||||
}).toThrowError("song is already playing");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
beforeEach(function () {
|
||||
jasmine.addMatchers({
|
||||
toBePlaying: function () {
|
||||
return {
|
||||
compare: function (actual, expected) {
|
||||
var player = actual;
|
||||
|
||||
return {
|
||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
function Player() {
|
||||
}
|
||||
Player.prototype.play = function(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.pause = function() {
|
||||
this.isPlaying = false;
|
||||
};
|
||||
|
||||
Player.prototype.resume = function() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error("song is already playing");
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.makeFavorite = function() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
};
|
||||
|
||||
module.exports = Player;
|
||||
@@ -0,0 +1,9 @@
|
||||
function Song() {
|
||||
}
|
||||
|
||||
Song.prototype.persistFavoriteStatus = function(value) {
|
||||
// something complicated
|
||||
throw new Error("not yet implemented");
|
||||
};
|
||||
|
||||
module.exports = Song;
|
||||
@@ -0,0 +1,58 @@
|
||||
describe("Player", function() {
|
||||
var player;
|
||||
var song;
|
||||
|
||||
beforeEach(function() {
|
||||
player = new Player();
|
||||
song = new Song();
|
||||
});
|
||||
|
||||
it("should be able to play a Song", function() {
|
||||
player.play(song);
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
|
||||
//demonstrates use of custom matcher
|
||||
expect(player).toBePlaying(song);
|
||||
});
|
||||
|
||||
describe("when song has been paused", function() {
|
||||
beforeEach(function() {
|
||||
player.play(song);
|
||||
player.pause();
|
||||
});
|
||||
|
||||
it("should indicate that the song is currently paused", function() {
|
||||
expect(player.isPlaying).toBeFalsy();
|
||||
|
||||
// demonstrates use of 'not' with a custom matcher
|
||||
expect(player).not.toBePlaying(song);
|
||||
});
|
||||
|
||||
it("should be possible to resume", function() {
|
||||
player.resume();
|
||||
expect(player.isPlaying).toBeTruthy();
|
||||
expect(player.currentlyPlayingSong).toEqual(song);
|
||||
});
|
||||
});
|
||||
|
||||
// demonstrates use of spies to intercept and test method calls
|
||||
it("tells the current song if the user has made it a favorite", function() {
|
||||
spyOn(song, 'persistFavoriteStatus');
|
||||
|
||||
player.play(song);
|
||||
player.makeFavorite();
|
||||
|
||||
expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
//demonstrates use of expected exceptions
|
||||
describe("#resume", function() {
|
||||
it("should throw an exception if song is already playing", function() {
|
||||
player.play(song);
|
||||
|
||||
expect(function() {
|
||||
player.resume();
|
||||
}).toThrowError("song is already playing");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
beforeEach(function () {
|
||||
jasmine.addMatchers({
|
||||
toBePlaying: function () {
|
||||
return {
|
||||
compare: function (actual, expected) {
|
||||
var player = actual;
|
||||
|
||||
return {
|
||||
pass: player.currentlyPlayingSong === expected && player.isPlaying
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
function Player() {
|
||||
}
|
||||
Player.prototype.play = function(song) {
|
||||
this.currentlyPlayingSong = song;
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.pause = function() {
|
||||
this.isPlaying = false;
|
||||
};
|
||||
|
||||
Player.prototype.resume = function() {
|
||||
if (this.isPlaying) {
|
||||
throw new Error("song is already playing");
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
};
|
||||
|
||||
Player.prototype.makeFavorite = function() {
|
||||
this.currentlyPlayingSong.persistFavoriteStatus(true);
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
function Song() {
|
||||
}
|
||||
|
||||
Song.prototype.persistFavoriteStatus = function(value) {
|
||||
// something complicated
|
||||
throw new Error("not yet implemented");
|
||||
};
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
jasmineRequire.html = function(j$) {
|
||||
j$.ResultsNode = jasmineRequire.ResultsNode();
|
||||
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||
j$.QueryString = jasmineRequire.QueryString();
|
||||
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlReporter = function(j$) {
|
||||
|
||||
var noopTimer = {
|
||||
start: function() {},
|
||||
elapsed: function() { return 0; }
|
||||
};
|
||||
|
||||
function HtmlReporter(options) {
|
||||
var env = options.env || {},
|
||||
getContainer = options.getContainer,
|
||||
createElement = options.createElement,
|
||||
createTextNode = options.createTextNode,
|
||||
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
|
||||
timer = options.timer || noopTimer,
|
||||
results = [],
|
||||
specsExecuted = 0,
|
||||
failureCount = 0,
|
||||
pendingSpecCount = 0,
|
||||
htmlReporterMain,
|
||||
symbols;
|
||||
|
||||
this.initialize = function() {
|
||||
clearPrior();
|
||||
htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'},
|
||||
createDom('div', {className: 'banner'},
|
||||
createDom('a', {className: 'title', href: 'http://jasmine.github.io/', target: '_blank'}),
|
||||
createDom('span', {className: 'version'}, j$.version)
|
||||
),
|
||||
createDom('ul', {className: 'symbol-summary'}),
|
||||
createDom('div', {className: 'alert'}),
|
||||
createDom('div', {className: 'results'},
|
||||
createDom('div', {className: 'failures'})
|
||||
)
|
||||
);
|
||||
getContainer().appendChild(htmlReporterMain);
|
||||
|
||||
symbols = find('.symbol-summary');
|
||||
};
|
||||
|
||||
var totalSpecsDefined;
|
||||
this.jasmineStarted = function(options) {
|
||||
totalSpecsDefined = options.totalSpecsDefined || 0;
|
||||
timer.start();
|
||||
};
|
||||
|
||||
var summary = createDom('div', {className: 'summary'});
|
||||
|
||||
var topResults = new j$.ResultsNode({}, '', null),
|
||||
currentParent = topResults;
|
||||
|
||||
this.suiteStarted = function(result) {
|
||||
currentParent.addChild(result, 'suite');
|
||||
currentParent = currentParent.last();
|
||||
};
|
||||
|
||||
this.suiteDone = function(result) {
|
||||
if (currentParent == topResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentParent = currentParent.parent;
|
||||
};
|
||||
|
||||
this.specStarted = function(result) {
|
||||
currentParent.addChild(result, 'spec');
|
||||
};
|
||||
|
||||
var failures = [];
|
||||
this.specDone = function(result) {
|
||||
if(noExpectations(result) && console && console.error) {
|
||||
console.error('Spec \'' + result.fullName + '\' has no expectations.');
|
||||
}
|
||||
|
||||
if (result.status != 'disabled') {
|
||||
specsExecuted++;
|
||||
}
|
||||
|
||||
symbols.appendChild(createDom('li', {
|
||||
className: noExpectations(result) ? 'empty' : result.status,
|
||||
id: 'spec_' + result.id,
|
||||
title: result.fullName
|
||||
}
|
||||
));
|
||||
|
||||
if (result.status == 'failed') {
|
||||
failureCount++;
|
||||
|
||||
var failure =
|
||||
createDom('div', {className: 'spec-detail failed'},
|
||||
createDom('div', {className: 'description'},
|
||||
createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName)
|
||||
),
|
||||
createDom('div', {className: 'messages'})
|
||||
);
|
||||
var messages = failure.childNodes[1];
|
||||
|
||||
for (var i = 0; i < result.failedExpectations.length; i++) {
|
||||
var expectation = result.failedExpectations[i];
|
||||
messages.appendChild(createDom('div', {className: 'result-message'}, expectation.message));
|
||||
messages.appendChild(createDom('div', {className: 'stack-trace'}, expectation.stack));
|
||||
}
|
||||
|
||||
failures.push(failure);
|
||||
}
|
||||
|
||||
if (result.status == 'pending') {
|
||||
pendingSpecCount++;
|
||||
}
|
||||
};
|
||||
|
||||
this.jasmineDone = function() {
|
||||
var banner = find('.banner');
|
||||
banner.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
|
||||
|
||||
var alert = find('.alert');
|
||||
|
||||
alert.appendChild(createDom('span', { className: 'exceptions' },
|
||||
createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions'),
|
||||
createDom('input', {
|
||||
className: 'raise',
|
||||
id: 'raise-exceptions',
|
||||
type: 'checkbox'
|
||||
})
|
||||
));
|
||||
var checkbox = find('#raise-exceptions');
|
||||
|
||||
checkbox.checked = !env.catchingExceptions();
|
||||
checkbox.onclick = onRaiseExceptionsClick;
|
||||
|
||||
if (specsExecuted < totalSpecsDefined) {
|
||||
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
|
||||
alert.appendChild(
|
||||
createDom('span', {className: 'bar skipped'},
|
||||
createDom('a', {href: '?', title: 'Run all specs'}, skippedMessage)
|
||||
)
|
||||
);
|
||||
}
|
||||
var statusBarMessage = '';
|
||||
var statusBarClassName = 'bar ';
|
||||
|
||||
if (totalSpecsDefined > 0) {
|
||||
statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
|
||||
if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
|
||||
statusBarClassName += (failureCount > 0) ? 'failed' : 'passed';
|
||||
} else {
|
||||
statusBarClassName += 'skipped';
|
||||
statusBarMessage += 'No specs found';
|
||||
}
|
||||
|
||||
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
|
||||
|
||||
var results = find('.results');
|
||||
results.appendChild(summary);
|
||||
|
||||
summaryList(topResults, summary);
|
||||
|
||||
function summaryList(resultsTree, domParent) {
|
||||
var specListNode;
|
||||
for (var i = 0; i < resultsTree.children.length; i++) {
|
||||
var resultNode = resultsTree.children[i];
|
||||
if (resultNode.type == 'suite') {
|
||||
var suiteListNode = createDom('ul', {className: 'suite', id: 'suite-' + resultNode.result.id},
|
||||
createDom('li', {className: 'suite-detail'},
|
||||
createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description)
|
||||
)
|
||||
);
|
||||
|
||||
summaryList(resultNode, suiteListNode);
|
||||
domParent.appendChild(suiteListNode);
|
||||
}
|
||||
if (resultNode.type == 'spec') {
|
||||
if (domParent.getAttribute('class') != 'specs') {
|
||||
specListNode = createDom('ul', {className: 'specs'});
|
||||
domParent.appendChild(specListNode);
|
||||
}
|
||||
var specDescription = resultNode.result.description;
|
||||
if(noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom('li', {
|
||||
className: resultNode.result.status,
|
||||
id: 'spec-' + resultNode.result.id
|
||||
},
|
||||
createDom('a', {href: specHref(resultNode.result)}, specDescription)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length) {
|
||||
alert.appendChild(
|
||||
createDom('span', {className: 'menu bar spec-list'},
|
||||
createDom('span', {}, 'Spec List | '),
|
||||
createDom('a', {className: 'failures-menu', href: '#'}, 'Failures')));
|
||||
alert.appendChild(
|
||||
createDom('span', {className: 'menu bar failure-list'},
|
||||
createDom('a', {className: 'spec-list-menu', href: '#'}, 'Spec List'),
|
||||
createDom('span', {}, ' | Failures ')));
|
||||
|
||||
find('.failures-menu').onclick = function() {
|
||||
setMenuModeTo('failure-list');
|
||||
};
|
||||
find('.spec-list-menu').onclick = function() {
|
||||
setMenuModeTo('spec-list');
|
||||
};
|
||||
|
||||
setMenuModeTo('failure-list');
|
||||
|
||||
var failureNode = find('.failures');
|
||||
for (var i = 0; i < failures.length; i++) {
|
||||
failureNode.appendChild(failures[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function find(selector) {
|
||||
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
|
||||
}
|
||||
|
||||
function clearPrior() {
|
||||
// return the reporter
|
||||
var oldReporter = find('');
|
||||
|
||||
if(oldReporter) {
|
||||
getContainer().removeChild(oldReporter);
|
||||
}
|
||||
}
|
||||
|
||||
function createDom(type, attrs, childrenVarArgs) {
|
||||
var el = createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(createTextNode(child));
|
||||
} else {
|
||||
if (child) {
|
||||
el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == 'className') {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function pluralize(singular, count) {
|
||||
var word = (count == 1 ? singular : singular + 's');
|
||||
|
||||
return '' + count + ' ' + word;
|
||||
}
|
||||
|
||||
function specHref(result) {
|
||||
return '?spec=' + encodeURIComponent(result.fullName);
|
||||
}
|
||||
|
||||
function setMenuModeTo(mode) {
|
||||
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
|
||||
}
|
||||
|
||||
function noExpectations(result) {
|
||||
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
|
||||
result.status === 'passed';
|
||||
}
|
||||
}
|
||||
|
||||
return HtmlReporter;
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlSpecFilter = function() {
|
||||
function HtmlSpecFilter(options) {
|
||||
var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
var filterPattern = new RegExp(filterString);
|
||||
|
||||
this.matches = function(specName) {
|
||||
return filterPattern.test(specName);
|
||||
};
|
||||
}
|
||||
|
||||
return HtmlSpecFilter;
|
||||
};
|
||||
|
||||
jasmineRequire.ResultsNode = function() {
|
||||
function ResultsNode(result, type, parent) {
|
||||
this.result = result;
|
||||
this.type = type;
|
||||
this.parent = parent;
|
||||
|
||||
this.children = [];
|
||||
|
||||
this.addChild = function(result, type) {
|
||||
this.children.push(new ResultsNode(result, type, this));
|
||||
};
|
||||
|
||||
this.last = function() {
|
||||
return this.children[this.children.length - 1];
|
||||
};
|
||||
}
|
||||
|
||||
return ResultsNode;
|
||||
};
|
||||
|
||||
jasmineRequire.QueryString = function() {
|
||||
function QueryString(options) {
|
||||
|
||||
this.setParam = function(key, value) {
|
||||
var paramMap = queryStringToParamMap();
|
||||
paramMap[key] = value;
|
||||
options.getWindowLocation().search = toQueryString(paramMap);
|
||||
};
|
||||
|
||||
this.getParam = function(key) {
|
||||
return queryStringToParamMap()[key];
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function toQueryString(paramMap) {
|
||||
var qStrPairs = [];
|
||||
for (var prop in paramMap) {
|
||||
qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
|
||||
}
|
||||
return '?' + qStrPairs.join('&');
|
||||
}
|
||||
|
||||
function queryStringToParamMap() {
|
||||
var paramStr = options.getWindowLocation().search.substring(1),
|
||||
params = [],
|
||||
paramMap = {};
|
||||
|
||||
if (paramStr.length > 0) {
|
||||
params = paramStr.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
var value = decodeURIComponent(p[1]);
|
||||
if (value === 'true' || value === 'false') {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
paramMap[decodeURIComponent(p[0])] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return QueryString;
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
http://www.JSON.org/json2.js
|
||||
2009-08-17
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
This file creates a global JSON object containing two methods: stringify
|
||||
and parse.
|
||||
|
||||
JSON.stringify(value, replacer, space)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
replacer an optional parameter that determines how object
|
||||
values are stringified for objects. It can be a
|
||||
function or an array of strings.
|
||||
|
||||
space an optional parameter that specifies the indentation
|
||||
of nested structures. If it is omitted, the text will
|
||||
be packed without extra whitespace. If it is a number,
|
||||
it will specify the number of spaces to indent at each
|
||||
level. If it is a string (such as '\t' or ' '),
|
||||
it contains the characters used to indent at each level.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
|
||||
When an object value is found, if the object contains a toJSON
|
||||
method, its toJSON method will be called and the result will be
|
||||
stringified. A toJSON method does not serialize: it returns the
|
||||
value represented by the name/value pair that should be serialized,
|
||||
or undefined if nothing should be serialized. The toJSON method
|
||||
will be passed the key associated with the value, and this will be
|
||||
bound to the value
|
||||
|
||||
For example, this would serialize Dates as ISO strings.
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
You can provide an optional replacer method. It will be passed the
|
||||
key and value of each member, with this bound to the containing
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
If the replacer parameter is an array of strings, then it will be
|
||||
used to select the members to be serialized. It filters the results
|
||||
such that only members with keys listed in the replacer array are
|
||||
stringified.
|
||||
|
||||
Values that do not have JSON representations, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped; in arrays they will be replaced with null. You can use
|
||||
a replacer function to replace those with JSON values.
|
||||
JSON.stringify(undefined) returns undefined.
|
||||
|
||||
The optional space parameter produces a stringification of the
|
||||
value that is filled with line breaks and indentation to make it
|
||||
easier to read.
|
||||
|
||||
If the space parameter is a non-empty string, then that string will
|
||||
be used for indentation. If the space parameter is a number, then
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||
|
||||
text = JSON.stringify([new Date()], function (key, value) {
|
||||
return this[key] instanceof Date ?
|
||||
'Date(' + this[key] + ')' : value;
|
||||
});
|
||||
// text is '["Date(---current time---)"]'
|
||||
|
||||
|
||||
JSON.parse(text, reviver)
|
||||
This method parses a JSON text to produce an object or array.
|
||||
It can throw a SyntaxError exception.
|
||||
|
||||
The optional reviver parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values,
|
||||
and its return value is used instead of the original value.
|
||||
If it returns what it received, then the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||
var d;
|
||||
if (typeof value === 'string' &&
|
||||
value.slice(0, 5) === 'Date(' &&
|
||||
value.slice(-1) === ')') {
|
||||
d = new Date(value.slice(5, -1));
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
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 = {};
|
||||
}
|
||||
|
||||
(function () {
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
if (typeof Date.prototype.toJSON !== 'function') {
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
|
||||
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();
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// 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 + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// The value is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// 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(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
k = rep[i];
|
||||
if (typeof k === 'string') {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
if (typeof JSON.stringify !== 'function') {
|
||||
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.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// If the JSON object does not yet have a parse method, give it one.
|
||||
|
||||
if (typeof JSON.parse !== 'function') {
|
||||
JSON.parse = function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' +
|
||||
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// 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, ''))) {
|
||||
|
||||
// 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
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
}());
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
module.exports = function(jasmineRequire) {
|
||||
var jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
var consoleFns = require('../console/console.js');
|
||||
consoleFns.console(consoleFns, 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()
|
||||
}),
|
||||
|
||||
|
||||
jasmine: jasmine
|
||||
};
|
||||
|
||||
extend(global, jasmineInterface);
|
||||
|
||||
jasmine.addCustomEqualityTester = function(tester) {
|
||||
env.addCustomEqualityTester(tester);
|
||||
};
|
||||
|
||||
jasmine.addMatchers = function(matchers) {
|
||||
return env.addMatchers(matchers);
|
||||
};
|
||||
|
||||
jasmine.clock = function() {
|
||||
return env.clock;
|
||||
};
|
||||
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
|
||||
return jasmine;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# DO NOT Edit this file. Canonical version of Jasmine lives in the repo's package.json. This file is generated
|
||||
# by a grunt task when the standalone release is built.
|
||||
#
|
||||
module Jasmine
|
||||
module Core
|
||||
VERSION = "2.0.1"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "jasmine-core",
|
||||
"license": "MIT",
|
||||
"version": "2.0.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pivotal/jasmine.git"
|
||||
},
|
||||
"description": "Official packaging of Jasmine's core files for use by Node.js projects.",
|
||||
"homepage": "http://jasmine.github.io",
|
||||
"main": "./lib/jasmine-core.js",
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-jshint": "~0.7.0",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-compass": "~0.6.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"shelljs": "~0.1.4",
|
||||
"glob": "~3.2.9",
|
||||
"jasmine": "https://github.com/pivotal/jasmine-npm/archive/master.tar.gz",
|
||||
"load-grunt-tasks": "^0.4.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# Jasmine Core 2.0.1 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
This release is for small bug fixes and enhancements ahead of a real-soon-now 2.1.
|
||||
|
||||
## Changes
|
||||
|
||||
### Features
|
||||
|
||||
* NodeJS is now supported with a jasmine-core npm
|
||||
* [Support browsers that don't supply a `Date.now()` by having a `mockDate` object](http://www.pivotaltracker.com/story/66606132) - Closes #361
|
||||
* [Show message if no specs where loaded](http://www.pivotaltracker.com/story/12784235)
|
||||
* When using `jasmine.any`, the `class` will now be included in the error message
|
||||
* Reporters now receive the number of passed expectations in a spec
|
||||
* Use default failure message for `toBeNaN`
|
||||
* Use the latest `jasmine_selenium_runner` so we use the fix for printing objects with cycles
|
||||
* Add jasmine logo image to HTML runner
|
||||
* Stop Jasmine's CSS affecting the style of the body tag - Closes #600
|
||||
* Standardized location of the standalone distributions - they now live in the repo in `/dist` as well as on the Releases page
|
||||
|
||||
### Bugs
|
||||
|
||||
* Don't allow calling the same done callback multiple times - Fixes #523
|
||||
* [Remove 'empty' as an option as a spec result](http://www.pivotaltracker.com/story/73741032) as this was a breaking change
|
||||
* Instead, we determine if a spec has no expectations using the added
|
||||
key of `passedExpectations` in combination of the `failedExpectations`
|
||||
to determine that there a spec is 'empty'
|
||||
* Fix build in IE8 (IE8 doesn't support `Object.freeze`)
|
||||
* Fix `ObjectContaining` to match recursively
|
||||
|
||||
### Documentation
|
||||
|
||||
* Update release doc to use GitHub releases
|
||||
* Add installation instructions to README - Merges #621
|
||||
* Add Ruby Gem and Python Egg to docs
|
||||
* Add detailed steps on how to contribute - Merges #580 from @pablofiu
|
||||
|
||||
## Pull Requests and Issues
|
||||
|
||||
* Contains is explicitly false if actual is `undefined` or `null` - Fixes #627
|
||||
* namespace `html-reporter` -> `jasmine_html-reporter` - Fixes #600
|
||||
* Throw a more specific error when `expect` is used without a `currentSpec` - Fixes #602
|
||||
* Reduced size of logo with PNG Gauntlet - Merges #588
|
||||
* HTML Reporter resets previous DOM when re-initialized - Merges #594 from @plukevdh
|
||||
* Narrow down raise exceptions query selector; Finding by any input tag is a little bit broad - Closes #605
|
||||
* Pass through custom equality testers in toHaveBeenCalledWith - Fixes #536
|
||||
* Fix outdated copyright year (update to 2014) - Merges #550 from @slothmonster
|
||||
* [Add package.json to Python egg to get correct version number](http://www.pivotaltracker.com/story/67556148) - Fixes #551
|
||||
* Allow users to set the maximum length of array that the pretty-printer
|
||||
will print out - Fixes #323 @mikemoraned and #374 @futuraprime
|
||||
* `matchersUtil.equals()`` does not expect a matcher as its first argument,
|
||||
so send the "actual" value first and the "expected" value second. - Merges #538 from @cbandy
|
||||
* Add single quote check to `jshint` and fix src files for that - Closes #522
|
||||
* Remove an `eval` in order to support running jasmine within CSP - Closes #503
|
||||
* Allow matcher custom failure messages to be a function - Closes #520
|
||||
* More color blind friendly CSS from @dleppik - Closes #463 & #509
|
||||
* Use `load-grunt-tasks` Merges #521 from @robinboehm
|
||||
* Special case printing `-0` - Closes #496
|
||||
* Allow stub or spy Date object safely using a closure to get a clean copy - Closes #506
|
||||
* [Use `\d7` instead of plain 'x' for more square appearance](http://www.pivotaltracker.com/story/48434179)
|
||||
* Better support in pretty printer when an object has null prototype - Fixes #500
|
||||
* Update link at top of README to improve access to Jasmine 2.0 docs - Merges #486 from @nextmat
|
||||
* Force query selector to seek within the html-reporter element - Merges #479 from @shprink
|
||||
* Netbeans files are in gitignore - Merges #478 from @shprink
|
||||
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_
|
||||
@@ -0,0 +1,179 @@
|
||||
# Jasmine Core 2.0 Release Notes
|
||||
|
||||
## Summary
|
||||
|
||||
These notes are for Jasmine Core 2.0.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
The [`introduction.js`][intro] page covers the current syntax, highlighting the changes. Here are the known interface changes that are not backwards compatible with 1.x.
|
||||
|
||||
* New syntax for asynchronous specs
|
||||
* New syntax for spies
|
||||
* New interface for reporters
|
||||
* Better Equality testing
|
||||
* Replaced custom matchers for ease of use
|
||||
* Change to `toThrow` matcher
|
||||
* Clock now remains installed when a spec finishes
|
||||
* More Jasmine internal variables/functions have been moved into closures
|
||||
|
||||
### New syntax for asynchronous specs
|
||||
|
||||
Similar to [Mocha][mocha], Jasmine `before`s, `spec`s, and `after`s can take an optional `done` callback in order to force asynchronous tests. The next function, whether it's a `before`, `spec` or `after`, will wait until this function is called or until a timeout is reached.
|
||||
|
||||
### New syntax for spies
|
||||
|
||||
Spies have a slightly modified syntax. The idea came from a desire to preserve any of the properties on a spied-upon function and some better testing patterns.
|
||||
|
||||
### New interface for reporters
|
||||
|
||||
The reporter interface has been **replaced**. The callbacks are different and more consistent. The objects passed in should only provide what is needed to report results. This enforces an interface to result data so custom reporters will be less coupled to the Jasmine implementation. The Jasmine reporter API now includes a slot for a `timer` object.
|
||||
|
||||
### Better Equality testing
|
||||
|
||||
We removed the previous equality code and are now using new code for testing equality. We started with [Underscore.js][underscore]'s `isEqual`, refactored a bit and added some additional tests.
|
||||
|
||||
### Replaced custom matchers for ease of use
|
||||
|
||||
The interface for adding custom matchers has been **replaced**. It has always been possible to add custom matchers, but the API was barely documented and difficult to test. We've changed how matchers are added and tested. Jasmine adds its own matchers by the same mechanism that custom matchers use. Dogfooding FTW.
|
||||
|
||||
### Change to `toThrow` matcher
|
||||
|
||||
We've changed the behavior of the `toThrow` matcher, moving some functionality to the `toThrowError` matcher. This should allow more of the requested use cases.
|
||||
|
||||
### Clock now remains installed when a spec finishes
|
||||
|
||||
After installing the Jasmine Clock, it will stay installed until `uninstall` is called -- clearing up any ambiguity for when those timing functions will revert to using the global clock object.
|
||||
|
||||
## More Jasmine internal variables/functions have been moved into closures
|
||||
|
||||
Certain variables/functions like a function to get the next spec id have been moved into closures, making the Jasmine interface cleaner.
|
||||
|
||||
## Other Changes
|
||||
|
||||
* Massive refactoring and better testing
|
||||
* Environment setup now in `boot.js`
|
||||
* Development and Build moved to Grunt
|
||||
* Changes to how Jasmine is loaded
|
||||
* Changes to how Jasmine is tested
|
||||
* Better node.js support
|
||||
* Better Continuous Integration Environment at Travis
|
||||
* Support matrix updated
|
||||
* Removed JsDoc Pages
|
||||
* Adding Code Climate for JavaScript
|
||||
|
||||
## Massive refactoring and better testing
|
||||
|
||||
This is the biggest set of changes. We've touched nearly every file and every object. We've merged objects together and factored out code. We styled the code more consistently. We've improved nearly every test.
|
||||
|
||||
In general, Jasmine is made of smaller, more-loosely-coupled objects, unit-tested with explicit dependencies injected. This made tests easier to read, write, and maintain. We know this has made Jasmine development easier for the core team. We expect (and hope) this makes it easier for the community to extend Jasmine and provide pull requests that make more sense the first time out.
|
||||
|
||||
## Environment setup now in `boot.js`
|
||||
|
||||
Instantiation and setup of the Jasmine environment, including building reporters, exposing the "global" functions, and executing tests has moved into its own file: `boot.js`. This should make it easier to add custom reporters, configure some objects, or just in general change how you use Jasmine from the outside.
|
||||
|
||||
For example, during development, Jasmine uses its own `devboot.js` to load itself twice - once from `jasmine.js` and once from the source directories.
|
||||
|
||||
## Development and Build moved to Grunt
|
||||
|
||||
We've moved away from Ruby and embraced [Node.js][node] and [Grunt.js][grunt] for the various command line tasks during development. Yes, it's a just a different set of dependencies. But it's less code for the team to maintain - it turns out that JavaScript tools are pretty good at building JavaScript projects. This will make it easier for the community to make sure contributions work in browsers and in Node.js before submitting Pull Requests. There is more detail in the [Contributor's Guide][contrib].
|
||||
|
||||
## Changes to how Jasmine is loaded
|
||||
|
||||
We did not want to add new run-time dependencies, yet we needed to be cleaner when loading Jasmine. So we wrote a custom "require" scheme that works in Node.js and in browsers. This only affects pull requests which add files - please be careful in these cases. Again, the [Contributor's Guide][contrib] should help.
|
||||
|
||||
## Changes to how Jasmine is tested with Jasmine
|
||||
|
||||
Writing a custom require system helped enforce self-testing - the built `jasmine.js` testing Jasmine from the source directories. Overall this has improved the stability of the code. When you look at Jasmine's tests, you'll see both `jasmine` and `j$` used. The former, `jasmine`, will always be used to test the code from source, which is loaded into the reference `j$`. Please adhere to this pattern when writing tests for contributions.
|
||||
|
||||
## Better node.js support
|
||||
|
||||
`Node.js` is now officially a first-class citizen. For a long time we've made sure tests were green in Node before releasing. But it is now officially part of Jasmine's CI build at [Travis][travis]. For the curious, the [`node_suite.js`][node_suite], is essentially a `boot.js` for Node. An official `npm` is coming.
|
||||
|
||||
## Better Continuous Integration Environment at Travis
|
||||
|
||||
The [CI build at Travis][travis_jasmine] now runs the core specs in a build matrix across browsers. It's far from complete on the operating system matrix, but you will see that Jasmine runs against: Firefox, Chrome, Safari 5, Safari 6, [Phantom.js][phantom], [Node.js][node], and IE versions 8, 9, and 10. Big thanks to [SauceLabs][sauce] for their support of open source projects. We will happily take pull requests for additional OS/Browser combos within the matrix.
|
||||
|
||||
## Support Matrix Updated
|
||||
|
||||
We're dropping support for IE < 8. [Jasmine 1.x][jasmine_downloads] remains for projects that need to support older browsers.
|
||||
|
||||
## Removed JsDoc Pages
|
||||
|
||||
Comments in code are lies waiting to happen. Jasmine's JsDoc comments were no exception. The comments were out of date, the generated pages were even more out of date, and frankly they were not helpful. So they're gone.
|
||||
|
||||
Last year saw the posting of the [`introduction.js`][intro] page to document the real, practical interface for projects to use. This page has received a lot of positive feedback so expect more pages like this one.
|
||||
|
||||
## Adding Code Climate for JavaScript
|
||||
|
||||
We are running Code Climate for Jasmine. We have some work to do here but it's helping us easily find code hotspots.
|
||||
|
||||
## Pull Requests and Issues
|
||||
|
||||
The following Pull Requests were merged:
|
||||
|
||||
* ObjectContaining wrong filed value error message #[394](https://github.com/pivotal/jasmine/issues/394) from albertandrejev
|
||||
* Removed unnecessary parameter from `suiteFactory()` call #[397](https://github.com/pivotal/jasmine/issues/397) from valera-rozuvan
|
||||
* `jasmine.Any` supports `Boolean` #[392](https://github.com/pivotal/jasmine/issues/392) from albertandrejev
|
||||
* Reporters get execution time #[30](https://github.com/pivotal/jasmine/issues/30)
|
||||
* `toThrow` matchers handle falsy exceptions #[317](https://github.com/pivotal/jasmine/issues/371)
|
||||
* Removed deprecated `jasmine.Matchers.pp` #[363](https://github.com/pivotal/jasmine/issues/363) from robinboehm
|
||||
* Fix for Clock ticking to default to 0 #[340](https://github.com/pivotal/jasmine/issues/340) from Caio Cunha
|
||||
* Whitespace failures should be easier to understand #[332](https://github.com/pivotal/jasmine/issues/332) from bjornblomqvist
|
||||
* Fix for more markdown-y image for Build status #[329](https://github.com/pivotal/jasmine/issues/329) from sunliwen
|
||||
* UTF-8 encoding fixes #[333](https://github.com/pivotal/jasmine/issues/333) from bjornblomqvist
|
||||
* Replaced deprecated octal literal with hexadecimal from kris7t
|
||||
* Make getGlobal() work in strict mode from metaweta
|
||||
* Clears timeout timer even when async spec throws an exception from tidoust
|
||||
* Timeouts scheduled within a delayed function are correctly scheduled and executed from maciej-filip-sz
|
||||
|
||||
### Bug Fixes
|
||||
* Improved the performance of the HTML output with a CSS change #[428](https://github.com/pivotal/jasmine/issues/428) - Thanks @tjgrathwell
|
||||
* Removed an accidental global pollution of `j$` as a reference to Jasmine. Thanks to Morten Maxild from the mailing list
|
||||
* There is now a consistent `this` between `beforeEach`, `it` and `afterEach` for a spec
|
||||
* A spy's strategy now has properties `returnValue` and `throwError` because they are better names
|
||||
* Make it easy to copy the title of failing specs from the HTML output
|
||||
* Don't add periods to the full name of a spec fix #[427](https://github.com/pivotal/jasmine/issues/427)
|
||||
* Allow Env to take optional spec/suite ids when asked to `execute`
|
||||
* [Mock clock now less intrusive, replacing global timer functions only when clock is installed](http://www.pivotaltracker.com/story/54168708)
|
||||
* Restore custom failure messages for `toHaveBeenCalledWith`
|
||||
* Jasmine global object has a addCustomEqualityTester and addMatchers (no longer directly on global)
|
||||
* Fixed a global leak of `timer`
|
||||
* Remove currentRunner from Env (users can use topSuite from Env instead)
|
||||
* [Specs without expectations are now considered passing](http://www.pivotaltracker.com/story/59422744)
|
||||
* Improve error message when a spec does not call the async callback within the default time interval
|
||||
* Allow passing a negativeCompare in a custom matcher for more custom implementations when `.not` is called
|
||||
* Update favicon to be higher resolution
|
||||
* Make all async functions be subject to the timeout
|
||||
|
||||
There were several other pull requests that either had already been fixed, or were good starting points for the various changes above. Thank you for all of the hard work to keep Jasmine awesome.
|
||||
|
||||
## Other Bugs and Features
|
||||
|
||||
There were a few small changes and fixes that didn't fit into any of the above categories:
|
||||
|
||||
* HTML Reporter refactored for simplicity and performance
|
||||
* Default character encoding on the HTML runner page is UTF-8
|
||||
* [Escape special regex characters from the spec param](http://www.pivotaltracker.com/story/52731407)
|
||||
* Favicon returns
|
||||
* [Clock supports `eval`'d strings as functions](http://www.pivotaltracker.com/story/40853563)
|
||||
* There should always be stack traces on failures
|
||||
* Removed references to unused `jasmine.VERBOSE`
|
||||
* Removed references to unused `jasmine.XmlHttpRequest`
|
||||
|
||||
[mocha]: http://visionmedia.github.io/mocha/
|
||||
[underscore]: http://underscorejs.org/
|
||||
[grunt]: http://gruntjs.com
|
||||
[node]: http://nodejs.org
|
||||
[phantom]: http://phantomjs.org
|
||||
[jasmine_downloads]: https://github.com/pivotal/jasmine/downloads
|
||||
[contrib]: https://github.com/pivotal/jasmine/blob/master/CONTRIBUTING.md
|
||||
[travis]: http://travis-ci.org
|
||||
[travis_jasmine]: http://travis-ci.org/jasmine
|
||||
[sauce]: http://saucelabs.com
|
||||
[node_suite]: https://github.com/pivotal/jasmine/blob/master/spec/node_suite.js
|
||||
[intro]: http://jasmine.github.io/2.0/introduction.html
|
||||
|
||||
------
|
||||
|
||||
_Release Notes generated with [Anchorman](http://github.com/infews/anchorman)_
|
||||
@@ -0,0 +1 @@
|
||||
ordereddict==1.1
|
||||
@@ -0,0 +1,47 @@
|
||||
from setuptools import setup, find_packages, os
|
||||
import json
|
||||
|
||||
with open('package.json') as packageFile:
|
||||
version = json.load(packageFile)['version']
|
||||
|
||||
setup(
|
||||
name="jasmine-core",
|
||||
version=version,
|
||||
url="http://pivotal.github.io/jasmine/",
|
||||
author="Pivotal Labs",
|
||||
author_email="jasmine-js@googlegroups.com",
|
||||
description=('Jasmine is a Behavior Driven Development testing framework for JavaScript. It does not rely on '+
|
||||
'browsers, DOM, or any JavaScript framework. Thus it\'s suited for websites, '+
|
||||
'Node.js (http://nodejs.org) projects, or anywhere that JavaScript can run.'),
|
||||
license='MIT',
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Console',
|
||||
'Environment :: Web Environment',
|
||||
'Framework :: Django',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Software Development :: Build Tools',
|
||||
'Topic :: Software Development :: Quality Assurance',
|
||||
'Topic :: Software Development :: Testing',
|
||||
],
|
||||
|
||||
packages=['jasmine_core', 'jasmine_core.images'],
|
||||
package_dir={'jasmine_core': 'lib/jasmine-core', 'jasmine_core.images': 'images'},
|
||||
package_data={'jasmine_core': ['*.js', '*.css'], 'jasmine_core.images': ['*.png']},
|
||||
|
||||
include_package_data=True,
|
||||
|
||||
install_requires=['glob2>=0.4.1', 'ordereddict==1.1']
|
||||
)
|
||||
@@ -0,0 +1,238 @@
|
||||
describe("ConsoleReporter", function() {
|
||||
var out;
|
||||
|
||||
beforeEach(function() {
|
||||
out = (function() {
|
||||
var output = "";
|
||||
return {
|
||||
print: function(str) {
|
||||
output += str;
|
||||
},
|
||||
getOutput: function() {
|
||||
return output;
|
||||
},
|
||||
clear: function() {
|
||||
output = "";
|
||||
}
|
||||
};
|
||||
}());
|
||||
});
|
||||
|
||||
it("reports that the suite has started to the console", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
|
||||
expect(out.getOutput()).toEqual("Started\n");
|
||||
});
|
||||
|
||||
it("starts the provided timer when jasmine starts", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start']),
|
||||
reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
|
||||
expect(timerSpy.start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports a passing spec as a dot", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.specDone({status: "passed"});
|
||||
|
||||
expect(out.getOutput()).toEqual(".");
|
||||
});
|
||||
|
||||
it("does not report a disabled spec", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.specDone({status: "disabled"});
|
||||
|
||||
expect(out.getOutput()).toEqual("");
|
||||
});
|
||||
|
||||
it("reports a failing spec as an 'F'", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.specDone({status: "failed"});
|
||||
|
||||
expect(out.getOutput()).toEqual("F");
|
||||
});
|
||||
|
||||
it("reports a pending spec as a '*'", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.specDone({status: "pending"});
|
||||
|
||||
expect(out.getOutput()).toEqual("*");
|
||||
});
|
||||
|
||||
it("alerts user if there are no specs", function(){
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
out.clear();
|
||||
reporter.jasmineDone();
|
||||
|
||||
expect(out.getOutput()).toMatch(/No specs found/);
|
||||
});
|
||||
|
||||
it("reports a summary when done (singular spec and time)", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
reporter.specDone({status: "passed"});
|
||||
|
||||
timerSpy.elapsed.and.returnValue(1000);
|
||||
|
||||
out.clear();
|
||||
reporter.jasmineDone();
|
||||
|
||||
expect(out.getOutput()).toMatch(/1 spec, 0 failures/);
|
||||
expect(out.getOutput()).not.toMatch(/0 pending specs/);
|
||||
expect(out.getOutput()).toMatch("Finished in 1 second\n");
|
||||
});
|
||||
|
||||
it("reports a summary when done (pluralized specs and seconds)", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
reporter.specDone({status: "passed"});
|
||||
reporter.specDone({status: "pending"});
|
||||
reporter.specDone({
|
||||
status: "failed",
|
||||
description: "with a failing spec",
|
||||
fullName: "A suite with a failing spec",
|
||||
failedExpectations: [
|
||||
{
|
||||
passed: false,
|
||||
message: "Expected true to be false.",
|
||||
expected: false,
|
||||
actual: true,
|
||||
stack: "foo\nbar\nbaz"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
out.clear();
|
||||
|
||||
timerSpy.elapsed.and.returnValue(100);
|
||||
|
||||
reporter.jasmineDone();
|
||||
|
||||
expect(out.getOutput()).toMatch(/3 specs, 1 failure, 1 pending spec/);
|
||||
expect(out.getOutput()).toMatch("Finished in 0.1 seconds\n");
|
||||
});
|
||||
|
||||
it("reports a summary when done that includes stack traces for a failing suite", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
reporter.specDone({status: "passed"});
|
||||
reporter.specDone({
|
||||
status: "failed",
|
||||
description: "with a failing spec",
|
||||
fullName: "A suite with a failing spec",
|
||||
failedExpectations: [
|
||||
{
|
||||
passed: false,
|
||||
message: "Expected true to be false.",
|
||||
expected: false,
|
||||
actual: true,
|
||||
stack: "foo bar baz"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
out.clear();
|
||||
|
||||
reporter.jasmineDone({});
|
||||
|
||||
expect(out.getOutput()).toMatch(/foo bar baz/);
|
||||
});
|
||||
|
||||
it("calls the onComplete callback when the suite is done", function() {
|
||||
var onComplete = jasmine.createSpy('onComplete'),
|
||||
reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
onComplete: onComplete
|
||||
});
|
||||
|
||||
reporter.jasmineDone({});
|
||||
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
describe("with color", function() {
|
||||
|
||||
it("reports that the suite has started to the console", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
showColors: true
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
|
||||
expect(out.getOutput()).toEqual("Started\n");
|
||||
});
|
||||
|
||||
it("reports a passing spec as a dot", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
showColors: true
|
||||
});
|
||||
|
||||
reporter.specDone({status: "passed"});
|
||||
|
||||
expect(out.getOutput()).toEqual("\x1B[32m.\x1B[0m");
|
||||
});
|
||||
|
||||
it("does not report a disabled spec", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
showColors: true
|
||||
});
|
||||
|
||||
reporter.specDone({status: 'disabled'});
|
||||
|
||||
expect(out.getOutput()).toEqual("");
|
||||
});
|
||||
|
||||
it("reports a failing spec as an 'F'", function() {
|
||||
var reporter = new j$.ConsoleReporter({
|
||||
print: out.print,
|
||||
showColors: true
|
||||
});
|
||||
|
||||
reporter.specDone({status: 'failed'});
|
||||
|
||||
expect(out.getOutput()).toEqual("\x1B[31mF\x1B[0m");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
describe("Any", function() {
|
||||
it("matches a string", function() {
|
||||
var any = new j$.Any(String);
|
||||
|
||||
expect(any.jasmineMatches("foo")).toBe(true);
|
||||
});
|
||||
|
||||
it("matches a number", function() {
|
||||
var any = new j$.Any(Number);
|
||||
|
||||
expect(any.jasmineMatches(1)).toBe(true);
|
||||
});
|
||||
|
||||
it("matches a function", function() {
|
||||
var any = new j$.Any(Function);
|
||||
|
||||
expect(any.jasmineMatches(function(){})).toBe(true);
|
||||
});
|
||||
|
||||
it("matches an Object", function() {
|
||||
var any = new j$.Any(Object);
|
||||
|
||||
expect(any.jasmineMatches({})).toBe(true);
|
||||
});
|
||||
|
||||
it("matches a Boolean", function() {
|
||||
var any = new j$.Any(Boolean);
|
||||
|
||||
expect(any.jasmineMatches(true)).toBe(true);
|
||||
});
|
||||
|
||||
it("matches another constructed object", function() {
|
||||
var Thing = function() {},
|
||||
any = new j$.Any(Thing);
|
||||
|
||||
expect(any.jasmineMatches(new Thing())).toBe(true);
|
||||
});
|
||||
|
||||
it("jasmineToString's itself", function() {
|
||||
var any = new j$.Any(Number);
|
||||
|
||||
expect(any.jasmineToString()).toMatch('<jasmine.any');
|
||||
expect(any.jasmineToString()).toMatch('Number');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
describe("CallTracker", function() {
|
||||
it("tracks that it was called when executed", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
expect(callTracker.any()).toBe(false);
|
||||
|
||||
callTracker.track();
|
||||
|
||||
expect(callTracker.any()).toBe(true);
|
||||
});
|
||||
|
||||
it("tracks that number of times that it is executed", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
expect(callTracker.count()).toEqual(0);
|
||||
|
||||
callTracker.track();
|
||||
|
||||
expect(callTracker.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it("tracks the params from each execution", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track({object: void 0, args: []});
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
|
||||
expect(callTracker.argsFor(0)).toEqual([]);
|
||||
|
||||
expect(callTracker.argsFor(1)).toEqual([0, "foo"]);
|
||||
});
|
||||
|
||||
it("returns any empty array when there was no call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
expect(callTracker.argsFor(0)).toEqual([]);
|
||||
});
|
||||
|
||||
it("allows access for the arguments for all calls", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track({object: {}, args: []});
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
|
||||
expect(callTracker.allArgs()).toEqual([[], [0, "foo"]]);
|
||||
});
|
||||
|
||||
it("tracks the context and arguments for each call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track({object: {}, args: []});
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
|
||||
expect(callTracker.all()[0]).toEqual({object: {}, args: []});
|
||||
|
||||
expect(callTracker.all()[1]).toEqual({object: {}, args: [0, "foo"]});
|
||||
});
|
||||
|
||||
it("simplifies access to the arguments for the last (most recent) call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track();
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
|
||||
expect(callTracker.mostRecent()).toEqual({
|
||||
object: {},
|
||||
args: [0, "foo"]
|
||||
});
|
||||
});
|
||||
|
||||
it("returns a useful falsy value when there isn't a last (most recent) call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
expect(callTracker.mostRecent()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("simplifies access to the arguments for the first (oldest) call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
|
||||
expect(callTracker.first()).toEqual({object: {}, args: [0, "foo"]})
|
||||
});
|
||||
|
||||
it("returns a useful falsy value when there isn't a first (oldest) call", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
expect(callTracker.first()).toBeFalsy();
|
||||
});
|
||||
|
||||
|
||||
it("allows the tracking to be reset", function() {
|
||||
var callTracker = new j$.CallTracker();
|
||||
|
||||
callTracker.track();
|
||||
callTracker.track({object: {}, args: [0, "foo"]});
|
||||
callTracker.reset();
|
||||
|
||||
expect(callTracker.any()).toBe(false);
|
||||
expect(callTracker.count()).toEqual(0);
|
||||
expect(callTracker.argsFor(0)).toEqual([]);
|
||||
expect(callTracker.all()).toEqual([]);
|
||||
expect(callTracker.mostRecent()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,445 @@
|
||||
describe("Clock", function() {
|
||||
|
||||
it("does not replace setTimeout until it is installed", function() {
|
||||
var fakeSetTimeout = jasmine.createSpy("global setTimeout"),
|
||||
fakeGlobal = { setTimeout: fakeSetTimeout },
|
||||
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction"]),
|
||||
delayedFn = jasmine.createSpy("delayedFn"),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
fakeGlobal.setTimeout(delayedFn, 0);
|
||||
|
||||
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
||||
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
||||
|
||||
fakeSetTimeout.calls.reset();
|
||||
|
||||
clock.install();
|
||||
fakeGlobal.setTimeout(delayedFn, 0);
|
||||
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
||||
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not replace clearTimeout until it is installed", function() {
|
||||
var fakeClearTimeout = jasmine.createSpy("global cleartimeout"),
|
||||
fakeGlobal = { clearTimeout: fakeClearTimeout },
|
||||
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["removeFunctionWithId"]),
|
||||
delayedFn = jasmine.createSpy("delayedFn"),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
fakeGlobal.clearTimeout("foo");
|
||||
|
||||
expect(fakeClearTimeout).toHaveBeenCalledWith("foo");
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).not.toHaveBeenCalled();
|
||||
|
||||
fakeClearTimeout.calls.reset();
|
||||
|
||||
clock.install();
|
||||
fakeGlobal.clearTimeout("foo");
|
||||
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled();
|
||||
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not replace setInterval until it is installed", function() {
|
||||
var fakeSetInterval = jasmine.createSpy("global setInterval"),
|
||||
fakeGlobal = { setInterval: fakeSetInterval },
|
||||
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction"]),
|
||||
delayedFn = jasmine.createSpy("delayedFn"),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
fakeGlobal.setInterval(delayedFn, 0);
|
||||
|
||||
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 0);
|
||||
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
||||
|
||||
fakeSetInterval.calls.reset();
|
||||
|
||||
clock.install();
|
||||
fakeGlobal.setInterval(delayedFn, 0);
|
||||
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
||||
expect(fakeSetInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not replace clearInterval until it is installed", function() {
|
||||
var fakeClearInterval = jasmine.createSpy("global clearinterval"),
|
||||
fakeGlobal = { clearInterval: fakeClearInterval },
|
||||
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["removeFunctionWithId"]),
|
||||
delayedFn = jasmine.createSpy("delayedFn"),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
fakeGlobal.clearInterval("foo");
|
||||
|
||||
expect(fakeClearInterval).toHaveBeenCalledWith("foo");
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).not.toHaveBeenCalled();
|
||||
|
||||
fakeClearInterval.calls.reset();
|
||||
|
||||
clock.install();
|
||||
fakeGlobal.clearInterval("foo");
|
||||
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled();
|
||||
expect(fakeClearInterval).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("replaces the global timer functions on uninstall", function() {
|
||||
var fakeSetTimeout = jasmine.createSpy("global setTimeout"),
|
||||
fakeClearTimeout = jasmine.createSpy("global clearTimeout"),
|
||||
fakeSetInterval = jasmine.createSpy("global setInterval"),
|
||||
fakeClearInterval = jasmine.createSpy("global clearInterval"),
|
||||
fakeGlobal = {
|
||||
setTimeout: fakeSetTimeout,
|
||||
clearTimeout: fakeClearTimeout,
|
||||
setInterval: fakeSetInterval,
|
||||
clearInterval: fakeClearInterval
|
||||
},
|
||||
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction", "reset"]),
|
||||
delayedFn = jasmine.createSpy("delayedFn"),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
clock.uninstall();
|
||||
fakeGlobal.setTimeout(delayedFn, 0);
|
||||
fakeGlobal.clearTimeout("foo");
|
||||
fakeGlobal.setInterval(delayedFn, 10);
|
||||
fakeGlobal.clearInterval("bar");
|
||||
|
||||
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
||||
expect(fakeClearTimeout).toHaveBeenCalledWith("foo");
|
||||
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10);
|
||||
expect(fakeClearInterval).toHaveBeenCalledWith("bar");
|
||||
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("schedules the delayed function (via setTimeout) with the fake timer", function() {
|
||||
var fakeSetTimeout = jasmine.createSpy('setTimeout'),
|
||||
scheduleFunction = jasmine.createSpy('scheduleFunction'),
|
||||
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
|
||||
fakeGlobal = { setTimeout: fakeSetTimeout },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
clock.setTimeout(delayedFn, 0, 'a', 'b');
|
||||
|
||||
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b']);
|
||||
});
|
||||
|
||||
it("returns an id for the delayed function", function() {
|
||||
var fakeSetTimeout = jasmine.createSpy('setTimeout'),
|
||||
scheduleId = 123,
|
||||
scheduleFunction = jasmine.createSpy('scheduleFunction').and.returnValue(scheduleId),
|
||||
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
|
||||
fakeGlobal = { setTimeout: fakeSetTimeout },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate),
|
||||
timeoutId;
|
||||
|
||||
clock.install();
|
||||
timeoutId = clock.setTimeout(delayedFn, 0);
|
||||
|
||||
expect(timeoutId).toEqual(123);
|
||||
});
|
||||
|
||||
it("clears the scheduled function with the scheduler", function() {
|
||||
var fakeClearTimeout = jasmine.createSpy('clearTimeout'),
|
||||
delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['removeFunctionWithId']),
|
||||
fakeGlobal = { setTimeout: fakeClearTimeout },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
clock.clearTimeout(123);
|
||||
|
||||
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalledWith(123);
|
||||
});
|
||||
|
||||
it("schedules the delayed function with the fake timer", function() {
|
||||
var fakeSetInterval = jasmine.createSpy('setInterval'),
|
||||
scheduleFunction = jasmine.createSpy('scheduleFunction'),
|
||||
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
|
||||
fakeGlobal = { setInterval: fakeSetInterval },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
clock.setInterval(delayedFn, 0, 'a', 'b');
|
||||
|
||||
expect(fakeSetInterval).not.toHaveBeenCalled();
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(delayedFn, 0, ['a', 'b'], true);
|
||||
});
|
||||
|
||||
it("returns an id for the delayed function", function() {
|
||||
var fakeSetInterval = jasmine.createSpy('setInterval'),
|
||||
scheduleId = 123,
|
||||
scheduleFunction = jasmine.createSpy('scheduleFunction').and.returnValue(scheduleId),
|
||||
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
|
||||
fakeGlobal = { setInterval: fakeSetInterval },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate),
|
||||
intervalId;
|
||||
|
||||
clock.install();
|
||||
intervalId = clock.setInterval(delayedFn, 0);
|
||||
|
||||
expect(intervalId).toEqual(123);
|
||||
});
|
||||
|
||||
it("clears the scheduled function with the scheduler", function() {
|
||||
var clearInterval = jasmine.createSpy('clearInterval'),
|
||||
delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['removeFunctionWithId']),
|
||||
fakeGlobal = { setInterval: clearInterval },
|
||||
delayedFn = jasmine.createSpy('delayedFn'),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
clock.clearInterval(123);
|
||||
|
||||
expect(clearInterval).not.toHaveBeenCalled();
|
||||
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalledWith(123);
|
||||
});
|
||||
|
||||
it("gives you a friendly reminder if the Clock is not installed and you tick", function() {
|
||||
var clock = new j$.Clock({}, jasmine.createSpyObj('delayedFunctionScheduler', ['tick']));
|
||||
expect(function() {
|
||||
clock.tick(50);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it("on IE < 9, fails if extra args are passed to fake clock", function() {
|
||||
//fail, because this would break in IE9.
|
||||
var fakeSetTimeout = jasmine.createSpy('setTimeout'),
|
||||
fakeSetInterval = jasmine.createSpy('setInterval'),
|
||||
delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['scheduleFunction']),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
fakeGlobal = {
|
||||
setTimeout: fakeSetTimeout,
|
||||
setInterval: fakeSetInterval
|
||||
},
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
|
||||
|
||||
fakeSetTimeout.apply = null;
|
||||
fakeSetInterval.apply = null;
|
||||
|
||||
clock.install();
|
||||
|
||||
clock.setTimeout(fn, 0);
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, []);
|
||||
expect(function() {
|
||||
clock.setTimeout(fn, 0, 'extra');
|
||||
}).toThrow();
|
||||
|
||||
clock.setInterval(fn, 0);
|
||||
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(fn, 0, [], true);
|
||||
expect(function() {
|
||||
clock.setInterval(fn, 0, 'extra');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Clock (acceptance)", function() {
|
||||
it("can run setTimeouts/setIntervals synchronously", function() {
|
||||
var delayedFn1 = jasmine.createSpy('delayedFn1'),
|
||||
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
||||
delayedFn3 = jasmine.createSpy('delayedFn3'),
|
||||
recurring1 = jasmine.createSpy('recurring1'),
|
||||
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
|
||||
clock.setTimeout(delayedFn1, 0);
|
||||
var intervalId = clock.setInterval(recurring1, 50);
|
||||
clock.setTimeout(delayedFn2, 100);
|
||||
clock.setTimeout(delayedFn3, 200);
|
||||
|
||||
expect(delayedFn1).not.toHaveBeenCalled();
|
||||
expect(delayedFn2).not.toHaveBeenCalled();
|
||||
expect(delayedFn3).not.toHaveBeenCalled();
|
||||
|
||||
clock.tick(0);
|
||||
|
||||
expect(delayedFn1).toHaveBeenCalled();
|
||||
expect(delayedFn2).not.toHaveBeenCalled();
|
||||
expect(delayedFn3).not.toHaveBeenCalled();
|
||||
|
||||
clock.tick(50);
|
||||
|
||||
expect(recurring1).toHaveBeenCalled();
|
||||
expect(recurring1.calls.count()).toBe(1);
|
||||
expect(delayedFn2).not.toHaveBeenCalled();
|
||||
expect(delayedFn3).not.toHaveBeenCalled();
|
||||
|
||||
clock.tick(50);
|
||||
|
||||
expect(recurring1.calls.count()).toBe(2);
|
||||
expect(delayedFn2).toHaveBeenCalled();
|
||||
expect(delayedFn3).not.toHaveBeenCalled();
|
||||
|
||||
clock.tick(100);
|
||||
|
||||
expect(recurring1.calls.count()).toBe(4);
|
||||
expect(delayedFn3).toHaveBeenCalled();
|
||||
|
||||
clock.clearInterval(intervalId);
|
||||
clock.tick(50);
|
||||
|
||||
expect(recurring1.calls.count()).toBe(4);
|
||||
});
|
||||
|
||||
it("can clear a previously set timeout", function() {
|
||||
var clearedFn = jasmine.createSpy('clearedFn'),
|
||||
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate),
|
||||
timeoutId;
|
||||
|
||||
clock.install();
|
||||
|
||||
timeoutId = clock.setTimeout(clearedFn, 100);
|
||||
expect(clearedFn).not.toHaveBeenCalled();
|
||||
|
||||
clock.clearTimeout(timeoutId);
|
||||
clock.tick(100);
|
||||
|
||||
expect(clearedFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("correctly schedules functions after the Clock has advanced", function() {
|
||||
var delayedFn1 = jasmine.createSpy('delayedFn1'),
|
||||
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
|
||||
clock.tick(100);
|
||||
clock.setTimeout(delayedFn1, 10, ['some', 'arg']);
|
||||
clock.tick(5);
|
||||
expect(delayedFn1).not.toHaveBeenCalled();
|
||||
clock.tick(5);
|
||||
expect(delayedFn1).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("correctly schedules functions while the Clock is advancing", function() {
|
||||
var delayedFn1 = jasmine.createSpy('delayedFn1'),
|
||||
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
||||
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 0); });
|
||||
clock.install();
|
||||
clock.setTimeout(delayedFn1, 5);
|
||||
|
||||
clock.tick(5);
|
||||
expect(delayedFn1).toHaveBeenCalled();
|
||||
expect(delayedFn2).not.toHaveBeenCalled();
|
||||
|
||||
clock.tick();
|
||||
expect(delayedFn2).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("correctly calls functions scheduled while the Clock is advancing", function() {
|
||||
var delayedFn1 = jasmine.createSpy('delayedFn1'),
|
||||
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
||||
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
|
||||
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 1); });
|
||||
clock.install();
|
||||
clock.setTimeout(delayedFn1, 5);
|
||||
|
||||
clock.tick(6);
|
||||
expect(delayedFn1).toHaveBeenCalled();
|
||||
expect(delayedFn2).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not mock the Date object by default", function() {
|
||||
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
global = {Date: Date},
|
||||
mockDate = new j$.MockDate(global),
|
||||
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install();
|
||||
|
||||
expect(global.Date).toEqual(Date);
|
||||
|
||||
var now = new global.Date().getTime();
|
||||
|
||||
clock.tick(50);
|
||||
|
||||
expect(new global.Date().getTime() - now).not.toEqual(50);
|
||||
});
|
||||
|
||||
it("mocks the Date object and sets it to current time", function() {
|
||||
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
global = {Date: Date},
|
||||
mockDate = new j$.MockDate(global),
|
||||
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate);
|
||||
|
||||
clock.install().mockDate();
|
||||
|
||||
var now = new global.Date().getTime();
|
||||
|
||||
clock.tick(50);
|
||||
|
||||
expect(new global.Date().getTime() - now).toEqual(50);
|
||||
|
||||
var timeoutDate = 0;
|
||||
clock.setTimeout(function() {
|
||||
timeoutDate = new global.Date().getTime();
|
||||
}, 100);
|
||||
|
||||
clock.tick(100);
|
||||
|
||||
expect(timeoutDate - now).toEqual(150);
|
||||
});
|
||||
|
||||
it("mocks the Date object and sets it to a given time", function() {
|
||||
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
|
||||
global = {Date: Date},
|
||||
mockDate = new j$.MockDate(global),
|
||||
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate),
|
||||
baseTime = new Date(2013, 9, 23);
|
||||
|
||||
|
||||
clock.install().mockDate(baseTime);
|
||||
|
||||
var now = new global.Date().getTime();
|
||||
|
||||
expect(now).toEqual(baseTime.getTime());
|
||||
|
||||
clock.tick(50);
|
||||
|
||||
expect(new global.Date().getTime()).toEqual(baseTime.getTime() + 50);
|
||||
|
||||
var timeoutDate = 0;
|
||||
clock.setTimeout(function() {
|
||||
timeoutDate = new global.Date().getTime();
|
||||
}, 100);
|
||||
|
||||
clock.tick(100);
|
||||
|
||||
expect(timeoutDate).toEqual(baseTime.getTime() + 150);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,246 @@
|
||||
describe("DelayedFunctionScheduler", function() {
|
||||
it("schedules a function for later execution", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn, 0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("schedules a string for later execution", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
strfn = "horrible = true;";
|
||||
|
||||
scheduler.scheduleFunction(strfn, 0);
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(horrible).toEqual(true);
|
||||
});
|
||||
|
||||
it("#tick defaults to 0", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn, 0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick();
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("defaults delay to 0", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("optionally passes params to scheduled functions", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn, 0, ['foo', 'bar']);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(fn).toHaveBeenCalledWith('foo', 'bar');
|
||||
});
|
||||
|
||||
it("scheduled fns can optionally reoccur", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn, 20, [], true);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(20);
|
||||
|
||||
expect(fn.calls.count()).toBe(1);
|
||||
|
||||
scheduler.tick(40);
|
||||
|
||||
expect(fn.calls.count()).toBe(3);
|
||||
|
||||
scheduler.tick(21);
|
||||
|
||||
expect(fn.calls.count()).toBe(4);
|
||||
|
||||
});
|
||||
|
||||
it("increments scheduled fns ids unless one is passed", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler();
|
||||
|
||||
expect(scheduler.scheduleFunction(function() {
|
||||
}, 0)).toBe(1);
|
||||
expect(scheduler.scheduleFunction(function() {
|
||||
}, 0)).toBe(2);
|
||||
expect(scheduler.scheduleFunction(function() {
|
||||
}, 0, [], false, 123)).toBe(123);
|
||||
expect(scheduler.scheduleFunction(function() {
|
||||
}, 0)).toBe(3);
|
||||
});
|
||||
|
||||
it("#removeFunctionWithId removes a previously scheduled function with a given id", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
timeoutKey;
|
||||
|
||||
timeoutKey = scheduler.scheduleFunction(fn, 0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.removeFunctionWithId(timeoutKey);
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reset removes scheduled functions", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
scheduler.scheduleFunction(fn, 0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.reset();
|
||||
|
||||
scheduler.tick(0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reset resets the returned ids", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler();
|
||||
expect(scheduler.scheduleFunction(function() { }, 0)).toBe(1);
|
||||
expect(scheduler.scheduleFunction(function() { }, 0, [], false, 123)).toBe(123);
|
||||
|
||||
scheduler.reset();
|
||||
expect(scheduler.scheduleFunction(function() { }, 0)).toBe(1);
|
||||
expect(scheduler.scheduleFunction(function() { }, 0, [], false, 123)).toBe(123);
|
||||
});
|
||||
|
||||
it("reset resets the current tick time", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn');
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(15);
|
||||
scheduler.reset();
|
||||
|
||||
scheduler.scheduleFunction(fn, 20, [], false, 1, 20);
|
||||
|
||||
scheduler.tick(5);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("executes recurring functions interleaved with regular functions in the correct order", function() {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
recurringCallCount = 0,
|
||||
recurring = jasmine.createSpy('recurring').and.callFake(function() {
|
||||
recurringCallCount++;
|
||||
if (recurringCallCount < 5) {
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
|
||||
scheduler.scheduleFunction(recurring, 10, [], true);
|
||||
scheduler.scheduleFunction(fn, 50);
|
||||
|
||||
scheduler.tick(60);
|
||||
|
||||
expect(recurring).toHaveBeenCalled();
|
||||
expect(recurring.calls.count()).toBe(6);
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("schedules a function for later execution during a tick", function () {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
fnDelay = 10;
|
||||
|
||||
scheduler.scheduleFunction(function () {
|
||||
scheduler.scheduleFunction(fn, fnDelay);
|
||||
}, 0);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(fnDelay);
|
||||
|
||||
expect(fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("#removeFunctionWithId removes a previously scheduled function with a given id during a tick", function () {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
fnDelay = 10,
|
||||
timeoutKey;
|
||||
|
||||
scheduler.scheduleFunction(function () {
|
||||
scheduler.removeFunctionWithId(timeoutKey);
|
||||
}, 0);
|
||||
timeoutKey = scheduler.scheduleFunction(fn, fnDelay);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
|
||||
scheduler.tick(fnDelay);
|
||||
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("executes recurring functions interleaved with regular functions and functions scheduled during a tick in the correct order", function () {
|
||||
var scheduler = new j$.DelayedFunctionScheduler(),
|
||||
fn = jasmine.createSpy('fn'),
|
||||
recurringCallCount = 0,
|
||||
recurring = jasmine.createSpy('recurring').and.callFake(function() {
|
||||
recurringCallCount++;
|
||||
if (recurringCallCount < 5) {
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
}
|
||||
}),
|
||||
innerFn = jasmine.createSpy('innerFn').and.callFake(function() {
|
||||
expect(recurring.calls.count()).toBe(4);
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
}),
|
||||
scheduling = jasmine.createSpy('scheduling').and.callFake(function() {
|
||||
expect(recurring.calls.count()).toBe(3);
|
||||
expect(fn).not.toHaveBeenCalled();
|
||||
scheduler.scheduleFunction(innerFn, 10); // 41ms absolute
|
||||
});
|
||||
|
||||
scheduler.scheduleFunction(recurring, 10, [], true);
|
||||
scheduler.scheduleFunction(fn, 50);
|
||||
scheduler.scheduleFunction(scheduling, 31);
|
||||
|
||||
scheduler.tick(60);
|
||||
|
||||
expect(recurring).toHaveBeenCalled();
|
||||
expect(recurring.calls.count()).toBe(6);
|
||||
expect(fn).toHaveBeenCalled();
|
||||
expect(scheduling).toHaveBeenCalled();
|
||||
expect(innerFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// TODO: Fix these unit tests!
|
||||
describe("Env", function() {
|
||||
var env;
|
||||
beforeEach(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() {
|
||||
env.pending();
|
||||
}).toThrow(j$.Spec.pendingSpecExceptionMessage);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#topSuite", function() {
|
||||
it("returns the Jasmine top suite for users to traverse the spec tree", function() {
|
||||
var suite = env.topSuite();
|
||||
expect(suite.description).toEqual('Jasmine__TopLevel__Suite');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
describe("ExceptionFormatter", function() {
|
||||
describe("#message", function() {
|
||||
it('formats Firefox exception messages', function() {
|
||||
var sampleFirefoxException = {
|
||||
fileName: 'foo.js',
|
||||
lineNumber: '1978',
|
||||
message: 'you got your foo in my bar',
|
||||
name: 'A Classic Mistake'
|
||||
},
|
||||
exceptionFormatter = new j$.ExceptionFormatter(),
|
||||
message = exceptionFormatter.message(sampleFirefoxException);
|
||||
|
||||
expect(message).toEqual('A Classic Mistake: you got your foo in my bar in foo.js (line 1978)');
|
||||
});
|
||||
|
||||
it('formats Webkit exception messages', function() {
|
||||
var sampleWebkitException = {
|
||||
sourceURL: 'foo.js',
|
||||
line: '1978',
|
||||
message: 'you got your foo in my bar',
|
||||
name: 'A Classic Mistake'
|
||||
},
|
||||
exceptionFormatter = new j$.ExceptionFormatter(),
|
||||
message = exceptionFormatter.message(sampleWebkitException);
|
||||
|
||||
expect(message).toEqual('A Classic Mistake: you got your foo in my bar in foo.js (line 1978)');
|
||||
});
|
||||
|
||||
it('formats V8 exception messages', function() {
|
||||
var sampleV8 = {
|
||||
message: 'you got your foo in my bar',
|
||||
name: 'A Classic Mistake'
|
||||
},
|
||||
exceptionFormatter = new j$.ExceptionFormatter(),
|
||||
message = exceptionFormatter.message(sampleV8);
|
||||
|
||||
expect(message).toEqual('A Classic Mistake: you got your foo in my bar');
|
||||
});
|
||||
|
||||
it("formats thrown exceptions that aren't errors", function() {
|
||||
var thrown = "crazy error",
|
||||
exceptionFormatter = new j$.ExceptionFormatter(),
|
||||
message = exceptionFormatter.message(thrown);
|
||||
|
||||
expect(message).toEqual("crazy error thrown");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#stack", function() {
|
||||
it("formats stack traces from Webkit, Firefox, node.js or IE10+", function() {
|
||||
if (jasmine.getEnv().ieVersion < 10 || jasmine.getEnv().safariVersion < 6) { return; }
|
||||
|
||||
var error;
|
||||
try { throw new Error("an error") } catch(e) { error = e; }
|
||||
|
||||
expect(new j$.ExceptionFormatter().stack(error)).toMatch(/ExceptionFormatterSpec\.js.*\d+/)
|
||||
});
|
||||
|
||||
it("returns null if no Error provided", function() {
|
||||
expect(new j$.ExceptionFormatter().stack()).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
describe('Exceptions:', function() {
|
||||
var env;
|
||||
|
||||
beforeEach(function() {
|
||||
env = new j$.Env();
|
||||
});
|
||||
|
||||
describe('with break on exception', function() {
|
||||
it('should not catch the exception', function() {
|
||||
env.catchExceptions(false);
|
||||
env.describe('suite for break on exceptions', function() {
|
||||
env.it('should break when an exception is thrown', function() {
|
||||
throw new Error('I should hit a breakpoint!');
|
||||
});
|
||||
});
|
||||
var spy = jasmine.createSpy('spy');
|
||||
|
||||
try {
|
||||
env.execute();
|
||||
spy();
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with catch on exception", function() {
|
||||
it('should handle exceptions thrown, but continue', function(done) {
|
||||
var secondTest = jasmine.createSpy('second test');
|
||||
env.describe('Suite for handles exceptions', function () {
|
||||
env.it('should be a test that fails because it throws an exception', function() {
|
||||
throw new Error();
|
||||
});
|
||||
env.it('should be a passing test that runs after exceptions are thrown from a async test', secondTest);
|
||||
});
|
||||
|
||||
var expectations = function() {
|
||||
expect(secondTest).toHaveBeenCalled();
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({ jasmineDone: expectations });
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should handle exceptions thrown directly in top-level describe blocks and continue", function(done) {
|
||||
var secondDescribe = jasmine.createSpy("second describe");
|
||||
env.describe("a suite that throws an exception", function () {
|
||||
env.it("is a test that should pass", function () {
|
||||
this.expect(true).toEqual(true);
|
||||
});
|
||||
|
||||
throw new Error("top level error");
|
||||
});
|
||||
env.describe("a suite that doesn't throw an exception", secondDescribe);
|
||||
|
||||
var expectations = function() {
|
||||
expect(secondDescribe).toHaveBeenCalled();
|
||||
done();
|
||||
};
|
||||
|
||||
env.addReporter({ jasmineDone: expectations });
|
||||
env.execute();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
describe("buildExpectationResult", function() {
|
||||
it("defaults to passed", function() {
|
||||
var result = j$.buildExpectationResult({passed: 'some-value'});
|
||||
expect(result.passed).toBe('some-value');
|
||||
});
|
||||
|
||||
it("message defaults to Passed for passing specs", function() {
|
||||
var result = j$.buildExpectationResult({passed: true, message: 'some-value'});
|
||||
expect(result.message).toBe('Passed.');
|
||||
});
|
||||
|
||||
it("message returns the message for failing expectations", function() {
|
||||
var result = j$.buildExpectationResult({passed: false, message: 'some-value'});
|
||||
expect(result.message).toBe('some-value');
|
||||
});
|
||||
|
||||
it("delegates message formatting to the provided formatter if there was an Error", function() {
|
||||
var fakeError = {message: 'foo'},
|
||||
messageFormatter = jasmine.createSpy("exception message formatter").and.returnValue(fakeError.message);
|
||||
|
||||
var result = j$.buildExpectationResult(
|
||||
{
|
||||
passed: false,
|
||||
error: fakeError,
|
||||
messageFormatter: messageFormatter
|
||||
});
|
||||
|
||||
expect(messageFormatter).toHaveBeenCalledWith(fakeError);
|
||||
expect(result.message).toEqual('foo');
|
||||
});
|
||||
|
||||
it("delegates stack formatting to the provided formatter if there was an Error", function() {
|
||||
var fakeError = {stack: 'foo'},
|
||||
stackFormatter = jasmine.createSpy("stack formatter").and.returnValue(fakeError.stack);
|
||||
|
||||
var result = j$.buildExpectationResult(
|
||||
{
|
||||
passed: false,
|
||||
error: fakeError,
|
||||
stackFormatter: stackFormatter
|
||||
});
|
||||
|
||||
expect(stackFormatter).toHaveBeenCalledWith(fakeError);
|
||||
expect(result.stack).toEqual('foo');
|
||||
});
|
||||
|
||||
it("matcherName returns passed matcherName", function() {
|
||||
var result = j$.buildExpectationResult({matcherName: 'some-value'});
|
||||
expect(result.matcherName).toBe('some-value');
|
||||
});
|
||||
|
||||
it("expected returns passed expected", function() {
|
||||
var result = j$.buildExpectationResult({expected: 'some-value'});
|
||||
expect(result.expected).toBe('some-value');
|
||||
});
|
||||
|
||||
it("actual returns passed actual", function() {
|
||||
var result = j$.buildExpectationResult({actual: 'some-value'});
|
||||
expect(result.actual).toBe('some-value');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,427 @@
|
||||
describe("Expectation", function() {
|
||||
it(".addMatchers makes matchers available to any expectation", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {},
|
||||
toBar: function() {}
|
||||
},
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({});
|
||||
|
||||
expect(expectation.toFoo).toBeDefined();
|
||||
expect(expectation.toBar).toBeDefined();
|
||||
});
|
||||
|
||||
it(".addCoreMatchers makes matchers available to any expectation", function() {
|
||||
var coreMatchers = {
|
||||
toQuux: function() {}
|
||||
},
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addCoreMatchers(coreMatchers);
|
||||
|
||||
expectation = new j$.Expectation({});
|
||||
|
||||
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();
|
||||
|
||||
expect(builtExpectation instanceof j$.Expectation).toBe(true);
|
||||
expect(builtExpectation.not instanceof j$.Expectation).toBe(true);
|
||||
expect(builtExpectation.not.isNot).toBe(true);
|
||||
});
|
||||
|
||||
it("wraps matchers's compare functions, passing in matcher dependencies", function() {
|
||||
var fakeCompare = function() { return { pass: true }; },
|
||||
matcherFactory = jasmine.createSpy("matcher").and.returnValue({ compare: fakeCompare }),
|
||||
matchers = {
|
||||
toFoo: matcherFactory
|
||||
},
|
||||
util = {},
|
||||
customEqualityTesters = ['a'],
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
util: util,
|
||||
customEqualityTesters: customEqualityTesters,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(matcherFactory).toHaveBeenCalledWith(util, customEqualityTesters)
|
||||
});
|
||||
|
||||
it("wraps matchers's compare functions, passing the actual and expected", function() {
|
||||
var fakeCompare = jasmine.createSpy('fake-compare').and.returnValue({pass: true}),
|
||||
matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: fakeCompare
|
||||
};
|
||||
}
|
||||
},
|
||||
util = {
|
||||
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
util: util,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(fakeCompare).toHaveBeenCalledWith("an actual", "hello");
|
||||
});
|
||||
|
||||
it("reports a passing result to the spec when the comparison passes", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: true }; }
|
||||
};
|
||||
}
|
||||
},
|
||||
util = {
|
||||
buildFailureMessage: jasmine.createSpy('buildFailureMessage')
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
util: util,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(true, {
|
||||
matcherName: "toFoo",
|
||||
passed: true,
|
||||
message: "",
|
||||
expected: "hello",
|
||||
actual: "an actual"
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result to the spec when the comparison fails", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: false }; }
|
||||
};
|
||||
}
|
||||
},
|
||||
util = {
|
||||
buildFailureMessage: function() { return ""; }
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
util: util,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: ""
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result and a custom fail message to the spec when the comparison fails", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return {
|
||||
pass: false,
|
||||
message: "I am a custom message"
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: "I am a custom message"
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result with a custom fail message function to the spec when the comparison fails", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return {
|
||||
pass: false,
|
||||
message: function() { return "I am a custom message"; }
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: "an actual",
|
||||
message: "I am a custom message"
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a passing result to the spec when the comparison fails for a negative expectation", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: false }; }
|
||||
};
|
||||
}
|
||||
},
|
||||
util = {
|
||||
buildFailureMessage: function() { return ""; }
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
actual = "an actual",
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult,
|
||||
isNot: true
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(true, {
|
||||
matcherName: "toFoo",
|
||||
passed: true,
|
||||
message: "",
|
||||
expected: "hello",
|
||||
actual: actual
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result to the spec when the comparison passes for a negative expectation", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: true }; }
|
||||
};
|
||||
}
|
||||
},
|
||||
util = {
|
||||
buildFailureMessage: function() { return "default message"; }
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
actual = "an actual",
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
util: util,
|
||||
addExpectationResult: addExpectationResult,
|
||||
isNot: true
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "default message"
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result and a custom fail message to the spec when the comparison passes for a negative expectation", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() {
|
||||
return {
|
||||
pass: true,
|
||||
message: "I am a custom message"
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
actual = "an actual",
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult,
|
||||
isNot: true
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "I am a custom message"
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a passing result to the spec when the 'not' comparison passes, given a negativeCompare", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: true }; },
|
||||
negativeCompare: function() { return { pass: true }; }
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
actual = "an actual",
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult,
|
||||
isNot: true
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(true, {
|
||||
matcherName: "toFoo",
|
||||
passed: true,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: ""
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a failing result and a custom fail message to the spec when the 'not' comparison fails, given a negativeCompare", function() {
|
||||
var matchers = {
|
||||
toFoo: function() {
|
||||
return {
|
||||
compare: function() { return { pass: true }; },
|
||||
negativeCompare: function() {
|
||||
return {
|
||||
pass: false,
|
||||
message: "I'm a custom message"
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
addExpectationResult = jasmine.createSpy("addExpectationResult"),
|
||||
actual = "an actual",
|
||||
expectation;
|
||||
|
||||
j$.Expectation.addMatchers(matchers);
|
||||
|
||||
expectation = new j$.Expectation({
|
||||
matchers: matchers,
|
||||
actual: "an actual",
|
||||
addExpectationResult: addExpectationResult,
|
||||
isNot: true
|
||||
});
|
||||
|
||||
expectation.toFoo("hello");
|
||||
|
||||
expect(addExpectationResult).toHaveBeenCalledWith(false, {
|
||||
matcherName: "toFoo",
|
||||
passed: false,
|
||||
expected: "hello",
|
||||
actual: actual,
|
||||
message: "I'm a custom message"
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
xdescribe('JsApiReporter (integration specs)', function() {
|
||||
describe('results', function() {
|
||||
var reporter, spec1, spec2;
|
||||
var env;
|
||||
var suite, nestedSuite, nestedSpec;
|
||||
|
||||
beforeEach(function() {
|
||||
env = new j$.Env();
|
||||
|
||||
suite = env.describe("top-level suite", function() {
|
||||
spec1 = env.it("spec 1", function() {
|
||||
this.expect(true).toEqual(true);
|
||||
|
||||
});
|
||||
|
||||
spec2 = env.it("spec 2", function() {
|
||||
this.expect(true).toEqual(false);
|
||||
});
|
||||
|
||||
nestedSuite = env.describe("nested suite", function() {
|
||||
nestedSpec = env.it("nested spec", function() {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
reporter = new j$.JsApiReporter({});
|
||||
env.addReporter(reporter);
|
||||
|
||||
env.execute();
|
||||
|
||||
});
|
||||
|
||||
it('results() should return a hash of all results, indexed by spec id', function() {
|
||||
var expectedSpec1Results = {
|
||||
result: "passed"
|
||||
},
|
||||
expectedSpec2Results = {
|
||||
result: "failed"
|
||||
};
|
||||
expect(reporter.results()[spec1.id].result).toEqual('passed');
|
||||
expect(reporter.results()[spec2.id].result).toEqual('failed');
|
||||
});
|
||||
|
||||
it("should return nested suites as children of their parents", function() {
|
||||
expect(reporter.suites()).toEqual([
|
||||
{ id: 0, name: 'top-level suite', type: 'suite',
|
||||
children: [
|
||||
{ id: 0, name: 'spec 1', type: 'spec', children: [ ] },
|
||||
{ id: 1, name: 'spec 2', type: 'spec', children: [ ] },
|
||||
{ id: 1, name: 'nested suite', type: 'suite',
|
||||
children: [
|
||||
{ id: 2, name: 'nested spec', type: 'spec', children: [ ] }
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
describe("#summarizeResult_", function() {
|
||||
it("should summarize a passing result", function() {
|
||||
var result = reporter.results()[spec1.id];
|
||||
var summarizedResult = reporter.summarizeResult_(result);
|
||||
expect(summarizedResult.result).toEqual('passed');
|
||||
expect(summarizedResult.messages.length).toEqual(0);
|
||||
});
|
||||
|
||||
it("should have a stack trace for failing specs", function() {
|
||||
var result = reporter.results()[spec2.id];
|
||||
var summarizedResult = reporter.summarizeResult_(result);
|
||||
expect(summarizedResult.result).toEqual('failed');
|
||||
expect(summarizedResult.messages[0].trace.stack).toEqual(result.messages[0].trace.stack);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("JsApiReporter", function() {
|
||||
|
||||
it("knows when a full environment is started", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
expect(reporter.started).toBe(false);
|
||||
expect(reporter.finished).toBe(false);
|
||||
|
||||
reporter.jasmineStarted();
|
||||
|
||||
expect(reporter.started).toBe(true);
|
||||
expect(reporter.finished).toBe(false);
|
||||
});
|
||||
|
||||
it("knows when a full environment is done", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
expect(reporter.started).toBe(false);
|
||||
expect(reporter.finished).toBe(false);
|
||||
|
||||
reporter.jasmineStarted();
|
||||
reporter.jasmineDone({});
|
||||
|
||||
expect(reporter.finished).toBe(true);
|
||||
});
|
||||
|
||||
it("defaults to 'loaded' status", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
expect(reporter.status()).toEqual('loaded');
|
||||
});
|
||||
|
||||
it("reports 'started' when Jasmine has started", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
|
||||
expect(reporter.status()).toEqual('started');
|
||||
});
|
||||
|
||||
it("reports 'done' when Jasmine is done", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
reporter.jasmineDone({});
|
||||
|
||||
expect(reporter.status()).toEqual('done');
|
||||
});
|
||||
|
||||
it("tracks a suite", function() {
|
||||
var reporter = new j$.JsApiReporter({});
|
||||
|
||||
reporter.suiteStarted({
|
||||
id: 123,
|
||||
description: "A suite"
|
||||
});
|
||||
|
||||
var suites = reporter.suites();
|
||||
|
||||
expect(suites).toEqual({123: {id: 123, description: "A suite"}});
|
||||
|
||||
reporter.suiteDone({
|
||||
id: 123,
|
||||
description: "A suite",
|
||||
status: 'passed'
|
||||
});
|
||||
|
||||
expect(suites).toEqual({123: {id: 123, description: "A suite", status: 'passed'}});
|
||||
});
|
||||
|
||||
describe("#specResults", function() {
|
||||
var reporter, specResult1, specResult2;
|
||||
beforeEach(function() {
|
||||
reporter = new j$.JsApiReporter({});
|
||||
specResult1 = {
|
||||
id: 1,
|
||||
description: "A spec"
|
||||
};
|
||||
specResult2 = {
|
||||
id: 2,
|
||||
description: "Another spec"
|
||||
};
|
||||
|
||||
reporter.specDone(specResult1);
|
||||
reporter.specDone(specResult2);
|
||||
});
|
||||
|
||||
it("should return a slice of results", function() {
|
||||
expect(reporter.specResults(0, 1)).toEqual([specResult1]);
|
||||
expect(reporter.specResults(1, 1)).toEqual([specResult2]);
|
||||
});
|
||||
|
||||
describe("when the results do not exist", function() {
|
||||
it("should return a slice of shorter length", function() {
|
||||
expect(reporter.specResults(0, 3)).toEqual([specResult1, specResult2]);
|
||||
expect(reporter.specResults(2, 3)).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#executionTime", function() {
|
||||
it("should start the timer when jasmine starts", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
reporter = new j$.JsApiReporter({
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
reporter.jasmineStarted();
|
||||
expect(timerSpy.start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should return the time it took the specs to run, in ms", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
reporter = new j$.JsApiReporter({
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
timerSpy.elapsed.and.returnValue(1000);
|
||||
reporter.jasmineDone();
|
||||
expect(reporter.executionTime()).toEqual(1000);
|
||||
});
|
||||
|
||||
describe("when the specs haven't finished being run", function() {
|
||||
it("should return undefined", function() {
|
||||
var timerSpy = jasmine.createSpyObj('timer', ['start', 'elapsed']),
|
||||
reporter = new j$.JsApiReporter({
|
||||
timer: timerSpy
|
||||
});
|
||||
|
||||
expect(reporter.executionTime()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
describe("FakeDate", function() {
|
||||
it("does not fail if no global date is found", function() {
|
||||
var fakeGlobal = {},
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
expect(function() {
|
||||
mockDate.install();
|
||||
mockDate.tick(0);
|
||||
mockDate.uninstall();
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it("replaces the global Date when it is installed", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
expect(fakeGlobal.Date).toEqual(globalDate);
|
||||
mockDate.install();
|
||||
|
||||
expect(fakeGlobal.Date).not.toEqual(globalDate);
|
||||
});
|
||||
|
||||
it("replaces the global Date on uninstall", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
mockDate.uninstall();
|
||||
|
||||
expect(fakeGlobal.Date).toEqual(globalDate);
|
||||
});
|
||||
|
||||
it("takes the current time as the base when installing without parameters", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
globalDate.calls.reset();
|
||||
new fakeGlobal.Date();
|
||||
expect(globalDate).toHaveBeenCalledWith(1000);
|
||||
});
|
||||
|
||||
it("can accept a date as time base when installing", function() {
|
||||
var fakeGlobal = { Date: Date },
|
||||
mockDate = new j$.MockDate(fakeGlobal),
|
||||
baseDate = new Date();
|
||||
|
||||
spyOn(baseDate, 'getTime').and.returnValue(123);
|
||||
mockDate.install(baseDate);
|
||||
|
||||
expect(new fakeGlobal.Date().getTime()).toEqual(123);
|
||||
});
|
||||
|
||||
it("makes real dates", function() {
|
||||
var fakeGlobal = { Date: Date },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
expect(new fakeGlobal.Date()).toEqual(jasmine.any(Date));
|
||||
});
|
||||
|
||||
it("fakes current time when using Date.now()", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate };
|
||||
|
||||
globalDate.now = function() {};
|
||||
var mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
expect(fakeGlobal.Date.now()).toEqual(1000);
|
||||
});
|
||||
|
||||
it("does not stub Date.now() if it doesn't already exist", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
expect(fakeGlobal.Date.now).toThrowError("Browser does not support Date.now()");
|
||||
});
|
||||
|
||||
it("makes time passes using tick", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate };
|
||||
|
||||
globalDate.now = function() {};
|
||||
var mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
mockDate.tick(100);
|
||||
|
||||
expect(fakeGlobal.Date.now()).toEqual(1100);
|
||||
|
||||
mockDate.tick(1000);
|
||||
|
||||
expect(fakeGlobal.Date.now()).toEqual(2100);
|
||||
});
|
||||
|
||||
it("allows to increase 0 milliseconds using tick", function() {
|
||||
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
|
||||
return {
|
||||
getTime: function() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}),
|
||||
fakeGlobal = { Date: globalDate };
|
||||
|
||||
globalDate.now = function() {};
|
||||
var mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
mockDate.tick(0);
|
||||
expect(fakeGlobal.Date.now()).toEqual(1000);
|
||||
|
||||
mockDate.tick();
|
||||
expect(fakeGlobal.Date.now()).toEqual(1000);
|
||||
});
|
||||
|
||||
it("allows to create a Date in a different time than the mocked time", function() {
|
||||
var fakeGlobal = { Date: Date },
|
||||
mockDate = new j$.MockDate(fakeGlobal),
|
||||
baseDate = new Date(2013, 9, 23, 0, 0, 0, 0);
|
||||
|
||||
mockDate.install(baseDate);
|
||||
|
||||
var otherDate = new fakeGlobal.Date(2013, 9, 23, 0, 0, 1, 0);
|
||||
expect(otherDate.getTime()).not.toEqual(baseDate.getTime());
|
||||
});
|
||||
|
||||
it("copies all Date properties to the mocked date", function() {
|
||||
var fakeGlobal = { Date: Date },
|
||||
mockDate = new j$.MockDate(fakeGlobal);
|
||||
|
||||
mockDate.install();
|
||||
|
||||
expect(fakeGlobal.Date.UTC(2013, 9, 23)).toEqual(Date.UTC(2013, 9, 23));
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user