kookaburra 0.27.0 → 1.0.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/Gemfile +5 -4
- data/Gemfile.lock +22 -14
- data/README.markdown +43 -27
- data/Rakefile +19 -2
- data/VERSION +1 -1
- data/kookaburra.gemspec +17 -16
- data/lib/kookaburra/api_driver.rb +178 -64
- data/lib/kookaburra/given_driver.rb +1 -1
- data/spec/integration/test_a_rack_application_spec.rb +22 -5
- data/spec/kookaburra/api_driver_spec.rb +79 -136
- metadata +29 -15
- data/lib/kookaburra/json_api_driver.rb +0 -65
- data/spec/kookaburra/json_api_driver_spec.rb +0 -95
data/Gemfile
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
gem '
|
4
|
-
gem 'json_pure'
|
3
|
+
gem 'rest-client'
|
5
4
|
|
6
5
|
# Add dependencies to develop your gem here.
|
7
6
|
# Include everything needed to run rake, tests, features, etc.
|
8
7
|
group :development do
|
8
|
+
gem 'jruby-openssl', :platforms => :jruby
|
9
9
|
gem 'rspec'
|
10
10
|
gem 'capybara'
|
11
11
|
gem 'yard'
|
12
|
-
gem '
|
12
|
+
gem 'kramdown' # used by yard to format documentation, but not a dependency as far as the yard gem is concerned
|
13
13
|
gem 'jeweler'
|
14
14
|
gem 'reek'
|
15
15
|
gem 'sinatra'
|
16
|
-
gem 'find_a_port'
|
16
|
+
gem 'find_a_port'
|
17
|
+
gem 'json'
|
17
18
|
end
|
data/Gemfile.lock
CHANGED
@@ -2,6 +2,7 @@ GEM
|
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
4
|
addressable (2.3.2)
|
5
|
+
bouncy-castle-java (1.5.0146.1)
|
5
6
|
capybara (1.1.2)
|
6
7
|
mime-types (>= 1.16)
|
7
8
|
nokogiri (>= 1.3.3)
|
@@ -9,10 +10,11 @@ GEM
|
|
9
10
|
rack-test (>= 0.5.4)
|
10
11
|
selenium-webdriver (~> 2.0)
|
11
12
|
xpath (~> 0.1.4)
|
12
|
-
childprocess (0.3.
|
13
|
+
childprocess (0.3.5)
|
13
14
|
ffi (~> 1.0, >= 1.0.6)
|
14
15
|
diff-lcs (1.1.3)
|
15
|
-
ffi (1.1.
|
16
|
+
ffi (1.1.5)
|
17
|
+
ffi (1.1.5-java)
|
16
18
|
find_a_port (1.0.1)
|
17
19
|
git (1.2.5)
|
18
20
|
jeweler (1.8.4)
|
@@ -20,28 +22,32 @@ GEM
|
|
20
22
|
git (>= 1.2.5)
|
21
23
|
rake
|
22
24
|
rdoc
|
23
|
-
|
24
|
-
|
25
|
+
jruby-openssl (0.7.7)
|
26
|
+
bouncy-castle-java (>= 1.5.0146.1)
|
27
|
+
json (1.7.5)
|
28
|
+
json (1.7.5-java)
|
29
|
+
kramdown (0.14.0)
|
25
30
|
libwebsocket (0.1.5)
|
26
31
|
addressable
|
27
32
|
mime-types (1.19)
|
28
33
|
multi_json (1.3.6)
|
29
34
|
nokogiri (1.5.5)
|
30
|
-
|
35
|
+
nokogiri (1.5.5-java)
|
31
36
|
rack (1.4.1)
|
32
37
|
rack-protection (1.2.0)
|
33
38
|
rack
|
34
|
-
rack-test (0.6.
|
39
|
+
rack-test (0.6.2)
|
35
40
|
rack (>= 1.0)
|
36
41
|
rake (0.9.2.2)
|
37
42
|
rdoc (3.12)
|
38
43
|
json (~> 1.4)
|
39
|
-
redcarpet (1.17.2)
|
40
44
|
reek (1.2.12)
|
41
45
|
ripper_ruby_parser (~> 0.0.7)
|
42
46
|
ruby2ruby (~> 1.2.5)
|
43
47
|
ruby_parser (~> 2.0)
|
44
48
|
sexp_processor (~> 3.0)
|
49
|
+
rest-client (1.6.7)
|
50
|
+
mime-types (>= 1.16)
|
45
51
|
ripper_ruby_parser (0.0.8)
|
46
52
|
sexp_processor (~> 3.0)
|
47
53
|
rspec (2.11.0)
|
@@ -49,9 +55,9 @@ GEM
|
|
49
55
|
rspec-expectations (~> 2.11.0)
|
50
56
|
rspec-mocks (~> 2.11.0)
|
51
57
|
rspec-core (2.11.1)
|
52
|
-
rspec-expectations (2.11.
|
58
|
+
rspec-expectations (2.11.3)
|
53
59
|
diff-lcs (~> 1.1.3)
|
54
|
-
rspec-mocks (2.11.
|
60
|
+
rspec-mocks (2.11.3)
|
55
61
|
ruby2ruby (1.2.5)
|
56
62
|
ruby_parser (~> 2.0)
|
57
63
|
sexp_processor (~> 3.0)
|
@@ -64,7 +70,7 @@ GEM
|
|
64
70
|
multi_json (~> 1.0)
|
65
71
|
rubyzip
|
66
72
|
sexp_processor (3.2.0)
|
67
|
-
sinatra (1.3.
|
73
|
+
sinatra (1.3.3)
|
68
74
|
rack (~> 1.3, >= 1.3.6)
|
69
75
|
rack-protection (~> 1.2)
|
70
76
|
tilt (~> 1.3, >= 1.3.3)
|
@@ -74,16 +80,18 @@ GEM
|
|
74
80
|
yard (0.8.2.1)
|
75
81
|
|
76
82
|
PLATFORMS
|
83
|
+
java
|
77
84
|
ruby
|
78
85
|
|
79
86
|
DEPENDENCIES
|
80
87
|
capybara
|
81
|
-
find_a_port
|
88
|
+
find_a_port
|
82
89
|
jeweler
|
83
|
-
|
84
|
-
|
85
|
-
|
90
|
+
jruby-openssl
|
91
|
+
json
|
92
|
+
kramdown
|
86
93
|
reek
|
94
|
+
rest-client
|
87
95
|
rspec
|
88
96
|
sinatra
|
89
97
|
yard
|
data/README.markdown
CHANGED
@@ -3,6 +3,11 @@
|
|
3
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
|
+
## Requirements ##
|
7
|
+
|
8
|
+
Requires Ruby 1.9. Tested with both MRI and JRUBY (not that you must run
|
9
|
+
JRuby in 1.9 compatability mode.)
|
10
|
+
|
6
11
|
## Installation ##
|
7
12
|
|
8
13
|
Kookaburra is available as a Rubygem and [published on Rubygems.org] [Kookaburra Gem],
|
@@ -111,13 +116,14 @@ and shut down a Rack application server. Just add the following to
|
|
111
116
|
|
112
117
|
require 'kookaburra/test_helpers'
|
113
118
|
require 'thwait'
|
119
|
+
require 'find_a_port' # from the find_a_port gem
|
114
120
|
|
115
121
|
# Change these to the files that define your custom GivenDriver and UIDriver
|
116
122
|
# implementations.
|
117
123
|
require 'my_app/kookaburra/given_driver'
|
118
124
|
require 'my_app/kookaburra/ui_driver'
|
119
125
|
|
120
|
-
APP_PORT =
|
126
|
+
APP_PORT = FindAPort.available_port
|
121
127
|
|
122
128
|
# c.app_host below should be set to whatever the root URL of your running
|
123
129
|
# application is.
|
@@ -141,6 +147,10 @@ and shut down a Rack application server. Just add the following to
|
|
141
147
|
c.before(:all, :type => :request) do
|
142
148
|
# Run the server process in a forked process, and get a handle on that
|
143
149
|
# process, so that it can be shut down after the tests run.
|
150
|
+
#
|
151
|
+
# Note that you cannot fork under JRuby and will need to use a thread.
|
152
|
+
# See `spec/integration/test_a_rack_application_spec.rb` for an
|
153
|
+
# example.
|
144
154
|
@rack_server_pid = fork do
|
145
155
|
Capybara.server_port = APP_PORT
|
146
156
|
Capybara::Server.new(MyApplication).boot
|
@@ -205,13 +215,14 @@ and shut down a Rack application server. Just add the following to
|
|
205
215
|
|
206
216
|
require 'kookaburra/test_helpers'
|
207
217
|
require 'thwait'
|
218
|
+
require 'find_a_port' # from the find_a_port gem
|
208
219
|
|
209
220
|
# Change these to the files that define your custom GivenDriver and UIDriver
|
210
221
|
# implementations.
|
211
222
|
require 'my_app/kookaburra/given_driver'
|
212
223
|
require 'my_app/kookaburra/ui_driver'
|
213
224
|
|
214
|
-
APP_PORT =
|
225
|
+
APP_PORT = FindAPort.available_port
|
215
226
|
|
216
227
|
# c.app_host below should be set to whatever the root URL of your running
|
217
228
|
# application is.
|
@@ -227,12 +238,16 @@ and shut down a Rack application server. Just add the following to
|
|
227
238
|
|
228
239
|
World(Kookaburra::TestHelpers)
|
229
240
|
|
230
|
-
# Start the application server prior to running
|
231
|
-
#
|
241
|
+
# Start the application server prior to running the tests.
|
242
|
+
# `MyApplication` below should be replaced with the object that
|
232
243
|
# implements the Rack `#call` interface for your application. For a Rails
|
233
244
|
# app, this would be along the lines of `MyAppName::Application`.
|
234
245
|
# Runs the server process in a forked process, and get a handle on that
|
235
246
|
# process, so that it can be shut down after the tests run.
|
247
|
+
#
|
248
|
+
# Note that you cannot fork under JRuby and will need to use a thread.
|
249
|
+
# See `spec/integration/test_a_rack_application_spec.rb` for an
|
250
|
+
# example.
|
236
251
|
@rack_server_pid = fork do
|
237
252
|
Capybara.server_port = APP_PORT
|
238
253
|
Capybara::Server.new(MyApplication).boot
|
@@ -519,32 +534,32 @@ rather than driving a web browser.
|
|
519
534
|
|
520
535
|
#### API Driver ####
|
521
536
|
|
522
|
-
The `Kookaburra::APIDriver` is used to interact with an application's
|
523
|
-
web services API. You tell Kookaburra about your API by
|
524
|
-
`Kookaburra::APIDriver` for your application
|
525
|
-
|
526
|
-
|
527
|
-
`Kookaburra::JsonApiDriver`:
|
537
|
+
The `Kookaburra::APIDriver` is used to interact with an application's
|
538
|
+
external web services API. You tell Kookaburra about your API by
|
539
|
+
creating a subclass of `Kookaburra::APIDriver` for your application,
|
540
|
+
specifying how requests should be encoded and decoded, and specifying
|
541
|
+
any headers that should be present on every request.
|
528
542
|
|
529
543
|
# lib/my_app/kookaburra/api_driver.rb
|
530
544
|
|
531
|
-
class MyApp::Kookaburra::APIDriver < Kookaburra::
|
545
|
+
class MyApp::Kookaburra::APIDriver < Kookaburra::APIDriver
|
546
|
+
encode_with { |data| JSON.dump(data) }
|
547
|
+
decode_with { |data| JSON.parse(data) }
|
548
|
+
header 'Content-Type', 'application/json'
|
549
|
+
header 'Accept', 'application/json'
|
550
|
+
|
532
551
|
def create_account(account_data)
|
533
|
-
post '/api/
|
552
|
+
post '/api/accounts', account_data
|
534
553
|
end
|
535
554
|
|
536
555
|
def get_account(id)
|
537
|
-
get '/api/
|
556
|
+
get '/api/accounts/%d' % id
|
538
557
|
end
|
539
558
|
end
|
540
559
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
`#delete` in such a way that any Ruby data structure provided as parameters will
|
545
|
-
be appropriately translated to the API's required data format, and any response
|
546
|
-
body from the API request will be translated into a Ruby data structure and
|
547
|
-
returned.
|
560
|
+
The content of your application's APIDriver should consist mainly of
|
561
|
+
mappings between discrete actions and HTTP requests to the specified URL
|
562
|
+
paths.
|
548
563
|
|
549
564
|
#### UI Driver ####
|
550
565
|
|
@@ -623,12 +638,13 @@ You describe the various user interface components by sub-classing
|
|
623
638
|
### The Application Driver Layer ###
|
624
639
|
|
625
640
|
`Kookaburra::APIDriver`, `Kookaburra::UIDriver` and
|
626
|
-
`Kookaburra::UIDriver::UIComponent` rely on the Application Driver layer
|
627
|
-
interact with your application. In the case of the `APIDriver`,
|
628
|
-
the [
|
629
|
-
`UIDriver` and `UIComponent` rely on
|
630
|
-
|
631
|
-
driver for
|
641
|
+
`Kookaburra::UIDriver::UIComponent` rely on the Application Driver layer
|
642
|
+
to interact with your application. In the case of the `APIDriver`,
|
643
|
+
Kookaburra uses the [RestClient] [RestClient] library to send HTTP
|
644
|
+
requests to your application. The `UIDriver` and `UIComponent` rely on
|
645
|
+
whatever is passed to `Kookaburra.new` as the `:browser` option.
|
646
|
+
Presently, we have only used Capybara as the application driver for
|
647
|
+
Kookaburra.
|
632
648
|
|
633
649
|
It's possible that something other than Capybara could be passed in, as long as
|
634
650
|
that something presented the same API. In reality, using something other than
|
@@ -664,4 +680,4 @@ further details.
|
|
664
680
|
[RSpec]: http://rspec.info "RSpec.info: home"
|
665
681
|
[Cucumber]: http://cukes.info/ "Cucumber - Making BDD fun"
|
666
682
|
[Pull Request]: https://github.com/projectdx/kookaburra/pull/new/master "Send a pull request - GitHub"
|
667
|
-
[
|
683
|
+
[RestClient]: https://github.com/archiloque/rest-client "archiloque/rest-client -GitHub"
|
data/Rakefile
CHANGED
@@ -29,8 +29,25 @@ require 'rspec/core/rake_task'
|
|
29
29
|
|
30
30
|
task :default => :spec
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
# TODO: figure out how to get rake task working under JRuby and rbenv
|
33
|
+
if defined?(JRUBY_VERSION) && ENV['RBENV_VERSION']
|
34
|
+
desc 'Run specs'
|
35
|
+
task :spec do
|
36
|
+
msg = <<-EOM
|
37
|
+
********************************************************************************
|
38
|
+
* You appear to be running under JRuby and using rbenv.
|
39
|
+
*
|
40
|
+
* For some reason the `rake spec` command isn't working correctly in
|
41
|
+
* these circumstances. However, you should be able to just run the
|
42
|
+
* `rspec` command directly.
|
43
|
+
********************************************************************************
|
44
|
+
EOM
|
45
|
+
raise msg
|
46
|
+
end
|
47
|
+
else
|
48
|
+
desc 'Run specs'
|
49
|
+
RSpec::Core::RakeTask.new
|
50
|
+
end
|
34
51
|
|
35
52
|
require 'reek/rake/task'
|
36
53
|
Reek::Rake::Task.new do |t|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.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 = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Wilger", "Sam Livingston-Gray", "Ravi Gadad"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-10-14"
|
13
13
|
s.description = "Cucumber + Capybara = Kookaburra? It made sense at the time."
|
14
14
|
s.email = "johnwilger@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -35,7 +35,6 @@ Gem::Specification.new do |s|
|
|
35
35
|
"lib/kookaburra/dependency_accessor.rb",
|
36
36
|
"lib/kookaburra/exceptions.rb",
|
37
37
|
"lib/kookaburra/given_driver.rb",
|
38
|
-
"lib/kookaburra/json_api_driver.rb",
|
39
38
|
"lib/kookaburra/mental_model.rb",
|
40
39
|
"lib/kookaburra/mental_model_matcher.rb",
|
41
40
|
"lib/kookaburra/test_helpers.rb",
|
@@ -47,7 +46,6 @@ Gem::Specification.new do |s|
|
|
47
46
|
"spec/integration/test_a_rack_application_spec.rb",
|
48
47
|
"spec/kookaburra/api_driver_spec.rb",
|
49
48
|
"spec/kookaburra/configuration_spec.rb",
|
50
|
-
"spec/kookaburra/json_api_driver_spec.rb",
|
51
49
|
"spec/kookaburra/mental_model_matcher_spec.rb",
|
52
50
|
"spec/kookaburra/mental_model_spec.rb",
|
53
51
|
"spec/kookaburra/test_helpers_spec.rb",
|
@@ -70,39 +68,42 @@ Gem::Specification.new do |s|
|
|
70
68
|
s.specification_version = 3
|
71
69
|
|
72
70
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
73
|
-
s.add_runtime_dependency(%q<
|
74
|
-
s.
|
71
|
+
s.add_runtime_dependency(%q<rest-client>, [">= 0"])
|
72
|
+
s.add_development_dependency(%q<jruby-openssl>, [">= 0"])
|
75
73
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
76
74
|
s.add_development_dependency(%q<capybara>, [">= 0"])
|
77
75
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
78
|
-
s.add_development_dependency(%q<
|
76
|
+
s.add_development_dependency(%q<kramdown>, [">= 0"])
|
79
77
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
80
78
|
s.add_development_dependency(%q<reek>, [">= 0"])
|
81
79
|
s.add_development_dependency(%q<sinatra>, [">= 0"])
|
82
|
-
s.add_development_dependency(%q<find_a_port>, [">=
|
80
|
+
s.add_development_dependency(%q<find_a_port>, [">= 0"])
|
81
|
+
s.add_development_dependency(%q<json>, [">= 0"])
|
83
82
|
else
|
84
|
-
s.add_dependency(%q<
|
85
|
-
s.add_dependency(%q<
|
83
|
+
s.add_dependency(%q<rest-client>, [">= 0"])
|
84
|
+
s.add_dependency(%q<jruby-openssl>, [">= 0"])
|
86
85
|
s.add_dependency(%q<rspec>, [">= 0"])
|
87
86
|
s.add_dependency(%q<capybara>, [">= 0"])
|
88
87
|
s.add_dependency(%q<yard>, [">= 0"])
|
89
|
-
s.add_dependency(%q<
|
88
|
+
s.add_dependency(%q<kramdown>, [">= 0"])
|
90
89
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
91
90
|
s.add_dependency(%q<reek>, [">= 0"])
|
92
91
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
93
|
-
s.add_dependency(%q<find_a_port>, [">=
|
92
|
+
s.add_dependency(%q<find_a_port>, [">= 0"])
|
93
|
+
s.add_dependency(%q<json>, [">= 0"])
|
94
94
|
end
|
95
95
|
else
|
96
|
-
s.add_dependency(%q<
|
97
|
-
s.add_dependency(%q<
|
96
|
+
s.add_dependency(%q<rest-client>, [">= 0"])
|
97
|
+
s.add_dependency(%q<jruby-openssl>, [">= 0"])
|
98
98
|
s.add_dependency(%q<rspec>, [">= 0"])
|
99
99
|
s.add_dependency(%q<capybara>, [">= 0"])
|
100
100
|
s.add_dependency(%q<yard>, [">= 0"])
|
101
|
-
s.add_dependency(%q<
|
101
|
+
s.add_dependency(%q<kramdown>, [">= 0"])
|
102
102
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
103
103
|
s.add_dependency(%q<reek>, [">= 0"])
|
104
104
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
105
|
-
s.add_dependency(%q<find_a_port>, [">=
|
105
|
+
s.add_dependency(%q<find_a_port>, [">= 0"])
|
106
|
+
s.add_dependency(%q<json>, [">= 0"])
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
@@ -1,91 +1,205 @@
|
|
1
|
+
require 'restclient'
|
1
2
|
require 'kookaburra/exceptions'
|
2
|
-
require 'delegate'
|
3
|
-
require 'patron'
|
4
3
|
|
5
4
|
class Kookaburra
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
# Communicate with a Web Services API
|
6
|
+
#
|
7
|
+
# You will create a subclass of `APIDriver` in your testing
|
8
|
+
# implementation to be used with you subclass of
|
9
|
+
# `Kookaburra::GivenDriver`. While the `GivenDriver` implements the
|
10
|
+
# "business domain" DSL for setting up your application state, the
|
11
|
+
# `APIDriver` maps discreet operations to your application's web
|
12
|
+
# service API and can (optionally) handle encoding input data and
|
13
|
+
# decoding response bodies to and from your preferred serialization
|
14
|
+
# format.
|
15
|
+
class APIDriver
|
16
|
+
class << self
|
17
|
+
# Serializes input data
|
18
|
+
#
|
19
|
+
# If specified, any input data provided to `APIDriver#post`,
|
20
|
+
# `APIDriver#put` or `APIDriver#request` will be processed through
|
21
|
+
# this function prior to being sent to the HTTP server.
|
22
|
+
#
|
23
|
+
# @yieldparam data [Object] The data parameter that was passed to
|
24
|
+
# the request method
|
25
|
+
# @yieldreturn [String] The text to be used as the request body
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# class MyAPIDriver < Kookaburra::APIDriver
|
29
|
+
# encode_with { |data| JSON.dump(data) }
|
30
|
+
# # ...
|
31
|
+
# end
|
32
|
+
def encode_with(&block)
|
33
|
+
define_method(:encode) do |data|
|
34
|
+
return if data.nil?
|
35
|
+
block.call(data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Deserialize response body
|
40
|
+
#
|
41
|
+
# If specified, the response bodies of all requests made using
|
42
|
+
# this `APIDriver` will be processed through this function prior
|
43
|
+
# to being returned.
|
44
|
+
#
|
45
|
+
# @yieldparam data [String] The response body sent by the HTTP
|
46
|
+
# server
|
47
|
+
#
|
48
|
+
# @yieldreturn [Object] The result of parsing the response body
|
49
|
+
# through this function
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# class MyAPIDriver < Kookaburra::APIDriver
|
53
|
+
# decode_with { |data| JSON.parse(data) }
|
54
|
+
# # ...
|
55
|
+
# end
|
56
|
+
def decode_with(&block)
|
57
|
+
define_method(:decode) do |data|
|
58
|
+
block.call(data)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set custom HTTP headers
|
63
|
+
#
|
64
|
+
# Can be called multiple times to set HTTP headers that will be
|
65
|
+
# provided with every request made by the `APIDriver`.
|
66
|
+
#
|
67
|
+
# @param [String] name The name of the header, e.g. 'Content-Type'
|
68
|
+
# @param [String] value The value to which the header is set
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# class MyAPIDriver < Kookaburra::APIDriver
|
72
|
+
# header 'Content-Type', 'application/json'
|
73
|
+
# header 'Accept', 'application/json'
|
74
|
+
# # ...
|
75
|
+
# end
|
76
|
+
def header(name, value)
|
77
|
+
headers[name] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
# Used to retrieve the list of headers within the instance. Not
|
81
|
+
# intended to be used elsewhere.
|
82
|
+
#
|
83
|
+
# @private
|
84
|
+
def headers
|
85
|
+
@headers ||= {}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Create a new `APIDriver` instance
|
10
90
|
#
|
11
91
|
# @param [Kookaburra::Configuration] configuration
|
12
|
-
# @param [
|
13
|
-
|
14
|
-
|
15
|
-
|
92
|
+
# @param [RestClient] http_client (optional) Generally only
|
93
|
+
# overriden when testing Kookaburra itself
|
94
|
+
def initialize(configuration, http_client = RestClient)
|
95
|
+
@configuration = configuration
|
96
|
+
@http_client = http_client
|
16
97
|
end
|
17
98
|
|
18
|
-
#
|
99
|
+
# Convenience method to make a POST request
|
19
100
|
#
|
20
|
-
# @
|
21
|
-
|
22
|
-
|
23
|
-
# @option options [Integer] :expected_response_status (201) The HTTP status
|
24
|
-
# code that you expect the server to respond with.
|
25
|
-
# @raise [Kookaburra::UnexpectedResponse] raised if the HTTP status of the
|
26
|
-
# response does not match the `:expected_response_status`
|
27
|
-
def post(path, data, options = {})
|
28
|
-
request(:post, path, options, data)
|
101
|
+
# @see APIDriver#request
|
102
|
+
def post(path, data)
|
103
|
+
request(:post, path, data)
|
29
104
|
end
|
30
105
|
|
31
|
-
#
|
106
|
+
# Convenience method to make a PUT request
|
32
107
|
#
|
33
|
-
# @
|
34
|
-
|
35
|
-
|
36
|
-
# @option options [Integer] :expected_response_status (201) The HTTP status
|
37
|
-
# code that you expect the server to respond with.
|
38
|
-
# @raise [Kookaburra::UnexpectedResponse] raised if the HTTP status of the
|
39
|
-
# response does not match the `:expected_response_status`
|
40
|
-
def put(path, data, options = {})
|
41
|
-
request(:put, path, options, data)
|
108
|
+
# @see APIDriver#request
|
109
|
+
def put(path, data)
|
110
|
+
request(:put, path, data)
|
42
111
|
end
|
43
112
|
|
44
|
-
#
|
113
|
+
# Convenience method to make a GET request
|
45
114
|
#
|
46
|
-
# @
|
47
|
-
|
48
|
-
|
49
|
-
# @raise [Kookaburra::UnexpectedResponse] raised if the HTTP status of the
|
50
|
-
# response does not match the `:expected_response_status`
|
51
|
-
def get(path, options = {})
|
52
|
-
request(:get, path, options)
|
115
|
+
# @see APIDriver#request
|
116
|
+
def get(path)
|
117
|
+
request(:get, path)
|
53
118
|
end
|
54
119
|
|
55
|
-
#
|
120
|
+
# Convenience method to make a DELETE request
|
121
|
+
#
|
122
|
+
# @see APIDriver#request
|
123
|
+
def delete(path)
|
124
|
+
request(:delete, path)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Make an HTTP request
|
128
|
+
#
|
129
|
+
# If you need to make a request other than the typical GET, POST,
|
130
|
+
# PUT and DELETE, you can use this method directly.
|
131
|
+
#
|
132
|
+
# This *will* follow redirects when the server's response code is in
|
133
|
+
# the 3XX range. If the response is a 303, the request will be
|
134
|
+
# transformed into a GET request.
|
56
135
|
#
|
57
|
-
# @
|
58
|
-
# @
|
59
|
-
#
|
60
|
-
# @
|
61
|
-
#
|
62
|
-
|
63
|
-
|
136
|
+
# @see APIDriver.encode_with
|
137
|
+
# @see APIDriver.decode_with
|
138
|
+
# @see APIDriver.header
|
139
|
+
# @see APIDriver#get
|
140
|
+
# @see APIDriver#post
|
141
|
+
# @see APIDriver#put
|
142
|
+
# @see APIDriver#delete
|
143
|
+
#
|
144
|
+
# @param [Symbol] method The HTTP verb to use with the request
|
145
|
+
# @param [String] path The path to request. Will be joined with the
|
146
|
+
# `Kookaburra::Configuration#app_host` setting to build the
|
147
|
+
# URL unless a full URL is specified here.
|
148
|
+
# @param [Object] data The data to be posted in the request body. If
|
149
|
+
# an encoder was specified, this can be any type of object as
|
150
|
+
# long as the encoder can serialize it into a String. If no
|
151
|
+
# encoder was specified, then this can be one of:
|
152
|
+
#
|
153
|
+
# * a String - will be passed as is
|
154
|
+
# * a Hash - will be encoded as normal HTTP form params
|
155
|
+
# * a Hash containing references to one or more Files - will
|
156
|
+
# set the content type to multipart/form-data
|
157
|
+
#
|
158
|
+
# @return [Object] The response body returned by the server. If a
|
159
|
+
# decoder was specified, this will return the result of
|
160
|
+
# parsing the response body through the decoder function.
|
161
|
+
#
|
162
|
+
# @raise [Kookaburra::UnexpectedResponse] Raised if the HTTP
|
163
|
+
# response received is not in the 2XX-3XX range.
|
164
|
+
def request(method, path, data = nil)
|
165
|
+
data = encode(data)
|
166
|
+
response = @http_client.send(method, url_for(path), *[data, headers].compact)
|
167
|
+
decode(response.body)
|
168
|
+
rescue RestClient::Exception => e
|
169
|
+
raise_unexpected_response(e)
|
64
170
|
end
|
65
171
|
|
66
172
|
private
|
67
173
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
if path.nil?
|
72
|
-
raise ArgumentError, "You must specify a request URL, but it was nil."
|
73
|
-
end
|
74
|
-
args = [type, path, data, options].compact
|
75
|
-
response = __getobj__.send(*args)
|
174
|
+
def headers
|
175
|
+
self.class.headers
|
176
|
+
end
|
76
177
|
|
77
|
-
|
78
|
-
|
178
|
+
def url_for(path)
|
179
|
+
URI.join(base_url, path).to_s
|
79
180
|
end
|
80
181
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
182
|
+
def base_url
|
183
|
+
@configuration.app_host
|
184
|
+
end
|
185
|
+
|
186
|
+
def encode(data)
|
187
|
+
data
|
188
|
+
end
|
189
|
+
|
190
|
+
def decode(data)
|
191
|
+
data
|
192
|
+
end
|
193
|
+
|
194
|
+
def raise_unexpected_response(exception)
|
195
|
+
message = <<-END
|
196
|
+
Unexpected response from server: #{exception.message}
|
197
|
+
|
198
|
+
#{exception.http_body}
|
199
|
+
END
|
200
|
+
new_exception = UnexpectedResponse.new(message)
|
201
|
+
new_exception.set_backtrace(exception.backtrace)
|
202
|
+
raise new_exception
|
89
203
|
end
|
90
204
|
end
|
91
205
|
end
|
@@ -5,7 +5,7 @@ class Kookaburra
|
|
5
5
|
# test preconditions. Unlike {Kookaburra::APIDriver}, which is meant to be a
|
6
6
|
# simple mapping to your application's API, a method in the GivenDriver may be
|
7
7
|
# comprised of several distinct API calls as well as access to Kookaburra's
|
8
|
-
# test data store
|
8
|
+
# test data store via `#mental_model`.
|
9
9
|
#
|
10
10
|
# @abstract Subclass and implement your Given DSL.
|
11
11
|
#
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'kookaburra/test_helpers'
|
2
|
-
require 'kookaburra/
|
2
|
+
require 'kookaburra/api_driver'
|
3
3
|
require 'capybara'
|
4
4
|
require 'thwait'
|
5
5
|
require 'find_a_port'
|
@@ -182,7 +182,12 @@ describe "testing a Rack application with Kookaburra" do
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
-
class MyAPIDriver < Kookaburra::
|
185
|
+
class MyAPIDriver < Kookaburra::APIDriver
|
186
|
+
encode_with { |data| JSON.dump(data) }
|
187
|
+
decode_with { |data| JSON.parse(data) }
|
188
|
+
header 'Content-Type', 'application/json'
|
189
|
+
header 'Accept', 'application/json'
|
190
|
+
|
186
191
|
def create_user(user_data)
|
187
192
|
post '/users', user_data
|
188
193
|
end
|
@@ -315,17 +320,29 @@ describe "testing a Rack application with Kookaburra" do
|
|
315
320
|
end
|
316
321
|
|
317
322
|
before(:all) do
|
318
|
-
|
323
|
+
start_server = lambda {
|
319
324
|
Capybara.server_port = APP_PORT
|
320
325
|
Capybara::Server.new(JsonApiApp.new).boot
|
321
326
|
ThreadsWait.all_waits(Thread.list)
|
327
|
+
}
|
328
|
+
if defined?(JRUBY_VERSION)
|
329
|
+
# Can't `fork` in JRuby. This doesn't provide the state
|
330
|
+
# isolation that you get with forking (AFAIK, I'm no JVM
|
331
|
+
# expert, though), but it lets the tests run and pass.
|
332
|
+
Thread.new { start_server.call }
|
333
|
+
else
|
334
|
+
@rack_server_pid = fork do
|
335
|
+
start_server.call
|
336
|
+
end
|
322
337
|
end
|
323
338
|
sleep 1 # Give the server a chance to start up.
|
324
339
|
end
|
325
340
|
|
326
341
|
after(:all) do
|
327
|
-
|
328
|
-
|
342
|
+
unless defined?(JRUBY_VERSION)
|
343
|
+
Process.kill(9, @rack_server_pid)
|
344
|
+
Process.wait
|
345
|
+
end
|
329
346
|
end
|
330
347
|
|
331
348
|
it "runs the tests against the app" do
|
@@ -1,159 +1,102 @@
|
|
1
1
|
require 'kookaburra/api_driver'
|
2
2
|
|
3
3
|
describe Kookaburra::APIDriver do
|
4
|
+
def url_for(uri)
|
5
|
+
URI.join('http://example.com', uri).to_s
|
6
|
+
end
|
7
|
+
|
4
8
|
let(:configuration) { stub('Configuration', :app_host => 'http://example.com') }
|
5
9
|
|
6
10
|
let(:api) { Kookaburra::APIDriver.new(configuration, client) }
|
7
11
|
|
8
|
-
let(:response) {
|
9
|
-
stub('Patron::Response', :body => 'foo', :status => 200, :url => '/foo')
|
10
|
-
}
|
12
|
+
let(:response) { stub('RestClient::Response', body: 'foo', code: 200) }
|
11
13
|
|
12
|
-
let(:client) {
|
13
|
-
mock('Patron::Session', :post => response, :get => response,
|
14
|
-
:put => response, :delete => response, :base_url= => nil)
|
15
|
-
}
|
16
|
-
|
17
|
-
describe '#initialize' do
|
18
|
-
it 'instantiates a new http client if no :http_client option is passed' do
|
19
|
-
Patron::Session.should_receive(:new).and_return(stub.as_null_object)
|
20
|
-
Kookaburra::APIDriver.new(configuration)
|
21
|
-
end
|
14
|
+
let(:client) { stub('RestClient') }
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
it 'sends POST requests to the server and returns the response body' do
|
17
|
+
client.should_receive(:post).with(url_for('/foo'), 'bar', {}) \
|
18
|
+
.and_return(response)
|
19
|
+
api.post('/foo', 'bar').should == 'foo'
|
27
20
|
end
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
it 'delegates to the http client' do
|
35
|
-
client.should_receive(:post).with('/foo', 'bar', {}) \
|
36
|
-
.and_return(response)
|
37
|
-
api.post('/foo', 'bar')
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'returns the response body' do
|
41
|
-
api.post('/foo', 'bar').should == 'foo'
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'does not raise an UnexpectedResponse if the response status matches the specified expectation' do
|
45
|
-
response.stub!(:status => 666)
|
46
|
-
lambda { api.post('/foo', 'bar', :expected_response_status => 666) } \
|
47
|
-
.should_not raise_error
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'raises an UnexpectedResponse if the response status is not the specified status' do
|
51
|
-
lambda { api.post('/foo', 'bar', :expected_response_status => 666) } \
|
52
|
-
.should raise_error(Kookaburra::UnexpectedResponse,
|
53
|
-
"POST to /foo responded with 201 status, not 666 as expected\n\nfoo")
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'is OK by default with a response status of 201' do
|
57
|
-
lambda { api.post('/foo', 'bar') } \
|
58
|
-
.should_not raise_error(Kookaburra::UnexpectedResponse)
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'is OK by default with a response status of 200' do
|
62
|
-
response.stub!(:status => 200)
|
63
|
-
lambda { api.post('/foo', 'bar') } \
|
64
|
-
.should_not raise_error(Kookaburra::UnexpectedResponse)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'raises an ArgumentError with a useful message if no request path is specified' do
|
68
|
-
lambda { api.post(nil, 'bar') } \
|
69
|
-
.should raise_error(ArgumentError, "You must specify a request URL, but it was nil.")
|
70
|
-
end
|
22
|
+
it 'sends PUT requests to the server and returns the response body' do
|
23
|
+
client.should_receive(:put).with(url_for('/foo'), 'bar', {}) \
|
24
|
+
.and_return(response)
|
25
|
+
api.put('/foo', 'bar').should == 'foo'
|
71
26
|
end
|
72
27
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
api.put('/foo', 'bar')
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'returns the response body' do
|
81
|
-
api.put('/foo', 'bar').should == 'foo'
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'does not raise an UnexpectedResponse if the response status matches the specified expectation' do
|
85
|
-
response.stub!(:status => 666)
|
86
|
-
lambda { api.put('/foo', 'bar', :expected_response_status => 666) } \
|
87
|
-
.should_not raise_error
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'raises an UnexpectedResponse if the response status is not the specified status' do
|
91
|
-
lambda { api.put('/foo', 'bar', :expected_response_status => 666) } \
|
92
|
-
.should raise_error(Kookaburra::UnexpectedResponse,
|
93
|
-
"PUT to /foo responded with 200 status, not 666 as expected\n\nfoo")
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'raises an ArgumentError with a useful message if no request path is specified' do
|
97
|
-
lambda { api.put(nil, 'bar') } \
|
98
|
-
.should raise_error(ArgumentError, "You must specify a request URL, but it was nil.")
|
99
|
-
end
|
28
|
+
it 'sends GET requests to the server and returns the response body' do
|
29
|
+
client.should_receive(:get).with(url_for('/foo'), {}) \
|
30
|
+
.and_return(response)
|
31
|
+
api.get('/foo').should == 'foo'
|
100
32
|
end
|
101
33
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
api.get('/foo')
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'returns the response body' do
|
110
|
-
api.get('/foo').should == 'foo'
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'does not raise an UnexpectedResponse if the response status matches the specified expectation' do
|
114
|
-
response.stub!(:status => 666)
|
115
|
-
lambda { api.get('/foo', :expected_response_status => 666) } \
|
116
|
-
.should_not raise_error
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'raises an UnexpectedResponse if the response status is not the specified status' do
|
120
|
-
lambda { api.get('/foo', :expected_response_status => 666) } \
|
121
|
-
.should raise_error(Kookaburra::UnexpectedResponse,
|
122
|
-
"GET to /foo responded with 200 status, not 666 as expected\n\nfoo")
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'raises an ArgumentError with a useful message if no request path is specified' do
|
126
|
-
lambda { api.get(nil) } \
|
127
|
-
.should raise_error(ArgumentError, "You must specify a request URL, but it was nil.")
|
128
|
-
end
|
34
|
+
it 'sends DELETE requests to the server and returns the response body' do
|
35
|
+
client.should_receive(:delete).with(url_for('/foo'), {}) \
|
36
|
+
.and_return(response)
|
37
|
+
api.delete('/foo').should == 'foo'
|
129
38
|
end
|
130
39
|
|
131
|
-
describe '
|
132
|
-
|
133
|
-
client.
|
134
|
-
.and_return(response)
|
135
|
-
api.delete('/foo')
|
40
|
+
describe 'any type of HTTP request' do
|
41
|
+
before(:each) do
|
42
|
+
client.stub!(:http_verb => response)
|
136
43
|
end
|
137
44
|
|
138
45
|
it 'returns the response body' do
|
139
|
-
api.
|
140
|
-
end
|
141
|
-
|
142
|
-
it '
|
143
|
-
response.stub!(:
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
46
|
+
api.request(:http_verb, '/foo', 'bar').should == 'foo'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'raises an UnexpectedResponse if the request is not successful' do
|
50
|
+
response.stub!(code: 500)
|
51
|
+
client.stub!(:http_verb).and_raise(RestClient::Exception.new(response))
|
52
|
+
lambda { api.request(:http_verb, '/foo') } \
|
53
|
+
.should raise_error(Kookaburra::UnexpectedResponse)
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when custom headers are specified' do
|
57
|
+
let(:api) {
|
58
|
+
klass = Class.new(Kookaburra::APIDriver) do
|
59
|
+
header 'Header-Foo', 'Baz'
|
60
|
+
header 'Header-Bar', 'Bam'
|
61
|
+
end
|
62
|
+
klass.new(configuration, client)
|
63
|
+
}
|
64
|
+
|
65
|
+
it "sets headers on requests" do
|
66
|
+
client.should_receive(:http_verb).with(url_for('/foo'), {}, 'Header-Foo' => 'Baz', 'Header-Bar' => 'Bam')
|
67
|
+
api.request(:http_verb, '/foo', {})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when a custom encoder is specified' do
|
72
|
+
let(:api) {
|
73
|
+
klass = Class.new(Kookaburra::APIDriver) do
|
74
|
+
encode_with { |data| :some_encoded_data }
|
75
|
+
end
|
76
|
+
klass.new(configuration, client)
|
77
|
+
}
|
78
|
+
|
79
|
+
it "encodes input to requests" do
|
80
|
+
client.should_receive(:http_verb) do |_, data, _|
|
81
|
+
data.should == :some_encoded_data
|
82
|
+
response
|
83
|
+
end
|
84
|
+
|
85
|
+
api.request(:http_verb, '/foo', :ruby_data)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when a custom decoder is specified' do
|
90
|
+
let(:api) {
|
91
|
+
klass = Class.new(Kookaburra::APIDriver) do
|
92
|
+
decode_with { |data| :some_decoded_data }
|
93
|
+
end
|
94
|
+
klass.new(configuration, client)
|
95
|
+
}
|
96
|
+
|
97
|
+
it "decodes response bodies from requests" do
|
98
|
+
api.request(:http_verb, '/foo').should == :some_decoded_data
|
99
|
+
end
|
157
100
|
end
|
158
101
|
end
|
159
102
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kookaburra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,10 +11,10 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-10-14 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: rest-client
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: '0'
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: jruby-openssl
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
none: false
|
36
36
|
requirements:
|
37
37
|
- - ! '>='
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
|
-
type: :
|
40
|
+
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
none: false
|
@@ -94,21 +94,21 @@ dependencies:
|
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
- !ruby/object:Gem::Dependency
|
97
|
-
name:
|
97
|
+
name: kramdown
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
99
99
|
none: false
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ! '>='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
|
-
- -
|
109
|
+
- - ! '>='
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '
|
111
|
+
version: '0'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: jeweler
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,7 +164,7 @@ dependencies:
|
|
164
164
|
requirements:
|
165
165
|
- - ! '>='
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version:
|
167
|
+
version: '0'
|
168
168
|
type: :development
|
169
169
|
prerelease: false
|
170
170
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -172,7 +172,23 @@ dependencies:
|
|
172
172
|
requirements:
|
173
173
|
- - ! '>='
|
174
174
|
- !ruby/object:Gem::Version
|
175
|
-
version:
|
175
|
+
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: json
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
none: false
|
180
|
+
requirements:
|
181
|
+
- - ! '>='
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0'
|
184
|
+
type: :development
|
185
|
+
prerelease: false
|
186
|
+
version_requirements: !ruby/object:Gem::Requirement
|
187
|
+
none: false
|
188
|
+
requirements:
|
189
|
+
- - ! '>='
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
176
192
|
description: Cucumber + Capybara = Kookaburra? It made sense at the time.
|
177
193
|
email: johnwilger@gmail.com
|
178
194
|
executables: []
|
@@ -199,7 +215,6 @@ files:
|
|
199
215
|
- lib/kookaburra/dependency_accessor.rb
|
200
216
|
- lib/kookaburra/exceptions.rb
|
201
217
|
- lib/kookaburra/given_driver.rb
|
202
|
-
- lib/kookaburra/json_api_driver.rb
|
203
218
|
- lib/kookaburra/mental_model.rb
|
204
219
|
- lib/kookaburra/mental_model_matcher.rb
|
205
220
|
- lib/kookaburra/test_helpers.rb
|
@@ -211,7 +226,6 @@ files:
|
|
211
226
|
- spec/integration/test_a_rack_application_spec.rb
|
212
227
|
- spec/kookaburra/api_driver_spec.rb
|
213
228
|
- spec/kookaburra/configuration_spec.rb
|
214
|
-
- spec/kookaburra/json_api_driver_spec.rb
|
215
229
|
- spec/kookaburra/mental_model_matcher_spec.rb
|
216
230
|
- spec/kookaburra/mental_model_spec.rb
|
217
231
|
- spec/kookaburra/test_helpers_spec.rb
|
@@ -238,7 +252,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
252
|
version: '0'
|
239
253
|
segments:
|
240
254
|
- 0
|
241
|
-
hash: -
|
255
|
+
hash: -1361909781639378810
|
242
256
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
257
|
none: false
|
244
258
|
requirements:
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
require 'json'
|
3
|
-
require 'kookaburra/api_driver'
|
4
|
-
|
5
|
-
class Kookaburra
|
6
|
-
# Delegates all methods (by default) to and instance of
|
7
|
-
# {Kookaburra::APIDriver}.
|
8
|
-
#
|
9
|
-
# Expects the application's API to accept and respond with JSON formatted
|
10
|
-
# data. All methods will decode the response body using
|
11
|
-
# `ActiveSupport::JSON.decode`. Methods that take input data ({#post} and
|
12
|
-
# {#put}) will encode the post data using `ActiveSupport::JSON.encode`.
|
13
|
-
class JsonApiDriver < SimpleDelegator
|
14
|
-
#
|
15
|
-
# Sets both the "Content-Type" and "Accept" headers to "application/json".
|
16
|
-
#
|
17
|
-
# @param [Kookaburra::Configuration] configuration
|
18
|
-
# @param [Kookaburra::APIDriver] api_driver (Kookaburra::APIDriver.new)
|
19
|
-
# The APIDriver instance to be delegated to. Changing this is probably
|
20
|
-
# only useful for testing Kookaburra itself.
|
21
|
-
def initialize(configuration, api_driver = nil)
|
22
|
-
api_driver = api_driver || APIDriver.new(configuration)
|
23
|
-
api_driver.headers.merge!(
|
24
|
-
'Content-Type' => 'application/json',
|
25
|
-
'Accept' => 'application/json'
|
26
|
-
)
|
27
|
-
super(api_driver)
|
28
|
-
end
|
29
|
-
|
30
|
-
def post(path, data, *args)
|
31
|
-
request(:post, path, data, *args)
|
32
|
-
end
|
33
|
-
|
34
|
-
def put(path, data, *args)
|
35
|
-
request(:put, path, data, *args)
|
36
|
-
end
|
37
|
-
|
38
|
-
def get(path, *args)
|
39
|
-
request(:get, path, nil, *args)
|
40
|
-
end
|
41
|
-
|
42
|
-
def delete(path, *args)
|
43
|
-
request(:delete, path, nil, *args)
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def request(type, path, data = nil, *args)
|
49
|
-
# don't want to send data to methods that don't accept it
|
50
|
-
args = [path, *([encode(data), args].reject(&:nil?))].flatten
|
51
|
-
|
52
|
-
output = __getobj__.send(type, *args)
|
53
|
-
|
54
|
-
decode(output)
|
55
|
-
end
|
56
|
-
|
57
|
-
def encode(data)
|
58
|
-
JSON.dump(data) unless data.nil?
|
59
|
-
end
|
60
|
-
|
61
|
-
def decode(data)
|
62
|
-
JSON.parse(data)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'kookaburra/json_api_driver'
|
2
|
-
|
3
|
-
describe Kookaburra::JsonApiDriver do
|
4
|
-
let(:response) { '{"foo":"bar"}' }
|
5
|
-
|
6
|
-
let(:api) {
|
7
|
-
stub('APIDriver', :get => response, :post => response, :put => response,
|
8
|
-
:delete => response, :headers => {})
|
9
|
-
}
|
10
|
-
|
11
|
-
let(:configuration) {
|
12
|
-
stub('Configuration')
|
13
|
-
}
|
14
|
-
|
15
|
-
let(:json) { Kookaburra::JsonApiDriver.new(stub('Configuration'), api) }
|
16
|
-
|
17
|
-
describe '#initialize' do
|
18
|
-
it 'instantiates a new APIDriver if no :api_driver option is passed' do
|
19
|
-
Kookaburra::APIDriver.should_receive(:new) \
|
20
|
-
.with(configuration) \
|
21
|
-
.and_return(api)
|
22
|
-
Kookaburra::JsonApiDriver.new(configuration)
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'does not instantiate a new APIDriver if an :api_driver option is passed' do
|
26
|
-
Kookaburra::APIDriver.should_receive(:new).never
|
27
|
-
Kookaburra::JsonApiDriver.new(configuration, api)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'sets appropriate headers for a JSON API request' do
|
31
|
-
Kookaburra::JsonApiDriver.new(configuration, api)
|
32
|
-
api.headers.should == {
|
33
|
-
'Content-Type' => 'application/json',
|
34
|
-
'Accept' => 'application/json'
|
35
|
-
}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'delegates to a Kookaburra::APIDriver by default' do
|
40
|
-
api.stub!(:foo => :bar)
|
41
|
-
json.foo.should == :bar
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '#post' do
|
45
|
-
it 'delegates to the api driver as a JSON request' do
|
46
|
-
api.should_receive(:post) \
|
47
|
-
.with('/foo', '{"foo":"bar"}') \
|
48
|
-
.and_return('{"baz":"bam"}')
|
49
|
-
json.post('/foo', 'foo' => 'bar')
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'returns the JSON-decoded response body' do
|
53
|
-
json.post('/foo', :bar => :baz).should == {'foo' => 'bar'}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '#put' do
|
58
|
-
it 'delegates to the api driver as a JSON request' do
|
59
|
-
api.should_receive(:put) \
|
60
|
-
.with('/foo', '{"foo":"bar"}') \
|
61
|
-
.and_return('{"baz":"bam"}')
|
62
|
-
json.put('/foo', 'foo' => 'bar')
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'returns the JSON-decoded response body' do
|
66
|
-
json.put('/foo', :bar => :baz).should == {'foo' => 'bar'}
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe '#get' do
|
71
|
-
it 'delegates to the api driver as a JSON request' do
|
72
|
-
api.should_receive(:get) \
|
73
|
-
.with('/foo') \
|
74
|
-
.and_return('{"baz":"bam"}')
|
75
|
-
json.get('/foo')
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'returns the JSON-decoded response body' do
|
79
|
-
json.get('/foo').should == {'foo' => 'bar'}
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe '#delete' do
|
84
|
-
it 'delegates to the api driver as a JSON request' do
|
85
|
-
api.should_receive(:delete) \
|
86
|
-
.with('/foo') \
|
87
|
-
.and_return('{"baz":"bam"}')
|
88
|
-
json.delete('/foo')
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'returns the JSON-decoded response body' do
|
92
|
-
json.delete('/foo').should == {'foo' => 'bar'}
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|