├── .gitignore ├── src ├── version.json ├── WaitsBlock.js ├── Block.js ├── Reporter.js ├── MultiReporter.js ├── Reporters.js ├── WaitsForBlock.js ├── util.js ├── Runner.js ├── NestedResults.js ├── Suite.js ├── Queue.js ├── JsApiReporter.js ├── PrettyPrinter.js ├── mock-timeout.js ├── Spec.js ├── Env.js └── Matchers.js ├── images ├── go.png ├── fail.png ├── go-16.png ├── fail-16.png ├── pending.png ├── spinner.gif ├── pending-16.png ├── question-bk.png └── questionbk-16.png ├── examples ├── html │ ├── spec │ │ └── example_suite.js │ └── example_suite.html └── ruby │ ├── spec │ ├── example │ │ └── example_spec.js │ ├── jasmine_spec.rb │ └── jasmine_helper.rb │ └── Rakefile ├── geminstaller.yml ├── spec ├── jasmine_spec.rb ├── suites │ ├── UtilSpec.js │ ├── QueueSpec.js │ ├── MockClockSpec.js │ ├── MultiReporterSpec.js │ ├── ReporterSpec.js │ ├── EnvSpec.js │ ├── NestedResultsSpec.js │ ├── JsApiReporterSpec.js │ ├── SuiteSpec.js │ ├── PrettyPrintSpec.js │ ├── SpecSpec.js │ ├── ExceptionsSpec.js │ ├── TrivialReporterSpec.js │ ├── SpySpec.js │ └── RunnerSpec.js ├── jasmine_helper.rb └── runner.html ├── lib ├── consolex.js ├── jasmine.css └── TrivialReporter.js ├── MIT.LICENSE ├── contrib └── ruby │ ├── run.html │ ├── spec │ └── jasmine_runner_spec.rb │ ├── jasmine_spec_builder.rb │ └── jasmine_runner.rb ├── Rakefile └── doc ├── symbols ├── src │ ├── src_WaitsBlock.js.html │ ├── src_Block.js.html │ ├── src_Reporter.js.html │ ├── src_Reporters.js.html │ ├── src_MultiReporter.js.html │ └── src_WaitsForBlock.js.html ├── jasmine.MultiReporter.html └── jasmine.Block.html ├── index.html └── files.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .svn/ 3 | -------------------------------------------------------------------------------- /src/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "major": 0, 3 | "minor": 10, 4 | "build": 0 5 | } -------------------------------------------------------------------------------- /images/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/go.png -------------------------------------------------------------------------------- /images/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/fail.png -------------------------------------------------------------------------------- /images/go-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/go-16.png -------------------------------------------------------------------------------- /images/fail-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/fail-16.png -------------------------------------------------------------------------------- /images/pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/pending.png -------------------------------------------------------------------------------- /images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/spinner.gif -------------------------------------------------------------------------------- /images/pending-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/pending-16.png -------------------------------------------------------------------------------- /images/question-bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/question-bk.png -------------------------------------------------------------------------------- /images/questionbk-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/jasmine/master/images/questionbk-16.png -------------------------------------------------------------------------------- /examples/html/spec/example_suite.js: -------------------------------------------------------------------------------- 1 | describe('ExampleSuite', function () { 2 | it('should have a passing test', function() { 3 | expect(true).toEqual(true); 4 | }); 5 | 6 | describe('Nested Describe', function () { 7 | it('should also have a passing test', function () { 8 | expect(true).toEqual(true); 9 | }); 10 | }); 11 | }); -------------------------------------------------------------------------------- /examples/ruby/spec/example/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('ExampleSuite', function () { 2 | it('should have a passing test', function() { 3 | expect(true).toEqual(true); 4 | }); 5 | 6 | describe('Nested Describe', function () { 7 | it('should also have a passing test', function () { 8 | expect(true).toEqual(true); 9 | }); 10 | }); 11 | }); -------------------------------------------------------------------------------- /geminstaller.yml: -------------------------------------------------------------------------------- 1 | --- 2 | gems: 3 | - name: rake 4 | version: 0.8.7 5 | - name: ragaskar-jsdoc_helper 6 | version: 0.0.2.1 7 | - name: json 8 | version: 1.1.9 9 | - name: pivotal-selenium-rc 10 | version: 1.11.20090610 11 | - name: rack 12 | version: 1.0.0 13 | - name: thin 14 | version: 1.2.4 15 | - name: eventmachine 16 | version: 0.12.8 17 | - name: rspec 18 | version: 1.2.9 19 | - name: selenium-client 20 | version: 1.2.17 21 | -------------------------------------------------------------------------------- /src/WaitsBlock.js: -------------------------------------------------------------------------------- 1 | jasmine.WaitsBlock = function(env, timeout, spec) { 2 | this.timeout = timeout; 3 | jasmine.Block.call(this, env, null, spec); 4 | }; 5 | 6 | jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); 7 | 8 | jasmine.WaitsBlock.prototype.execute = function (onComplete) { 9 | this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); 10 | this.env.setTimeout(function () { 11 | onComplete(); 12 | }, this.timeout); 13 | }; 14 | -------------------------------------------------------------------------------- /src/Block.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blocks are functions with executable code that make up a spec. 3 | * 4 | * @constructor 5 | * @param {jasmine.Env} env 6 | * @param {Function} func 7 | * @param {jasmine.Spec} spec 8 | */ 9 | jasmine.Block = function(env, func, spec) { 10 | this.env = env; 11 | this.func = func; 12 | this.spec = spec; 13 | }; 14 | 15 | jasmine.Block.prototype.execute = function(onComplete) { 16 | try { 17 | this.func.apply(this.spec); 18 | } catch (e) { 19 | this.spec.fail(e); 20 | } 21 | onComplete(); 22 | }; -------------------------------------------------------------------------------- /src/Reporter.js: -------------------------------------------------------------------------------- 1 | /** No-op base class for Jasmine reporters. 2 | * 3 | * @constructor 4 | */ 5 | jasmine.Reporter = function() { 6 | }; 7 | 8 | //noinspection JSUnusedLocalSymbols 9 | jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { 10 | }; 11 | 12 | //noinspection JSUnusedLocalSymbols 13 | jasmine.Reporter.prototype.reportRunnerResults = function(runner) { 14 | }; 15 | 16 | //noinspection JSUnusedLocalSymbols 17 | jasmine.Reporter.prototype.reportSuiteResults = function(suite) { 18 | }; 19 | 20 | //noinspection JSUnusedLocalSymbols 21 | jasmine.Reporter.prototype.reportSpecResults = function(spec) { 22 | }; 23 | 24 | //noinspection JSUnusedLocalSymbols 25 | jasmine.Reporter.prototype.log = function(str) { 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /spec/jasmine_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require "selenium_rc" 3 | require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_helper.rb")) 4 | require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder")) 5 | 6 | jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path, 7 | JasmineHelper.specs, 8 | JasmineHelper.dir_mappings) 9 | 10 | spec_builder = Jasmine::SpecBuilder.new(JasmineHelper.raw_spec_files, jasmine_runner) 11 | 12 | should_stop = false 13 | 14 | Spec::Runner.configure do |config| 15 | config.after(:suite) do 16 | spec_builder.stop if should_stop 17 | end 18 | end 19 | 20 | spec_builder.start 21 | should_stop = true 22 | spec_builder.declare_suites 23 | -------------------------------------------------------------------------------- /examples/ruby/spec/jasmine_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require "selenium_rc" 3 | require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_helper.rb")) 4 | require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder")) 5 | 6 | jasmine_runner = Jasmine::Runner.new(SeleniumRC::Server.new.jar_path, 7 | JasmineHelper.specs, 8 | JasmineHelper.dir_mappings) 9 | 10 | spec_builder = Jasmine::SpecBuilder.new(JasmineHelper.raw_spec_files, jasmine_runner) 11 | 12 | should_stop = false 13 | 14 | Spec::Runner.configure do |config| 15 | config.after(:suite) do 16 | spec_builder.stop if should_stop 17 | end 18 | end 19 | 20 | spec_builder.start 21 | should_stop = true 22 | spec_builder.declare_suites 23 | -------------------------------------------------------------------------------- /spec/suites/UtilSpec.js: -------------------------------------------------------------------------------- 1 | describe("jasmine.util", function() { 2 | describe("extend", function () { 3 | it("should add properies to a destination object ", function() { 4 | var destination = {baz: 'baz'}; 5 | jasmine.util.extend(destination, { 6 | foo: 'foo', bar: 'bar' 7 | }); 8 | expect(destination).toEqual({foo: 'foo', bar: 'bar', baz: 'baz'}); 9 | }); 10 | 11 | it("should replace properies that already exist on a destination object", function() { 12 | var destination = {foo: 'foo'}; 13 | jasmine.util.extend(destination, { 14 | foo: 'bar' 15 | }); 16 | expect(destination).toEqual({foo: 'bar'}); 17 | jasmine.util.extend(destination, { 18 | foo: null 19 | }); 20 | expect(destination).toEqual({foo: null}); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examples/ruby/Rakefile: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), "spec/jasmine_helper.rb")) 2 | 3 | namespace :test do 4 | desc "Run continuous integration tests" 5 | require "spec" 6 | require 'spec/rake/spectask' 7 | 8 | Spec::Rake::SpecTask.new(:ci) do |t| 9 | t.spec_opts = ["--color", "--format", "specdoc"] 10 | t.spec_files = ["spec/jasmine_spec.rb"] 11 | end 12 | end 13 | 14 | desc "Run specs via server" 15 | task :jasmine_server do 16 | require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder")) 17 | 18 | puts "your tests are here:" 19 | puts " http://localhost:8888/run.html" 20 | 21 | Jasmine::SimpleServer.start(8888, 22 | lambda { JasmineHelper.specs }, 23 | JasmineHelper.dir_mappings) 24 | end 25 | -------------------------------------------------------------------------------- /spec/suites/QueueSpec.js: -------------------------------------------------------------------------------- 1 | describe("jasmine.Queue", function() { 2 | it("should not call itself recursively, so we don't get stack overflow errors", function() { 3 | var queue = new jasmine.Queue(new jasmine.Env()); 4 | queue.add(new jasmine.Block(null, function() {})); 5 | queue.add(new jasmine.Block(null, function() {})); 6 | queue.add(new jasmine.Block(null, function() {})); 7 | queue.add(new jasmine.Block(null, function() {})); 8 | 9 | var nestCount = 0; 10 | var maxNestCount = 0; 11 | var nextCallCount = 0; 12 | queue.next_ = function() { 13 | nestCount++; 14 | if (nestCount > maxNestCount) maxNestCount = nestCount; 15 | 16 | jasmine.Queue.prototype.next_.apply(queue, arguments); 17 | nestCount--; 18 | }; 19 | 20 | queue.start(); 21 | expect(maxNestCount).toEqual(1); 22 | }); 23 | }); -------------------------------------------------------------------------------- /examples/html/example_suite.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Test Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/MultiReporter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @constructor 3 | */ 4 | jasmine.MultiReporter = function() { 5 | this.subReporters_ = []; 6 | }; 7 | jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); 8 | 9 | jasmine.MultiReporter.prototype.addReporter = function(reporter) { 10 | this.subReporters_.push(reporter); 11 | }; 12 | 13 | (function() { 14 | var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"]; 15 | for (var i = 0; i < functionNames.length; i++) { 16 | var functionName = functionNames[i]; 17 | jasmine.MultiReporter.prototype[functionName] = (function(functionName) { 18 | return function() { 19 | for (var j = 0; j < this.subReporters_.length; j++) { 20 | var subReporter = this.subReporters_[j]; 21 | if (subReporter[functionName]) { 22 | subReporter[functionName].apply(subReporter, arguments); 23 | } 24 | } 25 | }; 26 | })(functionName); 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /lib/consolex.js: -------------------------------------------------------------------------------- 1 | /** Console X 2 | * http://github.com/deadlyicon/consolex.js 3 | * 4 | * By Jared Grippe 5 | * 6 | * Copyright (c) 2009 Jared Grippe 7 | * Licensed under the MIT license. 8 | * 9 | * consolex avoids ever having to see javascript bugs in browsers that do not implement the entire 10 | * firebug console suit 11 | * 12 | */ 13 | (function(window) { 14 | window.console || (window.console = {}); 15 | 16 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", 17 | "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; 18 | 19 | function emptyFunction(){} 20 | 21 | for (var i = 0; i < names.length; ++i){ 22 | window.console[names[i]] || (window.console[names[i]] = emptyFunction); 23 | if (typeof window.console[names[i]] !== 'function') 24 | window.console[names[i]] = (function(method) { 25 | return function(){ return Function.prototype.apply.apply(method, [console,arguments]); }; 26 | })(window.console[names[i]]); 27 | } 28 | })(this); -------------------------------------------------------------------------------- /spec/suites/MockClockSpec.js: -------------------------------------------------------------------------------- 1 | describe("MockClock", function () { 2 | 3 | beforeEach(function() { 4 | jasmine.Clock.useMock(); 5 | }); 6 | 7 | describe("setTimeout", function () { 8 | it("should mock the clock when useMock is in a beforeEach", function() { 9 | var expected = false; 10 | setTimeout(function() { 11 | expected = true; 12 | }, 30000); 13 | expect(expected).toBe(false); 14 | jasmine.Clock.tick(30001); 15 | expect(expected).toBe(true); 16 | }); 17 | }); 18 | 19 | describe("setInterval", function () { 20 | it("should mock the clock when useMock is in a beforeEach", function() { 21 | var interval = 0; 22 | setInterval(function() { 23 | interval++; 24 | }, 30000); 25 | expect(interval).toEqual(0); 26 | jasmine.Clock.tick(30001); 27 | expect(interval).toEqual(1); 28 | jasmine.Clock.tick(30001); 29 | expect(interval).toEqual(2); 30 | jasmine.Clock.tick(1); 31 | expect(interval).toEqual(2); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /examples/ruby/spec/jasmine_helper.rb: -------------------------------------------------------------------------------- 1 | class JasmineHelper 2 | def self.jasmine_lib_dir 3 | File.expand_path(File.join(jasmine_root, 'lib')) 4 | end 5 | 6 | def self.jasmine_root 7 | File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..')) 8 | end 9 | 10 | def self.jasmine 11 | ['/lib/' + File.basename(Dir.glob("#{JasmineHelper.jasmine_lib_dir}/jasmine*.js").first)] + 12 | ['/lib/json2.js', 13 | '/lib/TrivialReporter.js', 14 | '/lib/consolex.js' 15 | ] 16 | end 17 | 18 | def self.jasmine_src_dir 19 | File.expand_path(File.join(jasmine_root, 'src')) 20 | end 21 | 22 | def self.jasmine_spec_dir 23 | File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec')) 24 | end 25 | 26 | def self.raw_spec_files 27 | Dir.glob(File.join(jasmine_spec_dir, "**/*[Ss]pec.js")) 28 | end 29 | 30 | def self.specs 31 | raw_spec_files.collect {|f| f.sub(jasmine_spec_dir, "/spec")} 32 | end 33 | 34 | def self.dir_mappings 35 | { 36 | "/src" => jasmine_src_dir, 37 | "/spec" => jasmine_spec_dir, 38 | "/lib" => jasmine_lib_dir 39 | } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/jasmine_helper.rb: -------------------------------------------------------------------------------- 1 | class JasmineHelper 2 | def self.jasmine_lib_dir 3 | File.expand_path(File.join(jasmine_root, 'lib')) 4 | end 5 | 6 | def self.jasmine 7 | ['/lib/' + File.basename(Dir.glob("#{JasmineHelper.jasmine_lib_dir}/jasmine*.js").first)] + 8 | ['/lib/json2.js', 9 | '/lib/TrivialReporter.js'] 10 | end 11 | 12 | def self.jasmine_root 13 | File.expand_path(File.join(File.dirname(__FILE__), '..')) 14 | end 15 | 16 | 17 | def self.jasmine_src_dir 18 | File.expand_path(File.join(jasmine_root, 'src')) 19 | end 20 | 21 | def self.jasmine_lib_dir 22 | File.expand_path(File.join(jasmine_root, 'lib')) 23 | end 24 | 25 | def self.jasmine_spec_dir 26 | File.expand_path(File.join(jasmine_root, 'spec')) 27 | end 28 | 29 | def self.raw_spec_files 30 | Dir.glob(File.join(jasmine_spec_dir, "**/*[Ss]pec.js")) 31 | end 32 | 33 | def self.specs 34 | Jasmine.cachebust(raw_spec_files).collect {|f| f.sub(jasmine_spec_dir, "/spec")} 35 | end 36 | 37 | def self.dir_mappings 38 | { 39 | "/src" => jasmine_src_dir, 40 | "/spec" => jasmine_spec_dir, 41 | "/lib" => jasmine_lib_dir 42 | } 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /src/Reporters.js: -------------------------------------------------------------------------------- 1 | /** JasmineReporters.reporter 2 | * Base object that will get called whenever a Spec, Suite, or Runner is done. It is up to 3 | * descendants of this object to do something with the results (see json_reporter.js) 4 | * 5 | * @deprecated 6 | */ 7 | jasmine.Reporters = {}; 8 | 9 | /** 10 | * @deprecated 11 | * @param callbacks 12 | */ 13 | jasmine.Reporters.reporter = function(callbacks) { 14 | /** 15 | * @deprecated 16 | * @param callbacks 17 | */ 18 | var that = { 19 | callbacks: callbacks || {}, 20 | 21 | doCallback: function(callback, results) { 22 | if (callback) { 23 | callback(results); 24 | } 25 | }, 26 | 27 | reportRunnerResults: function(runner) { 28 | that.doCallback(that.callbacks.runnerCallback, runner); 29 | }, 30 | reportSuiteResults: function(suite) { 31 | that.doCallback(that.callbacks.suiteCallback, suite); 32 | }, 33 | reportSpecResults: function(spec) { 34 | that.doCallback(that.callbacks.specCallback, spec); 35 | }, 36 | log: function (str) { 37 | if (console && console.log) console.log(str); 38 | } 39 | }; 40 | 41 | return that; 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /spec/suites/MultiReporterSpec.js: -------------------------------------------------------------------------------- 1 | describe("jasmine.MultiReporter", function() { 2 | var multiReporter, fakeReporter1, fakeReporter2; 3 | 4 | beforeEach(function() { 5 | multiReporter = new jasmine.MultiReporter(); 6 | fakeReporter1 = jasmine.createSpyObj("fakeReporter1", ["reportSpecResults"]); 7 | fakeReporter2 = jasmine.createSpyObj("fakeReporter2", ["reportSpecResults", "reportRunnerStarting"]); 8 | multiReporter.addReporter(fakeReporter1); 9 | multiReporter.addReporter(fakeReporter2); 10 | }); 11 | 12 | it("should support all the method calls that jasmine.Reporter supports", function() { 13 | multiReporter.reportRunnerStarting(); 14 | multiReporter.reportRunnerResults(); 15 | multiReporter.reportSuiteResults(); 16 | multiReporter.reportSpecResults(); 17 | multiReporter.log(); 18 | }); 19 | 20 | it("should delegate to any and all subreporters", function() { 21 | multiReporter.reportSpecResults('blah', 'foo'); 22 | expect(fakeReporter1.reportSpecResults).wasCalledWith('blah', 'foo'); 23 | expect(fakeReporter2.reportSpecResults).wasCalledWith('blah', 'foo'); 24 | }); 25 | 26 | it("should quietly skip delegating to any subreporters which lack the given method", function() { 27 | multiReporter.reportRunnerStarting('blah', 'foo'); 28 | expect(fakeReporter2.reportRunnerStarting).wasCalledWith('blah', 'foo'); 29 | }); 30 | }); -------------------------------------------------------------------------------- /src/WaitsForBlock.js: -------------------------------------------------------------------------------- 1 | jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { 2 | this.timeout = timeout; 3 | this.latchFunction = latchFunction; 4 | this.message = message; 5 | this.totalTimeSpentWaitingForLatch = 0; 6 | jasmine.Block.call(this, env, null, spec); 7 | }; 8 | 9 | jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); 10 | 11 | jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100; 12 | 13 | jasmine.WaitsForBlock.prototype.execute = function (onComplete) { 14 | var self = this; 15 | self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen')); 16 | var latchFunctionResult; 17 | try { 18 | latchFunctionResult = self.latchFunction.apply(self.spec); 19 | } catch (e) { 20 | self.spec.fail(e); 21 | onComplete(); 22 | return; 23 | } 24 | 25 | if (latchFunctionResult) { 26 | onComplete(); 27 | } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) { 28 | var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen'); 29 | self.spec.fail({ 30 | name: 'timeout', 31 | message: message 32 | }); 33 | self.spec._next(); 34 | } else { 35 | self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; 36 | self.env.setTimeout(function () { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); 37 | } 38 | }; -------------------------------------------------------------------------------- /lib/jasmine.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; 3 | } 4 | 5 | 6 | body .run_spec { 7 | float:right; 8 | } 9 | 10 | .runner.running { 11 | background-color: yellow; 12 | } 13 | 14 | 15 | 16 | .runner { 17 | border: 1px solid gray; 18 | margin: 5px; 19 | padding-left: 1em; 20 | padding-right: 1em; 21 | } 22 | 23 | 24 | 25 | .suite { 26 | border: 1px outset gray; 27 | margin: 5px; 28 | padding-left: 1em; 29 | } 30 | 31 | .suite.passed { 32 | background-color: #cfc; 33 | } 34 | 35 | .suite.failed { 36 | background-color: #fdd; 37 | } 38 | 39 | .spec { 40 | margin: 5px; 41 | clear: both; 42 | } 43 | 44 | .passed { 45 | background-color: #cfc; 46 | } 47 | 48 | .failed { 49 | background-color: #fdd; 50 | } 51 | 52 | .skipped { 53 | color: #777; 54 | background-color: #eee; 55 | } 56 | 57 | /*.resultMessage {*/ 58 | /*white-space: pre;*/ 59 | /*}*/ 60 | 61 | .resultMessage span.result { 62 | display: block; 63 | line-height: 2em; 64 | color: black; 65 | } 66 | 67 | .resultMessage .mismatch { 68 | color: black; 69 | } 70 | 71 | .stackTrace { 72 | white-space: pre; 73 | font-size: .8em; 74 | margin-left: 10px; 75 | height: 5em; 76 | overflow: auto; 77 | border: 1px inset red; 78 | padding: 1em; 79 | background: #eef; 80 | } 81 | 82 | 83 | #jasmine_content { 84 | position:fixed; 85 | left: 100%; 86 | } 87 | -------------------------------------------------------------------------------- /contrib/ruby/run.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine suite 6 | <% css_files.each do |css_file| %> 7 | 8 | <% end %> 9 | 10 | <% jasmine_files.each do |jasmine_file| %> 11 | 12 | <% end %> 13 | 14 | <% spec_helpers.each do |spec_helper| %> 15 | 16 | <% end %> 17 | 18 | 38 | 39 | <% spec_files.each do |spec_file| %> 40 | 41 | <% end %> 42 | 43 | 44 | 45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace 3 | */ 4 | jasmine.util = {}; 5 | 6 | /** 7 | * Declare that a child class inherit it's prototype from the parent class. 8 | * 9 | * @private 10 | * @param {Function} childClass 11 | * @param {Function} parentClass 12 | */ 13 | jasmine.util.inherit = function(childClass, parentClass) { 14 | /** 15 | * @private 16 | */ 17 | var subclass = function() { 18 | }; 19 | subclass.prototype = parentClass.prototype; 20 | childClass.prototype = new subclass; 21 | }; 22 | 23 | jasmine.util.formatException = function(e) { 24 | var lineNumber; 25 | if (e.line) { 26 | lineNumber = e.line; 27 | } 28 | else if (e.lineNumber) { 29 | lineNumber = e.lineNumber; 30 | } 31 | 32 | var file; 33 | 34 | if (e.sourceURL) { 35 | file = e.sourceURL; 36 | } 37 | else if (e.fileName) { 38 | file = e.fileName; 39 | } 40 | 41 | var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); 42 | 43 | if (file && lineNumber) { 44 | message += ' in ' + file + ' (line ' + lineNumber + ')'; 45 | } 46 | 47 | return message; 48 | }; 49 | 50 | jasmine.util.htmlEscape = function(str) { 51 | if (!str) return str; 52 | return str.replace(/&/g, '&') 53 | .replace(//g, '>'); 55 | }; 56 | 57 | jasmine.util.argsToArray = function(args) { 58 | var arrayOfArgs = []; 59 | for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); 60 | return arrayOfArgs; 61 | }; 62 | 63 | jasmine.util.extend = function(destination, source) { 64 | for (var property in source) destination[property] = source[property]; 65 | return destination; 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /spec/suites/ReporterSpec.js: -------------------------------------------------------------------------------- 1 | describe('jasmine.Reporter', function() { 2 | var env; 3 | 4 | 5 | beforeEach(function() { 6 | env = new jasmine.Env(); 7 | env.updateInterval = 0; 8 | }); 9 | 10 | it('should get called from the test runner', function() { 11 | env.describe('Suite for JSON Reporter with Callbacks', function () { 12 | env.it('should be a test', function() { 13 | this.runs(function () { 14 | this.expect(true).toEqual(true); 15 | }); 16 | }); 17 | env.it('should be a failing test', function() { 18 | this.runs(function () { 19 | this.expect(false).toEqual(true); 20 | }); 21 | }); 22 | }); 23 | env.describe('Suite for JSON Reporter with Callbacks 2', function () { 24 | env.it('should be a test', function() { 25 | this.runs(function () { 26 | this.expect(true).toEqual(true); 27 | }); 28 | }); 29 | 30 | }); 31 | 32 | var foo = 0; 33 | var bar = 0; 34 | var baz = 0; 35 | 36 | var specCallback = function (results) { 37 | foo++; 38 | }; 39 | var suiteCallback = function (results) { 40 | bar++; 41 | }; 42 | var runnerCallback = function (results) { 43 | baz++; 44 | }; 45 | 46 | env.reporter = jasmine.Reporters.reporter({ 47 | specCallback: specCallback, 48 | suiteCallback: suiteCallback, 49 | runnerCallback: runnerCallback 50 | }); 51 | 52 | var runner = env.currentRunner(); 53 | runner.execute(); 54 | 55 | expect(foo).toEqual(3); // 'foo was expected to be 3, was ' + foo); 56 | expect(bar).toEqual(2); // 'bar was expected to be 2, was ' + bar); 57 | expect(baz).toEqual(1); // 'baz was expected to be 1, was ' + baz); 58 | }); 59 | 60 | }); -------------------------------------------------------------------------------- /src/Runner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Runner 3 | * 4 | * @constructor 5 | * @param {jasmine.Env} env 6 | */ 7 | jasmine.Runner = function(env) { 8 | var self = this; 9 | self.env = env; 10 | self.queue = new jasmine.Queue(env); 11 | self.before_ = []; 12 | self.after_ = []; 13 | self.suites_ = []; 14 | }; 15 | 16 | jasmine.Runner.prototype.execute = function() { 17 | var self = this; 18 | if (self.env.reporter.reportRunnerStarting) { 19 | self.env.reporter.reportRunnerStarting(this); 20 | } 21 | self.queue.start(function () { 22 | self.finishCallback(); 23 | }); 24 | }; 25 | 26 | jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { 27 | beforeEachFunction.typeName = 'beforeEach'; 28 | this.before_.push(beforeEachFunction); 29 | }; 30 | 31 | jasmine.Runner.prototype.afterEach = function(afterEachFunction) { 32 | afterEachFunction.typeName = 'afterEach'; 33 | this.after_.push(afterEachFunction); 34 | }; 35 | 36 | 37 | jasmine.Runner.prototype.finishCallback = function() { 38 | this.env.reporter.reportRunnerResults(this); 39 | }; 40 | 41 | jasmine.Runner.prototype.addSuite = function(suite) { 42 | this.suites_.push(suite); 43 | }; 44 | 45 | jasmine.Runner.prototype.add = function(block) { 46 | if (block instanceof jasmine.Suite) { 47 | this.addSuite(block); 48 | } 49 | this.queue.add(block); 50 | }; 51 | 52 | jasmine.Runner.prototype.specs = function () { 53 | var suites = this.suites(); 54 | var specs = []; 55 | for (var i = 0; i < suites.length; i++) { 56 | specs = specs.concat(suites[i].specs()); 57 | } 58 | return specs; 59 | }; 60 | 61 | 62 | jasmine.Runner.prototype.suites = function() { 63 | return this.suites_; 64 | }; 65 | 66 | jasmine.Runner.prototype.results = function() { 67 | return this.queue.results(); 68 | }; -------------------------------------------------------------------------------- /spec/suites/EnvSpec.js: -------------------------------------------------------------------------------- 1 | describe("jasmine.Env", function() { 2 | var env; 3 | beforeEach(function() { 4 | env = new jasmine.Env(); 5 | env.updateInterval = 0; 6 | }); 7 | 8 | describe('ids', function () { 9 | 10 | it('nextSpecId should return consecutive integers, starting at 0', function () { 11 | expect(env.nextSpecId()).toEqual(0); 12 | expect(env.nextSpecId()).toEqual(1); 13 | expect(env.nextSpecId()).toEqual(2); 14 | }); 15 | 16 | }); 17 | describe("reporting", function() { 18 | var fakeReporter; 19 | 20 | beforeEach(function() { 21 | fakeReporter = jasmine.createSpyObj("fakeReporter", ["log"]); 22 | }); 23 | 24 | describe('version', function () { 25 | var oldVersion; 26 | 27 | beforeEach(function () { 28 | oldVersion = jasmine.version_; 29 | }); 30 | 31 | afterEach(function () { 32 | jasmine.version_ = oldVersion; 33 | }); 34 | 35 | it('should raise an error if version is not set', function () { 36 | jasmine.version_ = null; 37 | var exception; 38 | try { 39 | env.version(); 40 | } 41 | catch (e) { 42 | exception = e; 43 | } 44 | expect(exception.message).toEqual('Version not set'); 45 | 46 | }); 47 | 48 | it("version should return the current version as an int", function() { 49 | jasmine.version_ = { 50 | "major": 1, 51 | "minor": 9, 52 | "build": 7, 53 | "revision": 8 54 | }; 55 | expect(env.version()).toEqual({ 56 | "major": 1, 57 | "minor": 9, 58 | "build": 7, 59 | "revision": 8 60 | }); 61 | 62 | }); 63 | }); 64 | 65 | it("should allow reporters to be registered", function() { 66 | env.addReporter(fakeReporter); 67 | env.reporter.log("message"); 68 | expect(fakeReporter.log).wasCalledWith("message"); 69 | }); 70 | }); 71 | }); -------------------------------------------------------------------------------- /src/NestedResults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults 3 | * 4 | * @constructor 5 | */ 6 | jasmine.NestedResults = function() { 7 | /** 8 | * The total count of results 9 | */ 10 | this.totalCount = 0; 11 | /** 12 | * Number of passed results 13 | */ 14 | this.passedCount = 0; 15 | /** 16 | * Number of failed results 17 | */ 18 | this.failedCount = 0; 19 | /** 20 | * Was this suite/spec skipped? 21 | */ 22 | this.skipped = false; 23 | /** 24 | * @ignore 25 | */ 26 | this.items_ = []; 27 | }; 28 | 29 | /** 30 | * Roll up the result counts. 31 | * 32 | * @param result 33 | */ 34 | jasmine.NestedResults.prototype.rollupCounts = function(result) { 35 | this.totalCount += result.totalCount; 36 | this.passedCount += result.passedCount; 37 | this.failedCount += result.failedCount; 38 | }; 39 | 40 | /** 41 | * Tracks a result's message. 42 | * @param message 43 | */ 44 | jasmine.NestedResults.prototype.log = function(message) { 45 | this.items_.push(new jasmine.MessageResult(message)); 46 | }; 47 | 48 | /** 49 | * Getter for the results: message & results. 50 | */ 51 | jasmine.NestedResults.prototype.getItems = function() { 52 | return this.items_; 53 | }; 54 | 55 | /** 56 | * Adds a result, tracking counts (total, passed, & failed) 57 | * @param {jasmine.ExpectationResult|jasmine.NestedResults} result 58 | */ 59 | jasmine.NestedResults.prototype.addResult = function(result) { 60 | if (result.type != 'MessageResult') { 61 | if (result.items_) { 62 | this.rollupCounts(result); 63 | } else { 64 | this.totalCount++; 65 | if (result.passed()) { 66 | this.passedCount++; 67 | } else { 68 | this.failedCount++; 69 | } 70 | } 71 | } 72 | this.items_.push(result); 73 | }; 74 | 75 | /** 76 | * @returns {Boolean} True if everything below passed 77 | */ 78 | jasmine.NestedResults.prototype.passed = function() { 79 | return this.passedCount === this.totalCount; 80 | }; 81 | -------------------------------------------------------------------------------- /src/Suite.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal representation of a Jasmine suite. 3 | * 4 | * @constructor 5 | * @param {jasmine.Env} env 6 | * @param {String} description 7 | * @param {Function} specDefinitions 8 | * @param {jasmine.Suite} parentSuite 9 | */ 10 | jasmine.Suite = function(env, description, specDefinitions, parentSuite) { 11 | var self = this; 12 | self.id = env.nextSuiteId ? env.nextSuiteId() : null; 13 | self.description = description; 14 | self.queue = new jasmine.Queue(env); 15 | self.parentSuite = parentSuite; 16 | self.env = env; 17 | self.before_ = []; 18 | self.after_ = []; 19 | self.specs_ = []; 20 | }; 21 | 22 | jasmine.Suite.prototype.getFullName = function() { 23 | var fullName = this.description; 24 | for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { 25 | fullName = parentSuite.description + ' ' + fullName; 26 | } 27 | return fullName; 28 | }; 29 | 30 | jasmine.Suite.prototype.finish = function(onComplete) { 31 | this.env.reporter.reportSuiteResults(this); 32 | this.finished = true; 33 | if (typeof(onComplete) == 'function') { 34 | onComplete(); 35 | } 36 | }; 37 | 38 | jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { 39 | beforeEachFunction.typeName = 'beforeEach'; 40 | this.before_.push(beforeEachFunction); 41 | }; 42 | 43 | jasmine.Suite.prototype.afterEach = function(afterEachFunction) { 44 | afterEachFunction.typeName = 'afterEach'; 45 | this.after_.push(afterEachFunction); 46 | }; 47 | 48 | jasmine.Suite.prototype.results = function() { 49 | return this.queue.results(); 50 | }; 51 | 52 | jasmine.Suite.prototype.add = function(block) { 53 | if (block instanceof jasmine.Suite) { 54 | this.env.currentRunner().addSuite(block); 55 | } else { 56 | this.specs_.push(block); 57 | } 58 | this.queue.add(block); 59 | }; 60 | 61 | jasmine.Suite.prototype.specs = function() { 62 | return this.specs_; 63 | }; 64 | 65 | jasmine.Suite.prototype.execute = function(onComplete) { 66 | var self = this; 67 | this.queue.start(function () { 68 | self.finish(onComplete); 69 | }); 70 | }; -------------------------------------------------------------------------------- /spec/suites/NestedResultsSpec.js: -------------------------------------------------------------------------------- 1 | describe('jasmine.NestedResults', function() { 2 | it('#addResult increments counters', function() { 3 | // Leaf case 4 | var results = new jasmine.NestedResults(); 5 | 6 | results.addResult(new jasmine.ExpectationResult({ 7 | matcherName: "foo", passed: true, message: 'Passed.', actual: 'bar', expected: 'bar'} 8 | )); 9 | 10 | expect(results.getItems().length).toEqual(1); 11 | expect(results.totalCount).toEqual(1); 12 | expect(results.passedCount).toEqual(1); 13 | expect(results.failedCount).toEqual(0); 14 | 15 | results.addResult(new jasmine.ExpectationResult({ 16 | matcherName: "baz", passed: false, message: 'FAIL.', actual: "corge", expected: "quux" 17 | })); 18 | 19 | expect(results.getItems().length).toEqual(2); 20 | expect(results.totalCount).toEqual(2); 21 | expect(results.passedCount).toEqual(1); 22 | expect(results.failedCount).toEqual(1); 23 | }); 24 | 25 | it('should roll up counts for nested results', function() { 26 | // Branch case 27 | var leafResultsOne = new jasmine.NestedResults(); 28 | leafResultsOne.addResult(new jasmine.ExpectationResult({ 29 | matcherName: "toSomething", passed: true, message: 'message', actual: '', expected:'' 30 | })); 31 | 32 | leafResultsOne.addResult(new jasmine.ExpectationResult({ 33 | matcherName: "toSomethingElse", passed: false, message: 'message', actual: 'a', expected: 'b' 34 | })); 35 | 36 | var leafResultsTwo = new jasmine.NestedResults(); 37 | leafResultsTwo.addResult(new jasmine.ExpectationResult({ 38 | matcherName: "toSomething", passed: true, message: 'message', actual: '', expected: '' 39 | })); 40 | leafResultsTwo.addResult(new jasmine.ExpectationResult({ 41 | matcherName: "toSomethineElse", passed: false, message: 'message', actual: 'c', expected: 'd' 42 | })); 43 | 44 | var branchResults = new jasmine.NestedResults(); 45 | branchResults.addResult(leafResultsOne); 46 | branchResults.addResult(leafResultsTwo); 47 | 48 | expect(branchResults.getItems().length).toEqual(2); 49 | expect(branchResults.totalCount).toEqual(4); 50 | expect(branchResults.passedCount).toEqual(2); 51 | expect(branchResults.failedCount).toEqual(2); 52 | }); 53 | 54 | }); 55 | -------------------------------------------------------------------------------- /contrib/ruby/spec/jasmine_runner_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec' 2 | require 'open-uri' 3 | require 'thin' 4 | 5 | require File.dirname(__FILE__) + '/../jasmine_runner' 6 | 7 | describe Jasmine::SimpleServer do 8 | before do 9 | @port = Jasmine::find_unused_port 10 | end 11 | 12 | after do 13 | Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid 14 | end 15 | 16 | it "should start and print script tags" do 17 | @jasmine_server_pid = fork do 18 | Process.setpgrp 19 | Jasmine::SimpleServer.start(@port, ["file1", "file2"], {}) 20 | exit! 0 21 | end 22 | 23 | Jasmine::wait_for_listener(@port) 24 | 25 | run_html = open("http://localhost:#{@port}/").read 26 | run_html.should =~ / 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/JsApiReporter.js: -------------------------------------------------------------------------------- 1 | /** JavaScript API reporter. 2 | * 3 | * @constructor 4 | */ 5 | jasmine.JsApiReporter = function() { 6 | this.started = false; 7 | this.finished = false; 8 | this.suites_ = []; 9 | this.results_ = {}; 10 | }; 11 | 12 | jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { 13 | this.started = true; 14 | var suites = runner.suites(); 15 | for (var i = 0; i < suites.length; i++) { 16 | var suite = suites[i]; 17 | this.suites_.push(this.summarize_(suite)); 18 | } 19 | }; 20 | 21 | jasmine.JsApiReporter.prototype.suites = function() { 22 | return this.suites_; 23 | }; 24 | 25 | jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { 26 | var isSuite = suiteOrSpec instanceof jasmine.Suite; 27 | var summary = { 28 | id: suiteOrSpec.id, 29 | name: suiteOrSpec.description, 30 | type: isSuite ? 'suite' : 'spec', 31 | children: [] 32 | }; 33 | if (isSuite) { 34 | var specs = suiteOrSpec.specs(); 35 | for (var i = 0; i < specs.length; i++) { 36 | summary.children.push(this.summarize_(specs[i])); 37 | } 38 | } 39 | return summary; 40 | }; 41 | 42 | jasmine.JsApiReporter.prototype.results = function() { 43 | return this.results_; 44 | }; 45 | 46 | jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { 47 | return this.results_[specId]; 48 | }; 49 | 50 | //noinspection JSUnusedLocalSymbols 51 | jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { 52 | this.finished = true; 53 | }; 54 | 55 | //noinspection JSUnusedLocalSymbols 56 | jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { 57 | }; 58 | 59 | //noinspection JSUnusedLocalSymbols 60 | jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { 61 | this.results_[spec.id] = { 62 | messages: spec.results().getItems(), 63 | result: spec.results().failedCount > 0 ? "failed" : "passed" 64 | }; 65 | }; 66 | 67 | //noinspection JSUnusedLocalSymbols 68 | jasmine.JsApiReporter.prototype.log = function(str) { 69 | }; 70 | 71 | jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ 72 | var results = {}; 73 | for (var i = 0; i < specIds.length; i++) { 74 | var specId = specIds[i]; 75 | results[specId] = this.summarizeResult_(this.results_[specId]); 76 | } 77 | return results; 78 | }; 79 | 80 | jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ 81 | var summaryMessages = []; 82 | for (var messageIndex in result.messages) { 83 | var resultMessage = result.messages[messageIndex]; 84 | summaryMessages.push({ 85 | text: resultMessage.text, 86 | passed: resultMessage.passed ? resultMessage.passed() : true, 87 | type: resultMessage.type, 88 | message: resultMessage.message, 89 | trace: { 90 | stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : undefined 91 | } 92 | }); 93 | }; 94 | 95 | var summaryResult = { 96 | result : result.result, 97 | messages : summaryMessages 98 | }; 99 | 100 | return summaryResult; 101 | }; 102 | 103 | -------------------------------------------------------------------------------- /spec/suites/JsApiReporterSpec.js: -------------------------------------------------------------------------------- 1 | describe('jasmine.jsApiReporter', function() { 2 | 3 | 4 | describe('results', function () { 5 | var reporter, spec1, spec2, spec3, expectedSpec1Results, expectedSpec2Results; 6 | 7 | beforeEach(function() { 8 | var env = new jasmine.Env(); 9 | env.updateInterval = 0; 10 | var suite = new jasmine.Suite(env); 11 | spec1 = new jasmine.Spec(env, suite, 'spec 1'); 12 | spec1.runs(function () { 13 | this.expect(true).toEqual(true); 14 | }); 15 | expectedSpec1Results = { 16 | messages: spec1.results().getItems(), 17 | result: "passed" 18 | }; 19 | spec2 = new jasmine.Spec(env, suite, 'spec 2'); 20 | spec2.runs(function () { 21 | this.expect(true).toEqual(false); 22 | }); 23 | expectedSpec2Results = { 24 | messages: spec2.results().getItems(), 25 | result: "failed" 26 | }; 27 | 28 | spec3 = new jasmine.Spec(env, suite, 'spec 3'); 29 | spec3.runs(function () { 30 | this.log('some debug message') 31 | }); 32 | 33 | spec1.execute(); 34 | spec2.execute(); 35 | spec3.execute(); 36 | 37 | reporter = new jasmine.JsApiReporter(); 38 | reporter.reportSpecResults(spec1); 39 | reporter.reportSpecResults(spec2); 40 | reporter.reportSpecResults(spec3); 41 | }); 42 | 43 | it('resultForSpec() should return the result for the given spec', function () { 44 | expect(reporter.resultsForSpec(spec1.id)).toEqual(expectedSpec1Results); 45 | expect(reporter.resultsForSpec(spec2.id)).toEqual(expectedSpec2Results); 46 | 47 | }); 48 | 49 | it('results() should return a hash of all results, indexed by spec id', function () { 50 | expect(reporter.results()[spec1.id]).toEqual(expectedSpec1Results); 51 | expect(reporter.results()[spec2.id]).toEqual(expectedSpec2Results); 52 | }); 53 | 54 | describe("#summarizeResult_", function() { 55 | it("should summarize a passing result", function() { 56 | var result = reporter.results()[spec1.id]; 57 | var summarizedResult = reporter.summarizeResult_(result); 58 | expect(summarizedResult.result).toEqual('passed'); 59 | expect(summarizedResult.messages.length).toEqual(1); 60 | expect(summarizedResult.messages[0].message).toEqual(result.messages[0].message); 61 | expect(summarizedResult.messages[0].passed).toBeTruthy(); 62 | expect(summarizedResult.messages[0].type).toEqual('ExpectationResult'); 63 | expect(summarizedResult.messages[0].text).toEqual(undefined); 64 | expect(summarizedResult.messages[0].trace.stack).toEqual(undefined); 65 | }); 66 | 67 | it("should have a stack trace for failing specs", function() { 68 | var result = reporter.results()[spec2.id]; 69 | var summarizedResult = reporter.summarizeResult_(result); 70 | expect(summarizedResult.result).toEqual('failed'); 71 | expect(summarizedResult.messages[0].trace.stack).toEqual(result.messages[0].trace.stack); 72 | }); 73 | 74 | it("should have messages for specs with messages", function() { 75 | var result = reporter.results()[spec3.id]; 76 | var summarizedResult = reporter.summarizeResult_(result); 77 | expect(summarizedResult.result).toEqual('passed'); 78 | expect(summarizedResult.messages[0].text).toEqual('some debug message'); 79 | }); 80 | }); 81 | }); 82 | }); -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), "spec/jasmine_helper.rb")) 2 | 3 | def jasmine_sources 4 | sources = ["src/base.js", "src/util.js", "src/Env.js", "src/Reporter.js", "src/Block.js"] 5 | sources += Dir.glob('src/*.js').reject{|f| f == 'src/base.js' || sources.include?(f)}.sort 6 | end 7 | 8 | def jasmine_filename(version) 9 | "jasmine-#{version['major']}.#{version['minor']}.#{version['build']}.js" 10 | end 11 | 12 | def version_hash 13 | JSON.parse(File.new("src/version.json").read); 14 | end 15 | 16 | def start_jasmine_server(jasmine_includes = nil) 17 | require File.expand_path(File.join(JasmineHelper.jasmine_root, "contrib/ruby/jasmine_spec_builder")) 18 | 19 | puts "your tests are here:" 20 | puts " http://localhost:8888/run.html" 21 | 22 | Jasmine::SimpleServer.start( 23 | 8888, 24 | lambda { JasmineHelper.specs }, 25 | JasmineHelper.dir_mappings, 26 | :jasmine_files => jasmine_includes) 27 | end 28 | 29 | namespace :jasmine do 30 | desc 'Builds lib/jasmine from source' 31 | task :build => 'jasmine:doc' do 32 | puts 'Building Jasmine from source' 33 | require 'json' 34 | sources = jasmine_sources 35 | version = version_hash 36 | old_jasmine_files = Dir.glob('lib/jasmine*.js') 37 | old_jasmine_files.each do |file| 38 | File.delete(file) 39 | end 40 | jasmine = File.new("lib/#{jasmine_filename version}", 'w') 41 | jasmine.puts(File.read(sources.shift)) 42 | jasmine.puts %{ 43 | jasmine.version_= { 44 | "major": #{version['major']}, 45 | "minor": #{version['minor']}, 46 | "build": #{version['build']}, 47 | "revision": #{Time.now.to_i} 48 | }; 49 | } 50 | sources.each do |source_filename| 51 | jasmine.puts(File.read(source_filename)) 52 | end 53 | jasmine.close 54 | end 55 | 56 | desc "Build jasmine documentation" 57 | task :doc do 58 | puts 'Creating Jasmine Documentation' 59 | require 'rubygems' 60 | #sudo gem install ragaskar-jsdoc_helper 61 | require 'jsdoc_helper' 62 | 63 | 64 | JsdocHelper::Rake::Task.new(:lambda_jsdoc) do |t| 65 | t[:files] = jasmine_sources << 'lib/TrivialReporter.js' 66 | t[:options] = "-a" 67 | end 68 | Rake::Task[:lambda_jsdoc].invoke 69 | end 70 | 71 | 72 | desc "Run jasmine tests of source via server" 73 | task :server do 74 | files = jasmine_sources + ['lib/TrivialReporter.js', 'lib/consolex.js'] 75 | jasmine_includes = lambda { 76 | raw_jasmine_includes = files.collect { |f| File.expand_path(File.join(JasmineHelper.jasmine_root, f)) } 77 | Jasmine.cachebust(raw_jasmine_includes).collect {|f| f.sub(JasmineHelper.jasmine_src_dir, "/src").sub(JasmineHelper.jasmine_lib_dir, "/lib") } 78 | } 79 | start_jasmine_server(jasmine_includes) 80 | end 81 | 82 | desc "Build jasmine and run tests via server" 83 | task :server_build => 'jasmine:build' do 84 | 85 | start_jasmine_server 86 | end 87 | 88 | namespace :test do 89 | desc "Run continuous integration tests" 90 | task :ci => 'jasmine:build' do 91 | require "spec" 92 | require 'spec/rake/spectask' 93 | Spec::Rake::SpecTask.new(:lambda_ci) do |t| 94 | t.spec_opts = ["--color", "--format", "specdoc"] 95 | t.spec_files = ["spec/jasmine_spec.rb"] 96 | end 97 | Rake::Task[:lambda_ci].invoke 98 | end 99 | 100 | end 101 | 102 | end -------------------------------------------------------------------------------- /spec/suites/SuiteSpec.js: -------------------------------------------------------------------------------- 1 | describe('Suite', function() { 2 | var fakeTimer; 3 | var env; 4 | 5 | beforeEach(function() { 6 | env = new jasmine.Env(); 7 | env.updateInterval = 0; 8 | 9 | fakeTimer = new jasmine.FakeTimer(); 10 | env.setTimeout = fakeTimer.setTimeout; 11 | env.clearTimeout = fakeTimer.clearTimeout; 12 | env.setInterval = fakeTimer.setInterval; 13 | env.clearInterval = fakeTimer.clearInterval; 14 | }); 15 | 16 | describe('Specs', function () { 17 | it('#specs should return all immediate children that are specs.', function () { 18 | var suite =env.describe('Suite 1', function () { 19 | env.it('Spec 1', function() { 20 | this.runs(function () { 21 | this.expect(true).toEqual(true); 22 | }); 23 | }); 24 | env.it('Spec 2', function() { 25 | this.runs(function () { 26 | this.expect(true).toEqual(true); 27 | }); 28 | }); 29 | env.describe('Suite 2', function () { 30 | env.it('Spec 3', function() { 31 | this.runs(function () { 32 | this.expect(true).toEqual(true); 33 | }); 34 | }); 35 | }); 36 | env.it('Spec 4', function() { 37 | this.runs(function () { 38 | this.expect(true).toEqual(true); 39 | }); 40 | }); 41 | }); 42 | 43 | var suiteSpecs = suite.specs(); 44 | expect(suiteSpecs.length).toEqual(3); 45 | expect(suiteSpecs[0].description).toEqual('Spec 1'); 46 | expect(suiteSpecs[1].description).toEqual('Spec 2'); 47 | expect(suiteSpecs[2].description).toEqual('Spec 4'); 48 | }); 49 | 50 | describe('SpecCount', function () { 51 | 52 | it('should keep a count of the number of specs that are run', function() { 53 | var suite = env.describe('one suite description', function () { 54 | env.it('should be a test', function() { 55 | this.runs(function () { 56 | this.expect(true).toEqual(true); 57 | }); 58 | }); 59 | env.it('should be another test', function() { 60 | this.runs(function () { 61 | this.expect(true).toEqual(true); 62 | }); 63 | }); 64 | env.it('should be a third test', function() { 65 | this.runs(function () { 66 | this.expect(true).toEqual(true); 67 | }); 68 | }); 69 | }); 70 | 71 | expect(suite.specs().length).toEqual(3); 72 | }); 73 | 74 | it('specCount should be correct even with runs/waits blocks', function() { 75 | var suite = env.describe('one suite description', function () { 76 | env.it('should be a test', function() { 77 | this.runs(function () { 78 | this.expect(true).toEqual(true); 79 | }); 80 | }); 81 | env.it('should be another test', function() { 82 | this.runs(function () { 83 | this.expect(true).toEqual(true); 84 | }); 85 | this.waits(10); 86 | this.runs(function () { 87 | this.expect(true).toEqual(true); 88 | }); 89 | }); 90 | env.it('should be a third test', function() { 91 | this.runs(function () { 92 | this.expect(true).toEqual(true); 93 | }); 94 | }); 95 | }); 96 | 97 | expect(suite.specs().length).toEqual(3); 98 | }); 99 | }); 100 | }); 101 | }); -------------------------------------------------------------------------------- /spec/suites/PrettyPrintSpec.js: -------------------------------------------------------------------------------- 1 | describe("jasmine.pp", function () { 2 | it("should wrap strings in single quotes", function() { 3 | expect(jasmine.pp("some string")).toEqual("'some string'"); 4 | expect(jasmine.pp("som' string")).toEqual("'som' string'"); 5 | }); 6 | 7 | it("should stringify primitives properly", function() { 8 | expect(jasmine.pp(true)).toEqual("true"); 9 | expect(jasmine.pp(false)).toEqual("false"); 10 | expect(jasmine.pp(null)).toEqual("null"); 11 | expect(jasmine.pp(undefined)).toEqual("undefined"); 12 | expect(jasmine.pp(3)).toEqual("3"); 13 | expect(jasmine.pp(-3.14)).toEqual("-3.14"); 14 | }); 15 | 16 | it("should stringify arrays properly", function() { 17 | expect(jasmine.pp([1, 2])).toEqual("[ 1, 2 ]"); 18 | expect(jasmine.pp([1, 'foo', {}, undefined, null])).toEqual("[ 1, 'foo', { }, undefined, null ]"); 19 | }); 20 | 21 | it("should indicate circular array references", function() { 22 | var array1 = [1, 2]; 23 | var array2 = [array1]; 24 | array1.push(array2); 25 | expect(jasmine.pp(array1)).toEqual("[ 1, 2, [ ] ]"); 26 | }); 27 | 28 | it("should stringify objects properly", function() { 29 | expect(jasmine.pp({foo: 'bar'})).toEqual("{ foo : 'bar' }"); 30 | expect(jasmine.pp({foo:'bar', baz:3, nullValue: null, undefinedValue: undefined})).toEqual("{ foo : 'bar', baz : 3, nullValue : null, undefinedValue : undefined }"); 31 | expect(jasmine.pp({foo: function () { 32 | }, bar: [1, 2, 3]})).toEqual("{ foo : Function, bar : [ 1, 2, 3 ] }"); 33 | }); 34 | 35 | it("should stringify RegExp objects properly", function() { 36 | expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); 37 | }); 38 | 39 | it("should indicate circular object references", function() { 40 | var sampleValue = {foo: 'hello'}; 41 | sampleValue.nested = sampleValue; 42 | expect(jasmine.pp(sampleValue)).toEqual("{ foo : 'hello', nested : }"); 43 | }); 44 | 45 | it("should indicate getters on objects as such", function() { 46 | var sampleValue = {id: 1}; 47 | if (sampleValue.__defineGetter__) { 48 | //not supported in IE! 49 | sampleValue.__defineGetter__('calculatedValue', function() { 50 | throw new Error("don't call me!"); 51 | }); 52 | } 53 | if (sampleValue.__defineGetter__) { 54 | expect(jasmine.pp(sampleValue)).toEqual("{ id : 1, calculatedValue : }"); 55 | } 56 | else { 57 | expect(jasmine.pp(sampleValue)).toEqual("{ id : 1 }"); 58 | } 59 | }); 60 | 61 | it("should stringify HTML nodes properly", function() { 62 | var sampleNode = document.createElement('div'); 63 | sampleNode.innerHTML = 'foobar'; 64 | expect(jasmine.pp(sampleNode)).toEqual("HTMLNode"); 65 | expect(jasmine.pp({foo: sampleNode})).toEqual("{ foo : HTMLNode }"); 66 | }); 67 | 68 | it('should not do HTML escaping of strings', function() { 69 | expect(jasmine.pp('some html string &', false)).toEqual('\'some html string &\''); 70 | }); 71 | 72 | it("should abbreviate window objects", function() { 73 | expect(jasmine.pp(window)).toEqual(""); 74 | }); 75 | 76 | it("should stringify Date objects properly", function() { 77 | var now = new Date(); 78 | expect(jasmine.pp(now)).toEqual("Date(" + now.toString() + ")"); 79 | }); 80 | 81 | it("should stringify spy objects properly", function() { 82 | var TestObject = { 83 | someFunction: function() { 84 | } 85 | }; 86 | spyOn(TestObject, 'someFunction'); 87 | expect(jasmine.pp(TestObject.someFunction)).toEqual("spy on someFunction"); 88 | 89 | expect(jasmine.pp(jasmine.createSpy("something"))).toEqual("spy on something"); 90 | }); 91 | 92 | }); 93 | 94 | -------------------------------------------------------------------------------- /spec/suites/SpecSpec.js: -------------------------------------------------------------------------------- 1 | describe('Spec', function () { 2 | var env, suite; 3 | beforeEach(function() { 4 | env = new jasmine.Env(); 5 | env.updateInterval = 0; 6 | suite = new jasmine.Suite(env, 'suite 1'); 7 | }); 8 | 9 | describe('initialization', function () { 10 | 11 | it('should raise an error if an env is not passed', function () { 12 | try { 13 | new jasmine.Spec(); 14 | } 15 | catch (e) { 16 | expect(e.message).toEqual('jasmine.Env() required'); 17 | } 18 | }); 19 | 20 | it('should raise an error if a suite is not passed', function () { 21 | try { 22 | new jasmine.Spec(env); 23 | } 24 | catch (e) { 25 | expect(e.message).toEqual('jasmine.Suite() required'); 26 | } 27 | }); 28 | 29 | it('should assign sequential ids for specs belonging to the same env', function () { 30 | var spec1 = new jasmine.Spec(env, suite); 31 | var spec2 = new jasmine.Spec(env, suite); 32 | var spec3 = new jasmine.Spec(env, suite); 33 | expect(spec1.id).toEqual(0); 34 | expect(spec2.id).toEqual(1); 35 | expect(spec3.id).toEqual(2); 36 | }); 37 | 38 | }); 39 | 40 | it('getFullName returns suite & spec description', function () { 41 | var spec = new jasmine.Spec(env, suite, 'spec 1'); 42 | expect(spec.getFullName()).toEqual('suite 1 spec 1.') 43 | }); 44 | 45 | describe('results', function () { 46 | var spec, results; 47 | beforeEach(function () { 48 | spec = new jasmine.Spec(env, suite); 49 | results = spec.results(); 50 | expect(results.totalCount).toEqual(0); 51 | spec.runs(function () { 52 | this.expect(true).toEqual(true); 53 | this.expect(true).toEqual(true); 54 | }); 55 | }); 56 | 57 | 58 | it('results shows the total number of expectations for each spec after execution', function () { 59 | expect(results.totalCount).toEqual(0); 60 | spec.execute(); 61 | expect(results.totalCount).toEqual(2); 62 | }); 63 | 64 | it('results shows the number of passed expectations for each spec after execution', function () { 65 | expect(results.passedCount).toEqual(0); 66 | spec.execute(); 67 | expect(results.passedCount).toEqual(2); 68 | }); 69 | 70 | it('results shows the number of failed expectations for each spec after execution', function () { 71 | spec.runs(function () { 72 | this.expect(true).toEqual(false); 73 | }); 74 | expect(results.failedCount).toEqual(0); 75 | spec.execute(); 76 | expect(results.failedCount).toEqual(1); 77 | }); 78 | 79 | describe('results.passed', function () { 80 | it('is true if all spec expectations pass', function () { 81 | spec.runs(function () { 82 | this.expect(true).toEqual(true); 83 | }); 84 | spec.execute(); 85 | expect(results.passed()).toEqual(true); 86 | }); 87 | 88 | it('is false if one spec expectation fails', function () { 89 | spec.runs(function () { 90 | this.expect(true).toEqual(false); 91 | }); 92 | spec.execute(); 93 | expect(results.passed()).toEqual(false); 94 | }); 95 | 96 | it('a spec with no expectations will return true', function () { 97 | var specWithoutExpectations = new jasmine.Spec(env, suite); 98 | specWithoutExpectations.runs(function() { 99 | 100 | }); 101 | specWithoutExpectations.execute(); 102 | expect(results.passed()).toEqual(true); 103 | }); 104 | 105 | it('an unexecuted spec will return true', function () { 106 | expect(results.passed()).toEqual(true); 107 | }); 108 | }); 109 | }); 110 | }); -------------------------------------------------------------------------------- /doc/symbols/src/src_WaitsBlock.js.html: -------------------------------------------------------------------------------- 1 |
  1 jasmine.WaitsBlock = function(env, timeout, spec) {
 9 |   2   this.timeout = timeout;
10 |   3   jasmine.Block.call(this, env, null, spec);
11 |   4 };
12 |   5 
13 |   6 jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
14 |   7 
15 |   8 jasmine.WaitsBlock.prototype.execute = function (onComplete) {
16 |   9   this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
17 |  10   this.env.setTimeout(function () {
18 |  11     onComplete();
19 |  12   }, this.timeout);
20 |  13 };
21 |  14 
-------------------------------------------------------------------------------- /doc/symbols/src/src_Block.js.html: -------------------------------------------------------------------------------- 1 |
  1 /**
 9 |   2  * Blocks are functions with executable code that make up a spec.
10 |   3  *
11 |   4  * @constructor
12 |   5  * @param {jasmine.Env} env
13 |   6  * @param {Function} func
14 |   7  * @param {jasmine.Spec} spec
15 |   8  */
16 |   9 jasmine.Block = function(env, func, spec) {
17 |  10   this.env = env;
18 |  11   this.func = func;
19 |  12   this.spec = spec;
20 |  13 };
21 |  14 
22 |  15 jasmine.Block.prototype.execute = function(onComplete) {  
23 |  16   try {
24 |  17     this.func.apply(this.spec);
25 |  18   } catch (e) {
26 |  19     this.spec.fail(e);
27 |  20   }
28 |  21   onComplete();
29 |  22 };
-------------------------------------------------------------------------------- /spec/suites/ExceptionsSpec.js: -------------------------------------------------------------------------------- 1 | describe('Exceptions:', function() { 2 | var env; 3 | 4 | beforeEach(function() { 5 | env = new jasmine.Env(); 6 | env.updateInterval = 0; 7 | }); 8 | 9 | it('jasmine.formatException formats Firefox exception messages as expected', function() { 10 | var sampleFirefoxException = { 11 | fileName: 'foo.js', 12 | line: '1978', 13 | message: 'you got your foo in my bar', 14 | name: 'A Classic Mistake' 15 | }; 16 | 17 | var expected = 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'; 18 | 19 | expect(jasmine.util.formatException(sampleFirefoxException)).toEqual(expected); 20 | }); 21 | 22 | it('jasmine.formatException formats Webkit exception messages as expected', function() { 23 | var sampleWebkitException = { 24 | sourceURL: 'foo.js', 25 | lineNumber: '1978', 26 | message: 'you got your foo in my bar', 27 | name: 'A Classic Mistake' 28 | }; 29 | 30 | var expected = 'A Classic Mistake: you got your foo in my bar in foo.js (line 1978)'; 31 | 32 | expect(jasmine.util.formatException(sampleWebkitException)).toEqual(expected); 33 | }); 34 | 35 | it('should handle exceptions thrown, but continue', function() { 36 | var fakeTimer = new jasmine.FakeTimer(); 37 | env.setTimeout = fakeTimer.setTimeout; 38 | env.clearTimeout = fakeTimer.clearTimeout; 39 | env.setInterval = fakeTimer.setInterval; 40 | env.clearInterval = fakeTimer.clearInterval; 41 | 42 | //we run two exception tests to make sure we continue after throwing an exception 43 | var suite = env.describe('Suite for handles exceptions', function () { 44 | env.it('should be a test that fails because it throws an exception', function() { 45 | throw new Error('fake error 1'); 46 | }); 47 | 48 | env.it('should be another test that fails because it throws an exception', function() { 49 | this.runs(function () { 50 | throw new Error('fake error 2'); 51 | }); 52 | this.runs(function () { 53 | this.expect(true).toEqual(true); 54 | }); 55 | }); 56 | 57 | env.it('should be a passing test that runs after exceptions are thrown', function() { 58 | this.expect(true).toEqual(true); 59 | }); 60 | 61 | env.it('should be another test that fails because it throws an exception after a wait', function() { 62 | this.runs(function () { 63 | var foo = 'foo'; 64 | }); 65 | this.waits(250); 66 | this.runs(function () { 67 | throw new Error('fake error 3'); 68 | }); 69 | }); 70 | 71 | env.it('should be a passing test that runs after exceptions are thrown from a async test', function() { 72 | this.expect(true).toEqual(true); 73 | }); 74 | }); 75 | 76 | var runner = env.currentRunner(); 77 | suite.execute(); 78 | fakeTimer.tick(2500); 79 | 80 | var suiteResults = suite.results(); 81 | var specResults = suiteResults.getItems(); 82 | 83 | expect(suiteResults.passed()).toEqual(false); 84 | // 85 | expect(specResults.length).toEqual(5); 86 | expect(specResults[0].passed()).toMatch(false); 87 | var blockResults = specResults[0].getItems(); 88 | expect(blockResults[0].passed()).toEqual(false); 89 | expect(blockResults[0].message).toMatch(/fake error 1/); 90 | 91 | expect(specResults[1].passed()).toEqual(false); 92 | var blockResults = specResults[1].getItems(); 93 | expect(blockResults[0].passed()).toEqual(false); 94 | expect(blockResults[0].message).toMatch(/fake error 2/), 95 | expect(blockResults[1].passed()).toEqual(true); 96 | 97 | expect(specResults[2].passed()).toEqual(true); 98 | 99 | expect(specResults[3].passed()).toEqual(false); 100 | blockResults = specResults[3].getItems(); 101 | expect(blockResults[0].message).toMatch(/fake error 3/); 102 | 103 | expect(specResults[4].passed()).toEqual(true); 104 | 105 | }); 106 | 107 | }); -------------------------------------------------------------------------------- /src/PrettyPrinter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base class for pretty printing for expectation results. 3 | */ 4 | jasmine.PrettyPrinter = function() { 5 | this.ppNestLevel_ = 0; 6 | }; 7 | 8 | /** 9 | * Formats a value in a nice, human-readable string. 10 | * 11 | * @param value 12 | */ 13 | jasmine.PrettyPrinter.prototype.format = function(value) { 14 | if (this.ppNestLevel_ > 40) { 15 | throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); 16 | } 17 | 18 | this.ppNestLevel_++; 19 | try { 20 | if (value === undefined) { 21 | this.emitScalar('undefined'); 22 | } else if (value === null) { 23 | this.emitScalar('null'); 24 | } else if (value.navigator && value.frames && value.setTimeout) { 25 | this.emitScalar(''); 26 | } else if (value instanceof jasmine.Matchers.Any) { 27 | this.emitScalar(value.toString()); 28 | } else if (typeof value === 'string') { 29 | this.emitString(value); 30 | } else if (jasmine.isSpy(value)) { 31 | this.emitScalar("spy on " + value.identity); 32 | } else if (typeof value === 'function') { 33 | this.emitScalar('Function'); 34 | } else if (typeof value.nodeType === 'number') { 35 | this.emitScalar('HTMLNode'); 36 | } else if (value instanceof Date) { 37 | this.emitScalar('Date(' + value + ')'); 38 | } else if (value instanceof RegExp) { 39 | this.emitScalar(value.toString()); 40 | } else if (value.__Jasmine_been_here_before__) { 41 | this.emitScalar(''); 42 | } else if (jasmine.isArray_(value) || typeof value == 'object') { 43 | value.__Jasmine_been_here_before__ = true; 44 | if (jasmine.isArray_(value)) { 45 | this.emitArray(value); 46 | } else { 47 | this.emitObject(value); 48 | } 49 | delete value.__Jasmine_been_here_before__; 50 | } else { 51 | this.emitScalar(value.toString()); 52 | } 53 | } finally { 54 | this.ppNestLevel_--; 55 | } 56 | }; 57 | 58 | jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { 59 | for (var property in obj) { 60 | if (property == '__Jasmine_been_here_before__') continue; 61 | fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false); 62 | } 63 | }; 64 | 65 | jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; 66 | jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; 67 | jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; 68 | jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; 69 | 70 | jasmine.StringPrettyPrinter = function() { 71 | jasmine.PrettyPrinter.call(this); 72 | 73 | this.string = ''; 74 | }; 75 | jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); 76 | 77 | jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { 78 | this.append(value); 79 | }; 80 | 81 | jasmine.StringPrettyPrinter.prototype.emitString = function(value) { 82 | this.append("'" + value + "'"); 83 | }; 84 | 85 | jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { 86 | this.append('[ '); 87 | for (var i = 0; i < array.length; i++) { 88 | if (i > 0) { 89 | this.append(', '); 90 | } 91 | this.format(array[i]); 92 | } 93 | this.append(' ]'); 94 | }; 95 | 96 | jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { 97 | var self = this; 98 | this.append('{ '); 99 | var first = true; 100 | 101 | this.iterateObject(obj, function(property, isGetter) { 102 | if (first) { 103 | first = false; 104 | } else { 105 | self.append(', '); 106 | } 107 | 108 | self.append(property); 109 | self.append(' : '); 110 | if (isGetter) { 111 | self.append(''); 112 | } else { 113 | self.format(obj[property]); 114 | } 115 | }); 116 | 117 | this.append(' }'); 118 | }; 119 | 120 | jasmine.StringPrettyPrinter.prototype.append = function(value) { 121 | this.string += value; 122 | }; 123 | -------------------------------------------------------------------------------- /doc/symbols/src/src_Reporter.js.html: -------------------------------------------------------------------------------- 1 |
  1 /** No-op base class for Jasmine reporters.
 9 |   2  *
10 |   3  * @constructor
11 |   4  */
12 |   5 jasmine.Reporter = function() {
13 |   6 };
14 |   7 
15 |   8 //noinspection JSUnusedLocalSymbols
16 |   9 jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
17 |  10 };
18 |  11 
19 |  12 //noinspection JSUnusedLocalSymbols
20 |  13 jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
21 |  14 };
22 |  15 
23 |  16 //noinspection JSUnusedLocalSymbols
24 |  17 jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
25 |  18 };
26 |  19 
27 |  20 //noinspection JSUnusedLocalSymbols
28 |  21 jasmine.Reporter.prototype.reportSpecResults = function(spec) {
29 |  22 };
30 |  23 
31 |  24 //noinspection JSUnusedLocalSymbols
32 |  25 jasmine.Reporter.prototype.log = function(str) {
33 |  26 };
34 |  27 
35 |  28 
-------------------------------------------------------------------------------- /contrib/ruby/jasmine_spec_builder.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_runner.rb")) 2 | require 'enumerator' 3 | module Jasmine 4 | 5 | class SpecBuilder 6 | attr_accessor :suites 7 | 8 | def initialize(spec_files, runner) 9 | @spec_files = spec_files 10 | @runner = runner 11 | @spec_ids = [] 12 | end 13 | 14 | def start 15 | guess_example_locations 16 | 17 | @runner.start 18 | load_suite_info 19 | wait_for_suites_to_finish_running 20 | end 21 | 22 | def stop 23 | @runner.stop 24 | end 25 | 26 | def script_path 27 | File.expand_path(__FILE__) 28 | end 29 | 30 | def guess_example_locations 31 | @example_locations = {} 32 | 33 | example_name_parts = [] 34 | previous_indent_level = 0 35 | @spec_files.each do |filename| 36 | line_number = 1 37 | File.open(filename, "r") do |file| 38 | file.readlines.each do |line| 39 | match = /^(\s*)(describe|it)\s*\(\s*["'](.*)["']\s*,\s*function/.match(line) 40 | if (match) 41 | indent_level = match[1].length / 2 42 | example_name = match[3] 43 | example_name_parts[indent_level] = example_name 44 | 45 | full_example_name = example_name_parts.slice(0, indent_level + 1).join(" ") 46 | @example_locations[full_example_name] = "#{filename}:#{line_number}: in `it'" 47 | end 48 | line_number += 1 49 | end 50 | end 51 | end 52 | end 53 | 54 | def load_suite_info 55 | started = Time.now 56 | while !eval_js('jsApiReporter && jsApiReporter.started') do 57 | raise "couldn't connect to Jasmine after 60 seconds" if (started + 60 < Time.now) 58 | sleep 0.1 59 | end 60 | 61 | @suites = eval_js('JSON.stringify(jsApiReporter.suites())') 62 | end 63 | 64 | def results_for(spec_id) 65 | @spec_results ||= load_results 66 | @spec_results[spec_id.to_s] 67 | end 68 | 69 | def load_results 70 | @spec_results = {} 71 | @spec_ids.each_slice(50) do |slice| 72 | @spec_results.merge!(eval_js("JSON.stringify(jsApiReporter.resultsForSpecs(#{JSON.generate(slice)}))")) 73 | end 74 | @spec_results 75 | end 76 | 77 | def wait_for_suites_to_finish_running 78 | puts "Waiting for suite to finish in browser ..." 79 | while !eval_js('jsApiReporter.finished') do 80 | sleep 0.1 81 | end 82 | end 83 | 84 | def declare_suites 85 | me = self 86 | suites.each do |suite| 87 | declare_suite(self, suite) 88 | end 89 | end 90 | 91 | def declare_suite(parent, suite) 92 | me = self 93 | parent.describe suite["name"] do 94 | suite["children"].each do |suite_or_spec| 95 | type = suite_or_spec["type"] 96 | if type == "suite" 97 | me.declare_suite(self, suite_or_spec) 98 | elsif type == "spec" 99 | me.declare_spec(self, suite_or_spec) 100 | else 101 | raise "unknown type #{type} for #{suite_or_spec.inspect}" 102 | end 103 | end 104 | end 105 | end 106 | 107 | def declare_spec(parent, spec) 108 | me = self 109 | example_name = spec["name"] 110 | @spec_ids << spec["id"] 111 | backtrace = @example_locations[parent.description + " " + example_name] 112 | parent.it example_name, {}, backtrace do 113 | me.report_spec(spec["id"]) 114 | end 115 | end 116 | 117 | def report_spec(spec_id) 118 | spec_results = results_for(spec_id) 119 | 120 | out = "" 121 | messages = spec_results['messages'].each do |message| 122 | case 123 | when message["type"] == "MessageResult" 124 | puts message["text"] 125 | puts "\n" 126 | else 127 | unless message["message"] =~ /^Passed.$/ 128 | STDERR << message["message"] 129 | STDERR << "\n" 130 | 131 | out << message["message"] 132 | out << "\n" 133 | end 134 | 135 | if !message["passed"] && message["trace"]["stack"] 136 | stack_trace = message["trace"]["stack"].gsub(/
/, "\n").gsub(/<\/?b>/, " ") 137 | STDERR << stack_trace.gsub(/\(.*\)@http:\/\/localhost:[0-9]+\/specs\//, "/spec/") 138 | STDERR << "\n" 139 | end 140 | end 141 | 142 | end 143 | fail out unless spec_results['result'] == 'passed' 144 | puts out unless out.empty? 145 | end 146 | 147 | private 148 | 149 | def eval_js(js) 150 | @runner.eval_js(js) 151 | end 152 | end 153 | end 154 | -------------------------------------------------------------------------------- /lib/TrivialReporter.js: -------------------------------------------------------------------------------- 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 | if (child) { el.appendChild(child); } 16 | } 17 | } 18 | 19 | for (var attr in attrs) { 20 | el[attr] = attrs[attr]; 21 | } 22 | 23 | return el; 24 | }; 25 | 26 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 27 | var suites = runner.suites(); 28 | 29 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 30 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 31 | this.runnerMessageSpan = this.createDom('span', {}, "Running...")); 32 | this.document.body.appendChild(this.runnerDiv); 33 | 34 | for (var i = 0; i < suites.length; i++) { 35 | var suite = suites[i]; 36 | var suiteDiv = this.createDom('div', { className: 'suite' }, 37 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 38 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 39 | this.suiteDivs[suite.getFullName()] = suiteDiv; 40 | var parentDiv = this.document.body; 41 | if (suite.parentSuite) { 42 | parentDiv = this.suiteDivs[suite.parentSuite.getFullName()]; 43 | } 44 | parentDiv.appendChild(suiteDiv); 45 | } 46 | 47 | this.startedAt = new Date(); 48 | }; 49 | 50 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 51 | var results = runner.results(); 52 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 53 | this.runnerDiv.setAttribute("class", className); 54 | //do it twice for IE 55 | this.runnerDiv.setAttribute("className", className); 56 | var specs = runner.specs(); 57 | var specCount = 0; 58 | for (var i = 0; i < specs.length; i++) { 59 | if (this.specFilter(specs[i])) { 60 | specCount++; 61 | } 62 | } 63 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 64 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 65 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 66 | }; 67 | 68 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 69 | var results = suite.results(); 70 | var status = results.passed() ? 'passed' : 'failed'; 71 | if (results.totalCount == 0) { // todo: change this to check results.skipped 72 | status = 'skipped'; 73 | } 74 | this.suiteDivs[suite.getFullName()].className += " " + status; 75 | }; 76 | 77 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 78 | var results = spec.results(); 79 | var status = results.passed() ? 'passed' : 'failed'; 80 | if (results.skipped) { 81 | status = 'skipped'; 82 | } 83 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 84 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 85 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, spec.getFullName())); 86 | 87 | 88 | var resultItems = results.getItems(); 89 | for (var i = 0; i < resultItems.length; i++) { 90 | var result = resultItems[i]; 91 | if (result.passed && !result.passed()) { 92 | specDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 93 | specDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 94 | } 95 | } 96 | this.suiteDivs[spec.suite.getFullName()].appendChild(specDiv); 97 | }; 98 | 99 | jasmine.TrivialReporter.prototype.log = function() { 100 | console.log.apply(console, arguments); 101 | }; 102 | 103 | jasmine.TrivialReporter.prototype.getLocation = function() { 104 | return this.document.location; 105 | }; 106 | 107 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 108 | var paramMap = {}; 109 | var params = this.getLocation().search.substring(1).split('&'); 110 | for (var i = 0; i < params.length; i++) { 111 | var p = params[i].split('='); 112 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 113 | } 114 | 115 | if (!paramMap["spec"]) return true; 116 | return spec.getFullName().indexOf(paramMap["spec"]) == 0; 117 | }; -------------------------------------------------------------------------------- /spec/suites/TrivialReporterSpec.js: -------------------------------------------------------------------------------- 1 | describe("TrivialReporter", function() { 2 | var trivialReporter; 3 | var body; 4 | 5 | beforeEach(function() { 6 | body = document.createElement("body"); 7 | }); 8 | 9 | function fakeSpec(name) { 10 | return { 11 | getFullName: function() { 12 | return name; 13 | } 14 | }; 15 | } 16 | 17 | it("should run only specs beginning with spec parameter", function() { 18 | var trivialReporter = new jasmine.TrivialReporter({ location: {search: "?spec=run%20this"} }); 19 | expect(trivialReporter.specFilter(fakeSpec("run this"))).toBeTruthy(); 20 | expect(trivialReporter.specFilter(fakeSpec("not the right spec"))).toBeFalsy(); 21 | expect(trivialReporter.specFilter(fakeSpec("not run this"))).toBeFalsy(); 22 | }); 23 | 24 | it("should display empty divs for every suite when the runner is starting", function() { 25 | var trivialReporter = new jasmine.TrivialReporter({ body: body }); 26 | trivialReporter.reportRunnerStarting({ 27 | suites: function() { 28 | return [ new jasmine.Suite({}, "suite 1", null, null) ]; 29 | } 30 | }); 31 | 32 | var divs = body.getElementsByTagName("div"); 33 | expect(divs.length).toEqual(2); 34 | expect(divs[1].innerHTML).toContain("suite 1"); 35 | }); 36 | 37 | describe('Matcher reporting', function () { 38 | var getResultMessageDiv = function (body) { 39 | var divs = body.getElementsByTagName("div"); 40 | for (var i = 0; i < divs.length; i++) { 41 | if (divs[i].className.match(/resultMessage/)) { 42 | return divs[i]; 43 | } 44 | } 45 | }; 46 | 47 | var runner, spec, fakeTimer; 48 | beforeEach(function () { 49 | var env = new jasmine.Env(); 50 | fakeTimer = new jasmine.FakeTimer(); 51 | env.setTimeout = fakeTimer.setTimeout; 52 | env.clearTimeout = fakeTimer.clearTimeout; 53 | env.setInterval = fakeTimer.setInterval; 54 | env.clearInterval = fakeTimer.clearInterval; 55 | runner = env.currentRunner(); 56 | var suite = new jasmine.Suite(env, 'some suite'); 57 | runner.add(suite); 58 | spec = new jasmine.Spec(env, suite, 'some spec'); 59 | suite.add(spec); 60 | var trivialReporter = new jasmine.TrivialReporter({ body: body, location: {search: "?"} }); 61 | env.addReporter(trivialReporter); 62 | }); 63 | 64 | describe('toContain', function () { 65 | it('should show actual and expected', function () { 66 | spec.runs(function () { 67 | this.expect('foo').toContain('bar'); 68 | }); 69 | runner.execute(); 70 | fakeTimer.tick(0); 71 | 72 | var resultEl = getResultMessageDiv(body); 73 | expect(resultEl.innerHTML).toMatch(/foo/); 74 | expect(resultEl.innerHTML).toMatch(/bar/); 75 | }); 76 | }); 77 | }); 78 | 79 | 80 | describe("failure messages (integration)", function () { 81 | var spec, results, expectationResult; 82 | 83 | beforeEach(function() { 84 | results = { 85 | passed: function() { 86 | return false; 87 | }, 88 | getItems: function() { 89 | }}; 90 | 91 | spec = { 92 | suite: { 93 | getFullName: function() { 94 | return "suite 1"; 95 | } 96 | }, 97 | getFullName: function() { 98 | return "foo"; 99 | }, 100 | results: function() { 101 | return results; 102 | } 103 | }; 104 | 105 | trivialReporter = new jasmine.TrivialReporter({ body: body }); 106 | trivialReporter.reportRunnerStarting({ 107 | suites: function() { 108 | return [ new jasmine.Suite({}, "suite 1", null, null) ]; 109 | } 110 | }); 111 | }); 112 | 113 | it("should add the failure message to the DOM (non-toEquals matchers)", function() { 114 | expectationResult = new jasmine.ExpectationResult({ 115 | matcherName: "toBeNull", passed: false, message: "Expected 'a' to be null, but it was not" 116 | }); 117 | 118 | spyOn(results, 'getItems').andReturn([expectationResult]); 119 | 120 | trivialReporter.reportSpecResults(spec); 121 | 122 | var divs = body.getElementsByTagName("div"); 123 | expect(divs[3].innerHTML).toEqual("Expected 'a' to be null, but it was not"); 124 | }); 125 | 126 | it("should add the failure message to the DOM (non-toEquals matchers)", function() { 127 | expectationResult = new jasmine.ExpectationResult({ 128 | matcherName: "toBeNull", passed: false, message: "Expected '1 < 2' to e null, & it was not" 129 | }); 130 | 131 | spyOn(results, 'getItems').andReturn([expectationResult]); 132 | 133 | trivialReporter.reportSpecResults(spec); 134 | 135 | var divs = body.getElementsByTagName("div"); 136 | expect(divs[3].innerHTML).toEqual("Expected '1 < 2' to <b>e null, & it was not"); 137 | }); 138 | }); 139 | 140 | }); 141 | -------------------------------------------------------------------------------- /src/mock-timeout.js: -------------------------------------------------------------------------------- 1 | // Mock setTimeout, clearTimeout 2 | // Contributed by Pivotal Computer Systems, www.pivotalsf.com 3 | 4 | jasmine.FakeTimer = function() { 5 | this.reset(); 6 | 7 | var self = this; 8 | self.setTimeout = function(funcToCall, millis) { 9 | self.timeoutsMade++; 10 | self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); 11 | return self.timeoutsMade; 12 | }; 13 | 14 | self.setInterval = function(funcToCall, millis) { 15 | self.timeoutsMade++; 16 | self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); 17 | return self.timeoutsMade; 18 | }; 19 | 20 | self.clearTimeout = function(timeoutKey) { 21 | self.scheduledFunctions[timeoutKey] = undefined; 22 | }; 23 | 24 | self.clearInterval = function(timeoutKey) { 25 | self.scheduledFunctions[timeoutKey] = undefined; 26 | }; 27 | 28 | }; 29 | 30 | jasmine.FakeTimer.prototype.reset = function() { 31 | this.timeoutsMade = 0; 32 | this.scheduledFunctions = {}; 33 | this.nowMillis = 0; 34 | }; 35 | 36 | jasmine.FakeTimer.prototype.tick = function(millis) { 37 | var oldMillis = this.nowMillis; 38 | var newMillis = oldMillis + millis; 39 | this.runFunctionsWithinRange(oldMillis, newMillis); 40 | this.nowMillis = newMillis; 41 | }; 42 | 43 | jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { 44 | var scheduledFunc; 45 | var funcsToRun = []; 46 | for (var timeoutKey in this.scheduledFunctions) { 47 | scheduledFunc = this.scheduledFunctions[timeoutKey]; 48 | if (scheduledFunc != undefined && 49 | scheduledFunc.runAtMillis >= oldMillis && 50 | scheduledFunc.runAtMillis <= nowMillis) { 51 | funcsToRun.push(scheduledFunc); 52 | this.scheduledFunctions[timeoutKey] = undefined; 53 | } 54 | } 55 | 56 | if (funcsToRun.length > 0) { 57 | funcsToRun.sort(function(a, b) { 58 | return a.runAtMillis - b.runAtMillis; 59 | }); 60 | for (var i = 0; i < funcsToRun.length; ++i) { 61 | try { 62 | var funcToRun = funcsToRun[i]; 63 | this.nowMillis = funcToRun.runAtMillis; 64 | funcToRun.funcToCall(); 65 | if (funcToRun.recurring) { 66 | this.scheduleFunction(funcToRun.timeoutKey, 67 | funcToRun.funcToCall, 68 | funcToRun.millis, 69 | true); 70 | } 71 | } catch(e) { 72 | } 73 | } 74 | this.runFunctionsWithinRange(oldMillis, nowMillis); 75 | } 76 | }; 77 | 78 | jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { 79 | this.scheduledFunctions[timeoutKey] = { 80 | runAtMillis: this.nowMillis + millis, 81 | funcToCall: funcToCall, 82 | recurring: recurring, 83 | timeoutKey: timeoutKey, 84 | millis: millis 85 | }; 86 | }; 87 | 88 | /** 89 | * @namespace 90 | */ 91 | jasmine.Clock = { 92 | defaultFakeTimer: new jasmine.FakeTimer(), 93 | 94 | reset: function() { 95 | jasmine.Clock.assertInstalled(); 96 | jasmine.Clock.defaultFakeTimer.reset(); 97 | }, 98 | 99 | tick: function(millis) { 100 | jasmine.Clock.assertInstalled(); 101 | jasmine.Clock.defaultFakeTimer.tick(millis); 102 | }, 103 | 104 | runFunctionsWithinRange: function(oldMillis, nowMillis) { 105 | jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); 106 | }, 107 | 108 | scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { 109 | jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); 110 | }, 111 | 112 | useMock: function() { 113 | var spec = jasmine.getEnv().currentSpec; 114 | spec.after(jasmine.Clock.uninstallMock); 115 | 116 | jasmine.Clock.installMock(); 117 | }, 118 | 119 | installMock: function() { 120 | jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; 121 | }, 122 | 123 | uninstallMock: function() { 124 | jasmine.Clock.assertInstalled(); 125 | jasmine.Clock.installed = jasmine.Clock.real; 126 | }, 127 | 128 | real: { 129 | setTimeout: window.setTimeout, 130 | clearTimeout: window.clearTimeout, 131 | setInterval: window.setInterval, 132 | clearInterval: window.clearInterval 133 | }, 134 | 135 | assertInstalled: function() { 136 | if (jasmine.Clock.installed != jasmine.Clock.defaultFakeTimer) { 137 | throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); 138 | } 139 | }, 140 | 141 | installed: null 142 | }; 143 | jasmine.Clock.installed = jasmine.Clock.real; 144 | 145 | //else for IE support 146 | window.setTimeout = function(funcToCall, millis) { 147 | if (jasmine.Clock.installed.setTimeout.apply) { 148 | return jasmine.Clock.installed.setTimeout.apply(this, arguments); 149 | } else { 150 | return jasmine.Clock.installed.setTimeout(funcToCall, millis); 151 | } 152 | }; 153 | 154 | window.setInterval = function(funcToCall, millis) { 155 | if (jasmine.Clock.installed.setInterval.apply) { 156 | return jasmine.Clock.installed.setInterval.apply(this, arguments); 157 | } else { 158 | return jasmine.Clock.installed.setInterval(funcToCall, millis); 159 | } 160 | }; 161 | 162 | window.clearTimeout = function(timeoutKey) { 163 | if (jasmine.Clock.installed.clearTimeout.apply) { 164 | return jasmine.Clock.installed.clearTimeout.apply(this, arguments); 165 | } else { 166 | return jasmine.Clock.installed.clearTimeout(timeoutKey); 167 | } 168 | }; 169 | 170 | window.clearInterval = function(timeoutKey) { 171 | if (jasmine.Clock.installed.clearTimeout.apply) { 172 | return jasmine.Clock.installed.clearInterval.apply(this, arguments); 173 | } else { 174 | return jasmine.Clock.installed.clearInterval(timeoutKey); 175 | } 176 | }; 177 | 178 | -------------------------------------------------------------------------------- /src/Spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internal representation of a Jasmine specification, or test. 3 | * 4 | * @constructor 5 | * @param {jasmine.Env} env 6 | * @param {jasmine.Suite} suite 7 | * @param {String} description 8 | */ 9 | jasmine.Spec = function(env, suite, description) { 10 | if (!env) { 11 | throw new Error('jasmine.Env() required'); 12 | } 13 | if (!suite) { 14 | throw new Error('jasmine.Suite() required'); 15 | } 16 | var spec = this; 17 | spec.id = env.nextSpecId ? env.nextSpecId() : null; 18 | spec.env = env; 19 | spec.suite = suite; 20 | spec.description = description; 21 | spec.queue = new jasmine.Queue(env); 22 | 23 | spec.afterCallbacks = []; 24 | spec.spies_ = []; 25 | 26 | spec.results_ = new jasmine.NestedResults(); 27 | spec.results_.description = description; 28 | spec.matchersClass = null; 29 | }; 30 | 31 | jasmine.Spec.prototype.getFullName = function() { 32 | return this.suite.getFullName() + ' ' + this.description + '.'; 33 | }; 34 | 35 | 36 | jasmine.Spec.prototype.results = function() { 37 | return this.results_; 38 | }; 39 | 40 | jasmine.Spec.prototype.log = function(message) { 41 | return this.results_.log(message); 42 | }; 43 | 44 | /** @deprecated */ 45 | jasmine.Spec.prototype.getResults = function() { 46 | return this.results_; 47 | }; 48 | 49 | jasmine.Spec.prototype.runs = function (func) { 50 | var block = new jasmine.Block(this.env, func, this); 51 | this.addToQueue(block); 52 | return this; 53 | }; 54 | 55 | jasmine.Spec.prototype.addToQueue = function (block) { 56 | if (this.queue.isRunning()) { 57 | this.queue.insertNext(block); 58 | } else { 59 | this.queue.add(block); 60 | } 61 | }; 62 | 63 | jasmine.Spec.prototype.addMatcherResult = function(result) { 64 | this.results_.addResult(result); 65 | }; 66 | 67 | jasmine.Spec.prototype.expect = function(actual) { 68 | return new (this.getMatchersClass_())(this.env, actual, this); 69 | }; 70 | 71 | jasmine.Spec.prototype.waits = function(timeout) { 72 | var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); 73 | this.addToQueue(waitsFunc); 74 | return this; 75 | }; 76 | 77 | jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) { 78 | var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this); 79 | this.addToQueue(waitsForFunc); 80 | return this; 81 | }; 82 | 83 | jasmine.Spec.prototype.fail = function (e) { 84 | var expectationResult = new jasmine.ExpectationResult({ 85 | passed: false, 86 | message: e ? jasmine.util.formatException(e) : 'Exception' 87 | }); 88 | this.results_.addResult(expectationResult); 89 | }; 90 | 91 | jasmine.Spec.prototype.getMatchersClass_ = function() { 92 | return this.matchersClass || this.env.matchersClass; 93 | }; 94 | 95 | jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { 96 | var parent = this.getMatchersClass_(); 97 | var newMatchersClass = function() { 98 | parent.apply(this, arguments); 99 | }; 100 | jasmine.util.inherit(newMatchersClass, parent); 101 | for (var method in matchersPrototype) { 102 | newMatchersClass.prototype[method] = matchersPrototype[method]; 103 | } 104 | this.matchersClass = newMatchersClass; 105 | }; 106 | 107 | jasmine.Spec.prototype.finishCallback = function() { 108 | this.env.reporter.reportSpecResults(this); 109 | }; 110 | 111 | jasmine.Spec.prototype.finish = function(onComplete) { 112 | this.removeAllSpies(); 113 | this.finishCallback(); 114 | if (onComplete) { 115 | onComplete(); 116 | } 117 | }; 118 | 119 | jasmine.Spec.prototype.after = function(doAfter, test) { 120 | 121 | if (this.queue.isRunning()) { 122 | this.queue.add(new jasmine.Block(this.env, doAfter, this)); 123 | } else { 124 | this.afterCallbacks.unshift(doAfter); 125 | } 126 | }; 127 | 128 | jasmine.Spec.prototype.execute = function(onComplete) { 129 | var spec = this; 130 | if (!spec.env.specFilter(spec)) { 131 | spec.results_.skipped = true; 132 | spec.finish(onComplete); 133 | return; 134 | } 135 | this.env.reporter.log('>> Jasmine Running ' + this.suite.description + ' ' + this.description + '...'); 136 | 137 | spec.env.currentSpec = spec; 138 | 139 | spec.addBeforesAndAftersToQueue(); 140 | 141 | spec.queue.start(function () { 142 | spec.finish(onComplete); 143 | }); 144 | }; 145 | 146 | jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { 147 | var runner = this.env.currentRunner(); 148 | for (var suite = this.suite; suite; suite = suite.parentSuite) { 149 | for (var i = 0; i < suite.before_.length; i++) { 150 | this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); 151 | } 152 | } 153 | for (var i = 0; i < runner.before_.length; i++) { 154 | this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); 155 | } 156 | for (i = 0; i < this.afterCallbacks.length; i++) { 157 | this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); 158 | } 159 | for (suite = this.suite; suite; suite = suite.parentSuite) { 160 | for (var i = 0; i < suite.after_.length; i++) { 161 | this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); 162 | } 163 | } 164 | for (var i = 0; i < runner.after_.length; i++) { 165 | this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); 166 | } 167 | }; 168 | 169 | jasmine.Spec.prototype.explodes = function() { 170 | throw 'explodes function should not have been called'; 171 | }; 172 | 173 | jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { 174 | if (obj == undefined) { 175 | throw "spyOn could not find an object to spy upon for " + methodName + "()"; 176 | } 177 | 178 | if (!ignoreMethodDoesntExist && obj[methodName] === undefined) { 179 | throw methodName + '() method does not exist'; 180 | } 181 | 182 | if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { 183 | throw new Error(methodName + ' has already been spied upon'); 184 | } 185 | 186 | var spyObj = jasmine.createSpy(methodName); 187 | 188 | this.spies_.push(spyObj); 189 | spyObj.baseObj = obj; 190 | spyObj.methodName = methodName; 191 | spyObj.originalValue = obj[methodName]; 192 | 193 | obj[methodName] = spyObj; 194 | 195 | return spyObj; 196 | }; 197 | 198 | jasmine.Spec.prototype.removeAllSpies = function() { 199 | for (var i = 0; i < this.spies_.length; i++) { 200 | var spy = this.spies_[i]; 201 | spy.baseObj[spy.methodName] = spy.originalValue; 202 | } 203 | this.spies_ = []; 204 | }; 205 | 206 | -------------------------------------------------------------------------------- /spec/suites/SpySpec.js: -------------------------------------------------------------------------------- 1 | describe('Spies', function () { 2 | it('should replace the specified function with a spy object', function() { 3 | var originalFunctionWasCalled = false; 4 | var TestClass = { 5 | someFunction: function() { 6 | originalFunctionWasCalled = true; 7 | } 8 | }; 9 | this.spyOn(TestClass, 'someFunction'); 10 | 11 | expect(TestClass.someFunction.wasCalled).toEqual(false); 12 | expect(TestClass.someFunction.callCount).toEqual(0); 13 | TestClass.someFunction('foo'); 14 | expect(TestClass.someFunction.wasCalled).toEqual(true); 15 | expect(TestClass.someFunction.callCount).toEqual(1); 16 | expect(TestClass.someFunction.mostRecentCall.args).toEqual(['foo']); 17 | expect(TestClass.someFunction.mostRecentCall.object).toEqual(TestClass); 18 | expect(originalFunctionWasCalled).toEqual(false); 19 | 20 | TestClass.someFunction('bar'); 21 | expect(TestClass.someFunction.callCount).toEqual(2); 22 | expect(TestClass.someFunction.mostRecentCall.args).toEqual(['bar']); 23 | }); 24 | 25 | it('should allow you to view args for a particular call', function() { 26 | var originalFunctionWasCalled = false; 27 | var TestClass = { 28 | someFunction: function() { 29 | originalFunctionWasCalled = true; 30 | } 31 | }; 32 | this.spyOn(TestClass, 'someFunction'); 33 | 34 | TestClass.someFunction('foo'); 35 | TestClass.someFunction('bar'); 36 | expect(TestClass.someFunction.argsForCall[0]).toEqual(['foo']); 37 | expect(TestClass.someFunction.argsForCall[1]).toEqual(['bar']); 38 | expect(TestClass.someFunction.mostRecentCall.args).toEqual(['bar']); 39 | }); 40 | 41 | it('should be possible to call through to the original method, or return a specific result', function() { 42 | var originalFunctionWasCalled = false; 43 | var passedArgs; 44 | var passedObj; 45 | var TestClass = { 46 | someFunction: function() { 47 | originalFunctionWasCalled = true; 48 | passedArgs = arguments; 49 | passedObj = this; 50 | return "return value from original function"; 51 | } 52 | }; 53 | 54 | this.spyOn(TestClass, 'someFunction').andCallThrough(); 55 | var result = TestClass.someFunction('arg1', 'arg2'); 56 | expect(result).toEqual("return value from original function"); 57 | expect(originalFunctionWasCalled).toEqual(true); 58 | expect(passedArgs).toEqual(['arg1', 'arg2']); 59 | expect(passedObj).toEqual(TestClass); 60 | expect(TestClass.someFunction.wasCalled).toEqual(true); 61 | }); 62 | 63 | it('should be possible to return a specific value', function() { 64 | var originalFunctionWasCalled = false; 65 | var TestClass = { 66 | someFunction: function() { 67 | originalFunctionWasCalled = true; 68 | return "return value from original function"; 69 | } 70 | }; 71 | 72 | this.spyOn(TestClass, 'someFunction').andReturn("some value"); 73 | originalFunctionWasCalled = false; 74 | var result = TestClass.someFunction('arg1', 'arg2'); 75 | expect(result).toEqual("some value"); 76 | expect(originalFunctionWasCalled).toEqual(false); 77 | }); 78 | 79 | it('should be possible to throw a specific error', function() { 80 | var originalFunctionWasCalled = false; 81 | var TestClass = { 82 | someFunction: function() { 83 | originalFunctionWasCalled = true; 84 | return "return value from original function"; 85 | } 86 | }; 87 | 88 | this.spyOn(TestClass, 'someFunction').andThrow(new Error('fake error')); 89 | var exception; 90 | try { 91 | TestClass.someFunction('arg1', 'arg2'); 92 | } catch (e) { 93 | exception = e; 94 | } 95 | expect(exception.message).toEqual('fake error'); 96 | expect(originalFunctionWasCalled).toEqual(false); 97 | }); 98 | 99 | it('should be possible to call a specified function', function() { 100 | var originalFunctionWasCalled = false; 101 | var fakeFunctionWasCalled = false; 102 | var passedArgs; 103 | var passedObj; 104 | var TestClass = { 105 | someFunction: function() { 106 | originalFunctionWasCalled = true; 107 | return "return value from original function"; 108 | } 109 | }; 110 | 111 | this.spyOn(TestClass, 'someFunction').andCallFake(function() { 112 | fakeFunctionWasCalled = true; 113 | passedArgs = arguments; 114 | passedObj = this; 115 | return "return value from fake function"; 116 | }); 117 | 118 | var result = TestClass.someFunction('arg1', 'arg2'); 119 | expect(result).toEqual("return value from fake function"); 120 | expect(originalFunctionWasCalled).toEqual(false); 121 | expect(fakeFunctionWasCalled).toEqual(true); 122 | expect(passedArgs).toEqual(['arg1', 'arg2']); 123 | expect(passedObj).toEqual(TestClass); 124 | expect(TestClass.someFunction.wasCalled).toEqual(true); 125 | }); 126 | 127 | it('is torn down when this.removeAllSpies is called', function() { 128 | var originalFunctionWasCalled = false; 129 | var TestClass = { 130 | someFunction: function() { 131 | originalFunctionWasCalled = true; 132 | } 133 | }; 134 | this.spyOn(TestClass, 'someFunction'); 135 | 136 | TestClass.someFunction('foo'); 137 | expect(originalFunctionWasCalled).toEqual(false); 138 | 139 | this.removeAllSpies(); 140 | 141 | TestClass.someFunction('foo'); 142 | expect(originalFunctionWasCalled).toEqual(true); 143 | }); 144 | 145 | it('calls removeAllSpies during spec finish', function() { 146 | var test = new jasmine.Spec(new jasmine.Env(), {}, 'sample test'); 147 | 148 | this.spyOn(test, 'removeAllSpies'); 149 | 150 | test.finish(); 151 | 152 | expect(test.removeAllSpies).wasCalled(); 153 | }); 154 | 155 | it('throws an exception when some method is spied on twice', function() { 156 | var TestClass = { someFunction: function() { 157 | } }; 158 | this.spyOn(TestClass, 'someFunction'); 159 | var exception; 160 | try { 161 | this.spyOn(TestClass, 'someFunction'); 162 | } catch (e) { 163 | exception = e; 164 | } 165 | expect(exception).toBeDefined(); 166 | }); 167 | 168 | it('should be able to reset a spy', function() { 169 | var TestClass = { someFunction: function() {} }; 170 | this.spyOn(TestClass, 'someFunction'); 171 | 172 | expect(TestClass.someFunction).wasNotCalled(); 173 | TestClass.someFunction(); 174 | expect(TestClass.someFunction).wasCalled(); 175 | TestClass.someFunction.reset(); 176 | expect(TestClass.someFunction).wasNotCalled(); 177 | expect(TestClass.someFunction.callCount).toEqual(0); 178 | }); 179 | 180 | it("should create an object with a bunch of spy methods when you call jasmine.createSpyObj()", function() { 181 | var spyObj = jasmine.createSpyObj('BaseName', ['method1', 'method2']); 182 | expect(spyObj).toEqual({ method1: jasmine.any(Function), method2: jasmine.any(Function)}); 183 | expect(spyObj.method1.identity).toEqual('BaseName.method1'); 184 | expect(spyObj.method2.identity).toEqual('BaseName.method2'); 185 | }); 186 | 187 | }); -------------------------------------------------------------------------------- /src/Env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Environment for Jasmine 3 | * 4 | * @constructor 5 | */ 6 | jasmine.Env = function() { 7 | this.currentSpec = null; 8 | this.currentSuite = null; 9 | this.currentRunner_ = new jasmine.Runner(this); 10 | 11 | this.reporter = new jasmine.MultiReporter(); 12 | 13 | this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; 14 | this.lastUpdate = 0; 15 | this.specFilter = function() { 16 | return true; 17 | }; 18 | 19 | this.nextSpecId_ = 0; 20 | this.nextSuiteId_ = 0; 21 | this.equalityTesters_ = []; 22 | 23 | // wrap matchers 24 | this.matchersClass = function() { 25 | jasmine.Matchers.apply(this, arguments); 26 | }; 27 | jasmine.util.inherit(this.matchersClass, jasmine.Matchers); 28 | 29 | for (var methodName in jasmine.Matchers.prototype) { 30 | var orig = jasmine.Matchers.prototype[methodName]; 31 | this.matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); 32 | } 33 | }; 34 | 35 | 36 | jasmine.Env.prototype.setTimeout = jasmine.setTimeout; 37 | jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; 38 | jasmine.Env.prototype.setInterval = jasmine.setInterval; 39 | jasmine.Env.prototype.clearInterval = jasmine.clearInterval; 40 | 41 | /** 42 | * @returns an object containing jasmine version build info, if set. 43 | */ 44 | jasmine.Env.prototype.version = function () { 45 | if (jasmine.version_) { 46 | return jasmine.version_; 47 | } else { 48 | throw new Error('Version not set'); 49 | } 50 | }; 51 | 52 | /** 53 | * @returns a sequential integer starting at 0 54 | */ 55 | jasmine.Env.prototype.nextSpecId = function () { 56 | return this.nextSpecId_++; 57 | }; 58 | 59 | /** 60 | * @returns a sequential integer starting at 0 61 | */ 62 | jasmine.Env.prototype.nextSuiteId = function () { 63 | return this.nextSuiteId_++; 64 | }; 65 | 66 | /** 67 | * Register a reporter to receive status updates from Jasmine. 68 | * @param {jasmine.Reporter} reporter An object which will receive status updates. 69 | */ 70 | jasmine.Env.prototype.addReporter = function(reporter) { 71 | this.reporter.addReporter(reporter); 72 | }; 73 | 74 | jasmine.Env.prototype.execute = function() { 75 | this.currentRunner_.execute(); 76 | }; 77 | 78 | jasmine.Env.prototype.describe = function(description, specDefinitions) { 79 | var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); 80 | 81 | var parentSuite = this.currentSuite; 82 | if (parentSuite) { 83 | parentSuite.add(suite); 84 | } else { 85 | this.currentRunner_.add(suite); 86 | } 87 | 88 | this.currentSuite = suite; 89 | 90 | specDefinitions.call(suite); 91 | 92 | this.currentSuite = parentSuite; 93 | 94 | return suite; 95 | }; 96 | 97 | jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { 98 | if (this.currentSuite) { 99 | this.currentSuite.beforeEach(beforeEachFunction); 100 | } else { 101 | this.currentRunner_.beforeEach(beforeEachFunction); 102 | } 103 | }; 104 | 105 | jasmine.Env.prototype.currentRunner = function () { 106 | return this.currentRunner_; 107 | }; 108 | 109 | jasmine.Env.prototype.afterEach = function(afterEachFunction) { 110 | if (this.currentSuite) { 111 | this.currentSuite.afterEach(afterEachFunction); 112 | } else { 113 | this.currentRunner_.afterEach(afterEachFunction); 114 | } 115 | 116 | }; 117 | 118 | jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { 119 | return { 120 | execute: function() { 121 | } 122 | }; 123 | }; 124 | 125 | jasmine.Env.prototype.it = function(description, func) { 126 | var spec = new jasmine.Spec(this, this.currentSuite, description); 127 | this.currentSuite.add(spec); 128 | this.currentSpec = spec; 129 | 130 | if (func) { 131 | spec.runs(func); 132 | } 133 | 134 | return spec; 135 | }; 136 | 137 | jasmine.Env.prototype.xit = function(desc, func) { 138 | return { 139 | id: this.nextSpecId(), 140 | runs: function() { 141 | } 142 | }; 143 | }; 144 | 145 | jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { 146 | if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { 147 | return true; 148 | } 149 | 150 | a.__Jasmine_been_here_before__ = b; 151 | b.__Jasmine_been_here_before__ = a; 152 | 153 | var hasKey = function(obj, keyName) { 154 | return obj != null && obj[keyName] !== undefined; 155 | }; 156 | 157 | for (var property in b) { 158 | if (!hasKey(a, property) && hasKey(b, property)) { 159 | mismatchKeys.push("expected has key '" + property + "', but missing from actual."); 160 | } 161 | } 162 | for (property in a) { 163 | if (!hasKey(b, property) && hasKey(a, property)) { 164 | mismatchKeys.push("expected missing key '" + property + "', but present in actual."); 165 | } 166 | } 167 | for (property in b) { 168 | if (property == '__Jasmine_been_here_before__') continue; 169 | if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { 170 | mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); 171 | } 172 | } 173 | 174 | if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { 175 | mismatchValues.push("arrays were not the same length"); 176 | } 177 | 178 | delete a.__Jasmine_been_here_before__; 179 | delete b.__Jasmine_been_here_before__; 180 | return (mismatchKeys.length == 0 && mismatchValues.length == 0); 181 | }; 182 | 183 | jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { 184 | mismatchKeys = mismatchKeys || []; 185 | mismatchValues = mismatchValues || []; 186 | 187 | if (a === b) return true; 188 | 189 | if (a === undefined || a === null || b === undefined || b === null) { 190 | return (a == undefined && b == undefined); 191 | } 192 | 193 | if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { 194 | return a === b; 195 | } 196 | 197 | if (a instanceof Date && b instanceof Date) { 198 | return a.getTime() == b.getTime(); 199 | } 200 | 201 | if (a instanceof jasmine.Matchers.Any) { 202 | return a.matches(b); 203 | } 204 | 205 | if (b instanceof jasmine.Matchers.Any) { 206 | return b.matches(a); 207 | } 208 | 209 | if (typeof a === "object" && typeof b === "object") { 210 | return this.compareObjects_(a, b, mismatchKeys, mismatchValues); 211 | } 212 | 213 | for (var i = 0; i < this.equalityTesters_.length; i++) { 214 | var equalityTester = this.equalityTesters_[i]; 215 | var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); 216 | if (result !== undefined) return result; 217 | } 218 | 219 | //Straight check 220 | return (a === b); 221 | }; 222 | 223 | jasmine.Env.prototype.contains_ = function(haystack, needle) { 224 | if (jasmine.isArray_(haystack)) { 225 | for (var i = 0; i < haystack.length; i++) { 226 | if (this.equals_(haystack[i], needle)) return true; 227 | } 228 | return false; 229 | } 230 | return haystack.indexOf(needle) >= 0; 231 | }; 232 | 233 | jasmine.Env.prototype.addEqualityTester = function(equalityTester) { 234 | this.equalityTesters_.push(equalityTester); 235 | }; 236 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | JsDoc Reference - Index 8 | 9 | 10 | 174 | 175 | 176 | 177 | 179 | 180 |
181 | 183 |
184 |

Classes

185 | 218 |
219 |
220 | 221 |
222 |

Class Index

223 | 224 | 225 |
226 |

_global_

227 | 228 |
229 |
230 | 231 |
232 |

jasmine

233 | 234 |
235 |
236 | 237 |
238 |

jasmine.Block

239 | 240 |
241 |
242 | 243 |
244 |

jasmine.Clock

245 | 246 |
247 |
248 | 249 |
250 |

jasmine.Env

251 | 252 |
253 |
254 | 255 |
256 |

jasmine.JsApiReporter

257 | 258 |
259 |
260 | 261 |
262 |

jasmine.Matchers

263 | 264 |
265 |
266 | 267 |
268 |

jasmine.MultiReporter

269 | 270 |
271 |
272 | 273 |
274 |

jasmine.NestedResults

275 | 276 |
277 |
278 | 279 |
280 |

jasmine.Reporter

281 | 282 |
283 |
284 | 285 |
286 |

jasmine.Runner

287 | 288 |
289 |
290 | 291 |
292 |

jasmine.Spec

293 | 294 |
295 |
296 | 297 |
298 |

jasmine.Spy

299 | 300 |
301 |
302 | 303 |
304 |

jasmine.Suite

305 | 306 |
307 |
308 | 309 |
310 |

jasmine.util

311 | 312 |
313 |
314 | 315 | 316 |
317 |
318 | 319 | Documentation generated by JsDoc Toolkit 2.1.0 on Tue Nov 10 2009 17:31:30 GMT-0500 (EST) 320 |
321 | 322 | -------------------------------------------------------------------------------- /doc/symbols/src/src_Reporters.js.html: -------------------------------------------------------------------------------- 1 |
  1 /** JasmineReporters.reporter
 9 |   2  *    Base object that will get called whenever a Spec, Suite, or Runner is done.  It is up to
10 |   3  *    descendants of this object to do something with the results (see json_reporter.js)
11 |   4  *
12 |   5  * @deprecated
13 |   6  */
14 |   7 jasmine.Reporters = {};
15 |   8 
16 |   9 /**
17 |  10  * @deprecated
18 |  11  * @param callbacks
19 |  12  */
20 |  13 jasmine.Reporters.reporter = function(callbacks) {
21 |  14   /**
22 |  15    * @deprecated
23 |  16    * @param callbacks
24 |  17    */
25 |  18   var that = {
26 |  19     callbacks: callbacks || {},
27 |  20 
28 |  21     doCallback: function(callback, results) {
29 |  22       if (callback) {
30 |  23         callback(results);
31 |  24       }
32 |  25     },
33 |  26 
34 |  27     reportRunnerResults: function(runner) {
35 |  28       that.doCallback(that.callbacks.runnerCallback, runner);
36 |  29     },
37 |  30     reportSuiteResults:  function(suite) {
38 |  31       that.doCallback(that.callbacks.suiteCallback, suite);
39 |  32     },
40 |  33     reportSpecResults:   function(spec) {
41 |  34       that.doCallback(that.callbacks.specCallback, spec);
42 |  35     },
43 |  36     log: function (str) {
44 |  37       if (console && console.log) console.log(str);
45 |  38     }
46 |  39   };
47 |  40 
48 |  41   return that;
49 |  42 };
50 |  43 
51 |  44 
-------------------------------------------------------------------------------- /doc/symbols/src/src_MultiReporter.js.html: -------------------------------------------------------------------------------- 1 |
  1 /**
 9 |   2  * @constructor
10 |   3  */
11 |   4 jasmine.MultiReporter = function() {
12 |   5   this.subReporters_ = [];
13 |   6 };
14 |   7 jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
15 |   8 
16 |   9 jasmine.MultiReporter.prototype.addReporter = function(reporter) {
17 |  10   this.subReporters_.push(reporter);
18 |  11 };
19 |  12 
20 |  13 (function() {
21 |  14   var functionNames = ["reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecResults", "log"];
22 |  15   for (var i = 0; i < functionNames.length; i++) {
23 |  16     var functionName = functionNames[i];
24 |  17     jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
25 |  18       return function() {
26 |  19         for (var j = 0; j < this.subReporters_.length; j++) {
27 |  20           var subReporter = this.subReporters_[j];
28 |  21           if (subReporter[functionName]) {
29 |  22             subReporter[functionName].apply(subReporter, arguments);
30 |  23           }
31 |  24         }
32 |  25       };
33 |  26     })(functionName);
34 |  27   }
35 |  28 })();
36 |  29 
-------------------------------------------------------------------------------- /spec/suites/RunnerSpec.js: -------------------------------------------------------------------------------- 1 | describe('RunnerTest', function() { 2 | var fakeTimer; 3 | var env; 4 | 5 | beforeEach(function() { 6 | env = new jasmine.Env(); 7 | env.updateInterval = 0; 8 | 9 | fakeTimer = new jasmine.FakeTimer(); 10 | env.setTimeout = fakeTimer.setTimeout; 11 | env.clearTimeout = fakeTimer.clearTimeout; 12 | env.setInterval = fakeTimer.setInterval; 13 | env.clearInterval = fakeTimer.clearInterval; 14 | }); 15 | 16 | describe('beforeEach', function() { 17 | it('should run before each spec for all suites', function () { 18 | var foo; 19 | env.beforeEach(function () { 20 | foo = 0; 21 | }); 22 | 23 | env.describe('suite 1', function () { 24 | env.it('test 1-1', function() { 25 | foo++; 26 | this.expect(foo).toEqual(1); 27 | }); 28 | env.it('test 1-2', function() { 29 | foo++; 30 | this.expect(foo).toEqual(1); 31 | }); 32 | }); 33 | 34 | env.describe('suite 2', function () { 35 | env.it('test 2-1', function() { 36 | foo++; 37 | this.expect(foo).toEqual(1); 38 | }); 39 | }); 40 | 41 | env.currentRunner().execute(); 42 | 43 | var runnerResults = env.currentRunner().results(); 44 | expect(runnerResults.totalCount).toEqual(3); 45 | expect(runnerResults.passedCount).toEqual(3); 46 | }); 47 | 48 | 49 | it('should provide all specs', function () { 50 | var foo; 51 | env.beforeEach(function () { 52 | foo = 0; 53 | }); 54 | 55 | env.describe('suite 1', function () { 56 | env.it('test 1-1', function() { 57 | foo++; 58 | this.expect(foo).toEqual(1); 59 | }); 60 | env.it('test 1-2', function() { 61 | foo++; 62 | this.expect(foo).toEqual(1); 63 | }); 64 | }); 65 | 66 | env.describe('suite 2', function () { 67 | env.it('test 2-1', function() { 68 | foo++; 69 | this.expect(foo).toEqual(1); 70 | }); 71 | }); 72 | 73 | env.currentRunner().execute(); 74 | 75 | 76 | expect(env.currentRunner().specs().length).toEqual(3); 77 | }); 78 | }); 79 | 80 | describe('afterEach', function() { 81 | it('should run after each spec for all suites', function () { 82 | var foo = 3; 83 | env.afterEach(function () { 84 | foo = foo - 1; 85 | }); 86 | 87 | env.describe('suite 1', function () { 88 | env.it('test 1-1', function() { 89 | this.expect(foo).toEqual(3); 90 | }); 91 | env.it('test 1-2', function() { 92 | this.expect(foo).toEqual(2); 93 | }); 94 | }); 95 | 96 | env.describe('suite 2', function () { 97 | env.it('test 2-1', function() { 98 | this.expect(foo).toEqual(1); 99 | }); 100 | }); 101 | 102 | env.currentRunner().execute(); 103 | 104 | var runnerResults = env.currentRunner().results(); 105 | expect(runnerResults.totalCount).toEqual(3); 106 | expect(runnerResults.passedCount).toEqual(3); 107 | }); 108 | }); 109 | 110 | 111 | it('should run child suites and specs and generate results when execute is called', function() { 112 | env.describe('one suite description', function () { 113 | env.it('should be a test', function() { 114 | this.runs(function () { 115 | this.expect(true).toEqual(true); 116 | }); 117 | }); 118 | }); 119 | 120 | env.describe('another suite description', function () { 121 | env.it('should be another test', function() { 122 | this.runs(function () { 123 | this.expect(true).toEqual(false); 124 | }); 125 | }); 126 | }); 127 | 128 | env.currentRunner().execute(); 129 | 130 | var runnerResults = env.currentRunner().results(); 131 | expect(runnerResults.totalCount).toEqual(2); 132 | expect(runnerResults.passedCount).toEqual(1); 133 | expect(runnerResults.failedCount).toEqual(1); 134 | }); 135 | 136 | 137 | it('should ignore suites that have been x\'d', function() { 138 | env.xdescribe('one suite description', function () { 139 | env.it('should be a test', function() { 140 | this.runs(function () { 141 | this.expect(true).toEqual(true); 142 | }); 143 | }); 144 | }); 145 | 146 | env.describe('another suite description', function () { 147 | env.it('should be another test', function() { 148 | this.runs(function () { 149 | this.expect(true).toEqual(false); 150 | }); 151 | }); 152 | }); 153 | 154 | env.currentRunner().execute(); 155 | 156 | var runnerResults = env.currentRunner().results(); 157 | expect(runnerResults.totalCount).toEqual(1); 158 | expect(runnerResults.passedCount).toEqual(0); 159 | expect(runnerResults.failedCount).toEqual(1); 160 | }); 161 | 162 | it('should roll up results from all specs', function() { 163 | env.describe('one suite description', function () { 164 | env.it('should be a test', function() { 165 | this.runs(function () { 166 | this.expect(true).toEqual(true); 167 | }); 168 | }); 169 | }); 170 | 171 | env.describe('another suite description', function () { 172 | env.it('should be another test', function() { 173 | this.runs(function () { 174 | this.expect(true).toEqual(false); 175 | }); 176 | }); 177 | }); 178 | 179 | env.currentRunner().execute(); 180 | 181 | var results = env.currentRunner().results(); 182 | expect(results.totalCount).toEqual(2); 183 | expect(results.passedCount).toEqual(1); 184 | expect(results.failedCount).toEqual(1); 185 | }); 186 | 187 | describe('reporting', function () { 188 | var fakeReporter; 189 | beforeEach(function () { 190 | fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting", "reportRunnerResults"]); 191 | env.addReporter(fakeReporter); 192 | }); 193 | 194 | it('should report runner results when the runner has completed running', function() { 195 | env.describe('one suite description', function () { 196 | env.it('should be a test', function() { 197 | this.runs(function () { 198 | this.expect(true).toEqual(true); 199 | }); 200 | }); 201 | }); 202 | 203 | env.describe('another suite description', function () { 204 | env.it('should be another test', function() { 205 | this.waits(200); 206 | this.runs(function () { 207 | this.expect(true).toEqual(false); 208 | }); 209 | }); 210 | }); 211 | 212 | env.currentRunner().execute(); 213 | expect(fakeReporter.reportRunnerResults).wasNotCalled(); 214 | fakeTimer.tick(200); 215 | //This blows up the JSApiReporter. 216 | //expect(fakeReporter.reportRunnerResults).wasCalledWith(env.currentRunner); 217 | expect(fakeReporter.reportRunnerResults).wasCalled(); 218 | expect(fakeReporter.reportRunnerResults.mostRecentCall.args[0].results()).toEqual(env.currentRunner().results()); 219 | }); 220 | 221 | 222 | }); 223 | 224 | it("should report when the tests start running", function() { 225 | var fakeReporter = jasmine.createSpyObj("fakeReporter", ["log", "reportRunnerStarting"]); 226 | env.addReporter(fakeReporter); 227 | 228 | 229 | var runner = new jasmine.Runner(env); 230 | runner.arbitraryVariable = 'foo'; 231 | spyOn(runner.queue, 'start'); 232 | expect(fakeReporter.reportRunnerStarting).wasNotCalled(); 233 | runner.execute(); 234 | expect(fakeReporter.reportRunnerStarting).wasCalled(); 235 | var reportedRunner = fakeReporter.reportRunnerStarting.mostRecentCall.args[0]; 236 | expect(reportedRunner.arbitraryVariable).toEqual('foo'); 237 | expect(runner.queue.start).wasCalled(); 238 | 239 | }); 240 | 241 | it("should return a flat array of all suites, including nested suites", function() { 242 | var suite1, suite2; 243 | suite1 = env.describe("spec 1", function() { 244 | suite2 = env.describe("nested spec", function() { 245 | }); 246 | }); 247 | 248 | document.runner = env.currentRunner(); 249 | 250 | var suites = env.currentRunner().suites(); 251 | var suiteDescriptions = []; 252 | for (var i = 0; i < suites.length; i++) { 253 | suiteDescriptions.push(suites[i].getFullName()); 254 | } 255 | expect(suiteDescriptions).toEqual([suite1.getFullName(), suite2.getFullName()]); 256 | }); 257 | 258 | }); -------------------------------------------------------------------------------- /src/Matchers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @constructor 3 | * @param {jasmine.Env} env 4 | * @param actual 5 | * @param {jasmine.Spec} spec 6 | */ 7 | jasmine.Matchers = function(env, actual, spec) { 8 | this.env = env; 9 | this.actual = actual; 10 | this.spec = spec; 11 | }; 12 | 13 | jasmine.Matchers.pp = function(str) { 14 | return jasmine.util.htmlEscape(jasmine.pp(str)); 15 | }; 16 | 17 | jasmine.Matchers.prototype.report = function(result, failing_message, details) { 18 | var expectationResult = new jasmine.ExpectationResult({ 19 | passed: result, 20 | message: failing_message, 21 | details: details 22 | }); 23 | this.spec.addMatcherResult(expectationResult); 24 | return result; 25 | }; 26 | 27 | jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { 28 | return function() { 29 | var matcherArgs = jasmine.util.argsToArray(arguments); 30 | var result = matcherFunction.apply(this, arguments); 31 | var message; 32 | if (!result) { 33 | if (this.message) { 34 | message = this.message.apply(this, arguments); 35 | } else { 36 | var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); 37 | message = "Expected " + jasmine.pp(this.actual) + " " + englishyPredicate; 38 | if (matcherArgs.length > 0) { 39 | for (var i = 0; i < matcherArgs.length; i++) { 40 | if (i > 0) message += ","; 41 | message += " " + jasmine.pp(matcherArgs[i]); 42 | } 43 | } 44 | message += "."; 45 | } 46 | } 47 | var expectationResult = new jasmine.ExpectationResult({ 48 | matcherName: matcherName, 49 | passed: result, 50 | expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], 51 | actual: this.actual, 52 | message: message 53 | }); 54 | this.spec.addMatcherResult(expectationResult); 55 | return result; 56 | }; 57 | }; 58 | 59 | 60 | 61 | 62 | /** 63 | * toBe: compares the actual to the expected using === 64 | * @param expected 65 | */ 66 | 67 | jasmine.Matchers.prototype.toBe = function(expected) { 68 | return this.actual === expected; 69 | }; 70 | 71 | /** 72 | * toNotBe: compares the actual to the expected using !== 73 | * @param expected 74 | */ 75 | jasmine.Matchers.prototype.toNotBe = function(expected) { 76 | return this.actual !== expected; 77 | }; 78 | 79 | /** 80 | * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. 81 | * 82 | * @param expected 83 | */ 84 | 85 | jasmine.Matchers.prototype.toEqual = function(expected) { 86 | return this.env.equals_(this.actual, expected); 87 | }; 88 | 89 | /** 90 | * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual 91 | * @param expected 92 | */ 93 | jasmine.Matchers.prototype.toNotEqual = function(expected) { 94 | return !this.env.equals_(this.actual, expected); 95 | }; 96 | 97 | /** 98 | * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes 99 | * a pattern or a String. 100 | * 101 | * @param reg_exp 102 | */ 103 | jasmine.Matchers.prototype.toMatch = function(expected) { 104 | return new RegExp(expected).test(this.actual); 105 | }; 106 | 107 | /** 108 | * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch 109 | * @param reg_exp 110 | */ 111 | jasmine.Matchers.prototype.toNotMatch = function(expected) { 112 | return !(new RegExp(expected).test(this.actual)); 113 | }; 114 | 115 | /** 116 | * Matcher that compares the actual to undefined. 117 | */ 118 | jasmine.Matchers.prototype.toBeDefined = function() { 119 | return (this.actual !== undefined); 120 | }; 121 | 122 | /** 123 | * Matcher that compares the actual to undefined. 124 | */ 125 | jasmine.Matchers.prototype.toBeUndefined = function() { 126 | return (this.actual === undefined); 127 | }; 128 | 129 | /** 130 | * Matcher that compares the actual to null. 131 | */ 132 | jasmine.Matchers.prototype.toBeNull = function() { 133 | return (this.actual === null); 134 | }; 135 | 136 | /** 137 | * Matcher that boolean not-nots the actual. 138 | */ 139 | jasmine.Matchers.prototype.toBeTruthy = function() { 140 | return !!this.actual; 141 | }; 142 | 143 | 144 | /** 145 | * Matcher that boolean nots the actual. 146 | */ 147 | jasmine.Matchers.prototype.toBeFalsy = function() { 148 | return !this.actual; 149 | }; 150 | 151 | /** 152 | * Matcher that checks to see if the actual, a Jasmine spy, was called. 153 | */ 154 | jasmine.Matchers.prototype.wasCalled = function() { 155 | if (arguments.length > 0) { 156 | throw new Error('wasCalled does not take arguments, use wasCalledWith'); 157 | } 158 | 159 | if (!jasmine.isSpy(this.actual)) { 160 | throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 161 | } 162 | 163 | this.message = function() { 164 | return "Expected spy " + this.actual.identity + " to have been called."; 165 | }; 166 | 167 | return this.actual.wasCalled; 168 | }; 169 | 170 | /** 171 | * Matcher that checks to see if the actual, a Jasmine spy, was not called. 172 | */ 173 | jasmine.Matchers.prototype.wasNotCalled = function() { 174 | if (arguments.length > 0) { 175 | throw new Error('wasNotCalled does not take arguments'); 176 | } 177 | 178 | if (!jasmine.isSpy(this.actual)) { 179 | throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 180 | } 181 | 182 | this.message = function() { 183 | return "Expected spy " + this.actual.identity + " to not have been called."; 184 | }; 185 | 186 | return !this.actual.wasCalled; 187 | }; 188 | 189 | /** 190 | * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. 191 | * 192 | * @example 193 | * 194 | */ 195 | jasmine.Matchers.prototype.wasCalledWith = function() { 196 | if (!jasmine.isSpy(this.actual)) { 197 | throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 198 | } 199 | 200 | this.message = function() { 201 | return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + jasmine.pp(this.actual.argsForCall); 202 | }; 203 | 204 | return this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); 205 | }; 206 | 207 | /** 208 | * Matcher that checks that the expected item is an element in the actual Array. 209 | * 210 | * @param {Object} item 211 | */ 212 | jasmine.Matchers.prototype.toContain = function(expected) { 213 | return this.env.contains_(this.actual, expected); 214 | }; 215 | 216 | /** 217 | * Matcher that checks that the expected item is NOT an element in the actual Array. 218 | * 219 | * @param {Object} item 220 | */ 221 | jasmine.Matchers.prototype.toNotContain = function(expected) { 222 | return !this.env.contains_(this.actual, expected); 223 | }; 224 | 225 | jasmine.Matchers.prototype.toBeLessThan = function(expected) { 226 | return this.actual < expected; 227 | }; 228 | 229 | jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { 230 | return this.actual > expected; 231 | }; 232 | 233 | /** 234 | * Matcher that checks that the expected exception was thrown by the actual. 235 | * 236 | * @param {String} expectedException 237 | */ 238 | jasmine.Matchers.prototype.toThrow = function(expected) { 239 | function getException_(actual, expected) { 240 | var exception; 241 | if (typeof actual != 'function') { 242 | throw new Error('Actual is not a function'); 243 | } 244 | try { 245 | actual(); 246 | } catch (e) { 247 | exception = e; 248 | } 249 | return exception; 250 | } 251 | 252 | var result = false; 253 | var exception = getException_(this.actual, expected); 254 | if (exception) { 255 | result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); 256 | } 257 | 258 | this.message = function(expected) { 259 | var exception = getException_(this.actual, expected); 260 | if (exception && (expected === undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 261 | return ["Expected function to throw", expected.message || expected, ", but it threw", exception.message || exception ].join(' '); 262 | } else { 263 | return "Expected function to throw an exception."; 264 | } 265 | }; 266 | 267 | return result; 268 | }; 269 | 270 | jasmine.Matchers.Any = function(expectedClass) { 271 | this.expectedClass = expectedClass; 272 | }; 273 | 274 | jasmine.Matchers.Any.prototype.matches = function(other) { 275 | if (this.expectedClass == String) { 276 | return typeof other == 'string' || other instanceof String; 277 | } 278 | 279 | if (this.expectedClass == Number) { 280 | return typeof other == 'number' || other instanceof Number; 281 | } 282 | 283 | if (this.expectedClass == Function) { 284 | return typeof other == 'function' || other instanceof Function; 285 | } 286 | 287 | if (this.expectedClass == Object) { 288 | return typeof other == 'object'; 289 | } 290 | 291 | return other instanceof this.expectedClass; 292 | }; 293 | 294 | jasmine.Matchers.Any.prototype.toString = function() { 295 | return ''; 296 | }; 297 | 298 | -------------------------------------------------------------------------------- /contrib/ruby/jasmine_runner.rb: -------------------------------------------------------------------------------- 1 | require 'socket' 2 | require 'erb' 3 | require 'json' 4 | 5 | module Jasmine 6 | def self.root 7 | File.expand_path(File.join(File.dirname(__FILE__), '../..')) 8 | end 9 | 10 | # this seemingly-over-complex method is necessary to get an open port on at least some of our Macs 11 | def self.open_socket_on_unused_port 12 | infos = Socket::getaddrinfo("localhost", nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE) 13 | families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten] 14 | 15 | return TCPServer.open('0.0.0.0', 0) if families.has_key?('AF_INET') 16 | return TCPServer.open('::', 0) if families.has_key?('AF_INET6') 17 | return TCPServer.open(0) 18 | end 19 | 20 | def self.find_unused_port 21 | socket = open_socket_on_unused_port 22 | port = socket.addr[1] 23 | socket.close 24 | port 25 | end 26 | 27 | def self.server_is_listening_on(hostname, port) 28 | require 'socket' 29 | begin 30 | socket = TCPSocket.open(hostname, port) 31 | rescue Errno::ECONNREFUSED 32 | return false 33 | end 34 | socket.close 35 | true 36 | end 37 | 38 | def self.wait_for_listener(port, name = "required process", seconds_to_wait = 10) 39 | time_out_at = Time.now + seconds_to_wait 40 | until server_is_listening_on "localhost", port 41 | sleep 0.1 42 | puts "Waiting for #{name} on #{port}..." 43 | raise "#{name} didn't show up on port #{port} after #{seconds_to_wait} seconds." if Time.now > time_out_at 44 | end 45 | end 46 | 47 | def self.kill_process_group(process_group_id, signal="TERM") 48 | Process.kill signal, -process_group_id # negative pid means kill process group. (see man 2 kill) 49 | end 50 | 51 | def self.cachebust(files, root_dir="", replace=nil, replace_with=nil) 52 | require 'digest/md5' 53 | files.collect do |file_name| 54 | real_file_name = replace && replace_with ? file_name.sub(replace, replace_with) : file_name 55 | begin 56 | digest = Digest::MD5.hexdigest(File.read("#{root_dir}#{real_file_name}")) 57 | rescue 58 | digest = "MISSING-FILE" 59 | end 60 | "#{file_name}?cachebust=#{digest}" 61 | end 62 | end 63 | 64 | class RunAdapter 65 | def initialize(spec_files_or_proc, options = {}) 66 | @spec_files_or_proc = Jasmine.files(spec_files_or_proc) || [] 67 | @jasmine_files = Jasmine.files(options[:jasmine_files]) || [ 68 | "/__JASMINE_ROOT__/lib/" + File.basename(Dir.glob("#{Jasmine.root}/lib/jasmine*.js").first), 69 | "/__JASMINE_ROOT__/lib/TrivialReporter.js", 70 | "/__JASMINE_ROOT__/lib/json2.js", 71 | "/__JASMINE_ROOT__/lib/consolex.js", 72 | ] 73 | @stylesheets = ["/__JASMINE_ROOT__/lib/jasmine.css"] + (Jasmine.files(options[:stylesheets]) || []) 74 | @spec_helpers = Jasmine.files(options[:spec_helpers]) || [] 75 | end 76 | 77 | def call(env) 78 | run 79 | end 80 | 81 | def run 82 | stylesheets = @stylesheets 83 | spec_helpers = @spec_helpers 84 | spec_files = @spec_files_or_proc 85 | 86 | jasmine_files = @jasmine_files 87 | jasmine_files = jasmine_files.call if jasmine_files.respond_to?(:call) 88 | 89 | css_files = @stylesheets 90 | 91 | 92 | body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html"))).result(binding) 93 | [ 94 | 200, 95 | { 'Content-Type' => 'text/html' }, 96 | body 97 | ] 98 | end 99 | 100 | 101 | end 102 | 103 | class Redirect 104 | def initialize(url) 105 | @url = url 106 | end 107 | 108 | def call(env) 109 | [ 110 | 302, 111 | { 'Location' => @url }, 112 | [] 113 | ] 114 | end 115 | end 116 | 117 | class JsAlert 118 | def call(env) 119 | [ 120 | 200, 121 | { 'Content-Type' => 'application/javascript' }, 122 | "document.write('

Couldn\\'t load #{env["PATH_INFO"]}!

');" 123 | ] 124 | end 125 | end 126 | 127 | class FocusedSuite 128 | def initialize(spec_files_or_proc, options) 129 | @spec_files_or_proc = Jasmine.files(spec_files_or_proc) || [] 130 | @options = options 131 | end 132 | 133 | def call(env) 134 | spec_files = @spec_files_or_proc 135 | matching_specs = spec_files.select {|spec_file| spec_file =~ /#{Regexp.escape(env["PATH_INFO"])}/ }.compact 136 | if !matching_specs.empty? 137 | run_adapter = Jasmine::RunAdapter.new(matching_specs, @options) 138 | run_adapter.run 139 | else 140 | [ 141 | 200, 142 | { 'Content-Type' => 'application/javascript' }, 143 | "document.write('

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

');" 144 | ] 145 | end 146 | end 147 | 148 | end 149 | 150 | class SimpleServer 151 | def self.start(port, spec_files_or_proc, mappings, options = {}) 152 | require 'thin' 153 | config = { 154 | '/__suite__' => Jasmine::FocusedSuite.new(spec_files_or_proc, options), 155 | '/run.html' => Jasmine::Redirect.new('/'), 156 | '/' => Jasmine::RunAdapter.new(spec_files_or_proc, options) 157 | } 158 | mappings.each do |from, to| 159 | config[from] = Rack::File.new(to) 160 | end 161 | 162 | config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root) 163 | 164 | app = Rack::Cascade.new([ 165 | Rack::URLMap.new(config), 166 | JsAlert.new 167 | ]) 168 | 169 | begin 170 | Thin::Server.start('0.0.0.0', port, app) 171 | rescue RuntimeError => e 172 | raise e unless e.message == 'no acceptor' 173 | raise RuntimeError.new("A server is already running on port #{port}") 174 | end 175 | end 176 | end 177 | 178 | class SimpleClient 179 | def initialize(selenium_host, selenium_port, selenium_browser_start_command, http_address) 180 | require 'selenium/client' 181 | @driver = Selenium::Client::Driver.new( 182 | selenium_host, 183 | selenium_port, 184 | selenium_browser_start_command, 185 | http_address 186 | ) 187 | @http_address = http_address 188 | end 189 | 190 | def tests_have_finished? 191 | @driver.get_eval("window.jasmine.getEnv().currentRunner.finished") == "true" 192 | end 193 | 194 | def connect 195 | @driver.start 196 | @driver.open("/") 197 | end 198 | 199 | def disconnect 200 | @driver.stop 201 | end 202 | 203 | def run 204 | until tests_have_finished? do 205 | sleep 0.1 206 | end 207 | 208 | puts @driver.get_eval("window.results()") 209 | failed_count = @driver.get_eval("window.jasmine.getEnv().currentRunner.results().failedCount").to_i 210 | failed_count == 0 211 | end 212 | 213 | def eval_js(script) 214 | escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'" 215 | 216 | result = @driver.get_eval(" try { eval(#{escaped_script}, window); } catch(err) { window.eval(#{escaped_script}); }") 217 | JSON.parse("[#{result}]")[0] 218 | end 219 | end 220 | 221 | class Runner 222 | def initialize(selenium_jar_path, spec_files, dir_mappings, options={}) 223 | @selenium_jar_path = selenium_jar_path 224 | @spec_files = spec_files 225 | @dir_mappings = dir_mappings 226 | @options = options 227 | 228 | @browser = options[:browser] ? options[:browser].delete(:browser) : 'firefox' 229 | @selenium_pid = nil 230 | @jasmine_server_pid = nil 231 | end 232 | 233 | def start 234 | start_servers 235 | @client = Jasmine::SimpleClient.new("localhost", @selenium_server_port, "*#{@browser}", "http://localhost:#{@jasmine_server_port}/") 236 | @client.connect 237 | end 238 | 239 | def stop 240 | @client.disconnect 241 | stop_servers 242 | end 243 | 244 | def start_servers 245 | @jasmine_server_port = Jasmine::find_unused_port 246 | @selenium_server_port = Jasmine::find_unused_port 247 | 248 | @selenium_pid = fork do 249 | Process.setpgrp 250 | exec "java -jar #{@selenium_jar_path} -port #{@selenium_server_port} > /dev/null 2>&1" 251 | end 252 | puts "selenium started. pid is #{@selenium_pid}" 253 | 254 | @jasmine_server_pid = fork do 255 | Process.setpgrp 256 | Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @options) 257 | exit! 0 258 | end 259 | puts "jasmine server started. pid is #{@jasmine_server_pid}" 260 | 261 | Jasmine::wait_for_listener(@selenium_server_port, "selenium server") 262 | Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server") 263 | end 264 | 265 | def stop_servers 266 | puts "shutting down the servers..." 267 | Jasmine::kill_process_group(@selenium_pid) if @selenium_pid 268 | Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid 269 | end 270 | 271 | def run 272 | begin 273 | start 274 | puts "servers are listening on their ports -- running the test script..." 275 | tests_passed = @client.run 276 | ensure 277 | stop 278 | end 279 | return tests_passed 280 | end 281 | 282 | def eval_js(script) 283 | @client.eval_js(script) 284 | end 285 | end 286 | 287 | def self.files(f) 288 | result = f 289 | result = result.call if result.respond_to?(:call) 290 | result 291 | end 292 | 293 | end 294 | -------------------------------------------------------------------------------- /doc/files.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | JsDoc Reference - File Index 8 | 9 | 10 | 174 | 175 | 176 | 177 | 179 | 180 |
181 | 183 |
184 |

Classes

185 | 218 |
219 |
220 | 221 |
222 |

File Index

223 | 224 | 225 |
226 |

lib/TrivialReporter.js

227 | 228 |
229 | 230 | 231 | 232 | 233 |
234 |
235 |
236 | 237 |
238 |

src/base.js

239 | 240 |
241 | 242 | 243 | 244 | 245 |
246 |
247 |
248 | 249 |
250 |

src/Block.js

251 | 252 |
253 | 254 | 255 | 256 | 257 |
258 |
259 |
260 | 261 |
262 |

src/Env.js

263 | 264 |
265 | 266 | 267 | 268 | 269 |
270 |
271 |
272 | 273 |
274 |

src/JsApiReporter.js

275 | 276 |
277 | 278 | 279 | 280 | 281 |
282 |
283 |
284 | 285 |
286 |

src/Matchers.js

287 | 288 |
289 | 290 | 291 | 292 | 293 |
294 |
295 |
296 | 297 |
298 |

src/mock-timeout.js

299 | 300 |
301 | 302 | 303 | 304 | 305 |
306 |
307 |
308 | 309 |
310 |

src/MultiReporter.js

311 | 312 |
313 | 314 | 315 | 316 | 317 |
318 |
319 |
320 | 321 |
322 |

src/NestedResults.js

323 | 324 |
325 | 326 | 327 | 328 | 329 |
330 |
331 |
332 | 333 |
334 |

src/PrettyPrinter.js

335 | 336 |
337 | 338 | 339 | 340 | 341 |
342 |
343 |
344 | 345 |
346 |

src/Queue.js

347 | 348 |
349 | 350 | 351 | 352 | 353 |
354 |
355 |
356 | 357 |
358 |

src/Reporter.js

359 | 360 |
361 | 362 | 363 | 364 | 365 |
366 |
367 |
368 | 369 |
370 |

src/Reporters.js

371 | 372 |
373 | 374 | 375 | 376 | 377 |
378 |
379 |
380 | 381 |
382 |

src/Runner.js

383 | 384 |
385 | 386 | 387 | 388 | 389 |
390 |
391 |
392 | 393 |
394 |

src/Spec.js

395 | 396 |
397 | 398 | 399 | 400 | 401 |
402 |
403 |
404 | 405 |
406 |

src/Suite.js

407 | 408 |
409 | 410 | 411 | 412 | 413 |
414 |
415 |
416 | 417 |
418 |

src/util.js

419 | 420 |
421 | 422 | 423 | 424 | 425 |
426 |
427 |
428 | 429 |
430 |

src/WaitsBlock.js

431 | 432 |
433 | 434 | 435 | 436 | 437 |
438 |
439 |
440 | 441 |
442 |

src/WaitsForBlock.js

443 | 444 |
445 | 446 | 447 | 448 | 449 |
450 |
451 |
452 | 453 | 454 |
455 |
456 | 457 | Documentation generated by JsDoc Toolkit 2.1.0 on Tue Nov 10 2009 17:31:30 GMT-0500 (EST) 458 |
459 | 460 | -------------------------------------------------------------------------------- /doc/symbols/jasmine.MultiReporter.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | JsDoc Reference - jasmine.MultiReporter 9 | 10 | 174 | 175 | 176 | 177 | 178 | 179 | 181 | 182 | 183 | 184 |
185 | 186 | 188 |
189 |

Classes

190 | 223 |
224 | 225 |
226 | 227 |
228 | 229 |

230 | 231 | Class jasmine.MultiReporter 232 |

233 | 234 | 235 |

236 | 237 | 238 | 239 | 240 | 241 |
Defined in: MultiReporter.js. 242 | 243 |

244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 264 | 265 | 266 |
Class Summary
Constructor AttributesConstructor Name and Description
  259 |
260 | jasmine.MultiReporter() 261 |
262 |
263 |
267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 293 | 294 | 295 | 296 |
Method Summary
Method AttributesMethod Name and Description
  289 |
addReporter(reporter) 290 |
291 |
292 |
297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 |
307 |
308 | Class Detail 309 |
310 | 311 |
312 | jasmine.MultiReporter() 313 |
314 | 315 |
316 | 317 | 318 |
319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 |
332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 |
340 | Method Detail 341 |
342 | 343 | 344 |
345 | 346 | 347 | addReporter(reporter) 348 | 349 |
350 |
351 | 352 | 353 | 354 |
355 | 356 | 357 | 358 | 359 |
360 |
Parameters:
361 | 362 |
363 | reporter 364 | 365 |
366 |
367 | 368 |
369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 |
385 |
386 | 387 | 388 | 389 |
390 | 391 | Documentation generated by JsDoc Toolkit 2.1.0 on Tue Nov 10 2009 17:31:30 GMT-0500 (EST) 392 |
393 | 394 | 395 | -------------------------------------------------------------------------------- /doc/symbols/jasmine.Block.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | JsDoc Reference - jasmine.Block 9 | 10 | 174 | 175 | 176 | 177 | 178 | 179 | 181 | 182 | 183 | 184 |
185 | 186 | 188 |
189 |

Classes

190 | 223 |
224 | 225 |
226 | 227 |
228 | 229 |

230 | 231 | Class jasmine.Block 232 |

233 | 234 | 235 |

236 | 237 | 238 | 239 | 240 | 241 |
Defined in: Block.js. 242 | 243 |

244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 264 | 265 | 266 |
Class Summary
Constructor AttributesConstructor Name and Description
  259 |
260 | jasmine.Block(env, func, spec) 261 |
262 |
Blocks are functions with executable code that make up a spec.
263 |
267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 293 | 294 | 295 | 296 |
Method Summary
Method AttributesMethod Name and Description
  289 |
execute(onComplete) 290 |
291 |
292 |
297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 |
307 |
308 | Class Detail 309 |
310 | 311 |
312 | jasmine.Block(env, func, spec) 313 |
314 | 315 |
316 | Blocks are functions with executable code that make up a spec. 317 | 318 |
319 | 320 | 321 | 322 | 323 | 324 |
325 |
Parameters:
326 | 327 |
328 | {jasmine.Env} env 329 | 330 |
331 |
332 | 333 |
334 | {Function} func 335 | 336 |
337 |
338 | 339 |
340 | {jasmine.Spec} spec 341 | 342 |
343 |
344 | 345 |
346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 |
355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 |
363 | Method Detail 364 |
365 | 366 | 367 |
368 | 369 | 370 | execute(onComplete) 371 | 372 |
373 |
374 | 375 | 376 | 377 |
378 | 379 | 380 | 381 | 382 |
383 |
Parameters:
384 | 385 |
386 | onComplete 387 | 388 |
389 |
390 | 391 |
392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 |
408 |
409 | 410 | 411 | 412 |
413 | 414 | Documentation generated by JsDoc Toolkit 2.1.0 on Tue Nov 10 2009 17:31:29 GMT-0500 (EST) 415 |
416 | 417 | 418 | -------------------------------------------------------------------------------- /doc/symbols/src/src_WaitsForBlock.js.html: -------------------------------------------------------------------------------- 1 |
  1 jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
 9 |   2   this.timeout = timeout;
10 |   3   this.latchFunction = latchFunction;
11 |   4   this.message = message;
12 |   5   this.totalTimeSpentWaitingForLatch = 0;
13 |   6   jasmine.Block.call(this, env, null, spec);
14 |   7 };
15 |   8 
16 |   9 jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
17 |  10 
18 |  11 jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100;
19 |  12 
20 |  13 jasmine.WaitsForBlock.prototype.execute = function (onComplete) {
21 |  14   var self = this;
22 |  15   self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen'));
23 |  16   var latchFunctionResult;
24 |  17   try {
25 |  18     latchFunctionResult = self.latchFunction.apply(self.spec);
26 |  19   } catch (e) {
27 |  20     self.spec.fail(e);
28 |  21     onComplete();
29 |  22     return;
30 |  23   }
31 |  24 
32 |  25   if (latchFunctionResult) {
33 |  26     onComplete();
34 |  27   } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) {
35 |  28     var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen');
36 |  29     self.spec.fail({
37 |  30       name: 'timeout',
38 |  31       message: message
39 |  32     });
40 |  33     self.spec._next();
41 |  34   } else {
42 |  35     self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
43 |  36     self.env.setTimeout(function () { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
44 |  37   }
45 |  38 };
--------------------------------------------------------------------------------