kookaburra 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|