Compare commits

...

84 Commits

Author SHA1 Message Date
ragaskar
b6f96bc121 Version 1.2.0
- Bump version
- Update pages submodule
2012-05-14 07:35:47 -07:00
Rajan Agaskar
feebfbba68 Update README.markdown 2012-05-09 09:51:29 -07:00
Rajan Agaskar
8e4bd86865 Merge pull request #220 from moonmaster9000/patch-1
update the copyright and remove the blank "what's here" section.
2012-05-02 10:51:26 -07:00
Matt Parker
bb1a4428db update the copyright and remove the blank "what's here" section. 2012-04-13 23:30:12 -03:00
Davis W. Frank
079740ca2c Make Thor tasks more visible; Init Pages submodule when not present if about to run tests that require it 2012-04-09 22:21:09 -07:00
ragaskar
fbbccf6ef7 Bump to 1.2.0.rc3 2012-04-04 09:48:00 -07:00
ragaskar
7ad75c13d4 Fix Matchers.any specs in Firefox
- Firefox adds whitespace to the resulting to_string function, necessary
  to remove it for the match to occur correctly.
2012-04-04 08:41:59 -07:00
Davis W. Frank
d46ca4f506 correct for 1.2.0.rc2 2012-04-03 15:35:08 -07:00
Davis W. Frank
ee7af4496c Pages updated for 1.2.0.rc1 2012-04-02 18:37:35 -07:00
Davis W. Frank
e22c4492a5 release prep for 1.2.0.rc1 2012-04-02 18:34:59 -07:00
Davis W. Frank
d63836afb4 Fix for copying built Github pages to the submodule properly 2012-04-02 18:33:38 -07:00
Davis W. Frank
06f1edc197 Merge branch 'master' of github.com:pivotal/jasmine 2012-04-01 17:03:06 -07:00
Davis W. Frank
3a6b233a2e Merge pull request #209 from mark-rushakoff/ruby187fix
fix JasmineDev#has_node? for Ruby 1.8.7
2012-04-01 17:02:20 -07:00
Mark Rushakoff
d15964b7dc fix JasmineDev#has_node? for Ruby 1.8.7 2012-04-01 15:44:36 -07:00
Davis W. Frank
6e22754c10 1.2.0.rc1 commit 2012-04-01 13:19:24 -07:00
Davis W. Frank
bab4538404 Fix to name the standalone distribution from the version number 2012-04-01 13:11:53 -07:00
Davis W. Frank
06d191af74 Merge branch 'master' of github.com:pivotal/jasmine 2012-04-01 13:08:55 -07:00
Davis W. Frank
ad78d0d0d8 Fixed bug where version for Ruby gem wasn't correct 2012-04-01 13:08:42 -07:00
Davis W. Frank
733a6a4ae4 Merge pull request #208 from mark-rushakoff/ansicolor-cleanup
Remove remaining references to term-ansicolor
2012-04-01 13:00:57 -07:00
Mark Rushakoff
3e0cad41f5 Remove remaining references to term-ansicolor 2012-04-01 12:30:38 -07:00
Davis W. Frank
885832e920 Forgot to update Contribute to include new Thor tasks 2012-04-01 11:36:29 -07:00
Davis W. Frank
3a0ada034b Move sources order to Ruby, which is where it's used. 2012-04-01 11:28:57 -07:00
Davis W. Frank
674197aef8 Removed TermAnsiColor gem (uses GPL and isn't needed anymore) 2012-04-01 10:51:04 -07:00
Davis W. Frank
626da5a112 Re-implemented all development Rake tasks in Thor. Now actually tested.
Fixes:
* https://www.pivotaltracker.com/story/show/25484287 & https://github.com/pivotal/jasmine/issues/183
* https://www.pivotaltracker.com/story/show/25485401 & https://github.com/pivotal/jasmine/issues/189
* https://www.pivotaltracker.com/story/show/25485953 & https://github.com/pivotal/jasmine/issues/159
2012-04-01 10:47:29 -07:00
Davis W. Frank
4a1a2123a3 Fixes https://github.com/pivotal/jasmine-gem/issues/65 and https://www.pivotaltracker.com/story/show/24902023 2012-02-25 11:58:54 -08:00
Davis W. Frank
c87cf71f4f Merge pull request #156 from cathoderay/master
fixing typo
2012-01-08 12:46:14 -08:00
Davis W. Frank
e4c557faae Merge pull request #158 from grosser/contribute-markup
fix task list not displaying properly on github for contribute.markdown
2012-01-08 12:45:50 -08:00
Davis W. Frank
6559c5b43a Merge pull request #157 from grosser/license
add license to gemspec so automated tools can pick it up
2012-01-08 12:45:21 -08:00
Davis W. Frank
912397120b Merge pull request #170 from edtsech/patch-1
Remove double negative in docs (not.toNotContain, not.toNotEqual)
2012-01-08 12:41:46 -08:00
Edward Tsech
551464b8d2 Remove double negative in docs (not.toNotContain, not.toNotEqual) 2012-01-04 16:21:54 +01:00
Davis W. Frank
8a298e5c0e Merge pull request #168 from thedeeno/linux_open_browser
add linux support to ``rake spec:browser``
2012-01-03 17:07:17 -08:00
Dane O'Connor
94a153ed15 add linux support to rake spec:browser 2012-01-03 17:12:20 -05:00
Davis W. Frank
b4439f74d5 Merge pull request #100 from gvanhove/objectContaining
Merging after verifying locally that all specs are green (node, browser)
2011-11-18 13:26:04 -08:00
gvanhove
d70e733f70 remove unwanted spaces in it calls, and make the spec counting regex tolerate them if they exist so counts match even when using bad style 2011-11-14 18:43:13 -08:00
gvanhove
ac096f9911 convert objectContaining to use jasmineMatches and jasmineToString 2011-11-14 18:29:30 -08:00
gvanhove
08d72926ff More renaming of hash 2011-11-14 18:29:30 -08:00
gvanhove
67ec0af254 use jasmineMatches for equality testing of complicated matchers 2011-11-14 18:29:30 -08:00
gvanhove
4f2fcff15a Use jasmineToString for printing out complicated matchers 2011-11-14 18:29:30 -08:00
gvanhove
7158fc2426 Rename hashContaining to objectContaining, since this is javascript. Also call the toString from prettyPrinter 2011-11-14 18:26:48 -08:00
gvanhove
992367dcbc New matcher "hashContaining" similar to rspec's hash_including 2011-11-14 18:26:48 -08:00
gvanhove
ce886e20e4 commit updated version into jasmine.js 2011-11-14 18:26:48 -08:00
grosser
86b0c80cc9 fix task list not displaying properly on github for contribute.markdown 2011-11-13 09:18:34 -08:00
grosser
7dff84b1dc add license to gemspec so automated tools can pick it up 2011-11-13 09:12:29 -08:00
Ronald Andreu Kaiser
8c22b26d9c fixing typo 2011-11-11 16:42:50 -02:00
Davis W. Frank & Sean Durham
ad4f48dcd4 Add new HTMLReporter 2011-11-04 14:43:19 -07:00
Davis W. Frank & Rajan Agaskar
de9e2abad5 Use correct name for Davis. 2011-11-04 14:31:15 -07:00
ragaskar
41f496001f Version bump to 1.1.0 2011-09-10 13:51:11 -04:00
ragaskar
6b5956724b Version bump to rc4 2011-09-01 07:26:07 -04:00
Rajan Agaskar
ec24992250 Merge pull request #123 from Osukaru/master
fixed html comments in SpecRunner.html example
2011-09-01 04:23:41 -07:00
Osukaru
83f232237d fixed html comments 2011-08-26 01:22:11 +03:00
Rajan Agaskar
98d32bb4a4 Merge pull request #111 from qfox/patch-1
Add missing semi.
2011-07-21 04:07:52 -07:00
qfox
c4f27ae377 ASI trolling 2011-07-21 00:58:53 -07:00
ragaskar
a075c75bce Version bump to 1.1.0.rc3 2011-07-13 07:23:29 -04:00
ragaskar
a617b59e6a Bump to rc2 2011-06-24 21:34:29 -04:00
ragaskar
917b37481e Update rake 2011-06-24 21:25:06 -04:00
ragaskar
67bbc98faa Bump version 2011-06-24 21:22:19 -04:00
Davis W. Frank
620f7b6e4c Updates to Pages; Updates to docs; 2011-06-23 19:02:17 -07:00
ragaskar
b722f416c7 Write out version.rb on dist build 2011-06-23 07:55:04 -04:00
ragaskar
634a7dc402 Rollback pages submodule bump 2011-06-23 07:32:05 -04:00
Davis W. Frank
a4522e4dce Updated Release readme 2011-06-21 20:19:28 -07:00
Davis W. Frank
e113c338d0 Merge branch 'master' of github.com:pivotal/jasmine 2011-06-21 20:11:10 -07:00
ragaskar
b81f690a25 Require JSON in time for the gemspec 2011-06-21 08:05:41 -04:00
ragaskar
c06e189699 Ignore tags 2011-06-21 08:05:20 -04:00
Davis W. Frank
67b6cfb828 Improve the rake standalone task 2011-06-20 18:27:57 -07:00
Davis W. Frank
57e622fb2a Fix to version structure for "release_candidate" 2011-06-20 18:17:24 -07:00
Davis W. Frank
c0664dd6aa merge 2011-06-20 08:46:37 -07:00
Davis W. Frank
b640ce6fc0 wip on readme for release 2011-06-20 07:32:40 -07:00
ragaskar
e9af7834f5 Better argument handling in Jasmine::Core#spec_files 2011-06-18 09:43:14 -04:00
ragaskar
0d43ae9c38 Give Jasmine::Core access to jasmine specs
[#13128217]
2011-06-18 09:39:23 -04:00
ragaskar
30431a3958 Gem-ize jasmine
[Finishes #13128217]
2011-06-17 21:01:42 -04:00
Davis W. Frank
3775919c92 remove old, commented-out tasks 2011-06-17 08:23:17 -07:00
Davis W. Frank
a692ff8c95 Need HAML in the Gemfile; continued fixes to the Rake tasks 2011-06-17 08:20:22 -07:00
Davis W. Frank
e4e9b51544 rename TrivialConsoleReporter to ConsoleReporter 2011-06-16 22:35:57 -07:00
Davis W. Frank
0b97951766 Better coloring of output of Rake tasks; Turn off colored output in Rake tasks if not on a TTY (not sure if it works in Hudson); Add support to TCR for turning off colors since there is code to calc options but it wasn't used; NOTE: coloring in TCR should be MUCH better tested. 2011-06-16 22:34:11 -07:00
Davis W. Frank
75dd391d57 should fix red build 2011-06-16 08:33:59 -07:00
Davis W. Frank
ae24e00c0f Support for release candidates in the version.json file; propagates up through the version string everywhere: filenames, ZIP, source code 2011-06-15 18:37:12 -07:00
Davis W. Frank
6b2e45eab5 Refactor of standalone build tasks; Better templating of the core runner.html and the example SpecRunner.html 2011-06-15 09:15:40 -07:00
Davis W. Frank
e59171935f breaking up distribution tasks; moving version to a template to have a simpler concat function 2011-06-14 08:30:14 -07:00
Davis W. Frank
2ba0aa371c Refactor how the distribution is built 2011-06-13 08:23:10 -07:00
Davis W. Frank
c2ed71717f Remove link to github page from Runner 2011-06-11 16:51:16 -07:00
Davis W. Frank
09e8822107 WIP on new Contribution docs 2011-06-11 16:47:12 -07:00
Davis W. Frank
15763c2eb0 Output number of expected specs for browser, node before running specs. NOTE: We distribution tasks still broken. 2011-06-11 15:59:34 -07:00
Davis W. Frank
3f264cde34 fix so that all specs are pulled into runner.html 2011-06-11 14:48:41 -07:00
Davis W. Frank
f83cb7f766 Runner.html is now generated (ensures all source & specs get tested); beginnings of refactoring of Rake tasks. 2011-06-09 19:24:51 -07:00
87 changed files with 3993 additions and 1167 deletions

7
.gitignore vendored
View File

@@ -5,3 +5,10 @@ site/
.bundle/
.pairs
.rvmrc
*.gem
.bundle
tags
Gemfile.lock
pkg/*
.sass-cache/*
src/html/.sass-cache/*

2
.rspec Normal file
View File

@@ -0,0 +1,2 @@
--color
--format Fuubar

45
Contribute.markdown Normal file
View File

@@ -0,0 +1,45 @@
# Developing for Jasmine Core
## How to Contribute
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.
## 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
* _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.
## Environment
Ruby, RubyGems and Rake are used in order to script the various file interactions. You will need to run on a system that supports Ruby in order to run Jasmine's specs.
Node.js is used to run most of the specs (the HTML-independent code) and should be present. Additionally, the JS Hint project scrubs the source code as part of the spec process.
## 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/`.
Please respect the code patterns as possible. For example, using `jasmine.getGlobal()` to get the global object so as to remain environment agnostic.
## Running Specs
As in all good projects, the `spec/` directory mirrors `src/` and follows the same rules. The browser runner will include and attempt to run all specs. The node runner will exclude any html-dependent specs (those in `spec/html/`).
You will notice that all specs are run against the built `jasmine.js` instead of the component source files. This is intentional as a way to ensure that the concatenation code is working correctly.
Please ensure all specs are green before committing or issuing a pull request.
There are Thor tasks to help with getting green - run `thor list` to see them all. Here are the key tasks:
* `thor jasmine_dev:execute_specs` outputs the expected number of specs that should be run and attempts to run in browser and Node
* `thor jasmine_dev:execute_specs_in_browser` opens `spec/runner.html` in the default browser on MacOS. Please run this in at least Firefox and Chrome before committing
* `thor jasmine_dev:execute_specs_in_node` runs all the Jasmine specs in Node.js - it will complain if Node is not installed
* `thor jasmine_dev:js_hint` runs all the files through JSHint and will complain about potential viable issues with your code. Fix them.

View File

@@ -1,6 +1,3 @@
source :rubygems
gem "json_pure", "~>1.4.3"
gem "frank"
gem "ragaskar-jsdoc_helper"
gem "rake", "0.8.7"
gem "rake"
gemspec

View File

@@ -1,33 +0,0 @@
GEM
remote: http://rubygems.org/
specs:
daemons (1.0.10)
frank (1.0.8)
haml (>= 3.0)
mongrel (>= 1.2.0.pre2)
net-scp (>= 1.0)
net-ssh (>= 2.0)
rack (>= 1.0)
tilt (= 0.9)
gem_plugin (0.2.3)
haml (3.0.25)
json_pure (1.4.6)
mongrel (1.2.0.pre2)
daemons (~> 1.0.10)
gem_plugin (~> 0.2.3)
net-scp (1.0.4)
net-ssh (>= 1.99.1)
net-ssh (2.1.0)
rack (1.2.1)
ragaskar-jsdoc_helper (0.0.2.1)
rake (0.8.7)
tilt (0.9)
PLATFORMS
ruby
DEPENDENCIES
frank
json_pure (~> 1.4.3)
ragaskar-jsdoc_helper
rake (= 0.8.7)

View File

@@ -1,49 +0,0 @@
1. Ensure all specs are green in browsers & Node.js (via rake tasks)
1. Ensure CI is green
1.
## Development
## Release
# Making a Release of Jasmine Core
'Jasmine' is the Github repo for Jasmine Core and contains all the JavaScript code for the Jasmine BDD framework.
It also contains two HTML pages for the Github Pages at http://pivotal.github.com/jasmine.
## The Repo
All of the JS for Jasmine is in the src directory. The specs for each file are in the specs directory. There are rake tasks to build the various files for distribution.
## Running Specs
There are rake tasks to help with getting green:
* `rake spec:browser` opens `spec/runner.html` in the default browser. Please run this in at least Firefox and Chrome before comitting
* `rake spec:node` runs all the Jasmine specs in Node.js
* `rake jasmine:lint` runs all the files through JSHint and will complain about potential viable issues with your code. Fix them.
## The Pages
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.
The pages are built with [Frank](https://github.com/blahed/frank). All the source for these pages live in the pages_source directory.
## Releasing
Once all specs are green and you've updated the version in `version.json`, you need to run the rake task to make a distribution: `rake jasmine:dist`.

View File

@@ -6,40 +6,14 @@ Jasmine is a Behavior Driven Development testing framework for JavaScript. It do
Documentation & guides live here: [http://pivotal.github.com/jasmine/](http://pivotal.github.com/jasmine/)
## 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](jasmine-js@googlegroups.com)
* Check the current build status: [ci.pivotallabs.com](http://ci.pivotallabs.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)
## How to Contribute
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.
### Development Environment
Jasmine Core relies on Ruby for executing the test suite and building the project for release. The spec suite runs in any major, modern browser (Firefox, Safari, Chrome, and yes various IE's) and in [Node.js](http://nodejs.org). While you probably have browsers installed, you want to make sure that Ruby and Node are present.
### How to Develop for Jasmine Core
* Write specs
* Make them pass in a browser (or three):
* open `spec/runner.html` in your browsers
* `rake spec:browser` will run in the default browser on MacOS
* Make them pass in Node: `rake spec:node`
* Fix any warnings or errors from JSHint: `rake jasmine:lint`
Running `rake spec` will run the browser tests, then run specs in Node, then run JSHint. But this will only run in the default browser and only on MacOS (for now).
### Making a Successful Pull Request
* __Include specs for your work__ - it helps us understand your intent and makes sure that future development doesn't break your work
* __Ensure the full test suite is green__ in all the big browsers, Node, and JSHint - your contribution shouldn't break Jasmine for other users
Do these things and we'll take a look.
## Maintainers
@@ -47,4 +21,4 @@ Do these things and we'll take a look.
* [Rajan Agaskar](mailto:rajan@pivotallabs.com), Pivotal Labs
* [Christian Williams](mailto:antixian666@gmail.com), Square
Copyright (c) 2008-2011 Pivotal Labs. This software is licensed under the MIT License.
Copyright (c) 2008-2012 Pivotal Labs. This software is licensed under the MIT License.

192
Rakefile
View File

@@ -1,170 +1,44 @@
require 'json'
require "bundler"
Bundler::GemHelper.install_tasks
require "json"
require "tilt"
def jasmine_sources
first_sources = JSON.parse(File.read('src/SourcesList.json')).collect {|f| "src/core/#{f}"}
sources = first_sources
sources += Dir.glob('src/core/*.js').reject {|f| first_sources.include?(f)}.sort
sources
Dir["#{File.dirname(__FILE__)}/tasks/**/*.rb"].each do |file|
require file
end
def jasmine_html_sources
["src/html/TrivialReporter.js"]
desc "Run all Jasmine JS specs"
task :jasmine_specs do
jasmine_dev = JasmineDev.new
return unless jasmine_dev.node_installed?
system "thor jasmine_dev:execute_specs"
puts "\n\033[33m>>> DEPRECATED <<< Run Jasmine's JavaScript specs with 'thor jasmine_dev:execute_specs'\n\033[0m"
end
def jasmine_version
"#{version_hash['major']}.#{version_hash['minor']}.#{version_hash['build']}"
desc "Run all Jasmine core tests (JavaScript and dev tasks)"
task :spec => :require_pages_submodule do
jasmine_dev = JasmineDev.new
return unless jasmine_dev.node_installed?
system "rspec"
end
def version_hash
require 'json'
@version ||= JSON.parse(File.new("src/core/version.json").read);
end
task :require_pages_submodule do
jasmine_dev = JasmineDev.new
def substitute_jasmine_version(filename)
contents = File.read(filename)
contents = contents.gsub(/##JASMINE_VERSION##/, (jasmine_version))
contents = contents.gsub(/[^\n]*REMOVE_THIS_LINE_FROM_BUILD[^\n]*/, '')
File.open(filename, 'w') { |f| f.write(contents) }
end
task :default => :spec
desc "Run spec suite: Browser, Node, JSHint"
task :spec => ["jasmine:build", "spec:node", "spec:browser"]
namespace :spec do
desc 'Run specs in Node.js'
task :node do
raise "Node is required to run all jasmine specs" unless system("node spec/node_suite.js")
end
desc "Run specs in the default browser (MacOS only)"
task :browser do
system("open spec/runner.html")
unless jasmine_dev.pages_submodule_installed?
puts 'Installing the Github pages submodule:'
system 'git submodule update --init'
puts 'Now continuing...'
end
end
namespace :jasmine do
desc 'Prepares for distribution'
task :dist => ['jasmine:build',
'jasmine:doc',
'jasmine:build_pages',
'jasmine:build_example_project',
'jasmine:fill_index_downloads']
desc 'Check jasmine sources for coding problems'
task :lint do
puts "Running JSHint via Node.js"
system("node jshint/run.js") || exit(1)
end
desc "Alias to JSHint"
task :hint => :lint
desc 'Builds lib/jasmine from source'
task :build => :lint do
puts 'Building Jasmine from source'
sources = jasmine_sources
version = version_hash
File.open("lib/jasmine.js", 'w') do |jasmine|
sources.each do |source_filename|
jasmine.puts(File.read(source_filename))
end
jasmine.puts %{
jasmine.version_= {
"major": #{version['major'].to_json},
"minor": #{version['minor'].to_json},
"build": #{version['build'].to_json},
"revision": #{Time.now.to_i}
};
}
end
File.open("lib/jasmine-html.js", 'w') do |jasmine_html|
jasmine_html_sources.each do |source_filename|
jasmine_html.puts(File.read(source_filename))
end
end
FileUtils.cp("src/html/jasmine.css", "lib/jasmine.css")
end
downloads_file = 'pages/download.html'
task :need_pages_submodule do
unless File.exist?(downloads_file)
raise "Jasmine pages submodule isn't present. Run git submodule update --init"
end
end
desc "Build the Github pages HTML"
task :build_pages => :need_pages_submodule do
Dir.chdir("pages") do
FileUtils.rm_r('pages_output') if File.exist?('pages_output')
Dir.chdir('pages_source') do
system("frank export ../pages_output")
end
puts "\nCopying Frank output to the root of the gh-pages branch\n\n"
system("cp -r pages_output/* .")
end
end
desc "Build jasmine documentation"
task :doc => :need_pages_submodule do
puts 'Creating Jasmine Documentation'
require 'rubygems'
require 'jsdoc_helper'
FileUtils.rm_r "pages/jsdoc", :force => true
JsdocHelper::Rake::Task.new(:lambda_jsdoc) do |t|
t[:files] = jasmine_sources << jasmine_html_sources
t[:options] = "-a"
t[:out] = "pages/jsdoc"
# JsdocHelper bug: template must be relative to the JsdocHelper gem, ick
t[:template] = File.join("../".*(100), Dir::getwd, "jsdoc-template")
end
Rake::Task[:lambda_jsdoc].invoke
end
desc "Build example project"
task :build_example_project => :need_pages_submodule do
require 'tmpdir'
temp_dir = File.join(Dir.tmpdir, 'jasmine-standalone-project')
puts "Building Example Project in #{temp_dir}"
FileUtils.rm_r temp_dir if File.exist?(temp_dir)
Dir.mkdir(temp_dir)
root = File.expand_path(File.dirname(__FILE__))
FileUtils.cp_r File.join(root, 'example/.'), File.join(temp_dir)
substitute_jasmine_version(File.join(temp_dir, "SpecRunner.html"))
lib_dir = File.join(temp_dir, "lib/jasmine-#{jasmine_version}")
FileUtils.mkdir_p(lib_dir)
{
"lib/jasmine.js" => "jasmine.js",
"lib/jasmine-html.js" => "jasmine-html.js",
"src/html/jasmine.css" => "jasmine.css",
"MIT.LICENSE" => "MIT.LICENSE"
}.each_pair do |src, dest|
FileUtils.cp(File.join(root, src), File.join(lib_dir, dest))
end
dist_dir = File.join(root, 'pages/downloads')
zip_file_name = File.join(dist_dir, "jasmine-standalone-#{jasmine_version}.zip")
puts "Zipping Example Project and moving to #{zip_file_name}"
FileUtils.mkdir(dist_dir) unless File.exist?(dist_dir)
if File.exist?(zip_file_name)
puts "WARNING!!! #{zip_file_name} already exists!"
FileUtils.rm(zip_file_name)
end
exec "cd #{temp_dir} && zip -r #{zip_file_name} . -x .[a-zA-Z0-9]*"
end
end
desc "View full development tasks"
task :list_dev_tasks do
puts "Jasmine uses Thor for command line tasks for development. Here is the command set:"
system "thor list"
end

42
Release.markdown Normal file
View File

@@ -0,0 +1,42 @@
# How to work on a Jasmine Release
## Development
___Jasmine Core Maintainers Only___
Follow the instructions in `Contribute.markdown` 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), please squash them when merging back to `master`.
### Version
We attempt to stick to [Semantic Versioning](). 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 `src/version.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)
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.
The pages are built with [Frank](https://github.com/blahed/frank). All the source for these pages live in the `pages/pages_source` directory.
## Release
When ready to release - specs are all green and the stories are done:
1. Update the version in `version.json` to a release candidate - add a `release_candidate` property with a value of 1
1. Update any comments on the public interfaces
1. Update any links or top-level landing page for the Github Pages
1. `thor jasmine_dev:release_prep` - updates the version, builds the `.js` files, builds the standalone release, and builds the Github pages
1. `rake release` - tags the repo with the version, builds the `jasmine-core` gem, pushes the gem to Rubygems.org
There should be a post to Pivotal Labs blog and a tweet to that link.

29
config.rb Normal file
View File

@@ -0,0 +1,29 @@
#
# Compass configuration file - for building Jasmine's 'final CSS files
#
# Require any additional compass plugins here.
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "src/html"
sass_dir = "src/html"
images_dir = "images"
javascripts_dir = "javascripts"
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
output_style = :compact
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
line_comments = false
# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass

View File

@@ -1,21 +0,0 @@
# Project-specific configuration for CruiseControl.rb
Project.configure do |project|
# Send email notifications about broken and fixed builds to email1@your.site, email2@your.site (default: send to nobody)
# project.email_notifier.emails = ['email1@your.site', 'email2@your.site']
# Set email 'from' field to john@doe.com:
# project.email_notifier.from = 'john@doe.com'
# Build the project by invoking rake task 'custom'
project.rake_task = 'jasmine:test:ci:saucelabs'
# Build the project by invoking shell script "build_my_app.sh". Keep in mind that when the script is invoked,
# current working directory is <em>[cruise&nbsp;data]</em>/projects/your_project/work, so if you do not keep build_my_app.sh
# in version control, it should be '../build_my_app.sh' instead
#project.build_command = 'cp ../saucelabs.yml .'
# Ping Subversion for new revisions every 5 minutes (default: 30 seconds)
# project.scheduler.polling_interval = 5.minutes
end

View File

@@ -1,27 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Test Runner</title>
<link rel="stylesheet" type="text/css" href="lib/jasmine-##JASMINE_VERSION##/jasmine.css">
<script type="text/javascript" src="lib/jasmine-##JASMINE_VERSION##/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-##JASMINE_VERSION##/jasmine-html.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>
<div id="REMOVE_THIS_LINE_FROM_BUILD"><p>You must be trying to look at examples in the Jasmine source tree.</p><p>Please download a distribution version of Jasmine at <a href="http://pivotal.github.com/jasmine/">http://pivotal.github.com/jasmine/</a>.</p></div>
<script type="text/javascript">
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
</script>
</body>
</html>

29
jasmine-core.gemspec Normal file
View File

@@ -0,0 +1,29 @@
# -*- 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 "json_pure", ">= 1.4.3"
s.add_development_dependency "frank"
s.add_development_dependency "sass"
s.add_development_dependency "compass"
s.add_development_dependency "ragaskar-jsdoc_helper"
s.add_development_dependency "rspec"
s.add_development_dependency "fuubar"
s.add_development_dependency "awesome_print"
s.add_development_dependency "thor"
s.add_development_dependency "nokogiri"
end

1
jasmine_dev.thor Normal file
View File

@@ -0,0 +1 @@
require "#{File.expand_path(File.dirname(__FILE__))}/tasks/jasmine_dev"

View File

@@ -1,5 +1,5 @@
var fs = require("fs");
var sys = require("sys");
var util = require("util");
var path = require("path");
var JSHINT = require("./jshint").JSHINT;

36
lib/jasmine-core.rb Normal file
View File

@@ -0,0 +1,36 @@
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
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 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
end
end
end

View File

@@ -0,0 +1,54 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-1.1.0.rc1/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="lib/jasmine-1.1.0.rc1/jasmine.css">
<script type="text/javascript" src="lib/jasmine-1.1.0.rc1/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-1.1.0.rc1/jasmine-html.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/SpecHelper.js"></script>
<script type="text/javascript" src="spec/PlayerSpec.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="src/Player.js"></script>
<script type="text/javascript" src="src/Song.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,616 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.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;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};
jasmine.HtmlReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = doc.location.search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
this.summaryMenuItem.onclick = function() {
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
};
this.detailsMenuItem.onclick = function() {
showDetails();
};
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
dom.alert.appendChild(this.runningAlert);
}
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
// skipped specs UI
if (isUndefined(this.skippedAlert)) {
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
}
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.skippedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.skippedAlert);
}
// passing specs UI
if (isUndefined(this.passedAlert)) {
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
}
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
// failing specs UI
if (isUndefined(this.failedAlert)) {
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
}
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
if (this.failedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.failedAlert);
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
};
this.complete = function() {
dom.alert.removeChild(this.runningAlert);
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
} else {
showDetails();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.HtmlReporter.SpecView.prototype.status = function() {
return this.getSpecStatus(this.spec);
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
break;
case 'passed':
this.appendSummaryToSuiteDiv();
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.results().getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
/* @deprecated Use jasmine.HtmlReporter instead
*/
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.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;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

View File

@@ -0,0 +1,81 @@
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }

View File

@@ -196,6 +196,21 @@ jasmine.any = function(clazz) {
return new jasmine.Matchers.Any(clazz);
};
/**
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
* attributes on the object.
*
* @example
* // don't care about any other attributes than foo.
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
*
* @param sample {Object} sample
* @returns matchable object for the sample
*/
jasmine.objectContaining = function (sample) {
return new jasmine.Matchers.ObjectContaining(sample);
};
/**
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
*
@@ -735,12 +750,17 @@ jasmine.Env.prototype.version = function () {
* @returns string containing jasmine version build info, if set.
*/
jasmine.Env.prototype.versionString = function() {
if (jasmine.version_) {
var version = this.version();
return version.major + "." + version.minor + "." + version.build + " revision " + version.revision;
} else {
if (!jasmine.version_) {
return "version unknown";
}
var version = this.version();
var versionString = version.major + "." + version.minor + "." + version.build;
if (version.release_candidate) {
versionString += ".rc" + version.release_candidate;
}
versionString += " revision " + version.revision;
return versionString;
};
/**
@@ -909,11 +929,19 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
return a.getTime() == b.getTime();
}
if (a instanceof jasmine.Matchers.Any) {
if (a.jasmineMatches) {
return a.jasmineMatches(b);
}
if (b.jasmineMatches) {
return b.jasmineMatches(a);
}
if (a instanceof jasmine.Matchers.ObjectContaining) {
return a.matches(b);
}
if (b instanceof jasmine.Matchers.Any) {
if (b instanceof jasmine.Matchers.ObjectContaining) {
return b.matches(a);
}
@@ -1207,7 +1235,7 @@ jasmine.Matchers.prototype.toEqual = function(expected) {
/**
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
* @param expected
* @deprecated as of 1.0. Use not.toNotEqual() instead.
* @deprecated as of 1.0. Use not.toEqual() instead.
*/
jasmine.Matchers.prototype.toNotEqual = function(expected) {
return !this.env.equals_(this.actual, expected);
@@ -1380,7 +1408,7 @@ jasmine.Matchers.prototype.toContain = function(expected) {
* Matcher that checks that the expected item is NOT an element in the actual Array.
*
* @param {Object} expected
* @deprecated as of 1.0. Use not.toNotContain() instead.
* @deprecated as of 1.0. Use not.toContain() instead.
*/
jasmine.Matchers.prototype.toNotContain = function(expected) {
return !this.env.contains_(this.actual, expected);
@@ -1448,7 +1476,7 @@ jasmine.Matchers.Any = function(expectedClass) {
this.expectedClass = expectedClass;
};
jasmine.Matchers.Any.prototype.matches = function(other) {
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
if (this.expectedClass == String) {
return typeof other == 'string' || other instanceof String;
}
@@ -1468,10 +1496,222 @@ jasmine.Matchers.Any.prototype.matches = function(other) {
return other instanceof this.expectedClass;
};
jasmine.Matchers.Any.prototype.toString = function() {
jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
this.sample = sample;
};
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
var env = jasmine.getEnv();
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in this.sample) {
if (!hasKey(other, property) && hasKey(this.sample, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
}
}
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
/**
* @constructor
*/
@@ -1612,8 +1852,8 @@ jasmine.PrettyPrinter.prototype.format = function(value) {
this.emitScalar('null');
} else if (value === jasmine.getGlobal()) {
this.emitScalar('<global>');
} else if (value instanceof jasmine.Matchers.Any) {
this.emitScalar(value.toString());
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
} else if (typeof value === 'string') {
this.emitString(value);
} else if (jasmine.isSpy(value)) {
@@ -2280,193 +2520,10 @@ jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
}, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
}
};
// Mock setTimeout, clearTimeout
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
jasmine.FakeTimer = function() {
this.reset();
var self = this;
self.setTimeout = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
return self.timeoutsMade;
};
self.setInterval = function(funcToCall, millis) {
self.timeoutsMade++;
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
return self.timeoutsMade;
};
self.clearTimeout = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
self.clearInterval = function(timeoutKey) {
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
};
};
jasmine.FakeTimer.prototype.reset = function() {
this.timeoutsMade = 0;
this.scheduledFunctions = {};
this.nowMillis = 0;
};
jasmine.FakeTimer.prototype.tick = function(millis) {
var oldMillis = this.nowMillis;
var newMillis = oldMillis + millis;
this.runFunctionsWithinRange(oldMillis, newMillis);
this.nowMillis = newMillis;
};
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
var scheduledFunc;
var funcsToRun = [];
for (var timeoutKey in this.scheduledFunctions) {
scheduledFunc = this.scheduledFunctions[timeoutKey];
if (scheduledFunc != jasmine.undefined &&
scheduledFunc.runAtMillis >= oldMillis &&
scheduledFunc.runAtMillis <= nowMillis) {
funcsToRun.push(scheduledFunc);
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
}
}
if (funcsToRun.length > 0) {
funcsToRun.sort(function(a, b) {
return a.runAtMillis - b.runAtMillis;
});
for (var i = 0; i < funcsToRun.length; ++i) {
try {
var funcToRun = funcsToRun[i];
this.nowMillis = funcToRun.runAtMillis;
funcToRun.funcToCall();
if (funcToRun.recurring) {
this.scheduleFunction(funcToRun.timeoutKey,
funcToRun.funcToCall,
funcToRun.millis,
true);
}
} catch(e) {
}
}
this.runFunctionsWithinRange(oldMillis, nowMillis);
}
};
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
this.scheduledFunctions[timeoutKey] = {
runAtMillis: this.nowMillis + millis,
funcToCall: funcToCall,
recurring: recurring,
timeoutKey: timeoutKey,
millis: millis
};
};
/**
* @namespace
*/
jasmine.Clock = {
defaultFakeTimer: new jasmine.FakeTimer(),
reset: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.reset();
},
tick: function(millis) {
jasmine.Clock.assertInstalled();
jasmine.Clock.defaultFakeTimer.tick(millis);
},
runFunctionsWithinRange: function(oldMillis, nowMillis) {
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
},
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
},
useMock: function() {
if (!jasmine.Clock.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Clock.uninstallMock);
jasmine.Clock.installMock();
}
},
installMock: function() {
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
},
uninstallMock: function() {
jasmine.Clock.assertInstalled();
jasmine.Clock.installed = jasmine.Clock.real;
},
real: {
setTimeout: jasmine.getGlobal().setTimeout,
clearTimeout: jasmine.getGlobal().clearTimeout,
setInterval: jasmine.getGlobal().setInterval,
clearInterval: jasmine.getGlobal().clearInterval
},
assertInstalled: function() {
if (!jasmine.Clock.isInstalled()) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
isInstalled: function() {
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
if (jasmine.Clock.installed.setInterval.apply) {
return jasmine.Clock.installed.setInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.setInterval(funcToCall, millis);
}
};
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
jasmine.getGlobal().clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
jasmine.version_= {
"major": 1,
"minor": 1,
"minor": 2,
"build": 0,
"revision": 1307546962
"revision": 1337005947
};

1
lib/jasmine-core/spec Symbolic link
View File

@@ -0,0 +1 @@
../../spec

View File

@@ -0,0 +1,6 @@
module Jasmine
module Core
VERSION = "1.2.0"
end
end

View File

@@ -1,190 +0,0 @@
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.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;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

View File

@@ -1,166 +0,0 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}

2
pages

Submodule pages updated: d08ce2de24...b928db73fc

View File

@@ -1,4 +1,4 @@
describe("TrivialConsoleReporter", function() {
describe("ConsoleReporter", function() {
//keep these literal. otherwise the test loses value as a test.
function green(str) {
return '\033[32m' + str + '\033[0m';
@@ -107,14 +107,14 @@ describe("TrivialConsoleReporter", function() {
})();
done = false;
reporter = new jasmine.TrivialConsoleReporter(out.print, function(runner) {
reporter = new jasmine.ConsoleReporter(out.print, function(runner) {
done = true
});
});
describe('Integration', function() {
it("prints the proper output under a pass scenario. small numbers.", function() {
it("prints the proper output under a pass scenario - small numbers.", function() {
simulateRun(reporter,
repeat(passingSpec, 3),
[],
@@ -134,16 +134,10 @@ describe("TrivialConsoleReporter", function() {
1777
);
expect(out.getOutput()).toEqual(
[
"Started",
green(".") + green(".") + green("."),
"",
"Finished in 0.777 seconds",
green("3 specs, 0 failures"),
""
].join("\n") + "\n"
);
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/\.\.\./);
expect(output).toMatch(/3 specs, 0 failures/);
});
it("prints the proper output under a pass scenario. large numbers.", function() {
@@ -165,33 +159,12 @@ describe("TrivialConsoleReporter", function() {
1000,
1777);
expect(out.getOutput()).toEqual(
[
"Started",
green(".") + green(".") + green(".") + green(".") + green(".") + //50 green dots
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") +
green(".") + green(".") + green(".") + green(".") + green(".") + //7 green dots
green(".") + green("."),
"",
"Finished in 0.777 seconds",
green("3 specs, 0 failures"),
""
].join("\n") + "\n"
);
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\./);
expect(output).toMatch(/3 specs, 0 failures/);
});
it("prints the proper output under a failure scenario.", function() {
simulateRun(reporter,
[failingSpec, passingSpec, failingSpec],
@@ -237,24 +210,12 @@ describe("TrivialConsoleReporter", function() {
1000,
1777);
expect(out.getOutput()).toEqual(
[
"Started",
red("F") + green(".") + red("F"),
"",
"The oven heats up",
" stack trace one",
" second line",
" stack trace two",
"",
"The washing machine washes clothes",
" stack trace one",
"",
"Finished in 0.777 seconds",
red("3 specs, 2 failures"),
""
].join("\n") + "\n"
);
var output = out.getOutput();
expect(output).toMatch(/^Started/);
expect(output).toMatch(/F\.F/);
expect(output).toMatch(/The oven heats up\n stack trace one\n second line\n stack trace two/);
expect(output).toMatch(/The washing machine washes clothes\n stack trace one/);
expect(output).toMatch(/3 specs, 2 failures/);
});
});
@@ -275,19 +236,19 @@ describe("TrivialConsoleReporter", function() {
it("prints a green dot if the spec passes", function() {
reporter.reportSpecResults(passingSpec);
expect(out.getOutput()).toEqual(green("."));
expect(out.getOutput()).toMatch(/\./);
});
it("prints a red dot if the spec fails", function() {
reporter.reportSpecResults(failingSpec);
expect(out.getOutput()).toEqual(red("F"));
expect(out.getOutput()).toMatch(/F/);
});
it("prints a yellow star if the spec was skipped", function() {
reporter.reportSpecResults(skippedSpec);
expect(out.getOutput()).toEqual(yellow("*"));
expect(out.getOutput()).toMatch(/\*/);
});
});

View File

@@ -64,9 +64,10 @@ describe("jasmine.Env", function() {
"major": 1,
"minor": 9,
"build": 7,
"release_candidate": "1",
"revision": 8
};
expect(env.versionString()).toEqual("1.9.7 revision 8");
expect(env.versionString()).toEqual("1.9.7.rc1 revision 8");
});
it("should return a nice string when version is unknown", function() {

View File

@@ -352,6 +352,33 @@ describe("jasmine.Matchers", function() {
}]).toEqual(["a", jasmine.any(Function)])).toPass();
});
describe("toEqual with an object implementing jasmineMatches", function () {
var matcher;
beforeEach(function () {
matcher = {
jasmineMatches: jasmine.createSpy("jasmineMatches")
};
});
describe("on the left side", function () {
it("uses the jasmineMatches function", function () {
matcher.jasmineMatches.andReturn(false);
expect(match(matcher).toEqual("foo")).toFail();
matcher.jasmineMatches.andReturn(true);
expect(match(matcher).toEqual("foo")).toPass();
});
});
describe("on the right side", function () {
it("uses the jasmineMatches function", function () {
matcher.jasmineMatches.andReturn(false);
expect(match("foo").toEqual(matcher)).toFail();
matcher.jasmineMatches.andReturn(true);
expect(match("foo").toEqual(matcher)).toPass();
});
});
});
it("toEqual handles circular objects ok", function() {
expect(match({foo: "bar", baz: jasmine.undefined}).toEqual({foo: "bar", baz: jasmine.undefined})).toPass();
expect(match({foo:['bar','baz','quux']}).toEqual({foo:['bar','baz','quux']})).toPass();
@@ -830,6 +857,252 @@ describe("jasmine.Matchers", function() {
});
});
describe("ObjectContaining", function () {
describe("with an empty object", function () {
var containing;
beforeEach(function () {
containing = new jasmine.Matchers.ObjectContaining({});
});
it("matches everything", function () {
expect(containing.jasmineMatches("foo", [], [])).toBe(true);
});
it("says it didn't expect to contain anything", function () {
expect(containing.jasmineToString()).toEqual("<jasmine.objectContaining({ })>");
});
});
describe("with an object with items in it", function () {
var containing, mismatchKeys, mismatchValues;
beforeEach(function () {
mismatchKeys = [];
mismatchValues = [];
containing = new jasmine.Matchers.ObjectContaining({foo: "fooVal", bar: "barVal"});
});
it("doesn't match an empty object", function () {
expect(containing.jasmineMatches({}, mismatchKeys, mismatchValues)).toBe(false);
});
it("doesn't match an object with none of the specified options", function () {
expect(containing.jasmineMatches({baz:"stuff"}, mismatchKeys, mismatchValues)).toBe(false);
});
it("adds a message for each missing key", function () {
containing.jasmineMatches({foo: "fooVal"}, mismatchKeys, mismatchValues);
expect(mismatchKeys.length).toEqual(1);
});
it("doesn't match an object when the values are different", function () {
expect(containing.jasmineMatches({foo:"notFoo", bar:"notBar"}, mismatchKeys, mismatchValues)).toBe(false);
});
it("adds a message when values don't match", function () {
containing.jasmineMatches({foo: "fooVal", bar: "notBar"}, mismatchKeys, mismatchValues);
expect(mismatchValues.length).toEqual(1);
});
it("doesn't match an object with only one of the values matching", function () {
expect(containing.jasmineMatches({foo:"notFoo", bar:"barVal"}, mismatchKeys, mismatchValues)).toBe(false);
});
it("matches when all the values are the same", function () {
expect(containing.jasmineMatches({foo: "fooVal", bar: "barVal"}, mismatchKeys, mismatchValues)).toBe(true);
});
it("matches when there are additional values", function () {
expect(containing.jasmineMatches({foo: "fooVal", bar: "barVal", baz: "bazVal"}, mismatchKeys, mismatchValues)).toBe(true);
});
it("doesn't modify missingKeys or missingValues when match is successful", function () {
containing.jasmineMatches({foo: "fooVal", bar: "barVal"}, mismatchKeys, mismatchValues);
expect(mismatchKeys.length).toEqual(0);
expect(mismatchValues.length).toEqual(0);
});
it("says what it expects to contain", function () {
expect(containing.jasmineToString()).toEqual("<jasmine.objectContaining(" + jasmine.pp({foo:"fooVal", bar:"barVal"}) + ")>");
});
});
describe("in real life", function () {
var method;
beforeEach(function () {
method = jasmine.createSpy("method");
method({a:"b", c:"d"});
});
it("works correctly for positive matches", function () {
expect(method).toHaveBeenCalledWith(jasmine.objectContaining({a:"b"}));
});
it("works correctly for negative matches", function () {
expect(method).not.toHaveBeenCalledWith(jasmine.objectContaining({z:"x"}));
});
});
});
describe("Matchers.Any", function () {
var any;
describe(".jasmineToString", function () {
describe("with Object", function () {
it("says it's looking for an object", function () {
any = jasmine.any(Object);
expect(any.jasmineToString().replace(/\n/g, "")).toMatch(/<jasmine\.any\(function Object.*\)>/);
});
});
describe("with Function", function () {
it("says it's looking for a function", function () {
any = jasmine.any(Function);
expect(any.jasmineToString().replace(/\n/g, "")).toMatch(/<jasmine\.any\(function Function.*\)>/);
});
});
describe("with String", function () {
it("says it's looking for a string", function () {
any = jasmine.any(String);
expect(any.jasmineToString().replace(/\n/g, "")).toMatch(/<jasmine\.any\(function String.*\)>/);
});
});
describe("with Number", function () {
it("says it's looking for a number", function () {
any = jasmine.any(Number);
expect(any.jasmineToString().replace(/\n/g, "")).toMatch(/<jasmine\.any\(function Number.*\)>/);
});
});
describe("with some other defined 'class'", function () {
it("says it's looking for an object", function () {
function MyClass () {}
any = jasmine.any(MyClass);
expect(any.jasmineToString().replace("\n", "")).toMatch(/<jasmine\.any\(function MyClass.*\)>/);
});
});
});
describe(".jasmineMatches", function () {
describe("with Object", function () {
beforeEach(function () {
any = jasmine.any(Object);
});
it("matches an empty object", function () {
expect(any.jasmineMatches({})).toEqual(true);
});
it("matches a newed up object", function () {
expect(any.jasmineMatches(new Object())).toEqual(true);
});
it("doesn't match a string", function () {
expect(any.jasmineMatches("")).toEqual(false);
});
it("doesn't match a number", function () {
expect(any.jasmineMatches(123)).toEqual(false);
});
it("doesn't match a function", function () {
expect(any.jasmineMatches(function () {})).toEqual(false);
});
});
describe("with Function", function () {
beforeEach(function () {
any = jasmine.any(Function);
});
it("doesn't match an object", function () {
expect(any.jasmineMatches({})).toEqual(false);
});
it("doesn't match a string", function () {
expect(any.jasmineMatches("")).toEqual(false);
});
it("doesn't match a number", function () {
expect(any.jasmineMatches(123)).toEqual(false);
});
it("matches a function", function () {
expect(any.jasmineMatches(function () {})).toEqual(true);
});
});
describe("with Number", function () {
beforeEach(function () {
any = jasmine.any(Number);
});
it("doesn't match an object", function () {
expect(any.jasmineMatches({})).toEqual(false);
});
it("doesn't match a string", function () {
expect(any.jasmineMatches("")).toEqual(false);
});
it("matches a number", function () {
expect(any.jasmineMatches(123)).toEqual(true);
});
it("doesn't match a function", function () {
expect(any.jasmineMatches(function () {})).toEqual(false);
});
});
describe("with String", function () {
beforeEach(function () {
any = jasmine.any(String);
});
it("doesn't match an object", function () {
expect(any.jasmineMatches({})).toEqual(false);
});
it("matches a string", function () {
expect(any.jasmineMatches("")).toEqual(true);
});
it("doesn't match a number", function () {
expect(any.jasmineMatches(123)).toEqual(false);
});
it("doesn't match a function", function () {
expect(any.jasmineMatches(function () {})).toEqual(false);
});
});
describe("with some defined 'class'", function () {
function MyClass () {}
beforeEach(function () {
any = jasmine.any(MyClass);
});
it("doesn't match an object", function () {
expect(any.jasmineMatches({})).toEqual(false);
});
it("doesn't match a string", function () {
expect(any.jasmineMatches("")).toEqual(false);
});
it("doesn't match a number", function () {
expect(any.jasmineMatches(123)).toEqual(false);
});
it("doesn't match a function", function () {
expect(any.jasmineMatches(function () {})).toEqual(false);
});
it("matches an instance of the defined class", function () {
expect(any.jasmineMatches(new MyClass())).toEqual(true);
});
});
});
});
describe("all matchers", function() {
it("should return null, for future-proofing, since we might eventually allow matcher chaining", function() {
expect(match(true).toBe(true)).toBeUndefined();

View File

@@ -83,5 +83,12 @@ describe("jasmine.pp", function () {
expect(jasmine.pp(jasmine.createSpy("something"))).toEqual("spy on something");
});
it("should stringify objects that implement jasmineToString", function () {
var obj = {
jasmineToString: function () { return "strung"; }
};
expect(jasmine.pp(obj)).toEqual("strung");
});
});

View File

@@ -0,0 +1,209 @@
describe("HtmlReporter", function() {
var env;
var htmlReporter;
var body;
var fakeDocument;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
body = document.createElement("body");
fakeDocument = { body: body, location: { search: "" } };
htmlReporter = new jasmine.HtmlReporter(fakeDocument);
});
function fakeSpec(name) {
return {
getFullName: function() {
return name;
}
};
}
function findElements(divs, withClass) {
var els = [];
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == withClass) els.push(divs[i]);
}
return els;
}
function findElement(divs, withClass) {
var els = findElements(divs, withClass);
if (els.length > 0) {
return els[0];
}
throw new Error("couldn't find div with class " + withClass);
}
it("should run only specs beginning with spec parameter", function() {
fakeDocument.location.search = "?spec=run%20this";
expect(htmlReporter.specFilter(fakeSpec("run this"))).toBeTruthy();
expect(htmlReporter.specFilter(fakeSpec("not the right spec"))).toBeFalsy();
expect(htmlReporter.specFilter(fakeSpec("not run this"))).toBeFalsy();
});
describe("running without any specs", function() {
var runner;
beforeEach(function() {
runner = env.currentRunner();
env.addReporter(htmlReporter);
});
it("should not error", function() {
var exec = function() {
runner.execute();
};
expect(exec).not.toThrow();
});
});
describe('Matcher reporting', function() {
var getResultMessageDiv = function(body) {
var divs = body.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
if (divs[i].className.match(/resultMessage/)) {
return divs[i];
}
}
};
var runner, spec, fakeTimer;
beforeEach(function() {
fakeTimer = new jasmine.FakeTimer();
env.setTimeout = fakeTimer.setTimeout;
env.clearTimeout = fakeTimer.clearTimeout;
env.setInterval = fakeTimer.setInterval;
env.clearInterval = fakeTimer.clearInterval;
runner = env.currentRunner();
var suite = new jasmine.Suite(env, 'some suite');
runner.add(suite);
spec = new jasmine.Spec(env, suite, 'some spec');
suite.add(spec);
fakeDocument.location.search = "?";
env.addReporter(htmlReporter);
});
describe('toContain', function() {
it('should show actual and expected', function() {
spec.runs(function() {
this.expect('foo').toContain('bar');
});
runner.execute();
fakeTimer.tick(0);
var resultEl = getResultMessageDiv(body);
expect(resultEl.innerHTML).toMatch(/foo/);
expect(resultEl.innerHTML).toMatch(/bar/);
});
});
});
describe("failure messages (integration)", function() {
var spec, results, expectationResult;
it("should add the failure message to the DOM (non-toEquals matchers)", function() {
env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect('a').toBeNull();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toMatch(/Expected 'a' to be null/);
});
it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() {
env.describe("suite", function() {
env.it("will have log messages", function() {
this.expect('1 < 2').toBeNull();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toMatch(/Expected '1 &lt; 2' to be null/);
});
});
describe("log messages", function() {
it("should appear in the report of a failed spec", function() {
env.describe("suite", function() {
env.it("will have log messages", function() {
this.log("this is a", "multipart log message");
this.expect(true).toBeFalsy();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var errorDiv = findElement(divs, 'specDetail failed');
expect(errorDiv.innerHTML).toMatch("this is a multipart log message");
});
xit("should work on IE without console.log.apply", function() {
});
});
describe("duplicate example names", function() {
it("should report failures correctly", function() {
var suite1 = env.describe("suite", function() {
env.it("will have log messages", function() {
this.log("this one fails!");
this.expect(true).toBeFalsy();
});
});
var suite2 = env.describe("suite", function() {
env.it("will have log messages", function() {
this.log("this one passes!");
this.expect(true).toBeTruthy();
});
});
env.addReporter(htmlReporter);
env.execute();
var divs = body.getElementsByTagName("div");
var failedSpecDiv = findElement(divs, 'specDetail failed');
expect(failedSpecDiv.className).toEqual('specDetail failed');
expect(failedSpecDiv.innerHTML).toContain("this one fails!");
expect(failedSpecDiv.innerHTML).not.toContain("this one passes!");
});
});
describe('#reportSpecStarting', function() {
beforeEach(function() {
env.describe("suite 1", function() {
env.it("spec 1", function() {
});
});
spyOn(htmlReporter, 'log').andCallThrough();
});
it('DOES NOT log running specs by default', function() {
env.addReporter(htmlReporter);
env.execute();
expect(htmlReporter.log).not.toHaveBeenCalled();
});
it('logs running specs when log_running_specs is true', function() {
htmlReporter.logRunningSpecs = true;
env.addReporter(htmlReporter);
env.execute();
expect(htmlReporter.log).toHaveBeenCalledWith('>> Jasmine Running suite 1 spec 1...');
});
});
});

View File

@@ -1,16 +1,16 @@
var fs = require('fs');
var sys = require('sys');
var util = require('util');
var path = require('path');
// yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]
// undefined = "diz be undefined yo";
var jasmineGlobals = require('../lib/jasmine.js');
var jasmineGlobals = require('../lib/jasmine-core/jasmine.js');
for (var k in jasmineGlobals) {
global[k] = jasmineGlobals[k];
}
require('../src/console/TrivialConsoleReporter.js');
require('../src/console/ConsoleReporter.js');
/*
Pulling in code from jasmine-node.
@@ -30,14 +30,14 @@ delete global.window;
function noop() {
}
jasmine.executeSpecs = function(specs, done) {
jasmine.executeSpecs = function(specs, done, isVerbose, showColors) {
for (var i = 0, len = specs.length; i < len; ++i) {
var filename = specs[i];
require(filename.replace(/\.\w+$/, ""));
}
var jasmineEnv = jasmine.getEnv();
var consoleReporter = new jasmine.TrivialConsoleReporter(sys.print, done);
var consoleReporter = new jasmine.ConsoleReporter(util.print, done, showColors);
jasmineEnv.addReporter(consoleReporter);
jasmineEnv.execute();
@@ -124,4 +124,4 @@ jasmine.executeSpecs(domIndependentSpecs, function(runner, log) {
} else {
process.exit(1);
}
}, isVerbose, showColors);
}, isVerbose, showColors);

View File

@@ -2,62 +2,83 @@
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Test Runner</title>
<title>Jasmine Spec Runner: Jasmine Core</title>
<link rel="shortcut icon" type="image/png" href="../images/jasmine_favicon.png">
<link href="../lib/jasmine-core/jasmine.css" rel="stylesheet"/>
<script type="text/javascript" src="../lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript">
// yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]
undefined = "diz be undefined yo";
</script>
<link rel="shortcut icon" type="image/png" href="../images/jasmine_favicon.png">
<script type="text/javascript" src="../lib/jasmine.js"></script>
<script type="text/javascript" src="../src/html/TrivialReporter.js"></script>
<script type="text/javascript" src="../src/console/TrivialConsoleReporter.js"></script>
<script type="text/javascript" src="core/BaseSpec.js"></script>
<script type="text/javascript" src="core/CustomMatchersSpec.js"></script>
<script type="text/javascript" src="core/EnvSpec.js"></script>
<script type="text/javascript" src="core/ExceptionsSpec.js"></script>
<script type="text/javascript" src="core/JsApiReporterSpec.js"></script>
<script type="text/javascript" src="core/MatchersSpec.js"></script>
<script type="text/javascript" src="core/MockClockSpec.js"></script>
<script type="text/javascript" src="core/MultiReporterSpec.js"></script>
<script type="text/javascript" src="core/NestedResultsSpec.js"></script>
<script type="text/javascript" src="core/PrettyPrintSpec.js"></script>
<script type="text/javascript" src="core/ReporterSpec.js"></script>
<script type="text/javascript" src="core/RunnerSpec.js"></script>
<script type="text/javascript" src="core/QueueSpec.js"></script>
<script type="text/javascript" src="core/SpecSpec.js"></script>
<script type="text/javascript" src="core/SpecRunningSpec.js"></script>
<script type="text/javascript" src="core/SpySpec.js"></script>
<script type="text/javascript" src="core/SuiteSpec.js"></script>
<script type="text/javascript" src="core/UtilSpec.js"></script>
<script type="text/javascript" src="core/WaitsForBlockSpec.js"></script>
<script type="text/javascript" src="console/TrivialConsoleReporterSpec.js"></script>
<script type="text/javascript" src="html/MatchersHtmlSpec.js"></script>
<script type="text/javascript" src="html/PrettyPrintHtmlSpec.js"></script>
<script type="text/javascript" src="html/TrivialReporterSpec.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src=".././src/html/HtmlReporterHelpers.js"></script>
<script type="text/javascript" src=".././src/html/HtmlReporter.js"></script>
<script type="text/javascript" src=".././src/html/HtmlReporterHelpers.js"></script>
<script type="text/javascript" src=".././src/html/ReporterView.js"></script>
<script type="text/javascript" src=".././src/html/SpecView.js"></script>
<script type="text/javascript" src=".././src/html/SuiteView.js"></script>
<script type="text/javascript" src=".././src/html/TrivialReporter.js"></script>
<script type="text/javascript" src=".././src/console/ConsoleReporter.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src=".././spec/core/BaseSpec.js"></script>
<script type="text/javascript" src=".././spec/core/CustomMatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/EnvSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ExceptionsSpec.js"></script>
<script type="text/javascript" src=".././spec/core/JsApiReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MatchersSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MockClockSpec.js"></script>
<script type="text/javascript" src=".././spec/core/MultiReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/NestedResultsSpec.js"></script>
<script type="text/javascript" src=".././spec/core/PrettyPrintSpec.js"></script>
<script type="text/javascript" src=".././spec/core/QueueSpec.js"></script>
<script type="text/javascript" src=".././spec/core/ReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/core/RunnerSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecRunningSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpecSpec.js"></script>
<script type="text/javascript" src=".././spec/core/SpySpec.js"></script>
<script type="text/javascript" src=".././spec/core/SuiteSpec.js"></script>
<script type="text/javascript" src=".././spec/core/UtilSpec.js"></script>
<script type="text/javascript" src=".././spec/core/WaitsForBlockSpec.js"></script>
<script type="text/javascript" src=".././spec/html/HTMLReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/html/MatchersHtmlSpec.js"></script>
<script type="text/javascript" src=".././spec/html/PrettyPrintHtmlSpec.js"></script>
<script type="text/javascript" src=".././spec/html/TrivialReporterSpec.js"></script>
<script type="text/javascript" src=".././spec/console/ConsoleReporterSpec.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
jasmineEnv.execute();
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
<link href="../src/html/jasmine.css" rel="stylesheet"/>
</head>
<body>

51
spec/spec_helper.rb Normal file
View File

@@ -0,0 +1,51 @@
# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# Require this file using `require "spec_helper.rb"` to ensure that it is only
# loaded once.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
config.filter_run :focus
end
require 'awesome_print'
require 'tmpdir'
require 'nokogiri'
def project_root
File.join(File.expand_path(File.dirname(__FILE__)), '..')
end
require "#{project_root}/tasks/jasmine_dev"
def capture_output(capture = true)
if capture
output = StringIO.new
$stdout = output
end
yield
if capture
output.string
end
ensure
$stdout = STDOUT
end
def reset_dir(dir)
FileUtils.rm_r dir if File.exists?(dir)
FileUtils.mkdir_p dir
end
def jasmine_version
version = jasmine_version_object
version_string = "#{version['major']}.#{version['minor']}.#{version['build']}"
version_string += ".rc#{version['release_candidate']}" if version['release_candidate']
version_string
end
def jasmine_version_object
@version_object ||= JSON.parse(File.read(File.join(JasmineDev.project_root, 'src', 'version.json')))
end

View File

@@ -0,0 +1,33 @@
require 'spec_helper.rb'
describe "Build Jasmine task" do
let(:jasmine_core_dir) { "#{Dir.tmpdir}/jasmine-core" }
let(:jasmine_dev) { JasmineDev.new }
before do
reset_dir jasmine_core_dir
@output = capture_output { jasmine_dev.build_distribution jasmine_core_dir }
end
it "should say that JSHint is running" do
@output.should match(/Running JSHint/)
@output.should match(/Jasmine JSHint PASSED/)
end
it "should tell the developer it is building the distribution" do
@output.should match(/Building Jasmine distribution/)
end
it "should build jasmine.js in the destination directory" do
File.exist?("#{jasmine_core_dir}/jasmine.js").should be_true
end
it "should build jasmine-html.js in the destination directory" do
File.exist?("#{jasmine_core_dir}/jasmine-html.js").should be_true
end
it "should build jasmine.css" do
File.exist?("#{jasmine_core_dir}/jasmine.css").should be_true
end
end

View File

@@ -0,0 +1,69 @@
require 'spec_helper.rb'
describe "Build Github Pages task" do
let(:pages_dir) { File.join(Dir.tmpdir, 'pages') }
let(:jasmine_dev) { JasmineDev.new }
before do
reset_dir pages_dir
end
describe "when the Github pages submodule is not present" do
before do
jasmine_dev.should_receive(:has_pages_submodule?).and_return(false)
@output = capture_output { jasmine_dev.build_github_pages pages_dir }
end
it "should tell the user the task is running" do
@output.should match(/Building Github Pages/)
end
it "should prompt the user to install the submodule" do
@output.should match(/Submodule for Github Pages isn't present/)
end
end
describe "when the Github pages submodule is present" do
before do
jasmine_dev.should_receive(:has_pages_submodule?).and_return(true)
@output = capture_output { jasmine_dev.build_github_pages pages_dir }
end
it "should tell the user the task is running" do
@output.should match(/Building Github Pages/)
end
it "should tell the user the pages are built" do
@output.should match(/Congratulations, project dumped to/)
end
it "should build the pages output to the requested diretory" do
Dir.chdir File.join(pages_dir, 'pages_output') do
pages = Dir.glob(File.join('**', '*'))
pages.should include('download.html')
pages.should include('index.html')
pages.should include(File.join('images', 'jasmine_logo.png'))
pages.should include(File.join('images', 'pivotal_logo.gif'))
pages.should include(File.join('css', 'pygments.css'))
pages.should include(File.join('css', 'screen.css'))
end
end
it "should copy the generated page files to the destination directory" do
Dir.chdir pages_dir do
pages = Dir.glob(File.join('**', '*'))
pages.should include('download.html')
pages.should include('index.html')
pages.should include(File.join('images', 'jasmine_logo.png'))
pages.should include(File.join('images', 'pivotal_logo.gif'))
pages.should include(File.join('css', 'pygments.css'))
pages.should include(File.join('css', 'screen.css'))
end
end
end
end

View File

@@ -0,0 +1,109 @@
require 'spec_helper.rb'
describe "Standalone Distribution tasks" do
let(:jasmine_dev) { JasmineDev.new }
let(:standalone_temp_dir) { File.join(Dir.tmpdir, 'jasmine_test') }
let(:download_dir) { File.join(standalone_temp_dir, 'download')}
describe "build_standalone_distribution" do
before do
reset_dir standalone_temp_dir
reset_dir download_dir
Dir.should_receive(:tmpdir).any_number_of_times.and_return(standalone_temp_dir)
@standalone_staging_dir = File.join(standalone_temp_dir, 'jasmine_standalone')
@version_dir = File.join(@standalone_staging_dir, "jasmine-standalone-#{jasmine_version}")
@lib_dir = File.join(@version_dir, 'lib')
@source_dir = File.join(@version_dir, 'src')
@spec_dir = File.join(@version_dir, 'spec')
@output = capture_output { jasmine_dev.build_standalone_distribution download_dir }
end
it "should build the distribution" do
@output.should match(/Building Jasmine distribution/)
end
it "should tell the developer the task has started" do
@output.should match(/Building standalone distribution/)
end
it "should copy the lib directory to the staging directory, under a versioned directory" do
lib_dir_files = Dir.glob(File.join(standalone_temp_dir, 'jasmine_standalone', '**', '*'))
staged_lib_files = %w{ jasmine.js jasmine-html.js jasmine.css MIT.LICENSE }
staged_lib_files.each do |filename|
lib_dir_files.should include(File.join(@lib_dir, "jasmine-#{jasmine_version}", filename))
end
end
it "should copy the sample project source to the staging directory" do
File.exist?(File.join(@source_dir, 'Player.js')).should be_true
File.exist?(File.join(@source_dir, 'Song.js')).should be_true
end
it "should copy the sample project specs to the staging directory" do
File.exist?(File.join(@spec_dir, 'PlayerSpec.js')).should be_true
File.exist?(File.join(@spec_dir, 'SpecHelper.js')).should be_true
end
it "should copy a build SpecRunner.html to the staging directory" do
File.exist?(File.join(@version_dir, 'SpecRunner.html')).should be_true
end
it "should zip up the contents of the staging directory" do
File.exist?(File.join(@standalone_staging_dir, "jasmine-standalone-#{jasmine_version}.zip")).should be_true
end
it "should copy the zip file to the pages sub directory" do
File.exist?(File.join(download_dir, "jasmine-standalone-#{jasmine_version}.zip")).should be_true
end
describe "when the zip file is unzipped" do
before do
@out_directory = File.join(standalone_temp_dir, 'unzip')
reset_dir @out_directory
FileUtils.cp File.join(@standalone_staging_dir, "jasmine-standalone-#{jasmine_version}.zip"),
@out_directory
Dir.chdir @out_directory do
system("unzip -qq jasmine-standalone-#{jasmine_version}.zip")
end
end
describe "the distirbution" do
before do
Dir.chdir @out_directory do
@files = Dir.glob(File.join('**', '*'))
end
end
it "should include the correct root files" do
@files.should include('SpecRunner.html')
end
it "should include the correct lib files" do
%w{ jasmine.js jasmine-html.js jasmine.css MIT.LICENSE }.each do |file|
@files.should include(File.join('lib', "jasmine-#{jasmine_version}", file))
end
end
it "should include the correct src files" do
%w{Player.js Song.js}.each do |file|
@files.should include(File.join('src', file))
end
end
it "should include the correct spec files" do
%w{PlayerSpec.js SpecHelper.js}.each do |file|
@files.should include(File.join('spec', file))
end
end
end
end
end
end

View File

@@ -0,0 +1,63 @@
require 'spec_helper.rb'
describe "Build Standalone runner HTML task" do
let(:jasmine_dev) { JasmineDev.new }
let(:standalone_temp_dir) { "#{Dir.tmpdir}/jasmine_test" }
describe "build_standalone_runner" do
before do
reset_dir standalone_temp_dir
Dir.should_receive(:tmpdir).any_number_of_times.and_return(standalone_temp_dir)
@standalone_staging_dir = File.join(standalone_temp_dir, 'jasmine_standalone')
@version_dir = File.join(@standalone_staging_dir, "jasmine-standalone-#{jasmine_version}")
@output = capture_output { jasmine_dev.build_standalone_runner }
end
it "should tell the developer the task has started" do
@output.should match(/Building standalone runner HTML/)
end
it "should copy a build SpecRunner.html to the staging directory" do
File.exist?(File.join(@version_dir, 'SpecRunner.html')).should be_true
end
describe "should build the file that has HTML that" do
before do
html = File.read(File.join(@version_dir, 'SpecRunner.html'))
@runner = Nokogiri(html)
end
it "should have the favicon tag" do
favicon_tag = @runner.css('link')[0]
favicon_tag['href'].should match("lib/jasmine-#{jasmine_version}/jasmine_favicon.png")
end
it "should have the stylesheet" do
css_tag = @runner.css('link')[1]
css_tag['href'].should match("lib/jasmine-#{jasmine_version}/jasmine.css")
end
it "should have the jasmine script tags" do
script_sources = @runner.css('script').collect {|tag| tag['src']}
script_sources.should include("lib/jasmine-#{jasmine_version}/jasmine.js")
script_sources.should include("lib/jasmine-#{jasmine_version}/jasmine-html.js")
end
it "should have the example source files" do
script_sources = @runner.css('script').collect {|tag| tag['src']}
script_sources.should include('src/Player.js')
script_sources.should include('src/Song.js')
end
it "should have the example source files" do
script_sources = @runner.css('script').collect {|tag| tag['src']}
script_sources.should include('spec/SpecHelper.js')
script_sources.should include('spec/PlayerSpec.js')
end
end
end
end

View File

@@ -0,0 +1,26 @@
require 'spec_helper.rb'
describe "Spec counting task" do
let(:jasmine_dev) { JasmineDev.new }
before do
@output = capture_output { jasmine_dev.count_specs }
end
it "should tell the developer that the specs are being counted" do
@output.should match(/Counting specs/)
end
it "should report the number of specs that will run in node" do
@output.should match(/\d+ \e\[0mspecs for Node.js/)
end
it "should report the number of specs that will run in the browser" do
@output.should match(/\d+ \e\[0mspecs for Browser/)
end
it "should remind the developer to check the count" do
@output.should match(/Please verify/)
end
end

View File

@@ -0,0 +1,81 @@
require 'spec_helper.rb'
describe "Spec tasks" do
let(:jasmine_dev) { JasmineDev.new }
describe "execute_specs_in_node" do
describe "when Node.js is not present" do
before do
jasmine_dev.should_receive(:has_node?).and_return(false)
@output = capture_output { jasmine_dev.execute_specs_in_node }
end
it "should prompt the user to install Node" do
@output.should match(/Node\.js is required/)
end
end
describe "when Node.js is present" do
before do
jasmine_dev.should_receive(:has_node?).and_return(true)
@output = capture_output { jasmine_dev.execute_specs_in_node }
end
it "should build the distribution" do
@output.should match(/Building Jasmine distribution/)
end
it "should tell the developer that the specs are being counted" do
@output.should match(/Counting specs/)
end
it "should tell the user that the specs are running in Node.js" do
@output.should match(/specs via Node/)
@output.should match(/Started/)
@output.should match(/\d+ specs, 0 failures/)
end
end
end
describe "execute_specs_in_browser" do
before do
jasmine_dev.should_receive(:run)
@output = capture_output { jasmine_dev.execute_specs_in_browser }
end
it "should build the distribution" do
@output.should match(/Building Jasmine distribution/)
end
it "should tell the developer that the specs are being counted" do
@output.should match(/Counting specs/)
end
it "should tell the user that the specs are running in the broswer" do
@output.should match(/specs via the default web browser/)
end
end
describe "execute_specs" do
before do
@output = capture_output { jasmine_dev.execute_specs }
end
it "should build the distribution" do
@output.should match(/Building Jasmine distribution/)
end
it "should tell the developer that the specs are being counted" do
@output.should match(/Counting specs/)
end
it "should tell the user that the specs are running in Node.js" do
@output.should match(/specs via Node/)
end
it "should tell the user that the specs are running in the broswer" do
@output.should match(/specs via the default web browser/)
end
end
end

39
spec/tasks/jshint_spec.rb Normal file
View File

@@ -0,0 +1,39 @@
require 'spec_helper.rb'
describe "JSHint task" do
let(:tmp_dir) { "#{Dir.tmpdir}/jasmine_tasks_test" }
let(:jasmine_dev) { JasmineDev.new }
before do
reset_dir tmp_dir
end
describe "when Node is not present" do
before do
jasmine_dev.should_receive(:has_node?).and_return(false)
@output = capture_output { jasmine_dev.js_hint }
end
it "should not tell the user that lint is running" do
@output.should_not match(/Running JSHint/)
end
it "should prompt the user to install Node" do
@output.should match(/Node\.js is required/)
end
end
describe "when Node is present" do
before do
jasmine_dev.should_receive(:has_node?).and_return(true)
@output = capture_output { jasmine_dev.js_hint }
end
it "should tell the user that lint is running" do
@output.should match(/Running JSHint/)
@output.should match(/Jasmine JSHint PASSED/)
end
end
end

View File

@@ -0,0 +1,39 @@
require 'spec_helper.rb'
describe "Release task" do
let(:jasmine_dev) { JasmineDev.new }
describe "when the pages submodule is not present" do
before do
jasmine_dev.should_receive(:has_pages_submodule?).and_return(false)
@output = capture_output { jasmine_dev.release_prep }
end
it "should tell the user the task is running" do
@output.should match(/Building Release/)
end
it "should prompt the user to install the submodule" do
@output.should match(/Submodule for Github Pages isn't present/)
end
end
describe "when the pages submodule is present" do
before do
JasmineDev.any_instance.should_receive(:write_version_files)
JasmineDev.any_instance.should_receive(:build_distribution)
JasmineDev.any_instance.should_receive(:build_standalone_distribution)
JasmineDev.any_instance.should_receive(:build_github_pages)
jasmine_dev.should_receive(:has_pages_submodule?).and_return(true)
@output = capture_output { jasmine_dev.release_prep }
end
it "should tell the user the task is running" do
@output.should match(/Building Release/)
end
end
end

View File

@@ -0,0 +1,55 @@
require 'spec_helper.rb'
describe "Version tasks" do
let(:jasmine_dev) { JasmineDev.new }
describe "write_version_files" do
before do
@output = capture_output { jasmine_dev.write_version_files }
end
it "should tell the user that the task has started" do
@output.should match(/Building version files/)
end
it "should build the version.js file" do
js_version = File.read(File.join(project_root, 'src', 'version.js'))
js_version.should match(%Q{"build": #{jasmine_version_object["build"]}})
js_version.should match(%Q{"minor": #{jasmine_version_object["minor"]}})
js_version.should match(%Q{"build": #{jasmine_version_object["build"]}})
if jasmine_version_object["release_candidate"]
js_version.should match(%Q{"release_candidate": #{jasmine_version_object["release_candidate"]}})
end
js_version.should match(/"revision": \d+/)
end
it "should build the jasmine-core ruby gem version" do
ruby_version = File.read(File.join(project_root, 'lib', 'jasmine-core', 'version.rb'))
ruby_version.should match(%Q{VERSION = "#{jasmine_version}"})
end
end
describe "display_version" do
describe "when Node.js is not present" do
before do
@output = capture_output { jasmine_dev.display_version }
end
it "should display a version header" do
@output.should match(/Current version/)
end
it "should display the current version Object" do
@output.should match(/Display version: \e\[33m\d+\.\d+\.\d+/)
end
it "should display the current version string" do
@output.should match(/\{ "major": \d+, "minor": \d+, "build": \d+/)
end
end
end
end

View File

@@ -0,0 +1,49 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title><%= title %></title>
<%= favicon %>
<%= jasmine_tags %>
<!-- include source files here... -->
<%= source_tags %>
<!-- include spec files here... -->
<%= spec_file_tags %>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1 @@
<script type="text/javascript" src="<%= file %>"></script>

View File

@@ -1,7 +0,0 @@
[
"base.js",
"util.js",
"Env.js",
"Reporter.js",
"Block.js"
]

View File

@@ -1,4 +1,4 @@
jasmine.TrivialConsoleReporter = function(print, doneCallback) {
jasmine.ConsoleReporter = function(print, doneCallback, showColors) {
//inspired by mhevery's jasmine-node reporter
//https://github.com/mhevery/jasmine-node
@@ -16,7 +16,7 @@ jasmine.TrivialConsoleReporter = function(print, doneCallback) {
};
function coloredStr(color, str) {
return ansi[color] + str + ansi.none;
return showColors ? (ansi[color] + str + ansi.none) : str;
}
function greenStr(str) {

View File

@@ -19,4 +19,4 @@ jasmine.Block.prototype.execute = function(onComplete) {
this.spec.fail(e);
}
onComplete();
};
};

View File

@@ -51,12 +51,17 @@ jasmine.Env.prototype.version = function () {
* @returns string containing jasmine version build info, if set.
*/
jasmine.Env.prototype.versionString = function() {
if (jasmine.version_) {
var version = this.version();
return version.major + "." + version.minor + "." + version.build + " revision " + version.revision;
} else {
if (!jasmine.version_) {
return "version unknown";
}
var version = this.version();
var versionString = version.major + "." + version.minor + "." + version.build;
if (version.release_candidate) {
versionString += ".rc" + version.release_candidate;
}
versionString += " revision " + version.revision;
return versionString;
};
/**
@@ -225,11 +230,19 @@ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
return a.getTime() == b.getTime();
}
if (a instanceof jasmine.Matchers.Any) {
if (a.jasmineMatches) {
return a.jasmineMatches(b);
}
if (b.jasmineMatches) {
return b.jasmineMatches(a);
}
if (a instanceof jasmine.Matchers.ObjectContaining) {
return a.matches(b);
}
if (b instanceof jasmine.Matchers.Any) {
if (b instanceof jasmine.Matchers.ObjectContaining) {
return b.matches(a);
}

View File

@@ -104,7 +104,7 @@ jasmine.Matchers.prototype.toEqual = function(expected) {
/**
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
* @param expected
* @deprecated as of 1.0. Use not.toNotEqual() instead.
* @deprecated as of 1.0. Use not.toEqual() instead.
*/
jasmine.Matchers.prototype.toNotEqual = function(expected) {
return !this.env.equals_(this.actual, expected);
@@ -277,7 +277,7 @@ jasmine.Matchers.prototype.toContain = function(expected) {
* Matcher that checks that the expected item is NOT an element in the actual Array.
*
* @param {Object} expected
* @deprecated as of 1.0. Use not.toNotContain() instead.
* @deprecated as of 1.0. Use not.toContain() instead.
*/
jasmine.Matchers.prototype.toNotContain = function(expected) {
return !this.env.contains_(this.actual, expected);
@@ -345,7 +345,7 @@ jasmine.Matchers.Any = function(expectedClass) {
this.expectedClass = expectedClass;
};
jasmine.Matchers.Any.prototype.matches = function(other) {
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
if (this.expectedClass == String) {
return typeof other == 'string' || other instanceof String;
}
@@ -365,7 +365,36 @@ jasmine.Matchers.Any.prototype.matches = function(other) {
return other instanceof this.expectedClass;
};
jasmine.Matchers.Any.prototype.toString = function() {
jasmine.Matchers.Any.prototype.jasmineToString = function() {
return '<jasmine.any(' + this.expectedClass + ')>';
};
jasmine.Matchers.ObjectContaining = function (sample) {
this.sample = sample;
};
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
mismatchKeys = mismatchKeys || [];
mismatchValues = mismatchValues || [];
var env = jasmine.getEnv();
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in this.sample) {
if (!hasKey(other, property) && hasKey(this.sample, property)) {
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
}
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
}
}
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
};
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
};

View File

@@ -23,8 +23,8 @@ jasmine.PrettyPrinter.prototype.format = function(value) {
this.emitScalar('null');
} else if (value === jasmine.getGlobal()) {
this.emitScalar('<global>');
} else if (value instanceof jasmine.Matchers.Any) {
this.emitScalar(value.toString());
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
} else if (typeof value === 'string') {
this.emitString(value);
} else if (jasmine.isSpy(value)) {

View File

@@ -74,4 +74,4 @@ jasmine.Runner.prototype.topLevelSuites = function() {
jasmine.Runner.prototype.results = function() {
return this.queue.results();
};
};

View File

@@ -79,4 +79,4 @@ jasmine.Suite.prototype.execute = function(onComplete) {
this.queue.start(function () {
self.finish(onComplete);
});
};
};

15
src/core/base.js Executable file → Normal file
View File

@@ -196,6 +196,21 @@ jasmine.any = function(clazz) {
return new jasmine.Matchers.Any(clazz);
};
/**
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
* attributes on the object.
*
* @example
* // don't care about any other attributes than foo.
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
*
* @param sample {Object} sample
* @returns matchable object for the sample
*/
jasmine.objectContaining = function (sample) {
return new jasmine.Matchers.ObjectContaining(sample);
};
/**
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
*

0
src/core/mock-timeout.js Executable file → Normal file
View File

101
src/html/HtmlReporter.js Normal file
View File

@@ -0,0 +1,101 @@
jasmine.HtmlReporter = function(_doc) {
var self = this;
var doc = _doc || window.document;
var reporterView;
var dom = {};
// Jasmine Reporter Public Interface
self.logRunningSpecs = false;
self.reportRunnerStarting = function(runner) {
var specs = runner.specs() || [];
if (specs.length == 0) {
return;
}
createReporterDom(runner.env.versionString());
doc.body.appendChild(dom.reporter);
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && reporterView.complete();
};
self.reportSuiteResults = function(suite) {
reporterView.suiteComplete(suite);
};
self.reportSpecStarting = function(spec) {
if (self.logRunningSpecs) {
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
self.reportSpecResults = function(spec) {
reporterView.specComplete(spec);
};
self.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
self.specFilter = function(spec) {
if (!focusedSpecName()) {
return true;
}
return spec.getFullName().indexOf(focusedSpecName()) === 0;
};
return self;
function focusedSpecName() {
var specName;
(function memoizeFocusedSpec() {
if (specName) {
return;
}
var paramMap = [];
var params = doc.location.search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
specName = paramMap.spec;
})();
return specName;
}
function createReporterDom(version) {
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
dom.banner = self.createDom('div', { className: 'banner' },
self.createDom('span', { className: 'title' }, "Jasmine "),
self.createDom('span', { className: 'version' }, version)),
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
dom.alert = self.createDom('div', {className: 'alert'}),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);

View File

@@ -0,0 +1,60 @@
jasmine.HtmlReporterHelpers = {};
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.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;
};
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
var results = child.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
return status;
};
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
var parentDiv = this.dom.summary;
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
var parent = child[parentSuite];
if (parent) {
if (typeof this.views.suites[parent.id] == 'undefined') {
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
}
parentDiv = this.views.suites[parent.id].element;
}
parentDiv.appendChild(childElement);
};
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
for(var fn in jasmine.HtmlReporterHelpers) {
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
}
};

164
src/html/ReporterView.js Normal file
View File

@@ -0,0 +1,164 @@
jasmine.HtmlReporter.ReporterView = function(dom) {
this.startedAt = new Date();
this.runningSpecCount = 0;
this.completeSpecCount = 0;
this.passedCount = 0;
this.failedCount = 0;
this.skippedCount = 0;
this.createResultsMenu = function() {
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
' | ',
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
this.summaryMenuItem.onclick = function() {
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
};
this.detailsMenuItem.onclick = function() {
showDetails();
};
};
this.addSpecs = function(specs, specFilter) {
this.totalSpecCount = specs.length;
this.views = {
specs: {},
suites: {}
};
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
if (specFilter(spec)) {
this.runningSpecCount++;
}
}
};
this.specComplete = function(spec) {
this.completeSpecCount++;
if (isUndefined(this.views.specs[spec.id])) {
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
}
var specView = this.views.specs[spec.id];
switch (specView.status()) {
case 'passed':
this.passedCount++;
break;
case 'failed':
this.failedCount++;
break;
case 'skipped':
this.skippedCount++;
break;
}
specView.refresh();
this.refresh();
};
this.suiteComplete = function(suite) {
var suiteView = this.views.suites[suite.id];
if (isUndefined(suiteView)) {
return;
}
suiteView.refresh();
};
this.refresh = function() {
if (isUndefined(this.resultsMenu)) {
this.createResultsMenu();
}
// currently running UI
if (isUndefined(this.runningAlert)) {
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
dom.alert.appendChild(this.runningAlert);
}
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
// skipped specs UI
if (isUndefined(this.skippedAlert)) {
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
}
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.skippedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.skippedAlert);
}
// passing specs UI
if (isUndefined(this.passedAlert)) {
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
}
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
// failing specs UI
if (isUndefined(this.failedAlert)) {
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
}
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
if (this.failedCount === 1 && isDefined(dom.alert)) {
dom.alert.appendChild(this.failedAlert);
dom.alert.appendChild(this.resultsMenu);
}
// summary info
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
};
this.complete = function() {
dom.alert.removeChild(this.runningAlert);
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
if (this.failedCount === 0) {
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
} else {
showDetails();
}
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
};
return this;
function showDetails() {
if (dom.reporter.className.search(/showDetails/) === -1) {
dom.reporter.className += " showDetails";
}
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDefined(obj) {
return !isUndefined(obj);
}
function specPluralizedFor(count) {
var str = count + " spec";
if (count > 1) {
str += "s"
}
return str;
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);

79
src/html/SpecView.js Normal file
View File

@@ -0,0 +1,79 @@
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
this.spec = spec;
this.dom = dom;
this.views = views;
this.symbol = this.createDom('li', { className: 'pending' });
this.dom.symbolSummary.appendChild(this.symbol);
this.summary = this.createDom('div', { className: 'specSummary' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.description)
);
this.detail = this.createDom('div', { className: 'specDetail' },
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
title: this.spec.getFullName()
}, this.spec.getFullName())
);
};
jasmine.HtmlReporter.SpecView.prototype.status = function() {
return this.getSpecStatus(this.spec);
};
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
this.symbol.className = this.status();
switch (this.status()) {
case 'skipped':
break;
case 'passed':
this.appendSummaryToSuiteDiv();
break;
case 'failed':
this.appendSummaryToSuiteDiv();
this.appendFailureDetail();
break;
}
};
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
this.summary.className += ' ' + this.status();
this.appendToSummary(this.spec, this.summary);
};
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
this.detail.className += ' ' + this.status();
var resultItems = this.spec.results().getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
this.detail.appendChild(messagesDiv);
this.dom.details.appendChild(this.detail);
}
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);

22
src/html/SuiteView.js Normal file
View File

@@ -0,0 +1,22 @@
jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
this.suite = suite;
this.dom = dom;
this.views = views;
this.element = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
);
this.appendToSummary(this.suite, this.element);
};
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
return this.getSpecStatus(this.suite);
};
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
this.element.className += " " + this.status();
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);

View File

@@ -1,3 +1,5 @@
/* @deprecated Use jasmine.HtmlReporter instead
*/
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
@@ -31,10 +33,10 @@ jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarA
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"),
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",

302
src/html/_HTMLReporter.scss Normal file
View File

@@ -0,0 +1,302 @@
@import "compass";
$line-height: 14px;
$margin-unit: 14px;
$feint-text-color: #aaa;
$light-text-color: #666;
$text-color: #333;
$page-background-color: #eee;
$light-passing-color: #a6b779;
$passing-color: #5e7d00;
$light-failing-color: #cf867e;
$failing-color: #b03911;
$neutral-color: #bababa;
$font-size: 11px;
$large-font-size: 14px;
body {
background-color: $page-background-color;
padding: 0;
margin: 5px;
overflow-y: scroll;
}
#HTMLReporter {
font-size: $font-size;
font-family: Monaco, "Lucida Console", monospace;
line-height: $line-height;
color: $text-color;
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
p, h1, h2, h3, h4, h5, h6 {
margin: 0;
line-height: $line-height;
}
.banner,
.symbolSummary,
.summary,
.resultMessage,
.specDetail .description,
.alert .bar,
.stackTrace {
padding-left: $margin-unit - 5px;
padding-right: $margin-unit - 5px;
}
// This div is available for testing elements that must be added to the DOM.
// We position it out of view, so it doesn't obstruct the runner.
#jasmine_content {
position: fixed;
right: 100%;
}
.version {
color: $feint-text-color;
}
//--- Banner ---//
.banner {
margin-top: $line-height;
}
.duration {
color: $feint-text-color;
float: right;
}
//--- Symbol summary ---//
.symbolSummary {
@include clearfix;
margin: $line-height 0;
li {
display: block;
float: left;
height: $line-height / 2;
width: $line-height;
margin-bottom: $line-height / 2;
//opacity: .9;
font-size: 16px;
&.passed {
font-size: 14px;
&:before{
color: $passing-color;
content: "\02022";
}
}
&.failed {
line-height: ($line-height / 2) + 2;
&:before{
color: $failing-color;
content: "x";
font-weight: bold;
margin-left: -1px;
}
}
&.skipped {
font-size: 14px;
&:before{
color: $neutral-color;
content: "\02022";
}
}
&.pending{
line-height: ($line-height / 2) + 4;
&:before {
color: $feint-text-color;
content: "-";
}
}
}
}
//--- Alert ---//
.bar {
line-height: $line-height * 2;
font-size: $large-font-size;
display: block;
color: #eee;
}
.runningAlert {
background-color: $light-text-color;
}
.skippedAlert {
background-color: $feint-text-color;
&:first-child {
background-color: $text-color;
}
&:hover {
text-decoration: none;
color: white;
text-decoration: underline;
}
}
.passingAlert {
background-color: $light-passing-color;
&:first-child {
background-color: $passing-color;
}
}
.failingAlert {
background-color: $light-failing-color;
&:first-child {
background-color: $failing-color
}
}
//--- Results ---//
.results {
margin-top: $line-height;
}
//--- Results menu ---//
#details {
display: none;
}
.resultsMenu,
.resultsMenu a {
background-color: #fff;
color: $text-color;
}
&.showDetails {
.summaryMenuItem {
font-weight: normal;
text-decoration: inherit;
&:hover {
text-decoration: underline;
}
}
.detailsMenuItem {
font-weight: bold;
text-decoration: underline;
}
.summary {
display: none;
}
#details {
display: block;
}
}
.summaryMenuItem {
font-weight: bold;
text-decoration: underline;
}
//--- Results summary ---//
.summary {
margin-top: $margin-unit;
.suite .suite, .specSummary {
margin-left: $margin-unit;
}
.specSummary {
&.passed a {
color: $passing-color;
}
&.failed a {
color: $failing-color;
}
}
}
.description+.suite {
margin-top: 0;
}
.suite {
margin-top: $margin-unit;
a {
color: $text-color;
}
}
//--- Results details ---//
#details {
.specDetail {
margin-bottom: $line-height * 2;
.description {
//line-height: $line-height * 2;
display: block;
color: white;
background-color: $failing-color;
//font-size: $large-font-size;
}
}
}
.resultMessage {
padding-top: $line-height;
color: $text-color;
}
.resultMessage span.result {
display: block;
}
.stackTrace {
margin: 5px 0 0 0;
max-height: $line-height * 16;
overflow: auto;
line-height: 18px;
color: $light-text-color;
border: 1px solid #ddd;
background: white;
white-space: pre;
}
}

View File

@@ -0,0 +1,169 @@
#TrivialReporter {
padding: 8px 13px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow-y: scroll;
background-color: white;
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
a:visited, a {
color: #303;
}
a:hover, a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
&.show-passed .passed,
&.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}
}

View File

@@ -1,166 +1,81 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }

2
src/html/jasmine.scss Normal file
View File

@@ -0,0 +1,2 @@
@import "HTMLReporter";
@import "TrivialReporter";

View File

@@ -0,0 +1,3 @@
<link rel="stylesheet" type="text/css" href="lib/jasmine-<%= jasmine_version %>/jasmine.css">
<script type="text/javascript" src="lib/jasmine-<%= jasmine_version %>/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-<%= jasmine_version %>/jasmine-html.js"></script>

View File

@@ -0,0 +1,7 @@
jasmine.version_= {
"major": <%= major %>,
"minor": <%= minor %>,
"build": <%= build %>,
"revision": <%= revision %><%= %Q{,\n "release_candidate": #{release_candidate}} if release_candidate %>
};

View File

@@ -0,0 +1,6 @@
module Jasmine
module Core
VERSION = "<%= "#{major}.#{minor}.#{build}" %><%= ".rc#{release_candidate}" if release_candidate %>"
end
end

7
src/version.js Normal file
View File

@@ -0,0 +1,7 @@
jasmine.version_= {
"major": 1,
"minor": 2,
"build": 0,
"revision": 1337006083
};

View File

@@ -1,5 +1,5 @@
{
"major": 1,
"minor": 1,
"minor": 2,
"build": 0
}

17
tasks/docs.rb Normal file
View File

@@ -0,0 +1,17 @@
desc "Build jasmine documentation"
task :doc => :require_pages_submodule do
puts 'Creating Jasmine Documentation'
require 'rubygems'
require 'jsdoc_helper'
FileUtils.rm_r "pages/jsdoc", :force => true
JsdocHelper::Rake::Task.new(:lambda_jsdoc) do |t|
t[:files] = core_sources + html_sources + console_sources
t[:options] = "-a"
t[:out] = "pages/jsdoc"
# JsdocHelper bug: template must be relative to the JsdocHelper gem, ick
t[:template] = File.join("../".*(100), Dir::getwd, "jsdoc-template")
end
Rake::Task[:lambda_jsdoc].invoke
end

18
tasks/jasmine_dev.rb Normal file
View File

@@ -0,0 +1,18 @@
require 'thor'
require 'json'
require 'tilt'
require 'ostruct'
$:.unshift(File.join(File.dirname(__FILE__), "jasmine_dev"))
require "base"
require "sources"
require "js_hint"
require "build_distribution"
require "build_github_pages"
require "build_standalone_distribution"
require "build_standalone_runner"
require "count_specs"
require "execute_specs"
require "release"
require "version"

54
tasks/jasmine_dev/base.rb Normal file
View File

@@ -0,0 +1,54 @@
class JasmineDev < Thor
include Thor::Actions
def self.source_root
File.dirname(__FILE__)
end
def self.source_paths
[
File.join(JasmineDev.project_root, 'lib', 'jasmine-core'),
JasmineDev.project_root
]
end
def self.project_root
File.join(JasmineDev.source_root, '..', '..')
end
def self.spacer
"\n--------------------"
end
no_tasks do
# allows merged stdout in test with low-harassment
def run_with_output(*run_args)
say run *run_args
end
def node_installed?
return true if has_node?
say "Node.js is required to develop Jasmine. Please visit http://nodejs.org to install.",
:red
false
end
def has_node?
run "which node", :verbose => false, :capture => true
$?.exitstatus == 0
end
def pages_submodule_installed?
return true if has_pages_submodule?
say "Submodule for Github Pages isn't present. Run git submodule update --init",
:red
false
end
def has_pages_submodule?
File.exist?(File.join(JasmineDev.project_root, 'pages', 'index.html'))
end
end
end

View File

@@ -0,0 +1,53 @@
class JasmineDev < Thor
desc "build_distribution", "Build Jasmine js & css files"
def build_distribution(directory = "./lib/jasmine-core")
invoke :js_hint
say JasmineDev.spacer
say "Building Jasmine distribution from source into #{directory}", :cyan
say 'Building JavaScript...', :yellow
inside directory do
create_file "jasmine.js",
concat_contents_of(jasmine_js_paths),
:force => true
create_file "jasmine-html.js",
concat_contents_of(jasmine_html_js_paths),
:force => true
end
say 'Building CSS...', :yellow
run "compass compile", :capture => true
copy_file File.join("#{JasmineDev.project_root}", 'src', 'html', 'jasmine.css'),
File.join(directory, 'jasmine.css')
end
no_tasks do
def jasmine_js_paths
paths = JasmineDev::JASMINE_SOURCES[:core].collect do |f|
File.join(JasmineDev.project_root, 'src', 'core', f)
end
paths << File.join(JasmineDev.project_root, 'src', 'version.js')
paths
end
def jasmine_html_js_paths
JasmineDev::JASMINE_SOURCES[:html].collect do |f|
File.join(JasmineDev.project_root, 'src', 'html', f)
end
end
def concat_contents_of(paths)
paths.inject("") do |string, path|
string << File.read(path)
string
end
end
end
end

View File

@@ -0,0 +1,31 @@
class JasmineDev < Thor
desc "build_github_pages", "Build static pages for pivotal.github.com/jasmine"
def build_github_pages(pages_dir = File.expand_path(File.join('.', 'pages')))
say JasmineDev.spacer
say "Building Github Pages...", :cyan
return unless pages_submodule_installed?
pages_output = File.join(pages_dir, 'pages_output')
FileUtils.rm_r(pages_output) if File.exist?(pages_output)
inside File.join('pages', 'pages_source') do
run_with_output "frank export #{pages_output}", :capture => true
end
pages_files = Dir.chdir(pages_output) { Dir.glob('*') }
pages_files.each do |file|
source_path = File.join(pages_output, file)
destination_path = File.join(pages_dir, file)
if File.directory?(source_path)
directory source_path, destination_path
else
copy_file source_path, destination_path
end
end
end
end

View File

@@ -0,0 +1,49 @@
class JasmineDev < Thor
include Thor::Actions
desc "build_standalone_distribution", "Build Jasmine standalone distribution"
def build_standalone_distribution(download_dir = File.expand_path(File.join('.', 'pages', 'downloads')))
invoke :build_distribution
say JasmineDev.spacer
say "Building standalone distribution...", :cyan
say "Staging files...", :yellow
lib_files.each do |f|
copy_file f, File.join(standalone_temp_dir, 'lib', "jasmine-#{version_string}", f)
end
['src', 'spec'].each do |dir|
directory File.join('lib', 'jasmine-core', 'example', dir),
File.join(standalone_temp_dir, dir)
end
invoke :build_standalone_runner
say "Zipping distribution...", :yellow
inside standalone_temp_dir do
run_with_output "zip -rq ../jasmine-standalone-#{version_string}.zip ."
say "Copying Zip file to downloads directory", :yellow
run "cp ../jasmine-standalone-#{version_string}.zip #{download_dir}"
end
end
no_tasks do
def standalone_temp_dir
@standalone_temp_dir ||= File.join(Dir.tmpdir, 'jasmine_standalone', "jasmine-standalone-#{version_string}")
end
def lib_files
%w{ jasmine.js jasmine-html.js jasmine.css MIT.LICENSE }
end
def example_path
File.join('lib', "jasmine-#{version_string}")
end
end
end

View File

@@ -0,0 +1,59 @@
class JasmineDev < Thor
include Thor::Actions
desc "build_standalone_runner", "Build HTML spec runner for Jasmine standalone distribution"
def build_standalone_runner
say JasmineDev.spacer
say "Building standalone runner HTML...", :cyan
create_file File.join(standalone_temp_dir, 'SpecRunner.html') do
template = Tilt.new(File.join('spec', 'templates','runner.html.erb'))
scope = OpenStruct.new(:title => "Jasmine Spec Runner",
:favicon => example_favicon,
:jasmine_tags => example_jasmine_tags,
:source_tags => example_source_tags,
:spec_file_tags => example_spec_tags)
template.render(scope)
end
end
no_tasks do
def standalone_temp_dir
@standalone_temp_dir ||= File.join(Dir.tmpdir, 'jasmine_standalone', "jasmine-standalone-#{version_string}")
end
def example_path
File.join('lib', "jasmine-#{version_string}")
end
def example_favicon
%Q{<link rel="shortcut icon" type="image/png" href="#{example_path}/jasmine_favicon.png">}
end
def script_tags_for(files)
srcs = (files.is_a?(String) ? [files] : files)
srcs.inject([]) do |tags, file|
tags << %Q{<script type="text/javascript" src="#{file}"></script>}
tags
end.join("\n ")
end
def example_jasmine_tags
tags = %Q{<link rel="stylesheet" type="text/css" href="#{example_path}/jasmine.css">}
tags << "\n "
tags << script_tags_for(["#{example_path}/jasmine.js", "#{example_path}/jasmine-html.js"])
tags
end
def example_source_tags
script_tags_for ['spec/SpecHelper.js', 'spec/PlayerSpec.js']
end
def example_spec_tags
script_tags_for ['src/Player.js', 'src/Song.js']
end
end
end

View File

@@ -0,0 +1,29 @@
class JasmineDev < Thor
desc "count_specs", "Count the number of specs for each test runner"
def count_specs
say JasmineDev.spacer
say "Counting specs...", :cyan
core_spec_count = count_specs_in(File.join('spec', 'core'))
console_spec_count = count_specs_in(File.join('spec', 'console'))
html_spec_count = count_specs_in(File.join('spec', 'html'))
say "#{(core_spec_count + console_spec_count).to_s} ", :yellow
say "specs for Node.js runner (exclude DOM-related specs)"
say "#{(core_spec_count + console_spec_count + html_spec_count).to_s} ", :yellow
say "specs for Browser runner (all specs)"
say "\n"
say "Please verify that these numbers match the runner output."
end
no_tasks do
def count_specs_in(relative_path)
files = Dir.glob(File.join(JasmineDev.project_root, relative_path, '*.js'))
files.inject(0) do |count, file|
File.read(file).scan(/\sit\s*\(/) { |s| count += 1 }
count
end
end
end
end

View File

@@ -0,0 +1,52 @@
class JasmineDev < Thor
desc "execute_specs_in_node", "Run all relevant specs in Node.js"
def execute_specs_in_node
return unless node_installed?
invoke :build_distribution
invoke :count_specs
say JasmineDev.spacer
say "Running all appropriate specs via Node.js...", :cyan
with_color_option = STDOUT.isatty ? "--color" : "--noColor"
run_with_output "node spec/node_suite.js #{with_color_option}", :capture => true
end
desc "execute_specs_in_browser", "Run all relevent specs in your default browser"
def execute_specs_in_browser
invoke :build_distribution
invoke :count_specs
say JasmineDev.spacer
say "Running all appropriate specs via the default web browser...", :cyan
open_specs_in_browser
end
desc "execute_specs", "Run all of Jasmine's JavaScript specs"
def execute_specs
invoke :execute_specs_in_node
invoke :execute_specs_in_browser
end
no_tasks do
def open_specs_in_browser
require 'rbconfig'
case Object.const_get(defined?(RbConfig) ? :RbConfig : :Config)::CONFIG['host_os']
when /linux/
run "xdg-open spec/runner.html"
else
run "open spec/runner.html"
end
end
end
end

View File

@@ -0,0 +1,13 @@
class JasmineDev < Thor
desc "js_hint", "Run Jasmine source through JSHint"
def js_hint
say JasmineDev.spacer
return unless node_installed?
say "Running JSHint on Jasmine source and specs...", :cyan
run_with_output "node jshint/run.js", :capture => true
end
end

View File

@@ -0,0 +1,16 @@
class JasmineDev < Thor
desc 'release_prep', "Update version and build distributions"
def release_prep
say JasmineDev.spacer
say "Building Release...", :cyan
return unless pages_submodule_installed?
invoke :write_version_files
invoke :build_distribution
invoke :build_standalone_distribution
invoke :build_github_pages
end
end

View File

@@ -0,0 +1,32 @@
class JasmineDev < Thor
JASMINE_SOURCES = {
:core => [
"base.js",
"util.js",
"Env.js",
"Reporter.js",
"Block.js",
"JsApiReporter.js",
"Matchers.js",
"mock-timeout.js",
"MultiReporter.js",
"NestedResults.js",
"PrettyPrinter.js",
"Queue.js",
"Runner.js",
"Spec.js",
"Suite.js",
"WaitsBlock.js",
"WaitsForBlock.js"
],
:html => [
"HtmlReporterHelpers.js",
"HtmlReporter.js",
"ReporterView.js",
"SpecView.js",
"SuiteView.js",
"TrivialReporter.js"
]
}
end

View File

@@ -0,0 +1,62 @@
class JasmineDev < Thor
desc "write_version_files", "Write out version files"
def write_version_files
say JasmineDev.spacer
say "Building version files", :cyan
scope = OpenStruct.new(:major => version_object["major"],
:minor => version_object["minor"],
:build => version_object["build"],
:release_candidate => version_object["release_candidate"],
:revision => Time.now.to_i)
js_template = Tilt.new(File.join(JasmineDev.project_root, 'src', 'templates', 'version.js.erb'))
create_file File.join(JasmineDev.project_root, 'src', 'version.js'), :force => true do
js_template.render(scope)
end
rb_template = Tilt.new(File.join(JasmineDev.project_root, 'src', 'templates', 'version.rb.erb'))
create_file File.join(JasmineDev.project_root, 'lib', 'jasmine-core', 'version.rb'), :force => true do
rb_template.render(scope)
end
end
desc "display_version", "Display version currently stored in source"
def display_version
say "Current version information from src/version.json", :cyan
say "Display version: "
say "#{version_string}", :yellow
say "Version object: "
say "#{version_object_old}", :yellow
end
no_tasks do
def version
@version ||= File.read(File.join(JasmineDev.project_root, 'src', 'version.json'))
end
def version_string
display = "#{version_object['major']}.#{version_object['minor']}.#{version_object['build']}"
display += ".rc#{version_object['release_candidate']}" if version_object['release_candidate']
display
end
def version_object
@version_object ||= JSON.parse(version)
end
def version_object_old
version.gsub("\n", " ").
gsub(/\s+/, " ").
gsub(/\}\s+$/, "}")
end
end
end