Compare commits

...

23 Commits

Author SHA1 Message Date
Pivotal
c187adc096 Version bump to 0.10.4 2010-06-05 10:44:54 -04:00
Pivotal
5aa306cf66 Add unit specs for WaitsForBlock 2010-06-05 10:32:41 -04:00
Pivotal
462b50e84e Replace unshift with splice (unshift not IE-safe) 2010-06-05 10:12:16 -04:00
Pivotal
46249bf515 Fix spec failure that occured when stack traces/line numbers are available 2010-06-05 10:07:58 -04:00
Christian Williams
03d7bfb7d4 Oops, shouldn't onComplete there. 2010-06-04 14:48:48 -04:00
Christian Williams
11292ff83c Merge branch 'master' of git@github.com:pivotal/jasmine 2010-06-04 14:45:52 -04:00
Christian Williams
ab7678e713 Apply patch from Eric Pabst (May 18, 2010):
Replaced call to self.spec._next() with onComplete() when the test times out.

This is because there is no such function as _next(), and onComplete() seems to
do the right thing.
2010-06-04 14:45:42 -04:00
Eric Pabst
6431431dfc Replaced call to self.spec._next() with onComplete() when the test times out.
This is because there is no such function as _next(), and onComplete() seems to do the right thing.
2010-06-05 02:44:51 +08:00
Christian Williams
a2041e90a6 Multiple befores/afters in a single describe should be executed in order (as declared for befores, in reverse for afters). 2010-06-04 14:41:16 -04:00
Christian Williams
ed49104fad Jasmine should recover gracefully when there are errors in describe functions. 2010-06-04 14:14:31 -04:00
labday
803a2fb2ba Fixing documentation error. 2010-05-28 05:52:48 +08:00
John Firebaugh
bb1928a75c Remove geminstaller stuff.
This isn't a gem anymore, and geminstaller is deprecated.
2010-05-08 10:57:43 +08:00
John Firebaugh
7d5ff6985f Rebuild to fix line endings. 2010-05-08 10:57:43 +08:00
ragaskar
841e93fc09 'Hide' currently unusable Rake tasks 2010-04-20 07:26:51 -07:00
bigfix
5cfb019b6b Documentation and example fixes 2010-04-20 07:26:04 -07:00
Christian Williams & Ian Fisher
9f8d18b6b7 Version bump to 0.10.3 2010-04-01 16:03:52 -07:00
Christian Williams & Ian Fisher
f0574086de Version bump to 0.10.3 2010-04-01 16:00:50 -07:00
Christian Williams & Ian Fisher
2212d755c3 Merge commit '5f10b2e623c6c21d1b692bde4a8a5c6d4015cd44' 2010-04-01 15:57:24 -07:00
Christian Williams & Ian Fisher
5f10b2e623 Added Env#versionString; nicer styling in TrivialReporter; hide passed and skipped tests by default, but allow them to be displayed. 2010-04-01 15:56:29 -07:00
Christian Williams
d8ed4156c7 Remove contrib/ruby dir. 2010-03-24 14:18:17 -07:00
Christian Williams
1469f83262 Deprecate jasmine.include(). 2010-03-24 13:53:34 -07:00
Christian Williams
d6353a3db2 Typo. 2010-03-24 13:43:47 -07:00
Christian Williams
a16cbe7e5b Remove contrib dir. 2009-12-27 11:53:46 -06:00
29 changed files with 865 additions and 1238 deletions

View File

@@ -5,24 +5,11 @@ Jasmine
Quick Start
----------
### Ruby Suite Running
1. Get the latest release from the [downloads page](http://github.com/pivotal/jasmine/downloads).
2. Open `example/example_runner.html` in your favorite browser.
Please use the [jasmine-ruby gem](http://github.com/pivotal/jasmine-ruby) to run suites in a ruby environment.
### HTML Suite Running
[Get the latest release from the downloads page](http://github.com/pivotal/jasmine/downloads)
Open `example/example_runner.html` in your favorite browser.
### Automatic Suite Running (w/ Selenium)
sudo gem sources -a http://gems.github.com
sudo gem install geminstaller
git clone git://github.com/pivotal/jasmine.git
cd jasmine
sudo geminstaller
cd examples/ruby
rake test:ci
For running within a Ruby environment, including automated execution with Selenium, please use
the [jasmine-ruby gem](http://github.com/pivotal/jasmine-ruby).
Releases
----------
@@ -108,7 +95,7 @@ Jasmine has several built-in matchers. Here are a few:
>
>`expect(x).toBeDefined();` passes if `x` is not `undefined`
>
>`expect(x).toBeNull();` passes if `x` is not `null`
>`expect(x).toBeNull();` passes if `x` is `null`
>
>`expect(x).toBeTruthy();` passes if `x` evaluates to true
>

View File

@@ -56,7 +56,7 @@ namespace :jasmine do
end
desc 'Builds lib/jasmine from source'
task :build => [:lint, 'gems:geminstaller'] do
task :build => :lint do
puts 'Building Jasmine from source'
require 'json'
@@ -102,7 +102,6 @@ jasmine.version_= {
end
desc "Run jasmine tests of source via server"
task :server do
files = jasmine_sources + ['lib/TrivialReporter.js', 'lib/consolex.js']
jasmine_includes = lambda {
@@ -112,14 +111,12 @@ jasmine.version_= {
start_jasmine_server(jasmine_includes)
end
desc "Build jasmine and run tests via server"
task :server_build => 'jasmine:build' do
start_jasmine_server
end
namespace :test do
desc "Run continuous integration tests using a local Selenium runner"
task :ci => :'ci:local'
namespace :ci do
@@ -133,7 +130,6 @@ jasmine.version_= {
Rake::Task[:lambda_ci].invoke
end
desc "Run continuous integration tests using Sauce Labs 'Selenium in the Cloud'"
task :saucelabs => ['jasmine:copy_saucelabs_config', 'jasmine:build'] do
ENV['SAUCELABS'] = 'true'
Rake::Task['jasmine:test:ci:local'].invoke
@@ -147,12 +143,4 @@ jasmine.version_= {
end
end
desc "Run specs via server"
task :jasmine => ['jasmine:server']
namespace :gems do
desc "Run geminstaller."
task :geminstaller do
`geminstaller --sudo`
end
end

View File

@@ -1,334 +0,0 @@
require 'socket'
require 'erb'
require 'json'
module Jasmine
def self.root
File.expand_path(File.join(File.dirname(__FILE__), '../..'))
end
# this seemingly-over-complex method is necessary to get an open port on at least some of our Macs
def self.open_socket_on_unused_port
infos = Socket::getaddrinfo("localhost", nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
return TCPServer.open('0.0.0.0', 0) if families.has_key?('AF_INET')
return TCPServer.open('::', 0) if families.has_key?('AF_INET6')
return TCPServer.open(0)
end
def self.find_unused_port
socket = open_socket_on_unused_port
port = socket.addr[1]
socket.close
port
end
def self.server_is_listening_on(hostname, port)
require 'socket'
begin
socket = TCPSocket.open(hostname, port)
rescue Errno::ECONNREFUSED
return false
end
socket.close
true
end
def self.wait_for_listener(port, name = "required process", seconds_to_wait = 10)
time_out_at = Time.now + seconds_to_wait
until server_is_listening_on "localhost", port
sleep 0.1
puts "Waiting for #{name} on #{port}..."
raise "#{name} didn't show up on port #{port} after #{seconds_to_wait} seconds." if Time.now > time_out_at
end
end
def self.kill_process_group(process_group_id, signal="TERM")
Process.kill signal, -process_group_id # negative pid means kill process group. (see man 2 kill)
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
digest = Digest::MD5.hexdigest(File.read("#{root_dir}#{real_file_name}"))
rescue
digest = "MISSING-FILE"
end
"#{file_name}?cachebust=#{digest}"
end
end
class RunAdapter
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/consolex.js",
]
@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
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,
{ 'Content-Type' => 'text/html' },
body
]
end
end
class Redirect
def initialize(url)
@url = url
end
def call(env)
[
302,
{ 'Location' => @url },
[]
]
end
end
class JsAlert
def call(env)
[
200,
{ 'Content-Type' => 'application/javascript' },
"document.write('<p>Couldn\\'t load #{env["PATH_INFO"]}!</p>');"
]
end
end
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('<p>Couldn\\'t find any specs matching #{env["PATH_INFO"]}!</p>');"
]
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, options)
}
mappings.each do |from, to|
config[from] = Rack::File.new(to)
end
config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root)
app = Rack::Cascade.new([
Rack::URLMap.new(config),
JsAlert.new
])
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
class SimpleClient
def initialize(selenium_host, selenium_port, selenium_browser_start_command, http_address)
require 'selenium/client'
@driver = Selenium::Client::Driver.new(
selenium_host,
selenium_port,
selenium_browser_start_command,
http_address
)
@http_address = http_address
end
def tests_have_finished?
@driver.get_eval("window.jasmine.getEnv().currentRunner.finished") == "true"
end
def connect
@driver.start
@driver.open("/")
end
def disconnect
@driver.stop
end
def run
until tests_have_finished? do
sleep 0.1
end
puts @driver.get_eval("window.results()")
failed_count = @driver.get_eval("window.jasmine.getEnv().currentRunner.results().failedCount").to_i
failed_count == 0
end
def eval_js(script)
escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'"
result = @driver.get_eval(" try { eval(#{escaped_script}, window); } catch(err) { window.eval(#{escaped_script}); }")
JSON.parse("[#{result}]")[0]
end
end
class Runner
def initialize(selenium_jar_path, spec_files, dir_mappings, options={})
@selenium_jar_path = selenium_jar_path
@spec_files = spec_files
@dir_mappings = dir_mappings
@options = options
@browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox'
@selenium_pid = nil
@jasmine_server_pid = nil
@selenium_host = 'localhost'
@jasmine_server_port = Jasmine::find_unused_port
@selenium_server_port = Jasmine::find_unused_port
end
def start
start_jasmine_server
start_selenium_server
@client = Jasmine::SimpleClient.new(@selenium_host, @selenium_server_port, "*#{@browser}", "http://localhost:#{@jasmine_server_port}/")
@client.connect
end
def stop
@client.disconnect
stop_selenium_server
stop_jasmine_server
end
def start_jasmine_server
@jasmine_server_pid = fork do
Process.setpgrp
Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @options)
exit! 0
end
puts "jasmine server started. pid is #{@jasmine_server_pid}"
Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server")
end
def start_selenium_server
@selenium_pid = fork do
Process.setpgrp
exec "java -jar #{@selenium_jar_path} -port #{@selenium_server_port} > /dev/null 2>&1"
end
puts "selenium started. pid is #{@selenium_pid}"
Jasmine::wait_for_listener(@selenium_server_port, "selenium server")
end
def stop_jasmine_server
puts "shutting down Jasmine server..."
Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid
end
def stop_selenium_server
puts "shutting down Selenium server..."
Jasmine::kill_process_group(@selenium_pid) if @selenium_pid
end
def run
begin
start
puts "servers are listening on their ports -- running the test script..."
tests_passed = @client.run
ensure
stop
end
return tests_passed
end
def eval_js(script)
@client.eval_js(script)
end
end
class SauceLabsRunner < Runner
def initialize(spec_files, dir_mappings, options={})
@spec_files = spec_files
@dir_mappings = dir_mappings
@options = options
@browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox'
@jasmine_server_pid = nil
@jasmine_server_port = Jasmine::find_unused_port
@saucelabs_config = SeleniumConfig.new(options[:saucelabs_config], options[:saucelabs_config_file], @jasmine_server_port)
end
def start_selenium_server
@sauce_tunnel = SauceTunnel.new(@saucelabs_config)
end
def start
start_jasmine_server
start_selenium_server
@client = Jasmine::SimpleClient.new(@saucelabs_config['selenium_server_address'],
4444,
@saucelabs_config['selenium_browser_key'],
"http://#{@saucelabs_config['application_address']}")
@client.connect
end
def stop
@client.disconnect
@sauce_tunnel.shutdown
stop_jasmine_server
end
end
def self.files(f)
result = f
result = result.call if result.respond_to?(:call)
result
end
end

View File

@@ -1,153 +0,0 @@
require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_runner.rb"))
require 'enumerator'
module Jasmine
class SpecBuilder
attr_accessor :suites
def initialize(spec_files, runner)
@spec_files = spec_files
@runner = runner
@spec_ids = []
end
def start
guess_example_locations
@runner.start
load_suite_info
wait_for_suites_to_finish_running
end
def stop
@runner.stop
end
def script_path
File.expand_path(__FILE__)
end
def guess_example_locations
@example_locations = {}
example_name_parts = []
previous_indent_level = 0
@spec_files.each do |filename|
line_number = 1
File.open(filename, "r") do |file|
file.readlines.each do |line|
match = /^(\s*)(describe|it)\s*\(\s*["'](.*)["']\s*,\s*function/.match(line)
if (match)
indent_level = match[1].length / 2
example_name = match[3]
example_name_parts[indent_level] = example_name
full_example_name = example_name_parts.slice(0, indent_level + 1).join(" ")
@example_locations[full_example_name] = "#{filename}:#{line_number}: in `it'"
end
line_number += 1
end
end
end
end
def load_suite_info
started = Time.now
while !eval_js('jsApiReporter && jsApiReporter.started') do
raise "couldn't connect to Jasmine after 60 seconds" if (started + 60 < Time.now)
sleep 0.1
end
@suites = eval_js("var result = jsApiReporter.suites(); if (window.Prototype && result && result.toJSON) { result.toJSON()} else { JSON.stringify(result) }")
end
def results_for(spec_id)
@spec_results ||= load_results
@spec_results[spec_id.to_s]
end
def load_results
@spec_results = {}
@spec_ids.each_slice(50) do |slice|
@spec_results.merge!(eval_js("var result = jsApiReporter.resultsForSpecs(#{JSON.generate(slice)}); if (window.Prototype && result && result.toJSON) { result.toJSON()} else { JSON.stringify(result) }"))
end
@spec_results
end
def wait_for_suites_to_finish_running
puts "Waiting for suite to finish in browser ..."
while !eval_js('jsApiReporter.finished') do
sleep 0.1
end
end
def declare_suites
me = self
suites.each do |suite|
declare_suite(self, suite)
end
end
def declare_suite(parent, suite)
me = self
parent.describe suite["name"] do
suite["children"].each do |suite_or_spec|
type = suite_or_spec["type"]
if type == "suite"
me.declare_suite(self, suite_or_spec)
elsif type == "spec"
me.declare_spec(self, suite_or_spec)
else
raise "unknown type #{type} for #{suite_or_spec.inspect}"
end
end
end
end
def declare_spec(parent, spec)
me = self
example_name = spec["name"]
@spec_ids << spec["id"]
backtrace = @example_locations[parent.description + " " + example_name]
parent.it example_name, {}, backtrace do
me.report_spec(spec["id"])
end
end
def report_spec(spec_id)
spec_results = results_for(spec_id)
out = ""
messages = spec_results['messages'].each do |message|
case
when message["type"] == "MessageResult"
puts message["text"]
puts "\n"
else
unless message["message"] =~ /^Passed.$/
STDERR << message["message"]
STDERR << "\n"
out << message["message"]
out << "\n"
end
if !message["passed"] && message["trace"]["stack"]
stack_trace = message["trace"]["stack"].gsub(/<br \/>/, "\n").gsub(/<\/?b>/, " ")
STDERR << stack_trace.gsub(/\(.*\)@http:\/\/localhost:[0-9]+\/specs\//, "/spec/")
STDERR << "\n"
end
end
end
fail out unless spec_results['result'] == 'passed'
puts out unless out.empty?
end
private
def eval_js(js)
@runner.eval_js(js)
end
end
end

View File

@@ -1,47 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
<title>Jasmine suite</title>
<% css_files.each do |css_file| %>
<link rel="stylesheet" href="<%= css_file %>" type="text/css" media="screen"/>
<% end %>
<% jasmine_files.each do |jasmine_file| %>
<script src="<%= jasmine_file %>" type="text/javascript"></script>
<% end %>
<% spec_helpers.each do |spec_helper| %>
<script src="<%= spec_helper %>" type="text/javascript"></script>
<% end %>
<script type="text/javascript">
var jsApiReporter;
(function() {
var jasmineEnv = jasmine.getEnv();
jsApiReporter = new jasmine.JsApiReporter();
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(jsApiReporter);
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
};
window.onload = function() {
jasmineEnv.execute();
};
})();
</script>
<% spec_files.each do |spec_file| %>
<script src="<%= spec_file %>" type="text/javascript"></script>
<% end %>
</head>
<body>
<div id="jasmine_content"></div>
</body>
</html>

View File

@@ -1,71 +0,0 @@
require 'spec'
require 'open-uri'
require 'thin'
require File.dirname(__FILE__) + '/../jasmine_runner'
describe Jasmine::SimpleServer do
before do
@port = Jasmine::find_unused_port
end
after do
Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid
end
it "should start and print script tags" do
@jasmine_server_pid = fork do
Process.setpgrp
Jasmine::SimpleServer.start(@port, ["file1", "file2"], {})
exit! 0
end
Jasmine::wait_for_listener(@port)
run_html = open("http://localhost:#{@port}/").read
run_html.should =~ /<script src="file1"/
run_html.should =~ /<script src="file2"/
end
describe "RuntimeError" do
it "should throw an Already Running error if there is already a server running" do
Thin::Server.should_receive(:start).and_raise(RuntimeError.new('no acceptor'))
lambda {
Jasmine::SimpleServer.start(@port, ["file1", "file2"], {})
}.should raise_error(RuntimeError, "A server is already running on port #{@port}")
end
it "re-raises other RuntimeErrors" do
Thin::Server.should_receive(:start).and_raise(RuntimeError.new('some random error'))
lambda {
Jasmine::SimpleServer.start(@port, ["file1", "file2"], {})
}.should raise_error(RuntimeError, "some random error")
end
end
it "should take a proc that returns a list of spec files" do
spec_fileses = [["file1", "file2"], ["file1", "file2", "file3"]]
spec_files_proc = lambda do
spec_fileses.shift
end
@jasmine_server_pid = fork do
Process.setpgrp
Jasmine::SimpleServer.start(@port, spec_files_proc, {})
exit! 0
end
Jasmine::wait_for_listener(@port)
run_html = open("http://localhost:#{@port}/").read
run_html.should =~ /<script src="file1"/
run_html.should =~ /<script src="file2"/
run_html = open("http://localhost:#{@port}/").read
run_html.should =~ /<script src="file1"/
run_html.should =~ /<script src="file2"/
run_html.should =~ /<script src="file3"/
end
end

View File

@@ -3,18 +3,13 @@
<html>
<head>
<title>Jasmine Test Runner</title>
<link rel="stylesheet" type="text/css" href="../lib/jasmine.css">
<script type="text/javascript" src="../lib/jasmine-0.10.4.js"></script>
<script type="text/javascript" src="../lib/TrivialReporter.js"></script>
<script type="text/javascript" src="../lib/consolex.js"></script>
<script type="text/javascript" src="spec/example_suite.js"></script>
</head>
<script type="text/javascript" src="../../lib/jasmine-0.10.1.js"></script>
<script type="text/javascript" src="../../lib/TrivialReporter.js"></script>
<script type="text/javascript" src="../../lib/consolex.js"></script>
<link rel="stylesheet" type="text/css" href="../../lib/jasmine.css">
<script type="text/javascript">
jasmine.include('spec/example_suite.js', true);
</script>
<body>
<script type="text/javascript">
var jasmineEnv = jasmine.getEnv();
jasmineEnv.reporter = new jasmine.TrivialReporter();

View File

@@ -1,33 +0,0 @@
require File.expand_path(File.join(File.dirname(__FILE__), "spec/jasmine_helper.rb"))
namespace :test do
desc "Run continuous integration tests"
task :ci => :'ci:local'
namespace :ci do
require "spec"
require 'spec/rake/spectask'
Spec::Rake::SpecTask.new(:local) do |t|
t.spec_opts = ["--color", "--format", "specdoc"]
t.spec_files = ["spec/jasmine_spec.rb"]
end
desc "Run continuous integration tests using Sauce Labs 'Selenium in the Cloud'"
task :saucelabs do
ENV['SAUCELABS'] = 'true'
Rake::Task['test:ci:local'].invoke
end
end
end
desc "Run specs via server"
task :jasmine_server do
require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder"))
puts "your tests are here:"
puts " http://localhost:8888/run.html"
Jasmine::SimpleServer.start(8888,
lambda { JasmineHelper.specs },
JasmineHelper.dir_mappings)
end

View File

@@ -1,11 +0,0 @@
describe('ExampleSuite', function () {
it('should have a passing test', function() {
expect(true).toEqual(true);
});
describe('Nested Describe', function () {
it('should also have a passing test', function () {
expect(true).toEqual(true);
});
});
});

View File

@@ -1,41 +0,0 @@
class JasmineHelper
def self.jasmine_lib_dir
File.expand_path(File.join(jasmine_root, 'lib'))
end
def self.jasmine_root
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
end
def self.jasmine
['/lib/' + File.basename(Dir.glob("#{JasmineHelper.jasmine_lib_dir}/jasmine*.js").first)] +
['/lib/json2.js',
'/lib/TrivialReporter.js',
'/lib/consolex.js'
]
end
def self.jasmine_src_dir
File.expand_path(File.join(jasmine_root, 'src'))
end
def self.jasmine_spec_dir
File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec'))
end
def self.raw_spec_files
Dir.glob(File.join(jasmine_spec_dir, "**/*[Ss]pec.js"))
end
def self.specs
raw_spec_files.collect {|f| f.sub(jasmine_spec_dir, "/spec")}
end
def self.dir_mappings
{
"/src" => jasmine_src_dir,
"/spec" => jasmine_spec_dir,
"/lib" => jasmine_lib_dir
}
end
end

View File

@@ -1,31 +0,0 @@
require 'rubygems'
require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_helper.rb"))
require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder"))
jasmine_runner = if ENV['SAUCELABS'] == 'true'
require 'sauce_tunnel'
require 'selenium_config'
Jasmine::SauceLabsRunner.new(JasmineHelper.specs,
JasmineHelper.dir_mappings,
:saucelabs_config => 'saucelabs',
:saucelabs_config_file => File.expand_path(File.join(File.dirname(__FILE__), "saucelabs.yml")))
else
require "selenium_rc"
Jasmine::Runner.new(SeleniumRC::Server.new('localhost').jar_path,
JasmineHelper.specs,
JasmineHelper.dir_mappings)
end
spec_builder = Jasmine::SpecBuilder.new(JasmineHelper.raw_spec_files, jasmine_runner)
should_stop = false
Spec::Runner.configure do |config|
config.after(:suite) do
spec_builder.stop if should_stop
end
end
spec_builder.start
should_stop = true
spec_builder.declare_suites

View File

@@ -1,24 +0,0 @@
local:
application_framework: :selenium
#
# Possible Sauce Labs configurations as of 2009/11/19
# From: http://saucelabs.com/products/docs/sauce-ondemand/browsers
# os: "Windows 2003"
# browser: "iexplore"
# browser-version: "6.", "7.", "8."
# browser: "firefox"
# browser-version: "2.", "3.0", "3.5"
# browser: "safari"
# browser-version: "3.", "4."
# browser: "opera"
# browser-version: "9."
# browser: "googlechrome"
# browser-version: ""
# os: "Linux"
# browser: "firefox"
# browser-version: "3."
saucelabs:
application_framework: :external
selenium_server_address: "saucelabs.com"
selenium_browser_key: '{"username": "--YOUR-SAUCELABS-USERNAME--", "access-key": "--YOUR-SAUCELABS-ACCESS-KEY--", "os": "Linux", "browser": "firefox", "browser-version": "3."}'
application_port: "80"

View File

@@ -1,25 +0,0 @@
---
gems:
- name: rake
version: 0.8.7
- name: ragaskar-jsdoc_helper
version: 0.0.2.1
- name: json
version: 1.1.9
- name: selenium-rc
version: 2.2.0
- name: rack
version: 1.0.0
- name: thin
version: 1.2.4
- name: eventmachine
version: 0.12.8
- name: rspec
version: 1.2.9
- name: selenium-client
version: 1.2.18
- name: rest-client
version: 1.0.3
- name: saucelabs-adapter
version: 0.3.2
install_options: --source=http://gems.pivotallabs.com

View File

@@ -17,7 +17,11 @@ jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarA
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
@@ -26,10 +30,29 @@ jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarA
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var suites = runner.suites();
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."));
this.document.body.appendChild(this.runnerDiv);
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
"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);
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
@@ -37,7 +60,7 @@ jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
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.getFullName()] = suiteDiv;
var parentDiv = this.document.body;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.getFullName()];
}
@@ -45,6 +68,23 @@ jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
}
this.startedAt = new Date();
var self = this;
showPassed.onchange = function(evt) {
if (evt.target.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onchange = function(evt) {
if (evt.target.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
@@ -63,6 +103,8 @@ jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
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) {
@@ -82,17 +124,30 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
}
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()) }, spec.getFullName()));
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.passed && !result.passed()) {
specDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
specDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
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.getFullName()].appendChild(specDiv);
};
@@ -114,4 +169,4 @@ jasmine.TrivialReporter.prototype.specFilter = function(spec) {
if (!paramMap["spec"]) return true;
return spec.getFullName().indexOf(paramMap["spec"]) == 0;
};
};

View File

@@ -13,7 +13,7 @@ jasmine.unimplementedMethod_ = function() {
};
/**
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code is just
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
* a plain old variable and may be redefined by somebody else.
*
* @private
@@ -57,6 +57,10 @@ jasmine.MessageResult = function(text) {
this.trace = new Error(); // todo: test better
};
jasmine.MessageResult.prototype.toString = function() {
return this.text;
};
jasmine.ExpectationResult = function(params) {
this.type = 'ExpectationResult';
this.matcherName = params.matcherName;
@@ -71,6 +75,10 @@ jasmine.ExpectationResult = function(params) {
this.trace = this.passed_ ? '' : new Error(this.message);
};
jasmine.ExpectationResult.prototype.toString = function () {
return this.message;
};
jasmine.ExpectationResult.prototype.passed = function () {
return this.passed_;
};
@@ -558,6 +566,7 @@ jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
*
* @param {String} url path to the file to include
* @param {Boolean} opt_global
* @deprecated We suggest you use a different method of including JS source files. <code>jasmine.include</code> will be removed soon.
*/
jasmine.include = function(url, opt_global) {
if (opt_global) {
@@ -690,6 +699,18 @@ 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 {
return "version unknown";
}
};
/**
* @returns a sequential integer starting at 0
*/
@@ -728,10 +749,21 @@ jasmine.Env.prototype.describe = function(description, specDefinitions) {
this.currentSuite = suite;
specDefinitions.call(suite);
var declarationError = null;
try {
specDefinitions.call(suite);
} catch(e) {
declarationError = e;
}
this.currentSuite = parentSuite;
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
return suite;
};
@@ -1764,12 +1796,12 @@ jasmine.Runner.prototype.execute = function() {
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.push(beforeEachFunction);
this.before_.splice(0,0,beforeEachFunction);
};
jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.push(afterEachFunction);
this.after_.splice(0,0,afterEachFunction);
};
@@ -2050,12 +2082,12 @@ jasmine.Suite.prototype.finish = function(onComplete) {
jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.push(beforeEachFunction);
this.before_.unshift(beforeEachFunction);
};
jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.push(afterEachFunction);
this.after_.unshift(afterEachFunction);
};
jasmine.Suite.prototype.results = function() {
@@ -2126,193 +2158,192 @@ jasmine.WaitsForBlock.prototype.execute = function (onComplete) {
name: 'timeout',
message: message
});
self.spec._next();
} else {
self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
self.env.setTimeout(function () { self.execute(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() {
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: window.setTimeout,
clearTimeout: window.clearTimeout,
setInterval: window.setInterval,
clearInterval: window.clearInterval
},
assertInstalled: function() {
if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
window.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);
}
};
window.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);
}
};
window.clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
window.clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
// 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() {
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: window.setTimeout,
clearTimeout: window.clearTimeout,
setInterval: window.setInterval,
clearInterval: window.clearInterval
},
assertInstalled: function() {
if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
window.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);
}
};
window.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);
}
};
window.clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
window.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": 0,
"minor": 10,
"build": 2,
"revision": 1268969696
"build": 4,
"revision": 1275748595
};

View File

@@ -3,8 +3,40 @@ body {
}
body .run_spec {
float:right;
.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 {
@@ -12,24 +44,26 @@ body .run_spec {
}
.runner {
border: 1px solid gray;
margin: 5px;
padding-left: 1em;
padding-right: 1em;
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #cfc;
background-color: #dfd;
}
.suite.failed {
@@ -38,22 +72,51 @@ body .run_spec {
.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: #fdd;
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
@@ -72,15 +135,32 @@ body .run_spec {
white-space: pre;
font-size: .8em;
margin-left: 10px;
height: 5em;
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

@@ -8,13 +8,13 @@
// yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]
undefined = "diz be undefined yo";
</script>
<script type="text/javascript" src="../src/base.js"></script>
<script type="text/javascript" src="../src/util.js"></script>
<script type="text/javascript" src="../src/Env.js"></script>
<script type="text/javascript" src="../src/Reporter.js"></script>
<script type="text/javascript" src="../src/Block.js"></script>
<script type="text/javascript" src="../src/JsApiReporter.js"></script>
<script type="text/javascript" src="../src/Matchers.js"></script>
<script type="text/javascript" src="../src/mock-timeout.js"></script>
@@ -28,35 +28,33 @@
<script type="text/javascript" src="../src/Suite.js"></script>
<script type="text/javascript" src="../src/WaitsBlock.js"></script>
<script type="text/javascript" src="../src/WaitsForBlock.js"></script>
<script type="text/javascript" src="../lib/TrivialReporter.js"></script>
<script type="text/javascript" src="../lib/consolex.js"></script>
<script type="text/javascript">
(function () {
var suites = [
'suites/CustomMatchersSpec.js',
'suites/EnvSpec.js',
'suites/ExceptionsSpec.js',
'suites/JsApiReporterSpec.js',
'suites/MatchersSpec.js',
'suites/MultiReporterSpec.js',
'suites/NestedResultsSpec.js',
'suites/PrettyPrintSpec.js',
'suites/ReporterSpec.js',
'suites/RunnerSpec.js',
'suites/QueueSpec.js',
'suites/SpecSpec.js',
'suites/SpecRunningSpec.js',
'suites/SpySpec.js',
'suites/SuiteSpec.js',
'suites/TrivialReporterSpec.js',
];
for (var i = 0; i < suites.length; i++) {
jasmine.include(suites[i], true);
}
<script type="text/javascript" src="suites/CustomMatchersSpec.js"></script>
<script type="text/javascript" src="suites/EnvSpec.js"></script>
<script type="text/javascript" src="suites/ExceptionsSpec.js"></script>
<script type="text/javascript" src="suites/JsApiReporterSpec.js"></script>
<script type="text/javascript" src="suites/MatchersSpec.js"></script>
<script type="text/javascript" src="suites/MultiReporterSpec.js"></script>
<script type="text/javascript" src="suites/NestedResultsSpec.js"></script>
<script type="text/javascript" src="suites/PrettyPrintSpec.js"></script>
<script type="text/javascript" src="suites/ReporterSpec.js"></script>
<script type="text/javascript" src="suites/RunnerSpec.js"></script>
<script type="text/javascript" src="suites/QueueSpec.js"></script>
<script type="text/javascript" src="suites/SpecSpec.js"></script>
<script type="text/javascript" src="suites/SpecRunningSpec.js"></script>
<script type="text/javascript" src="suites/SpySpec.js"></script>
<script type="text/javascript" src="suites/SuiteSpec.js"></script>
<script type="text/javascript" src="suites/TrivialReporterSpec.js"></script>
<script type="text/javascript" src="suites/WaitsForBlockSpec.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;

View File

@@ -57,6 +57,23 @@ describe("jasmine.Env", function() {
"revision": 8
});
});
describe("versionString", function() {
it("should return a stringified version number", function() {
jasmine.version_ = {
"major": 1,
"minor": 9,
"build": 7,
"revision": 8
};
expect(env.versionString()).toEqual("1.9.7 revision 8");
});
it("should return a nice string when version is unknown", function() {
jasmine.version_ = null;
expect(env.versionString()).toEqual("version unknown");
});
});
});
it("should allow reporters to be registered", function() {
@@ -138,4 +155,4 @@ describe("jasmine.Env", function() {
});
});
});
});
});

View File

@@ -861,7 +861,7 @@ describe("jasmine spec running", function () {
expect(suiteResults.getItems()[2].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass");
});
it("testNestedDescribes", function() {
it("should permit nested describes", function() {
var actions = [];
env.beforeEach(function () {
@@ -953,6 +953,63 @@ describe("jasmine spec running", function () {
expect(actions).toEqual(expected);
});
it("should run multiple befores and afters in the order they are declared", function() {
var actions = [];
env.beforeEach(function () {
actions.push('runner beforeEach1');
});
env.afterEach(function () {
actions.push('runner afterEach1');
});
env.beforeEach(function () {
actions.push('runner beforeEach2');
});
env.afterEach(function () {
actions.push('runner afterEach2');
});
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('beforeEach1');
});
env.afterEach(function() {
actions.push('afterEach1');
});
env.beforeEach(function() {
actions.push('beforeEach2');
});
env.afterEach(function() {
actions.push('afterEach2');
});
env.it('does it 1', function() {
actions.push('outer it 1');
});
});
env.execute();
var expected = [
"runner beforeEach1",
"runner beforeEach2",
"beforeEach1",
"beforeEach2",
"outer it 1",
"afterEach2",
"afterEach1",
"runner afterEach2",
"runner afterEach1"
];
expect(actions).toEqual(expected);
});
it("builds up nested names", function() {
var nestedSpec;
env.describe('Test Subject', function() {
@@ -1083,4 +1140,56 @@ describe("jasmine spec running", function () {
expect(exceptionMessage).toEqual('explodes function should not have been called');
});
it("should recover gracefully when there are errors in describe functions", function() {
var specs = [];
var superSimpleReporter = new jasmine.Reporter();
superSimpleReporter.reportSpecResults = function(spec) {
specs.push("Spec: " + spec.getFullName());
var results = spec.results().getItems();
for (var i = 0; i < results.length; i++) {
var result = results[i];
specs.push("Result: " + result);
}
};
try {
env.describe("outer1", function() {
env.describe("inner1", function() {
env.it("should thingy", function() {
this.expect(true).toEqual(true);
});
throw new Error("fake error");
});
env.describe("inner2", function() {
env.it("should other thingy", function() {
this.expect(true).toEqual(true);
});
});
});
} catch(e) {
}
env.describe("outer2", function() {
env.it("should xxx", function() {
this.expect(true).toEqual(true);
});
});
env.addReporter(superSimpleReporter);
env.execute();
expect(specs.join('')).toMatch(new RegExp(
'Spec: outer1 inner1 should thingy.' +
'Result: Passed.' +
'Spec: outer1 encountered a declaration exception.' +
'Result: Error: fake error.*' +
'Spec: outer1 inner2 should other thingy.' +
'Result: Passed.' +
'Spec: outer2 should xxx.' +
'Result: Passed.'
));
});
});

View File

@@ -14,6 +14,20 @@ describe("TrivialReporter", function() {
};
}
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() {
var trivialReporter = new jasmine.TrivialReporter({ location: {search: "?spec=run%20this"} });
expect(trivialReporter.specFilter(fakeSpec("run this"))).toBeTruthy();
@@ -24,14 +38,15 @@ describe("TrivialReporter", function() {
it("should display empty divs for every suite when the runner is starting", function() {
var trivialReporter = new jasmine.TrivialReporter({ body: body });
trivialReporter.reportRunnerStarting({
env: new jasmine.Env(),
suites: function() {
return [ new jasmine.Suite({}, "suite 1", null, null) ];
}
});
var divs = body.getElementsByTagName("div");
expect(divs.length).toEqual(2);
expect(divs[1].innerHTML).toContain("suite 1");
var divs = findElements(body.getElementsByTagName("div"), "suite");
expect(divs.length).toEqual(1);
expect(divs[0].innerHTML).toContain("suite 1");
});
describe('Matcher reporting', function () {
@@ -104,6 +119,7 @@ describe("TrivialReporter", function() {
trivialReporter = new jasmine.TrivialReporter({ body: body });
trivialReporter.reportRunnerStarting({
env: new jasmine.Env(),
suites: function() {
return [ new jasmine.Suite({}, "suite 1", null, null) ];
}
@@ -120,10 +136,11 @@ describe("TrivialReporter", function() {
trivialReporter.reportSpecResults(spec);
var divs = body.getElementsByTagName("div");
expect(divs[3].innerHTML).toEqual("Expected 'a' to be null, but it was not");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toEqual("Expected 'a' to be null, but it was not");
});
it("should add the failure message to the DOM (non-toEquals matchers)", function() {
it("should add the failure message to the DOM (non-toEquals matchers) html escaping", function() {
expectationResult = new jasmine.ExpectationResult({
matcherName: "toBeNull", passed: false, message: "Expected '1 < 2' to <b>e null, & it was not"
});
@@ -133,7 +150,8 @@ describe("TrivialReporter", function() {
trivialReporter.reportSpecResults(spec);
var divs = body.getElementsByTagName("div");
expect(divs[3].innerHTML).toEqual("Expected '1 &lt; 2' to &lt;b&gt;e null, &amp; it was not");
var errorDiv = findElement(divs, 'resultMessage fail');
expect(errorDiv.innerHTML).toEqual("Expected '1 &lt; 2' to &lt;b&gt;e null, &amp; it was not");
});
});

View File

@@ -0,0 +1,88 @@
describe('WaitsForBlock', function () {
var env, suite, timeout, spec, message, onComplete, fakeTimer;
beforeEach(function() {
env = new jasmine.Env();
env.updateInterval = 0;
suite = new jasmine.Suite(env, 'suite 1');
timeout = 1000;
spec = new jasmine.Spec(env, suite);
message = "some error message";
onComplete = jasmine.createSpy("onComplete");
});
it('onComplete should be called if the latchFunction returns true', function () {
var latchFunction = function() {
return true;
};
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
expect(onComplete).wasNotCalled();
block.execute(onComplete);
expect(onComplete).wasCalled();
});
it('latchFunction should run in same scope as spec', function () {
var result;
var latchFunction = function() {
result = this.scopedValue;
};
spec.scopedValue = 'foo';
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
block.execute(onComplete);
expect(result).toEqual('foo');
});
it('should fail spec and call onComplete if there is an error in the latchFunction', function() {
var latchFunction = jasmine.createSpy('latchFunction').andThrow('some error');
spyOn(spec, 'fail');
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
block.execute(onComplete);
expect(spec.fail).wasCalledWith('some error');
expect(onComplete).wasCalled();
});
describe("if latchFunction returns false", function() {
var latchFunction, fakeTimer;
beforeEach(function() {
latchFunction = jasmine.createSpy('latchFunction').andReturn(false);
fakeTimer = new jasmine.FakeTimer();
env.setTimeout = fakeTimer.setTimeout;
env.clearTimeout = fakeTimer.clearTimeout;
env.setInterval = fakeTimer.setInterval;
env.clearInterval = fakeTimer.clearInterval;
});
it('latchFunction should be retried after 100 ms', function () {
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
expect(latchFunction).wasNotCalled();
block.execute(onComplete);
expect(latchFunction.callCount).toEqual(1);
fakeTimer.tick(50);
expect(latchFunction.callCount).toEqual(1);
fakeTimer.tick(50);
expect(latchFunction.callCount).toEqual(2);
});
it('onComplete should be called if latchFunction returns true before timeout', function () {
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
expect(onComplete).wasNotCalled();
block.execute(onComplete);
expect(onComplete).wasNotCalled();
latchFunction.andReturn(true);
fakeTimer.tick(100);
expect(onComplete).wasCalled();
});
it('spec should fail with the passed message if the timeout is reached (and not call onComplete)', function () {
spyOn(spec, 'fail');
var block = new jasmine.WaitsForBlock(env, timeout, latchFunction, message, spec);
block.execute(onComplete);
expect(spec.fail).wasNotCalled();
fakeTimer.tick(timeout);
expect(spec.fail).wasCalled();
var failMessage = spec.fail.mostRecentCall.args[0].message;
expect(failMessage).toMatch(message);
expect(onComplete).wasNotCalled();
});
});
});

View File

@@ -46,6 +46,18 @@ 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 {
return "version unknown";
}
};
/**
* @returns a sequential integer starting at 0
*/
@@ -84,10 +96,21 @@ jasmine.Env.prototype.describe = function(description, specDefinitions) {
this.currentSuite = suite;
specDefinitions.call(suite);
var declarationError = null;
try {
specDefinitions.call(suite);
} catch(e) {
declarationError = e;
}
this.currentSuite = parentSuite;
if (declarationError) {
this.it("encountered a declaration exception", function() {
throw declarationError;
});
}
return suite;
};

View File

@@ -25,12 +25,12 @@ jasmine.Runner.prototype.execute = function() {
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.push(beforeEachFunction);
this.before_.splice(0,0,beforeEachFunction);
};
jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.push(afterEachFunction);
this.after_.splice(0,0,afterEachFunction);
};

View File

@@ -37,12 +37,12 @@ jasmine.Suite.prototype.finish = function(onComplete) {
jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
beforeEachFunction.typeName = 'beforeEach';
this.before_.push(beforeEachFunction);
this.before_.unshift(beforeEachFunction);
};
jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
afterEachFunction.typeName = 'afterEach';
this.after_.push(afterEachFunction);
this.after_.unshift(afterEachFunction);
};
jasmine.Suite.prototype.results = function() {

View File

@@ -30,7 +30,6 @@ jasmine.WaitsForBlock.prototype.execute = function (onComplete) {
name: 'timeout',
message: message
});
self.spec._next();
} else {
self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
self.env.setTimeout(function () { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);

View File

@@ -13,7 +13,7 @@ jasmine.unimplementedMethod_ = function() {
};
/**
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code is just
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
* a plain old variable and may be redefined by somebody else.
*
* @private
@@ -57,6 +57,10 @@ jasmine.MessageResult = function(text) {
this.trace = new Error(); // todo: test better
};
jasmine.MessageResult.prototype.toString = function() {
return this.text;
};
jasmine.ExpectationResult = function(params) {
this.type = 'ExpectationResult';
this.matcherName = params.matcherName;
@@ -71,6 +75,10 @@ jasmine.ExpectationResult = function(params) {
this.trace = this.passed_ ? '' : new Error(this.message);
};
jasmine.ExpectationResult.prototype.toString = function () {
return this.message;
};
jasmine.ExpectationResult.prototype.passed = function () {
return this.passed_;
};
@@ -558,6 +566,7 @@ jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
*
* @param {String} url path to the file to include
* @param {Boolean} opt_global
* @deprecated We suggest you use a different method of including JS source files. <code>jasmine.include</code> will be removed soon.
*/
jasmine.include = function(url, opt_global) {
if (opt_global) {

View File

@@ -1,177 +1,177 @@
// 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() {
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: window.setTimeout,
clearTimeout: window.clearTimeout,
setInterval: window.setInterval,
clearInterval: window.clearInterval
},
assertInstalled: function() {
if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
window.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);
}
};
window.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);
}
};
window.clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
window.clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};
// 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() {
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: window.setTimeout,
clearTimeout: window.clearTimeout,
setInterval: window.setInterval,
clearInterval: window.clearInterval
},
assertInstalled: function() {
if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) {
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
}
},
installed: null
};
jasmine.Clock.installed = jasmine.Clock.real;
//else for IE support
window.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);
}
};
window.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);
}
};
window.clearTimeout = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearTimeout(timeoutKey);
}
};
window.clearInterval = function(timeoutKey) {
if (jasmine.Clock.installed.clearTimeout.apply) {
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
} else {
return jasmine.Clock.installed.clearInterval(timeoutKey);
}
};

View File

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