kookaburra 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/Gemfile +7 -7
- data/Gemfile.lock +13 -12
- data/README.markdown +125 -45
- data/VERSION +1 -1
- data/kookaburra.gemspec +18 -17
- data/lib/kookaburra/api_driver.rb +19 -15
- data/lib/kookaburra.rb +88 -89
- data/test/kookaburra_test.rb +6 -15
- metadata +22 -28
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/Gemfile
CHANGED
@@ -7,11 +7,11 @@ gem 'rack-test'
|
|
7
7
|
# Add dependencies to develop your gem here.
|
8
8
|
# Include everything needed to run rake, tests, features, etc.
|
9
9
|
group :development do
|
10
|
-
gem 'minitest'
|
11
|
-
gem '
|
12
|
-
gem '
|
13
|
-
gem 'bundler'
|
14
|
-
gem 'jeweler'
|
15
|
-
gem 'rcov'
|
16
|
-
gem 'reek'
|
10
|
+
gem 'minitest'
|
11
|
+
gem 'yard'
|
12
|
+
gem 'redcarpet', '~> 1.0' # used to format documentation
|
13
|
+
gem 'bundler'
|
14
|
+
gem 'jeweler'
|
15
|
+
gem 'rcov'
|
16
|
+
gem 'reek'
|
17
17
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
activesupport (3.
|
4
|
+
activesupport (3.2.0)
|
5
|
+
i18n (~> 0.6)
|
5
6
|
multi_json (~> 1.0)
|
6
|
-
bluecloth (2.2.0)
|
7
7
|
git (1.2.5)
|
8
8
|
i18n (0.6.0)
|
9
9
|
jeweler (1.6.4)
|
10
10
|
bundler (~> 1.0)
|
11
11
|
git (>= 1.2.5)
|
12
12
|
rake
|
13
|
-
minitest (2.
|
13
|
+
minitest (2.10.1)
|
14
14
|
multi_json (1.0.4)
|
15
|
-
rack (1.
|
15
|
+
rack (1.4.0)
|
16
16
|
rack-test (0.6.1)
|
17
17
|
rack (>= 1.0)
|
18
18
|
rake (0.9.2.2)
|
19
|
-
rcov (0.
|
19
|
+
rcov (1.0.0)
|
20
|
+
redcarpet (1.17.2)
|
20
21
|
reek (1.2.8)
|
21
22
|
ruby2ruby (~> 1.2)
|
22
23
|
ruby_parser (~> 2.0)
|
@@ -26,20 +27,20 @@ GEM
|
|
26
27
|
sexp_processor (~> 3.0)
|
27
28
|
ruby_parser (2.3.1)
|
28
29
|
sexp_processor (~> 3.0)
|
29
|
-
sexp_processor (3.0.
|
30
|
-
yard (0.
|
30
|
+
sexp_processor (3.0.10)
|
31
|
+
yard (0.7.4)
|
31
32
|
|
32
33
|
PLATFORMS
|
33
34
|
ruby
|
34
35
|
|
35
36
|
DEPENDENCIES
|
36
37
|
activesupport (>= 3.0)
|
37
|
-
|
38
|
-
bundler (~> 1.0.0)
|
38
|
+
bundler
|
39
39
|
i18n
|
40
|
-
jeweler
|
40
|
+
jeweler
|
41
41
|
minitest
|
42
42
|
rack-test
|
43
43
|
rcov
|
44
|
-
|
45
|
-
|
44
|
+
redcarpet (~> 1.0)
|
45
|
+
reek
|
46
|
+
yard
|
data/README.markdown
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
# Kookaburra #
|
2
2
|
|
3
|
-
Kookaburra is a framework for implementing the [Window Driver] [
|
3
|
+
Kookaburra is a framework for implementing the [Window Driver] [Window Driver] pattern in
|
4
4
|
order to keep acceptance tests maintainable.
|
5
5
|
|
6
|
+
## Installation ##
|
7
|
+
|
8
|
+
Kookaburra is available as a Rubygem and [published on Rubygems.org] [Kookaburra
|
9
|
+
Gem], so installation is trivial:
|
10
|
+
|
11
|
+
gem install kookaburra
|
12
|
+
|
13
|
+
If you're using [Bundler](http://gembundler.com/) for your project, just add the
|
14
|
+
following:
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem 'kookaburra'
|
18
|
+
end
|
19
|
+
|
6
20
|
## Setup ##
|
7
21
|
|
8
22
|
Kookaburra itself abstracts some common patterns for implementing the Window
|
9
|
-
Driver pattern for tests of Ruby web applications built on [Rack] [
|
23
|
+
Driver pattern for tests of Ruby web applications built on [Rack] [Rack]. You will need
|
10
24
|
to tell Kookaburra which classes contain the specific Domain Driver
|
11
25
|
implementations for your application as well as which driver to use for running
|
12
|
-
the tests (currently only tested with [Capybara] [
|
26
|
+
the tests (currently only tested with [Capybara] [Capybara]). The details of setting up your
|
13
27
|
Domain Driver layer are discussed below, but in general you will need the
|
14
28
|
following in a locations such as `lib/my_application/kookaburra.rb` (replace
|
15
29
|
`MyApplication` with a module name suitable to your actual application:
|
@@ -33,7 +47,7 @@ following in a locations such as `lib/my_application/kookaburra.rb` (replace
|
|
33
47
|
|
34
48
|
### RSpec ###
|
35
49
|
|
36
|
-
For [RSpec] [
|
50
|
+
For [RSpec] [RSpec] integration tests, just add the following to
|
37
51
|
`spec/support/kookaburra_setup.rb`:
|
38
52
|
|
39
53
|
require 'my_application/kookaburra'
|
@@ -44,7 +58,7 @@ For [RSpec] [4] integration tests, just add the following to
|
|
44
58
|
|
45
59
|
### Cucumber ###
|
46
60
|
|
47
|
-
For Cucumber, add the following to `features/support/kookaburra_setup.rb`:
|
61
|
+
For [Cucumber] [Cucumber], add the following to `features/support/kookaburra_setup.rb`:
|
48
62
|
|
49
63
|
require 'my_application/kookaburra'
|
50
64
|
|
@@ -64,12 +78,15 @@ Cucumber step definitions.
|
|
64
78
|
Kookaburra attempts to extract some common patterns that make it easier to use
|
65
79
|
the Window Driver pattern along with various Ruby testing frameworks, but you
|
66
80
|
still need to define your own testing DSL. An acceptance testing stack using
|
67
|
-
Kookaburra has the following
|
81
|
+
Kookaburra has the following layers:
|
68
82
|
|
69
|
-
1. The **Business Specification Language** (Cucumber scenarios
|
70
|
-
|
71
|
-
|
72
|
-
|
83
|
+
1. The **Business Specification Language** (Cucumber scenarios or other
|
84
|
+
spcification documents)
|
85
|
+
2. The **Test Implementation** (Cucumber step definitions, RSpec example blocks,
|
86
|
+
etc.)
|
87
|
+
3. The **Domain Driver** (Kookaburra::GivenDriver and Kookaburra::UIDriver)
|
88
|
+
4. The **Window Driver** (Kookaburra::UIDriver::UIComponent)
|
89
|
+
5. The **Application Driver** (Capybara and Rack::Test)
|
73
90
|
|
74
91
|
### The Business Specification Language ###
|
75
92
|
|
@@ -104,18 +121,28 @@ for some reason your e-commerce system was going to be a terminal application
|
|
104
121
|
rather than a web application, you would not need to change this scenario at
|
105
122
|
all, because the actual business concepts described would not change.
|
106
123
|
|
107
|
-
### The
|
108
|
-
|
109
|
-
The
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
124
|
+
### The Test Implementation ###
|
125
|
+
|
126
|
+
The Test Implementation layer exists as the line in between the Business
|
127
|
+
Specification Language and the Domain Driver, and it includes Cucumber step
|
128
|
+
definitions, RSpec example blocks, Test::Unit tests, etc. At this layer, your
|
129
|
+
code orchestrates calls into the Domain Driver to mimic user interactions under
|
130
|
+
various conditions and make assertions about the results.
|
131
|
+
|
132
|
+
**Assertions always belong within the test implementation layer.** Some testing
|
133
|
+
frameworks such as RSpec add methods like `#should` to `Object`, which has the
|
134
|
+
effect of poisoning the entire Ruby namespace with these methods---if you are
|
135
|
+
using RSpec, you can call `#should` anywhere in your code and it will work when
|
136
|
+
RSpec is loaded. Do not be tempted to call a testing library's Object decorators
|
137
|
+
anywhere outside of your test implementation (such as within `UIDriver` or
|
138
|
+
`UIComponent` subclasses.) Doing so will tightly couple your Domain Driver
|
139
|
+
and/or Window Driver implementation to a specific testing library. If you must
|
140
|
+
make some type of assertion within the Domain Driver layer, a better approach is
|
141
|
+
to simply raise an exception with an informative error message when some desired
|
142
|
+
condition is not met.
|
143
|
+
|
144
|
+
Given the Cucumber scenario above, here is how the test implementation layer
|
145
|
+
might look:
|
119
146
|
|
120
147
|
# step_definitions/various_steps.rb
|
121
148
|
|
@@ -158,6 +185,7 @@ Driver layer to interact with your application:
|
|
158
185
|
The step definitions contain neither explicitly shared state (instance
|
159
186
|
variables) nor any logic branches; they are simply wrappers around calls into
|
160
187
|
the Domain Driver layer. There are a couple of advantages to this approach.
|
188
|
+
|
161
189
|
First, because step definitions are so simple, it isn't necessary to force *Very
|
162
190
|
Specific Wording* on the business analyst/product owner who is writing the
|
163
191
|
specs. For instance, if she writes "I see a summary of my order" in another
|
@@ -183,8 +211,9 @@ The second advantage is that by pushing all of the complexity down into the
|
|
183
211
|
Domain Driver, it's now trivial to reuse the exact same code in
|
184
212
|
developer-centric integration tests. This ensures you have parity between the
|
185
213
|
way the automated acceptance tests run and any additional testing that the
|
186
|
-
development team needs to add in.
|
187
|
-
|
214
|
+
development team needs to add in.
|
215
|
+
|
216
|
+
Using RSpec, the test implementation would be as follows:
|
188
217
|
|
189
218
|
# spec/integration/purchase_items_in_cart_spec.rb
|
190
219
|
|
@@ -204,10 +233,17 @@ RSpec as follows:
|
|
204
233
|
end
|
205
234
|
end
|
206
235
|
|
207
|
-
|
208
|
-
usually interact only with the GivenDriver and the UIDriver.
|
236
|
+
### The Domain Driver ###
|
209
237
|
|
210
|
-
|
238
|
+
The Domain Driver layer is where you build up an internal DSL that describes the
|
239
|
+
business concepts of your application at a fairly high level. It consists of
|
240
|
+
three top-level drivers: the `APIDriver` (available via `#api`) for interacting
|
241
|
+
with your application's external API, the `GivenDriver` (available via `#given`)
|
242
|
+
which really just wraps the `APIDriver` and is used to set up state for your
|
243
|
+
tests, and the UIDriver (available via `#ui`) for describing the tasks that a
|
244
|
+
user can accomplish with the application.
|
245
|
+
|
246
|
+
#### Test Data ####
|
211
247
|
|
212
248
|
`Kookaburra::TestData` is the component via which the `GivenDriver` and the
|
213
249
|
`UIDriver` share information. For instance, if you create a user account via the
|
@@ -258,7 +294,7 @@ access default data:
|
|
258
294
|
end
|
259
295
|
end
|
260
296
|
|
261
|
-
####
|
297
|
+
#### API Driver ####
|
262
298
|
|
263
299
|
The `Kookaburra::APIDriver` is used to interact with an application's external
|
264
300
|
web services API. You tell Kookaburra about your API by creating a subclass of
|
@@ -273,7 +309,7 @@ web services API. You tell Kookaburra about your API by creating a subclass of
|
|
273
309
|
end
|
274
310
|
end
|
275
311
|
|
276
|
-
####
|
312
|
+
#### Given Driver ####
|
277
313
|
|
278
314
|
The `Kookaburra::GivenDriver` is used to create a particular "preexisting"
|
279
315
|
state within your application's data and ensure you have a handle to that data
|
@@ -301,7 +337,24 @@ the Domain Driver DSL for your application:
|
|
301
337
|
end
|
302
338
|
end
|
303
339
|
|
304
|
-
|
340
|
+
Although there is nothing that actually *prevents* you from either interacting
|
341
|
+
with the UI or directly manipulating your application via calls into the model
|
342
|
+
from the `GivenDriver`, both things should be avoided. In the first case, the
|
343
|
+
`GivenDriver`'s purpose is to describe state that exists *before* the user
|
344
|
+
interaction that is being tested. Although this state may be the result of a
|
345
|
+
previous user interaction, your tests will generally be much, much faster if you
|
346
|
+
are able to create this state via API calls rather than driving a web browser.
|
347
|
+
|
348
|
+
In the second case, by avoiding manipulating your applications's state at the
|
349
|
+
code level and instead doing so via an external API, it is much less likely that
|
350
|
+
you will be creating a state that your application can't actually get into in a
|
351
|
+
production environment. Additionally, this opens up the possibility of running
|
352
|
+
your tests against a "remote" server where you would not have access to the
|
353
|
+
application internals. ("Remote" in the sense that it is not in the same Ruby
|
354
|
+
process as your running tests, although it may or may not be on the same
|
355
|
+
machine.)
|
356
|
+
|
357
|
+
#### UI Driver ####
|
305
358
|
|
306
359
|
`Kookaburra::UIDriver` provides the necessary tools for driving your
|
307
360
|
application's user interface using the Window Driver pattern. You will subclass
|
@@ -325,13 +378,14 @@ within your subclass:
|
|
325
378
|
### The Window Driver Layer ###
|
326
379
|
|
327
380
|
While your `GivenDriver` and `UIDriver` provide a DSL that represents actions
|
328
|
-
your users can perform in your application, the [Window Driver] [
|
329
|
-
the individual user interface components that the user interacts
|
330
|
-
these tasks. By describing each interface component using an OOP
|
331
|
-
much easier to maintain your acceptance/integration tests,
|
332
|
-
implementation details of each component are captured in a single
|
333
|
-
that implementation changes, you can---for example---fix every
|
334
|
-
needs to log a user into the system just by updating the
|
381
|
+
your users can perform in your application, the [Window Driver] [Window Driver]
|
382
|
+
layer describes the individual user interface components that the user interacts
|
383
|
+
with to perform these tasks. By describing each interface component using an OOP
|
384
|
+
approach, it is much easier to maintain your acceptance/integration tests,
|
385
|
+
because the implementation details of each component are captured in a single
|
386
|
+
place. If/when that implementation changes, you can---for example---fix every
|
387
|
+
single test that needs to log a user into the system just by updating the
|
388
|
+
SignInScreen class.
|
335
389
|
|
336
390
|
You describe the various user interface components by sub-classing
|
337
391
|
`Kookaburra::UIDriver::UIComponent`:
|
@@ -370,22 +424,48 @@ You describe the various user interface components by sub-classing
|
|
370
424
|
end
|
371
425
|
end
|
372
426
|
|
427
|
+
### The Application Driver Layer ###
|
428
|
+
|
429
|
+
`Kookaburra::APIDriver`, `Kookaburra::UIDriver` and
|
430
|
+
`Kookaburra::UIDriver::UIComponent` rely on the Application Driver layer to
|
431
|
+
interact with your application. In the case of the `APIDriver`, Kookaburra uses
|
432
|
+
`Rack::Test` to send HTTP requests to your application. The `UIDriver` and
|
433
|
+
`UIComponent` rely on whatever is configured as `Kookaburra.adapter`. Presently,
|
434
|
+
we have only used Capybara as the application driver for Kookaburra:
|
435
|
+
|
436
|
+
Kookaburra.adapter = Capybara
|
437
|
+
|
438
|
+
It's possible that something other than Capybara could be passed in, as long as
|
439
|
+
that something presented the same API. In reality, using something other than
|
440
|
+
Capybara is likely to require some changes to Kookaburra itself. If you have a
|
441
|
+
particular interest in making this work, please feel free to fork the project
|
442
|
+
and send us a [GitHub pull request] [Pull Request] with your changes.
|
443
|
+
|
373
444
|
## Contributing to kookaburra ##
|
374
445
|
|
375
|
-
* Check out the latest master to make sure the feature hasn't been implemented
|
376
|
-
|
446
|
+
* Check out the latest master to make sure the feature hasn't been implemented
|
447
|
+
or the bug hasn't been fixed yet
|
448
|
+
* Check out the issue tracker to make sure someone already hasn't requested it
|
449
|
+
and/or contributed it
|
377
450
|
* Fork the project
|
378
451
|
* Start a feature/bugfix branch
|
379
452
|
* Commit and push until you are happy with your contribution
|
380
|
-
* Make sure to add tests for it. This is important so I don't break it in a
|
381
|
-
|
453
|
+
* Make sure to add tests for it. This is important so I don't break it in a
|
454
|
+
future version unintentionally.
|
455
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to
|
456
|
+
have your own version, or is otherwise necessary, that is fine, but please
|
457
|
+
isolate to its own commit so I can cherry-pick around it.
|
458
|
+
* Send us a [pull request] [Pull Request]
|
382
459
|
|
383
460
|
## Copyright ##
|
384
461
|
|
385
462
|
Copyright © 2011 Renewable Funding, LLC. See LICENSE.txt for
|
386
463
|
further details.
|
387
464
|
|
388
|
-
[
|
389
|
-
[
|
390
|
-
[
|
391
|
-
[
|
465
|
+
[Window Driver]: http://martinfowler.com/eaaDev/WindowDriver.html "Window Driver - Martin Fowler"
|
466
|
+
[Kookaburra Gem]: https://rubygems.org/gems/kookaburra "kookaburra | RubyGems.org | your community gem host"
|
467
|
+
[Rack]: http://rack.rubyforge.org/ "Rack: a Ruby Webserver Interface"
|
468
|
+
[Capybara]: https://github.com/jnicklas/capybara "jnicklas/capybara - GitHub"
|
469
|
+
[RSpec]: http://rspec.info "RSpec.info: home"
|
470
|
+
[Cucumber]: http://cukes.info/ "Cucumber - Making BDD fun"
|
471
|
+
[Pull Request]: https://github.com/projectdx/kookaburra/pull/new/master "Send a pull request - GitHub"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/kookaburra.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "kookaburra"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Renewable Funding, LLC"]
|
12
|
-
s.date = "2012-01-
|
12
|
+
s.date = "2012-01-24"
|
13
13
|
s.description = "Cucumber + Capybara = Kookaburra? It made sense at the time."
|
14
14
|
s.email = "devteam@renewfund.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
21
|
".rvmrc",
|
22
|
+
".yardopts",
|
22
23
|
"Gemfile",
|
23
24
|
"Gemfile.lock",
|
24
25
|
"LICENSE.txt",
|
@@ -55,35 +56,35 @@ Gem::Specification.new do |s|
|
|
55
56
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.0"])
|
56
57
|
s.add_runtime_dependency(%q<rack-test>, [">= 0"])
|
57
58
|
s.add_development_dependency(%q<minitest>, [">= 0"])
|
58
|
-
s.add_development_dependency(%q<
|
59
|
-
s.add_development_dependency(%q<
|
60
|
-
s.add_development_dependency(%q<bundler>, ["
|
61
|
-
s.add_development_dependency(%q<jeweler>, ["
|
59
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<redcarpet>, ["~> 1.0"])
|
61
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
62
63
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
63
|
-
s.add_development_dependency(%q<reek>, ["
|
64
|
+
s.add_development_dependency(%q<reek>, [">= 0"])
|
64
65
|
else
|
65
66
|
s.add_dependency(%q<i18n>, [">= 0"])
|
66
67
|
s.add_dependency(%q<activesupport>, [">= 3.0"])
|
67
68
|
s.add_dependency(%q<rack-test>, [">= 0"])
|
68
69
|
s.add_dependency(%q<minitest>, [">= 0"])
|
69
|
-
s.add_dependency(%q<
|
70
|
-
s.add_dependency(%q<
|
71
|
-
s.add_dependency(%q<bundler>, ["
|
72
|
-
s.add_dependency(%q<jeweler>, ["
|
70
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
71
|
+
s.add_dependency(%q<redcarpet>, ["~> 1.0"])
|
72
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
73
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
73
74
|
s.add_dependency(%q<rcov>, [">= 0"])
|
74
|
-
s.add_dependency(%q<reek>, ["
|
75
|
+
s.add_dependency(%q<reek>, [">= 0"])
|
75
76
|
end
|
76
77
|
else
|
77
78
|
s.add_dependency(%q<i18n>, [">= 0"])
|
78
79
|
s.add_dependency(%q<activesupport>, [">= 3.0"])
|
79
80
|
s.add_dependency(%q<rack-test>, [">= 0"])
|
80
81
|
s.add_dependency(%q<minitest>, [">= 0"])
|
81
|
-
s.add_dependency(%q<
|
82
|
-
s.add_dependency(%q<
|
83
|
-
s.add_dependency(%q<bundler>, ["
|
84
|
-
s.add_dependency(%q<jeweler>, ["
|
82
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
83
|
+
s.add_dependency(%q<redcarpet>, ["~> 1.0"])
|
84
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
85
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
85
86
|
s.add_dependency(%q<rcov>, [">= 0"])
|
86
|
-
s.add_dependency(%q<reek>, ["
|
87
|
+
s.add_dependency(%q<reek>, [">= 0"])
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
@@ -1,21 +1,16 @@
|
|
1
1
|
require 'rack/test'
|
2
2
|
|
3
3
|
module Kookaburra
|
4
|
-
# Pattern:
|
5
|
-
# - Get some data from test_data.factory
|
6
|
-
# - Post it to the API
|
7
|
-
# - Remember the response in test_data
|
8
4
|
class APIDriver
|
9
|
-
include Rack::Test::Methods
|
10
|
-
attr_reader :app, :test_data
|
11
|
-
protected :app, :test_data
|
12
|
-
|
13
5
|
def initialize(opts)
|
14
|
-
@app
|
15
|
-
@test_data = opts.fetch(:test_data)
|
6
|
+
@app = opts.fetch(:app)
|
16
7
|
end
|
17
8
|
|
18
|
-
|
9
|
+
protected
|
10
|
+
|
11
|
+
include Rack::Test::Methods
|
12
|
+
|
13
|
+
attr_reader :app
|
19
14
|
|
20
15
|
def raise_unless_status(expected_status, short_description)
|
21
16
|
message = "%s failed (#{last_response.status})\n#{last_response.body}" % short_description
|
@@ -25,21 +20,30 @@ module Kookaburra
|
|
25
20
|
##### JSON Tools #####
|
26
21
|
|
27
22
|
def post_as_json(short_description, path, data = {}, options = {})
|
28
|
-
|
29
|
-
header 'Accept', 'application/json'
|
23
|
+
set_json_request_headers
|
30
24
|
post path, data.to_json
|
31
25
|
raise_unless_status options[:expected_status] || 201, short_description
|
32
26
|
end
|
33
27
|
|
34
28
|
def put_as_json(short_description, path, data = {}, options = {})
|
35
|
-
|
36
|
-
header 'Accept', 'application/json'
|
29
|
+
set_json_request_headers
|
37
30
|
put path, data.to_json
|
38
31
|
raise_unless_status options[:expected_status] || 201, short_description
|
39
32
|
end
|
40
33
|
|
34
|
+
def get_as_json(short_description, path, data = {}, options = {})
|
35
|
+
set_json_request_headers
|
36
|
+
get path, data
|
37
|
+
raise_unless_status options[:expected_status] || 200, short_description
|
38
|
+
end
|
39
|
+
|
41
40
|
def hash_from_response_json
|
42
41
|
HashWithIndifferentAccess.new( JSON.parse(last_response.body) )
|
43
42
|
end
|
43
|
+
|
44
|
+
def set_json_request_headers
|
45
|
+
header 'Content-Type', 'application/json'
|
46
|
+
header 'Accept', 'application/json'
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
data/lib/kookaburra.rb
CHANGED
@@ -3,136 +3,134 @@ require 'kookaburra/api_driver'
|
|
3
3
|
require 'kookaburra/given_driver'
|
4
4
|
require 'kookaburra/ui_driver'
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# `spec/support/kookaburra.rb`:
|
11
|
-
#
|
12
|
-
# RSpec.configure do |c|
|
13
|
-
# c.include(Kookaburra, :type => :request)
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# That will make #given, #api and #ui entry-points available to your examples,
|
17
|
-
# e.g.:
|
18
|
-
#
|
19
|
-
# describe "Widget Management" do
|
20
|
-
# describe "viewing a list of widgets" do
|
21
|
-
# example "when there are no widgets" do
|
22
|
-
# given.there_is_a_user(:bob)
|
23
|
-
# given.user_has_no_widgets(:bob)
|
24
|
-
#
|
25
|
-
# ui.log_in_as(:bob)
|
26
|
-
# ui.navigate_to(:list_of_widgets)
|
27
|
-
#
|
28
|
-
# ui.list_of_widgets.should be_visible
|
29
|
-
# ui.list_of_widgets.should be_empty
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# For Cucumber, add the following to `features/support/kookaburra_setup.rb`:
|
35
|
-
#
|
36
|
-
# Kookaburra.adapter = Capybara
|
37
|
-
# World(Kookaburra)
|
38
|
-
#
|
39
|
-
# Before do
|
40
|
-
# kookaburra_reset!
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# After doing to, the #api, #given and #ui methods will be available in your
|
44
|
-
# Cucumber step definitions.
|
45
|
-
#
|
46
|
-
# (Obviously, the specific methods on #given and #ui are something that will be
|
47
|
-
# unique to your application's domain.)
|
48
|
-
#
|
49
|
-
# [1] http://martinfowler.com/eaaDev/WindowDriver.html
|
6
|
+
# This module contains the methods for Kookaburra configuration as well as
|
7
|
+
# accessors to the `GivenDriver`, `APIDriver` and `UIDriver`. See
|
8
|
+
# {file:README.markdown README} for more information on setting up Kookaburra
|
9
|
+
# for your project.
|
50
10
|
module Kookaburra
|
51
11
|
class << self
|
52
|
-
# Provides the default adapter for the Kookaburra library.
|
53
|
-
# this will probably be the `Capybara` class:
|
12
|
+
# Provides the default adapter for the Kookaburra library.
|
54
13
|
#
|
55
|
-
#
|
14
|
+
# If not using Capybara, the Object must respond to `#app` and return a Rack
|
15
|
+
# application; and it must respond to `#current_session` and return an
|
16
|
+
# object that provides the same interface as `Capybara::Session`
|
56
17
|
#
|
57
|
-
#
|
58
|
-
#
|
18
|
+
# @example using Capybara
|
19
|
+
# Kookaburra.adapter = Capybara
|
59
20
|
attr_accessor :adapter
|
60
21
|
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
22
|
+
# A reference to your application's subclass of `Kookaburra::APIDriver`
|
23
|
+
#
|
24
|
+
# @example setting your APIDriver
|
25
|
+
# Kookaburra.api_driver = MyApplication::Kookaburra::APIDriver
|
64
26
|
attr_accessor :api_driver
|
65
27
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# The Given Driver that will be used by Kookaburra, typically a subclass of
|
71
|
-
# Kookaburra::GivenDriver containing the testing DSL for your app. The default
|
72
|
-
# is an instance of Kookaburra::GivenDriver.
|
28
|
+
# A reference to your application's subclass of `Kookaburra::GivenDriver`
|
29
|
+
#
|
30
|
+
# @example setting your GivenDriver
|
31
|
+
# Kookaburra.api_driver = MyApplication::Kookaburra::GivenDriver
|
73
32
|
attr_accessor :given_driver
|
74
33
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# The UI Driver that will be used by Kookaburra, typically a subclass of
|
80
|
-
# Kookaburra::UIDriver containing the testing DSL for your app. The default
|
81
|
-
# is an instance of Kookaburra::UIDriver.
|
34
|
+
# A reference to your application's subclass of `Kookaburra::UIDriver`
|
35
|
+
#
|
36
|
+
# @example setting your UIDriver
|
37
|
+
# Kookaburra.api_driver = MyApplication::Kookaburra::UIDriver
|
82
38
|
attr_accessor :ui_driver
|
83
39
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
40
|
+
# Configure the test data collections and default data for your tests
|
41
|
+
#
|
42
|
+
# The passed block is evaluated in the context of the `Kookaburra::TestData`
|
43
|
+
# class and therefore has access to the
|
44
|
+
# `Kookaburra::TestData.provide_collection` and
|
45
|
+
# `Kookaburra::TestData.default` methods. Anything else in the block will
|
46
|
+
# also be evaluated in the context of the class, allowing you to further
|
47
|
+
# augment the TestData class.
|
48
|
+
#
|
49
|
+
# @param [Proc] blk the TestData configuration code
|
50
|
+
#
|
51
|
+
# @example creating a collection
|
52
|
+
# Kookaburra.test_data_setup do
|
53
|
+
# provide_collection :users
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# @example specifying default values for use in tests
|
57
|
+
# Kookaburra.test_data_setup do
|
58
|
+
# default :user,
|
59
|
+
# :first_name => 'Bob',
|
60
|
+
# :last_name => 'Jones',
|
61
|
+
# :password => 'bob_jones_password'
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# @example otherwise extending TestData
|
66
|
+
# Kookaburra.test_data_setup do
|
67
|
+
# include MyApplication::Kookaburra::TestDataExtensions
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @see Kookaburra::TestData.provide_collection
|
71
|
+
# @see Kookaburra::TestData.default
|
88
72
|
def test_data_setup(&blk)
|
89
73
|
Kookaburra::TestData.class_eval(&blk)
|
90
74
|
end
|
91
75
|
end
|
92
76
|
|
93
|
-
#
|
94
|
-
# context. For example, in an RSpec example:
|
77
|
+
# Used to override Kookaburra.adapter in Kookaburra's own tests.
|
95
78
|
#
|
96
|
-
#
|
97
|
-
# it "does something" do
|
98
|
-
# self.kookaburra_adapter = CapybaraLikeThing
|
99
|
-
# ...
|
100
|
-
# end
|
101
|
-
# end
|
79
|
+
# This method should not be used by applications using Kookaburra.
|
102
80
|
#
|
81
|
+
# @private
|
103
82
|
attr_accessor :kookaburra_adapter
|
104
83
|
|
105
84
|
def kookaburra_adapter
|
106
85
|
@kookaburra_adapter ||= Kookaburra.adapter
|
107
86
|
end
|
108
87
|
|
109
|
-
#
|
88
|
+
# The configured instance of the `Kookaburra::APIDriver` subclass for your
|
89
|
+
# application.
|
90
|
+
#
|
91
|
+
# Can be used in the Test Implementation layer to access the application's API
|
92
|
+
# directly, however you should probably only call this within your
|
93
|
+
# `GivenDriver`.
|
94
|
+
#
|
95
|
+
# @return [Kookaburra::APIDriver]
|
110
96
|
def api
|
111
|
-
kookaburra_drivers[:api] ||= Kookaburra.api_driver.new(
|
112
|
-
:app => kookaburra_adapter.app,
|
113
|
-
:test_data => kookaburra_test_data)
|
97
|
+
kookaburra_drivers[:api] ||= Kookaburra.api_driver.new(:app => kookaburra_adapter.app)
|
114
98
|
end
|
115
99
|
|
116
|
-
#
|
100
|
+
# The configured instance of the `Kookaburra::GivenDriver` subclass for your
|
101
|
+
# application.
|
102
|
+
#
|
103
|
+
# Use #given inside your test implementation to call methods from your
|
104
|
+
# `GivenDriver` subclass.
|
105
|
+
#
|
106
|
+
# @return [Kookaburra::GivenDriver]
|
117
107
|
def given
|
118
108
|
kookaburra_drivers[:given] ||= \
|
119
109
|
Kookaburra.given_driver.new(:api_driver => api, :test_data => kookaburra_test_data)
|
120
110
|
end
|
121
111
|
|
122
|
-
#
|
112
|
+
# The configured instance of the `Kookaburra::UIDriver` subclass for your
|
113
|
+
# application.
|
114
|
+
#
|
115
|
+
# Use #given inside your test implementation to call methods from your
|
116
|
+
# `UIDriver` subclass.
|
117
|
+
#
|
118
|
+
# @return [Kookaburra::UIDriver]
|
123
119
|
def ui
|
124
120
|
kookaburra_drivers[:ui] ||= Kookaburra.ui_driver.new(
|
125
121
|
:browser => kookaburra_adapter.current_session,
|
126
122
|
:test_data => kookaburra_test_data)
|
127
123
|
end
|
128
124
|
|
125
|
+
# Reset the Kookaburra drivers to clear state between Cucumber scenarios
|
126
|
+
#
|
129
127
|
# This method causes new instances of all the Kookaburra drivers to be created
|
130
128
|
# the next time they are used, and, in particular, resets the state of any
|
131
129
|
# test data that is shared between the various drivers. This is necessary when
|
132
130
|
# Kookaburra is mixed in to Cucumber's World, because World does not get a new
|
133
|
-
# instance for each scenario.
|
134
|
-
# `Before` block in your cucumber setup, i.e.:
|
131
|
+
# instance for each scenario.
|
135
132
|
#
|
133
|
+
# @example add this to `features/support/kookaburra_setup.rb`
|
136
134
|
# Before do
|
137
135
|
# kookaburra_reset!
|
138
136
|
# end
|
@@ -142,14 +140,15 @@ module Kookaburra
|
|
142
140
|
|
143
141
|
private
|
144
142
|
|
145
|
-
# The Kookaburra::TestData instance should not be
|
146
|
-
# the drivers should reference the same
|
143
|
+
# The Kookaburra::TestData instance should not be accesed directly in the test
|
144
|
+
# implementation layer, but all of the drivers should reference the same
|
145
|
+
# instance.
|
147
146
|
def kookaburra_test_data
|
148
147
|
kookaburra_drivers[:test_data] ||= Kookaburra::TestData.new
|
149
148
|
end
|
150
149
|
|
151
150
|
# Holds references to all drivers in a single hash, so that
|
152
|
-
# Kookaburra#kookaburra_reset
|
151
|
+
# `Kookaburra#kookaburra_reset!` can clear all Kookaburra state on the
|
153
152
|
# instance of the including class.
|
154
153
|
def kookaburra_drivers
|
155
154
|
@kookaburra_drivers ||= {}
|
data/test/kookaburra_test.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe Kookaburra do
|
4
|
+
before(:each) do
|
5
|
+
Kookaburra.api_driver = Kookaburra::APIDriver
|
6
|
+
Kookaburra.given_driver = Kookaburra::GivenDriver
|
7
|
+
Kookaburra.ui_driver = Kookaburra::UIDriver
|
8
|
+
end
|
9
|
+
|
4
10
|
describe 'as a mixin' do
|
5
11
|
let(:mixer_class) do
|
6
12
|
Class.new do
|
@@ -138,11 +144,6 @@ describe Kookaburra do
|
|
138
144
|
Kookaburra.api_driver = :an_api_driver
|
139
145
|
assert_equal :an_api_driver, Kookaburra.api_driver
|
140
146
|
end
|
141
|
-
|
142
|
-
it 'defaults to Kookaburra::APIDriver' do
|
143
|
-
Kookaburra.api_driver = nil
|
144
|
-
assert_equal Kookaburra::APIDriver, Kookaburra.api_driver
|
145
|
-
end
|
146
147
|
end
|
147
148
|
|
148
149
|
describe '#given_driver' do
|
@@ -150,11 +151,6 @@ describe Kookaburra do
|
|
150
151
|
Kookaburra.given_driver = :a_given_driver
|
151
152
|
assert_equal :a_given_driver, Kookaburra.given_driver
|
152
153
|
end
|
153
|
-
|
154
|
-
it 'defaults to Kookaburra::GivenDriver' do
|
155
|
-
Kookaburra.given_driver = nil
|
156
|
-
assert_equal Kookaburra::GivenDriver, Kookaburra.given_driver
|
157
|
-
end
|
158
154
|
end
|
159
155
|
|
160
156
|
describe '#ui_driver' do
|
@@ -162,11 +158,6 @@ describe Kookaburra do
|
|
162
158
|
Kookaburra.ui_driver = :a_ui_driver
|
163
159
|
assert_equal :a_ui_driver, Kookaburra.ui_driver
|
164
160
|
end
|
165
|
-
|
166
|
-
it 'defaults to Kookaburra::UIDriver' do
|
167
|
-
Kookaburra.ui_driver = nil
|
168
|
-
assert_equal Kookaburra::UIDriver, Kookaburra.ui_driver
|
169
|
-
end
|
170
161
|
end
|
171
162
|
|
172
163
|
describe '.test_data_setup' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kookaburra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Renewable Funding, LLC
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-24 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
@@ -84,7 +84,7 @@ dependencies:
|
|
84
84
|
segments:
|
85
85
|
- 0
|
86
86
|
version: "0"
|
87
|
-
name:
|
87
|
+
name: yard
|
88
88
|
prerelease: false
|
89
89
|
type: :development
|
90
90
|
requirement: *id005
|
@@ -94,13 +94,12 @@ dependencies:
|
|
94
94
|
requirements:
|
95
95
|
- - ~>
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
hash:
|
97
|
+
hash: 15
|
98
98
|
segments:
|
99
|
+
- 1
|
99
100
|
- 0
|
100
|
-
|
101
|
-
|
102
|
-
version: 0.6.0
|
103
|
-
name: yard
|
101
|
+
version: "1.0"
|
102
|
+
name: redcarpet
|
104
103
|
prerelease: false
|
105
104
|
type: :development
|
106
105
|
requirement: *id006
|
@@ -108,14 +107,12 @@ dependencies:
|
|
108
107
|
version_requirements: &id007 !ruby/object:Gem::Requirement
|
109
108
|
none: false
|
110
109
|
requirements:
|
111
|
-
- -
|
110
|
+
- - ">="
|
112
111
|
- !ruby/object:Gem::Version
|
113
|
-
hash:
|
112
|
+
hash: 3
|
114
113
|
segments:
|
115
|
-
- 1
|
116
114
|
- 0
|
117
|
-
|
118
|
-
version: 1.0.0
|
115
|
+
version: "0"
|
119
116
|
name: bundler
|
120
117
|
prerelease: false
|
121
118
|
type: :development
|
@@ -124,14 +121,12 @@ dependencies:
|
|
124
121
|
version_requirements: &id008 !ruby/object:Gem::Requirement
|
125
122
|
none: false
|
126
123
|
requirements:
|
127
|
-
- -
|
124
|
+
- - ">="
|
128
125
|
- !ruby/object:Gem::Version
|
129
|
-
hash:
|
126
|
+
hash: 3
|
130
127
|
segments:
|
131
|
-
-
|
132
|
-
|
133
|
-
- 4
|
134
|
-
version: 1.6.4
|
128
|
+
- 0
|
129
|
+
version: "0"
|
135
130
|
name: jeweler
|
136
131
|
prerelease: false
|
137
132
|
type: :development
|
@@ -154,14 +149,12 @@ dependencies:
|
|
154
149
|
version_requirements: &id010 !ruby/object:Gem::Requirement
|
155
150
|
none: false
|
156
151
|
requirements:
|
157
|
-
- -
|
152
|
+
- - ">="
|
158
153
|
- !ruby/object:Gem::Version
|
159
|
-
hash:
|
154
|
+
hash: 3
|
160
155
|
segments:
|
161
|
-
-
|
162
|
-
|
163
|
-
- 8
|
164
|
-
version: 1.2.8
|
156
|
+
- 0
|
157
|
+
version: "0"
|
165
158
|
name: reek
|
166
159
|
prerelease: false
|
167
160
|
type: :development
|
@@ -178,6 +171,7 @@ extra_rdoc_files:
|
|
178
171
|
files:
|
179
172
|
- .document
|
180
173
|
- .rvmrc
|
174
|
+
- .yardopts
|
181
175
|
- Gemfile
|
182
176
|
- Gemfile.lock
|
183
177
|
- LICENSE.txt
|