evergreen 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/README.rdoc +4 -0
  2. data/bin/evergreen +18 -0
  3. data/lib/evergreen.rb +44 -0
  4. data/lib/evergreen/cli.rb +23 -0
  5. data/lib/evergreen/evergreen.js +3 -0
  6. data/lib/evergreen/runner.rb +56 -0
  7. data/lib/evergreen/server.rb +31 -0
  8. data/lib/evergreen/spec.rb +60 -0
  9. data/lib/evergreen/version.rb +3 -0
  10. data/lib/evergreen/views/list.erb +6 -0
  11. data/lib/evergreen/views/spec.erb +37 -0
  12. data/lib/jasmine/MIT.LICENSE +20 -0
  13. data/lib/jasmine/README.markdown +489 -0
  14. data/lib/jasmine/Rakefile +146 -0
  15. data/lib/jasmine/cruise_config.rb +21 -0
  16. data/lib/jasmine/doc/files.html +460 -0
  17. data/lib/jasmine/doc/index.html +322 -0
  18. data/lib/jasmine/doc/symbols/_global_.html +918 -0
  19. data/lib/jasmine/doc/symbols/jasmine.Block.html +417 -0
  20. data/lib/jasmine/doc/symbols/jasmine.Clock.html +678 -0
  21. data/lib/jasmine/doc/symbols/jasmine.Env.html +1169 -0
  22. data/lib/jasmine/doc/symbols/jasmine.JsApiReporter.html +822 -0
  23. data/lib/jasmine/doc/symbols/jasmine.Matchers.html +1474 -0
  24. data/lib/jasmine/doc/symbols/jasmine.MultiReporter.html +394 -0
  25. data/lib/jasmine/doc/symbols/jasmine.NestedResults.html +710 -0
  26. data/lib/jasmine/doc/symbols/jasmine.Reporter.html +574 -0
  27. data/lib/jasmine/doc/symbols/jasmine.Runner.html +710 -0
  28. data/lib/jasmine/doc/symbols/jasmine.Spec.html +1253 -0
  29. data/lib/jasmine/doc/symbols/jasmine.Spy.html +855 -0
  30. data/lib/jasmine/doc/symbols/jasmine.Suite.html +705 -0
  31. data/lib/jasmine/doc/symbols/jasmine.html +1345 -0
  32. data/lib/jasmine/doc/symbols/jasmine.util.html +535 -0
  33. data/lib/jasmine/doc/symbols/src/lib_TrivialReporter.js.html +124 -0
  34. data/lib/jasmine/doc/symbols/src/src_Block.js.html +29 -0
  35. data/lib/jasmine/doc/symbols/src/src_Env.js.html +248 -0
  36. data/lib/jasmine/doc/symbols/src/src_JsApiReporter.js.html +111 -0
  37. data/lib/jasmine/doc/symbols/src/src_Matchers.js.html +344 -0
  38. data/lib/jasmine/doc/symbols/src/src_MultiReporter.js.html +36 -0
  39. data/lib/jasmine/doc/symbols/src/src_NestedResults.js.html +88 -0
  40. data/lib/jasmine/doc/symbols/src/src_PrettyPrinter.js.html +130 -0
  41. data/lib/jasmine/doc/symbols/src/src_Queue.js.html +102 -0
  42. data/lib/jasmine/doc/symbols/src/src_Reporter.js.html +35 -0
  43. data/lib/jasmine/doc/symbols/src/src_Reporters.js.html +51 -0
  44. data/lib/jasmine/doc/symbols/src/src_Runner.js.html +75 -0
  45. data/lib/jasmine/doc/symbols/src/src_Spec.js.html +214 -0
  46. data/lib/jasmine/doc/symbols/src/src_Suite.js.html +77 -0
  47. data/lib/jasmine/doc/symbols/src/src_WaitsBlock.js.html +21 -0
  48. data/lib/jasmine/doc/symbols/src/src_WaitsForBlock.js.html +45 -0
  49. data/lib/jasmine/doc/symbols/src/src_base.js.html +585 -0
  50. data/lib/jasmine/doc/symbols/src/src_mock-timeout.js.html +185 -0
  51. data/lib/jasmine/doc/symbols/src/src_util.js.html +75 -0
  52. data/lib/jasmine/example/example_runner.html +22 -0
  53. data/lib/jasmine/example/spec/example_suite.js +11 -0
  54. data/lib/jasmine/images/fail-16.png +0 -0
  55. data/lib/jasmine/images/fail.png +0 -0
  56. data/lib/jasmine/images/go-16.png +0 -0
  57. data/lib/jasmine/images/go.png +0 -0
  58. data/lib/jasmine/images/pending-16.png +0 -0
  59. data/lib/jasmine/images/pending.png +0 -0
  60. data/lib/jasmine/images/question-bk.png +0 -0
  61. data/lib/jasmine/images/questionbk-16.png +0 -0
  62. data/lib/jasmine/images/spinner.gif +0 -0
  63. data/lib/jasmine/lib/TrivialReporter.js +171 -0
  64. data/lib/jasmine/lib/consolex.js +28 -0
  65. data/lib/jasmine/lib/jasmine-0.10.4.js +2371 -0
  66. data/lib/jasmine/lib/jasmine.css +166 -0
  67. data/lib/jasmine/lib/json2.js +478 -0
  68. data/lib/jasmine/spec/jasmine_helper.rb +44 -0
  69. data/lib/jasmine/spec/jasmine_spec.rb +31 -0
  70. data/lib/jasmine/spec/runner.html +80 -0
  71. data/lib/jasmine/spec/saucelabs.yml +24 -0
  72. data/lib/jasmine/spec/suites/CustomMatchersSpec.js +112 -0
  73. data/lib/jasmine/spec/suites/EnvSpec.js +158 -0
  74. data/lib/jasmine/spec/suites/ExceptionsSpec.js +107 -0
  75. data/lib/jasmine/spec/suites/JsApiReporterSpec.js +96 -0
  76. data/lib/jasmine/spec/suites/MatchersSpec.js +709 -0
  77. data/lib/jasmine/spec/suites/MockClockSpec.js +34 -0
  78. data/lib/jasmine/spec/suites/MultiReporterSpec.js +30 -0
  79. data/lib/jasmine/spec/suites/NestedResultsSpec.js +54 -0
  80. data/lib/jasmine/spec/suites/PrettyPrintSpec.js +93 -0
  81. data/lib/jasmine/spec/suites/QueueSpec.js +23 -0
  82. data/lib/jasmine/spec/suites/ReporterSpec.js +60 -0
  83. data/lib/jasmine/spec/suites/RunnerSpec.js +267 -0
  84. data/lib/jasmine/spec/suites/SpecRunningSpec.js +1195 -0
  85. data/lib/jasmine/spec/suites/SpecSpec.js +110 -0
  86. data/lib/jasmine/spec/suites/SpySpec.js +201 -0
  87. data/lib/jasmine/spec/suites/SuiteSpec.js +120 -0
  88. data/lib/jasmine/spec/suites/TrivialReporterSpec.js +158 -0
  89. data/lib/jasmine/spec/suites/UtilSpec.js +40 -0
  90. data/lib/jasmine/spec/suites/WaitsForBlockSpec.js +88 -0
  91. data/lib/jasmine/src/Block.js +22 -0
  92. data/lib/jasmine/src/Env.js +263 -0
  93. data/lib/jasmine/src/JsApiReporter.js +104 -0
  94. data/lib/jasmine/src/Matchers.js +336 -0
  95. data/lib/jasmine/src/MultiReporter.js +28 -0
  96. data/lib/jasmine/src/NestedResults.js +80 -0
  97. data/lib/jasmine/src/PrettyPrinter.js +122 -0
  98. data/lib/jasmine/src/Queue.js +94 -0
  99. data/lib/jasmine/src/Reporter.js +27 -0
  100. data/lib/jasmine/src/Reporters.js +43 -0
  101. data/lib/jasmine/src/Runner.js +77 -0
  102. data/lib/jasmine/src/Spec.js +206 -0
  103. data/lib/jasmine/src/Suite.js +82 -0
  104. data/lib/jasmine/src/WaitsBlock.js +13 -0
  105. data/lib/jasmine/src/WaitsForBlock.js +37 -0
  106. data/lib/jasmine/src/base.js +586 -0
  107. data/lib/jasmine/src/mock-timeout.js +177 -0
  108. data/lib/jasmine/src/util.js +67 -0
  109. data/lib/jasmine/src/version.json +5 -0
  110. metadata +238 -0
@@ -0,0 +1,4 @@
1
+ Evergreen
2
+ =========
3
+
4
+ Evergreen glues together some pieces to simplify JavaScript unit testing in Rails3 applications.
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'evergreen'
6
+
7
+ begin
8
+ # The dup is to keep ARGV intact, so that tools like ruby-debug can respawn.
9
+ failure = Evergreen::Cli.execute(ARGV.dup)
10
+ Kernel.exit(failure ? 1 : 0)
11
+ rescue SystemExit => e
12
+ Kernel.exit(e.status)
13
+ rescue Exception => e
14
+ STDERR.puts("#{e.message} (#{e.class})")
15
+ STDERR.puts(e.backtrace.join("\n"))
16
+ Kernel.exit(1)
17
+ end
18
+
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'capybara'
4
+ require 'capybara/envjs'
5
+ require 'capybara/wait_until'
6
+ require 'launchy'
7
+ require 'evergreen/version'
8
+
9
+ module Evergreen
10
+ autoload :Cli, 'evergreen/cli'
11
+ autoload :Server, 'evergreen/server'
12
+ autoload :Runner, 'evergreen/runner'
13
+ autoload :Spec, 'evergreen/spec'
14
+
15
+ class << self
16
+ def application(root)
17
+ Class.new(Sinatra::Base).tap do |app|
18
+ app.reset!
19
+ app.class_eval do
20
+ set :static, true
21
+ set :root, File.expand_path('evergreen', File.dirname(__FILE__))
22
+ set :public, File.expand_path(File.join(root, 'public'), File.dirname(__FILE__))
23
+
24
+ use Rack::Static, :urls => ["/lib"], :root => File.expand_path('jasmine', File.dirname(__FILE__))
25
+ use Rack::Static, :urls => ["/evergreen"], :root => File.dirname(__FILE__)
26
+
27
+ get '/' do
28
+ @specs = Spec.all(root)
29
+ erb :list
30
+ end
31
+
32
+ get '/run/:name' do |name|
33
+ @spec = Spec.new(root, name)
34
+ erb :spec
35
+ end
36
+
37
+ get '/spec/:name.js' do |name|
38
+ Spec.new(root, name).read
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module Evergreen
2
+ class Cli
3
+ def self.execute(argv)
4
+ new.execute(argv)
5
+ end
6
+
7
+ def execute(argv)
8
+ command = argv.shift
9
+ root = File.expand_path(argv.shift || '.', Dir.pwd)
10
+
11
+ case command
12
+ when "serve"
13
+ Evergreen::Server.run(root)
14
+ return true
15
+ when "run"
16
+ return Evergreen::Runner.run(root)
17
+ else
18
+ puts "no such command '#{command}'"
19
+ return false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ var require = function(file) {
2
+ document.write('<script type="text/javascript" src="' + file + '"></script>');
3
+ };
@@ -0,0 +1,56 @@
1
+ module Evergreen
2
+ class Runner
3
+ attr_reader :spec
4
+
5
+ def self.run(root)
6
+ runners = Spec.all(root).map { |spec| new(spec) }
7
+ runners.each do |runner|
8
+ if runner.passed?
9
+ print '.'
10
+ else
11
+ print 'F'
12
+ end
13
+ end
14
+ puts ""
15
+
16
+ runners.each do |runner|
17
+ puts runner.failure_message unless runner.passed?
18
+ end
19
+ end
20
+
21
+ def initialize(spec)
22
+ @spec = spec
23
+ end
24
+
25
+ def passed?
26
+ failed_examples.empty?
27
+ end
28
+
29
+ def failed_examples
30
+ results.select { |row| !row.passed }
31
+ end
32
+
33
+ def failure_message
34
+ failed_examples.map do |row|
35
+ <<-ERROR
36
+ Failed: #{row.name}
37
+ #{row.message}
38
+ in #{row.trace.fileName}:#{row.trace.lineNumber}
39
+ ERROR
40
+ end.join("\n\n")
41
+ end
42
+
43
+ def results
44
+ @results ||= begin
45
+ session = Capybara::Session.new(:envjs, Evergreen.application(spec.root))
46
+ session.visit(spec.url)
47
+ session.evaluate_script('jasmine.results')
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+
55
+
56
+
@@ -0,0 +1,31 @@
1
+ module Evergreen
2
+ class Server
3
+ def self.run(root)
4
+ serve = new(root)
5
+ serve.boot
6
+ serve.launch_browser
7
+ end
8
+
9
+ def initialize(root)
10
+ @root = root
11
+ end
12
+
13
+ def server
14
+ @server ||= Capybara::Server.new(Evergreen.application(@root))
15
+ end
16
+
17
+ def boot
18
+ server.boot
19
+ end
20
+
21
+ def root_url
22
+ server.url('/')
23
+ end
24
+
25
+ def launch_browser
26
+ Launchy.open(root_url)
27
+ sleep
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,60 @@
1
+ module Evergreen
2
+ class Spec
3
+
4
+ def self.all(root)
5
+ Dir.glob(File.join(root, 'spec/javascripts', '*_spec.js')).map do |path|
6
+ new(root, File.basename(path).sub(/_spec\.js$/, ''))
7
+ end
8
+ end
9
+
10
+ attr_reader :name, :root
11
+
12
+ def initialize(root, name)
13
+ @root = root
14
+ @name = name
15
+ end
16
+
17
+ def path
18
+ File.join(root, 'spec/javascripts', name + '_spec.js')
19
+ end
20
+
21
+ def read
22
+ File.read(path)
23
+ end
24
+
25
+ def url
26
+ "/run/#{name}"
27
+ end
28
+
29
+ def passed?
30
+ run unless has_run?
31
+ results.all? { |row| row.passed }
32
+ end
33
+
34
+ def failure_message
35
+ run unless has_run?
36
+ results.each do |row|
37
+ puts "Failed: #{row.name}"
38
+ puts " #{row.message}"
39
+ puts " in #{row.trace.fileName}:#{row.trace.lineNumber}"
40
+ puts ""
41
+ puts ""
42
+ end
43
+ end
44
+
45
+ protected
46
+
47
+ def run
48
+ session.visit(url)
49
+ @results = session.evaluate_script('jasmine.results')
50
+ end
51
+
52
+ def has_run?
53
+ @results
54
+ end
55
+
56
+ def session
57
+ @session ||= Capybara::Session.new(:envjs, Evergreen.applications(root))
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module Evergreen
2
+ VERSION = '0.1'
3
+ end
@@ -0,0 +1,6 @@
1
+ <h1>JS Specs</h1>
2
+
3
+ <% @specs.each do |spec| %>
4
+ <p><a href="<%= spec.url %>"><%= spec.name %></a></p>
5
+ <% end %>
6
+
@@ -0,0 +1,37 @@
1
+ <!doctype html>
2
+
3
+ <html>
4
+ <head>
5
+ <link rel="stylesheet" type="text/css" href="/lib/jasmine.css">
6
+ <script src="/lib/jasmine-0.10.4.js" type="text/javascript"></script>
7
+ <script type="text/javascript" src="/lib/TrivialReporter.js"></script>
8
+ <script type="text/javascript" src="/lib/consolex.js"></script>
9
+ <script type="text/javascript" src="/evergreen/evergreen.js"></script>
10
+ <script src="/spec/<%= @spec.name %>.js" type="text/javascript"></script>
11
+ </head>
12
+ <body>
13
+ <script type="text/javascript">
14
+ (function() {
15
+ var jasmineEnv = jasmine.getEnv();
16
+ jasmineEnv.addReporter(new jasmine.TrivialReporter());
17
+ jasmineEnv.addReporter({
18
+ reportRunnerStarting: function(runner) {
19
+ jasmine.results = []
20
+ },
21
+ reportSpecResults: function(spec) {
22
+ var results = spec.results();
23
+ var item = results.getItems()[0] || {};
24
+ jasmine.results.push({
25
+ name: spec.getFullName(),
26
+ passed: results.failedCount === 0,
27
+ message: item.message,
28
+ trace: item.trace
29
+ });
30
+ }
31
+ });
32
+
33
+ jasmineEnv.execute();
34
+ })();
35
+ </script>
36
+ </body>
37
+ </html>
@@ -0,0 +1,20 @@
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.
@@ -0,0 +1,489 @@
1
+ Jasmine
2
+ =======
3
+ **A JavaScript Testing Framework**
4
+
5
+ Quick Start
6
+ ----------
7
+
8
+ 1. Get the latest release from the [downloads page](http://github.com/pivotal/jasmine/downloads).
9
+ 2. Open `example/example_runner.html` in your favorite browser.
10
+
11
+ For running within a Ruby environment, including automated execution with Selenium, please use
12
+ the [jasmine-ruby gem](http://github.com/pivotal/jasmine-ruby).
13
+
14
+ Releases
15
+ ----------
16
+ 0.10.0 [[download]](http://cloud.github.com/downloads/pivotal/jasmine/jasmine-0.10.0.zip)
17
+
18
+ 0.9.0 [[download]](http://github.com/pivotal/jasmine/zipball/0.9.0)
19
+
20
+ 0.8.0 [[download]](http://github.com/pivotal/jasmine/zipball/0.8.0)
21
+
22
+ ### Which Release Should I Use?
23
+
24
+ Please use the latest version unless you have a good reason not to. Some of this documentation may not be applicable to older versions.
25
+
26
+ Pull Requests
27
+ ----------
28
+ We welcome your contributions! Jasmine is currently maintained by Davis Frank ([infews](http://github.com/infews)), Rajan Agaskar ([ragaskar](http://github.com/ragaskar)), and Christian Williams ([Xian](http://github.com/Xian)). You can help us by removing all other recipients from your pull request.
29
+
30
+
31
+ Why Another JavaScript TDD/BDD Framework?
32
+ -----------
33
+
34
+ There are some great JavaScript testing frameworks out there already, so why did we write another?
35
+
36
+ None of the existing frameworks quite worked the way we wanted. Many only work from within a browser. Most don't support testing asynchronous code like event callbacks. Some have syntax that's hard for JS developers or IDEs to understand.
37
+
38
+ So we decided to start from scratch.
39
+
40
+ Enter Jasmine
41
+ ------------
42
+
43
+ Jasmine is our dream JavaScript testing framework. It's heavily influenced by, and borrows the best parts of, ScrewUnit, JSSpec, [JSpec](http://github.com/visionmedia/jspec/tree/master), and of course RSpec.
44
+
45
+ Jasmine was designed with a few principles in mind. We believe that a good JavaScript testing framework:
46
+
47
+ * should not be tied to any browser, framework, platform, or host language.
48
+ * should have idiomatic and unsurprising syntax.
49
+ * should work anywhere JavaScript can run, including browsers, servers, phones, etc.
50
+ * shouldn't intrude in your application's territory (e.g. by cluttering the global namespace).
51
+ * should play well with IDEs (e.g. test code should pass static analysis).
52
+
53
+ Some of our goals while writing Jasmine:
54
+
55
+ * it should encourage good testing practices.
56
+ * it should integrate easily with continuous build systems.
57
+ * it should be simple to get started with.
58
+
59
+ The result is Jasmine, and we love test-driving our code with it. Enjoy.
60
+
61
+ How To
62
+ ------
63
+
64
+ There is a simple example of how to use Jasmine in the /example directory. But here's more information.
65
+
66
+ ### Specs
67
+
68
+ Each spec is, naturally, a JavaScript function. You tell Jasmine about this spec with a call to `it()` with a string and the function. The string is a description that will be helpful to you when reading a report.
69
+
70
+ it('should be a test', function () {
71
+ var foo = 0;
72
+ foo++;
73
+ });
74
+
75
+ ### Expectations
76
+
77
+ Within your spec you will want to express expectations about the behavior of your application code. These are made with the `expect()` function and expectation matchers, like this:
78
+
79
+ it('should be a test', function () {
80
+ var foo = 0; // set up the world
81
+ foo++; // call your application code
82
+
83
+ expect(foo).toEqual(1); // passes because foo == 1
84
+ });
85
+
86
+ Results of the expectations are logged for later for reporting.
87
+
88
+ #### Expectation Matchers
89
+
90
+ Jasmine has several built-in matchers. Here are a few:
91
+
92
+ >`expect(x).toEqual(y);` compares objects or primitives `x` and `y` and passes if they are equivalent
93
+ >
94
+ >`expect(x).toMatch(pattern);` compares `x` to string or regular expression `pattern` and passes if they match
95
+ >
96
+ >`expect(x).toBeDefined();` passes if `x` is not `undefined`
97
+ >
98
+ >`expect(x).toBeNull();` passes if `x` is `null`
99
+ >
100
+ >`expect(x).toBeTruthy();` passes if `x` evaluates to true
101
+ >
102
+ >`expect(x).toBeFalsy();` passes if `x` evaluates to false
103
+ >
104
+ >`expect(x).toContain(y);` passes if array or string `x` contains `y`
105
+
106
+ Every matcher's criteria can be inverted by prepending `.not`:
107
+
108
+ >`expect(x).not.toEqual(y);` compares objects or primitives `x` and `y` and passes if they are *not* equivalent
109
+
110
+ #### Writing New Matchers
111
+
112
+ We've provided a small set of matchers that cover many common situations. However, we recommend that you write custom matchers when you want to assert a more specific sort of expectation. Custom matchers help to document the intent of your specs, and can help to remove code duplication in your specs.
113
+
114
+ It's extremely easy to create new matchers for your app. A matcher function receives the actual value as `this.actual`, and zero or more arguments may be passed in the function call. The function should return `true` if the actual value passes the matcher's requirements, and `false` if it does not.
115
+
116
+ Here's the definition of `toBeLessThan()`:
117
+
118
+ toBeLessThan: function(expected) {
119
+ return this.actual < expected;
120
+ };
121
+
122
+ To add the matcher to your suite, call `this.addMatchers()` from within a `before` or `it` block. Call it with an object mapping matcher name to function:
123
+
124
+ beforeEach(function() {
125
+ this.addMatchers({
126
+ toBeVisible: function() { return this.actual.isVisible(); }
127
+ });
128
+ });
129
+
130
+ ### Suites
131
+
132
+ Specs are grouped in Suites. Suites are defined using the global `describe()` function:
133
+
134
+ describe('One suite', function () {
135
+ it('has a test', function () {
136
+ ...
137
+ });
138
+
139
+ it('has another test', function () {
140
+ ...
141
+ });
142
+ });
143
+
144
+ The Suite name is so that reporting is more descriptive.
145
+
146
+ Suites are executed in the order in which `describe()` calls are made, usually in the order in which their script files are included. Additionally, specs within a suite share a functional scope. So you may declare variables inside a describe block and they are accessible from within your specs. For example:
147
+
148
+ describe('A suite with some variables', function () {
149
+ var bar = 0
150
+
151
+ it('has a test', function () {
152
+ bar++;
153
+ expect(bar).toEqual(1);
154
+ });
155
+
156
+ it('has another test', function () {
157
+ bar++;
158
+ expect(bar).toEqual(2);
159
+ });
160
+ });
161
+
162
+ #### beforeEach
163
+
164
+ A suite can have a beforeEach declaration. It takes a function that is run before each spec. For example:
165
+
166
+ describe('some suite', function () {
167
+
168
+ var suiteWideFoo;
169
+
170
+ beforeEach(function () {
171
+ suiteWideFoo = 1;
172
+ });
173
+
174
+ it('should equal bar', function () {
175
+ expect(suiteWideFoo).toEqual(1);
176
+ });
177
+ });
178
+
179
+ A runner can also have beforeEach declarations. Runner beforeEach functions are executed before every spec in all suites, and execute BEFORE suite beforeEach functions. For example:
180
+
181
+ var runnerWideFoo = [];
182
+
183
+ beforeEach(function () {
184
+ runnerWideFoo.push('runner');
185
+ });
186
+
187
+ describe('some suite', function () {
188
+
189
+ beforeEach(function () {
190
+ runnerWideFoo.push('suite');
191
+ });
192
+
193
+ it('should equal bar', function () {
194
+ expect(runnerWideFoo).toEqual(['runner', 'suite']);
195
+ });
196
+ });
197
+
198
+ #### afterEach
199
+
200
+ Similarly, there is an afterEach declaration. It takes a function that is run after each spec. For example:
201
+
202
+ describe('some suite', function () {
203
+
204
+ var suiteWideFoo;
205
+ afterEach(function () {
206
+ suiteWideFoo = 0;
207
+ });
208
+
209
+ it('should equal 1', function () {
210
+ expect(suiteWideFoo).toEqual(1);
211
+ });
212
+
213
+ it('should equal 0 after', function () {
214
+ expect(suiteWideFoo).toEqual(0);
215
+ };
216
+ });
217
+
218
+ A runner can also have an afterEach declarations. Runner afterEach functions are executed after every spec in all suites, and execute AFTER suite afterEach functions. For example:
219
+
220
+ var runnerWideFoo = [];
221
+
222
+ afterEach(function () {
223
+ runnerWideFoo.push('runner');
224
+ });
225
+
226
+ describe('some suite', function () {
227
+
228
+ afterEach(function () {
229
+ runnerWideFoo.push('suite');
230
+ });
231
+
232
+ it('should be empty', function () {
233
+ expect(runnerWideFoo).toEqual([]);
234
+ });
235
+
236
+ it('should be populated after', function () {
237
+ expect(runnerWideFoo).toEqual(['suite', 'runner']);
238
+ };
239
+ });
240
+
241
+ ### Single-spec After functions
242
+
243
+ A spec may ask Jasmine to execute some code after the spec has finished running; the code will run whether the spec finishes successfully or not. Multiple after functions may be given.
244
+
245
+ describe('some suite', function () {
246
+ it(function () {
247
+ var originalTitle = window.title;
248
+ this.after(function() { window.title = originalTitle; });
249
+ MyWindow.setTitle("new value");
250
+ expect(window.title).toEqual("new value");
251
+ });
252
+
253
+
254
+ ### Nested Describes
255
+ Jasmine supports nested describes. An example:
256
+
257
+ describe('some suite', function () {
258
+
259
+ var suiteWideFoo;
260
+
261
+ beforeEach(function () {
262
+ suiteWideFoo = 0;
263
+ });
264
+
265
+ describe('some nested suite', function() {
266
+ var nestedSuiteBar;
267
+ beforeEach(function() {
268
+ nestedSuiteBar=1;
269
+ });
270
+
271
+ it('nested expectation', function () {
272
+ expect(suiteWideFoo).toEqual(0);
273
+ expect(nestedSuiteBar).toEqual(1);
274
+ });
275
+
276
+ });
277
+
278
+ it('top-level describe', function () {
279
+ expect(suiteWideFoo).toEqual(0);
280
+ expect(nestedSuiteBar).toEqual(undefined);
281
+ });
282
+ });
283
+
284
+ ### Spies
285
+
286
+ Jasmine integrates 'spies' that permit many spying, mocking, and faking behaviors.
287
+
288
+ Here are a few examples:
289
+
290
+ var Klass = function () {
291
+ };
292
+
293
+ var Klass.prototype.method = function (arg) {
294
+ return arg;
295
+ };
296
+
297
+ var Klass.prototype.methodWithCallback = function (callback) {
298
+ return callback('foo');
299
+ };
300
+
301
+ ...
302
+
303
+ it('should spy on Klass#method') {
304
+ spyOn(Klass, 'method');
305
+ Klass.method('foo argument');
306
+
307
+ expect(Klass.method).wasCalledWith('foo argument');
308
+ });
309
+
310
+ it('should spy on Klass#methodWithCallback') {
311
+ var callback = Jasmine.createSpy();
312
+ Klass.methodWithCallback(callback);
313
+
314
+ expect(callback).wasCalledWith('foo');
315
+ });
316
+
317
+
318
+ Spies can be very useful for testing AJAX or other asynchronous behaviors that take callbacks by faking the method firing an async call.
319
+
320
+ var Klass = function () {
321
+ };
322
+
323
+ var Klass.prototype.asyncMethod = function (callback) {
324
+ someAsyncCall(callback);
325
+ };
326
+
327
+ ...
328
+
329
+ it('should test async call') {
330
+ spyOn(Klass, 'asyncMethod');
331
+ var callback = Jasmine.createSpy();
332
+
333
+ Klass.asyncMethod(callback);
334
+ expect(callback).wasNotCalled();
335
+
336
+ var someResponseData = 'foo';
337
+ Klass.asyncMethod.mostRecentCall.args[0](someResponseData);
338
+ expect(callback).wasCalledWith(someResponseData);
339
+
340
+ });
341
+
342
+ There are spy-specfic matchers that are very handy.
343
+
344
+ `expect(x).wasCalled()` passes if `x` is a spy and was called
345
+
346
+ `expect(x).wasCalledWith(arguments)` passes if `x` is a spy and was called with the specified arguments
347
+
348
+ `expect(x).wasNotCalled()` passes if `x` is a spy and was not called
349
+
350
+ `expect(x).wasNotCalledWith(arguments)` passes if `x` is a spy and was not called with the specified arguments
351
+
352
+ Spies can be trained to respond in a variety of ways when invoked:
353
+
354
+ `spyOn(x, 'method').andCallThrough()`: spies on AND calls the original function spied on
355
+
356
+ `spyOn(x, 'method').andReturn(arguments)`: returns passed arguments when spy is called
357
+
358
+ `spyOn(x, 'method').andThrow(exception)`: throws passed exception when spy is called
359
+
360
+ `spyOn(x, 'method').andCallFake(function)`: calls passed function when spy is called
361
+
362
+ Spies have some useful properties:
363
+
364
+ `callCount`: returns number of times spy was called
365
+
366
+ `mostRecentCall.args`: returns argument array from last call to spy.
367
+
368
+ `argsForCall[i]` returns arguments array for call `i` to spy.
369
+
370
+ Spies are automatically removed after each spec. They may be set in the beforeEach function.
371
+
372
+ ### Disabling Tests & Suites
373
+
374
+ Specs may be disabled by calling `xit()` instead of `it()`. Suites may be disabled by calling `xdescribe()` instead of `describe()`. A simple find/replace in your editor of choice will allow you to run a subset of your specs.
375
+
376
+ ### Asynchronous Specs
377
+
378
+ You may be thinking, "That's all very nice, but what's this about asynchronous tests?"
379
+
380
+ Well, say you need to make a call that is asynchronous - an AJAX API, event callback, or some other JavaScript library. That is, the call returns immediately, yet you want to make expectations 'at some point in the future' after some magic happens in the background.
381
+
382
+ Jasmine allows you to do this with `runs()` and `waits()` blocks.
383
+
384
+ `runs()` blocks by themselves simply run as if they were called directly. The following snippets of code should provide similar results:
385
+
386
+ it('should be a test', function () {
387
+ var foo = 0
388
+ foo++;
389
+
390
+ expect(foo).toEqual(1);
391
+ });
392
+
393
+ and
394
+
395
+ it('should be a test', function () {
396
+ runs( function () {
397
+ var foo = 0
398
+ foo++;
399
+
400
+ expect(foo).toEqual(1);
401
+ });
402
+ });
403
+
404
+ multiple `runs()` blocks in a spec will run serially. For example,
405
+
406
+ it('should be a test', function () {
407
+ runs( function () {
408
+ var foo = 0
409
+ foo++;
410
+
411
+ expect(foo).toEqual(1);
412
+ });
413
+ runs( function () {
414
+ var bar = 0
415
+ bar++;
416
+
417
+ expect(bar).toEqual(1);
418
+ });
419
+ });
420
+
421
+ `runs()` blocks share functional scope -- `this` properties will be common to all blocks, but declared `var`'s will not!
422
+
423
+ it('should be a test', function () {
424
+ runs( function () {
425
+ this.foo = 0
426
+ this.foo++;
427
+ var bar = 0;
428
+ bar++;
429
+
430
+ expect(this.foo).toEqual(1);
431
+ expect(bar).toEqual(1);
432
+ });
433
+ runs( function () {
434
+ this.foo++;
435
+ var bar = 0
436
+ bar++;
437
+
438
+ expect(foo).toEqual(2);
439
+ expect(bar).toEqual(1);
440
+ });
441
+ });
442
+
443
+ `runs()` blocks exist so you can test asynchronous processes. The function `waits()` works with `runs()` to provide a naive
444
+ timeout before the next block is run. You supply a time to wait before the next `runs()` function is executed. For example:
445
+
446
+ it('should be a test', function () {
447
+ runs(function () {
448
+ this.foo = 0;
449
+ var that = this;
450
+ setTimeout(function () {
451
+ that.foo++;
452
+ }, 250);
453
+ });
454
+
455
+ runs(function () {
456
+ this.expects(this.foo).toEqual(0);
457
+ });
458
+
459
+ waits(500);
460
+
461
+ runs(function () {
462
+ this.expects(this.foo).toEqual(1);
463
+ });
464
+ });
465
+
466
+ What's happening here?
467
+
468
+ * The first call to `runs()` sets call for 1/4 of a second in the future that increments `this.foo`.
469
+ * The second `runs()` is executed immediately and then verifies that `this.foo` was indeed initialized to zero in the previous `runs()`.
470
+ * Then we wait for half a second.
471
+ * Then the last call to `runs()` expects that `this.foo` was incremented by the `setTimeout`.
472
+
473
+ ## Support
474
+ We now have a Google Group for support & discussion.
475
+
476
+ * Homepage: [http://groups.google.com/group/jasmine-js](http://groups.google.com/group/jasmine-js)
477
+ * Group email: [jasmine-js@googlegroups.com](jasmine-js@googlegroups.com)
478
+ * Current build status of Jasmine is visible at [ci.pivotallabs.com](http://ci.pivotallabs.com)
479
+
480
+ ## Maintainers
481
+
482
+ * [Davis W. Frank](mailto:dwfrank@pivotallabs.com), Pivotal Labs
483
+ * [Rajan Agaskar](mailto:rajan@pivotallabs.com), Pivotal Labs
484
+ * [Christian Williams](mailto:xian@pivotallabs.com), Pivotal Labs
485
+
486
+ ## Acknowledgments
487
+ * A big shout out to the various JavaScript test framework authors, especially TJ for [JSpec](http://github.com/visionmedia/jspec/tree/master) - we played with it a bit before deciding that we really needed to roll our own.
488
+ * Thanks to Pivot [Jessica Miller](http://www.jessicamillerworks.com/) for our fancy pass/fail/pending icons
489
+ * Huge contributions have been made by [Erik Hanson](mailto:erik@pivotallabs.com), [Adam Abrons](mailto:adam@pivotallabs.com) and [Carl Jackson](mailto:carl@pivotallabs.com), and many other Pivots.