diff --git a/README.markdown b/README.markdown index 3b45bbb..a6cc6f4 100644 --- a/README.markdown +++ b/README.markdown @@ -8,9 +8,11 @@ Quick Start ### Ruby Suite Running sudo gem sources -a http://gems.github.com - sudo gem install json thin + sudo gem install geminstaller git clone git://github.com/pivotal/jasmine.git - cd jasmine/examples/ruby + cd jasmine + sudo geminstaller + cd examples/ruby rake jasmine_server open `http://localhost:8888/` in your favorite browser. @@ -24,9 +26,11 @@ open `examples/test/html/example_suite.html` in your favorite browser. ### Automatic Suite Running (w/ Selenium) sudo gem sources -a http://gems.github.com - sudo gem install json thin pivotal-selenium-rc selenium-client + sudo gem install geminstaller git clone git://github.com/pivotal/jasmine.git - cd jasmine/examples/ruby + cd jasmine + sudo geminstaller + cd examples/ruby rake test:ci Releases @@ -42,6 +46,10 @@ Releases Please use the latest version unless you have a good reason not to. Some of this documentation may not be applicable to older versions. +Pull Requests +---------- +We welcome your contributions! Jasmine is currently maintained by Davis Frank ([infews](http://github.com/infews)), Rajan Agaskar ([ragaskar](http://github.com/ragaskar)), and Christian Williams ([Xian](http://github.com/Xian)). You can help us by removing all other recipients from your pull request. + Why Another Frickin' JS TDD/BDD Framework? ----------- @@ -450,58 +458,10 @@ Spies have some useful properties: Spies are automatically removed after each spec. They may be set in the beforeEach function. -### Runner - -You don't need a DOM to run your tests, but you do need a page on which to load & execute your JS. Include the `jasmine.js` file in a script tag as well as the JS file with your specs. You can also use this page for reporting. More on that in a moment. - -Here's the example HTML file (in `jasmine/example`): - - - - - Jasmine Example - - - - - -

- Running Jasmine Example Specs -

-
- - - - -It's the call to `jasmine.execute()` that runs all of the defined specs, gathering reports of each expectation. - -### Reports - -If a reporter exists on the Jasmine instance (named `jasmine`), it will be called when each spec, suite and the overall runner complete. If you're at the single-spec result level, you'll get a spec description, whether it passed or failed, and what the failure message was. At the suite & runner report level, you'll get the total specs run so far, the passed counts, failed counts, and a description (of the suite or runner). - -There is a `Jasmine.Reporters` namespace for you to see how to handle reporting. See the file `json_reporter.js`, which takes the results objects and turns them into JSON strings, for two examples of how to make the results callbacks work for you. - - ### Disabling Tests & Suites Specs may be disabled by calling `xit()` instead of `it()`. Suites may be disabled by calling `xdescribe()` instead of `describe()`. A simple find/replace in your editor of choice will allow you to run a subset of your specs. -Contributing and Tests ----------------------- - -Sometimes it's hard to test a framework with the framework itself. Either the framework isn't mature enough or it just hurts your head. Jasmine is affected by both. - -So we made a little bootstrappy test reporter that lets us test Jasmine's pieces in isolation. See test/bootstrap.js. Feel free to use the bootstrap test suite to test your custom Matchers or extensions/changes to Jasmine. - -Your contributions are welcome. Please submit tests with your pull request. - ## Support We now have a Google Group for support & discussion. @@ -517,7 +477,3 @@ We now have a Google Group for support & discussion. * A big shout out to the various JavaScript test framework authors, especially TJ for [JSpec](http://github.com/visionmedia/jspec/tree/master) - we played with it a bit before deciding that we really needed to roll our own. * Thanks to Pivot [Jessica Miller](http://www.jessicamillerworks.com/) for our fancy pass/fail/pending icons * Huge contributions have been made by [Christian Williams](mailto:xian@pivotallabs.com) (the master "spy" coder), [Erik Hanson](mailto:erik@pivotallabs.com), [Adam Abrons](mailto:adam@pivotallabs.com) and [Carl Jackson](mailto:carl@pivotallabs.com), and many other Pivots. - -## TODO List - -* Pending & Disabled counts should be included in results diff --git a/Rakefile b/Rakefile index 767a100..aa08aa5 100644 --- a/Rakefile +++ b/Rakefile @@ -19,10 +19,11 @@ def start_jasmine_server(jasmine_includes = nil) puts "your tests are here:" puts " http://localhost:8888/run.html" - Jasmine::SimpleServer.start(8888, - lambda { JasmineHelper.spec_file_urls }, - JasmineHelper.dir_mappings, - jasmine_includes) + Jasmine::SimpleServer.start( + 8888, + lambda { JasmineHelper.specs }, + JasmineHelper.dir_mappings, + :jasmine_files => jasmine_includes) end namespace :jasmine do @@ -67,7 +68,11 @@ jasmine.version_= { desc "Run jasmine tests of source via server" task :server do - jasmine_includes = lambda { jasmine_sources + ['lib/TrivialReporter.js'] } + files = jasmine_sources + ['lib/TrivialReporter.js', 'lib/consolex.js'] + jasmine_includes = lambda { + raw_jasmine_includes = files.collect { |f| File.expand_path(File.join(JasmineHelper.jasmine_root, f)) } + Jasmine.cachebust(raw_jasmine_includes).collect {|f| f.sub(JasmineHelper.jasmine_src_dir, "/src").sub(JasmineHelper.jasmine_lib_dir, "/lib") } + } start_jasmine_server(jasmine_includes) end diff --git a/contrib/ruby/jasmine_runner.rb b/contrib/ruby/jasmine_runner.rb index 6d27b6b..5a6b1ef 100644 --- a/contrib/ruby/jasmine_runner.rb +++ b/contrib/ruby/jasmine_runner.rb @@ -49,6 +49,7 @@ module Jasmine end def self.cachebust(files, root_dir="", replace=nil, replace_with=nil) + require 'digest/md5' files.collect do |file_name| real_file_name = replace && replace_with ? file_name.sub(replace, replace_with) : file_name begin @@ -61,25 +62,33 @@ module Jasmine end class RunAdapter - def initialize(spec_files_or_proc, jasmine_files = nil, stylesheets = []) - @spec_files_or_proc = spec_files_or_proc - @jasmine_files = jasmine_files || [ + def initialize(spec_files_or_proc, options = {}) + @spec_files_or_proc = Jasmine.files(spec_files_or_proc) || [] + @jasmine_files = Jasmine.files(options[:jasmine_files]) || [ "/__JASMINE_ROOT__/lib/" + File.basename(Dir.glob("#{Jasmine.root}/lib/jasmine*.js").first), "/__JASMINE_ROOT__/lib/TrivialReporter.js", - "/__JASMINE_ROOT__/lib/json2.js" + "/__JASMINE_ROOT__/lib/json2.js", + "/__JASMINE_ROOT__/lib/consolex.js", ] - @stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"] + stylesheets + @stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"] + (Jasmine.files(options[:stylesheets]) || []) + @spec_helpers = Jasmine.files(options[:spec_helpers]) || [] end def call(env) + run + end + + def run + stylesheets = @stylesheets + spec_helpers = @spec_helpers spec_files = @spec_files_or_proc - spec_files = spec_files.call if spec_files.respond_to?(:call) jasmine_files = @jasmine_files jasmine_files = jasmine_files.call if jasmine_files.respond_to?(:call) css_files = @stylesheets + body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html"))).result(binding) [ 200, @@ -87,6 +96,8 @@ module Jasmine body ] end + + end class Redirect @@ -113,13 +124,36 @@ module Jasmine end end - class SimpleServer - def self.start(port, spec_files_or_proc, mappings, jasmine_files = nil, stylesheets = []) - require 'thin' + class FocusedSuite + def initialize(spec_files_or_proc, options) + @spec_files_or_proc = Jasmine.files(spec_files_or_proc) || [] + @options = options + end + def call(env) + spec_files = @spec_files_or_proc + matching_specs = spec_files.select {|spec_file| spec_file =~ /#{Regexp.escape(env["PATH_INFO"])}/ }.compact + if !matching_specs.empty? + run_adapter = Jasmine::RunAdapter.new(matching_specs, @options) + run_adapter.run + else + [ + 200, + { 'Content-Type' => 'application/javascript' }, + "document.write('

Couldn\\'t find any specs matching #{env["PATH_INFO"]}!

');" + ] + end + end + + end + + class SimpleServer + def self.start(port, spec_files_or_proc, mappings, options = {}) + require 'thin' config = { + '/__suite__' => Jasmine::FocusedSuite.new(spec_files_or_proc, options), '/run.html' => Jasmine::Redirect.new('/'), - '/' => Jasmine::RunAdapter.new(spec_files_or_proc, jasmine_files, stylesheets) + '/' => Jasmine::RunAdapter.new(spec_files_or_proc, options) } mappings.each do |from, to| config[from] = Rack::File.new(to) @@ -132,7 +166,12 @@ module Jasmine JsAlert.new ]) - Thin::Server.start('0.0.0.0', port, app) + begin + Thin::Server.start('0.0.0.0', port, app) + rescue RuntimeError => e + raise e unless e.message == 'no acceptor' + raise RuntimeError.new("A server is already running on port #{port}") + end end end @@ -180,15 +219,13 @@ module Jasmine end class Runner - def initialize(selenium_jar_path, spec_files, dir_mappings, jasmine_files = nil, options={}) + def initialize(selenium_jar_path, spec_files, dir_mappings, options={}) @selenium_jar_path = selenium_jar_path @spec_files = spec_files @dir_mappings = dir_mappings - @jasmine_files = jasmine_files - @browser = options[:browser] || 'firefox' - @stylesheets = options[:stylesheets] || [] - + @options = options + @browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox' @selenium_pid = nil @jasmine_server_pid = nil end @@ -216,7 +253,7 @@ module Jasmine @jasmine_server_pid = fork do Process.setpgrp - Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @jasmine_files, @stylesheets) + Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @options) exit! 0 end puts "jasmine server started. pid is #{@jasmine_server_pid}" @@ -246,4 +283,11 @@ module Jasmine @client.eval_js(script) end end + + def self.files(f) + result = f + result = result.call if result.respond_to?(:call) + result + end + end diff --git a/contrib/ruby/run.html b/contrib/ruby/run.html index 676d75c..9f0ecd0 100644 --- a/contrib/ruby/run.html +++ b/contrib/ruby/run.html @@ -11,6 +11,10 @@ <% end %> + <% spec_helpers.each do |spec_helper| %> + + <% end %> + + +