kookaburra 1.1.0 → 1.2.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/README.markdown +29 -65
- data/VERSION +1 -1
- data/kookaburra.gemspec +3 -2
- data/lib/kookaburra/api_driver.rb +9 -9
- data/lib/kookaburra/configuration.rb +1 -1
- data/lib/kookaburra/given_driver.rb +1 -1
- data/lib/kookaburra/mental_model.rb +11 -11
- data/lib/kookaburra/rack_app_server.rb +110 -0
- data/lib/kookaburra/ui_driver/has_ui_components.rb +3 -3
- data/lib/kookaburra/ui_driver/scoped_browser.rb +2 -2
- data/lib/kookaburra/ui_driver/ui_component.rb +6 -6
- data/spec/integration/test_a_rack_application_spec.rb +8 -26
- metadata +4 -3
data/README.markdown
CHANGED
@@ -115,22 +115,28 @@ and shut down a Rack application server. Just add the following to
|
|
115
115
|
`spec/support/kookaburra_setup.rb`:
|
116
116
|
|
117
117
|
require 'kookaburra/test_helpers'
|
118
|
-
require '
|
119
|
-
require 'find_a_port' # from the find_a_port gem
|
118
|
+
require 'kookaburra/rack_app_server'
|
120
119
|
|
121
120
|
# Change these to the files that define your custom GivenDriver and UIDriver
|
122
121
|
# implementations.
|
123
122
|
require 'my_app/kookaburra/given_driver'
|
124
123
|
require 'my_app/kookaburra/ui_driver'
|
125
124
|
|
126
|
-
|
125
|
+
# `MyApplication` below should be replaced with the object that
|
126
|
+
# implements the Rack `#call` interface for your application. For a
|
127
|
+
# Rails app, this would be along the lines of
|
128
|
+
# `MyAppName::Application`.
|
129
|
+
app_server = Kookaburra::RackAppServer.new do
|
130
|
+
require 'path/to/my_application'
|
131
|
+
MyApplication
|
132
|
+
end
|
127
133
|
|
128
|
-
# c.app_host below should be set to whatever the root URL of your
|
129
|
-
# application is.
|
134
|
+
# c.app_host below should be set to whatever the root URL of your
|
135
|
+
# running application is.
|
130
136
|
Kookaburra.configure do |c|
|
131
137
|
c.given_driver_class = MyApp::Kookaburra::GivenDriver
|
132
138
|
c.ui_driver_class = MyApp::Kookaburra::UIDriver
|
133
|
-
c.app_host = 'http://localhost:%d' %
|
139
|
+
c.app_host = 'http://localhost:%d' % app_server.port
|
134
140
|
c.browser = Capybara::Session.new(:selenium)
|
135
141
|
c.server_error_detection { |browser|
|
136
142
|
browser.has_css?('head title', :text => 'Internal Server Error')
|
@@ -140,36 +146,12 @@ and shut down a Rack application server. Just add the following to
|
|
140
146
|
RSpec.configure do |c|
|
141
147
|
c.include(Kookaburra::TestHelpers, :type => :request)
|
142
148
|
|
143
|
-
# Start the application server prior to running a group of integration
|
144
|
-
# specs. `MyApplication` below should be replaced with the object that
|
145
|
-
# implements the Rack `#call` interface for your application. For a Rails
|
146
|
-
# app, this would be along the lines of `MyAppName::Application`.
|
147
149
|
c.before(:all, :type => :request) do
|
148
|
-
|
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.
|
154
|
-
@rack_server_pid = fork do
|
155
|
-
Capybara.server_port = APP_PORT
|
156
|
-
Capybara::Server.new(MyApplication).boot
|
157
|
-
|
158
|
-
# This ensures that this forked process keeps running, because the
|
159
|
-
# actual server is started in a thread by Capybara.
|
160
|
-
ThreadsWait.all_waits(Thread.list)
|
161
|
-
end
|
162
|
-
|
163
|
-
# Give the server a chance to start up in the forked process. You may
|
164
|
-
# need to adjust this depending on how long your application takes to
|
165
|
-
# start up.
|
166
|
-
sleep 1
|
150
|
+
app_server.boot
|
167
151
|
end
|
168
152
|
|
169
|
-
# After the tests run, kill the server process.
|
170
153
|
c.after(:all, :type => :request) do
|
171
|
-
|
172
|
-
Process.wait
|
154
|
+
app_server.shutdown
|
173
155
|
end
|
174
156
|
end
|
175
157
|
|
@@ -214,22 +196,28 @@ and shut down a Rack application server. Just add the following to
|
|
214
196
|
`features/support/kookaburra_setup.rb`:
|
215
197
|
|
216
198
|
require 'kookaburra/test_helpers'
|
217
|
-
require '
|
218
|
-
require 'find_a_port' # from the find_a_port gem
|
199
|
+
require 'kookaburra/rack_app_server'
|
219
200
|
|
220
201
|
# Change these to the files that define your custom GivenDriver and UIDriver
|
221
202
|
# implementations.
|
222
203
|
require 'my_app/kookaburra/given_driver'
|
223
204
|
require 'my_app/kookaburra/ui_driver'
|
224
205
|
|
225
|
-
|
206
|
+
# `MyApplication` below should be replaced with the object that
|
207
|
+
# implements the Rack `#call` interface for your application. For a
|
208
|
+
# Rails app, this would be along the lines of
|
209
|
+
# `MyAppName::Application`.
|
210
|
+
app_server = Kookaburra::RackAppServer.new do
|
211
|
+
require 'path/to/my_application'
|
212
|
+
MyApplication
|
213
|
+
end
|
226
214
|
|
227
|
-
# c.app_host below should be set to whatever the root URL of your
|
228
|
-
# application is.
|
215
|
+
# c.app_host below should be set to whatever the root URL of your
|
216
|
+
# running application is.
|
229
217
|
Kookaburra.configure do |c|
|
230
218
|
c.given_driver_class = MyApp::Kookaburra::GivenDriver
|
231
219
|
c.ui_driver_class = MyApp::Kookaburra::UIDriver
|
232
|
-
c.app_host = 'http://localhost:%d' %
|
220
|
+
c.app_host = 'http://localhost:%d' % app_server.port
|
233
221
|
c.browser = Capybara::Session.new(:selenium)
|
234
222
|
c.server_error_detection { |browser|
|
235
223
|
browser.has_css?('head title', :text => 'Internal Server Error')
|
@@ -238,34 +226,10 @@ and shut down a Rack application server. Just add the following to
|
|
238
226
|
|
239
227
|
World(Kookaburra::TestHelpers)
|
240
228
|
|
241
|
-
|
242
|
-
# `MyApplication` below should be replaced with the object that
|
243
|
-
# implements the Rack `#call` interface for your application. For a Rails
|
244
|
-
# app, this would be along the lines of `MyAppName::Application`.
|
245
|
-
# Runs the server process in a forked process, and get a handle on that
|
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.
|
251
|
-
@rack_server_pid = fork do
|
252
|
-
Capybara.server_port = APP_PORT
|
253
|
-
Capybara::Server.new(MyApplication).boot
|
254
|
-
|
255
|
-
# This ensures that this forked process keeps running, because the
|
256
|
-
# actual server is started in a thread by Capybara.
|
257
|
-
ThreadsWait.all_waits(Thread.list)
|
258
|
-
end
|
259
|
-
|
260
|
-
# Give the server a chance to start up in the forked process. You may
|
261
|
-
# need to adjust this depending on how long your application takes to
|
262
|
-
# start up.
|
263
|
-
sleep 1
|
229
|
+
app_server.boot
|
264
230
|
|
265
|
-
# After the tests run, kill the server process.
|
266
231
|
at_exit do
|
267
|
-
|
268
|
-
Process.wait
|
232
|
+
app_server.shutdown
|
269
233
|
end
|
270
234
|
|
271
235
|
## Defining Your Testing DSL ##
|
@@ -297,7 +261,7 @@ have the following scenario defined for an e-commerce application:
|
|
297
261
|
Feature: Purchase Items in Cart
|
298
262
|
|
299
263
|
Scenario: Using Existing Billing and Shipping Information
|
300
|
-
|
264
|
+
|
301
265
|
Given I have an existing account
|
302
266
|
And I have previously specified default payment options
|
303
267
|
And I have previously specified default shipping options
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.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 = "1.
|
8
|
+
s.version = "1.2.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 = "
|
12
|
+
s.date = "2013-03-16"
|
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 = [
|
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
|
|
39
39
|
"lib/kookaburra/given_driver.rb",
|
40
40
|
"lib/kookaburra/mental_model.rb",
|
41
41
|
"lib/kookaburra/mental_model_matcher.rb",
|
42
|
+
"lib/kookaburra/rack_app_server.rb",
|
42
43
|
"lib/kookaburra/test_helpers.rb",
|
43
44
|
"lib/kookaburra/ui_driver.rb",
|
44
45
|
"lib/kookaburra/ui_driver/has_ui_components.rb",
|
@@ -5,11 +5,11 @@ require 'kookaburra/exceptions'
|
|
5
5
|
class Kookaburra
|
6
6
|
# Communicate with a Web Services API
|
7
7
|
#
|
8
|
-
# You will create a subclass of
|
8
|
+
# You will create a subclass of {APIDriver} in your testing
|
9
9
|
# implementation to be used with you subclass of
|
10
|
-
#
|
10
|
+
# {Kookaburra::GivenDriver}. While the {GivenDriver} implements the
|
11
11
|
# "business domain" DSL for setting up your application state, the
|
12
|
-
#
|
12
|
+
# {APIDriver} maps discreet operations to your application's web
|
13
13
|
# service API and can (optionally) handle encoding input data and
|
14
14
|
# decoding response bodies to and from your preferred serialization
|
15
15
|
# format.
|
@@ -17,8 +17,8 @@ class Kookaburra
|
|
17
17
|
class << self
|
18
18
|
# Serializes input data
|
19
19
|
#
|
20
|
-
# If specified, any input data provided to
|
21
|
-
#
|
20
|
+
# If specified, any input data provided to {APIDriver#post},
|
21
|
+
# {APIDriver#put} or {APIDriver#request} will be processed through
|
22
22
|
# this function prior to being sent to the HTTP server.
|
23
23
|
#
|
24
24
|
# @yieldparam data [Object] The data parameter that was passed to
|
@@ -40,7 +40,7 @@ class Kookaburra
|
|
40
40
|
# Deserialize response body
|
41
41
|
#
|
42
42
|
# If specified, the response bodies of all requests made using
|
43
|
-
# this
|
43
|
+
# this {APIDriver} will be processed through this function prior
|
44
44
|
# to being returned.
|
45
45
|
#
|
46
46
|
# @yieldparam data [String] The response body sent by the HTTP
|
@@ -63,7 +63,7 @@ class Kookaburra
|
|
63
63
|
# Set custom HTTP headers
|
64
64
|
#
|
65
65
|
# Can be called multiple times to set HTTP headers that will be
|
66
|
-
# provided with every request made by the
|
66
|
+
# provided with every request made by the {APIDriver}.
|
67
67
|
#
|
68
68
|
# @param [String] name The name of the header, e.g. 'Content-Type'
|
69
69
|
# @param [String] value The value to which the header is set
|
@@ -87,7 +87,7 @@ class Kookaburra
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
# Create a new
|
90
|
+
# Create a new {APIDriver} instance
|
91
91
|
#
|
92
92
|
# @param [Kookaburra::Configuration] configuration
|
93
93
|
# @param [RestClient] http_client (optional) Generally only
|
@@ -146,7 +146,7 @@ class Kookaburra
|
|
146
146
|
#
|
147
147
|
# @param [Symbol] method The HTTP verb to use with the request
|
148
148
|
# @param [String] path The path to request. Will be joined with the
|
149
|
-
#
|
149
|
+
# {Kookaburra::Configuration#app_host} setting to build the
|
150
150
|
# URL unless a full URL is specified here.
|
151
151
|
# @param [Object] data The data to be posted in the request body. If
|
152
152
|
# an encoder was specified, this can be any type of object as
|
@@ -23,7 +23,7 @@ class Kookaburra
|
|
23
23
|
|
24
24
|
# This object is used by {Kookaburra::UIDriver::UIComponent} to interface
|
25
25
|
# with the web browser. Typically it should be an instance of
|
26
|
-
#
|
26
|
+
# {Capybara::Session}
|
27
27
|
#
|
28
28
|
# @attribute [rw] browser
|
29
29
|
# @raise [Kookaburra::ConfigurationError] if you try to read this attribute
|
@@ -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 via
|
8
|
+
# test data store via {#mental_model}.
|
9
9
|
#
|
10
10
|
# @abstract Subclass and implement your Given DSL.
|
11
11
|
#
|
@@ -32,7 +32,7 @@ class Kookaburra
|
|
32
32
|
true
|
33
33
|
end
|
34
34
|
|
35
|
-
# A MentalModel::Collection behaves much like a
|
35
|
+
# A MentalModel::Collection behaves much like a {Hash} object, with the
|
36
36
|
# exception that it will raise an {UnknownKeyError} rather than return nil
|
37
37
|
# if you attempt to access a key that has not been set. The exception
|
38
38
|
# attempts to provide a more helpful error message.
|
@@ -61,7 +61,7 @@ class Kookaburra
|
|
61
61
|
end
|
62
62
|
|
63
63
|
# Unlike a Hash, this object is only identical to another if the actual
|
64
|
-
#
|
64
|
+
# {#object_id} attributes match.
|
65
65
|
#
|
66
66
|
# @return [Boolean]
|
67
67
|
def ===(other)
|
@@ -71,8 +71,8 @@ class Kookaburra
|
|
71
71
|
# Returns a new hash that contains key/value pairs for the
|
72
72
|
# specified keys with values copied from this collection.
|
73
73
|
#
|
74
|
-
# @note This is semantically the same as
|
75
|
-
# by
|
74
|
+
# @note This is semantically the same as {Hash#slice} as provided
|
75
|
+
# by {ActiveSupport::CoreExt::Hash}
|
76
76
|
# @param [Object] keys The list of keys that should be copied from
|
77
77
|
# the collection
|
78
78
|
# @return [Hash] The resulting keys/values from the collection
|
@@ -86,8 +86,8 @@ class Kookaburra
|
|
86
86
|
# Returns a new hash that contains every key/value from this
|
87
87
|
# collection *except* for the specified keys
|
88
88
|
#
|
89
|
-
# @note This is semantically the same as
|
90
|
-
# by
|
89
|
+
# @note This is semantically the same as {Hash#except} as provided
|
90
|
+
# by {ActiveSupport::CoreExt::Hash}
|
91
91
|
# @param [Object] keys The list of keys that should *not* be
|
92
92
|
# copied from the collection
|
93
93
|
# @return [Hash] The resulting keys/values from the collection
|
@@ -99,8 +99,8 @@ class Kookaburra
|
|
99
99
|
# in a subcollection.
|
100
100
|
#
|
101
101
|
# Deleting a key/value pair from a collection on the MentalModel works just
|
102
|
-
# like
|
103
|
-
# a subcollection, accessible at
|
102
|
+
# like {Hash#delete} but with a side effect - deleted members are added to
|
103
|
+
# a subcollection, accessible at {#deleted}.
|
104
104
|
#
|
105
105
|
# @param key the key to delete from the collection
|
106
106
|
#
|
@@ -114,7 +114,7 @@ class Kookaburra
|
|
114
114
|
|
115
115
|
# Finds or initializes, and returns, the subcollection of deleted items
|
116
116
|
#
|
117
|
-
# Key/value pairs
|
117
|
+
# Key/value pairs {#delete}d from a collection on the MentalModel will be added
|
118
118
|
# to this subcollection.
|
119
119
|
#
|
120
120
|
# @return [Kookaburra::MentalModel::Collection] the deleted items subcollection
|
@@ -125,8 +125,8 @@ class Kookaburra
|
|
125
125
|
# Deletes key/value pairs from the collection for which the given block evaluates
|
126
126
|
# to true, and persists all deleted pairs in a subcollection.
|
127
127
|
#
|
128
|
-
# Works just like
|
129
|
-
# added to a subcollection, accessible at
|
128
|
+
# Works just like {Hash#delete_if} but with a side effect - deleted members are
|
129
|
+
# added to a subcollection, accessible at {#deleted}.
|
130
130
|
#
|
131
131
|
# @return [Hash] the key/value pairs still remaining after the deletion
|
132
132
|
def delete_if(&block)
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'thwait'
|
3
|
+
require 'find_a_port'
|
4
|
+
|
5
|
+
# Handles Starting/Stopping Rack Server for Tests
|
6
|
+
#
|
7
|
+
# {RackAppServer} is basically a wrapper around {Capybara::Server} that
|
8
|
+
# makes it a bit easier to use Kookaburra with a Rack application (such
|
9
|
+
# as Rails or Sinatra) when you want to run your tests locally against a
|
10
|
+
# server that is only running for the duration of the tests. You simply
|
11
|
+
# tell it how to get ahold of your Rack application (see {#initialize})
|
12
|
+
# and then call {#boot} before your tests run and {#shutdown} after your
|
13
|
+
# tests run.
|
14
|
+
#
|
15
|
+
# @example using RSpec
|
16
|
+
# # put this in something like `spec_helper.rb`
|
17
|
+
# app_server = Kookaburra::RackAppServer.new do
|
18
|
+
# # unless you are in JRuby, this stuff all runs in a new fork later
|
19
|
+
# # on
|
20
|
+
# ENV['RAILS_ENV'] = 'test'
|
21
|
+
# require File.expand_path(File.join('..', '..', 'config', 'environment'), __FILE__)
|
22
|
+
# MyAppName::Application
|
23
|
+
# end
|
24
|
+
# RSpec.configure do
|
25
|
+
# c.before(:all) do
|
26
|
+
# app_server.boot
|
27
|
+
# end
|
28
|
+
# c.after(:all) do
|
29
|
+
# app_server.shutdown
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
class Kookaburra::RackAppServer
|
33
|
+
attr_reader :port
|
34
|
+
|
35
|
+
# Sets up a new app server
|
36
|
+
#
|
37
|
+
# @param startup_timeout [Integer] The maximum number of seconds to
|
38
|
+
# wait for the app server to respond
|
39
|
+
# @yieldreturn [#call] block must return a valid Rack application
|
40
|
+
def initialize(startup_timeout=10, &rack_app_initializer)
|
41
|
+
self.startup_timeout = startup_timeout
|
42
|
+
self.rack_app_initializer = rack_app_initializer
|
43
|
+
self.port = FindAPort.available_port
|
44
|
+
end
|
45
|
+
|
46
|
+
# Start the application server
|
47
|
+
#
|
48
|
+
# This will launch the server on a (detected to be) available port. It
|
49
|
+
# will then monitor that port and only return once the app server is
|
50
|
+
# responding (or after the timeout period specified on {#initialize}).
|
51
|
+
def boot
|
52
|
+
if defined?(JRUBY_VERSION)
|
53
|
+
thread_app_server
|
54
|
+
else
|
55
|
+
fork_app_server
|
56
|
+
end
|
57
|
+
wait_for_app_to_respond
|
58
|
+
end
|
59
|
+
|
60
|
+
def shutdown
|
61
|
+
return if defined?(JRUBY_VERSION)
|
62
|
+
Process.kill(9, rack_server_pid)
|
63
|
+
Process.wait
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
attr_accessor :rack_app_initializer, :rack_server_pid, :startup_timeout
|
69
|
+
attr_writer :port
|
70
|
+
|
71
|
+
def thread_app_server
|
72
|
+
Thread.new { start_server }
|
73
|
+
end
|
74
|
+
|
75
|
+
def fork_app_server
|
76
|
+
self.rack_server_pid = fork do
|
77
|
+
start_server
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def start_server
|
82
|
+
app = rack_app_initializer.call
|
83
|
+
Capybara.server_port = port
|
84
|
+
Capybara::Server.new(app).boot
|
85
|
+
# This ensures that this forked process keeps running, because the
|
86
|
+
# actual server is started in a thread by Capybara.
|
87
|
+
ThreadsWait.all_waits(Thread.list)
|
88
|
+
end
|
89
|
+
|
90
|
+
def wait_for_app_to_respond
|
91
|
+
begin
|
92
|
+
Timeout.timeout(startup_timeout) do
|
93
|
+
next until running?
|
94
|
+
end
|
95
|
+
rescue Timeout::Error
|
96
|
+
raise "Application does not seem to be responding on port #{port}."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def running?
|
101
|
+
res = Net::HTTP.start('localhost', port) { |http| http.get('/__identify__') }
|
102
|
+
if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
|
103
|
+
true
|
104
|
+
else
|
105
|
+
false
|
106
|
+
end
|
107
|
+
rescue Errno::ECONNREFUSED, Errno::EBADF, Errno::ETIMEDOUT
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
@@ -3,10 +3,10 @@ class Kookaburra
|
|
3
3
|
# Classes that can contain reerences to {UIComponent} instances
|
4
4
|
# (i.e. {UIDriver} and {UIDriver::UIComponent} subclasses are
|
5
5
|
# extended by this module in order to set up those references.
|
6
|
-
#
|
6
|
+
# {UIDriver} and {UIComponent} are already extended, so you
|
7
7
|
# shouldn't need to do so elsewhere.
|
8
8
|
#
|
9
|
-
# Instances of the extending class must define a
|
9
|
+
# Instances of the extending class must define a {#configuration}
|
10
10
|
# method that returns the current Kookaburra::Configuration
|
11
11
|
module HasUIComponents
|
12
12
|
|
@@ -17,7 +17,7 @@ class Kookaburra
|
|
17
17
|
# @param [Class] component_class The {UIComponent} subclass that defines
|
18
18
|
# this component.
|
19
19
|
# @param [Hash] options An extra options hash that will be passed
|
20
|
-
# to the
|
20
|
+
# to the {UIComponent} on initialization.
|
21
21
|
def ui_component(component_name, component_class, options = {})
|
22
22
|
define_method(component_name) do
|
23
23
|
component_class.new(configuration, options)
|
@@ -2,7 +2,7 @@ class Kookaburra
|
|
2
2
|
class UIDriver
|
3
3
|
# Wraps a Kookaburra `browser` object and changes all method calls
|
4
4
|
# to that object so that they are scoped within the specified
|
5
|
-
#
|
5
|
+
# {#component_locator}.
|
6
6
|
class ScopedBrowser < BasicObject
|
7
7
|
|
8
8
|
# @param [Object] browser The browser driver object used by
|
@@ -11,7 +11,7 @@ class Kookaburra
|
|
11
11
|
# locator used to identify the HTML element within which all
|
12
12
|
# calls to this object should be scoped. (A Proc is used rather
|
13
13
|
# than a string, because it is possible that the object creating
|
14
|
-
# this
|
14
|
+
# this {ScopedBrowser} will not know the correct string at the
|
15
15
|
# time this object is created.)
|
16
16
|
def initialize(browser, component_locator)
|
17
17
|
@browser = browser
|
@@ -60,13 +60,13 @@ class Kookaburra
|
|
60
60
|
# end
|
61
61
|
# end
|
62
62
|
#
|
63
|
-
# Note that the "browser operation" methods such as
|
64
|
-
#
|
65
|
-
# automatically scoped to the component's DOM element.
|
63
|
+
# Note that the "browser operation" methods such as {#fill_in} and
|
64
|
+
# {#click_button} are delegated to a {ScopedBrowser} and are
|
65
|
+
# automatically scoped to the component's DOM element.
|
66
66
|
#
|
67
|
-
# @note Even though a
|
67
|
+
# @note Even though a {UIComponent} should respond to all of the
|
68
68
|
# methods on the browser (i.e. all of the Capybara DSL methods),
|
69
|
-
# for some reason call to
|
69
|
+
# for some reason call to {#select} get routed to {Kernel#select}.
|
70
70
|
# You can get around this by calling it as `self.select`. See
|
71
71
|
# https://gist.github.com/3192103 for an example of this behavior.
|
72
72
|
#
|
@@ -92,7 +92,7 @@ class Kookaburra
|
|
92
92
|
#
|
93
93
|
# @param [Kookaburra::Configuration] configuration
|
94
94
|
# @param [Hash] options An options hash that can be used to
|
95
|
-
# further configure a
|
95
|
+
# further configure a {UIComponent}'s behavior.
|
96
96
|
def initialize(configuration, options = {})
|
97
97
|
@configuration = configuration
|
98
98
|
@options = options
|
@@ -1,16 +1,12 @@
|
|
1
1
|
require 'kookaburra/test_helpers'
|
2
2
|
require 'kookaburra/api_driver'
|
3
|
+
require 'kookaburra/rack_app_server'
|
3
4
|
require 'capybara'
|
4
|
-
require 'thwait'
|
5
|
-
require 'find_a_port'
|
6
5
|
|
7
6
|
# These are required for the Rack app used for testing
|
8
7
|
require 'sinatra/base'
|
9
8
|
require 'json'
|
10
9
|
|
11
|
-
# The server port to which the application server will attach
|
12
|
-
APP_PORT = FindAPort.available_port
|
13
|
-
|
14
10
|
describe "testing a Rack application with Kookaburra" do
|
15
11
|
describe "with an HTML interface" do
|
16
12
|
describe "with a JSON API" do
|
@@ -319,37 +315,23 @@ describe "testing a Rack application with Kookaburra" do
|
|
319
315
|
end
|
320
316
|
end
|
321
317
|
|
318
|
+
app_server = Kookaburra::RackAppServer.new do
|
319
|
+
JsonApiApp.new
|
320
|
+
end
|
321
|
+
|
322
322
|
before(:all) do
|
323
|
-
|
324
|
-
Capybara.server_port = APP_PORT
|
325
|
-
Capybara::Server.new(JsonApiApp.new).boot
|
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
|
337
|
-
end
|
338
|
-
sleep 1 # Give the server a chance to start up.
|
323
|
+
app_server.boot
|
339
324
|
end
|
340
325
|
|
341
326
|
after(:all) do
|
342
|
-
|
343
|
-
Process.kill(9, @rack_server_pid)
|
344
|
-
Process.wait
|
345
|
-
end
|
327
|
+
app_server.shutdown
|
346
328
|
end
|
347
329
|
|
348
330
|
it "runs the tests against the app" do
|
349
331
|
Kookaburra.configure do |c|
|
350
332
|
c.ui_driver_class = MyUIDriver
|
351
333
|
c.given_driver_class = MyGivenDriver
|
352
|
-
c.app_host = 'http://127.0.0.1:%d' %
|
334
|
+
c.app_host = 'http://127.0.0.1:%d' % app_server.port
|
353
335
|
c.browser = Capybara::Session.new(:selenium)
|
354
336
|
c.server_error_detection do |browser|
|
355
337
|
browser.has_css?('head title', :text => 'Internal Server Error')
|
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: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2013-03-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rest-client
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- lib/kookaburra/given_driver.rb
|
220
220
|
- lib/kookaburra/mental_model.rb
|
221
221
|
- lib/kookaburra/mental_model_matcher.rb
|
222
|
+
- lib/kookaburra/rack_app_server.rb
|
222
223
|
- lib/kookaburra/test_helpers.rb
|
223
224
|
- lib/kookaburra/ui_driver.rb
|
224
225
|
- lib/kookaburra/ui_driver/has_ui_components.rb
|
@@ -254,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
254
255
|
version: '0'
|
255
256
|
segments:
|
256
257
|
- 0
|
257
|
-
hash: -
|
258
|
+
hash: -356630097343812047
|
258
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
260
|
none: false
|
260
261
|
requirements:
|