diff --git a/.gitignore b/.gitignore index ba72ec6c..9f11b755 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ .idea/ -.idea/inspectionProfiles/ \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index a6c0eca4..00000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index e8b980bc..00000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/Rakefile b/Rakefile index 1ef40683..1531441e 100644 --- a/Rakefile +++ b/Rakefile @@ -10,16 +10,86 @@ namespace :test do end desc 'Builds lib/jasmine from source' -task :build do - - # these files must be better - sources = ["src/base.js", "src/util.js", "src/Env.js", "src/ActionCollection.js", "src/Reporter.js"] - - sources += Dir.glob('src/*.js').reject{|f| sources.include?(f)} - - jasmine = File.new('lib/jasmine.js', 'w') - sources.each do |source_filename| - jasmine.puts(File.read(source_filename)) +namespace :build do + task :jasmine => 'build:doc' do + require 'json' + sources = jasmine_sources + version = version_hash + old_jasmine_files = Dir.glob('lib/jasmine*.js') + old_jasmine_files.each do |file| + File.delete(file) + end + jasmine = File.new("lib/#{jasmine_filename version}", 'w') + jasmine.puts(File.read(sources.shift)) + jasmine.puts %{ +jasmine.version_= { + "major": #{version['major']}, + "minor": #{version['minor']}, + "build": #{version['build']}, + "revision": #{Time.now.to_i} + }; +} + sources.each do |source_filename| + jasmine.puts(File.read(source_filename)) + end end + + desc "Build jasmine documentation" + task :doc do + require 'rubygems' + #sudo gem install ragaskar-jsdoc_helper + require 'jsdoc_helper' + + + JsdocHelper::Rake::Task.new(:lambda_jsdoc) + Rake::Task[:lambda_jsdoc].invoke + end + end +def jasmine_sources + sources = ["src/base.js", "src/util.js", "src/Env.js", "src/Reporter.js", "src/Block.js"] + + sources += Dir.glob('src/*.js').reject{|f| f == 'src/base.js' || sources.include?(f)}.sort +end + +def jasmine_filename(version) + "jasmine-#{version['major']}.#{version['minor']}.#{version['build']}.js" +end + +def version_hash + JSON.parse(File.new("src/version.json").read); +end + +namespace :test do + desc "Run continuous integration tests" + task :ci => 'build:jasmine' do + require "spec" + require 'spec/rake/spectask' + Spec::Rake::SpecTask.new(:lambda_ci) do |t| + t.spec_opts = ["--color", "--format", "specdoc"] + t.spec_files = ["spec/jasmine_spec.rb"] + end + Rake::Task[:lambda_ci].invoke + end + +end + +desc "Run jasmine tests via server" +task :jasmine_server do + require File.expand_path(File.join(File.dirname(__FILE__), "contrib/ruby/jasmine_spec_builder")) + + includes = jasmine_sources + ['lib/TrivialReporter.js'] + spec_files = Dir.glob("spec/**/*.js") + + dir_mappings = { + "/spec" => "spec", + "/lib" => "lib", + "/src" => 'src' + } + + puts "your tests are here:" + puts " http://localhost:8888/run.html" + + Jasmine::SimpleServer.start(8888, includes + spec_files, dir_mappings) +end \ No newline at end of file diff --git a/contrib/ruby/jasmine_runner.rb b/contrib/ruby/jasmine_runner.rb index d3810f36..201abe71 100644 --- a/contrib/ruby/jasmine_runner.rb +++ b/contrib/ruby/jasmine_runner.rb @@ -1,5 +1,6 @@ require 'socket' require 'erb' +require 'json' module Jasmine # this seemingly-over-complex method is necessary to get an open port on at least some of our Macs @@ -73,16 +74,31 @@ module Jasmine end end + class Redirect + def initialize(url) + @url = url + end + + def call(env) + [ + 302, + { 'Location' => @url }, + [] + ] + end + end + class SimpleServer def self.start(port, spec_files_or_proc, mappings) require 'thin' config = { + '/' => Jasmine::Redirect.new('/run.html'), '/run.html' => Jasmine::RunAdapter.new(spec_files_or_proc) } mappings.each do |from, to| config[from] = Rack::File.new(to) - end + end app = Rack::URLMap.new(config) @@ -128,7 +144,7 @@ module Jasmine def eval_js(script) escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'" - result = @driver.get_eval("window.eval(#{escaped_script})") + result = @driver.get_eval("eval(#{escaped_script}, window)") JSON.parse("[#{result}]")[0] end end diff --git a/contrib/ruby/jasmine_spec_builder.rb b/contrib/ruby/jasmine_spec_builder.rb index 591cd102..6e03801e 100644 --- a/contrib/ruby/jasmine_spec_builder.rb +++ b/contrib/ruby/jasmine_spec_builder.rb @@ -114,13 +114,15 @@ module Jasmine puts message["text"] puts "\n" else - STDERR << message["message"] - STDERR << "\n" + unless message["message"] =~ /^Passed.$/ + STDERR << message["message"] + STDERR << "\n" - out << message["message"] - out << "\n" + out << message["message"] + out << "\n" + end - unless message["passed"] + unless message["passed_"] stack_trace = message["trace"]["stack"].gsub(/
/, "\n").gsub(/<\/?b>/, " ") STDERR << stack_trace.gsub(/\(.*\)@http:\/\/localhost:[0-9]+\/specs\//, "/spec/") STDERR << "\n" @@ -129,7 +131,7 @@ module Jasmine end fail out unless spec_results['result'] == 'passed' - puts out + puts out unless out.empty? end private diff --git a/contrib/ruby/run.html b/contrib/ruby/run.html index 0f3035d3..9b307c74 100644 --- a/contrib/ruby/run.html +++ b/contrib/ruby/run.html @@ -3,12 +3,10 @@ Jasmine suite - - - - - - + + <% spec_files.each do |spec_file| %> + + <% end %> - <% spec_files.each do |spec_file| %> - - <% end %> +
diff --git a/contrib/ruby/jasmine_runner_spec.rb b/contrib/ruby/spec/jasmine_runner_spec.rb similarity index 96% rename from contrib/ruby/jasmine_runner_spec.rb rename to contrib/ruby/spec/jasmine_runner_spec.rb index 83999de4..4339db76 100644 --- a/contrib/ruby/jasmine_runner_spec.rb +++ b/contrib/ruby/spec/jasmine_runner_spec.rb @@ -1,6 +1,6 @@ require 'spec' require 'open-uri' -require File.dirname(__FILE__) + '/jasmine_runner' +require File.dirname(__FILE__) + '/../jasmine_runner' describe Jasmine::SimpleServer do before do diff --git a/doc/files.html b/doc/files.html index b997fffd..4ce1733c 100644 --- a/doc/files.html +++ b/doc/files.html @@ -188,16 +188,16 @@ ul.inheritsList
  • jasmine
  • -
  • jasmine.ActionCollection
  • +
  • jasmine.Block
  • jasmine.Env
  • +
  • jasmine.JsApiReporter
  • +
  • jasmine.MultiReporter
  • jasmine.NestedResults
  • -
  • jasmine.QueuedFunction
  • -
  • jasmine.Reporter
  • jasmine.Runner
  • @@ -219,7 +219,31 @@ ul.inheritsList
    -

    lib/jasmine.js

    +

    lib/jasmine-0.9.0.js

    + +
    + + + + +
    +
    +
    + +
    +

    lib/json2.js

    + +
    + + + + +
    +
    +
    + +
    +

    lib/TrivialReporter.js

    @@ -234,7 +258,7 @@ ul.inheritsList
    - Documentation generated by JsDoc Toolkit 2.3.0 on Thu Jul 09 2009 21:42:19 GMT-0700 (PDT) + Documentation generated by JsDoc Toolkit 2.1.0 on Wed Sep 02 2009 07:41:14 GMT-0700 (PDT)
    \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index c9123ec3..9aa814fc 100644 --- a/doc/index.html +++ b/doc/index.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - + JsDoc Reference - Index @@ -188,16 +188,16 @@ ul.inheritsList
  • jasmine
  • -
  • jasmine.ActionCollection
  • +
  • jasmine.Block
  • jasmine.Env
  • +
  • jasmine.JsApiReporter
  • +
  • jasmine.MultiReporter
  • jasmine.NestedResults
  • -
  • jasmine.QueuedFunction
  • -
  • jasmine.Reporter
  • jasmine.Runner
  • @@ -231,7 +231,7 @@ ul.inheritsList
    -

    jasmine.ActionCollection

    +

    jasmine.Block


    @@ -242,6 +242,12 @@ ul.inheritsList
    +
    +

    jasmine.JsApiReporter

    + +
    +
    +

    jasmine.MultiReporter

    @@ -254,12 +260,6 @@ ul.inheritsList

    -
    -

    jasmine.QueuedFunction

    - -
    -
    -

    jasmine.Reporter

    @@ -300,7 +300,7 @@ ul.inheritsList
    - Documentation generated by JsDoc Toolkit 2.3.0 on Thu Jul 09 2009 21:42:19 GMT-0700 (PDT) + Documentation generated by JsDoc Toolkit 2.1.0 on Wed Sep 02 2009 07:41:14 GMT-0700 (PDT)
    \ No newline at end of file diff --git a/doc/symbols/_global_.html b/doc/symbols/_global_.html index e831a254..663deb5d 100644 --- a/doc/symbols/_global_.html +++ b/doc/symbols/_global_.html @@ -193,16 +193,16 @@ ul.inheritsList
  • jasmine
  • -
  • jasmine.ActionCollection
  • +
  • jasmine.Block
  • jasmine.Env
  • +
  • jasmine.JsApiReporter
  • +
  • jasmine.MultiReporter
  • jasmine.NestedResults
  • -
  • jasmine.QueuedFunction
  • -
  • jasmine.Reporter
  • jasmine.Runner
  • @@ -389,7 +389,7 @@ ul.inheritsList Used for restoring any state that is hijacked during spec execution.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -430,7 +430,7 @@ Used for restoring any state that is hijacked during spec execution. Used for spec setup, including validating assumptions.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -473,7 +473,7 @@ are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be of setup in some tests.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -527,7 +527,7 @@ It is passed an Object that is the actual value and should chain to one of the m jasmine.Matchers functions.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -568,7 +568,7 @@ jasmine.Matchers functions. // TODO: pending tests
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -619,7 +619,7 @@ jasmine.Matchers functions. Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -658,7 +658,7 @@ jasmine.Matchers functions. Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -725,7 +725,7 @@ spyOn(foo, 'not'); // actual foo.not will not be called, execution stops Waits for a timeout before moving to the next runs()-defined block.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -764,7 +764,7 @@ spyOn(foo, 'not'); // actual foo.not will not be called, execution stops Waits for the latchFunction to return true before proceeding to the next runs()-defined block.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -815,7 +815,7 @@ spyOn(foo, 'not'); // actual foo.not will not be called, execution stops Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -862,7 +862,7 @@ spyOn(foo, 'not'); // actual foo.not will not be called, execution stops A convenience method that allows existing specs to be disabled temporarily during development.
    - Defined in: jasmine.js. + Defined in: jasmine-0.9.0.js. @@ -908,7 +908,7 @@ A convenience method that allows existing specs to be disabled temporarily durin
    - Documentation generated by JsDoc Toolkit 2.3.0 on Thu Jul 09 2009 21:42:18 GMT-0700 (PDT) + Documentation generated by JsDoc Toolkit 2.1.0 on Wed Sep 02 2009 07:41:14 GMT-0700 (PDT)
    diff --git a/doc/symbols/jasmine.QueuedFunction.html b/doc/symbols/jasmine.Block.html similarity index 84% rename from doc/symbols/jasmine.QueuedFunction.html rename to doc/symbols/jasmine.Block.html index f53996bb..0577d1ff 100644 --- a/doc/symbols/jasmine.QueuedFunction.html +++ b/doc/symbols/jasmine.Block.html @@ -5,7 +5,7 @@ - JsDoc Reference - jasmine.QueuedFunction + JsDoc Reference - jasmine.Block
      1 jasmine.TrivialReporter = function(doc) {
    +  2   this.document = doc || document;
    +  3   this.suiteDivs = {};
    +  4 };
    +  5 
    +  6 jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
    +  7   var el = document.createElement(type);
    +  8 
    +  9   for (var i = 2; i < arguments.length; i++) {
    + 10     var child = arguments[i];
    + 11 
    + 12     if (typeof child === 'string') {
    + 13       el.appendChild(document.createTextNode(child));
    + 14     } else {
    + 15       el.appendChild(child);
    + 16     }
    + 17   }
    + 18 
    + 19   for (var attr in attrs) {
    + 20     if (attr == 'className') {
    + 21       el.setAttribute('class', attrs[attr]);
    + 22     } else {
    + 23       el[attr] = attrs[attr];
    + 24     }
    + 25   }
    + 26 
    + 27   return el;
    + 28 };
    + 29 
    + 30 jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
    + 31   var suites = runner.suites();
    + 32 
    + 33   this.runnerDiv = this.createDom('div', { className: 'runner running' }, "Running...");
    + 34   this.document.body.appendChild(this.runnerDiv);
    + 35 
    + 36   for (var i = 0; i < suites.length; i++) {
    + 37     var suite = suites[i];
    + 38     var suiteDiv = this.createDom('div', { className: 'suite' },
    + 39         this.createDom('a', { className: 'runSpec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
    + 40         suite.description);
    + 41     this.suiteDivs[suite.getFullName()] = suiteDiv;
    + 42     var parentDiv = this.document.body;
    + 43     if (suite.parentSuite) {
    + 44       parentDiv = this.suiteDivs[suite.parentSuite.getFullName()];
    + 45     }
    + 46     parentDiv.appendChild(suiteDiv);
    + 47   }
    + 48 };
    + 49 
    + 50 jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
    + 51   var results = runner.getResults();
    + 52   var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
    + 53   this.runnerDiv.setAttribute("class", className);
    + 54   var message = results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
    + 55   this.runnerDiv.replaceChild(this.document.createTextNode(message), this.runnerDiv.firstChild);
    + 56 };
    + 57 
    + 58 jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
    + 59   var results = suite.getResults();
    + 60   var status = results.passed() ? 'passed' : 'failed';
    + 61   if (results.totalCount == 0) { // todo: change this to check results.skipped
    + 62     status = 'skipped';
    + 63   }
    + 64   this.suiteDivs[suite.getFullName()].className += " " + status;
    + 65 };
    + 66 
    + 67 jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
    + 68   var results = spec.getResults();
    + 69   var status = results.passed() ? 'passed' : 'failed';
    + 70   if (results.skipped) {
    + 71     status = 'skipped';
    + 72   }
    + 73   var specDiv = this.createDom('div', { className: 'spec '  + status },
    + 74       this.createDom('a', { className: 'runSpec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
    + 75       spec.getFullName());
    + 76 
    + 77 
    + 78   var resultItems = results.getItems();
    + 79   for (var i = 0; i < resultItems.length; i++) {
    + 80     var result = resultItems[i];
    + 81     if (result.passed && !result.passed()) {
    + 82       var resultMessageDiv = this.createDom('div', {className: 'resultMessage fail'});
    + 83       resultMessageDiv.innerHTML = result.message; // todo: lame; mend
    + 84       specDiv.appendChild(resultMessageDiv);
    + 85       specDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
    + 86     }
    + 87   }
    + 88 
    + 89   this.suiteDivs[spec.suite.getFullName()].appendChild(specDiv);
    + 90 };
    + 91 
    + 92 jasmine.TrivialReporter.prototype.log = function() {
    + 93   console.log.apply(console, arguments);
    + 94 };
    + 95 
    + 96 jasmine.TrivialReporter.prototype.getLocation = function() {
    + 97   return this.document.location;
    + 98 };
    + 99 
    +100 jasmine.TrivialReporter.prototype.specFilter = function(spec) {
    +101   var paramMap = {};
    +102   var params = this.getLocation().search.substring(1).split('&');
    +103   for (var i = 0; i < params.length; i++) {
    +104     var p = params[i].split('=');
    +105     paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
    +106   }
    +107 
    +108   if (!paramMap["spec"]) return true;
    +109   return spec.getFullName().indexOf(paramMap["spec"]) == 0;
    +110 };
    +111 
    +112 //protect against console.log incidents
    +113 if (!("console" in window) || !("firebug" in console)) {
    +114   var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
    +115   window.console = {};
    +116   for (var i = 0, len = names.length; i < len; ++i) {
    +117     window.console[names[i]] = function() {
    +118     };
    +119   }
    +120 }
    +121 
    \ No newline at end of file diff --git a/doc/symbols/src/lib_jasmine.js.html b/doc/symbols/src/lib_jasmine-0.9.0.js.html similarity index 63% rename from doc/symbols/src/lib_jasmine.js.html rename to doc/symbols/src/lib_jasmine-0.9.0.js.html index 5edd9e96..e76c5a46 100644 --- a/doc/symbols/src/lib_jasmine.js.html +++ b/doc/symbols/src/lib_jasmine-0.9.0.js.html @@ -47,1891 +47,1980 @@ 40 41 jasmine.ExpectationResult = function(passed, message, details) { 42 this.type = 'ExpectationResult'; - 43 this.passed = passed; + 43 this.passed_ = passed; 44 this.message = message; 45 this.details = details; 46 this.trace = new Error(message); // todo: test better 47 }; 48 - 49 /** - 50 * Getter for the Jasmine environment. Ensures one gets created - 51 */ - 52 jasmine.getEnv = function() { - 53 return jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); - 54 }; - 55 - 56 /** - 57 * @ignore - 58 * @private - 59 * @param value - 60 * @returns {Boolean} - 61 */ - 62 jasmine.isArray_ = function(value) { - 63 return value && - 64 typeof value === 'object' && - 65 typeof value.length === 'number' && - 66 typeof value.splice === 'function' && - 67 !(value.propertyIsEnumerable('length')); - 68 }; - 69 - 70 /** - 71 * Pretty printer for expecations. Takes any object and turns it into a human-readable string. - 72 * - 73 * @param value {Object} an object to be outputted - 74 * @returns {String} - 75 */ - 76 jasmine.pp = function(value) { - 77 var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); - 78 stringPrettyPrinter.format(value); - 79 return stringPrettyPrinter.string; - 80 }; - 81 - 82 /** - 83 * Returns true if the object is a DOM Node. - 84 * - 85 * @param {Object} obj object to check - 86 * @returns {Boolean} - 87 */ - 88 jasmine.isDomNode = function(obj) { - 89 return obj['nodeType'] > 0; - 90 }; - 91 - 92 /** - 93 * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. - 94 * - 95 * @example - 96 * // don't care about which function is passed in, as long as it's a function - 97 * expect(mySpy).wasCalledWith(jasmine.any(Function)); + 49 jasmine.ExpectationResult.prototype.passed = function () { + 50 return this.passed_; + 51 }; + 52 + 53 /** + 54 * Getter for the Jasmine environment. Ensures one gets created + 55 */ + 56 jasmine.getEnv = function() { + 57 return jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); + 58 }; + 59 + 60 /** + 61 * @ignore + 62 * @private + 63 * @param value + 64 * @returns {Boolean} + 65 */ + 66 jasmine.isArray_ = function(value) { + 67 return value && + 68 typeof value === 'object' && + 69 typeof value.length === 'number' && + 70 typeof value.splice === 'function' && + 71 !(value.propertyIsEnumerable('length')); + 72 }; + 73 + 74 /** + 75 * Pretty printer for expecations. Takes any object and turns it into a human-readable string. + 76 * + 77 * @param value {Object} an object to be outputted + 78 * @returns {String} + 79 */ + 80 jasmine.pp = function(value) { + 81 var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); + 82 stringPrettyPrinter.format(value); + 83 return stringPrettyPrinter.string; + 84 }; + 85 + 86 /** + 87 * Returns true if the object is a DOM Node. + 88 * + 89 * @param {Object} obj object to check + 90 * @returns {Boolean} + 91 */ + 92 jasmine.isDomNode = function(obj) { + 93 return obj['nodeType'] > 0; + 94 }; + 95 + 96 /** + 97 * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. 98 * - 99 * @param {Class} clazz -100 * @returns matchable object of the type clazz -101 */ -102 jasmine.any = function(clazz) { -103 return new jasmine.Matchers.Any(clazz); -104 }; -105 -106 /** -107 * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. -108 * -109 * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine -110 * expectation syntax. Spies can be checked if they were called or not and what the calling params were. -111 * -112 * A Spy has the following mehtod: wasCalled, callCount, mostRecentCall, and argsForCall (see docs) -113 * Spies are torn down at the end of every spec. -114 * -115 * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. -116 * -117 * @example -118 * // a stub -119 * var myStub = jasmine.createSpy('myStub'); // can be used anywhere -120 * -121 * // spy example -122 * var foo = { -123 * not: function(bool) { return !bool; } -124 * } -125 * -126 * // actual foo.not will not be called, execution stops -127 * spyOn(foo, 'not'); -128 -129 // foo.not spied upon, execution will continue to implementation -130 * spyOn(foo, 'not').andCallThrough(); -131 * -132 * // fake example -133 * var foo = { -134 * not: function(bool) { return !bool; } -135 * } -136 * -137 * // foo.not(val) will return val -138 * spyOn(foo, 'not').andCallFake(function(value) {return value;}); -139 * -140 * // mock example -141 * foo.not(7 == 7); -142 * expect(foo.not).wasCalled(); -143 * expect(foo.not).wasCalledWith(true); -144 * -145 * @constructor -146 * @see spyOn, jasmine.createSpy, jasmine.createSpyObj -147 * @param {String} name -148 */ -149 jasmine.Spy = function(name) { -150 /** -151 * The name of the spy, if provided. -152 */ -153 this.identity = name || 'unknown'; + 99 * @example +100 * // don't care about which function is passed in, as long as it's a function +101 * expect(mySpy).wasCalledWith(jasmine.any(Function)); +102 * +103 * @param {Class} clazz +104 * @returns matchable object of the type clazz +105 */ +106 jasmine.any = function(clazz) { +107 return new jasmine.Matchers.Any(clazz); +108 }; +109 +110 /** +111 * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. +112 * +113 * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine +114 * expectation syntax. Spies can be checked if they were called or not and what the calling params were. +115 * +116 * A Spy has the following mehtod: wasCalled, callCount, mostRecentCall, and argsForCall (see docs) +117 * Spies are torn down at the end of every spec. +118 * +119 * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. +120 * +121 * @example +122 * // a stub +123 * var myStub = jasmine.createSpy('myStub'); // can be used anywhere +124 * +125 * // spy example +126 * var foo = { +127 * not: function(bool) { return !bool; } +128 * } +129 * +130 * // actual foo.not will not be called, execution stops +131 * spyOn(foo, 'not'); +132 +133 // foo.not spied upon, execution will continue to implementation +134 * spyOn(foo, 'not').andCallThrough(); +135 * +136 * // fake example +137 * var foo = { +138 * not: function(bool) { return !bool; } +139 * } +140 * +141 * // foo.not(val) will return val +142 * spyOn(foo, 'not').andCallFake(function(value) {return value;}); +143 * +144 * // mock example +145 * foo.not(7 == 7); +146 * expect(foo.not).wasCalled(); +147 * expect(foo.not).wasCalledWith(true); +148 * +149 * @constructor +150 * @see spyOn, jasmine.createSpy, jasmine.createSpyObj +151 * @param {String} name +152 */ +153 jasmine.Spy = function(name) { 154 /** -155 * Is this Object a spy? +155 * The name of the spy, if provided. 156 */ -157 this.isSpy = true; +157 this.identity = name || 'unknown'; 158 /** -159 * The acutal function this spy stubs. +159 * Is this Object a spy? 160 */ -161 this.plan = function() {}; +161 this.isSpy = true; 162 /** -163 * Tracking of the most recent call to the spy. -164 * @example -165 * var mySpy = jasmine.createSpy('foo'); -166 * mySpy(1, 2); -167 * mySpy.mostRecentCall.args = [1, 2]; -168 */ -169 this.mostRecentCall = {}; -170 -171 /** -172 * Holds arguments for each call to the spy, indexed by call count -173 * @example -174 * var mySpy = jasmine.createSpy('foo'); -175 * mySpy(1, 2); -176 * mySpy(7, 8); -177 * mySpy.mostRecentCall.args = [7, 8]; -178 * mySpy.argsForCall[0] = [1, 2]; -179 * mySpy.argsForCall[1] = [7, 8]; -180 */ -181 this.argsForCall = []; -182 }; -183 -184 /** -185 * Tells a spy to call through to the actual implemenatation. -186 * -187 * @example -188 * var foo = { -189 * bar: function() { // do some stuff } -190 * } -191 * -192 * // defining a spy on an existing property: foo.bar -193 * spyOn(foo, 'bar').andCallThrough(); -194 */ -195 jasmine.Spy.prototype.andCallThrough = function() { -196 this.plan = this.originalValue; -197 return this; -198 }; -199 -200 /** -201 * For setting the return value of a spy. -202 * -203 * @example -204 * // defining a spy from scratch: foo() returns 'baz' -205 * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); +163 * The acutal function this spy stubs. +164 */ +165 this.plan = function() {}; +166 /** +167 * Tracking of the most recent call to the spy. +168 * @example +169 * var mySpy = jasmine.createSpy('foo'); +170 * mySpy(1, 2); +171 * mySpy.mostRecentCall.args = [1, 2]; +172 */ +173 this.mostRecentCall = {}; +174 +175 /** +176 * Holds arguments for each call to the spy, indexed by call count +177 * @example +178 * var mySpy = jasmine.createSpy('foo'); +179 * mySpy(1, 2); +180 * mySpy(7, 8); +181 * mySpy.mostRecentCall.args = [7, 8]; +182 * mySpy.argsForCall[0] = [1, 2]; +183 * mySpy.argsForCall[1] = [7, 8]; +184 */ +185 this.argsForCall = []; +186 }; +187 +188 /** +189 * Tells a spy to call through to the actual implemenatation. +190 * +191 * @example +192 * var foo = { +193 * bar: function() { // do some stuff } +194 * } +195 * +196 * // defining a spy on an existing property: foo.bar +197 * spyOn(foo, 'bar').andCallThrough(); +198 */ +199 jasmine.Spy.prototype.andCallThrough = function() { +200 this.plan = this.originalValue; +201 return this; +202 }; +203 +204 /** +205 * For setting the return value of a spy. 206 * -207 * // defining a spy on an existing property: foo.bar() returns 'baz' -208 * spyOn(foo, 'bar').andReturn('baz'); -209 * -210 * @param {Object} value -211 */ -212 jasmine.Spy.prototype.andReturn = function(value) { -213 this.plan = function() { -214 return value; -215 }; -216 return this; -217 }; -218 -219 /** -220 * For throwing an exception when a spy is called. -221 * -222 * @example -223 * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' -224 * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); +207 * @example +208 * // defining a spy from scratch: foo() returns 'baz' +209 * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); +210 * +211 * // defining a spy on an existing property: foo.bar() returns 'baz' +212 * spyOn(foo, 'bar').andReturn('baz'); +213 * +214 * @param {Object} value +215 */ +216 jasmine.Spy.prototype.andReturn = function(value) { +217 this.plan = function() { +218 return value; +219 }; +220 return this; +221 }; +222 +223 /** +224 * For throwing an exception when a spy is called. 225 * -226 * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' -227 * spyOn(foo, 'bar').andThrow('baz'); -228 * -229 * @param {String} exceptionMsg -230 */ -231 jasmine.Spy.prototype.andThrow = function(exceptionMsg) { -232 this.plan = function() { -233 throw exceptionMsg; -234 }; -235 return this; -236 }; -237 -238 /** -239 * Calls an alternate implementation when a spy is called. -240 * -241 * @example -242 * var baz = function() { -243 * // do some stuff, return something -244 * } -245 * // defining a spy from scratch: foo() calls the function baz -246 * var foo = jasmine.createSpy('spy on foo').andCall(baz); -247 * -248 * // defining a spy on an existing property: foo.bar() calls an anonymnous function -249 * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); -250 * -251 * @param {Function} fakeFunc -252 */ -253 jasmine.Spy.prototype.andCallFake = function(fakeFunc) { -254 this.plan = fakeFunc; -255 return this; -256 }; -257 -258 /** -259 * Resets all of a spy's the tracking variables so that it can be used again. -260 * -261 * @example -262 * spyOn(foo, 'bar'); -263 * -264 * foo.bar(); -265 * -266 * expect(foo.bar.callCount).toEqual(1); +226 * @example +227 * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' +228 * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); +229 * +230 * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' +231 * spyOn(foo, 'bar').andThrow('baz'); +232 * +233 * @param {String} exceptionMsg +234 */ +235 jasmine.Spy.prototype.andThrow = function(exceptionMsg) { +236 this.plan = function() { +237 throw exceptionMsg; +238 }; +239 return this; +240 }; +241 +242 /** +243 * Calls an alternate implementation when a spy is called. +244 * +245 * @example +246 * var baz = function() { +247 * // do some stuff, return something +248 * } +249 * // defining a spy from scratch: foo() calls the function baz +250 * var foo = jasmine.createSpy('spy on foo').andCall(baz); +251 * +252 * // defining a spy on an existing property: foo.bar() calls an anonymnous function +253 * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); +254 * +255 * @param {Function} fakeFunc +256 */ +257 jasmine.Spy.prototype.andCallFake = function(fakeFunc) { +258 this.plan = fakeFunc; +259 return this; +260 }; +261 +262 /** +263 * Resets all of a spy's the tracking variables so that it can be used again. +264 * +265 * @example +266 * spyOn(foo, 'bar'); 267 * -268 * foo.bar.reset(); +268 * foo.bar(); 269 * -270 * expect(foo.bar.callCount).toEqual(0); -271 */ -272 jasmine.Spy.prototype.reset = function() { -273 this.wasCalled = false; -274 this.callCount = 0; -275 this.argsForCall = []; -276 this.mostRecentCall = {}; -277 }; -278 -279 jasmine.createSpy = function(name) { -280 -281 var spyObj = function() { -282 spyObj.wasCalled = true; -283 spyObj.callCount++; -284 var args = jasmine.util.argsToArray(arguments); -285 //spyObj.mostRecentCall = { -286 // object: this, -287 // args: args -288 //}; -289 spyObj.mostRecentCall.object = this; -290 spyObj.mostRecentCall.args = args; -291 spyObj.argsForCall.push(args); -292 return spyObj.plan.apply(this, arguments); -293 }; -294 -295 var spy = new jasmine.Spy(name); -296 -297 for(var prop in spy) { -298 spyObj[prop] = spy[prop]; -299 } +270 * expect(foo.bar.callCount).toEqual(1); +271 * +272 * foo.bar.reset(); +273 * +274 * expect(foo.bar.callCount).toEqual(0); +275 */ +276 jasmine.Spy.prototype.reset = function() { +277 this.wasCalled = false; +278 this.callCount = 0; +279 this.argsForCall = []; +280 this.mostRecentCall = {}; +281 }; +282 +283 jasmine.createSpy = function(name) { +284 +285 var spyObj = function() { +286 spyObj.wasCalled = true; +287 spyObj.callCount++; +288 var args = jasmine.util.argsToArray(arguments); +289 //spyObj.mostRecentCall = { +290 // object: this, +291 // args: args +292 //}; +293 spyObj.mostRecentCall.object = this; +294 spyObj.mostRecentCall.args = args; +295 spyObj.argsForCall.push(args); +296 return spyObj.plan.apply(this, arguments); +297 }; +298 +299 var spy = new jasmine.Spy(name); 300 -301 spyObj.reset(); -302 -303 return spyObj; -304 }; -305 -306 /** -307 * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something -308 * large in one call. -309 * -310 * @param {String} baseName name of spy class -311 * @param {Array} methodNames array of names of methods to make spies -312 */ -313 jasmine.createSpyObj = function(baseName, methodNames) { -314 var obj = {}; -315 for (var i = 0; i < methodNames.length; i++) { -316 obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); -317 } -318 return obj; -319 }; -320 -321 jasmine.log = function(message) { -322 jasmine.getEnv().currentSpec.getResults().log(message); +301 for(var prop in spy) { +302 spyObj[prop] = spy[prop]; +303 } +304 +305 spyObj.reset(); +306 +307 return spyObj; +308 }; +309 +310 /** +311 * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something +312 * large in one call. +313 * +314 * @param {String} baseName name of spy class +315 * @param {Array} methodNames array of names of methods to make spies +316 */ +317 jasmine.createSpyObj = function(baseName, methodNames) { +318 var obj = {}; +319 for (var i = 0; i < methodNames.length; i++) { +320 obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); +321 } +322 return obj; 323 }; 324 -325 /** -326 * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. -327 * -328 * @example -329 * // spy example -330 * var foo = { -331 * not: function(bool) { return !bool; } -332 * } -333 * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops -334 * -335 * @see jasmine.createSpy -336 * @param obj -337 * @param methodName -338 * @returns a Jasmine spy that can be chained with all spy methods -339 */ -340 var spyOn = function(obj, methodName) { -341 return jasmine.getEnv().currentSpec.spyOn(obj, methodName); -342 }; -343 -344 /** -345 * Creates a Jasmine spec that will be added to the current suite. -346 * -347 * // TODO: pending tests -348 * -349 * @example -350 * it('should be true', function() { -351 * expect(true).toEqual(true); -352 * }); -353 * -354 * @param {String} desc description of this specification -355 * @param {Function} func defines the preconditions and expectations of the spec -356 */ -357 var it = function(desc, func) { -358 return jasmine.getEnv().it(desc, func); -359 }; -360 -361 /** -362 * Creates a <em>disabled</em> Jasmine spec. -363 * -364 * A convenience method that allows existing specs to be disabled temporarily during development. -365 * -366 * @param {String} desc description of this specification -367 * @param {Function} func defines the preconditions and expectations of the spec -368 */ -369 var xit = function(desc, func) { -370 return jasmine.getEnv().xit(desc, func); -371 }; -372 -373 /** -374 * Starts a chain for a Jasmine expectation. -375 * -376 * It is passed an Object that is the actual value and should chain to one of the many -377 * jasmine.Matchers functions. -378 * -379 * @param {Object} actual Actual value to test against and expected value -380 */ -381 var expect = function(actual) { -382 return jasmine.getEnv().currentSpec.expect(actual); -383 }; -384 -385 /** -386 * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. -387 * -388 * @param {Function} func Function that defines part of a jasmine spec. -389 */ -390 var runs = function(func) { -391 jasmine.getEnv().currentSpec.runs(func); -392 }; -393 -394 /** -395 * Waits for a timeout before moving to the next runs()-defined block. -396 * @param {Number} timeout -397 */ -398 var waits = function(timeout) { -399 jasmine.getEnv().currentSpec.waits(timeout); -400 }; -401 -402 /** -403 * Waits for the latchFunction to return true before proceeding to the next runs()-defined block. -404 * -405 * @param {Number} timeout -406 * @param {Function} latchFunction -407 * @param {String} message -408 */ -409 var waitsFor = function(timeout, latchFunction, message) { -410 jasmine.getEnv().currentSpec.waitsFor(timeout, latchFunction, message); -411 }; -412 -413 /** -414 * A function that is called before each spec in a suite. -415 * -416 * Used for spec setup, including validating assumptions. -417 * -418 * @param {Function} beforeEachFunction -419 */ -420 var beforeEach = function(beforeEachFunction) { -421 jasmine.getEnv().beforeEach(beforeEachFunction); -422 }; -423 -424 /** -425 * A function that is called after each spec in a suite. -426 * -427 * Used for restoring any state that is hijacked during spec execution. -428 * -429 * @param {Function} afterEachFunction -430 */ -431 var afterEach = function(afterEachFunction) { -432 jasmine.getEnv().afterEach(afterEachFunction); -433 }; -434 -435 /** -436 * Defines a suite of specifications. -437 * -438 * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared -439 * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization -440 * of setup in some tests. +325 jasmine.log = function(message) { +326 jasmine.getEnv().currentSpec.getResults().log(message); +327 }; +328 +329 /** +330 * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. +331 * +332 * @example +333 * // spy example +334 * var foo = { +335 * not: function(bool) { return !bool; } +336 * } +337 * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops +338 * +339 * @see jasmine.createSpy +340 * @param obj +341 * @param methodName +342 * @returns a Jasmine spy that can be chained with all spy methods +343 */ +344 var spyOn = function(obj, methodName) { +345 return jasmine.getEnv().currentSpec.spyOn(obj, methodName); +346 }; +347 +348 /** +349 * Creates a Jasmine spec that will be added to the current suite. +350 * +351 * // TODO: pending tests +352 * +353 * @example +354 * it('should be true', function() { +355 * expect(true).toEqual(true); +356 * }); +357 * +358 * @param {String} desc description of this specification +359 * @param {Function} func defines the preconditions and expectations of the spec +360 */ +361 var it = function(desc, func) { +362 return jasmine.getEnv().it(desc, func); +363 }; +364 +365 /** +366 * Creates a <em>disabled</em> Jasmine spec. +367 * +368 * A convenience method that allows existing specs to be disabled temporarily during development. +369 * +370 * @param {String} desc description of this specification +371 * @param {Function} func defines the preconditions and expectations of the spec +372 */ +373 var xit = function(desc, func) { +374 return jasmine.getEnv().xit(desc, func); +375 }; +376 +377 /** +378 * Starts a chain for a Jasmine expectation. +379 * +380 * It is passed an Object that is the actual value and should chain to one of the many +381 * jasmine.Matchers functions. +382 * +383 * @param {Object} actual Actual value to test against and expected value +384 */ +385 var expect = function(actual) { +386 return jasmine.getEnv().currentSpec.expect(actual); +387 }; +388 +389 /** +390 * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. +391 * +392 * @param {Function} func Function that defines part of a jasmine spec. +393 */ +394 var runs = function(func) { +395 jasmine.getEnv().currentSpec.runs(func); +396 }; +397 +398 /** +399 * Waits for a timeout before moving to the next runs()-defined block. +400 * @param {Number} timeout +401 */ +402 var waits = function(timeout) { +403 jasmine.getEnv().currentSpec.waits(timeout); +404 }; +405 +406 /** +407 * Waits for the latchFunction to return true before proceeding to the next runs()-defined block. +408 * +409 * @param {Number} timeout +410 * @param {Function} latchFunction +411 * @param {String} message +412 */ +413 var waitsFor = function(timeout, latchFunction, message) { +414 jasmine.getEnv().currentSpec.waitsFor(timeout, latchFunction, message); +415 }; +416 +417 /** +418 * A function that is called before each spec in a suite. +419 * +420 * Used for spec setup, including validating assumptions. +421 * +422 * @param {Function} beforeEachFunction +423 */ +424 var beforeEach = function(beforeEachFunction) { +425 jasmine.getEnv().beforeEach(beforeEachFunction); +426 }; +427 +428 /** +429 * A function that is called after each spec in a suite. +430 * +431 * Used for restoring any state that is hijacked during spec execution. +432 * +433 * @param {Function} afterEachFunction +434 */ +435 var afterEach = function(afterEachFunction) { +436 jasmine.getEnv().afterEach(afterEachFunction); +437 }; +438 +439 /** +440 * Defines a suite of specifications. 441 * -442 * @example -443 * // TODO: a simple suite -444 * -445 * // TODO: a simple suite with a nested describe block -446 * -447 * @param {String} description A string, usually the class under test. -448 * @param {Function} specDefinitions function that defines several specs. -449 */ -450 var describe = function(description, specDefinitions) { -451 return jasmine.getEnv().describe(description, specDefinitions); -452 }; -453 -454 /** -455 * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. -456 * -457 * @param {String} description A string, usually the class under test. -458 * @param {Function} specDefinitions function that defines several specs. -459 */ -460 var xdescribe = function(description, specDefinitions) { -461 return jasmine.getEnv().xdescribe(description, specDefinitions); -462 }; -463 -464 -465 jasmine.XmlHttpRequest = XMLHttpRequest; -466 -467 // Provide the XMLHttpRequest class for IE 5.x-6.x: -468 if (typeof XMLHttpRequest == "undefined") jasmine.XmlHttpRequest = function() { -469 try { -470 return new ActiveXObject("Msxml2.XMLHTTP.6.0"); -471 } catch(e) { -472 } +442 * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared +443 * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization +444 * of setup in some tests. +445 * +446 * @example +447 * // TODO: a simple suite +448 * +449 * // TODO: a simple suite with a nested describe block +450 * +451 * @param {String} description A string, usually the class under test. +452 * @param {Function} specDefinitions function that defines several specs. +453 */ +454 var describe = function(description, specDefinitions) { +455 return jasmine.getEnv().describe(description, specDefinitions); +456 }; +457 +458 /** +459 * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. +460 * +461 * @param {String} description A string, usually the class under test. +462 * @param {Function} specDefinitions function that defines several specs. +463 */ +464 var xdescribe = function(description, specDefinitions) { +465 return jasmine.getEnv().xdescribe(description, specDefinitions); +466 }; +467 +468 +469 jasmine.XmlHttpRequest = XMLHttpRequest; +470 +471 // Provide the XMLHttpRequest class for IE 5.x-6.x: +472 if (typeof XMLHttpRequest == "undefined") jasmine.XmlHttpRequest = function() { 473 try { -474 return new ActiveXObject("Msxml2.XMLHTTP.3.0"); +474 return new ActiveXObject("Msxml2.XMLHTTP.6.0"); 475 } catch(e) { 476 } 477 try { -478 return new ActiveXObject("Msxml2.XMLHTTP"); +478 return new ActiveXObject("Msxml2.XMLHTTP.3.0"); 479 } catch(e) { 480 } 481 try { -482 return new ActiveXObject("Microsoft.XMLHTTP"); +482 return new ActiveXObject("Msxml2.XMLHTTP"); 483 } catch(e) { 484 } -485 throw new Error("This browser does not support XMLHttpRequest."); -486 }; -487 -488 /** -489 * Adds suite files to an HTML document so that they are executed, thus adding them to the current -490 * Jasmine environment. -491 * -492 * @param {String} url path to the file to include -493 * @param {Boolean} opt_global -494 */ -495 jasmine.include = function(url, opt_global) { -496 if (opt_global) { -497 document.write('<script type="text/javascript" src="' + url + '"></' + 'script>'); -498 } else { -499 var xhr; -500 try { -501 xhr = new jasmine.XmlHttpRequest(); -502 xhr.open("GET", url, false); -503 xhr.send(null); -504 } catch(e) { -505 throw new Error("couldn't fetch " + url + ": " + e); -506 } -507 -508 return eval(xhr.responseText); -509 } -510 }; -511 /** -512 * @namespace -513 */ -514 jasmine.util = {}; +485 try { +486 return new ActiveXObject("Microsoft.XMLHTTP"); +487 } catch(e) { +488 } +489 throw new Error("This browser does not support XMLHttpRequest."); +490 }; +491 +492 /** +493 * Adds suite files to an HTML document so that they are executed, thus adding them to the current +494 * Jasmine environment. +495 * +496 * @param {String} url path to the file to include +497 * @param {Boolean} opt_global +498 */ +499 jasmine.include = function(url, opt_global) { +500 if (opt_global) { +501 document.write('<script type="text/javascript" src="' + url + '"></' + 'script>'); +502 } else { +503 var xhr; +504 try { +505 xhr = new jasmine.XmlHttpRequest(); +506 xhr.open("GET", url, false); +507 xhr.send(null); +508 } catch(e) { +509 throw new Error("couldn't fetch " + url + ": " + e); +510 } +511 +512 return eval(xhr.responseText); +513 } +514 }; 515 -516 /** -517 * Declare that a child class inherite it's prototype from the parent class. -518 * -519 * @private -520 * @param {Function} childClass -521 * @param {Function} parentClass -522 */ -523 jasmine.util.inherit = function(childClass, parentClass) { -524 var subclass = function() { -525 }; -526 subclass.prototype = parentClass.prototype; -527 childClass.prototype = new subclass; -528 }; -529 -530 jasmine.util.formatException = function(e) { -531 var lineNumber; -532 if (e.line) { -533 lineNumber = e.line; -534 } -535 else if (e.lineNumber) { -536 lineNumber = e.lineNumber; -537 } -538 -539 var file; +516 jasmine.version_= { +517 "major": 0, +518 "minor": 9, +519 "build": 0, +520 "revision": 1251901478 +521 }; +522 /** +523 * @namespace +524 */ +525 jasmine.util = {}; +526 +527 /** +528 * Declare that a child class inherite it's prototype from the parent class. +529 * +530 * @private +531 * @param {Function} childClass +532 * @param {Function} parentClass +533 */ +534 jasmine.util.inherit = function(childClass, parentClass) { +535 var subclass = function() { +536 }; +537 subclass.prototype = parentClass.prototype; +538 childClass.prototype = new subclass; +539 }; 540 -541 if (e.sourceURL) { -542 file = e.sourceURL; -543 } -544 else if (e.fileName) { -545 file = e.fileName; -546 } -547 -548 var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); +541 jasmine.util.formatException = function(e) { +542 var lineNumber; +543 if (e.line) { +544 lineNumber = e.line; +545 } +546 else if (e.lineNumber) { +547 lineNumber = e.lineNumber; +548 } 549 -550 if (file && lineNumber) { -551 message += ' in ' + file + ' (line ' + lineNumber + ')'; -552 } -553 -554 return message; -555 }; -556 -557 jasmine.util.htmlEscape = function(str) { -558 if (!str) return str; -559 return str.replace(/&/g, '&') -560 .replace(/</g, '<') -561 .replace(/>/g, '>'); -562 }; -563 -564 jasmine.util.argsToArray = function(args) { -565 var arrayOfArgs = []; -566 for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); -567 return arrayOfArgs; -568 }; -569 -570 /** -571 * Environment for Jasmine -572 * -573 * @constructor -574 */ -575 jasmine.Env = function() { -576 this.currentSpec = null; -577 this.currentSuite = null; -578 this.currentRunner = new jasmine.Runner(this); -579 this.currentlyRunningTests = false; +550 var file; +551 +552 if (e.sourceURL) { +553 file = e.sourceURL; +554 } +555 else if (e.fileName) { +556 file = e.fileName; +557 } +558 +559 var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); +560 +561 if (file && lineNumber) { +562 message += ' in ' + file + ' (line ' + lineNumber + ')'; +563 } +564 +565 return message; +566 }; +567 +568 jasmine.util.htmlEscape = function(str) { +569 if (!str) return str; +570 return str.replace(/&/g, '&') +571 .replace(/</g, '<') +572 .replace(/>/g, '>'); +573 }; +574 +575 jasmine.util.argsToArray = function(args) { +576 var arrayOfArgs = []; +577 for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); +578 return arrayOfArgs; +579 }; 580 -581 this.reporter = new jasmine.MultiReporter(); -582 -583 this.updateInterval = 0; -584 this.lastUpdate = 0; -585 this.specFilter = function() { -586 return true; -587 }; -588 -589 this.nextSpecId_ = 0; -590 this.equalityTesters_ = []; -591 }; -592 +581 /** +582 * Environment for Jasmine +583 * +584 * @constructor +585 */ +586 jasmine.Env = function() { +587 this.currentSpec = null; +588 this.currentSuite = null; +589 this.currentRunner = new jasmine.Runner(this); +590 this.currentlyRunningTests = false; +591 +592 this.reporter = new jasmine.MultiReporter(); 593 -594 jasmine.Env.prototype.setTimeout = jasmine.setTimeout; -595 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; -596 jasmine.Env.prototype.setInterval = jasmine.setInterval; -597 jasmine.Env.prototype.clearInterval = jasmine.clearInterval; -598 -599 /** -600 * Register a reporter to receive status updates from Jasmine. -601 * @param {jasmine.Reporter} reporter An object which will receive status updates. -602 */ -603 jasmine.Env.prototype.addReporter = function(reporter) { -604 this.reporter.addReporter(reporter); -605 }; -606 -607 jasmine.Env.prototype.execute = function() { -608 this.currentRunner.execute(); -609 }; +594 this.updateInterval = 0; +595 this.lastUpdate = 0; +596 this.specFilter = function() { +597 return true; +598 }; +599 +600 this.nextSpecId_ = 0; +601 this.nextSuiteId_ = 0; +602 this.equalityTesters_ = []; +603 }; +604 +605 +606 jasmine.Env.prototype.setTimeout = jasmine.setTimeout; +607 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; +608 jasmine.Env.prototype.setInterval = jasmine.setInterval; +609 jasmine.Env.prototype.clearInterval = jasmine.clearInterval; 610 -611 jasmine.Env.prototype.describe = function(description, specDefinitions) { -612 var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); -613 -614 var parentSuite = this.currentSuite; -615 if (parentSuite) { -616 parentSuite.specs.push(suite); -617 } else { -618 this.currentRunner.suites.push(suite); -619 } -620 -621 this.currentSuite = suite; -622 -623 specDefinitions.call(suite); -624 -625 this.currentSuite = parentSuite; +611 jasmine.Env.prototype.version = function () { +612 if (jasmine.version_) { +613 return jasmine.version_; +614 } else { +615 throw new Error('Version not set'); +616 } +617 }; +618 +619 /** +620 * Register a reporter to receive status updates from Jasmine. +621 * @param {jasmine.Reporter} reporter An object which will receive status updates. +622 */ +623 jasmine.Env.prototype.addReporter = function(reporter) { +624 this.reporter.addReporter(reporter); +625 }; 626 -627 return suite; -628 }; -629 -630 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { -631 this.currentSuite.beforeEach(beforeEachFunction); -632 }; +627 jasmine.Env.prototype.execute = function() { +628 this.currentRunner.execute(); +629 }; +630 +631 jasmine.Env.prototype.describe = function(description, specDefinitions) { +632 var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); 633 -634 jasmine.Env.prototype.afterEach = function(afterEachFunction) { -635 this.currentSuite.afterEach(afterEachFunction); -636 }; -637 -638 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { -639 return { -640 execute: function() { -641 } -642 }; -643 }; +634 var parentSuite = this.currentSuite; +635 if (parentSuite) { +636 parentSuite.add(suite); +637 } else { +638 this.currentRunner.add(suite); +639 } +640 +641 this.currentSuite = suite; +642 +643 specDefinitions.call(suite); 644 -645 jasmine.Env.prototype.it = function(description, func) { -646 var spec = new jasmine.Spec(this, this.currentSuite, description); -647 this.currentSuite.specs.push(spec); -648 this.currentSpec = spec; +645 this.currentSuite = parentSuite; +646 +647 return suite; +648 }; 649 -650 if (func) { -651 spec.addToQueue(func); -652 } +650 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { +651 this.currentSuite.beforeEach(beforeEachFunction); +652 }; 653 -654 return spec; -655 }; -656 -657 jasmine.Env.prototype.xit = function(desc, func) { -658 return { -659 id: this.nextSpecId_++, -660 runs: function() { +654 jasmine.Env.prototype.afterEach = function(afterEachFunction) { +655 this.currentSuite.afterEach(afterEachFunction); +656 }; +657 +658 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { +659 return { +660 execute: function() { 661 } 662 }; 663 }; 664 -665 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { -666 if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { -667 return true; -668 } +665 jasmine.Env.prototype.it = function(description, func) { +666 var spec = new jasmine.Spec(this, this.currentSuite, description); +667 this.currentSuite.add(spec); +668 this.currentSpec = spec; 669 -670 a.__Jasmine_been_here_before__ = b; -671 b.__Jasmine_been_here_before__ = a; -672 -673 var hasKey = function(obj, keyName) { -674 return obj != null && obj[keyName] !== undefined; -675 }; +670 if (func) { +671 spec.runs(func); +672 } +673 +674 return spec; +675 }; 676 -677 for (var property in b) { -678 if (!hasKey(a, property) && hasKey(b, property)) { -679 mismatchKeys.push("expected has key '" + property + "', but missing from <b>actual</b>."); -680 } -681 } -682 for (property in a) { -683 if (!hasKey(b, property) && hasKey(a, property)) { -684 mismatchKeys.push("<b>expected</b> missing key '" + property + "', but present in actual."); -685 } -686 } -687 for (property in b) { -688 if (property == '__Jasmine_been_here_before__') continue; -689 if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { -690 mismatchValues.push("'" + property + "' was<br /><br />'" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "'<br /><br />in expected, but was<br /><br />'" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "'<br /><br />in actual.<br />"); -691 } -692 } -693 -694 if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { -695 mismatchValues.push("arrays were not the same length"); -696 } -697 -698 delete a.__Jasmine_been_here_before__; -699 delete b.__Jasmine_been_here_before__; -700 return (mismatchKeys.length == 0 && mismatchValues.length == 0); -701 }; -702 -703 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { -704 mismatchKeys = mismatchKeys || []; -705 mismatchValues = mismatchValues || []; -706 -707 if (a === b) return true; -708 -709 if (a === undefined || a === null || b === undefined || b === null) { -710 return (a == undefined && b == undefined); -711 } -712 -713 if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { -714 return a === b; -715 } -716 -717 if (a instanceof Date && b instanceof Date) { -718 return a.getTime() == b.getTime(); -719 } -720 -721 if (a instanceof jasmine.Matchers.Any) { -722 return a.matches(b); -723 } -724 -725 if (b instanceof jasmine.Matchers.Any) { -726 return b.matches(a); -727 } +677 jasmine.Env.prototype.xit = function(desc, func) { +678 return { +679 id: this.nextSpecId_++, +680 runs: function() { +681 } +682 }; +683 }; +684 +685 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { +686 if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { +687 return true; +688 } +689 +690 a.__Jasmine_been_here_before__ = b; +691 b.__Jasmine_been_here_before__ = a; +692 +693 var hasKey = function(obj, keyName) { +694 return obj != null && obj[keyName] !== undefined; +695 }; +696 +697 for (var property in b) { +698 if (!hasKey(a, property) && hasKey(b, property)) { +699 mismatchKeys.push("expected has key '" + property + "', but missing from <b>actual</b>."); +700 } +701 } +702 for (property in a) { +703 if (!hasKey(b, property) && hasKey(a, property)) { +704 mismatchKeys.push("<b>expected</b> missing key '" + property + "', but present in actual."); +705 } +706 } +707 for (property in b) { +708 if (property == '__Jasmine_been_here_before__') continue; +709 if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { +710 mismatchValues.push("'" + property + "' was<br /><br />'" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "'<br /><br />in expected, but was<br /><br />'" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "'<br /><br />in actual.<br />"); +711 } +712 } +713 +714 if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { +715 mismatchValues.push("arrays were not the same length"); +716 } +717 +718 delete a.__Jasmine_been_here_before__; +719 delete b.__Jasmine_been_here_before__; +720 return (mismatchKeys.length == 0 && mismatchValues.length == 0); +721 }; +722 +723 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { +724 mismatchKeys = mismatchKeys || []; +725 mismatchValues = mismatchValues || []; +726 +727 if (a === b) return true; 728 -729 if (typeof a === "object" && typeof b === "object") { -730 return this.compareObjects_(a, b, mismatchKeys, mismatchValues); +729 if (a === undefined || a === null || b === undefined || b === null) { +730 return (a == undefined && b == undefined); 731 } 732 -733 for (var i = 0; i < this.equalityTesters_.length; i++) { -734 var equalityTester = this.equalityTesters_[i]; -735 var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); -736 if (result !== undefined) return result; -737 } -738 -739 //Straight check -740 return (a === b); -741 }; -742 -743 jasmine.Env.prototype.contains_ = function(haystack, needle) { -744 if (jasmine.isArray_(haystack)) { -745 for (var i = 0; i < haystack.length; i++) { -746 if (this.equals_(haystack[i], needle)) return true; -747 } -748 return false; -749 } -750 return haystack.indexOf(needle) >= 0; -751 }; +733 if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { +734 return a === b; +735 } +736 +737 if (a instanceof Date && b instanceof Date) { +738 return a.getTime() == b.getTime(); +739 } +740 +741 if (a instanceof jasmine.Matchers.Any) { +742 return a.matches(b); +743 } +744 +745 if (b instanceof jasmine.Matchers.Any) { +746 return b.matches(a); +747 } +748 +749 if (typeof a === "object" && typeof b === "object") { +750 return this.compareObjects_(a, b, mismatchKeys, mismatchValues); +751 } 752 -753 jasmine.Env.prototype.addEqualityTester = function(equalityTester) { -754 this.equalityTesters_.push(equalityTester); -755 }; -756 /** -757 * base for Runner & Suite: allows for a queue of functions to get executed, allowing for -758 * any one action to complete, including asynchronous calls, before going to the next -759 * action. -760 * -761 * @constructor -762 * @param {jasmine.Env} env -763 */ -764 jasmine.ActionCollection = function(env) { -765 this.env = env; -766 this.actions = []; -767 this.index = 0; -768 this.finished = false; -769 }; -770 -771 /** -772 * Marks the collection as done & calls the finish callback, if there is one -773 */ -774 jasmine.ActionCollection.prototype.finish = function() { -775 if (this.finishCallback) { -776 this.finishCallback(); -777 } -778 this.finished = true; -779 }; -780 -781 /** -782 * Starts executing the queue of functions/actions. -783 */ -784 jasmine.ActionCollection.prototype.execute = function() { -785 if (this.actions.length > 0) { -786 this.next(); -787 } -788 }; -789 -790 /** -791 * Gets the current action. -792 */ -793 jasmine.ActionCollection.prototype.getCurrentAction = function() { -794 return this.actions[this.index]; -795 }; -796 -797 /** -798 * Executes the next queued function/action. If there are no more in the queue, calls #finish. -799 */ -800 jasmine.ActionCollection.prototype.next = function() { -801 if (this.index >= this.actions.length) { -802 this.finish(); -803 return; -804 } -805 -806 var currentAction = this.getCurrentAction(); -807 -808 currentAction.execute(this); -809 -810 if (currentAction.afterCallbacks) { -811 for (var i = 0; i < currentAction.afterCallbacks.length; i++) { -812 try { -813 currentAction.afterCallbacks[i](); -814 } catch (e) { -815 alert(e); -816 } -817 } -818 } -819 -820 this.waitForDone(currentAction); -821 }; -822 -823 jasmine.ActionCollection.prototype.waitForDone = function(action) { -824 var self = this; -825 var afterExecute = function afterExecute() { -826 self.index++; -827 self.next(); -828 }; -829 -830 if (action.finished) { -831 var now = new Date().getTime(); -832 if (this.env.updateInterval && now - this.env.lastUpdate > this.env.updateInterval) { -833 this.env.lastUpdate = now; -834 this.env.setTimeout(afterExecute, 0); -835 } else { -836 afterExecute(); -837 } -838 return; -839 } -840 -841 var id = this.env.setInterval(function() { -842 if (action.finished) { -843 self.env.clearInterval(id); -844 afterExecute(); -845 } -846 }, 150); +753 for (var i = 0; i < this.equalityTesters_.length; i++) { +754 var equalityTester = this.equalityTesters_[i]; +755 var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); +756 if (result !== undefined) return result; +757 } +758 +759 //Straight check +760 return (a === b); +761 }; +762 +763 jasmine.Env.prototype.contains_ = function(haystack, needle) { +764 if (jasmine.isArray_(haystack)) { +765 for (var i = 0; i < haystack.length; i++) { +766 if (this.equals_(haystack[i], needle)) return true; +767 } +768 return false; +769 } +770 return haystack.indexOf(needle) >= 0; +771 }; +772 +773 jasmine.Env.prototype.addEqualityTester = function(equalityTester) { +774 this.equalityTesters_.push(equalityTester); +775 }; +776 /** No-op base class for Jasmine reporters. +777 * +778 * @constructor +779 */ +780 jasmine.Reporter = function() { +781 }; +782 +783 //noinspection JSUnusedLocalSymbols +784 jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { +785 }; +786 +787 //noinspection JSUnusedLocalSymbols +788 jasmine.Reporter.prototype.reportRunnerResults = function(runner) { +789 }; +790 +791 //noinspection JSUnusedLocalSymbols +792 jasmine.Reporter.prototype.reportSuiteResults = function(suite) { +793 }; +794 +795 //noinspection JSUnusedLocalSymbols +796 jasmine.Reporter.prototype.reportSpecResults = function(spec) { +797 }; +798 +799 //noinspection JSUnusedLocalSymbols +800 jasmine.Reporter.prototype.log = function(str) { +801 }; +802 +803 /** +804 * Blocks are functions with executable code that make up a spec. +805 * +806 * @constructor +807 * @param {jasmine.Env} env +808 * @param {Function} func +809 * @param {jasmine.Spec} spec +810 */ +811 jasmine.Block = function(env, func, spec) { +812 this.env = env; +813 this.func = func; +814 this.spec = spec; +815 }; +816 +817 jasmine.Block.prototype.execute = function(onComplete) { +818 try { +819 this.func.apply(this.spec); +820 } catch (e) { +821 this.fail(e); +822 } +823 onComplete(); +824 }; +825 +826 jasmine.Block.prototype.fail = function(e) { +827 this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +828 }; +829 /** JavaScript API reporter. +830 * +831 * @constructor +832 */ +833 jasmine.JsApiReporter = function() { +834 this.started = false; +835 this.finished = false; +836 this.suites = []; +837 this.results = {}; +838 }; +839 +840 jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { +841 this.started = true; +842 var suites = runner.getAllSuites(); +843 for (var i = 0; i < suites.length; i++) { +844 var suite = suites[i]; +845 this.suites.push(this.summarize_(suite)); +846 } 847 }; -848 /** No-op base class for Jasmine reporters. -849 * -850 * @constructor -851 */ -852 jasmine.Reporter = function() { -853 }; -854 -855 //noinspection JSUnusedLocalSymbols -856 jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { -857 }; -858 -859 //noinspection JSUnusedLocalSymbols -860 jasmine.Reporter.prototype.reportRunnerResults = function(runner) { -861 }; -862 -863 //noinspection JSUnusedLocalSymbols -864 jasmine.Reporter.prototype.reportSuiteResults = function(suite) { -865 }; -866 -867 //noinspection JSUnusedLocalSymbols -868 jasmine.Reporter.prototype.reportSpecResults = function(spec) { +848 +849 jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { +850 var isSuite = suiteOrSpec instanceof jasmine.Suite +851 var summary = { +852 id: suiteOrSpec.id, +853 name: suiteOrSpec.description, +854 type: isSuite ? 'suite' : 'spec', +855 children: [] +856 }; +857 if (isSuite) { +858 var specs = suiteOrSpec.specs(); +859 for (var i = 0; i < specs.length; i++) { +860 summary.children.push(this.summarize_(specs[i])); +861 } +862 } +863 return summary; +864 }; +865 +866 //noinspection JSUnusedLocalSymbols +867 jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { +868 this.finished = true; 869 }; 870 871 //noinspection JSUnusedLocalSymbols -872 jasmine.Reporter.prototype.log = function (str) { +872 jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { 873 }; 874 -875 jasmine.Matchers = function(env, actual, results) { -876 this.env = env; -877 this.actual = actual; -878 this.passing_message = 'Passed.'; -879 this.results = results || new jasmine.NestedResults(); -880 }; -881 -882 jasmine.Matchers.pp = function(str) { -883 return jasmine.util.htmlEscape(jasmine.pp(str)); -884 }; -885 -886 jasmine.Matchers.prototype.getResults = function() { -887 return this.results; -888 }; -889 -890 jasmine.Matchers.prototype.report = function(result, failing_message, details) { -891 this.results.addResult(new jasmine.ExpectationResult(result, result ? this.passing_message : failing_message, details)); -892 return result; -893 }; -894 -895 /** -896 * Matcher that compares the actual to the expected using ===. -897 * -898 * @param expected -899 */ -900 jasmine.Matchers.prototype.toBe = function(expected) { -901 return this.report(this.actual === expected, 'Expected<br /><br />' + jasmine.Matchers.pp(expected) -902 + '<br /><br />to be the same object as<br /><br />' + jasmine.Matchers.pp(this.actual) -903 + '<br />'); -904 }; -905 -906 /** -907 * Matcher that compares the actual to the expected using !== -908 * @param expected -909 */ -910 jasmine.Matchers.prototype.toNotBe = function(expected) { -911 return this.report(this.actual !== expected, 'Expected<br /><br />' + jasmine.Matchers.pp(expected) -912 + '<br /><br />to be a different object from actual, but they were the same.'); -913 }; -914 -915 /** -916 * Matcher that compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. -917 * -918 * @param expected -919 */ -920 jasmine.Matchers.prototype.toEqual = function(expected) { -921 var mismatchKeys = []; -922 var mismatchValues = []; -923 -924 var formatMismatches = function(name, array) { -925 if (array.length == 0) return ''; -926 var errorOutput = '<br /><br />Different ' + name + ':<br />'; -927 for (var i = 0; i < array.length; i++) { -928 errorOutput += array[i] + '<br />'; -929 } -930 return errorOutput; -931 }; -932 -933 return this.report(this.env.equals_(this.actual, expected, mismatchKeys, mismatchValues), -934 'Expected<br /><br />' + jasmine.Matchers.pp(expected) -935 + '<br /><br />but got<br /><br />' + jasmine.Matchers.pp(this.actual) -936 + '<br />' -937 + formatMismatches('Keys', mismatchKeys) -938 + formatMismatches('Values', mismatchValues), { -939 matcherName: 'toEqual', expected: expected, actual: this.actual -940 }); -941 }; -942 /** @deprecated */ -943 jasmine.Matchers.prototype.should_equal = jasmine.Matchers.prototype.toEqual; +875 //noinspection JSUnusedLocalSymbols +876 jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { +877 this.results[spec.id] = { +878 messages: spec.results.getItems(), +879 result: spec.results.failedCount > 0 ? "failed" : "passed" +880 }; +881 }; +882 +883 //noinspection JSUnusedLocalSymbols +884 jasmine.JsApiReporter.prototype.log = function(str) { +885 }; +886 +887 jasmine.Matchers = function(env, actual, results) { +888 this.env = env; +889 this.actual = actual; +890 this.passing_message = 'Passed.'; +891 this.results = results || new jasmine.NestedResults(); +892 }; +893 +894 jasmine.Matchers.pp = function(str) { +895 return jasmine.util.htmlEscape(jasmine.pp(str)); +896 }; +897 +898 jasmine.Matchers.prototype.getResults = function() { +899 return this.results; +900 }; +901 +902 jasmine.Matchers.prototype.report = function(result, failing_message, details) { +903 this.results.addResult(new jasmine.ExpectationResult(result, result ? this.passing_message : failing_message, details)); +904 return result; +905 }; +906 +907 /** +908 * Matcher that compares the actual to the expected using ===. +909 * +910 * @param expected +911 */ +912 jasmine.Matchers.prototype.toBe = function(expected) { +913 return this.report(this.actual === expected, 'Expected<br /><br />' + jasmine.Matchers.pp(expected) +914 + '<br /><br />to be the same object as<br /><br />' + jasmine.Matchers.pp(this.actual) +915 + '<br />'); +916 }; +917 +918 /** +919 * Matcher that compares the actual to the expected using !== +920 * @param expected +921 */ +922 jasmine.Matchers.prototype.toNotBe = function(expected) { +923 return this.report(this.actual !== expected, 'Expected<br /><br />' + jasmine.Matchers.pp(expected) +924 + '<br /><br />to be a different object from actual, but they were the same.'); +925 }; +926 +927 /** +928 * Matcher that compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. +929 * +930 * @param expected +931 */ +932 jasmine.Matchers.prototype.toEqual = function(expected) { +933 var mismatchKeys = []; +934 var mismatchValues = []; +935 +936 var formatMismatches = function(name, array) { +937 if (array.length == 0) return ''; +938 var errorOutput = '<br /><br />Different ' + name + ':<br />'; +939 for (var i = 0; i < array.length; i++) { +940 errorOutput += array[i] + '<br />'; +941 } +942 return errorOutput; +943 }; 944 -945 /** -946 * Matcher that compares the actual to the expected using the ! of jasmine.Matchers.toEqual -947 * @param expected -948 */ -949 jasmine.Matchers.prototype.toNotEqual = function(expected) { -950 return this.report(!this.env.equals_(this.actual, expected), -951 'Expected ' + jasmine.Matchers.pp(expected) + ' to not equal ' + jasmine.Matchers.pp(this.actual) + ', but it does.'); -952 }; -953 /** @deprecated */ -954 jasmine.Matchers.prototype.should_not_equal = jasmine.Matchers.prototype.toNotEqual; -955 -956 /** -957 * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes -958 * a pattern or a String. -959 * -960 * @param reg_exp -961 */ -962 jasmine.Matchers.prototype.toMatch = function(reg_exp) { -963 return this.report((new RegExp(reg_exp).test(this.actual)), -964 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to match ' + reg_exp + '.'); -965 }; -966 /** @deprecated */ -967 jasmine.Matchers.prototype.should_match = jasmine.Matchers.prototype.toMatch; -968 -969 /** -970 * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch -971 * @param reg_exp -972 */ -973 jasmine.Matchers.prototype.toNotMatch = function(reg_exp) { -974 return this.report((!new RegExp(reg_exp).test(this.actual)), -975 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to not match ' + reg_exp + '.'); -976 }; -977 /** @deprecated */ -978 jasmine.Matchers.prototype.should_not_match = jasmine.Matchers.prototype.toNotMatch; -979 -980 /** -981 * Matcher that compares the acutal to undefined. -982 */ -983 jasmine.Matchers.prototype.toBeDefined = function() { -984 return this.report((this.actual !== undefined), -985 'Expected a value to be defined but it was undefined.'); -986 }; -987 /** @deprecated */ -988 jasmine.Matchers.prototype.should_be_defined = jasmine.Matchers.prototype.toBeDefined; -989 -990 /** -991 * Matcher that compares the actual to null. -992 * -993 */ -994 jasmine.Matchers.prototype.toBeNull = function() { -995 return this.report((this.actual === null), -996 'Expected a value to be null but it was ' + jasmine.Matchers.pp(this.actual) + '.'); -997 }; -998 /** @deprecated */ -999 jasmine.Matchers.prototype.should_be_null = jasmine.Matchers.prototype.toBeNull; -1000 -1001 /** -1002 * Matcher that boolean not-nots the actual. -1003 */ -1004 jasmine.Matchers.prototype.toBeTruthy = function() { -1005 return this.report(!!this.actual, -1006 'Expected a value to be truthy but it was ' + jasmine.Matchers.pp(this.actual) + '.'); -1007 }; -1008 /** @deprecated */ -1009 jasmine.Matchers.prototype.should_be_truthy = jasmine.Matchers.prototype.toBeTruthy; -1010 -1011 /** -1012 * Matcher that boolean nots the actual. -1013 */ -1014 jasmine.Matchers.prototype.toBeFalsy = function() { -1015 return this.report(!this.actual, -1016 'Expected a value to be falsy but it was ' + jasmine.Matchers.pp(this.actual) + '.'); -1017 }; -1018 /** @deprecated */ -1019 jasmine.Matchers.prototype.should_be_falsy = jasmine.Matchers.prototype.toBeFalsy; -1020 -1021 /** -1022 * Matcher that checks to see if the acutal, a Jasmine spy, was called. -1023 */ -1024 jasmine.Matchers.prototype.wasCalled = function() { -1025 if (!this.actual || !this.actual.isSpy) { -1026 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); -1027 } -1028 if (arguments.length > 0) { -1029 return this.report(false, 'wasCalled matcher does not take arguments'); -1030 } -1031 return this.report((this.actual.wasCalled), -1032 'Expected spy "' + this.actual.identity + '" to have been called, but it was not.'); -1033 }; -1034 /** @deprecated */ -1035 jasmine.Matchers.prototype.was_called = jasmine.Matchers.prototype.wasCalled; -1036 -1037 /** -1038 * Matcher that checks to see if the acutal, a Jasmine spy, was not called. -1039 */ -1040 jasmine.Matchers.prototype.wasNotCalled = function() { -1041 if (!this.actual || !this.actual.isSpy) { -1042 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); -1043 } -1044 return this.report((!this.actual.wasCalled), -1045 'Expected spy "' + this.actual.identity + '" to not have been called, but it was.'); -1046 }; -1047 /** @deprecated */ -1048 jasmine.Matchers.prototype.was_not_called = jasmine.Matchers.prototype.wasNotCalled; -1049 -1050 /** -1051 * Matcher that checks to see if the acutal, a Jasmine spy, was called with a set of parameters. -1052 * -1053 * @example -1054 * -1055 */ -1056 jasmine.Matchers.prototype.wasCalledWith = function() { -1057 if (!this.actual || !this.actual.isSpy) { -1058 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.', { -1059 matcherName: 'wasCalledWith' -1060 }); -1061 } -1062 -1063 var args = jasmine.util.argsToArray(arguments); -1064 -1065 return this.report(this.env.contains_(this.actual.argsForCall, args), -1066 'Expected ' + jasmine.Matchers.pp(this.actual.argsForCall) + ' to contain ' + jasmine.Matchers.pp(args) + ', but it does not.', { -1067 matcherName: 'wasCalledWith', expected: args, actual: this.actual.argsForCall -1068 }); -1069 }; -1070 -1071 /** -1072 * Matcher that checks that the expected item is an element in the actual Array. -1073 * -1074 * @param {Object} item -1075 */ -1076 jasmine.Matchers.prototype.toContain = function(item) { -1077 return this.report(this.env.contains_(this.actual, item), -1078 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to contain ' + jasmine.Matchers.pp(item) + ', but it does not.', { -1079 matcherName: 'toContain', expected: item, actual: this.actual +945 return this.report(this.env.equals_(this.actual, expected, mismatchKeys, mismatchValues), +946 'Expected<br /><br />' + jasmine.Matchers.pp(expected) +947 + '<br /><br />but got<br /><br />' + jasmine.Matchers.pp(this.actual) +948 + '<br />' +949 + formatMismatches('Keys', mismatchKeys) +950 + formatMismatches('Values', mismatchValues), { +951 matcherName: 'toEqual', expected: expected, actual: this.actual +952 }); +953 }; +954 /** @deprecated */ +955 jasmine.Matchers.prototype.should_equal = jasmine.Matchers.prototype.toEqual; +956 +957 /** +958 * Matcher that compares the actual to the expected using the ! of jasmine.Matchers.toEqual +959 * @param expected +960 */ +961 jasmine.Matchers.prototype.toNotEqual = function(expected) { +962 return this.report(!this.env.equals_(this.actual, expected), +963 'Expected ' + jasmine.Matchers.pp(expected) + ' to not equal ' + jasmine.Matchers.pp(this.actual) + ', but it does.'); +964 }; +965 /** @deprecated */ +966 jasmine.Matchers.prototype.should_not_equal = jasmine.Matchers.prototype.toNotEqual; +967 +968 /** +969 * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes +970 * a pattern or a String. +971 * +972 * @param reg_exp +973 */ +974 jasmine.Matchers.prototype.toMatch = function(reg_exp) { +975 return this.report((new RegExp(reg_exp).test(this.actual)), +976 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to match ' + reg_exp + '.'); +977 }; +978 /** @deprecated */ +979 jasmine.Matchers.prototype.should_match = jasmine.Matchers.prototype.toMatch; +980 +981 /** +982 * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch +983 * @param reg_exp +984 */ +985 jasmine.Matchers.prototype.toNotMatch = function(reg_exp) { +986 return this.report((!new RegExp(reg_exp).test(this.actual)), +987 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to not match ' + reg_exp + '.'); +988 }; +989 /** @deprecated */ +990 jasmine.Matchers.prototype.should_not_match = jasmine.Matchers.prototype.toNotMatch; +991 +992 /** +993 * Matcher that compares the acutal to undefined. +994 */ +995 jasmine.Matchers.prototype.toBeDefined = function() { +996 return this.report((this.actual !== undefined), +997 'Expected a value to be defined but it was undefined.'); +998 }; +999 /** @deprecated */ +1000 jasmine.Matchers.prototype.should_be_defined = jasmine.Matchers.prototype.toBeDefined; +1001 +1002 /** +1003 * Matcher that compares the actual to null. +1004 * +1005 */ +1006 jasmine.Matchers.prototype.toBeNull = function() { +1007 return this.report((this.actual === null), +1008 'Expected a value to be null but it was ' + jasmine.Matchers.pp(this.actual) + '.'); +1009 }; +1010 /** @deprecated */ +1011 jasmine.Matchers.prototype.should_be_null = jasmine.Matchers.prototype.toBeNull; +1012 +1013 /** +1014 * Matcher that boolean not-nots the actual. +1015 */ +1016 jasmine.Matchers.prototype.toBeTruthy = function() { +1017 return this.report(!!this.actual, +1018 'Expected a value to be truthy but it was ' + jasmine.Matchers.pp(this.actual) + '.'); +1019 }; +1020 /** @deprecated */ +1021 jasmine.Matchers.prototype.should_be_truthy = jasmine.Matchers.prototype.toBeTruthy; +1022 +1023 /** +1024 * Matcher that boolean nots the actual. +1025 */ +1026 jasmine.Matchers.prototype.toBeFalsy = function() { +1027 return this.report(!this.actual, +1028 'Expected a value to be falsy but it was ' + jasmine.Matchers.pp(this.actual) + '.'); +1029 }; +1030 /** @deprecated */ +1031 jasmine.Matchers.prototype.should_be_falsy = jasmine.Matchers.prototype.toBeFalsy; +1032 +1033 /** +1034 * Matcher that checks to see if the acutal, a Jasmine spy, was called. +1035 */ +1036 jasmine.Matchers.prototype.wasCalled = function() { +1037 if (!this.actual || !this.actual.isSpy) { +1038 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); +1039 } +1040 if (arguments.length > 0) { +1041 return this.report(false, 'wasCalled matcher does not take arguments'); +1042 } +1043 return this.report((this.actual.wasCalled), +1044 'Expected spy "' + this.actual.identity + '" to have been called, but it was not.'); +1045 }; +1046 /** @deprecated */ +1047 jasmine.Matchers.prototype.was_called = jasmine.Matchers.prototype.wasCalled; +1048 +1049 /** +1050 * Matcher that checks to see if the acutal, a Jasmine spy, was not called. +1051 */ +1052 jasmine.Matchers.prototype.wasNotCalled = function() { +1053 if (!this.actual || !this.actual.isSpy) { +1054 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); +1055 } +1056 return this.report((!this.actual.wasCalled), +1057 'Expected spy "' + this.actual.identity + '" to not have been called, but it was.'); +1058 }; +1059 /** @deprecated */ +1060 jasmine.Matchers.prototype.was_not_called = jasmine.Matchers.prototype.wasNotCalled; +1061 +1062 /** +1063 * Matcher that checks to see if the acutal, a Jasmine spy, was called with a set of parameters. +1064 * +1065 * @example +1066 * +1067 */ +1068 jasmine.Matchers.prototype.wasCalledWith = function() { +1069 if (!this.actual || !this.actual.isSpy) { +1070 return this.report(false, 'Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.', { +1071 matcherName: 'wasCalledWith' +1072 }); +1073 } +1074 +1075 var args = jasmine.util.argsToArray(arguments); +1076 +1077 return this.report(this.env.contains_(this.actual.argsForCall, args), +1078 'Expected ' + jasmine.Matchers.pp(this.actual.argsForCall) + ' to contain ' + jasmine.Matchers.pp(args) + ', but it does not.', { +1079 matcherName: 'wasCalledWith', expected: args, actual: this.actual.argsForCall 1080 }); 1081 }; 1082 1083 /** -1084 * Matcher that checks that the expected item is NOT an element in the actual Array. +1084 * Matcher that checks that the expected item is an element in the actual Array. 1085 * 1086 * @param {Object} item 1087 */ -1088 jasmine.Matchers.prototype.toNotContain = function(item) { -1089 return this.report(!this.env.contains_(this.actual, item), -1090 'Expected ' + jasmine.Matchers.pp(this.actual) + ' not to contain ' + jasmine.Matchers.pp(item) + ', but it does.'); -1091 }; -1092 -1093 /** -1094 * Matcher that checks that the expected exception was thrown by the actual. -1095 * -1096 * @param {String} expectedException -1097 */ -1098 jasmine.Matchers.prototype.toThrow = function(expectedException) { -1099 var exception = null; -1100 try { -1101 this.actual(); -1102 } catch (e) { -1103 exception = e; -1104 } -1105 if (expectedException !== undefined) { -1106 if (exception == null) { -1107 return this.report(false, "Expected function to throw " + jasmine.Matchers.pp(expectedException) + ", but it did not."); -1108 } -1109 return this.report( -1110 this.env.equals_( -1111 exception.message || exception, -1112 expectedException.message || expectedException), -1113 "Expected function to throw " + jasmine.Matchers.pp(expectedException) + ", but it threw " + jasmine.Matchers.pp(exception) + "."); -1114 } else { -1115 return this.report(exception != null, "Expected function to throw an exception, but it did not."); -1116 } -1117 }; -1118 -1119 jasmine.Matchers.Any = function(expectedClass) { -1120 this.expectedClass = expectedClass; -1121 }; -1122 -1123 jasmine.Matchers.Any.prototype.matches = function(other) { -1124 if (this.expectedClass == String) { -1125 return typeof other == 'string' || other instanceof String; +1088 jasmine.Matchers.prototype.toContain = function(item) { +1089 return this.report(this.env.contains_(this.actual, item), +1090 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to contain ' + jasmine.Matchers.pp(item) + ', but it does not.', { +1091 matcherName: 'toContain', expected: item, actual: this.actual +1092 }); +1093 }; +1094 +1095 /** +1096 * Matcher that checks that the expected item is NOT an element in the actual Array. +1097 * +1098 * @param {Object} item +1099 */ +1100 jasmine.Matchers.prototype.toNotContain = function(item) { +1101 return this.report(!this.env.contains_(this.actual, item), +1102 'Expected ' + jasmine.Matchers.pp(this.actual) + ' not to contain ' + jasmine.Matchers.pp(item) + ', but it does.'); +1103 }; +1104 +1105 jasmine.Matchers.prototype.toBeLessThan = function(expected) { +1106 return this.report(this.actual < expected, +1107 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to be less than ' + jasmine.Matchers.pp(expected) + ', but it was not.'); +1108 }; +1109 +1110 jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { +1111 return this.report(this.actual > expected, +1112 'Expected ' + jasmine.Matchers.pp(this.actual) + ' to be greater than ' + jasmine.Matchers.pp(expected) + ', but it was not.'); +1113 }; +1114 +1115 /** +1116 * Matcher that checks that the expected exception was thrown by the actual. +1117 * +1118 * @param {String} expectedException +1119 */ +1120 jasmine.Matchers.prototype.toThrow = function(expectedException) { +1121 var exception = null; +1122 try { +1123 this.actual(); +1124 } catch (e) { +1125 exception = e; 1126 } -1127 -1128 if (this.expectedClass == Number) { -1129 return typeof other == 'number' || other instanceof Number; -1130 } -1131 -1132 if (this.expectedClass == Function) { -1133 return typeof other == 'function' || other instanceof Function; -1134 } -1135 -1136 if (this.expectedClass == Object) { -1137 return typeof other == 'object'; +1127 if (expectedException !== undefined) { +1128 if (exception == null) { +1129 return this.report(false, "Expected function to throw " + jasmine.Matchers.pp(expectedException) + ", but it did not."); +1130 } +1131 return this.report( +1132 this.env.equals_( +1133 exception.message || exception, +1134 expectedException.message || expectedException), +1135 "Expected function to throw " + jasmine.Matchers.pp(expectedException) + ", but it threw " + jasmine.Matchers.pp(exception) + "."); +1136 } else { +1137 return this.report(exception != null, "Expected function to throw an exception, but it did not."); 1138 } -1139 -1140 return other instanceof this.expectedClass; -1141 }; -1142 -1143 jasmine.Matchers.Any.prototype.toString = function() { -1144 return '<jasmine.any(' + this.expectedClass + ')>'; -1145 }; -1146 -1147 // Mock setTimeout, clearTimeout -1148 // Contributed by Pivotal Computer Systems, www.pivotalsf.com -1149 -1150 jasmine.FakeTimer = function() { -1151 this.reset(); -1152 -1153 var self = this; -1154 self.setTimeout = function(funcToCall, millis) { -1155 self.timeoutsMade++; -1156 self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); -1157 return self.timeoutsMade; -1158 }; -1159 -1160 self.setInterval = function(funcToCall, millis) { -1161 self.timeoutsMade++; -1162 self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); -1163 return self.timeoutsMade; -1164 }; -1165 -1166 self.clearTimeout = function(timeoutKey) { -1167 self.scheduledFunctions[timeoutKey] = undefined; -1168 }; -1169 -1170 self.clearInterval = function(timeoutKey) { -1171 self.scheduledFunctions[timeoutKey] = undefined; -1172 }; -1173 -1174 }; -1175 -1176 jasmine.FakeTimer.prototype.reset = function() { -1177 this.timeoutsMade = 0; -1178 this.scheduledFunctions = {}; -1179 this.nowMillis = 0; -1180 }; -1181 -1182 jasmine.FakeTimer.prototype.tick = function(millis) { -1183 var oldMillis = this.nowMillis; -1184 var newMillis = oldMillis + millis; -1185 this.runFunctionsWithinRange(oldMillis, newMillis); -1186 this.nowMillis = newMillis; -1187 }; -1188 -1189 jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { -1190 var scheduledFunc; -1191 var funcsToRun = []; -1192 for (var timeoutKey in this.scheduledFunctions) { -1193 scheduledFunc = this.scheduledFunctions[timeoutKey]; -1194 if (scheduledFunc != undefined && -1195 scheduledFunc.runAtMillis >= oldMillis && -1196 scheduledFunc.runAtMillis <= nowMillis) { -1197 funcsToRun.push(scheduledFunc); -1198 this.scheduledFunctions[timeoutKey] = undefined; -1199 } -1200 } -1201 -1202 if (funcsToRun.length > 0) { -1203 funcsToRun.sort(function(a, b) { -1204 return a.runAtMillis - b.runAtMillis; -1205 }); -1206 for (var i = 0; i < funcsToRun.length; ++i) { -1207 try { -1208 var funcToRun = funcsToRun[i]; -1209 this.nowMillis = funcToRun.runAtMillis; -1210 funcToRun.funcToCall(); -1211 if (funcToRun.recurring) { -1212 this.scheduleFunction(funcToRun.timeoutKey, -1213 funcToRun.funcToCall, -1214 funcToRun.millis, -1215 true); -1216 } -1217 } catch(e) { -1218 } -1219 } -1220 this.runFunctionsWithinRange(oldMillis, nowMillis); -1221 } -1222 }; -1223 -1224 jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { -1225 this.scheduledFunctions[timeoutKey] = { -1226 runAtMillis: this.nowMillis + millis, -1227 funcToCall: funcToCall, -1228 recurring: recurring, -1229 timeoutKey: timeoutKey, -1230 millis: millis -1231 }; -1232 }; -1233 -1234 -1235 jasmine.Clock = { -1236 defaultFakeTimer: new jasmine.FakeTimer(), -1237 -1238 reset: function() { -1239 jasmine.Clock.assertInstalled(); -1240 jasmine.Clock.defaultFakeTimer.reset(); -1241 }, -1242 -1243 tick: function(millis) { -1244 jasmine.Clock.assertInstalled(); -1245 jasmine.Clock.defaultFakeTimer.tick(millis); -1246 }, -1247 -1248 runFunctionsWithinRange: function(oldMillis, nowMillis) { -1249 jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); -1250 }, -1251 -1252 scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { -1253 jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); -1254 }, -1255 -1256 useMock: function() { -1257 var spec = jasmine.getEnv().currentSpec; -1258 spec.after(jasmine.Clock.uninstallMock); -1259 -1260 jasmine.Clock.installMock(); -1261 }, -1262 -1263 installMock: function() { -1264 jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; -1265 }, -1266 -1267 uninstallMock: function() { -1268 jasmine.Clock.assertInstalled(); -1269 jasmine.Clock.installed = jasmine.Clock.real; -1270 }, -1271 -1272 real: { -1273 setTimeout: window.setTimeout, -1274 clearTimeout: window.clearTimeout, -1275 setInterval: window.setInterval, -1276 clearInterval: window.clearInterval -1277 }, -1278 -1279 assertInstalled: function() { -1280 if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) { -1281 throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); -1282 } -1283 }, -1284 -1285 installed: null -1286 }; -1287 jasmine.Clock.installed = jasmine.Clock.real; -1288 -1289 window.setTimeout = function(funcToCall, millis) { -1290 return jasmine.Clock.installed.setTimeout.apply(this, arguments); -1291 }; -1292 -1293 window.setInterval = function(funcToCall, millis) { -1294 return jasmine.Clock.installed.setInterval.apply(this, arguments); -1295 }; -1296 -1297 window.clearTimeout = function(timeoutKey) { -1298 return jasmine.Clock.installed.clearTimeout.apply(this, arguments); -1299 }; -1300 -1301 window.clearInterval = function(timeoutKey) { -1302 return jasmine.Clock.installed.clearInterval.apply(this, arguments); -1303 }; -1304 -1305 /** -1306 * @constructor -1307 */ -1308 jasmine.MultiReporter = function() { -1309 this.subReporters_ = []; -1310 }; -1311 jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); -1312 -1313 jasmine.MultiReporter.prototype.addReporter = function(reporter) { -1314 this.subReporters_.push(reporter); -1315 }; -1316 -1317 (function() { -1318 var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"]; -1319 for (var i = 0; i < functionNames.length; i++) { -1320 var functionName = functionNames[i]; -1321 jasmine.MultiReporter.prototype[functionName] = (function(functionName) { -1322 return function() { -1323 for (var j = 0; j < this.subReporters_.length; j++) { -1324 var subReporter = this.subReporters_[j]; -1325 if (subReporter[functionName]) { -1326 subReporter[functionName].apply(subReporter, arguments); -1327 } -1328 } -1329 }; -1330 })(functionName); -1331 } -1332 })(); -1333 /** -1334 * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults -1335 * -1336 * @constructor -1337 */ -1338 jasmine.NestedResults = function() { -1339 /** -1340 * The total count of results -1341 */ -1342 this.totalCount = 0; -1343 /** -1344 * Number of passed results -1345 */ -1346 this.passedCount = 0; -1347 /** -1348 * Number of failed results -1349 */ -1350 this.failedCount = 0; -1351 /** -1352 * Was this suite/spec skipped? -1353 */ -1354 this.skipped = false; -1355 /** -1356 * @ignore -1357 */ -1358 this.items_ = []; -1359 }; -1360 -1361 /** -1362 * Roll up the result counts. -1363 * -1364 * @param result -1365 */ -1366 jasmine.NestedResults.prototype.rollupCounts = function(result) { -1367 this.totalCount += result.totalCount; -1368 this.passedCount += result.passedCount; -1369 this.failedCount += result.failedCount; -1370 }; -1371 -1372 /** -1373 * Tracks a result's message. -1374 * @param message -1375 */ -1376 jasmine.NestedResults.prototype.log = function(message) { -1377 this.items_.push(new jasmine.MessageResult(message)); -1378 }; -1379 -1380 /** -1381 * Getter for the results: message & results. -1382 */ -1383 jasmine.NestedResults.prototype.getItems = function() { -1384 return this.items_; -1385 }; -1386 -1387 /** -1388 * Adds a result, tracking counts (total, passed, & failed) -1389 * @param {jasmine.ExpectationResult|jasmine.NestedResults} result -1390 */ -1391 jasmine.NestedResults.prototype.addResult = function(result) { -1392 if (result.type != 'MessageResult') { -1393 if (result.items_) { -1394 this.rollupCounts(result); -1395 } else { -1396 this.totalCount++; -1397 if (result.passed) { -1398 this.passedCount++; -1399 } else { -1400 this.failedCount++; -1401 } -1402 } -1403 } -1404 this.items_.push(result); -1405 }; -1406 -1407 /** -1408 * @returns {Boolean} True if <b>everything</b> below passed -1409 */ -1410 jasmine.NestedResults.prototype.passed = function() { -1411 return this.passedCount === this.totalCount; -1412 }; -1413 /** -1414 * Base class for pretty printing for expectation results. -1415 */ -1416 jasmine.PrettyPrinter = function() { -1417 this.ppNestLevel_ = 0; -1418 }; -1419 -1420 /** -1421 * Formats a value in a nice, human-readable string. -1422 * -1423 * @param value -1424 * @returns {String} -1425 */ -1426 jasmine.PrettyPrinter.prototype.format = function(value) { -1427 if (this.ppNestLevel_ > 40) { -1428 // return '(jasmine.pp nested too deeply!)'; -1429 throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); -1430 } -1431 -1432 this.ppNestLevel_++; -1433 try { -1434 if (value === undefined) { -1435 this.emitScalar('undefined'); -1436 } else if (value === null) { -1437 this.emitScalar('null'); -1438 } else if (value.navigator && value.frames && value.setTimeout) { -1439 this.emitScalar('<window>'); -1440 } else if (value instanceof jasmine.Matchers.Any) { -1441 this.emitScalar(value.toString()); -1442 } else if (typeof value === 'string') { -1443 this.emitScalar("'" + value + "'"); -1444 } else if (typeof value === 'function') { -1445 this.emitScalar('Function'); -1446 } else if (typeof value.nodeType === 'number') { -1447 this.emitScalar('HTMLNode'); -1448 } else if (value instanceof Date) { -1449 this.emitScalar('Date(' + value + ')'); -1450 } else if (value.__Jasmine_been_here_before__) { -1451 this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>'); -1452 } else if (jasmine.isArray_(value) || typeof value == 'object') { -1453 value.__Jasmine_been_here_before__ = true; -1454 if (jasmine.isArray_(value)) { -1455 this.emitArray(value); -1456 } else { -1457 this.emitObject(value); -1458 } -1459 delete value.__Jasmine_been_here_before__; -1460 } else { -1461 this.emitScalar(value.toString()); +1139 }; +1140 +1141 jasmine.Matchers.Any = function(expectedClass) { +1142 this.expectedClass = expectedClass; +1143 }; +1144 +1145 jasmine.Matchers.Any.prototype.matches = function(other) { +1146 if (this.expectedClass == String) { +1147 return typeof other == 'string' || other instanceof String; +1148 } +1149 +1150 if (this.expectedClass == Number) { +1151 return typeof other == 'number' || other instanceof Number; +1152 } +1153 +1154 if (this.expectedClass == Function) { +1155 return typeof other == 'function' || other instanceof Function; +1156 } +1157 +1158 if (this.expectedClass == Object) { +1159 return typeof other == 'object'; +1160 } +1161 +1162 return other instanceof this.expectedClass; +1163 }; +1164 +1165 jasmine.Matchers.Any.prototype.toString = function() { +1166 return '<jasmine.any(' + this.expectedClass + ')>'; +1167 }; +1168 +1169 /** +1170 * @constructor +1171 */ +1172 jasmine.MultiReporter = function() { +1173 this.subReporters_ = []; +1174 }; +1175 jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); +1176 +1177 jasmine.MultiReporter.prototype.addReporter = function(reporter) { +1178 this.subReporters_.push(reporter); +1179 }; +1180 +1181 (function() { +1182 var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"]; +1183 for (var i = 0; i < functionNames.length; i++) { +1184 var functionName = functionNames[i]; +1185 jasmine.MultiReporter.prototype[functionName] = (function(functionName) { +1186 return function() { +1187 for (var j = 0; j < this.subReporters_.length; j++) { +1188 var subReporter = this.subReporters_[j]; +1189 if (subReporter[functionName]) { +1190 subReporter[functionName].apply(subReporter, arguments); +1191 } +1192 } +1193 }; +1194 })(functionName); +1195 } +1196 })(); +1197 /** +1198 * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults +1199 * +1200 * @constructor +1201 */ +1202 jasmine.NestedResults = function() { +1203 /** +1204 * The total count of results +1205 */ +1206 this.totalCount = 0; +1207 /** +1208 * Number of passed results +1209 */ +1210 this.passedCount = 0; +1211 /** +1212 * Number of failed results +1213 */ +1214 this.failedCount = 0; +1215 /** +1216 * Was this suite/spec skipped? +1217 */ +1218 this.skipped = false; +1219 /** +1220 * @ignore +1221 */ +1222 this.items_ = []; +1223 }; +1224 +1225 /** +1226 * Roll up the result counts. +1227 * +1228 * @param result +1229 */ +1230 jasmine.NestedResults.prototype.rollupCounts = function(result) { +1231 this.totalCount += result.totalCount; +1232 this.passedCount += result.passedCount; +1233 this.failedCount += result.failedCount; +1234 }; +1235 +1236 /** +1237 * Tracks a result's message. +1238 * @param message +1239 */ +1240 jasmine.NestedResults.prototype.log = function(message) { +1241 this.items_.push(new jasmine.MessageResult(message)); +1242 }; +1243 +1244 /** +1245 * Getter for the results: message & results. +1246 */ +1247 jasmine.NestedResults.prototype.getItems = function() { +1248 return this.items_; +1249 }; +1250 +1251 /** +1252 * Adds a result, tracking counts (total, passed, & failed) +1253 * @param {jasmine.ExpectationResult|jasmine.NestedResults} result +1254 */ +1255 jasmine.NestedResults.prototype.addResult = function(result) { +1256 if (result.type != 'MessageResult') { +1257 if (result.items_) { +1258 this.rollupCounts(result); +1259 } else { +1260 this.totalCount++; +1261 if (result.passed()) { +1262 this.passedCount++; +1263 } else { +1264 this.failedCount++; +1265 } +1266 } +1267 } +1268 this.items_.push(result); +1269 }; +1270 +1271 /** +1272 * @returns {Boolean} True if <b>everything</b> below passed +1273 */ +1274 jasmine.NestedResults.prototype.passed = function() { +1275 return this.passedCount === this.totalCount; +1276 }; +1277 /** +1278 * Base class for pretty printing for expectation results. +1279 */ +1280 jasmine.PrettyPrinter = function() { +1281 this.ppNestLevel_ = 0; +1282 }; +1283 +1284 /** +1285 * Formats a value in a nice, human-readable string. +1286 * +1287 * @param value +1288 * @returns {String} +1289 */ +1290 jasmine.PrettyPrinter.prototype.format = function(value) { +1291 if (this.ppNestLevel_ > 40) { +1292 // return '(jasmine.pp nested too deeply!)'; +1293 throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); +1294 } +1295 +1296 this.ppNestLevel_++; +1297 try { +1298 if (value === undefined) { +1299 this.emitScalar('undefined'); +1300 } else if (value === null) { +1301 this.emitScalar('null'); +1302 } else if (value.navigator && value.frames && value.setTimeout) { +1303 this.emitScalar('<window>'); +1304 } else if (value instanceof jasmine.Matchers.Any) { +1305 this.emitScalar(value.toString()); +1306 } else if (typeof value === 'string') { +1307 this.emitString(value); +1308 } else if (typeof value === 'function') { +1309 this.emitScalar('Function'); +1310 } else if (typeof value.nodeType === 'number') { +1311 this.emitScalar('HTMLNode'); +1312 } else if (value instanceof Date) { +1313 this.emitScalar('Date(' + value + ')'); +1314 } else if (value.__Jasmine_been_here_before__) { +1315 this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>'); +1316 } else if (jasmine.isArray_(value) || typeof value == 'object') { +1317 value.__Jasmine_been_here_before__ = true; +1318 if (jasmine.isArray_(value)) { +1319 this.emitArray(value); +1320 } else { +1321 this.emitObject(value); +1322 } +1323 delete value.__Jasmine_been_here_before__; +1324 } else { +1325 this.emitScalar(value.toString()); +1326 } +1327 } finally { +1328 this.ppNestLevel_--; +1329 } +1330 }; +1331 +1332 jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { +1333 for (var property in obj) { +1334 if (property == '__Jasmine_been_here_before__') continue; +1335 fn(property, obj.__lookupGetter__(property) != null); +1336 } +1337 }; +1338 +1339 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; +1340 jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; +1341 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; +1342 jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; +1343 +1344 jasmine.StringPrettyPrinter = function() { +1345 jasmine.PrettyPrinter.call(this); +1346 +1347 this.string = ''; +1348 }; +1349 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); +1350 +1351 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { +1352 this.append(value); +1353 }; +1354 +1355 jasmine.StringPrettyPrinter.prototype.emitString = function(value) { +1356 this.append("'" + value + "'"); +1357 }; +1358 +1359 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { +1360 this.append('[ '); +1361 for (var i = 0; i < array.length; i++) { +1362 if (i > 0) { +1363 this.append(', '); +1364 } +1365 this.format(array[i]); +1366 } +1367 this.append(' ]'); +1368 }; +1369 +1370 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { +1371 var self = this; +1372 this.append('{ '); +1373 var first = true; +1374 +1375 this.iterateObject(obj, function(property, isGetter) { +1376 if (first) { +1377 first = false; +1378 } else { +1379 self.append(', '); +1380 } +1381 +1382 self.append(property); +1383 self.append(' : '); +1384 if (isGetter) { +1385 self.append('<getter>'); +1386 } else { +1387 self.format(obj[property]); +1388 } +1389 }); +1390 +1391 this.append(' }'); +1392 }; +1393 +1394 jasmine.StringPrettyPrinter.prototype.append = function(value) { +1395 this.string += value; +1396 }; +1397 jasmine.Queue = function(env) { +1398 this.env = env; +1399 this.blocks = []; +1400 this.running = false; +1401 this.index = 0; +1402 this.offset = 0; +1403 }; +1404 +1405 jasmine.Queue.prototype.addBefore = function (block) { +1406 this.blocks.unshift(block); +1407 }; +1408 +1409 jasmine.Queue.prototype.add = function(block) { +1410 this.blocks.push(block); +1411 }; +1412 +1413 jasmine.Queue.prototype.insertNext = function (block) { +1414 this.blocks.splice((this.index + this.offset + 1), 0, block); +1415 this.offset++; +1416 }; +1417 +1418 jasmine.Queue.prototype.start = function(onComplete) { +1419 var self = this; +1420 self.running = true; +1421 self.onComplete = onComplete; +1422 if (self.blocks[0]) { +1423 self.blocks[0].execute(function () { +1424 self._next(); +1425 }); +1426 } else { +1427 self.finish(); +1428 } +1429 }; +1430 +1431 jasmine.Queue.prototype.isRunning = function () { +1432 return this.running; +1433 }; +1434 +1435 jasmine.Queue.prototype._next = function () { +1436 var self = this; +1437 self.env.setTimeout(function () { +1438 self.offset = 0; +1439 self.index++; +1440 if (self.index < self.blocks.length) { +1441 self.blocks[self.index].execute(function () { +1442 self._next(); +1443 }); +1444 } else { +1445 self.finish(); +1446 } +1447 }, 0); +1448 }; +1449 +1450 jasmine.Queue.prototype.finish = function () { +1451 this.running = false; +1452 if (this.onComplete) { +1453 this.onComplete(); +1454 } +1455 }; +1456 +1457 jasmine.Queue.prototype.getResults = function () { +1458 var results = new jasmine.NestedResults(); +1459 for (var i = 0; i < this.blocks.length; i++) { +1460 if (this.blocks[i].getResults) { +1461 results.addResult(this.blocks[i].getResults()); 1462 } -1463 } finally { -1464 this.ppNestLevel_--; -1465 } -1466 }; +1463 } +1464 return results; +1465 }; +1466 1467 -1468 jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { -1469 for (var property in obj) { -1470 if (property == '__Jasmine_been_here_before__') continue; -1471 fn(property, obj.__lookupGetter__(property) != null); -1472 } -1473 }; -1474 -1475 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; -1476 jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; -1477 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; -1478 -1479 jasmine.StringPrettyPrinter = function() { -1480 jasmine.PrettyPrinter.call(this); -1481 -1482 this.string = ''; -1483 }; -1484 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); -1485 -1486 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { -1487 this.append(value); -1488 }; -1489 -1490 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { -1491 this.append('[ '); -1492 for (var i = 0; i < array.length; i++) { -1493 if (i > 0) { -1494 this.append(', '); +1468 /* JasmineReporters.reporter +1469 * Base object that will get called whenever a Spec, Suite, or Runner is done. It is up to +1470 * descendants of this object to do something with the results (see json_reporter.js) +1471 */ +1472 jasmine.Reporters = {}; +1473 +1474 jasmine.Reporters.reporter = function(callbacks) { +1475 var that = { +1476 callbacks: callbacks || {}, +1477 +1478 doCallback: function(callback, results) { +1479 if (callback) { +1480 callback(results); +1481 } +1482 }, +1483 +1484 reportRunnerResults: function(runner) { +1485 that.doCallback(that.callbacks.runnerCallback, runner); +1486 }, +1487 reportSuiteResults: function(suite) { +1488 that.doCallback(that.callbacks.suiteCallback, suite); +1489 }, +1490 reportSpecResults: function(spec) { +1491 that.doCallback(that.callbacks.specCallback, spec); +1492 }, +1493 log: function (str) { +1494 if (console && console.log) console.log(str); 1495 } -1496 this.format(array[i]); -1497 } -1498 this.append(' ]'); +1496 }; +1497 +1498 return that; 1499 }; 1500 -1501 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { -1502 var self = this; -1503 this.append('{ '); -1504 var first = true; -1505 -1506 this.iterateObject(obj, function(property, isGetter) { -1507 if (first) { -1508 first = false; -1509 } else { -1510 self.append(', '); -1511 } -1512 -1513 self.append(property); -1514 self.append(' : '); -1515 if (isGetter) { -1516 self.append('<getter>'); -1517 } else { -1518 self.format(obj[property]); -1519 } -1520 }); -1521 -1522 this.append(' }'); -1523 }; -1524 -1525 jasmine.StringPrettyPrinter.prototype.append = function(value) { -1526 this.string += value; -1527 }; -1528 /** -1529 * QueuedFunction is how ActionCollections' actions are implemented -1530 * -1531 * @constructor -1532 * @param {jasmine.Env} env -1533 * @param {Function} func -1534 * @param {Number} timeout -1535 * @param {Function} latchFunction -1536 * @param {jasmine.Spec} spec -1537 */ -1538 jasmine.QueuedFunction = function(env, func, timeout, latchFunction, spec) { -1539 this.env = env; -1540 this.func = func; -1541 this.timeout = timeout; -1542 this.latchFunction = latchFunction; -1543 this.spec = spec; -1544 -1545 this.totalTimeSpentWaitingForLatch = 0; -1546 this.latchTimeoutIncrement = 100; -1547 }; -1548 -1549 jasmine.QueuedFunction.prototype.next = function() { -1550 this.spec.finish(); // default value is to be done after one function -1551 }; -1552 -1553 jasmine.QueuedFunction.prototype.safeExecute = function() { -1554 this.env.reporter.log('>> Jasmine Running ' + this.spec.suite.description + ' ' + this.spec.description + '...'); -1555 -1556 try { -1557 this.func.apply(this.spec); -1558 } catch (e) { -1559 this.fail(e); -1560 } -1561 }; +1501 /** +1502 * Runner +1503 * +1504 * @constructor +1505 * @param {jasmine.Env} env +1506 */ +1507 jasmine.Runner = function(env) { +1508 var self = this; +1509 self.env = env; +1510 self.queue = new jasmine.Queue(env); +1511 self.suites = []; +1512 }; +1513 +1514 jasmine.Runner.prototype.execute = function() { +1515 var self = this; +1516 if (self.env.reporter.reportRunnerStarting) { +1517 self.env.reporter.reportRunnerStarting(this); +1518 } +1519 self.queue.start(function () { +1520 self.finishCallback(); +1521 }); +1522 }; +1523 +1524 jasmine.Runner.prototype.finishCallback = function() { +1525 this.env.reporter.reportRunnerResults(this); +1526 }; +1527 +1528 jasmine.Runner.prototype.addSuite = function(suite) { +1529 this.suites.push(suite); +1530 }; +1531 +1532 jasmine.Runner.prototype.add = function(block) { +1533 if (block instanceof jasmine.Suite) { +1534 this.addSuite(block); +1535 } +1536 this.queue.add(block); +1537 }; +1538 +1539 +1540 jasmine.Runner.prototype.getAllSuites = function() { +1541 return this.suites; +1542 }; +1543 +1544 jasmine.Runner.prototype.getResults = function() { +1545 return this.queue.getResults(); +1546 }; +1547 /** +1548 * Internal representation of a Jasmine specification, or test. +1549 * +1550 * @constructor +1551 * @param {jasmine.Env} env +1552 * @param {jasmine.Suite} suite +1553 * @param {String} description +1554 */ +1555 jasmine.Spec = function(env, suite, description) { +1556 var spec = this; +1557 spec.id = env.nextSpecId_++; +1558 spec.env = env; +1559 spec.suite = suite; +1560 spec.description = description; +1561 spec.queue = new jasmine.Queue(env); 1562 -1563 jasmine.QueuedFunction.prototype.execute = function() { -1564 var self = this; -1565 var executeNow = function() { -1566 self.safeExecute(); -1567 self.next(); -1568 }; -1569 -1570 var executeLater = function() { -1571 self.env.setTimeout(executeNow, self.timeout); -1572 }; -1573 -1574 var executeNowOrLater = function() { -1575 var latchFunctionResult; -1576 -1577 try { -1578 latchFunctionResult = self.latchFunction.apply(self.spec); -1579 } catch (e) { -1580 self.fail(e); -1581 self.next(); -1582 return; -1583 } +1563 spec.afterCallbacks = []; +1564 spec.spies_ = []; +1565 +1566 spec.results = new jasmine.NestedResults(); +1567 spec.results.description = description; +1568 spec.matchersClass = null; +1569 }; +1570 +1571 jasmine.Spec.prototype.getFullName = function() { +1572 return this.suite.getFullName() + ' ' + this.description + '.'; +1573 }; +1574 +1575 jasmine.Spec.prototype.getResults = function() { +1576 return this.results; +1577 }; +1578 +1579 jasmine.Spec.prototype.runs = function (func) { +1580 var block = new jasmine.Block(this.env, func, this); +1581 this.addToQueue(block); +1582 return this; +1583 }; 1584 -1585 if (latchFunctionResult) { -1586 executeNow(); -1587 } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { -1588 var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.latchFunction.description || 'something to happen'); -1589 self.fail({ -1590 name: 'timeout', -1591 message: message -1592 }); -1593 self.next(); -1594 } else { -1595 self.totalTimeSpentWaitingForLatch += self.latchTimeoutIncrement; -1596 self.env.setTimeout(executeNowOrLater, self.latchTimeoutIncrement); -1597 } -1598 }; -1599 -1600 if (this.latchFunction !== undefined) { -1601 executeNowOrLater(); -1602 } else if (this.timeout > 0) { -1603 executeLater(); -1604 } else { -1605 executeNow(); -1606 } -1607 }; -1608 -1609 jasmine.QueuedFunction.prototype.fail = function(e) { -1610 this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); -1611 }; -1612 /* JasmineReporters.reporter -1613 * Base object that will get called whenever a Spec, Suite, or Runner is done. It is up to -1614 * descendants of this object to do something with the results (see json_reporter.js) -1615 */ -1616 jasmine.Reporters = {}; -1617 -1618 jasmine.Reporters.reporter = function(callbacks) { -1619 var that = { -1620 callbacks: callbacks || {}, -1621 -1622 doCallback: function(callback, results) { -1623 if (callback) { -1624 callback(results); -1625 } -1626 }, +1585 jasmine.Spec.prototype.addToQueue = function (block) { +1586 if (this.queue.isRunning()) { +1587 this.queue.insertNext(block); +1588 } else { +1589 this.queue.add(block); +1590 } +1591 }; +1592 +1593 /** +1594 * @private +1595 * @deprecated +1596 */ +1597 jasmine.Spec.prototype.expects_that = function(actual) { +1598 return this.expect(actual); +1599 }; +1600 +1601 /** +1602 * @private +1603 */ +1604 jasmine.Spec.prototype.expect = function(actual) { +1605 return new (this.getMatchersClass_())(this.env, actual, this.results); +1606 }; +1607 +1608 jasmine.Spec.prototype.waits = function(timeout) { +1609 var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); +1610 this.addToQueue(waitsFunc); +1611 return this; +1612 }; +1613 +1614 jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) { +1615 var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this); +1616 this.addToQueue(waitsForFunc); +1617 return this; +1618 }; +1619 +1620 jasmine.Spec.prototype.failWithException = function (e) { +1621 this.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +1622 }; +1623 +1624 jasmine.Spec.prototype.getMatchersClass_ = function() { +1625 return this.matchersClass || jasmine.Matchers; +1626 }; 1627 -1628 reportRunnerResults: function(runner) { -1629 that.doCallback(that.callbacks.runnerCallback, runner); -1630 }, -1631 reportSuiteResults: function(suite) { -1632 that.doCallback(that.callbacks.suiteCallback, suite); -1633 }, -1634 reportSpecResults: function(spec) { -1635 that.doCallback(that.callbacks.specCallback, spec); -1636 }, -1637 log: function (str) { -1638 if (console && console.log) console.log(str); -1639 } -1640 }; -1641 -1642 return that; -1643 }; -1644 -1645 /** -1646 * Runner -1647 * -1648 * @constructor -1649 * @param {jasmine.Env} env -1650 */ -1651 jasmine.Runner = function(env) { -1652 jasmine.ActionCollection.call(this, env); +1628 jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { +1629 var parent = this.getMatchersClass_(); +1630 var newMatchersClass = function() { +1631 parent.apply(this, arguments); +1632 }; +1633 jasmine.util.inherit(newMatchersClass, parent); +1634 for (var method in matchersPrototype) { +1635 newMatchersClass.prototype[method] = matchersPrototype[method]; +1636 } +1637 this.matchersClass = newMatchersClass; +1638 }; +1639 +1640 jasmine.Spec.prototype.finishCallback = function() { +1641 this.env.reporter.reportSpecResults(this); +1642 }; +1643 +1644 jasmine.Spec.prototype.finish = function(onComplete) { +1645 this.removeAllSpies(); +1646 this.finishCallback(); +1647 if (onComplete) { +1648 onComplete(); +1649 } +1650 }; +1651 +1652 jasmine.Spec.prototype.after = function(doAfter, test) { 1653 -1654 this.suites = this.actions; -1655 }; -1656 jasmine.util.inherit(jasmine.Runner, jasmine.ActionCollection); -1657 -1658 jasmine.Runner.prototype.execute = function() { -1659 if (this.env.reporter.reportRunnerStarting) { -1660 this.env.reporter.reportRunnerStarting(this); -1661 } -1662 jasmine.ActionCollection.prototype.execute.call(this); -1663 }; -1664 -1665 jasmine.Runner.prototype.finishCallback = function() { -1666 this.env.reporter.reportRunnerResults(this); -1667 }; -1668 -1669 jasmine.Runner.prototype.getResults = function() { -1670 var results = new jasmine.NestedResults(); -1671 for (var i = 0; i < this.suites.length; i++) { -1672 results.rollupCounts(this.suites[i].getResults()); -1673 } -1674 return results; -1675 }; -1676 /** -1677 * Internal representation of a Jasmine specification, or test. -1678 * -1679 * @constructor -1680 * @param {jasmine.Env} env -1681 * @param {jasmine.Suite} suite -1682 * @param {String} description -1683 */ -1684 jasmine.Spec = function(env, suite, description) { -1685 this.id = env.nextSpecId_++; -1686 this.env = env; -1687 this.suite = suite; -1688 this.description = description; -1689 this.queue = []; -1690 this.currentTimeout = 0; -1691 this.currentLatchFunction = undefined; -1692 this.finished = false; -1693 this.afterCallbacks = []; -1694 this.spies_ = []; -1695 -1696 this.results = new jasmine.NestedResults(); -1697 this.results.description = description; -1698 this.runs = this.addToQueue; -1699 this.matchersClass = null; -1700 }; -1701 -1702 jasmine.Spec.prototype.getFullName = function() { -1703 return this.suite.getFullName() + ' ' + this.description + '.'; -1704 }; -1705 -1706 jasmine.Spec.prototype.getResults = function() { -1707 return this.results; -1708 }; -1709 -1710 jasmine.Spec.prototype.addToQueue = function(func) { -1711 var queuedFunction = new jasmine.QueuedFunction(this.env, func, this.currentTimeout, this.currentLatchFunction, this); -1712 this.queue.push(queuedFunction); -1713 -1714 if (this.queue.length > 1) { -1715 var previousQueuedFunction = this.queue[this.queue.length - 2]; -1716 previousQueuedFunction.next = function() { -1717 queuedFunction.execute(); -1718 }; -1719 } -1720 -1721 this.resetTimeout(); -1722 return this; -1723 }; +1654 if (this.queue.isRunning()) { +1655 this.queue.add(new jasmine.Block(this.env, doAfter, this)); +1656 } else { +1657 this.afterCallbacks.unshift(doAfter); +1658 } +1659 }; +1660 +1661 jasmine.Spec.prototype.execute = function(onComplete) { +1662 var spec = this; +1663 if (!spec.env.specFilter(spec)) { +1664 spec.results.skipped = true; +1665 spec.finish(onComplete); +1666 return; +1667 } +1668 this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...'); +1669 +1670 spec.env.currentSpec = spec; +1671 spec.env.currentlyRunningTests = true; +1672 +1673 spec.addBeforesAndAftersToQueue(); +1674 +1675 spec.queue.start(function () { +1676 spec.finish(onComplete); +1677 }); +1678 spec.env.currentlyRunningTests = false; +1679 }; +1680 +1681 jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { +1682 for (var suite = this.suite; suite; suite = suite.parentSuite) { +1683 if (suite.beforeQueue) { +1684 for (var i = 0; i < suite.beforeQueue.length; i++) +1685 this.queue.addBefore(new jasmine.Block(this.env, suite.beforeQueue[i], this)); +1686 } +1687 } +1688 for (i = 0; i < this.afterCallbacks.length; i++) { +1689 this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); +1690 } +1691 for (suite = this.suite; suite; suite = suite.parentSuite) { +1692 if (suite.afterQueue) { +1693 for (var j = 0; j < suite.afterQueue.length; j++) +1694 this.queue.add(new jasmine.Block(this.env, suite.afterQueue[j], this)); +1695 } +1696 } +1697 }; +1698 +1699 jasmine.Spec.prototype.explodes = function() { +1700 throw 'explodes function should not have been called'; +1701 }; +1702 +1703 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { +1704 if (obj == undefined) { +1705 throw "spyOn could not find an object to spy upon for " + methodName + "()"; +1706 } +1707 +1708 if (!ignoreMethodDoesntExist && obj[methodName] === undefined) { +1709 throw methodName + '() method does not exist'; +1710 } +1711 +1712 if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { +1713 throw new Error(methodName + ' has already been spied upon'); +1714 } +1715 +1716 var spyObj = jasmine.createSpy(methodName); +1717 +1718 this.spies_.push(spyObj); +1719 spyObj.baseObj = obj; +1720 spyObj.methodName = methodName; +1721 spyObj.originalValue = obj[methodName]; +1722 +1723 obj[methodName] = spyObj; 1724 -1725 /** -1726 * @private -1727 * @deprecated -1728 */ -1729 jasmine.Spec.prototype.expects_that = function(actual) { -1730 return this.expect(actual); -1731 }; -1732 -1733 /** -1734 * @private -1735 */ -1736 jasmine.Spec.prototype.expect = function(actual) { -1737 return new (this.getMatchersClass_())(this.env, actual, this.results); -1738 }; -1739 -1740 /** -1741 * @private -1742 */ -1743 jasmine.Spec.prototype.waits = function(timeout) { -1744 this.currentTimeout = timeout; -1745 this.currentLatchFunction = undefined; -1746 return this; -1747 }; -1748 -1749 /** -1750 * @private -1751 */ -1752 jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, message) { -1753 this.currentTimeout = timeout; -1754 this.currentLatchFunction = latchFunction; -1755 this.currentLatchFunction.description = message; -1756 return this; -1757 }; -1758 -1759 jasmine.Spec.prototype.getMatchersClass_ = function() { -1760 return this.matchersClass || jasmine.Matchers; -1761 }; -1762 -1763 jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { -1764 var parent = this.getMatchersClass_(); -1765 var newMatchersClass = function() { -1766 parent.apply(this, arguments); -1767 }; -1768 jasmine.util.inherit(newMatchersClass, parent); -1769 for (var method in matchersPrototype) { -1770 newMatchersClass.prototype[method] = matchersPrototype[method]; -1771 } -1772 this.matchersClass = newMatchersClass; -1773 }; -1774 -1775 jasmine.Spec.prototype.resetTimeout = function() { -1776 this.currentTimeout = 0; -1777 this.currentLatchFunction = undefined; -1778 }; -1779 -1780 jasmine.Spec.prototype.finishCallback = function() { -1781 this.env.reporter.reportSpecResults(this); -1782 }; -1783 -1784 jasmine.Spec.prototype.finish = function() { -1785 this.safeExecuteAfters(); +1725 return spyObj; +1726 }; +1727 +1728 jasmine.Spec.prototype.removeAllSpies = function() { +1729 for (var i = 0; i < this.spies_.length; i++) { +1730 var spy = this.spies_[i]; +1731 spy.baseObj[spy.methodName] = spy.originalValue; +1732 } +1733 this.spies_ = []; +1734 }; +1735 +1736 /** +1737 * Internal representation of a Jasmine suite. +1738 * +1739 * @constructor +1740 * @param {jasmine.Env} env +1741 * @param {String} description +1742 * @param {Function} specDefinitions +1743 * @param {jasmine.Suite} parentSuite +1744 */ +1745 jasmine.Suite = function(env, description, specDefinitions, parentSuite) { +1746 var self = this; +1747 self.id = env.nextSuiteId_++; +1748 self.description = description; +1749 self.queue = new jasmine.Queue(env); +1750 self.parentSuite = parentSuite; +1751 self.env = env; +1752 self.beforeQueue = []; +1753 self.afterQueue = []; +1754 self.specs_ = []; +1755 }; +1756 +1757 jasmine.Suite.prototype.getFullName = function() { +1758 var fullName = this.description; +1759 for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { +1760 fullName = parentSuite.description + ' ' + fullName; +1761 } +1762 return fullName; +1763 }; +1764 +1765 jasmine.Suite.prototype.finish = function(onComplete) { +1766 this.env.reporter.reportSuiteResults(this); +1767 this.finished = true; +1768 if (typeof(onComplete) == 'function') { +1769 onComplete(); +1770 } +1771 }; +1772 +1773 jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { +1774 beforeEachFunction.typeName = 'beforeEach'; +1775 this.beforeQueue.push(beforeEachFunction); +1776 }; +1777 +1778 jasmine.Suite.prototype.afterEach = function(afterEachFunction) { +1779 afterEachFunction.typeName = 'afterEach'; +1780 this.afterQueue.push(afterEachFunction); +1781 }; +1782 +1783 jasmine.Suite.prototype.getResults = function() { +1784 return this.queue.getResults(); +1785 }; 1786 -1787 this.removeAllSpies(); -1788 this.finishCallback(); -1789 this.finished = true; -1790 }; -1791 -1792 jasmine.Spec.prototype.after = function(doAfter) { -1793 this.afterCallbacks.unshift(doAfter); +1787 jasmine.Suite.prototype.add = function(block) { +1788 if (block instanceof jasmine.Suite) { +1789 this.env.currentRunner.addSuite(block); +1790 } else { +1791 this.specs_.push(block); +1792 } +1793 this.queue.add(block); 1794 }; 1795 -1796 jasmine.Spec.prototype.execute = function() { -1797 if (!this.env.specFilter(this)) { -1798 this.results.skipped = true; -1799 this.finishCallback(); -1800 this.finished = true; -1801 return; -1802 } +1796 jasmine.Suite.prototype.specCount = function() { +1797 return this.specs_.length; +1798 }; +1799 +1800 jasmine.Suite.prototype.specs = function() { +1801 return this.specs_; +1802 }; 1803 -1804 this.env.currentSpec = this; -1805 this.env.currentlyRunningTests = true; -1806 -1807 this.safeExecuteBefores(); -1808 -1809 if (this.queue[0]) { -1810 this.queue[0].execute(); -1811 } else { -1812 this.finish(); -1813 } -1814 this.env.currentlyRunningTests = false; -1815 }; +1804 jasmine.Suite.prototype.execute = function(onComplete) { +1805 var self = this; +1806 this.queue.start(function () { +1807 self.finish(onComplete); +1808 }); +1809 }; +1810 jasmine.WaitsBlock = function(env, timeout, spec) { +1811 this.timeout = timeout; +1812 jasmine.Block.call(this, env, null, spec); +1813 }; +1814 +1815 jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); 1816 -1817 jasmine.Spec.prototype.safeExecuteBefores = function() { -1818 var befores = []; -1819 for (var suite = this.suite; suite; suite = suite.parentSuite) { -1820 if (suite.beforeEachFunction) befores.push(suite.beforeEachFunction); -1821 } -1822 -1823 while (befores.length) { -1824 this.safeExecuteBeforeOrAfter(befores.pop()); -1825 } -1826 }; -1827 -1828 jasmine.Spec.prototype.safeExecuteAfters = function() { -1829 for (var suite = this.suite; suite; suite = suite.parentSuite) { -1830 if (suite.afterEachFunction) this.safeExecuteBeforeOrAfter(suite.afterEachFunction); -1831 } -1832 }; -1833 -1834 jasmine.Spec.prototype.safeExecuteBeforeOrAfter = function(func) { -1835 try { -1836 func.apply(this); -1837 } catch (e) { -1838 this.results.addResult(new jasmine.ExpectationResult(false, func.typeName + '() fail: ' + jasmine.util.formatException(e), null)); -1839 } -1840 }; -1841 -1842 jasmine.Spec.prototype.explodes = function() { -1843 throw 'explodes function should not have been called'; -1844 }; -1845 -1846 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { -1847 if (obj == undefined) { -1848 throw "spyOn could not find an object to spy upon for " + methodName + "()"; -1849 } -1850 -1851 if (!ignoreMethodDoesntExist && obj[methodName] === undefined) { -1852 throw methodName + '() method does not exist'; -1853 } -1854 -1855 if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { -1856 throw new Error(methodName + ' has already been spied upon'); -1857 } -1858 -1859 var spyObj = jasmine.createSpy(methodName); -1860 -1861 this.spies_.push(spyObj); -1862 spyObj.baseObj = obj; -1863 spyObj.methodName = methodName; -1864 spyObj.originalValue = obj[methodName]; -1865 -1866 obj[methodName] = spyObj; -1867 -1868 return spyObj; -1869 }; -1870 -1871 jasmine.Spec.prototype.removeAllSpies = function() { -1872 for (var i = 0; i < this.spies_.length; i++) { -1873 var spy = this.spies_[i]; -1874 spy.baseObj[spy.methodName] = spy.originalValue; -1875 } -1876 this.spies_ = []; -1877 }; -1878 -1879 /** -1880 * Internal representation of a Jasmine suite. -1881 * -1882 * @constructor -1883 * @param {jasmine.Env} env -1884 * @param {String} description -1885 * @param {Function} specDefinitions -1886 * @param {jasmine.Suite} parentSuite -1887 */ -1888 jasmine.Suite = function(env, description, specDefinitions, parentSuite) { -1889 jasmine.ActionCollection.call(this, env); -1890 -1891 this.description = description; -1892 this.specs = this.actions; -1893 this.parentSuite = parentSuite; -1894 -1895 this.beforeEachFunction = null; -1896 this.afterEachFunction = null; -1897 }; -1898 jasmine.util.inherit(jasmine.Suite, jasmine.ActionCollection); -1899 -1900 jasmine.Suite.prototype.getFullName = function() { -1901 var fullName = this.description; -1902 for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { -1903 fullName = parentSuite.description + ' ' + fullName; -1904 } -1905 return fullName; -1906 }; -1907 -1908 jasmine.Suite.prototype.finishCallback = function() { -1909 this.env.reporter.reportSuiteResults(this); -1910 }; -1911 -1912 jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { -1913 beforeEachFunction.typeName = 'beforeEach'; -1914 this.beforeEachFunction = beforeEachFunction; -1915 }; -1916 -1917 jasmine.Suite.prototype.afterEach = function(afterEachFunction) { -1918 afterEachFunction.typeName = 'afterEach'; -1919 this.afterEachFunction = afterEachFunction; -1920 }; -1921 -1922 jasmine.Suite.prototype.getResults = function() { -1923 var results = new jasmine.NestedResults(); -1924 for (var i = 0; i < this.specs.length; i++) { -1925 results.rollupCounts(this.specs[i].getResults()); -1926 } -1927 return results; -1928 }; -1929 -1930 \ No newline at end of file +1817 jasmine.WaitsBlock.prototype.execute = function (onComplete) { +1818 this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); +1819 this.env.setTimeout(function () { +1820 onComplete(); +1821 }, this.timeout); +1822 }; +1823 jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { +1824 this.timeout = timeout; +1825 this.latchFunction = latchFunction; +1826 this.message = message; +1827 this.totalTimeSpentWaitingForLatch = 0; +1828 jasmine.Block.call(this, env, null, spec); +1829 }; +1830 +1831 jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); +1832 +1833 jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100; +1834 +1835 jasmine.WaitsForBlock.prototype.execute = function (onComplete) { +1836 var self = this; +1837 self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen')); +1838 var latchFunctionResult; +1839 try { +1840 latchFunctionResult = self.latchFunction.apply(self.spec); +1841 } catch (e) { +1842 self.fail(e); +1843 onComplete(); +1844 return; +1845 } +1846 +1847 if (latchFunctionResult) { +1848 onComplete(); +1849 } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { +1850 var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen'); +1851 self.fail({ +1852 name: 'timeout', +1853 message: message +1854 }); +1855 self.spec._next(); +1856 } else { +1857 self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; +1858 self.env.setTimeout(function () { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); +1859 } +1860 }; +1861 // Mock setTimeout, clearTimeout +1862 // Contributed by Pivotal Computer Systems, www.pivotalsf.com +1863 +1864 jasmine.FakeTimer = function() { +1865 this.reset(); +1866 +1867 var self = this; +1868 self.setTimeout = function(funcToCall, millis) { +1869 self.timeoutsMade++; +1870 self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); +1871 return self.timeoutsMade; +1872 }; +1873 +1874 self.setInterval = function(funcToCall, millis) { +1875 self.timeoutsMade++; +1876 self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); +1877 return self.timeoutsMade; +1878 }; +1879 +1880 self.clearTimeout = function(timeoutKey) { +1881 self.scheduledFunctions[timeoutKey] = undefined; +1882 }; +1883 +1884 self.clearInterval = function(timeoutKey) { +1885 self.scheduledFunctions[timeoutKey] = undefined; +1886 }; +1887 +1888 }; +1889 +1890 jasmine.FakeTimer.prototype.reset = function() { +1891 this.timeoutsMade = 0; +1892 this.scheduledFunctions = {}; +1893 this.nowMillis = 0; +1894 }; +1895 +1896 jasmine.FakeTimer.prototype.tick = function(millis) { +1897 var oldMillis = this.nowMillis; +1898 var newMillis = oldMillis + millis; +1899 this.runFunctionsWithinRange(oldMillis, newMillis); +1900 this.nowMillis = newMillis; +1901 }; +1902 +1903 jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { +1904 var scheduledFunc; +1905 var funcsToRun = []; +1906 for (var timeoutKey in this.scheduledFunctions) { +1907 scheduledFunc = this.scheduledFunctions[timeoutKey]; +1908 if (scheduledFunc != undefined && +1909 scheduledFunc.runAtMillis >= oldMillis && +1910 scheduledFunc.runAtMillis <= nowMillis) { +1911 funcsToRun.push(scheduledFunc); +1912 this.scheduledFunctions[timeoutKey] = undefined; +1913 } +1914 } +1915 +1916 if (funcsToRun.length > 0) { +1917 funcsToRun.sort(function(a, b) { +1918 return a.runAtMillis - b.runAtMillis; +1919 }); +1920 for (var i = 0; i < funcsToRun.length; ++i) { +1921 try { +1922 var funcToRun = funcsToRun[i]; +1923 this.nowMillis = funcToRun.runAtMillis; +1924 funcToRun.funcToCall(); +1925 if (funcToRun.recurring) { +1926 this.scheduleFunction(funcToRun.timeoutKey, +1927 funcToRun.funcToCall, +1928 funcToRun.millis, +1929 true); +1930 } +1931 } catch(e) { +1932 } +1933 } +1934 this.runFunctionsWithinRange(oldMillis, nowMillis); +1935 } +1936 }; +1937 +1938 jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { +1939 this.scheduledFunctions[timeoutKey] = { +1940 runAtMillis: this.nowMillis + millis, +1941 funcToCall: funcToCall, +1942 recurring: recurring, +1943 timeoutKey: timeoutKey, +1944 millis: millis +1945 }; +1946 }; +1947 +1948 +1949 jasmine.Clock = { +1950 defaultFakeTimer: new jasmine.FakeTimer(), +1951 +1952 reset: function() { +1953 jasmine.Clock.assertInstalled(); +1954 jasmine.Clock.defaultFakeTimer.reset(); +1955 }, +1956 +1957 tick: function(millis) { +1958 jasmine.Clock.assertInstalled(); +1959 jasmine.Clock.defaultFakeTimer.tick(millis); +1960 }, +1961 +1962 runFunctionsWithinRange: function(oldMillis, nowMillis) { +1963 jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); +1964 }, +1965 +1966 scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { +1967 jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); +1968 }, +1969 +1970 useMock: function() { +1971 var spec = jasmine.getEnv().currentSpec; +1972 spec.after(jasmine.Clock.uninstallMock); +1973 +1974 jasmine.Clock.installMock(); +1975 }, +1976 +1977 installMock: function() { +1978 jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; +1979 }, +1980 +1981 uninstallMock: function() { +1982 jasmine.Clock.assertInstalled(); +1983 jasmine.Clock.installed = jasmine.Clock.real; +1984 }, +1985 +1986 real: { +1987 setTimeout: window.setTimeout, +1988 clearTimeout: window.clearTimeout, +1989 setInterval: window.setInterval, +1990 clearInterval: window.clearInterval +1991 }, +1992 +1993 assertInstalled: function() { +1994 if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) { +1995 throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); +1996 } +1997 }, +1998 +1999 installed: null +2000 }; +2001 jasmine.Clock.installed = jasmine.Clock.real; +2002 +2003 window.setTimeout = function(funcToCall, millis) { +2004 return jasmine.Clock.installed.setTimeout.apply(this, arguments); +2005 }; +2006 +2007 window.setInterval = function(funcToCall, millis) { +2008 return jasmine.Clock.installed.setInterval.apply(this, arguments); +2009 }; +2010 +2011 window.clearTimeout = function(timeoutKey) { +2012 return jasmine.Clock.installed.clearTimeout.apply(this, arguments); +2013 }; +2014 +2015 window.clearInterval = function(timeoutKey) { +2016 return jasmine.Clock.installed.clearInterval.apply(this, arguments); +2017 }; +2018 +2019 \ No newline at end of file diff --git a/doc/symbols/src/lib_json2.js.html b/doc/symbols/src/lib_json2.js.html new file mode 100644 index 00000000..59b08d24 --- /dev/null +++ b/doc/symbols/src/lib_json2.js.html @@ -0,0 +1,486 @@ +
      1 /*
    +  2     http://www.JSON.org/json2.js
    +  3     2008-11-19
    +  4 
    +  5     Public Domain.
    +  6 
    +  7     NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
    +  8 
    +  9     See http://www.JSON.org/js.html
    + 10 
    + 11     This file creates a global JSON object containing two methods: stringify
    + 12     and parse.
    + 13 
    + 14         JSON.stringify(value, replacer, space)
    + 15             value       any JavaScript value, usually an object or array.
    + 16 
    + 17             replacer    an optional parameter that determines how object
    + 18                         values are stringified for objects. It can be a
    + 19                         function or an array of strings.
    + 20 
    + 21             space       an optional parameter that specifies the indentation
    + 22                         of nested structures. If it is omitted, the text will
    + 23                         be packed without extra whitespace. If it is a number,
    + 24                         it will specify the number of spaces to indent at each
    + 25                         level. If it is a string (such as '\t' or ' '),
    + 26                         it contains the characters used to indent at each level.
    + 27 
    + 28             This method produces a JSON text from a JavaScript value.
    + 29 
    + 30             When an object value is found, if the object contains a toJSON
    + 31             method, its toJSON method will be called and the result will be
    + 32             stringified. A toJSON method does not serialize: it returns the
    + 33             value represented by the name/value pair that should be serialized,
    + 34             or undefined if nothing should be serialized. The toJSON method
    + 35             will be passed the key associated with the value, and this will be
    + 36             bound to the object holding the key.
    + 37 
    + 38             For example, this would serialize Dates as ISO strings.
    + 39 
    + 40                 Date.prototype.toJSON = function (key) {
    + 41                     function f(n) {
    + 42                         // Format integers to have at least two digits.
    + 43                         return n < 10 ? '0' + n : n;
    + 44                     }
    + 45 
    + 46                     return this.getUTCFullYear()   + '-' +
    + 47                          f(this.getUTCMonth() + 1) + '-' +
    + 48                          f(this.getUTCDate())      + 'T' +
    + 49                          f(this.getUTCHours())     + ':' +
    + 50                          f(this.getUTCMinutes())   + ':' +
    + 51                          f(this.getUTCSeconds())   + 'Z';
    + 52                 };
    + 53 
    + 54             You can provide an optional replacer method. It will be passed the
    + 55             key and value of each member, with this bound to the containing
    + 56             object. The value that is returned from your method will be
    + 57             serialized. If your method returns undefined, then the member will
    + 58             be excluded from the serialization.
    + 59 
    + 60             If the replacer parameter is an array of strings, then it will be
    + 61             used to select the members to be serialized. It filters the results
    + 62             such that only members with keys listed in the replacer array are
    + 63             stringified.
    + 64 
    + 65             Values that do not have JSON representations, such as undefined or
    + 66             functions, will not be serialized. Such values in objects will be
    + 67             dropped; in arrays they will be replaced with null. You can use
    + 68             a replacer function to replace those with JSON values.
    + 69             JSON.stringify(undefined) returns undefined.
    + 70 
    + 71             The optional space parameter produces a stringification of the
    + 72             value that is filled with line breaks and indentation to make it
    + 73             easier to read.
    + 74 
    + 75             If the space parameter is a non-empty string, then that string will
    + 76             be used for indentation. If the space parameter is a number, then
    + 77             the indentation will be that many spaces.
    + 78 
    + 79             Example:
    + 80 
    + 81             text = JSON.stringify(['e', {pluribus: 'unum'}]);
    + 82             // text is '["e",{"pluribus":"unum"}]'
    + 83 
    + 84 
    + 85             text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
    + 86             // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
    + 87 
    + 88             text = JSON.stringify([new Date()], function (key, value) {
    + 89                 return this[key] instanceof Date ?
    + 90                     'Date(' + this[key] + ')' : value;
    + 91             });
    + 92             // text is '["Date(---current time---)"]'
    + 93 
    + 94 
    + 95         JSON.parse(text, reviver)
    + 96             This method parses a JSON text to produce an object or array.
    + 97             It can throw a SyntaxError exception.
    + 98 
    + 99             The optional reviver parameter is a function that can filter and
    +100             transform the results. It receives each of the keys and values,
    +101             and its return value is used instead of the original value.
    +102             If it returns what it received, then the structure is not modified.
    +103             If it returns undefined then the member is deleted.
    +104 
    +105             Example:
    +106 
    +107             // Parse the text. Values that look like ISO date strings will
    +108             // be converted to Date objects.
    +109 
    +110             myData = JSON.parse(text, function (key, value) {
    +111                 var a;
    +112                 if (typeof value === 'string') {
    +113                     a =
    +114 /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
    +115                     if (a) {
    +116                         return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
    +117                             +a[5], +a[6]));
    +118                     }
    +119                 }
    +120                 return value;
    +121             });
    +122 
    +123             myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
    +124                 var d;
    +125                 if (typeof value === 'string' &&
    +126                         value.slice(0, 5) === 'Date(' &&
    +127                         value.slice(-1) === ')') {
    +128                     d = new Date(value.slice(5, -1));
    +129                     if (d) {
    +130                         return d;
    +131                     }
    +132                 }
    +133                 return value;
    +134             });
    +135 
    +136 
    +137     This is a reference implementation. You are free to copy, modify, or
    +138     redistribute.
    +139 
    +140     This code should be minified before deployment.
    +141     See http://javascript.crockford.com/jsmin.html
    +142 
    +143     USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    +144     NOT CONTROL.
    +145 */
    +146 
    +147 /*jslint evil: true */
    +148 
    +149 /*global JSON */
    +150 
    +151 /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    +152     call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    +153     getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    +154     lastIndex, length, parse, prototype, push, replace, slice, stringify,
    +155     test, toJSON, toString, valueOf
    +156 */
    +157 
    +158 // Create a JSON object only if one does not already exist. We create the
    +159 // methods in a closure to avoid creating global variables.
    +160 
    +161 if (!this.JSON) {
    +162     JSON = {};
    +163 }
    +164 (function () {
    +165 
    +166     function f(n) {
    +167         // Format integers to have at least two digits.
    +168         return n < 10 ? '0' + n : n;
    +169     }
    +170 
    +171     if (typeof Date.prototype.toJSON !== 'function') {
    +172 
    +173         Date.prototype.toJSON = function (key) {
    +174 
    +175             return this.getUTCFullYear()   + '-' +
    +176                  f(this.getUTCMonth() + 1) + '-' +
    +177                  f(this.getUTCDate())      + 'T' +
    +178                  f(this.getUTCHours())     + ':' +
    +179                  f(this.getUTCMinutes())   + ':' +
    +180                  f(this.getUTCSeconds())   + 'Z';
    +181         };
    +182 
    +183         String.prototype.toJSON =
    +184         Number.prototype.toJSON =
    +185         Boolean.prototype.toJSON = function (key) {
    +186             return this.valueOf();
    +187         };
    +188     }
    +189 
    +190     var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
    +191         escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
    +192         gap,
    +193         indent,
    +194         meta = {    // table of character substitutions
    +195             '\b': '\\b',
    +196             '\t': '\\t',
    +197             '\n': '\\n',
    +198             '\f': '\\f',
    +199             '\r': '\\r',
    +200             '"' : '\\"',
    +201             '\\': '\\\\'
    +202         },
    +203         rep;
    +204 
    +205 
    +206     function quote(string) {
    +207 
    +208 // If the string contains no control characters, no quote characters, and no
    +209 // backslash characters, then we can safely slap some quotes around it.
    +210 // Otherwise we must also replace the offending characters with safe escape
    +211 // sequences.
    +212 
    +213         escapable.lastIndex = 0;
    +214         return escapable.test(string) ?
    +215             '"' + string.replace(escapable, function (a) {
    +216                 var c = meta[a];
    +217                 return typeof c === 'string' ? c :
    +218                     '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    +219             }) + '"' :
    +220             '"' + string + '"';
    +221     }
    +222 
    +223 
    +224     function str(key, holder) {
    +225 
    +226 // Produce a string from holder[key].
    +227 
    +228         var i,          // The loop counter.
    +229             k,          // The member key.
    +230             v,          // The member value.
    +231             length,
    +232             mind = gap,
    +233             partial,
    +234             value = holder[key];
    +235 
    +236 // If the value has a toJSON method, call it to obtain a replacement value.
    +237 
    +238         if (value && typeof value === 'object' &&
    +239                 typeof value.toJSON === 'function') {
    +240             value = value.toJSON(key);
    +241         }
    +242 
    +243 // If we were called with a replacer function, then call the replacer to
    +244 // obtain a replacement value.
    +245 
    +246         if (typeof rep === 'function') {
    +247             value = rep.call(holder, key, value);
    +248         }
    +249 
    +250 // What happens next depends on the value's type.
    +251 
    +252         switch (typeof value) {
    +253         case 'string':
    +254             return quote(value);
    +255 
    +256         case 'number':
    +257 
    +258 // JSON numbers must be finite. Encode non-finite numbers as null.
    +259 
    +260             return isFinite(value) ? String(value) : 'null';
    +261 
    +262         case 'boolean':
    +263         case 'null':
    +264 
    +265 // If the value is a boolean or null, convert it to a string. Note:
    +266 // typeof null does not produce 'null'. The case is included here in
    +267 // the remote chance that this gets fixed someday.
    +268 
    +269             return String(value);
    +270 
    +271 // If the type is 'object', we might be dealing with an object or an array or
    +272 // null.
    +273 
    +274         case 'object':
    +275 
    +276 // Due to a specification blunder in ECMAScript, typeof null is 'object',
    +277 // so watch out for that case.
    +278 
    +279             if (!value) {
    +280                 return 'null';
    +281             }
    +282 
    +283 // Make an array to hold the partial results of stringifying this object value.
    +284 
    +285             gap += indent;
    +286             partial = [];
    +287 
    +288 // Is the value an array?
    +289 
    +290             if (Object.prototype.toString.apply(value) === '[object Array]') {
    +291 
    +292 // The value is an array. Stringify every element. Use null as a placeholder
    +293 // for non-JSON values.
    +294 
    +295                 length = value.length;
    +296                 for (i = 0; i < length; i += 1) {
    +297                     partial[i] = str(i, value) || 'null';
    +298                 }
    +299 
    +300 // Join all of the elements together, separated with commas, and wrap them in
    +301 // brackets.
    +302 
    +303                 v = partial.length === 0 ? '[]' :
    +304                     gap ? '[\n' + gap +
    +305                             partial.join(',\n' + gap) + '\n' +
    +306                                 mind + ']' :
    +307                           '[' + partial.join(',') + ']';
    +308                 gap = mind;
    +309                 return v;
    +310             }
    +311 
    +312 // If the replacer is an array, use it to select the members to be stringified.
    +313 
    +314             if (rep && typeof rep === 'object') {
    +315                 length = rep.length;
    +316                 for (i = 0; i < length; i += 1) {
    +317                     k = rep[i];
    +318                     if (typeof k === 'string') {
    +319                         v = str(k, value);
    +320                         if (v) {
    +321                             partial.push(quote(k) + (gap ? ': ' : ':') + v);
    +322                         }
    +323                     }
    +324                 }
    +325             } else {
    +326 
    +327 // Otherwise, iterate through all of the keys in the object.
    +328 
    +329                 for (k in value) {
    +330                     if (Object.hasOwnProperty.call(value, k)) {
    +331                         v = str(k, value);
    +332                         if (v) {
    +333                             partial.push(quote(k) + (gap ? ': ' : ':') + v);
    +334                         }
    +335                     }
    +336                 }
    +337             }
    +338 
    +339 // Join all of the member texts together, separated with commas,
    +340 // and wrap them in braces.
    +341 
    +342             v = partial.length === 0 ? '{}' :
    +343                 gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
    +344                         mind + '}' : '{' + partial.join(',') + '}';
    +345             gap = mind;
    +346             return v;
    +347         }
    +348     }
    +349 
    +350 // If the JSON object does not yet have a stringify method, give it one.
    +351 
    +352     if (typeof JSON.stringify !== 'function') {
    +353         JSON.stringify = function (value, replacer, space) {
    +354 
    +355 // The stringify method takes a value and an optional replacer, and an optional
    +356 // space parameter, and returns a JSON text. The replacer can be a function
    +357 // that can replace values, or an array of strings that will select the keys.
    +358 // A default replacer method can be provided. Use of the space parameter can
    +359 // produce text that is more easily readable.
    +360 
    +361             var i;
    +362             gap = '';
    +363             indent = '';
    +364 
    +365 // If the space parameter is a number, make an indent string containing that
    +366 // many spaces.
    +367 
    +368             if (typeof space === 'number') {
    +369                 for (i = 0; i < space; i += 1) {
    +370                     indent += ' ';
    +371                 }
    +372 
    +373 // If the space parameter is a string, it will be used as the indent string.
    +374 
    +375             } else if (typeof space === 'string') {
    +376                 indent = space;
    +377             }
    +378 
    +379 // If there is a replacer, it must be a function or an array.
    +380 // Otherwise, throw an error.
    +381 
    +382             rep = replacer;
    +383             if (replacer && typeof replacer !== 'function' &&
    +384                     (typeof replacer !== 'object' ||
    +385                      typeof replacer.length !== 'number')) {
    +386                 throw new Error('JSON.stringify');
    +387             }
    +388 
    +389 // Make a fake root object containing our value under the key of ''.
    +390 // Return the result of stringifying the value.
    +391 
    +392             return str('', {'': value});
    +393         };
    +394     }
    +395 
    +396 
    +397 // If the JSON object does not yet have a parse method, give it one.
    +398 
    +399     if (typeof JSON.parse !== 'function') {
    +400         JSON.parse = function (text, reviver) {
    +401 
    +402 // The parse method takes a text and an optional reviver function, and returns
    +403 // a JavaScript value if the text is a valid JSON text.
    +404 
    +405             var j;
    +406 
    +407             function walk(holder, key) {
    +408 
    +409 // The walk method is used to recursively walk the resulting structure so
    +410 // that modifications can be made.
    +411 
    +412                 var k, v, value = holder[key];
    +413                 if (value && typeof value === 'object') {
    +414                     for (k in value) {
    +415                         if (Object.hasOwnProperty.call(value, k)) {
    +416                             v = walk(value, k);
    +417                             if (v !== undefined) {
    +418                                 value[k] = v;
    +419                             } else {
    +420                                 delete value[k];
    +421                             }
    +422                         }
    +423                     }
    +424                 }
    +425                 return reviver.call(holder, key, value);
    +426             }
    +427 
    +428 
    +429 // Parsing happens in four stages. In the first stage, we replace certain
    +430 // Unicode characters with escape sequences. JavaScript handles many characters
    +431 // incorrectly, either silently deleting them, or treating them as line endings.
    +432 
    +433             cx.lastIndex = 0;
    +434             if (cx.test(text)) {
    +435                 text = text.replace(cx, function (a) {
    +436                     return '\\u' +
    +437                         ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    +438                 });
    +439             }
    +440 
    +441 // In the second stage, we run the text against regular expressions that look
    +442 // for non-JSON patterns. We are especially concerned with '()' and 'new'
    +443 // because they can cause invocation, and '=' because it can cause mutation.
    +444 // But just to be safe, we want to reject all unexpected forms.
    +445 
    +446 // We split the second stage into 4 regexp operations in order to work around
    +447 // crippling inefficiencies in IE's and Safari's regexp engines. First we
    +448 // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
    +449 // replace all simple value tokens with ']' characters. Third, we delete all
    +450 // open brackets that follow a colon or comma or that begin the text. Finally,
    +451 // we look to see that the remaining characters are only whitespace or ']' or
    +452 // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
    +453 
    +454             if (/^[\],:{}\s]*$/.
    +455 test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
    +456 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
    +457 replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
    +458 
    +459 // In the third stage we use the eval function to compile the text into a
    +460 // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
    +461 // in JavaScript: it can begin a block or an object literal. We wrap the text
    +462 // in parens to eliminate the ambiguity.
    +463 
    +464                 j = eval('(' + text + ')');
    +465 
    +466 // In the optional fourth stage, we recursively walk the new structure, passing
    +467 // each name/value pair to a reviver function for possible transformation.
    +468 
    +469                 return typeof reviver === 'function' ?
    +470                     walk({'': j}, '') : j;
    +471             }
    +472 
    +473 // If the text is not JSON parseable, then a SyntaxError is thrown.
    +474 
    +475             throw new SyntaxError('JSON.parse');
    +476         };
    +477     }
    +478 })();
    +479 
    \ No newline at end of file diff --git a/examples/html/example_suite.html b/examples/html/example_suite.html new file mode 100644 index 00000000..a97289e3 --- /dev/null +++ b/examples/html/example_suite.html @@ -0,0 +1,26 @@ + + + + Jasmine Test Runner + + + + + + + + + + + + + + + diff --git a/lib/example_suite.js b/examples/html/spec/example_suite.js similarity index 100% rename from lib/example_suite.js rename to examples/html/spec/example_suite.js diff --git a/examples/ruby/Rakefile b/examples/ruby/Rakefile new file mode 100644 index 00000000..79f39454 --- /dev/null +++ b/examples/ruby/Rakefile @@ -0,0 +1,32 @@ +namespace :test do + desc "Run continuous integration tests" + require "spec" + require 'spec/rake/spectask' + + Spec::Rake::SpecTask.new(:ci) do |t| + t.spec_opts = ["--color", "--format", "specdoc"] + t.spec_files = ["spec/jasmine_spec.rb"] + end +end + +desc "Run specs via server" +task :jasmine_server do + require File.expand_path(File.join(File.dirname(__FILE__), "../../contrib/ruby/jasmine_spec_builder")) + + JASMINE_LIB = File.expand_path(File.join(File.dirname(__FILE__), '../../lib')) + dir_mappings = { + "/spec" => 'spec', + "/lib" => JASMINE_LIB + } + + includes = ['lib/' + File.basename(Dir.glob("#{JASMINE_LIB}/jasmine*.js").first), + 'lib/json2.js', + 'lib/TrivialReporter.js'] + + spec_files = Dir.glob("spec/**/*[Ss]pec.js") + + puts "your tests are here:" + puts " http://localhost:8888/run.html" + + Jasmine::SimpleServer.start(8888, includes + spec_files, dir_mappings) +end diff --git a/examples/ruby/spec/example/example_spec.js b/examples/ruby/spec/example/example_spec.js new file mode 100644 index 00000000..494539e4 --- /dev/null +++ b/examples/ruby/spec/example/example_spec.js @@ -0,0 +1,11 @@ +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); + }); + }); +}); \ No newline at end of file diff --git a/examples/ruby/spec/jasmine_spec.rb b/examples/ruby/spec/jasmine_spec.rb new file mode 100644 index 00000000..9d7d6fc9 --- /dev/null +++ b/examples/ruby/spec/jasmine_spec.rb @@ -0,0 +1,30 @@ +require 'rubygems' +require File.expand_path(File.join(File.dirname(__FILE__), "../../../contrib/ruby/jasmine_spec_builder")) +require "selenium_rc" + + +JASMINE_LIB = File.expand_path(File.join(File.dirname(__FILE__), '../../../lib')) +dir_mappings = { + "/spec" => 'spec', + "/lib" => JASMINE_LIB +} + +includes = ['lib/' + File.basename(Dir.glob("#{JASMINE_LIB}/jasmine*.js").first), + 'lib/json2.js', + 'lib/TrivialReporter.js'] + +spec_files = Dir.glob("spec/**/*[Ss]pec.js") +jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path, includes + spec_files, dir_mappings) +spec_builder = Jasmine::SpecBuilder.new(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 diff --git a/lib/TrivialReporter.js b/lib/TrivialReporter.js index 8317007f..71389a74 100644 --- a/lib/TrivialReporter.js +++ b/lib/TrivialReporter.js @@ -28,7 +28,7 @@ jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarA }; jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { - var suites = runner.getAllSuites(); + var suites = runner.suites(); this.runnerDiv = this.createDom('div', { className: 'runner running' }, this.createDom('a', { className: 'runSpec', href: '?' }, "run all"), @@ -76,10 +76,11 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { this.createDom('a', { className: 'runSpec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), spec.getFullName()); + var resultItems = results.getItems(); for (var i = 0; i < resultItems.length; i++) { var result = resultItems[i]; - if (!result.passed) { + if (result.passed && !result.passed()) { var resultMessageDiv = this.createDom('div', {className: 'resultMessage fail'}); resultMessageDiv.innerHTML = result.message; // todo: lame; mend specDiv.appendChild(resultMessageDiv); diff --git a/lib/example_suite.html b/lib/example_suite.html deleted file mode 100644 index b59d189a..00000000 --- a/lib/example_suite.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - Jasmine Test Runner - - - - - - - - - - - - - - - - - diff --git a/lib/jasmine.js b/lib/jasmine-0.9.0.js similarity index 85% rename from lib/jasmine.js rename to lib/jasmine-0.9.0.js index 05a858c0..9017c45e 100644 --- a/lib/jasmine.js +++ b/lib/jasmine-0.9.0.js @@ -40,12 +40,16 @@ jasmine.MessageResult = function(text) { jasmine.ExpectationResult = function(passed, message, details) { this.type = 'ExpectationResult'; - this.passed = passed; + this.passed_ = passed; this.message = message; this.details = details; this.trace = new Error(message); // todo: test better }; +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; + /** * Getter for the Jasmine environment. Ensures one gets created */ @@ -508,6 +512,13 @@ jasmine.include = function(url, opt_global) { return eval(xhr.responseText); } }; + +jasmine.version_= { + "major": 0, + "minor": 9, + "build": 0, + "revision": 1251902474 + }; /** * @namespace */ @@ -587,6 +598,7 @@ jasmine.Env = function() { }; this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; this.equalityTesters_ = []; }; @@ -596,6 +608,14 @@ jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; jasmine.Env.prototype.setInterval = jasmine.setInterval; jasmine.Env.prototype.clearInterval = jasmine.clearInterval; +jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); + } +}; + /** * Register a reporter to receive status updates from Jasmine. * @param {jasmine.Reporter} reporter An object which will receive status updates. @@ -613,9 +633,9 @@ jasmine.Env.prototype.describe = function(description, specDefinitions) { var parentSuite = this.currentSuite; if (parentSuite) { - parentSuite.specs.push(suite); + parentSuite.add(suite); } else { - this.currentRunner.suites.push(suite); + this.currentRunner.add(suite); } this.currentSuite = suite; @@ -644,11 +664,11 @@ jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { jasmine.Env.prototype.it = function(description, func) { var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.specs.push(spec); + this.currentSuite.add(spec); this.currentSpec = spec; if (func) { - spec.addToQueue(func); + spec.runs(func); } return spec; @@ -753,98 +773,6 @@ jasmine.Env.prototype.contains_ = function(haystack, needle) { jasmine.Env.prototype.addEqualityTester = function(equalityTester) { this.equalityTesters_.push(equalityTester); }; -/** - * base for Runner & Suite: allows for a queue of functions to get executed, allowing for - * any one action to complete, including asynchronous calls, before going to the next - * action. - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.ActionCollection = function(env) { - this.env = env; - this.actions = []; - this.index = 0; - this.finished = false; -}; - -/** - * Marks the collection as done & calls the finish callback, if there is one - */ -jasmine.ActionCollection.prototype.finish = function() { - if (this.finishCallback) { - this.finishCallback(); - } - this.finished = true; -}; - -/** - * Starts executing the queue of functions/actions. - */ -jasmine.ActionCollection.prototype.execute = function() { - if (this.actions.length > 0) { - this.next(); - } -}; - -/** - * Gets the current action. - */ -jasmine.ActionCollection.prototype.getCurrentAction = function() { - return this.actions[this.index]; -}; - -/** - * Executes the next queued function/action. If there are no more in the queue, calls #finish. - */ -jasmine.ActionCollection.prototype.next = function() { - if (this.index >= this.actions.length) { - this.finish(); - return; - } - - var currentAction = this.getCurrentAction(); - - currentAction.execute(this); - - if (currentAction.afterCallbacks) { - for (var i = 0; i < currentAction.afterCallbacks.length; i++) { - try { - currentAction.afterCallbacks[i](); - } catch (e) { - alert(e); - } - } - } - - this.waitForDone(currentAction); -}; - -jasmine.ActionCollection.prototype.waitForDone = function(action) { - var self = this; - var afterExecute = function afterExecute() { - self.index++; - self.next(); - }; - - if (action.finished) { - var now = new Date().getTime(); - if (this.env.updateInterval && now - this.env.lastUpdate > this.env.updateInterval) { - this.env.lastUpdate = now; - this.env.setTimeout(afterExecute, 0); - } else { - afterExecute(); - } - return; - } - - var id = this.env.setInterval(function() { - if (action.finished) { - self.env.clearInterval(id); - afterExecute(); - } - }, 150); -}; /** No-op base class for Jasmine reporters. * * @constructor @@ -872,6 +800,32 @@ jasmine.Reporter.prototype.reportSpecResults = function(spec) { jasmine.Reporter.prototype.log = function(str) { }; +/** + * Blocks are functions with executable code that make up a spec. + * + * @constructor + * @param {jasmine.Env} env + * @param {Function} func + * @param {jasmine.Spec} spec + */ +jasmine.Block = function(env, func, spec) { + this.env = env; + this.func = func; + this.spec = spec; +}; + +jasmine.Block.prototype.execute = function(onComplete) { + try { + this.func.apply(this.spec); + } catch (e) { + this.fail(e); + } + onComplete(); +}; + +jasmine.Block.prototype.fail = function(e) { + this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +}; /** JavaScript API reporter. * * @constructor @@ -885,27 +839,27 @@ jasmine.JsApiReporter = function() { jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { this.started = true; - - for (var i = 0; i < runner.suites.length; i++) { - var suite = runner.suites[i]; + var suites = runner.suites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; this.suites.push(this.summarize_(suite)); } }; jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { + var isSuite = suiteOrSpec instanceof jasmine.Suite var summary = { id: suiteOrSpec.id, name: suiteOrSpec.description, - type: suiteOrSpec instanceof jasmine.Suite ? 'suite' : 'spec', + type: isSuite ? 'suite' : 'spec', children: [] }; - - if (suiteOrSpec.specs) { - for (var i = 0; i < suiteOrSpec.specs.length; i++) { - summary.children.push(this.summarize_(suiteOrSpec.specs[i])); + if (isSuite) { + var specs = suiteOrSpec.specs(); + for (var i = 0; i < specs.length; i++) { + summary.children.push(this.summarize_(specs[i])); } } - return summary; }; @@ -1212,6 +1166,704 @@ jasmine.Matchers.Any.prototype.toString = function() { return ''; }; +/** + * @constructor + */ +jasmine.MultiReporter = function() { + this.subReporters_ = []; +}; +jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); + +jasmine.MultiReporter.prototype.addReporter = function(reporter) { + this.subReporters_.push(reporter); +}; + +(function() { + var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"]; + for (var i = 0; i < functionNames.length; i++) { + var functionName = functionNames[i]; + jasmine.MultiReporter.prototype[functionName] = (function(functionName) { + return function() { + for (var j = 0; j < this.subReporters_.length; j++) { + var subReporter = this.subReporters_[j]; + if (subReporter[functionName]) { + subReporter[functionName].apply(subReporter, arguments); + } + } + }; + })(functionName); + } +})(); +/** + * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults + * + * @constructor + */ +jasmine.NestedResults = function() { + /** + * The total count of results + */ + this.totalCount = 0; + /** + * Number of passed results + */ + this.passedCount = 0; + /** + * Number of failed results + */ + this.failedCount = 0; + /** + * Was this suite/spec skipped? + */ + this.skipped = false; + /** + * @ignore + */ + this.items_ = []; +}; + +/** + * Roll up the result counts. + * + * @param result + */ +jasmine.NestedResults.prototype.rollupCounts = function(result) { + this.totalCount += result.totalCount; + this.passedCount += result.passedCount; + this.failedCount += result.failedCount; +}; + +/** + * Tracks a result's message. + * @param message + */ +jasmine.NestedResults.prototype.log = function(message) { + this.items_.push(new jasmine.MessageResult(message)); +}; + +/** + * Getter for the results: message & results. + */ +jasmine.NestedResults.prototype.getItems = function() { + return this.items_; +}; + +/** + * Adds a result, tracking counts (total, passed, & failed) + * @param {jasmine.ExpectationResult|jasmine.NestedResults} result + */ +jasmine.NestedResults.prototype.addResult = function(result) { + if (result.type != 'MessageResult') { + if (result.items_) { + this.rollupCounts(result); + } else { + this.totalCount++; + if (result.passed()) { + this.passedCount++; + } else { + this.failedCount++; + } + } + } + this.items_.push(result); +}; + +/** + * @returns {Boolean} True if everything below passed + */ +jasmine.NestedResults.prototype.passed = function() { + return this.passedCount === this.totalCount; +}; +/** + * Base class for pretty printing for expectation results. + */ +jasmine.PrettyPrinter = function() { + this.ppNestLevel_ = 0; +}; + +/** + * Formats a value in a nice, human-readable string. + * + * @param value + * @returns {String} + */ +jasmine.PrettyPrinter.prototype.format = function(value) { + if (this.ppNestLevel_ > 40) { + // return '(jasmine.pp nested too deeply!)'; + throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); + } + + this.ppNestLevel_++; + try { + if (value === undefined) { + this.emitScalar('undefined'); + } else if (value === null) { + this.emitScalar('null'); + } else if (value.navigator && value.frames && value.setTimeout) { + this.emitScalar(''); + } else if (value instanceof jasmine.Matchers.Any) { + this.emitScalar(value.toString()); + } else if (typeof value === 'string') { + this.emitString(value); + } else if (typeof value === 'function') { + this.emitScalar('Function'); + } else if (typeof value.nodeType === 'number') { + this.emitScalar('HTMLNode'); + } else if (value instanceof Date) { + this.emitScalar('Date(' + value + ')'); + } else if (value.__Jasmine_been_here_before__) { + this.emitScalar(''); + } else if (jasmine.isArray_(value) || typeof value == 'object') { + value.__Jasmine_been_here_before__ = true; + if (jasmine.isArray_(value)) { + this.emitArray(value); + } else { + this.emitObject(value); + } + delete value.__Jasmine_been_here_before__; + } else { + this.emitScalar(value.toString()); + } + } finally { + this.ppNestLevel_--; + } +}; + +jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { + for (var property in obj) { + if (property == '__Jasmine_been_here_before__') continue; + fn(property, obj.__lookupGetter__(property) != null); + } +}; + +jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; + +jasmine.StringPrettyPrinter = function() { + jasmine.PrettyPrinter.call(this); + + this.string = ''; +}; +jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); + +jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { + this.append(value); +}; + +jasmine.StringPrettyPrinter.prototype.emitString = function(value) { + this.append("'" + value + "'"); +}; + +jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + this.append('[ '); + for (var i = 0; i < array.length; i++) { + if (i > 0) { + this.append(', '); + } + this.format(array[i]); + } + this.append(' ]'); +}; + +jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + var self = this; + this.append('{ '); + var first = true; + + this.iterateObject(obj, function(property, isGetter) { + if (first) { + first = false; + } else { + self.append(', '); + } + + self.append(property); + self.append(' : '); + if (isGetter) { + self.append(''); + } else { + self.format(obj[property]); + } + }); + + this.append(' }'); +}; + +jasmine.StringPrettyPrinter.prototype.append = function(value) { + this.string += value; +}; +jasmine.Queue = function(env) { + this.env = env; + this.blocks = []; + this.running = false; + this.index = 0; + this.offset = 0; +}; + +jasmine.Queue.prototype.addBefore = function (block) { + this.blocks.unshift(block); +}; + +jasmine.Queue.prototype.add = function(block) { + this.blocks.push(block); +}; + +jasmine.Queue.prototype.insertNext = function (block) { + this.blocks.splice((this.index + this.offset + 1), 0, block); + this.offset++; +}; + +jasmine.Queue.prototype.start = function(onComplete) { + var self = this; + self.running = true; + self.onComplete = onComplete; + if (self.blocks[0]) { + self.blocks[0].execute(function () { + self._next(); + }); + } else { + self.finish(); + } +}; + +jasmine.Queue.prototype.isRunning = function () { + return this.running; +}; + +jasmine.Queue.prototype._next = function () { + var self = this; + self.env.setTimeout(function () { + self.offset = 0; + self.index++; + if (self.index < self.blocks.length) { + self.blocks[self.index].execute(function () { + self._next(); + }); + } else { + self.finish(); + } + }, 0); +}; + +jasmine.Queue.prototype.finish = function () { + this.running = false; + if (this.onComplete) { + this.onComplete(); + } +}; + +jasmine.Queue.prototype.getResults = function () { + var results = new jasmine.NestedResults(); + for (var i = 0; i < this.blocks.length; i++) { + if (this.blocks[i].getResults) { + results.addResult(this.blocks[i].getResults()); + } + } + return results; +}; + + +/* JasmineReporters.reporter + * Base object that will get called whenever a Spec, Suite, or Runner is done. It is up to + * descendants of this object to do something with the results (see json_reporter.js) + */ +jasmine.Reporters = {}; + +jasmine.Reporters.reporter = function(callbacks) { + var that = { + callbacks: callbacks || {}, + + doCallback: function(callback, results) { + if (callback) { + callback(results); + } + }, + + reportRunnerResults: function(runner) { + that.doCallback(that.callbacks.runnerCallback, runner); + }, + reportSuiteResults: function(suite) { + that.doCallback(that.callbacks.suiteCallback, suite); + }, + reportSpecResults: function(spec) { + that.doCallback(that.callbacks.specCallback, spec); + }, + log: function (str) { + if (console && console.log) console.log(str); + } + }; + + return that; +}; + +/** + * Runner + * + * @constructor + * @param {jasmine.Env} env + */ +jasmine.Runner = function(env) { + var self = this; + self.env = env; + self.queue = new jasmine.Queue(env); + self.suites_ = []; +}; + +jasmine.Runner.prototype.execute = function() { + var self = this; + if (self.env.reporter.reportRunnerStarting) { + self.env.reporter.reportRunnerStarting(this); + } + self.queue.start(function () { + self.finishCallback(); + }); +}; + +jasmine.Runner.prototype.finishCallback = function() { + this.env.reporter.reportRunnerResults(this); +}; + +jasmine.Runner.prototype.addSuite = function(suite) { + this.suites_.push(suite); +}; + +jasmine.Runner.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.addSuite(block); + } + this.queue.add(block); +}; + +/** @deprecated */ +jasmine.Runner.prototype.getAllSuites = function() { + return this.suites_; +}; + + +jasmine.Runner.prototype.suites = function() { + return this.suites_; +}; + +jasmine.Runner.prototype.getResults = function() { + return this.queue.getResults(); +}; +/** + * Internal representation of a Jasmine specification, or test. + * + * @constructor + * @param {jasmine.Env} env + * @param {jasmine.Suite} suite + * @param {String} description + */ +jasmine.Spec = function(env, suite, description) { + var spec = this; + spec.id = env.nextSpecId_++; + spec.env = env; + spec.suite = suite; + spec.description = description; + spec.queue = new jasmine.Queue(env); + + spec.afterCallbacks = []; + spec.spies_ = []; + + spec.results = new jasmine.NestedResults(); + spec.results.description = description; + spec.matchersClass = null; +}; + +jasmine.Spec.prototype.getFullName = function() { + return this.suite.getFullName() + ' ' + this.description + '.'; +}; + +jasmine.Spec.prototype.getResults = function() { + return this.results; +}; + +jasmine.Spec.prototype.runs = function (func) { + var block = new jasmine.Block(this.env, func, this); + this.addToQueue(block); + return this; +}; + +jasmine.Spec.prototype.addToQueue = function (block) { + if (this.queue.isRunning()) { + this.queue.insertNext(block); + } else { + this.queue.add(block); + } +}; + +/** + * @private + * @deprecated + */ +jasmine.Spec.prototype.expects_that = function(actual) { + return this.expect(actual); +}; + +/** + * @private + */ +jasmine.Spec.prototype.expect = function(actual) { + return new (this.getMatchersClass_())(this.env, actual, this.results); +}; + +jasmine.Spec.prototype.waits = function(timeout) { + var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); + this.addToQueue(waitsFunc); + return this; +}; + +jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) { + var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this); + this.addToQueue(waitsForFunc); + return this; +}; + +jasmine.Spec.prototype.failWithException = function (e) { + this.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +}; + +jasmine.Spec.prototype.getMatchersClass_ = function() { + return this.matchersClass || jasmine.Matchers; +}; + +jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { + var parent = this.getMatchersClass_(); + var newMatchersClass = function() { + parent.apply(this, arguments); + }; + jasmine.util.inherit(newMatchersClass, parent); + for (var method in matchersPrototype) { + newMatchersClass.prototype[method] = matchersPrototype[method]; + } + this.matchersClass = newMatchersClass; +}; + +jasmine.Spec.prototype.finishCallback = function() { + this.env.reporter.reportSpecResults(this); +}; + +jasmine.Spec.prototype.finish = function(onComplete) { + this.removeAllSpies(); + this.finishCallback(); + if (onComplete) { + onComplete(); + } +}; + +jasmine.Spec.prototype.after = function(doAfter, test) { + + if (this.queue.isRunning()) { + this.queue.add(new jasmine.Block(this.env, doAfter, this)); + } else { + this.afterCallbacks.unshift(doAfter); + } +}; + +jasmine.Spec.prototype.execute = function(onComplete) { + var spec = this; + if (!spec.env.specFilter(spec)) { + spec.results.skipped = true; + spec.finish(onComplete); + return; + } + this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...'); + + spec.env.currentSpec = spec; + spec.env.currentlyRunningTests = true; + + spec.addBeforesAndAftersToQueue(); + + spec.queue.start(function () { + spec.finish(onComplete); + }); + spec.env.currentlyRunningTests = false; +}; + +jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { + for (var suite = this.suite; suite; suite = suite.parentSuite) { + if (suite.beforeQueue) { + for (var i = 0; i < suite.beforeQueue.length; i++) + this.queue.addBefore(new jasmine.Block(this.env, suite.beforeQueue[i], this)); + } + } + for (i = 0; i < this.afterCallbacks.length; i++) { + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); + } + for (suite = this.suite; suite; suite = suite.parentSuite) { + if (suite.afterQueue) { + for (var j = 0; j < suite.afterQueue.length; j++) + this.queue.add(new jasmine.Block(this.env, suite.afterQueue[j], this)); + } + } +}; + +jasmine.Spec.prototype.explodes = function() { + throw 'explodes function should not have been called'; +}; + +jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { + if (obj == undefined) { + throw "spyOn could not find an object to spy upon for " + methodName + "()"; + } + + if (!ignoreMethodDoesntExist && obj[methodName] === undefined) { + throw methodName + '() method does not exist'; + } + + if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { + throw new Error(methodName + ' has already been spied upon'); + } + + var spyObj = jasmine.createSpy(methodName); + + this.spies_.push(spyObj); + spyObj.baseObj = obj; + spyObj.methodName = methodName; + spyObj.originalValue = obj[methodName]; + + obj[methodName] = spyObj; + + return spyObj; +}; + +jasmine.Spec.prototype.removeAllSpies = function() { + for (var i = 0; i < this.spies_.length; i++) { + var spy = this.spies_[i]; + spy.baseObj[spy.methodName] = spy.originalValue; + } + this.spies_ = []; +}; + +/** + * Internal representation of a Jasmine suite. + * + * @constructor + * @param {jasmine.Env} env + * @param {String} description + * @param {Function} specDefinitions + * @param {jasmine.Suite} parentSuite + */ +jasmine.Suite = function(env, description, specDefinitions, parentSuite) { + var self = this; + self.id = env.nextSuiteId_++; + self.description = description; + self.queue = new jasmine.Queue(env); + self.parentSuite = parentSuite; + self.env = env; + self.beforeQueue = []; + self.afterQueue = []; + self.specs_ = []; +}; + +jasmine.Suite.prototype.getFullName = function() { + var fullName = this.description; + for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { + fullName = parentSuite.description + ' ' + fullName; + } + return fullName; +}; + +jasmine.Suite.prototype.finish = function(onComplete) { + this.env.reporter.reportSuiteResults(this); + this.finished = true; + if (typeof(onComplete) == 'function') { + onComplete(); + } +}; + +jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { + beforeEachFunction.typeName = 'beforeEach'; + this.beforeQueue.push(beforeEachFunction); +}; + +jasmine.Suite.prototype.afterEach = function(afterEachFunction) { + afterEachFunction.typeName = 'afterEach'; + this.afterQueue.push(afterEachFunction); +}; + +jasmine.Suite.prototype.getResults = function() { + return this.queue.getResults(); +}; + +jasmine.Suite.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.env.currentRunner.addSuite(block); + } else { + this.specs_.push(block); + } + this.queue.add(block); +}; + +/** @deprecated */ +jasmine.Suite.prototype.specCount = function() { + return this.specs_.length; +}; + +jasmine.Suite.prototype.specs = function() { + return this.specs_; +}; + +jasmine.Suite.prototype.execute = function(onComplete) { + var self = this; + this.queue.start(function () { + self.finish(onComplete); + }); +}; +jasmine.WaitsBlock = function(env, timeout, spec) { + this.timeout = timeout; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); + +jasmine.WaitsBlock.prototype.execute = function (onComplete) { + this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); + this.env.setTimeout(function () { + onComplete(); + }, this.timeout); +}; +jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { + this.timeout = timeout; + this.latchFunction = latchFunction; + this.message = message; + this.totalTimeSpentWaitingForLatch = 0; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); + +jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100; + +jasmine.WaitsForBlock.prototype.execute = function (onComplete) { + var self = this; + self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen')); + var latchFunctionResult; + try { + latchFunctionResult = self.latchFunction.apply(self.spec); + } catch (e) { + self.fail(e); + onComplete(); + return; + } + + if (latchFunctionResult) { + onComplete(); + } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { + var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen'); + self.fail({ + 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 @@ -1370,650 +2022,3 @@ window.clearInterval = function(timeoutKey) { return jasmine.Clock.installed.clearInterval.apply(this, arguments); }; -/** - * @constructor - */ -jasmine.MultiReporter = function() { - this.subReporters_ = []; -}; -jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); - -jasmine.MultiReporter.prototype.addReporter = function(reporter) { - this.subReporters_.push(reporter); -}; - -(function() { - var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"]; - for (var i = 0; i < functionNames.length; i++) { - var functionName = functionNames[i]; - jasmine.MultiReporter.prototype[functionName] = (function(functionName) { - return function() { - for (var j = 0; j < this.subReporters_.length; j++) { - var subReporter = this.subReporters_[j]; - if (subReporter[functionName]) { - subReporter[functionName].apply(subReporter, arguments); - } - } - }; - })(functionName); - } -})(); -/** - * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults - * - * @constructor - */ -jasmine.NestedResults = function() { - /** - * The total count of results - */ - this.totalCount = 0; - /** - * Number of passed results - */ - this.passedCount = 0; - /** - * Number of failed results - */ - this.failedCount = 0; - /** - * Was this suite/spec skipped? - */ - this.skipped = false; - /** - * @ignore - */ - this.items_ = []; -}; - -/** - * Roll up the result counts. - * - * @param result - */ -jasmine.NestedResults.prototype.rollupCounts = function(result) { - this.totalCount += result.totalCount; - this.passedCount += result.passedCount; - this.failedCount += result.failedCount; -}; - -/** - * Tracks a result's message. - * @param message - */ -jasmine.NestedResults.prototype.log = function(message) { - this.items_.push(new jasmine.MessageResult(message)); -}; - -/** - * Getter for the results: message & results. - */ -jasmine.NestedResults.prototype.getItems = function() { - return this.items_; -}; - -/** - * Adds a result, tracking counts (total, passed, & failed) - * @param {jasmine.ExpectationResult|jasmine.NestedResults} result - */ -jasmine.NestedResults.prototype.addResult = function(result) { - if (result.type != 'MessageResult') { - if (result.items_) { - this.rollupCounts(result); - } else { - this.totalCount++; - if (result.passed) { - this.passedCount++; - } else { - this.failedCount++; - } - } - } - this.items_.push(result); -}; - -/** - * @returns {Boolean} True if everything below passed - */ -jasmine.NestedResults.prototype.passed = function() { - return this.passedCount === this.totalCount; -}; -/** - * Base class for pretty printing for expectation results. - */ -jasmine.PrettyPrinter = function() { - this.ppNestLevel_ = 0; -}; - -/** - * Formats a value in a nice, human-readable string. - * - * @param value - * @returns {String} - */ -jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - // return '(jasmine.pp nested too deeply!)'; - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - - this.ppNestLevel_++; - try { - if (value === undefined) { - this.emitScalar('undefined'); - } else if (value === null) { - this.emitScalar('null'); - } else if (value.navigator && value.frames && value.setTimeout) { - this.emitScalar(''); - } else if (value instanceof jasmine.Matchers.Any) { - this.emitScalar(value.toString()); - } else if (typeof value === 'string') { - this.emitScalar("'" + value + "'"); - } else if (typeof value === 'function') { - this.emitScalar('Function'); - } else if (typeof value.nodeType === 'number') { - this.emitScalar('HTMLNode'); - } else if (value instanceof Date) { - this.emitScalar('Date(' + value + ')'); - } else if (value.__Jasmine_been_here_before__) { - this.emitScalar(''); - } else if (jasmine.isArray_(value) || typeof value == 'object') { - value.__Jasmine_been_here_before__ = true; - if (jasmine.isArray_(value)) { - this.emitArray(value); - } else { - this.emitObject(value); - } - delete value.__Jasmine_been_here_before__; - } else { - this.emitScalar(value.toString()); - } - } finally { - this.ppNestLevel_--; - } -}; - -jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { - for (var property in obj) { - if (property == '__Jasmine_been_here_before__') continue; - fn(property, obj.__lookupGetter__(property) != null); - } -}; - -jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; - -jasmine.StringPrettyPrinter = function() { - jasmine.PrettyPrinter.call(this); - - this.string = ''; -}; -jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); - -jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { - this.append(value); -}; - -jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { - this.append('[ '); - for (var i = 0; i < array.length; i++) { - if (i > 0) { - this.append(', '); - } - this.format(array[i]); - } - this.append(' ]'); -}; - -jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { - var self = this; - this.append('{ '); - var first = true; - - this.iterateObject(obj, function(property, isGetter) { - if (first) { - first = false; - } else { - self.append(', '); - } - - self.append(property); - self.append(' : '); - if (isGetter) { - self.append(''); - } else { - self.format(obj[property]); - } - }); - - this.append(' }'); -}; - -jasmine.StringPrettyPrinter.prototype.append = function(value) { - this.string += value; -}; -/** - * QueuedFunction is how ActionCollections' actions are implemented - * - * @constructor - * @param {jasmine.Env} env - * @param {Function} func - * @param {Number} timeout - * @param {Function} latchFunction - * @param {jasmine.Spec} spec - */ -jasmine.QueuedFunction = function(env, func, timeout, latchFunction, spec) { - this.env = env; - this.func = func; - this.timeout = timeout; - this.latchFunction = latchFunction; - this.spec = spec; - - this.totalTimeSpentWaitingForLatch = 0; - this.latchTimeoutIncrement = 100; -}; - -jasmine.QueuedFunction.prototype.next = function() { - this.spec.finish(); // default value is to be done after one function -}; - -jasmine.QueuedFunction.prototype.safeExecute = function() { - this.env.reporter.log('>> Jasmine Running ' + this.spec.suite.description + ' ' + this.spec.description + '...'); - - try { - this.func.apply(this.spec); - } catch (e) { - this.fail(e); - } -}; - -jasmine.QueuedFunction.prototype.execute = function() { - var self = this; - var executeNow = function() { - self.safeExecute(); - self.next(); - }; - - var executeLater = function() { - self.env.setTimeout(executeNow, self.timeout); - }; - - var executeNowOrLater = function() { - var latchFunctionResult; - - try { - latchFunctionResult = self.latchFunction.apply(self.spec); - } catch (e) { - self.fail(e); - self.next(); - return; - } - - if (latchFunctionResult) { - executeNow(); - } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { - var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.latchFunction.description || 'something to happen'); - self.fail({ - name: 'timeout', - message: message - }); - self.next(); - } else { - self.totalTimeSpentWaitingForLatch += self.latchTimeoutIncrement; - self.env.setTimeout(executeNowOrLater, self.latchTimeoutIncrement); - } - }; - - if (this.latchFunction !== undefined) { - executeNowOrLater(); - } else if (this.timeout > 0) { - executeLater(); - } else { - executeNow(); - } -}; - -jasmine.QueuedFunction.prototype.fail = function(e) { - this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); -}; -/* JasmineReporters.reporter - * Base object that will get called whenever a Spec, Suite, or Runner is done. It is up to - * descendants of this object to do something with the results (see json_reporter.js) - */ -jasmine.Reporters = {}; - -jasmine.Reporters.reporter = function(callbacks) { - var that = { - callbacks: callbacks || {}, - - doCallback: function(callback, results) { - if (callback) { - callback(results); - } - }, - - reportRunnerResults: function(runner) { - that.doCallback(that.callbacks.runnerCallback, runner); - }, - reportSuiteResults: function(suite) { - that.doCallback(that.callbacks.suiteCallback, suite); - }, - reportSpecResults: function(spec) { - that.doCallback(that.callbacks.specCallback, spec); - }, - log: function (str) { - if (console && console.log) console.log(str); - } - }; - - return that; -}; - -/** - * Runner - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.Runner = function(env) { - jasmine.ActionCollection.call(this, env); - - this.suites = this.actions; -}; -jasmine.util.inherit(jasmine.Runner, jasmine.ActionCollection); - -jasmine.Runner.prototype.execute = function() { - if (this.env.reporter.reportRunnerStarting) { - this.env.reporter.reportRunnerStarting(this); - } - jasmine.ActionCollection.prototype.execute.call(this); -}; - -jasmine.Runner.prototype.finishCallback = function() { - this.env.reporter.reportRunnerResults(this); -}; - -jasmine.Runner.prototype.getAllSuites = function() { - var suitesToReturn = []; - - function addSuite(suite) { - suitesToReturn.push(suite); - - for (var j = 0; j < suite.specs.length; j++) { - var spec = suite.specs[j]; - if (spec instanceof jasmine.Suite) { - addSuite(spec); - } - } - } - - for (var i = 0; i < this.suites.length; i++) { - var suite = this.suites[i]; - addSuite(suite); - } - - return suitesToReturn; -}; - -jasmine.Runner.prototype.getResults = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.suites.length; i++) { - results.rollupCounts(this.suites[i].getResults()); - } - return results; -}; -/** - * Internal representation of a Jasmine specification, or test. - * - * @constructor - * @param {jasmine.Env} env - * @param {jasmine.Suite} suite - * @param {String} description - */ -jasmine.Spec = function(env, suite, description) { - this.id = env.nextSpecId_++; - this.env = env; - this.suite = suite; - this.description = description; - this.queue = []; - this.currentTimeout = 0; - this.currentLatchFunction = undefined; - this.finished = false; - this.afterCallbacks = []; - this.spies_ = []; - - this.results = new jasmine.NestedResults(); - this.results.description = description; - this.runs = this.addToQueue; - this.matchersClass = null; -}; - -jasmine.Spec.prototype.getFullName = function() { - return this.suite.getFullName() + ' ' + this.description + '.'; -}; - -jasmine.Spec.prototype.getResults = function() { - return this.results; -}; - -jasmine.Spec.prototype.addToQueue = function(func) { - var queuedFunction = new jasmine.QueuedFunction(this.env, func, this.currentTimeout, this.currentLatchFunction, this); - this.queue.push(queuedFunction); - - if (this.queue.length > 1) { - var previousQueuedFunction = this.queue[this.queue.length - 2]; - previousQueuedFunction.next = function() { - queuedFunction.execute(); - }; - } - - this.resetTimeout(); - return this; -}; - -/** - * @private - * @deprecated - */ -jasmine.Spec.prototype.expects_that = function(actual) { - return this.expect(actual); -}; - -/** - * @private - */ -jasmine.Spec.prototype.expect = function(actual) { - return new (this.getMatchersClass_())(this.env, actual, this.results); -}; - -/** - * @private - */ -jasmine.Spec.prototype.waits = function(timeout) { - this.currentTimeout = timeout; - this.currentLatchFunction = undefined; - return this; -}; - -/** - * @private - */ -jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, message) { - this.currentTimeout = timeout; - this.currentLatchFunction = latchFunction; - this.currentLatchFunction.description = message; - return this; -}; - -jasmine.Spec.prototype.getMatchersClass_ = function() { - return this.matchersClass || jasmine.Matchers; -}; - -jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { - var parent = this.getMatchersClass_(); - var newMatchersClass = function() { - parent.apply(this, arguments); - }; - jasmine.util.inherit(newMatchersClass, parent); - for (var method in matchersPrototype) { - newMatchersClass.prototype[method] = matchersPrototype[method]; - } - this.matchersClass = newMatchersClass; -}; - -jasmine.Spec.prototype.resetTimeout = function() { - this.currentTimeout = 0; - this.currentLatchFunction = undefined; -}; - -jasmine.Spec.prototype.finishCallback = function() { - this.env.reporter.reportSpecResults(this); -}; - -jasmine.Spec.prototype.finish = function() { - this.safeExecuteAfters(); - - this.removeAllSpies(); - this.finishCallback(); - this.finished = true; -}; - -jasmine.Spec.prototype.after = function(doAfter) { - this.afterCallbacks.unshift(doAfter); -}; - -jasmine.Spec.prototype.execute = function() { - if (!this.env.specFilter(this)) { - this.results.skipped = true; - this.finishCallback(); - this.finished = true; - return; - } - - this.env.currentSpec = this; - this.env.currentlyRunningTests = true; - - this.safeExecuteBefores(); - - if (this.queue[0]) { - this.queue[0].execute(); - } else { - this.finish(); - } - this.env.currentlyRunningTests = false; -}; - -jasmine.Spec.prototype.safeExecuteBefores = function() { - var befores = []; - for (var suite = this.suite; suite; suite = suite.parentSuite) { - if (suite.beforeEachFunction) befores.push(suite.beforeEachFunction); - } - - while (befores.length) { - this.safeExecuteBeforeOrAfter(befores.pop()); - } -}; - -jasmine.Spec.prototype.safeExecuteAfters = function() { - for (var suite = this.suite; suite; suite = suite.parentSuite) { - if (suite.afterEachFunction) this.safeExecuteBeforeOrAfter(suite.afterEachFunction); - } -}; - -jasmine.Spec.prototype.safeExecuteBeforeOrAfter = function(func) { - try { - func.apply(this); - } catch (e) { - this.results.addResult(new jasmine.ExpectationResult(false, func.typeName + '() fail: ' + jasmine.util.formatException(e), null)); - } -}; - -jasmine.Spec.prototype.explodes = function() { - throw 'explodes function should not have been called'; -}; - -jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { - if (obj == undefined) { - throw "spyOn could not find an object to spy upon for " + methodName + "()"; - } - - if (!ignoreMethodDoesntExist && obj[methodName] === undefined) { - throw methodName + '() method does not exist'; - } - - if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { - throw new Error(methodName + ' has already been spied upon'); - } - - var spyObj = jasmine.createSpy(methodName); - - this.spies_.push(spyObj); - spyObj.baseObj = obj; - spyObj.methodName = methodName; - spyObj.originalValue = obj[methodName]; - - obj[methodName] = spyObj; - - return spyObj; -}; - -jasmine.Spec.prototype.removeAllSpies = function() { - for (var i = 0; i < this.spies_.length; i++) { - var spy = this.spies_[i]; - spy.baseObj[spy.methodName] = spy.originalValue; - } - this.spies_ = []; -}; - -/** - * Internal representation of a Jasmine suite. - * - * @constructor - * @param {jasmine.Env} env - * @param {String} description - * @param {Function} specDefinitions - * @param {jasmine.Suite} parentSuite - */ -jasmine.Suite = function(env, description, specDefinitions, parentSuite) { - jasmine.ActionCollection.call(this, env); - - this.description = description; - this.specs = this.actions; - this.parentSuite = parentSuite; - - this.beforeEachFunction = null; - this.afterEachFunction = null; -}; -jasmine.util.inherit(jasmine.Suite, jasmine.ActionCollection); - -jasmine.Suite.prototype.getFullName = function() { - var fullName = this.description; - for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { - fullName = parentSuite.description + ' ' + fullName; - } - return fullName; -}; - -jasmine.Suite.prototype.finishCallback = function() { - this.env.reporter.reportSuiteResults(this); -}; - -jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.beforeEachFunction = beforeEachFunction; -}; - -jasmine.Suite.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.afterEachFunction = afterEachFunction; -}; - -jasmine.Suite.prototype.getResults = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.specs.length; i++) { - results.rollupCounts(this.specs[i].getResults()); - } - return results; -}; - diff --git a/lib/jasmine.css b/lib/jasmine.css index fce53e3c..71a8c960 100644 --- a/lib/jasmine.css +++ b/lib/jasmine.css @@ -84,4 +84,9 @@ p { .runSpec { margin-left: 5px; float: right; +} + +#jasmine_content { + position:fixed; + left: 100%; } \ No newline at end of file diff --git a/spec/bootstrap.html b/spec/bootstrap.html deleted file mode 100755 index c47b3b12..00000000 --- a/spec/bootstrap.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - Jasmine Tests - - - - - - - - - - - - - - - - - - - - - - - -

    - Running all Jasmine Test Suites -

    -
    - - -
    -
    - - -
    - - - - - - diff --git a/spec/bootstrap.js b/spec/bootstrap.js deleted file mode 100755 index 3c286e88..00000000 --- a/spec/bootstrap.js +++ /dev/null @@ -1,146 +0,0 @@ -var createElement = function(tag, attrs) { - var element = document.createElement(tag); - for (var attr in attrs) { - element[attr] = attrs[attr]; - } - return element; -}; - -// Bootstrap Test Reporter function -var Reporter = function () { - this.total = 0; - this.passes = 0; - this.fails = 0; - this.start = new Date(); -}; - -Reporter.prototype.toJSON = function(object) { - return JSON.stringify(object); -}; - -Reporter.prototype.test = function (result, message) { - this.total++; - - if (result) { - this.passes++; - iconElement = document.getElementById('icons'); - iconElement.appendChild(createElement('img', {src: '../images/go-16.png'})); - } - else { - this.fails++; - var fails_report = document.getElementById('fails'); - fails_report.style.display = ""; - - var iconElement = document.getElementById('icons'); - iconElement.appendChild(createElement('img', {src: '../images/fail-16.png'})); - - var failMessages = document.getElementById('fail_messages'); - var newFail = createElement('p', {'class': 'fail'}); - newFail.innerHTML = message; - failMessages.appendChild(newFail); - } -}; - -Reporter.prototype.summary = function () { - var el = createElement('p', {'class': ((this.fails > 0) ? 'failInSummary' : '') }); - el.innerHTML = this.total + ' expectations, ' + this.passes + ' passing, ' + this.fails + ' failed in ' + (new Date().getTime() - this.start.getTime()) + "ms."; - - var summaryElement = document.getElementById('results_summary'); - summaryElement.appendChild(el); - summaryElement.style.display = ""; -}; - - -var reporter = new Reporter(); - -function runSuite(filename) { - console.log(filename); - var suite = jasmine.include(filename); - suite.execute(); - emitSuiteResults(filename, suite); -} - -function emitSpecResults(testName, spec) { - var results = spec.results.getItems(); - reporter.test(results.length > 0, testName + ": should have results, got " + results.length); - - for (var i = 0; i < results.length; i++) { - reporter.test(results[i].passed === true, testName + ':' + spec.getFullName() + ": expectation number " + i + " failed: " + results[i].message); - } -} - -function emitSuiteResults(testName, suite) { - for (var j = 0; j < suite.specs.length; j++) { - var specOrSuite = suite.specs[j]; - - if (specOrSuite instanceof jasmine.Suite) { - emitSuiteResults(testName, specOrSuite); - } else { - emitSpecResults(testName, specOrSuite); - } - } -} - -var testExplodes = function () { - var suite = describe('exploding', function () { - it('should throw an exception when this.explodes is called inside a spec', function() { - var exceptionMessage = false; - - try { - this.explodes(); - } - catch (e) { - exceptionMessage = e; - } - expect(exceptionMessage).toEqual('explodes function should not have been called'); - }); - - }); - suite.execute(); - - emitSuiteResults('testExplodes', suite); -}; - -function newJasmineEnv() { - return new jasmine.Env(); -} - -var testRunner = function() { -}; - -var testRunnerFinishCallback = function () { - var env = newJasmineEnv(); - var foo = 0; - - env.currentRunner.finish(); - - reporter.test((env.currentRunner.finished === true), - "Runner finished flag was not set."); - - env.currentRunner.finishCallback = function () { - foo++; - }; - - env.currentRunner.finish(); - - reporter.test((env.currentRunner.finished === true), - "Runner finished flag was not set."); - reporter.test((foo === 1), - "Runner finish callback was not called"); -}; - -var runTests = function () { - document.getElementById('spinner').style.display = ""; - - runSuite('suites/PrettyPrintTest.js'); - runSuite('suites/MatchersTest.js'); - runSuite('suites/SpecRunningTest.js'); - runSuite('suites/NestedResultsTest.js'); - runSuite('suites/ReporterTest.js'); - runSuite('suites/RunnerTest.js'); - runSuite('suites/SpyTest.js'); - runSuite('suites/ExceptionsTest.js'); - - reporter.summary(); - document.getElementById('spinner').style.display = "none"; -}; \ No newline at end of file diff --git a/spec/jasmine_spec.rb b/spec/jasmine_spec.rb new file mode 100644 index 00000000..06e3b403 --- /dev/null +++ b/spec/jasmine_spec.rb @@ -0,0 +1,32 @@ +require 'rubygems' +require File.expand_path(File.join(File.dirname(__FILE__), "../contrib/ruby/jasmine_spec_builder")) +require "selenium_rc" + +dir_mappings = { + "/spec" => 'spec', + "/lib" => 'lib', + "/src" => 'src' +} + +def jasmine_sources + sources = ["src/base.js", "src/util.js", "src/Env.js", "src/Reporter.js", "src/Block.js"] + + sources += Dir.glob('src/*.js').reject{|f| f == 'src/base.js' || sources.include?(f)}.sort +end + +includes = jasmine_sources + ['lib/json2.js', 'lib/TrivialReporter.js'] +spec_files = Dir.glob("spec/**/*[Ss]pec.js") +jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path, includes + spec_files, dir_mappings) +spec_builder = Jasmine::SpecBuilder.new(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 diff --git a/spec/runner.html b/spec/runner.html index 3f683740..b6dac934 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -3,45 +3,45 @@ Jasmine Test Runner + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - @@ -49,8 +49,14 @@ var jasmineEnv = jasmine.getEnv(); - jasmineEnv.addReporter(new jasmine.TrivialReporter()); - jasmineEnv.execute(); + var trivialReporter = new jasmine.TrivialReporter(); + jasmineEnv.addReporter(trivialReporter); + jasmineEnv.specFilter = function(spec) { + return trivialReporter.specFilter(spec); + }; + window.onload = function() { + jasmineEnv.execute(); + }; diff --git a/spec/suites/EnvSpec.js b/spec/suites/EnvSpec.js new file mode 100644 index 00000000..3a05d3c5 --- /dev/null +++ b/spec/suites/EnvSpec.js @@ -0,0 +1,58 @@ +describe("jasmine.Env", function() { + describe("reporting", function() { + var env; + var fakeReporter; + + beforeEach(function() { + env = new jasmine.Env(); + fakeReporter = jasmine.createSpyObj("fakeReporter", ["log"]); + }); + + describe('version', function () { + var oldVersion; + + beforeEach(function () { + oldVersion = jasmine.version_; + }); + + afterEach(function () { + jasmine.version_ = oldVersion; + }); + + it('should raise an error if version is not set', function () { + jasmine.version_ = null; + var exception; + try { + env.version(); + } + catch (e) { + exception = e; + } + expect(exception.message).toEqual('Version not set'); + + }); + + it("version should return the current version as an int", function() { + jasmine.version_ = { + "major": 1, + "minor": 9, + "build": 7, + "revision": 8 + }; + expect(env.version()).toEqual({ + "major": 1, + "minor": 9, + "build": 7, + "revision": 8 + }); + + }); + }); + + it("should allow reporters to be registered", function() { + env.addReporter(fakeReporter); + env.reporter.log("message"); + expect(fakeReporter.log).wasCalledWith("message"); + }); + }); +}); \ No newline at end of file diff --git a/spec/suites/EnvTest.js b/spec/suites/EnvTest.js deleted file mode 100644 index 62676ae5..00000000 --- a/spec/suites/EnvTest.js +++ /dev/null @@ -1,17 +0,0 @@ -describe("jasmine.Env", function() { - describe("reporting", function() { - var env; - var fakeReporter; - - beforeEach(function() { - env = new jasmine.Env(); - fakeReporter = jasmine.createSpyObj("fakeReporter", ["log"]); - }); - - it("should allow reporters to be registered", function() { - env.addReporter(fakeReporter); - env.reporter.log("message"); - expect(fakeReporter.log).wasCalledWith("message"); - }); - }); -}); \ No newline at end of file diff --git a/spec/suites/ExceptionsTest.js b/spec/suites/ExceptionsSpec.js similarity index 72% rename from spec/suites/ExceptionsTest.js rename to spec/suites/ExceptionsSpec.js index 8fc4e9c2..9b9e5e20 100644 --- a/spec/suites/ExceptionsTest.js +++ b/spec/suites/ExceptionsSpec.js @@ -74,25 +74,33 @@ describe('Exceptions:', function() { var runner = env.currentRunner; suite.execute(); - fakeTimer.tick(300); //TODO: setting this to a large number causes failures, but shouldn't + fakeTimer.tick(2500); - var resultsForSpec0 = suite.specs[0].getResults(); - var resultsForSpec1 = suite.specs[1].getResults(); - var resultsForSpec2 = suite.specs[2].getResults(); - var resultsForSpec3 = suite.specs[3].getResults(); - - expect(suite.getResults().totalCount).toEqual(6); - expect(resultsForSpec0.getItems()[0].passed).toEqual(false); - expect(resultsForSpec0.getItems()[0].message).toMatch(/fake error 1/); + var suiteResults = suite.getResults(); + var specResults = suiteResults.getItems(); - expect(resultsForSpec1.getItems()[0].passed).toEqual(false), - expect(resultsForSpec1.getItems()[0].message).toMatch(/fake error 2/), - expect(resultsForSpec1.getItems()[1].passed).toEqual(true); + expect(suiteResults.passed()).toEqual(false); - expect(resultsForSpec2.getItems()[0].passed).toEqual(true); + expect(specResults.length).toEqual(5); + expect(specResults[0].passed()).toMatch(false); + var blockResults = specResults[0].getItems(); + expect(blockResults[0].passed()).toEqual(false); + expect(blockResults[0].message).toMatch(/fake error 1/); + + expect(specResults[1].passed()).toEqual(false); + var blockResults = specResults[1].getItems(); + expect(blockResults[0].passed()).toEqual(false); + expect(blockResults[0].message).toMatch(/fake error 2/), + expect(blockResults[1].passed()).toEqual(true); + + expect(specResults[2].passed()).toEqual(true); + + expect(specResults[3].passed()).toEqual(false); + blockResults = specResults[3].getItems(); + expect(blockResults[0].message).toMatch(/fake error 3/); + + expect(specResults[4].passed()).toEqual(true); - expect(resultsForSpec3.getItems()[0].passed).toEqual(false); - expect(resultsForSpec3.getItems()[0].message).toMatch(/fake error 3/); }); }); \ No newline at end of file diff --git a/spec/suites/MatchersTest.js b/spec/suites/MatchersSpec.js similarity index 97% rename from spec/suites/MatchersTest.js rename to spec/suites/MatchersSpec.js index 5199ae0e..91fcd17f 100644 --- a/spec/suites/MatchersTest.js +++ b/spec/suites/MatchersSpec.js @@ -222,7 +222,7 @@ describe("jasmine.Matchers", function() { expected = match(TestClass.someFunction); expect(expected.wasCalledWith('c', 'b', 'a')).toEqual(false); - expect(expected.getResults().getItems()[0].passed).toEqual(false); + expect(expected.getResults().getItems()[0].passed()).toEqual(false); TestClass.someFunction.reset(); TestClass.someFunction('a', 'b', 'c'); @@ -245,9 +245,9 @@ describe("jasmine.Matchers", function() { expect(results.getItems().length).toEqual(2); - expect(results.getItems()[0].passed).toEqual(true); + expect(results.getItems()[0].passed()).toEqual(true); - expect(results.getItems()[1].passed).toEqual(false); + expect(results.getItems()[1].passed()).toEqual(false); results = new jasmine.NestedResults(); expected = new jasmine.Matchers(env, false, results); @@ -297,17 +297,17 @@ describe("jasmine.Matchers", function() { expected = new jasmine.Matchers(env, [1, 2, 3], results); results.getItems().length = 0; expected.toEqual([1, 2, 3]); - expect(results.getItems()[0].passed).toEqual(true); + expect(results.getItems()[0].passed()).toEqual(true); expected = new jasmine.Matchers(env, [1, 2, 3], results); results.getItems().length = 0; expected.toEqual([{}, {}, {}]); - expect(results.getItems()[0].passed).toEqual(false); + expect(results.getItems()[0].passed()).toEqual(false); expected = new jasmine.Matchers(env, [{}, {}, {}], results); results.getItems().length = 0; expected.toEqual([1, 2, 3]); - expect(results.getItems()[0].passed).toEqual(false); + expect(results.getItems()[0].passed()).toEqual(false); }); }); diff --git a/spec/suites/MultiReporterTest.js b/spec/suites/MultiReporterSpec.js similarity index 100% rename from spec/suites/MultiReporterTest.js rename to spec/suites/MultiReporterSpec.js diff --git a/spec/suites/NestedResultsTest.js b/spec/suites/NestedResultsSpec.js similarity index 71% rename from spec/suites/NestedResultsTest.js rename to spec/suites/NestedResultsSpec.js index ca3de81c..e460d7aa 100644 --- a/spec/suites/NestedResultsTest.js +++ b/spec/suites/NestedResultsSpec.js @@ -3,14 +3,14 @@ describe('jasmine.NestedResults', function() { // Leaf case var results = new jasmine.NestedResults(); - results.addResult({passed: true, message: 'Passed.'}); + results.addResult(new jasmine.ExpectationResult(true,'Passed.')); expect(results.getItems().length).toEqual(1); expect(results.totalCount).toEqual(1); expect(results.passedCount).toEqual(1); expect(results.failedCount).toEqual(0); - results.addResult({passed: false, message: 'FAIL.'}); + results.addResult(new jasmine.ExpectationResult(false, 'FAIL.')); expect(results.getItems().length).toEqual(2); expect(results.totalCount).toEqual(2); @@ -21,12 +21,12 @@ describe('jasmine.NestedResults', function() { it('should roll up counts for nested results', function() { // Branch case var leafResultsOne = new jasmine.NestedResults(); - leafResultsOne.addResult({passed: true, message: ''}); - leafResultsOne.addResult({passed: false, message: ''}); + leafResultsOne.addResult(new jasmine.ExpectationResult( true, '')); + leafResultsOne.addResult(new jasmine.ExpectationResult( false, '')); var leafResultsTwo = new jasmine.NestedResults(); - leafResultsTwo.addResult({passed: true, message: ''}); - leafResultsTwo.addResult({passed: false, message: ''}); + leafResultsTwo.addResult(new jasmine.ExpectationResult( true, '')); + leafResultsTwo.addResult(new jasmine.ExpectationResult( false, '')); var branchResults = new jasmine.NestedResults(); branchResults.addResult(leafResultsOne); diff --git a/spec/suites/PrettyPrintTest.js b/spec/suites/PrettyPrintSpec.js similarity index 100% rename from spec/suites/PrettyPrintTest.js rename to spec/suites/PrettyPrintSpec.js diff --git a/spec/suites/ReporterTest.js b/spec/suites/ReporterSpec.js similarity index 81% rename from spec/suites/ReporterTest.js rename to spec/suites/ReporterSpec.js index e1e4dc29..4ceeccb2 100644 --- a/spec/suites/ReporterTest.js +++ b/spec/suites/ReporterSpec.js @@ -1,11 +1,19 @@ describe('jasmine.Reporter', function() { var env; + var fakeTimer; + beforeEach(function() { env = new jasmine.Env(); + + fakeTimer = new jasmine.FakeTimer(); + env.setTimeout = fakeTimer.setTimeout; + env.clearTimeout = fakeTimer.clearTimeout; + env.setInterval = fakeTimer.setInterval; + env.clearInterval = fakeTimer.clearInterval; }); - it('should ', function() { + it('should get called from the test runner', function() { env.describe('Suite for JSON Reporter with Callbacks', function () { env.it('should be a test', function() { this.runs(function () { @@ -49,6 +57,7 @@ describe('jasmine.Reporter', function() { var runner = env.currentRunner; runner.execute(); + fakeTimer.tick(0); expect(foo).toEqual(3); // 'foo was expected to be 3, was ' + foo); expect(bar).toEqual(2); // 'bar was expected to be 2, was ' + bar); diff --git a/spec/suites/RunnerSpec.js b/spec/suites/RunnerSpec.js new file mode 100644 index 00000000..c2404eaa --- /dev/null +++ b/spec/suites/RunnerSpec.js @@ -0,0 +1,164 @@ +describe('RunnerTest', function() { + var fakeTimer; + var env; + + beforeEach(function() { + env = new jasmine.Env(); + + fakeTimer = new jasmine.FakeTimer(); + env.setTimeout = fakeTimer.setTimeout; + env.clearTimeout = fakeTimer.clearTimeout; + env.setInterval = fakeTimer.setInterval; + env.clearInterval = fakeTimer.clearInterval; + }); + + it('should run child suites and specs and generate results when execute is called', function() { + env.describe('one suite description', function () { + env.it('should be a test', function() { + this.runs(function () { + this.expect(true).toEqual(true); + }); + }); + }); + + env.describe('another suite description', function () { + env.it('should be another test', function() { + this.runs(function () { + this.expect(true).toEqual(false); + }); + }); + }); + + env.currentRunner.execute(); + fakeTimer.tick(0); + + var runnerResults = env.currentRunner.getResults(); + expect(runnerResults.totalCount).toEqual(2); + expect(runnerResults.passedCount).toEqual(1); + expect(runnerResults.failedCount).toEqual(1); + }); + + + it('should ignore suites that have been x\'d', function() { + env.xdescribe('one suite description', function () { + env.it('should be a test', function() { + this.runs(function () { + this.expect(true).toEqual(true); + }); + }); + }); + + env.describe('another suite description', function () { + env.it('should be another test', function() { + this.runs(function () { + this.expect(true).toEqual(false); + }); + }); + }); + + env.currentRunner.execute(); + fakeTimer.tick(0); + + var runnerResults = env.currentRunner.getResults(); + expect(runnerResults.totalCount).toEqual(1); + expect(runnerResults.passedCount).toEqual(0); + expect(runnerResults.failedCount).toEqual(1); + }); + + it('should roll up results from all specs', function() { + env.describe('one suite description', function () { + env.it('should be a test', function() { + this.runs(function () { + this.expect(true).toEqual(true); + }); + }); + }); + + env.describe('another suite description', function () { + env.it('should be another test', function() { + this.runs(function () { + this.expect(true).toEqual(false); + }); + }); + }); + + env.currentRunner.execute(); + fakeTimer.tick(0); + + var results = env.currentRunner.getResults(); + expect(results.totalCount).toEqual(2); + expect(results.passedCount).toEqual(1); + expect(results.failedCount).toEqual(1); + }); + + describe('reporting', function () { + var fakeReporter; + beforeEach(function () { + fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); + env.addReporter(fakeReporter); + }); + + it('should report runner results when the runner has completed running', function() { + env.describe('one suite description', function () { + env.it('should be a test', function() { + this.runs(function () { + this.expect(true).toEqual(true); + }); + }); + }); + + env.describe('another suite description', function () { + env.it('should be another test', function() { + this.waits(200); + this.runs(function () { + this.expect(true).toEqual(false); + }); + }); + }); + + env.currentRunner.execute(); + expect(fakeReporter.reportRunnerResults).wasNotCalled(); + fakeTimer.tick(200); + //This blows up the JSApiReporter. + //expect(fakeReporter.reportRunnerResults).wasCalledWith(env.currentRunner); + expect(fakeReporter.reportRunnerResults).wasCalled(); + expect(fakeReporter.reportRunnerResults.mostRecentCall.args[0].getResults()).toEqual(env.currentRunner.getResults()); + }); + + + }); + + it("should report when the tests start running", function() { + var fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); + env.addReporter(fakeReporter); + + + var runner = new jasmine.Runner(env); + runner.arbitraryVariable = 'foo'; + spyOn(runner.queue, 'start'); + expect(fakeReporter.reportRunnerStarting).wasNotCalled(); + runner.execute(); + expect(fakeReporter.reportRunnerStarting).wasCalled(); + var reportedRunner = fakeReporter.reportRunnerStarting.mostRecentCall.args[0]; + expect(reportedRunner.arbitraryVariable).toEqual('foo'); + expect(runner.queue.start).wasCalled(); + + }); + + it("should return a flat array of all suites, including nested suites", function() { + var suite1, suite2; + suite1 = env.describe("spec 1", function() { + suite2 = env.describe("nested spec", function() {}); + }); + + document.runner = env.currentRunner; + + var suites = env.currentRunner.suites(); + var suiteDescriptions = []; + for (var i = 0; i < suites.length; i++) { + suiteDescriptions.push(suites[i].getFullName()); + } + expect(suiteDescriptions).toEqual([suite1.getFullName(), suite2.getFullName()]); + }); + +}); \ No newline at end of file diff --git a/spec/suites/RunnerTest.js b/spec/suites/RunnerTest.js deleted file mode 100644 index 7aaca2f8..00000000 --- a/spec/suites/RunnerTest.js +++ /dev/null @@ -1,139 +0,0 @@ -describe('RunnerTest', function() { - var env; - beforeEach(function () { - env = new jasmine.Env(); - }); - - it('should be able to add a suite', function() { - env.describe('one suite description', function () { - env.it('should be a test'); - }); - expect(env.currentRunner.suites.length).toEqual(1); // "Runner expected one suite, got " + env.currentRunner.suites.length); - }); - - it('should be able to push multiple suites', function() { - env.describe('one suite description', function () { - env.it('should be a test'); - }); - env.describe('another suite description', function () { - env.it('should be a test'); - }); - expect(env.currentRunner.suites.length).toEqual(2); //"Runner expected two suites, but got " + env.currentRunner.suites.length); - }); - - it('should run child suites and specs and generate results when execute is called', function() { - env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - - env.currentRunner.execute(); - - expect(env.currentRunner.suites.length).toEqual(2); // "Runner expected two suites, got " + env.currentRunner.suites.length); - expect(env.currentRunner.suites[0].specs[0].results.getItems()[0].passed).toEqual(true); //"Runner should have run specs in first suite"); - expect(env.currentRunner.suites[1].specs[0].results.getItems()[0].passed).toEqual(false); //"Runner should have run specs in second suite"); - }); - - it('should ignore suites that have been x\'d', function() { - env.xdescribe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - - env.currentRunner.execute(); - - expect(env.currentRunner.suites.length).toEqual(1); // "Runner expected 1 suite, got " + env.currentRunner.suites.length); - expect(env.currentRunner.suites[0].specs[0].results.getItems()[0].passed).toEqual(false); // "Runner should have run specs in first suite"); - expect(env.currentRunner.suites[1]).toEqual(undefined); // "Second suite should be undefined, but was " + reporter.toJSON(env.currentRunner.suites[1])); - }); - - it('should roll up results from all specs', function() { - var env = new jasmine.Env(); - env.describe('one suite description', function () { - env.it('should be a test', function() { - this.runs(function () { - this.expect(true).toEqual(true); - }); - }); - }); - - env.describe('another suite description', function () { - env.it('should be another test', function() { - this.runs(function () { - this.expect(true).toEqual(false); - }); - }); - }); - - env.currentRunner.execute(); - - var results = env.currentRunner.getResults(); - expect(results.totalCount).toEqual(2); - expect(results.passedCount).toEqual(1); - expect(results.failedCount).toEqual(1); - }); - - it('should set the finished flag when #finished is called', function(){ - env.currentRunner.finish(); - - expect(env.currentRunner.finished).toEqual(true); - }); - - it('should call the finish callback when the runner is finished', function() { - var foo = 0; - - env.currentRunner.finishCallback = function() { - foo++; - }; - - env.currentRunner.finish(); - - expect(env.currentRunner.finished).toEqual(true); - expect(foo).toEqual(1); - }); - - it("should report when the tests start running", function() { - var fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); - env.addReporter(fakeReporter); - - var runner = new jasmine.Runner(env); - runner.execute(); - expect(fakeReporter.reportRunnerStarting).wasCalledWith(env.currentRunner); - }); - - it("should return a flat array of all suites, including nested suites", function() { - var suite1, suite2; - suite1 = env.describe("spec 1", function() { - suite2 = env.describe("nested spec", function() {}); - }); - - console.log("runner:", env.currentRunner); - document.runner = env.currentRunner; - - var suites = env.currentRunner.getAllSuites(); - expect(suites).toEqual([suite1, suite2]); - }); - -}); \ No newline at end of file diff --git a/spec/suites/SpecRunningTest.js b/spec/suites/SpecRunningSpec.js similarity index 55% rename from spec/suites/SpecRunningTest.js rename to spec/suites/SpecRunningSpec.js index ca84e1d4..010756a1 100644 --- a/spec/suites/SpecRunningTest.js +++ b/spec/suites/SpecRunningSpec.js @@ -38,6 +38,7 @@ describe("jasmine spec running", function () { it("should build up some objects with results we can inspect", function() { + var specWithNoBody, specWithExpectation, specWithFailingExpectations, specWithMultipleExpectations; var suite = env.describe('default current suite', function() { @@ -63,21 +64,22 @@ describe("jasmine spec running", function () { }); suite.execute(); + fakeTimer.tick(0); expect(specWithNoBody.description).toEqual('new spec'); expect(specWithExpectation.results.getItems().length).toEqual(1); // "Results aren't there after a spec was executed" - expect(specWithExpectation.results.getItems()[0].passed).toEqual(true); // "Results has a result, but it's true" + expect(specWithExpectation.results.getItems()[0].passed()).toEqual(true); // "Results has a result, but it's true" expect(specWithExpectation.results.description).toEqual('spec with an expectation'); // "Spec's results did not get the spec's description" - expect(specWithFailingExpectations.results.getItems()[0].passed).toEqual(false); // "Expectation that failed, passed" + expect(specWithFailingExpectations.results.getItems()[0].passed()).toEqual(false); // "Expectation that failed, passed" expect(specWithMultipleExpectations.results.getItems().length).toEqual(2); // "Spec doesn't support multiple expectations" }); it("should work without a runs block", function() { var another_spec; - var currentSuite = env.describe('default current suite', function() { + env.describe('default current suite', function() { another_spec = env.it('spec with an expectation', function () { var foo = 'bar'; this.expect(foo).toEqual('bar'); @@ -89,37 +91,45 @@ describe("jasmine spec running", function () { another_spec.done = true; expect(another_spec.results.getItems().length).toEqual(2); - expect(another_spec.results.getItems()[0].passed).toEqual(true); // "In a spec without a run block, expected first expectation result to be true but was false" - expect(another_spec.results.getItems()[1].passed).toEqual(false); // "In a spec without a run block, expected second expectation result to be false but was true"; + expect(another_spec.results.getItems()[0].passed()).toEqual(true); // "In a spec without a run block, expected first expectation result to be true but was false" + expect(another_spec.results.getItems()[1].passed()).toEqual(false); // "In a spec without a run block, expected second expectation result to be false but was true"; expect(another_spec.results.description).toEqual('spec with an expectation'); // "In a spec without a run block, results did not include the spec's description"; }); + it('should queue waits and runs that it encounters while executing specs', function() { + var specWithRunsAndWaits; + var foo = 0; + env.describe('test async spec', function() { + specWithRunsAndWaits = env.it('spec w/ queued statments', function () { + this.runs(function () { + foo++; + }); + this.waits(500); + this.runs(function () { + foo++; + }); + this.waits(500); + this.runs(function () { + foo++; + }); + }); + }); + + expect(foo).toEqual(0); + specWithRunsAndWaits.execute(); + fakeTimer.tick(0); + + expect(foo).toEqual(1); + fakeTimer.tick(500); + expect(foo).toEqual(2); + fakeTimer.tick(500); + expect(foo).toEqual(3); + }); + it("should run asynchronous tests", function () { var foo = 0; - //set a bogus suite for the spec to attach to - // jasmine.getEnv().currentSuite = {specs: []}; - var a_spec; - env.describe('test async spec', function() { - a_spec = env.it('simple queue test', function () { - this.runs(function () { - foo++; - }); - this.runs(function () { - this.expect(foo).toEqual(1); - }); - }); - }); - - expect(a_spec.queue.length).toEqual(1, - 'Expected spec queue length to be 1, was ' + a_spec.queue.length); - - a_spec.execute(); - expect(a_spec.queue.length).toEqual(3, - 'Expected spec queue length to be 3, was ' + a_spec.queue.length); - - foo = 0; env.describe('test async spec', function() { a_spec = env.it('spec w/ queued statments', function () { this.runs(function () { @@ -132,9 +142,10 @@ describe("jasmine spec running", function () { }); a_spec.execute(); + fakeTimer.tick(0); expect(a_spec.results.getItems().length).toEqual(1); // 'No call to waits(): Spec queue did not run all functions'; - expect(a_spec.results.getItems()[0].passed).toEqual(true); // 'No call to waits(): Queued expectation failed'; + expect(a_spec.results.getItems()[0].passed()).toEqual(true); // 'No call to waits(): Queued expectation failed'; foo = 0; env.describe('test async spec', function() { @@ -152,6 +163,8 @@ describe("jasmine spec running", function () { }); a_spec.execute(); + fakeTimer.tick(0); + expect(a_spec.results.getItems().length).toEqual(0); fakeTimer.tick(500); @@ -160,7 +173,7 @@ describe("jasmine spec running", function () { fakeTimer.tick(500); expect(a_spec.results.getItems().length).toEqual(1); // 'Calling waits(): Spec queue did not run all functions'; - expect(a_spec.results.getItems()[0].passed).toEqual(true); // 'Calling waits(): Queued expectation failed'; + expect(a_spec.results.getItems()[0].passed()).toEqual(true); // 'Calling waits(): Queued expectation failed'; var bar = 0; var another_spec; @@ -185,16 +198,13 @@ describe("jasmine spec running", function () { }); }); - expect(another_spec.queue.length).toEqual(1); // 'Calling 2 waits(): Expected queue length to be 1, got ' + another_spec.queue.length; another_spec.execute(); fakeTimer.tick(1000); - expect(another_spec.queue.length).toEqual(4); // 'Calling 2 waits(): Expected queue length to be 4, got ' + another_spec.queue.length; - expect(another_spec.results.getItems().length).toEqual(1); // 'Calling 2 waits(): Spec queue did not run all functions'; - - expect(another_spec.results.getItems()[0].passed).toEqual(true); // 'Calling 2 waits(): Queued expectation failed'; + expect(another_spec.results.getItems().length).toEqual(1); + expect(another_spec.results.getItems()[0].passed()).toEqual(true); var baz = 0; var yet_another_spec; @@ -214,11 +224,13 @@ describe("jasmine spec running", function () { yet_another_spec.execute(); - fakeTimer.tick(250); + //tick twice so that second runs gets eval'd first: mockClock bug? + fakeTimer.tick(100); + fakeTimer.tick(150); - expect(yet_another_spec.queue.length).toEqual(3); // 'Calling 2 waits(): Expected queue length to be 3, got ' + another_spec.queue.length); - expect(yet_another_spec.results.getItems().length).toEqual(1); // 'Calling 2 waits(): Spec queue did not run all functions'); - expect(yet_another_spec.results.getItems()[0].passed).toEqual(false); // 'Calling 2 waits(): Queued expectation failed'); + + expect(yet_another_spec.results.getItems().length).toEqual(1); + expect(yet_another_spec.results.getItems()[0].passed()).toEqual(false); }); it("testAsyncSpecsWithMockSuite", function () { @@ -246,9 +258,8 @@ describe("jasmine spec running", function () { another_spec.execute(); fakeTimer.tick(2000); - expect(another_spec.queue.length).toEqual(4); // 'Calling 2 waits(): Expected queue length to be 4, got ' + another_spec.queue.length); - expect(another_spec.results.getItems().length).toEqual(1); // 'Calling 2 waits(): Spec queue did not run all functions'); - expect(another_spec.results.getItems()[0].passed).toEqual(true); // 'Calling 2 waits(): Queued expectation failed'); + expect(another_spec.results.getItems().length).toEqual(1); + expect(another_spec.results.getItems()[0].passed()).toEqual(true); }); it("testWaitsFor", function() { @@ -302,7 +313,7 @@ describe("jasmine spec running", function () { expect(actual).toEqual(expected); }); - it("testWaitsForFailsIfTimeout", function() { + it("waitsFor fails and skips the rest of the spec if timeout is reached and the latch function is still false", function() { var runsBlockExecuted = false; var spec; @@ -312,7 +323,7 @@ describe("jasmine spec running", function () { }); this.waitsFor(500, function() { - return false; // force a timeout + return false; }); this.runs(function() { @@ -322,15 +333,15 @@ describe("jasmine spec running", function () { }); spec.execute(); - expect(runsBlockExecuted).toEqual(false, 'should not have executed runs block yet'); + expect(runsBlockExecuted).toEqual(false); fakeTimer.tick(100); - expect(runsBlockExecuted).toEqual(false, 'should not have executed runs block yet'); + expect(runsBlockExecuted).toEqual(false); fakeTimer.tick(400); - expect(runsBlockExecuted).toEqual(false, 'should have timed out, so the second runs block should not have been called'); + expect(runsBlockExecuted).toEqual(false); var actual = spec.results.getItems()[0].message; var expected = 'timeout: timed out after 500 msec waiting for something to happen'; expect(actual).toEqual(expected, - 'expected "' + expected + '" but found "' + actual + '"'); + 'expected "' + expected + '" but found "' + actual + '"'); }); it("testSpecAfter", function() { @@ -351,38 +362,19 @@ describe("jasmine spec running", function () { }); suite.execute(); - expect(log).toEqual("specafter2after1"); // "after function should be executed in reverse order after spec runs"); + fakeTimer.tick(0); + + expect(log).toEqual("specafter2after1"); }); describe('test suite declaration', function() { var suite; - var dummyFunction = function() {}; + var dummyFunction = function() { + }; it('should give the suite a description', function() { suite = env.describe('one suite description', dummyFunction); - expect(suite.description).toEqual('one suite description'); // 'Suite did not get a description'); - }); - - it('should add tests to suites declared by the passed function', function() { - suite = env.describe('one suite description', function () { - env.it('should be a test'); - }); - - expect(suite.specs.length).toEqual(1); // 'Suite did not get a spec pushed'); - expect(suite.specs[0].queue.length).toEqual(0); // "Suite's Spec should not have queuedFunctions"); - }); - - it('should enqueue functions for multipart tests', function() { - suite = env.describe('one suite description', function () { - env.it('should be a test with queuedFunctions', function() { - this.runs(function() { - var foo = 0; - foo++; - }); - }); - }); - - expect(suite.specs[0].queue.length).toEqual(1); // "Suite's spec did not get a function pushed"); + expect(suite.description).toEqual('one suite description'); }); it('should enqueue functions for multipart tests and support waits, and run any ready runs() blocks', function() { @@ -401,9 +393,9 @@ describe("jasmine spec running", function () { }); }); - expect(suite.specs[0].queue.length).toEqual(1); // "Suite's spec length should have been 1, was " + suite.specs[0].queue.length); suite.execute(); - expect(suite.specs[0].queue.length).toEqual(3); // "Suite's spec length should have been 3, was " + suite.specs[0].queue.length); + fakeTimer.tick(0); + expect(foo).toEqual(1); expect(bar).toEqual(0); @@ -414,7 +406,6 @@ describe("jasmine spec running", function () { }); it("testBeforeAndAfterCallbacks", function () { - var suiteWithBefore = env.describe('one suite with a before', function () { this.beforeEach(function () { @@ -437,42 +428,370 @@ describe("jasmine spec running", function () { }); suiteWithBefore.execute(); - var suite = suiteWithBefore; - expect(suite.beforeEachFunction); // "testBeforeAndAfterCallbacks: Suite's beforeEach was not defined"); - expect(suite.specs[0].results.getItems()[0].passed).toEqual(true); // "testBeforeAndAfterCallbacks: the first spec's foo should have been 2"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true); // "testBeforeAndAfterCallbacks: the second spec's this.foo should have been 2"); + fakeTimer.tick(0); + var suite = suiteWithBefore; + + expect(suite.getResults().getItems()[0].passed()).toEqual(true); // "testBeforeAndAfterCallbacks: the first spec's foo should have been 2"); + expect(suite.getResults().getItems()[1].passed()).toEqual(true); // "testBeforeAndAfterCallbacks: the second spec's this.foo should have been 2"); + + + var foo = 1; var suiteWithAfter = env.describe('one suite with an after_each', function () { env.it('should be a spec with an after_each', function () { - this.runs(function() { - this.foo = 0; - this.foo++; - this.expect(this.foo).toEqual(1); - }); + this.expect(foo).toEqual(1); + foo++; + this.expect(foo).toEqual(2); }); env.it('should be another spec with an after_each', function () { - this.runs(function() { - this.foo = 0; - this.foo++; - this.expect(this.foo).toEqual(1); - }); + this.expect(foo).toEqual(0); + foo++; + this.expect(foo).toEqual(1); }); this.afterEach(function () { - this.foo = 0; + foo = 0; }); }); suiteWithAfter.execute(); - var suite = suiteWithAfter; - expect(suite.afterEachFunction); // "testBeforeAndAfterCallbacks: Suite's afterEach was not defined"); - expect(suite.specs[0].results.getItems()[0].passed).toEqual(true); // "testBeforeAndAfterCallbacks: afterEach failure: " + suite.results.getItems()[0].results[0].message); - expect(suite.specs[0].foo).toEqual(0); // "testBeforeAndAfterCallbacks: afterEach failure: foo was not reset to 0"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true); // "testBeforeAndAfterCallbacks: afterEach failure: " + suite.results.getItems()[0].results[0].message); - expect(suite.specs[1].foo).toEqual(0); // "testBeforeAndAfterCallbacks: afterEach failure: foo was not reset to 0"); + fakeTimer.tick(0); + suite = suiteWithAfter; + expect(suite.afterEach.length).toEqual(1); + expect(suite.getResults().getItems()[0].passed()).toEqual(true); + expect(suite.getResults().getItems()[1].passed()).toEqual(true); + expect(foo).toEqual(0); + + }); + + it('#waits should allow consecutive waits calls', function () { + var foo = 0; + var waitsSuite = env.describe('suite that waits', function () { + env.it('should wait', function() { + this.waits(500); + this.waits(500); + this.runs(function () { + foo++; + }); + }); + }); + + waitsSuite.execute(); + expect(foo).toEqual(0); + fakeTimer.tick(500); + expect(foo).toEqual(0); + fakeTimer.tick(500); + + expect(foo).toEqual(1); + }); + + it('nested suites', function () { + + var foo = 0; + var bar = 0; + var baz = 0; + var quux = 0; + var nested = env.describe('suite', function () { + env.describe('nested', function () { + env.it('should run nested suites', function () { + foo++; + }); + env.it('should run nested suites', function () { + bar++; + }); + }); + + env.describe('nested 2', function () { + env.it('should run suites following nested suites', function () { + baz++; + }); + }); + + env.it('should run tests following nested suites', function () { + quux++; + }); + }); + + expect(foo).toEqual(0); + expect(bar).toEqual(0); + expect(baz).toEqual(0); + expect(quux).toEqual(0); + nested.execute(); + fakeTimer.tick(0); + + expect(foo).toEqual(1); + expect(bar).toEqual(1); + expect(baz).toEqual(1); + expect(quux).toEqual(1); + }); + + describe('#waitsFor should allow consecutive calls', function () { + + var foo; + beforeEach(function () { + + foo = 0; + }); + + it('exits immediately (does not stack) if the latchFunction times out', function () { + var reachedFirstWaitsFor = false; + var reachedSecondWaitsFor = false; + var waitsSuite = env.describe('suite that waits', function () { + env.it('should stack timeouts', function() { + this.waitsFor(500, function () { + reachedFirstWaitsFor = true; + return false; + }); + this.waitsFor(500, function () { + reachedSecondWaitsFor = true; + }); + this.runs(function () { + foo++; + }); + }); + }); + + expect(reachedFirstWaitsFor).toEqual(false); + waitsSuite.execute(); + fakeTimer.tick(0); + + expect(reachedFirstWaitsFor).toEqual(true); + expect(foo).toEqual(0); + expect(reachedSecondWaitsFor).toEqual(false); + fakeTimer.tick(500); + expect(reachedSecondWaitsFor).toEqual(false); + expect(foo).toEqual(0); + fakeTimer.tick(500); + expect(reachedSecondWaitsFor).toEqual(false); + expect(foo).toEqual(0); + }); + + it('stacks latchFunctions', function () { + var firstWaitsResult = false; + var secondWaitsResult = false; + var waitsSuite = env.describe('suite that waits', function () { + env.it('spec with waitsFors', function() { + this.waitsFor(600, function () { + fakeTimer.setTimeout(function () { + firstWaitsResult = true; + }, 300); + return firstWaitsResult; + }); + this.waitsFor(600, function () { + fakeTimer.setTimeout(function () { + secondWaitsResult = true; + }, 300); + return secondWaitsResult; + }); + this.runs(function () { + foo++; + }); + }); + }); + + expect(firstWaitsResult).toEqual(false); + expect(secondWaitsResult).toEqual(false); + waitsSuite.execute(); + + expect(firstWaitsResult).toEqual(false); + expect(secondWaitsResult).toEqual(false); + expect(foo).toEqual(0); + + fakeTimer.tick(300); + + expect(firstWaitsResult).toEqual(true); + expect(secondWaitsResult).toEqual(false); + expect(foo).toEqual(0); + + fakeTimer.tick(300); + + expect(firstWaitsResult).toEqual(true); + expect(secondWaitsResult).toEqual(true); + expect(foo).toEqual(1); + + }); + }); + + it("#beforeEach should be able to eval runs and waits blocks", function () { + var foo = 0; + var bar = 0; + var suiteWithBefore = env.describe('one suite with a before', function () { + this.beforeEach(function () { + this.runs(function () { + foo++; + }); + this.waits(500); + this.runs(function () { + foo++; + }); + this.waits(500); + }); + + env.it('should be a spec', function () { + bar = 1; + foo++; + }); + + }); + + expect(foo).toEqual(0); + expect(bar).toEqual(0); + suiteWithBefore.execute(); + fakeTimer.tick(0); + + expect(bar).toEqual(0); + expect(foo).toEqual(1); + fakeTimer.tick(500); + + expect(bar).toEqual(0); + expect(foo).toEqual(2); + fakeTimer.tick(500); + expect(bar).toEqual(1); + expect(foo).toEqual(3); + }); + + it("#afterEach should be able to eval runs and waits blocks", function () { + var foo = 0; + var firstSpecHasRun = false; + var secondSpecHasRun = false; + var suiteWithAfter = env.describe('one suite with a before', function () { + this.afterEach(function () { + this.waits(500); + this.runs(function () { + foo++; + }); + this.waits(500); + }); + + env.it('should be the first spec', function () { + firstSpecHasRun = true; + }); + + env.it('should be a spec', function () { + secondSpecHasRun = true; + foo++; + }); + + }); + + expect(firstSpecHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + expect(foo).toEqual(0); + + suiteWithAfter.execute(); + fakeTimer.tick(0); + + + expect(firstSpecHasRun).toEqual(true); + expect(secondSpecHasRun).toEqual(false); + expect(foo).toEqual(0); + + fakeTimer.tick(500); + + expect(foo).toEqual(1); + expect(secondSpecHasRun).toEqual(false); + fakeTimer.tick(500); + + expect(foo).toEqual(2); + expect(secondSpecHasRun).toEqual(true); + + }); + + it("Spec#after should be able to eval runs and waits blocks", function () { + var runsBeforeAfter = false; + var firstSpecHasRun = false; + var secondSpecHasRun = false; + var afterHasRun = false; + var suiteWithAfter = env.describe('one suite with a before', function () { + + env.it('should be the first spec', function () { + firstSpecHasRun = true; + this.after(function () { + this.waits(500); + this.runs(function () { + afterHasRun = true; + }); + this.waits(500); + }, true); + this.waits(500); + this.runs(function () { + runsBeforeAfter = true; + }); + }); + + env.it('should be a spec', function () { + secondSpecHasRun = true; + }); + + }); + + expect(firstSpecHasRun).toEqual(false); + expect(runsBeforeAfter).toEqual(false); + expect(afterHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + + suiteWithAfter.execute(); + + expect(firstSpecHasRun).toEqual(true); + expect(runsBeforeAfter).toEqual(false); + expect(afterHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + + fakeTimer.tick(500); + + expect(firstSpecHasRun).toEqual(true); + expect(runsBeforeAfter).toEqual(true); + expect(afterHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + + fakeTimer.tick(500); + + expect(firstSpecHasRun).toEqual(true); + expect(runsBeforeAfter).toEqual(true); + expect(afterHasRun).toEqual(true); + expect(secondSpecHasRun).toEqual(false); + + fakeTimer.tick(500); + + expect(firstSpecHasRun).toEqual(true); + expect(runsBeforeAfter).toEqual(true); + expect(afterHasRun).toEqual(true); + expect(secondSpecHasRun).toEqual(true); + }); + + it("handles waits", function () { + var firstSpecHasRun = false; + var secondSpecHasRun = false; + var suiteWithAfter = env.describe('one suite with a before', function () { + + env.it('should be the first spec', function () { + this.waits(500); + this.runs(function () { + firstSpecHasRun = true; + }); + }); + + env.it('should be a spec', function () { + secondSpecHasRun = true; + }); + + }); + + expect(firstSpecHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + + suiteWithAfter.execute(); + + expect(firstSpecHasRun).toEqual(false); + expect(secondSpecHasRun).toEqual(false); + + fakeTimer.tick(500); + + expect(firstSpecHasRun).toEqual(true); + expect(secondSpecHasRun).toEqual(true); }); it("testBeforeExecutesSafely", function() { @@ -500,13 +819,12 @@ describe("jasmine spec running", function () { }); suite.execute(); + fakeTimer.tick(0); - expect(report).toEqual("firstsecond"); // "both tests should run"); - expect(suite.specs[0].results.getItems()[0].passed).toEqual(false); // "1st spec should fail"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true); // "2nd spec should pass"); - - expect(suite.specs[0].results.getItems()[0].passed).toEqual(false); // "1st spec should fail"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true); // "2nd spec should pass"); + expect(report).toEqual("firstsecond"); + var suiteResults = suite.getResults(); + expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(false); + expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true); }); it("testAfterExecutesSafely", function() { @@ -540,18 +858,21 @@ describe("jasmine spec running", function () { }); suite.execute(); + fakeTimer.tick(0); expect(report).toEqual("firstsecondthird"); // "all tests should run"); //After each errors should not go in spec results because it confuses the count. - expect(suite.specs.length).toEqual(3, 'testAfterExecutesSafely should have results for three specs'); - expect(suite.specs[0].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st spec should pass"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd spec should pass"); - expect(suite.specs[2].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd spec should pass"); + var suiteResults = suite.getResults(); + expect(suiteResults.getItems().length).toEqual(3, 'testAfterExecutesSafely should have results for three specs'); - expect(suite.specs[0].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 1st result for 1st suite spec should pass"); - expect(suite.specs[0].results.getItems()[1].passed).toEqual(false, "testAfterExecutesSafely 2nd result for 1st suite spec should fail because afterEach failed"); - expect(suite.specs[1].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 2nd suite spec should pass"); - expect(suite.specs[2].results.getItems()[0].passed).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass"); + expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 1st spec should pass"); + expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 2nd spec should pass"); + expect(suiteResults.getItems()[2].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 3rd spec should pass"); + + expect(suiteResults.getItems()[0].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 1st result for 1st suite spec should pass"); + expect(suiteResults.getItems()[0].getItems()[1].passed()).toEqual(false, "testAfterExecutesSafely 2nd result for 1st suite spec should fail because afterEach failed"); + expect(suiteResults.getItems()[1].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 2nd suite spec should pass"); + expect(suiteResults.getItems()[2].getItems()[0].passed()).toEqual(true, "testAfterExecutesSafely 3rd suite spec should pass"); }); it("testNestedDescribes", function() { @@ -604,6 +925,8 @@ describe("jasmine spec running", function () { }); env.execute(); + fakeTimer.tick(0); + var expected = [ "outer beforeEach", @@ -626,7 +949,7 @@ describe("jasmine spec running", function () { "inner 2 afterEach", "outer afterEach" ]; - expect(env.equals_(actions, expected)).toEqual(true); // "nested describes order failed:
    " + jasmine.pp(actions) + "
    wanted
    " + jasmine.pp(expected) + " 0) { - this.next(); - } -}; - -/** - * Gets the current action. - */ -jasmine.ActionCollection.prototype.getCurrentAction = function() { - return this.actions[this.index]; -}; - -/** - * Executes the next queued function/action. If there are no more in the queue, calls #finish. - */ -jasmine.ActionCollection.prototype.next = function() { - if (this.index >= this.actions.length) { - this.finish(); - return; - } - - var currentAction = this.getCurrentAction(); - - currentAction.execute(this); - - if (currentAction.afterCallbacks) { - for (var i = 0; i < currentAction.afterCallbacks.length; i++) { - try { - currentAction.afterCallbacks[i](); - } catch (e) { - alert(e); - } - } - } - - this.waitForDone(currentAction); -}; - -jasmine.ActionCollection.prototype.waitForDone = function(action) { - var self = this; - var afterExecute = function afterExecute() { - self.index++; - self.next(); - }; - - if (action.finished) { - var now = new Date().getTime(); - if (this.env.updateInterval && now - this.env.lastUpdate > this.env.updateInterval) { - this.env.lastUpdate = now; - this.env.setTimeout(afterExecute, 0); - } else { - afterExecute(); - } - return; - } - - var id = this.env.setInterval(function() { - if (action.finished) { - self.env.clearInterval(id); - afterExecute(); - } - }, 150); -}; diff --git a/src/Block.js b/src/Block.js new file mode 100644 index 00000000..b9f8f865 --- /dev/null +++ b/src/Block.js @@ -0,0 +1,26 @@ +/** + * Blocks are functions with executable code that make up a spec. + * + * @constructor + * @param {jasmine.Env} env + * @param {Function} func + * @param {jasmine.Spec} spec + */ +jasmine.Block = function(env, func, spec) { + this.env = env; + this.func = func; + this.spec = spec; +}; + +jasmine.Block.prototype.execute = function(onComplete) { + try { + this.func.apply(this.spec); + } catch (e) { + this.fail(e); + } + onComplete(); +}; + +jasmine.Block.prototype.fail = function(e) { + this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +}; \ No newline at end of file diff --git a/src/Env.js b/src/Env.js index fd4dc70d..37626ecc 100644 --- a/src/Env.js +++ b/src/Env.js @@ -18,6 +18,7 @@ jasmine.Env = function() { }; this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; this.equalityTesters_ = []; }; @@ -27,6 +28,14 @@ jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; jasmine.Env.prototype.setInterval = jasmine.setInterval; jasmine.Env.prototype.clearInterval = jasmine.clearInterval; +jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); + } +}; + /** * Register a reporter to receive status updates from Jasmine. * @param {jasmine.Reporter} reporter An object which will receive status updates. @@ -44,9 +53,9 @@ jasmine.Env.prototype.describe = function(description, specDefinitions) { var parentSuite = this.currentSuite; if (parentSuite) { - parentSuite.specs.push(suite); + parentSuite.add(suite); } else { - this.currentRunner.suites.push(suite); + this.currentRunner.add(suite); } this.currentSuite = suite; @@ -75,11 +84,11 @@ jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { jasmine.Env.prototype.it = function(description, func) { var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.specs.push(spec); + this.currentSuite.add(spec); this.currentSpec = spec; if (func) { - spec.addToQueue(func); + spec.runs(func); } return spec; diff --git a/src/JsApiReporter.js b/src/JsApiReporter.js index 1501123a..b5bcafcf 100644 --- a/src/JsApiReporter.js +++ b/src/JsApiReporter.js @@ -11,27 +11,27 @@ jasmine.JsApiReporter = function() { jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { this.started = true; - - for (var i = 0; i < runner.suites.length; i++) { - var suite = runner.suites[i]; + var suites = runner.suites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; this.suites.push(this.summarize_(suite)); } }; jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { + var isSuite = suiteOrSpec instanceof jasmine.Suite var summary = { id: suiteOrSpec.id, name: suiteOrSpec.description, - type: suiteOrSpec instanceof jasmine.Suite ? 'suite' : 'spec', + type: isSuite ? 'suite' : 'spec', children: [] }; - - if (suiteOrSpec.specs) { - for (var i = 0; i < suiteOrSpec.specs.length; i++) { - summary.children.push(this.summarize_(suiteOrSpec.specs[i])); + if (isSuite) { + var specs = suiteOrSpec.specs(); + for (var i = 0; i < specs.length; i++) { + summary.children.push(this.summarize_(specs[i])); } } - return summary; }; diff --git a/src/NestedResults.js b/src/NestedResults.js index c5fabf7f..69de9e05 100644 --- a/src/NestedResults.js +++ b/src/NestedResults.js @@ -62,7 +62,7 @@ jasmine.NestedResults.prototype.addResult = function(result) { this.rollupCounts(result); } else { this.totalCount++; - if (result.passed) { + if (result.passed()) { this.passedCount++; } else { this.failedCount++; diff --git a/src/PrettyPrinter.js b/src/PrettyPrinter.js index 9d8f4f96..ff793a91 100644 --- a/src/PrettyPrinter.js +++ b/src/PrettyPrinter.js @@ -28,7 +28,7 @@ jasmine.PrettyPrinter.prototype.format = function(value) { } else if (value instanceof jasmine.Matchers.Any) { this.emitScalar(value.toString()); } else if (typeof value === 'string') { - this.emitScalar("'" + value + "'"); + this.emitString(value); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (typeof value.nodeType === 'number') { @@ -63,6 +63,7 @@ jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; jasmine.StringPrettyPrinter = function() { jasmine.PrettyPrinter.call(this); @@ -75,6 +76,10 @@ jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { this.append(value); }; +jasmine.StringPrettyPrinter.prototype.emitString = function(value) { + this.append("'" + value + "'"); +}; + jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { this.append('[ '); for (var i = 0; i < array.length; i++) { diff --git a/src/Queue.js b/src/Queue.js new file mode 100644 index 00000000..5551c150 --- /dev/null +++ b/src/Queue.js @@ -0,0 +1,71 @@ +jasmine.Queue = function(env) { + this.env = env; + this.blocks = []; + this.running = false; + this.index = 0; + this.offset = 0; +}; + +jasmine.Queue.prototype.addBefore = function (block) { + this.blocks.unshift(block); +}; + +jasmine.Queue.prototype.add = function(block) { + this.blocks.push(block); +}; + +jasmine.Queue.prototype.insertNext = function (block) { + this.blocks.splice((this.index + this.offset + 1), 0, block); + this.offset++; +}; + +jasmine.Queue.prototype.start = function(onComplete) { + var self = this; + self.running = true; + self.onComplete = onComplete; + if (self.blocks[0]) { + self.blocks[0].execute(function () { + self._next(); + }); + } else { + self.finish(); + } +}; + +jasmine.Queue.prototype.isRunning = function () { + return this.running; +}; + +jasmine.Queue.prototype._next = function () { + var self = this; + self.env.setTimeout(function () { + self.offset = 0; + self.index++; + if (self.index < self.blocks.length) { + self.blocks[self.index].execute(function () { + self._next(); + }); + } else { + self.finish(); + } + }, 0); +}; + +jasmine.Queue.prototype.finish = function () { + this.running = false; + if (this.onComplete) { + this.onComplete(); + } +}; + +jasmine.Queue.prototype.getResults = function () { + var results = new jasmine.NestedResults(); + for (var i = 0; i < this.blocks.length; i++) { + if (this.blocks[i].getResults) { + results.addResult(this.blocks[i].getResults()); + } + } + return results; +}; + + diff --git a/src/QueuedFunction.js b/src/QueuedFunction.js deleted file mode 100644 index e4845c38..00000000 --- a/src/QueuedFunction.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * QueuedFunction is how ActionCollections' actions are implemented - * - * @constructor - * @param {jasmine.Env} env - * @param {Function} func - * @param {Number} timeout - * @param {Function} latchFunction - * @param {jasmine.Spec} spec - */ -jasmine.QueuedFunction = function(env, func, timeout, latchFunction, spec) { - this.env = env; - this.func = func; - this.timeout = timeout; - this.latchFunction = latchFunction; - this.spec = spec; - - this.totalTimeSpentWaitingForLatch = 0; - this.latchTimeoutIncrement = 100; -}; - -jasmine.QueuedFunction.prototype.next = function() { - this.spec.finish(); // default value is to be done after one function -}; - -jasmine.QueuedFunction.prototype.safeExecute = function() { - this.env.reporter.log('>> Jasmine Running ' + this.spec.suite.description + ' ' + this.spec.description + '...'); - - try { - this.func.apply(this.spec); - } catch (e) { - this.fail(e); - } -}; - -jasmine.QueuedFunction.prototype.execute = function() { - var self = this; - var executeNow = function() { - self.safeExecute(); - self.next(); - }; - - var executeLater = function() { - self.env.setTimeout(executeNow, self.timeout); - }; - - var executeNowOrLater = function() { - var latchFunctionResult; - - try { - latchFunctionResult = self.latchFunction.apply(self.spec); - } catch (e) { - self.fail(e); - self.next(); - return; - } - - if (latchFunctionResult) { - executeNow(); - } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { - var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.latchFunction.description || 'something to happen'); - self.fail({ - name: 'timeout', - message: message - }); - self.next(); - } else { - self.totalTimeSpentWaitingForLatch += self.latchTimeoutIncrement; - self.env.setTimeout(executeNowOrLater, self.latchTimeoutIncrement); - } - }; - - if (this.latchFunction !== undefined) { - executeNowOrLater(); - } else if (this.timeout > 0) { - executeLater(); - } else { - executeNow(); - } -}; - -jasmine.QueuedFunction.prototype.fail = function(e) { - this.spec.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); -}; diff --git a/src/Runner.js b/src/Runner.js index ce7dff03..8dc28c15 100644 --- a/src/Runner.js +++ b/src/Runner.js @@ -5,49 +5,47 @@ * @param {jasmine.Env} env */ jasmine.Runner = function(env) { - jasmine.ActionCollection.call(this, env); - - this.suites = this.actions; + var self = this; + self.env = env; + self.queue = new jasmine.Queue(env); + self.suites_ = []; }; -jasmine.util.inherit(jasmine.Runner, jasmine.ActionCollection); jasmine.Runner.prototype.execute = function() { - if (this.env.reporter.reportRunnerStarting) { - this.env.reporter.reportRunnerStarting(this); + var self = this; + if (self.env.reporter.reportRunnerStarting) { + self.env.reporter.reportRunnerStarting(this); } - jasmine.ActionCollection.prototype.execute.call(this); + self.queue.start(function () { + self.finishCallback(); + }); }; jasmine.Runner.prototype.finishCallback = function() { this.env.reporter.reportRunnerResults(this); }; +jasmine.Runner.prototype.addSuite = function(suite) { + this.suites_.push(suite); +}; + +jasmine.Runner.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.addSuite(block); + } + this.queue.add(block); +}; + +/** @deprecated */ jasmine.Runner.prototype.getAllSuites = function() { - var suitesToReturn = []; + return this.suites_; +}; - function addSuite(suite) { - suitesToReturn.push(suite); - for (var j = 0; j < suite.specs.length; j++) { - var spec = suite.specs[j]; - if (spec instanceof jasmine.Suite) { - addSuite(spec); - } - } - } - - for (var i = 0; i < this.suites.length; i++) { - var suite = this.suites[i]; - addSuite(suite); - } - - return suitesToReturn; +jasmine.Runner.prototype.suites = function() { + return this.suites_; }; jasmine.Runner.prototype.getResults = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.suites.length; i++) { - results.rollupCounts(this.suites[i].getResults()); - } - return results; -}; + return this.queue.getResults(); +}; \ No newline at end of file diff --git a/src/Spec.js b/src/Spec.js index d754382f..ca84436a 100644 --- a/src/Spec.js +++ b/src/Spec.js @@ -7,21 +7,19 @@ * @param {String} description */ jasmine.Spec = function(env, suite, description) { - this.id = env.nextSpecId_++; - this.env = env; - this.suite = suite; - this.description = description; - this.queue = []; - this.currentTimeout = 0; - this.currentLatchFunction = undefined; - this.finished = false; - this.afterCallbacks = []; - this.spies_ = []; + var spec = this; + spec.id = env.nextSpecId_++; + spec.env = env; + spec.suite = suite; + spec.description = description; + spec.queue = new jasmine.Queue(env); - this.results = new jasmine.NestedResults(); - this.results.description = description; - this.runs = this.addToQueue; - this.matchersClass = null; + spec.afterCallbacks = []; + spec.spies_ = []; + + spec.results = new jasmine.NestedResults(); + spec.results.description = description; + spec.matchersClass = null; }; jasmine.Spec.prototype.getFullName = function() { @@ -32,21 +30,20 @@ jasmine.Spec.prototype.getResults = function() { return this.results; }; -jasmine.Spec.prototype.addToQueue = function(func) { - var queuedFunction = new jasmine.QueuedFunction(this.env, func, this.currentTimeout, this.currentLatchFunction, this); - this.queue.push(queuedFunction); - - if (this.queue.length > 1) { - var previousQueuedFunction = this.queue[this.queue.length - 2]; - previousQueuedFunction.next = function() { - queuedFunction.execute(); - }; - } - - this.resetTimeout(); +jasmine.Spec.prototype.runs = function (func) { + var block = new jasmine.Block(this.env, func, this); + this.addToQueue(block); return this; }; +jasmine.Spec.prototype.addToQueue = function (block) { + if (this.queue.isRunning()) { + this.queue.insertNext(block); + } else { + this.queue.add(block); + } +}; + /** * @private * @deprecated @@ -62,25 +59,22 @@ jasmine.Spec.prototype.expect = function(actual) { return new (this.getMatchersClass_())(this.env, actual, this.results); }; -/** - * @private - */ jasmine.Spec.prototype.waits = function(timeout) { - this.currentTimeout = timeout; - this.currentLatchFunction = undefined; + var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); + this.addToQueue(waitsFunc); return this; }; -/** - * @private - */ -jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, message) { - this.currentTimeout = timeout; - this.currentLatchFunction = latchFunction; - this.currentLatchFunction.description = message; +jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) { + var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this); + this.addToQueue(waitsForFunc); return this; }; +jasmine.Spec.prototype.failWithException = function (e) { + this.results.addResult(new jasmine.ExpectationResult(false, jasmine.util.formatException(e), null)); +}; + jasmine.Spec.prototype.getMatchersClass_ = function() { return this.matchersClass || jasmine.Matchers; }; @@ -97,70 +91,62 @@ jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { this.matchersClass = newMatchersClass; }; -jasmine.Spec.prototype.resetTimeout = function() { - this.currentTimeout = 0; - this.currentLatchFunction = undefined; -}; - jasmine.Spec.prototype.finishCallback = function() { this.env.reporter.reportSpecResults(this); }; -jasmine.Spec.prototype.finish = function() { - this.safeExecuteAfters(); - +jasmine.Spec.prototype.finish = function(onComplete) { this.removeAllSpies(); this.finishCallback(); - this.finished = true; + if (onComplete) { + onComplete(); + } }; -jasmine.Spec.prototype.after = function(doAfter) { +jasmine.Spec.prototype.after = function(doAfter, test) { + + if (this.queue.isRunning()) { + this.queue.add(new jasmine.Block(this.env, doAfter, this)); + } else { this.afterCallbacks.unshift(doAfter); + } }; -jasmine.Spec.prototype.execute = function() { - if (!this.env.specFilter(this)) { - this.results.skipped = true; - this.finishCallback(); - this.finished = true; +jasmine.Spec.prototype.execute = function(onComplete) { + var spec = this; + if (!spec.env.specFilter(spec)) { + spec.results.skipped = true; + spec.finish(onComplete); return; } + this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...'); - this.env.currentSpec = this; - this.env.currentlyRunningTests = true; + spec.env.currentSpec = spec; + spec.env.currentlyRunningTests = true; - this.safeExecuteBefores(); + spec.addBeforesAndAftersToQueue(); - if (this.queue[0]) { - this.queue[0].execute(); - } else { - this.finish(); - } - this.env.currentlyRunningTests = false; + spec.queue.start(function () { + spec.finish(onComplete); + }); + spec.env.currentlyRunningTests = false; }; -jasmine.Spec.prototype.safeExecuteBefores = function() { - var befores = []; +jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { for (var suite = this.suite; suite; suite = suite.parentSuite) { - if (suite.beforeEachFunction) befores.push(suite.beforeEachFunction); + if (suite.beforeQueue) { + for (var i = 0; i < suite.beforeQueue.length; i++) + this.queue.addBefore(new jasmine.Block(this.env, suite.beforeQueue[i], this)); + } } - - while (befores.length) { - this.safeExecuteBeforeOrAfter(befores.pop()); + for (i = 0; i < this.afterCallbacks.length; i++) { + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); } -}; - -jasmine.Spec.prototype.safeExecuteAfters = function() { - for (var suite = this.suite; suite; suite = suite.parentSuite) { - if (suite.afterEachFunction) this.safeExecuteBeforeOrAfter(suite.afterEachFunction); - } -}; - -jasmine.Spec.prototype.safeExecuteBeforeOrAfter = function(func) { - try { - func.apply(this); - } catch (e) { - this.results.addResult(new jasmine.ExpectationResult(false, func.typeName + '() fail: ' + jasmine.util.formatException(e), null)); + for (suite = this.suite; suite; suite = suite.parentSuite) { + if (suite.afterQueue) { + for (var j = 0; j < suite.afterQueue.length; j++) + this.queue.add(new jasmine.Block(this.env, suite.afterQueue[j], this)); + } } }; diff --git a/src/Suite.js b/src/Suite.js index 60ac46c0..d60ee814 100644 --- a/src/Suite.js +++ b/src/Suite.js @@ -8,16 +8,16 @@ * @param {jasmine.Suite} parentSuite */ jasmine.Suite = function(env, description, specDefinitions, parentSuite) { - jasmine.ActionCollection.call(this, env); - - this.description = description; - this.specs = this.actions; - this.parentSuite = parentSuite; - - this.beforeEachFunction = null; - this.afterEachFunction = null; + var self = this; + self.id = env.nextSuiteId_++; + self.description = description; + self.queue = new jasmine.Queue(env); + self.parentSuite = parentSuite; + self.env = env; + self.beforeQueue = []; + self.afterQueue = []; + self.specs_ = []; }; -jasmine.util.inherit(jasmine.Suite, jasmine.ActionCollection); jasmine.Suite.prototype.getFullName = function() { var fullName = this.description; @@ -27,25 +27,49 @@ jasmine.Suite.prototype.getFullName = function() { return fullName; }; -jasmine.Suite.prototype.finishCallback = function() { +jasmine.Suite.prototype.finish = function(onComplete) { this.env.reporter.reportSuiteResults(this); + this.finished = true; + if (typeof(onComplete) == 'function') { + onComplete(); + } }; jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { beforeEachFunction.typeName = 'beforeEach'; - this.beforeEachFunction = beforeEachFunction; + this.beforeQueue.push(beforeEachFunction); }; jasmine.Suite.prototype.afterEach = function(afterEachFunction) { afterEachFunction.typeName = 'afterEach'; - this.afterEachFunction = afterEachFunction; + this.afterQueue.push(afterEachFunction); }; jasmine.Suite.prototype.getResults = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.specs.length; i++) { - results.rollupCounts(this.specs[i].getResults()); - } - return results; + return this.queue.getResults(); }; +jasmine.Suite.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.env.currentRunner.addSuite(block); + } else { + this.specs_.push(block); + } + this.queue.add(block); +}; + +/** @deprecated */ +jasmine.Suite.prototype.specCount = function() { + return this.specs_.length; +}; + +jasmine.Suite.prototype.specs = function() { + return this.specs_; +}; + +jasmine.Suite.prototype.execute = function(onComplete) { + var self = this; + this.queue.start(function () { + self.finish(onComplete); + }); +}; \ No newline at end of file diff --git a/src/WaitsBlock.js b/src/WaitsBlock.js new file mode 100644 index 00000000..151c0510 --- /dev/null +++ b/src/WaitsBlock.js @@ -0,0 +1,13 @@ +jasmine.WaitsBlock = function(env, timeout, spec) { + this.timeout = timeout; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); + +jasmine.WaitsBlock.prototype.execute = function (onComplete) { + this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); + this.env.setTimeout(function () { + onComplete(); + }, this.timeout); +}; diff --git a/src/WaitsForBlock.js b/src/WaitsForBlock.js new file mode 100644 index 00000000..93327738 --- /dev/null +++ b/src/WaitsForBlock.js @@ -0,0 +1,38 @@ +jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { + this.timeout = timeout; + this.latchFunction = latchFunction; + this.message = message; + this.totalTimeSpentWaitingForLatch = 0; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); + +jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100; + +jasmine.WaitsForBlock.prototype.execute = function (onComplete) { + var self = this; + self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen')); + var latchFunctionResult; + try { + latchFunctionResult = self.latchFunction.apply(self.spec); + } catch (e) { + self.fail(e); + onComplete(); + return; + } + + if (latchFunctionResult) { + onComplete(); + } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { + var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen'); + self.fail({ + 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); + } +}; \ No newline at end of file diff --git a/src/base.js b/src/base.js index dab87afc..81f3f573 100755 --- a/src/base.js +++ b/src/base.js @@ -40,12 +40,16 @@ jasmine.MessageResult = function(text) { jasmine.ExpectationResult = function(passed, message, details) { this.type = 'ExpectationResult'; - this.passed = passed; + this.passed_ = passed; this.message = message; this.details = details; this.trace = new Error(message); // todo: test better }; +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; + /** * Getter for the Jasmine environment. Ensures one gets created */ diff --git a/src/version.json b/src/version.json new file mode 100644 index 00000000..693bcc97 --- /dev/null +++ b/src/version.json @@ -0,0 +1,5 @@ +{ + "major": 0, + "minor": 9, + "build": 0 +} \ No newline at end of file