kookaburra 0.18.2 → 0.18.3
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/VERSION +1 -1
- data/kookaburra.gemspec +2 -2
- data/lib/kookaburra/api_driver.rb +5 -0
- data/spec/integration/test_a_rack_application_spec.rb +311 -0
- metadata +4 -4
- data/spec/kookaburra_integration_spec.rb +0 -348
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.18.
|
1
|
+
0.18.3
|
data/kookaburra.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "kookaburra"
|
8
|
-
s.version = "0.18.
|
8
|
+
s.version = "0.18.3"
|
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"]
|
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
|
|
41
41
|
"lib/kookaburra/ui_driver.rb",
|
42
42
|
"lib/kookaburra/ui_driver/ui_component.rb",
|
43
43
|
"lib/kookaburra/utils/active_record_shared_connection.rb",
|
44
|
+
"spec/integration/test_a_rack_application_spec.rb",
|
44
45
|
"spec/kookaburra/json_api_driver_spec.rb",
|
45
46
|
"spec/kookaburra/null_browser_spec.rb",
|
46
47
|
"spec/kookaburra/rack_driver_spec.rb",
|
@@ -48,7 +49,6 @@ Gem::Specification.new do |s|
|
|
48
49
|
"spec/kookaburra/test_helpers_spec.rb",
|
49
50
|
"spec/kookaburra/ui_driver/ui_component_spec.rb",
|
50
51
|
"spec/kookaburra/ui_driver_spec.rb",
|
51
|
-
"spec/kookaburra_integration_spec.rb",
|
52
52
|
"spec/kookaburra_spec.rb",
|
53
53
|
"spec/support/shared_examples/it_has_a_dependency_accessor.rb"
|
54
54
|
]
|
@@ -0,0 +1,311 @@
|
|
1
|
+
require 'kookaburra'
|
2
|
+
require 'capybara'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'active_support/hash_with_indifferent_access'
|
5
|
+
|
6
|
+
describe "testing a Rack application with Kookaburra" do
|
7
|
+
describe "with an HTML interface" do
|
8
|
+
describe "with a JSON API" do
|
9
|
+
require 'kookaburra/json_api_driver'
|
10
|
+
class MyAPIDriver < Kookaburra::JsonApiDriver
|
11
|
+
def create_user(user_data)
|
12
|
+
post '/users', user_data
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_widget(widget_data)
|
16
|
+
post '/widgets', widget_data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class MyGivenDriver < Kookaburra::GivenDriver
|
21
|
+
def a_user(name)
|
22
|
+
user = {'email' => 'bob@example.com', 'password' => '12345'}
|
23
|
+
result = api.create_user(user)
|
24
|
+
test_data.users[name] = result
|
25
|
+
end
|
26
|
+
|
27
|
+
def a_widget(name, attributes = {})
|
28
|
+
widget = {'name' => 'Foo'}.merge(attributes)
|
29
|
+
result = api.create_widget(widget)
|
30
|
+
test_data.widgets[name] = result
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class SignInScreen < Kookaburra::UIDriver::UIComponent
|
35
|
+
def component_path
|
36
|
+
'/session/new'
|
37
|
+
end
|
38
|
+
|
39
|
+
def component_locator
|
40
|
+
'#sign_in_screen'
|
41
|
+
end
|
42
|
+
|
43
|
+
def sign_in(user_data)
|
44
|
+
fill_in 'Email:', :with => user_data['email']
|
45
|
+
fill_in 'Password:', :with => user_data['password']
|
46
|
+
click_button 'Sign In'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class WidgetList < Kookaburra::UIDriver::UIComponent
|
51
|
+
def component_path
|
52
|
+
'/widgets'
|
53
|
+
end
|
54
|
+
|
55
|
+
def component_locator
|
56
|
+
'#widget_list'
|
57
|
+
end
|
58
|
+
|
59
|
+
def widgets
|
60
|
+
all('.widget_summary').map do |el|
|
61
|
+
extract_widget_data(el)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def last_widget_created
|
66
|
+
element = find('.last_widget.created')
|
67
|
+
extract_widget_data(element)
|
68
|
+
end
|
69
|
+
|
70
|
+
def choose_to_create_new_widget
|
71
|
+
click_on 'New Widget'
|
72
|
+
end
|
73
|
+
|
74
|
+
def choose_to_delete_widget(widget_data)
|
75
|
+
find("#delete_#{widget_data['id']}").click_button('Delete')
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def extract_widget_data(element)
|
81
|
+
{
|
82
|
+
'id' => element.find('.id').text,
|
83
|
+
'name' => element.find('.name').text
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class WidgetForm < Kookaburra::UIDriver::UIComponent
|
89
|
+
def component_locator
|
90
|
+
'#widget_form'
|
91
|
+
end
|
92
|
+
|
93
|
+
def submit(widget_data)
|
94
|
+
fill_in 'Name:', :with => widget_data['name']
|
95
|
+
click_on 'Save'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class MyUIDriver < Kookaburra::UIDriver
|
100
|
+
ui_component :sign_in_screen, SignInScreen
|
101
|
+
ui_component :widget_list, WidgetList
|
102
|
+
ui_component :widget_form, WidgetForm
|
103
|
+
|
104
|
+
def sign_in(name)
|
105
|
+
sign_in_screen.show
|
106
|
+
sign_in_screen.sign_in(test_data.users[name])
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_new_widget(name, attributes = {})
|
110
|
+
widget_list.show
|
111
|
+
widget_list.choose_to_create_new_widget
|
112
|
+
widget_form.submit('name' => 'My Widget')
|
113
|
+
test_data.widgets[name] = widget_list.last_widget_created
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete_widget(name)
|
117
|
+
widget_list.show
|
118
|
+
widget_list.choose_to_delete_widget(test_data.widgets[name])
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# This is the fixture Rack application against which the integration
|
123
|
+
# test will run. It uses class variables to persist data, because
|
124
|
+
# Sinatra will instantiate a new instance of TestRackApp for each
|
125
|
+
# request.
|
126
|
+
class TestRackApp < Sinatra::Base
|
127
|
+
enable :sessions
|
128
|
+
|
129
|
+
# we want error handling to behave as it would for a production
|
130
|
+
# deployment rather than development
|
131
|
+
set :raise_errors, false
|
132
|
+
set :show_exceptions, false
|
133
|
+
|
134
|
+
def parse_json_req_body
|
135
|
+
request.body.rewind
|
136
|
+
ActiveSupport::JSON.decode(request.body.read).symbolize_keys
|
137
|
+
end
|
138
|
+
|
139
|
+
post '/users' do
|
140
|
+
user_data = parse_json_req_body
|
141
|
+
@@users ||= {}
|
142
|
+
@@users[user_data[:email]] = user_data
|
143
|
+
status 201
|
144
|
+
headers 'Content-Type' => 'application/json'
|
145
|
+
body user_data.to_json
|
146
|
+
end
|
147
|
+
|
148
|
+
post '/session' do
|
149
|
+
user = @@users[params[:email]]
|
150
|
+
if user && user[:password] == params[:password]
|
151
|
+
session[:logged_in] = true
|
152
|
+
status 200
|
153
|
+
body 'You are logged in!'
|
154
|
+
else
|
155
|
+
session[:logged_in] = false
|
156
|
+
status 403
|
157
|
+
body 'Log in failed!'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
get '/session/new' do
|
162
|
+
body <<-EOF
|
163
|
+
<html>
|
164
|
+
<head>
|
165
|
+
<title>Sign In</title>
|
166
|
+
</head>
|
167
|
+
<body>
|
168
|
+
<div id="sign_in_screen">
|
169
|
+
<form action="/session" method="POST">
|
170
|
+
<label for="email">Email:</label>
|
171
|
+
<input id="email" name="email" type="text" />
|
172
|
+
|
173
|
+
<label for="password">Password:</label>
|
174
|
+
<input id="password" name="password" type="password" />
|
175
|
+
|
176
|
+
<input type="submit" value="Sign In" />
|
177
|
+
</form>
|
178
|
+
</div>
|
179
|
+
</body>
|
180
|
+
</html>
|
181
|
+
EOF
|
182
|
+
end
|
183
|
+
|
184
|
+
post '/widgets/:widget_id' do
|
185
|
+
@@widgets.delete_if do |w|
|
186
|
+
w[:id] == params['widget_id']
|
187
|
+
end
|
188
|
+
redirect to('/widgets')
|
189
|
+
end
|
190
|
+
|
191
|
+
get '/widgets/new' do
|
192
|
+
body <<-EOF
|
193
|
+
<html>
|
194
|
+
<head>
|
195
|
+
<title>New Widget</title>
|
196
|
+
</head>
|
197
|
+
<body>
|
198
|
+
<div id="widget_form">
|
199
|
+
<form action="/widgets" method="POST">
|
200
|
+
<label for="name">Name:</label>
|
201
|
+
<input id="name" name="name" type="text" />
|
202
|
+
|
203
|
+
<input type="submit" value="Save" />
|
204
|
+
</form>
|
205
|
+
</div>
|
206
|
+
</body>
|
207
|
+
</html>
|
208
|
+
EOF
|
209
|
+
end
|
210
|
+
|
211
|
+
post '/widgets' do
|
212
|
+
@@widgets ||= []
|
213
|
+
widget_data = if request.media_type == 'application/json'
|
214
|
+
parse_json_req_body
|
215
|
+
else
|
216
|
+
params.symbolize_keys.slice(:name)
|
217
|
+
end
|
218
|
+
widget_data[:id] = `uuidgen`.strip
|
219
|
+
@@widgets << widget_data
|
220
|
+
@@last_widget_created = widget_data
|
221
|
+
if request.accept? 'text/html'
|
222
|
+
redirect to('/widgets')
|
223
|
+
elsif request.accept? 'application/json'
|
224
|
+
status 201
|
225
|
+
headers 'Content-Type' => 'application/json'
|
226
|
+
body widget_data.to_json
|
227
|
+
else
|
228
|
+
redirect to('/widgets')
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
get '/widgets' do
|
233
|
+
raise "Not logged in!" unless session[:logged_in]
|
234
|
+
@@widgets ||= []
|
235
|
+
last_widget_created, @@last_widget_created = @@last_widget_created, nil
|
236
|
+
content = ''
|
237
|
+
content << <<-EOF
|
238
|
+
<html>
|
239
|
+
<head>
|
240
|
+
<title>Widgets</title>
|
241
|
+
</head>
|
242
|
+
<body>
|
243
|
+
<div id="widget_list">
|
244
|
+
EOF
|
245
|
+
if last_widget_created
|
246
|
+
content << <<-EOF
|
247
|
+
<div class="last_widget created">
|
248
|
+
<span class="id">#{last_widget_created[:id]}</span>
|
249
|
+
<span class="name">#{last_widget_created[:name]}</span>
|
250
|
+
</div>
|
251
|
+
EOF
|
252
|
+
end
|
253
|
+
content << <<-EOF
|
254
|
+
<ul>
|
255
|
+
EOF
|
256
|
+
@@widgets.each do |w|
|
257
|
+
content << <<-EOF
|
258
|
+
<li class="widget_summary">
|
259
|
+
<span class="id">#{w[:id]}</span>
|
260
|
+
<span class="name">#{w[:name]}</span>
|
261
|
+
<form id="delete_#{w[:id]}" action="/widgets/#{w[:id]}" method="POST">
|
262
|
+
<button type="submit" value="Delete" />
|
263
|
+
</form>
|
264
|
+
</li>
|
265
|
+
EOF
|
266
|
+
end
|
267
|
+
content << <<-EOF
|
268
|
+
</ul>
|
269
|
+
<a href="/widgets/new">New Widget</a>
|
270
|
+
</div>
|
271
|
+
</body>
|
272
|
+
</html>
|
273
|
+
EOF
|
274
|
+
body content
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
it "runs the tests against the app" do
|
280
|
+
my_app = TestRackApp.new
|
281
|
+
|
282
|
+
server_error_detection = lambda { |browser|
|
283
|
+
browser.has_css?('h1', :text => 'Internal Server Error')
|
284
|
+
}
|
285
|
+
|
286
|
+
k = Kookaburra.new({
|
287
|
+
:ui_driver_class => MyUIDriver,
|
288
|
+
:given_driver_class => MyGivenDriver,
|
289
|
+
:api_driver_class => MyAPIDriver,
|
290
|
+
:browser => Capybara::Session.new(:rack_test, my_app),
|
291
|
+
:rack_app => my_app,
|
292
|
+
:server_error_detection => server_error_detection
|
293
|
+
})
|
294
|
+
|
295
|
+
k.given.a_user(:bob)
|
296
|
+
k.given.a_widget(:widget_a)
|
297
|
+
k.given.a_widget(:widget_b, :name => 'Foo')
|
298
|
+
|
299
|
+
k.ui.sign_in(:bob)
|
300
|
+
k.ui.widget_list.show
|
301
|
+
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b)
|
302
|
+
|
303
|
+
k.ui.create_new_widget(:widget_c, :name => 'Bar')
|
304
|
+
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b, :widget_c)
|
305
|
+
|
306
|
+
k.ui.delete_widget(:widget_b)
|
307
|
+
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_c)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
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: 81
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 18
|
9
|
-
-
|
10
|
-
version: 0.18.
|
9
|
+
- 3
|
10
|
+
version: 0.18.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- John Wilger
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- lib/kookaburra/ui_driver.rb
|
224
224
|
- lib/kookaburra/ui_driver/ui_component.rb
|
225
225
|
- lib/kookaburra/utils/active_record_shared_connection.rb
|
226
|
+
- spec/integration/test_a_rack_application_spec.rb
|
226
227
|
- spec/kookaburra/json_api_driver_spec.rb
|
227
228
|
- spec/kookaburra/null_browser_spec.rb
|
228
229
|
- spec/kookaburra/rack_driver_spec.rb
|
@@ -230,7 +231,6 @@ files:
|
|
230
231
|
- spec/kookaburra/test_helpers_spec.rb
|
231
232
|
- spec/kookaburra/ui_driver/ui_component_spec.rb
|
232
233
|
- spec/kookaburra/ui_driver_spec.rb
|
233
|
-
- spec/kookaburra_integration_spec.rb
|
234
234
|
- spec/kookaburra_spec.rb
|
235
235
|
- spec/support/shared_examples/it_has_a_dependency_accessor.rb
|
236
236
|
homepage: http://github.com/projectdx/kookaburra
|
@@ -1,348 +0,0 @@
|
|
1
|
-
require 'kookaburra'
|
2
|
-
require 'capybara'
|
3
|
-
require 'sinatra/base'
|
4
|
-
require 'active_support/hash_with_indifferent_access'
|
5
|
-
|
6
|
-
describe 'Kookaburra Integration' do
|
7
|
-
describe "testing a Rack application" do
|
8
|
-
describe "with an HTML interface" do
|
9
|
-
describe "with a JSON API" do
|
10
|
-
require 'kookaburra/json_api_driver'
|
11
|
-
class MyAPIDriver < Kookaburra::JsonApiDriver
|
12
|
-
def create_user(user_data)
|
13
|
-
post '/users', user_data
|
14
|
-
end
|
15
|
-
|
16
|
-
def create_widget(widget_data)
|
17
|
-
post '/widgets', widget_data
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class MyGivenDriver < Kookaburra::GivenDriver
|
22
|
-
def a_user(name)
|
23
|
-
user = {'email' => 'bob@example.com', 'password' => '12345'}
|
24
|
-
result = api.create_user(user)
|
25
|
-
test_data.users[name] = result
|
26
|
-
end
|
27
|
-
|
28
|
-
def a_widget(name, attributes = {})
|
29
|
-
widget = {'name' => 'Foo'}.merge(attributes)
|
30
|
-
result = api.create_widget(widget)
|
31
|
-
test_data.widgets[name] = result
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class SignInScreen < Kookaburra::UIDriver::UIComponent
|
36
|
-
def component_path
|
37
|
-
'/session/new'
|
38
|
-
end
|
39
|
-
|
40
|
-
def component_locator
|
41
|
-
'#sign_in_screen'
|
42
|
-
end
|
43
|
-
|
44
|
-
def sign_in(user_data)
|
45
|
-
fill_in 'Email:', :with => user_data['email']
|
46
|
-
fill_in 'Password:', :with => user_data['password']
|
47
|
-
click_button 'Sign In'
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
class WidgetList < Kookaburra::UIDriver::UIComponent
|
52
|
-
def component_path
|
53
|
-
'/widgets'
|
54
|
-
end
|
55
|
-
|
56
|
-
def component_locator
|
57
|
-
'#widget_list'
|
58
|
-
end
|
59
|
-
|
60
|
-
def widgets
|
61
|
-
all('.widget_summary').map do |el|
|
62
|
-
extract_widget_data(el)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def last_widget_created
|
67
|
-
element = find('.last_widget.created')
|
68
|
-
extract_widget_data(element)
|
69
|
-
end
|
70
|
-
|
71
|
-
def choose_to_create_new_widget
|
72
|
-
click_on 'New Widget'
|
73
|
-
end
|
74
|
-
|
75
|
-
def choose_to_delete_widget(widget_data)
|
76
|
-
find("#delete_#{widget_data['id']}").click_button('Delete')
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
def extract_widget_data(element)
|
82
|
-
{
|
83
|
-
'id' => element.find('.id').text,
|
84
|
-
'name' => element.find('.name').text
|
85
|
-
}
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
class WidgetForm < Kookaburra::UIDriver::UIComponent
|
90
|
-
def component_locator
|
91
|
-
'#widget_form'
|
92
|
-
end
|
93
|
-
|
94
|
-
def submit(widget_data)
|
95
|
-
fill_in 'Name:', :with => widget_data['name']
|
96
|
-
click_on 'Save'
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
class MyUIDriver < Kookaburra::UIDriver
|
101
|
-
ui_component :sign_in_screen, SignInScreen
|
102
|
-
ui_component :widget_list, WidgetList
|
103
|
-
ui_component :widget_form, WidgetForm
|
104
|
-
|
105
|
-
def sign_in(name)
|
106
|
-
sign_in_screen.show
|
107
|
-
sign_in_screen.sign_in(test_data.users[name])
|
108
|
-
end
|
109
|
-
|
110
|
-
def create_new_widget(name, attributes = {})
|
111
|
-
widget_list.show
|
112
|
-
widget_list.choose_to_create_new_widget
|
113
|
-
widget_form.submit('name' => 'My Widget')
|
114
|
-
test_data.widgets[name] = widget_list.last_widget_created
|
115
|
-
end
|
116
|
-
|
117
|
-
def delete_widget(name)
|
118
|
-
widget_list.show
|
119
|
-
widget_list.choose_to_delete_widget(test_data.widgets[name])
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# This is the fixture Rack application against which the integration
|
124
|
-
# test will run. It uses class variables to persist data, because
|
125
|
-
# Sinatra will instantiate a new instance of TestRackApp for each
|
126
|
-
# request.
|
127
|
-
class TestRackApp < Sinatra::Base
|
128
|
-
enable :sessions
|
129
|
-
|
130
|
-
# we want error handling to behave as it would for a production
|
131
|
-
# deployment rather than development
|
132
|
-
set :raise_errors, false
|
133
|
-
set :show_exceptions, false
|
134
|
-
|
135
|
-
def parse_json_req_body
|
136
|
-
request.body.rewind
|
137
|
-
ActiveSupport::JSON.decode(request.body.read).symbolize_keys
|
138
|
-
end
|
139
|
-
|
140
|
-
post '/users' do
|
141
|
-
user_data = parse_json_req_body
|
142
|
-
@@users ||= {}
|
143
|
-
@@users[user_data[:email]] = user_data
|
144
|
-
status 201
|
145
|
-
headers 'Content-Type' => 'application/json'
|
146
|
-
body user_data.to_json
|
147
|
-
end
|
148
|
-
|
149
|
-
post '/session' do
|
150
|
-
user = @@users[params[:email]]
|
151
|
-
if user && user[:password] == params[:password]
|
152
|
-
session[:logged_in] = true
|
153
|
-
status 200
|
154
|
-
body 'You are logged in!'
|
155
|
-
else
|
156
|
-
session[:logged_in] = false
|
157
|
-
status 403
|
158
|
-
body 'Log in failed!'
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
get '/session/new' do
|
163
|
-
body <<-EOF
|
164
|
-
<html>
|
165
|
-
<head>
|
166
|
-
<title>Sign In</title>
|
167
|
-
</head>
|
168
|
-
<body>
|
169
|
-
<div id="sign_in_screen">
|
170
|
-
<form action="/session" method="POST">
|
171
|
-
<label for="email">Email:</label>
|
172
|
-
<input id="email" name="email" type="text" />
|
173
|
-
|
174
|
-
<label for="password">Password:</label>
|
175
|
-
<input id="password" name="password" type="password" />
|
176
|
-
|
177
|
-
<input type="submit" value="Sign In" />
|
178
|
-
</form>
|
179
|
-
</div>
|
180
|
-
</body>
|
181
|
-
</html>
|
182
|
-
EOF
|
183
|
-
end
|
184
|
-
|
185
|
-
post '/widgets/:widget_id' do
|
186
|
-
@@widgets.delete_if do |w|
|
187
|
-
w[:id] == params['widget_id']
|
188
|
-
end
|
189
|
-
redirect to('/widgets')
|
190
|
-
end
|
191
|
-
|
192
|
-
get '/widgets/new' do
|
193
|
-
body <<-EOF
|
194
|
-
<html>
|
195
|
-
<head>
|
196
|
-
<title>New Widget</title>
|
197
|
-
</head>
|
198
|
-
<body>
|
199
|
-
<div id="widget_form">
|
200
|
-
<form action="/widgets" method="POST">
|
201
|
-
<label for="name">Name:</label>
|
202
|
-
<input id="name" name="name" type="text" />
|
203
|
-
|
204
|
-
<input type="submit" value="Save" />
|
205
|
-
</form>
|
206
|
-
</div>
|
207
|
-
</body>
|
208
|
-
</html>
|
209
|
-
EOF
|
210
|
-
end
|
211
|
-
|
212
|
-
post '/widgets' do
|
213
|
-
@@widgets ||= []
|
214
|
-
widget_data = if request.media_type == 'application/json'
|
215
|
-
parse_json_req_body
|
216
|
-
else
|
217
|
-
params.symbolize_keys.slice(:name)
|
218
|
-
end
|
219
|
-
widget_data[:id] = `uuidgen`.strip
|
220
|
-
@@widgets << widget_data
|
221
|
-
@@last_widget_created = widget_data
|
222
|
-
if request.accept? 'text/html'
|
223
|
-
redirect to('/widgets')
|
224
|
-
elsif request.accept? 'application/json'
|
225
|
-
status 201
|
226
|
-
headers 'Content-Type' => 'application/json'
|
227
|
-
body widget_data.to_json
|
228
|
-
else
|
229
|
-
redirect to('/widgets')
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
get '/widgets' do
|
234
|
-
raise "Not logged in!" unless session[:logged_in]
|
235
|
-
@@widgets ||= []
|
236
|
-
last_widget_created, @@last_widget_created = @@last_widget_created, nil
|
237
|
-
content = ''
|
238
|
-
content << <<-EOF
|
239
|
-
<html>
|
240
|
-
<head>
|
241
|
-
<title>Widgets</title>
|
242
|
-
</head>
|
243
|
-
<body>
|
244
|
-
<div id="widget_list">
|
245
|
-
EOF
|
246
|
-
if last_widget_created
|
247
|
-
content << <<-EOF
|
248
|
-
<div class="last_widget created">
|
249
|
-
<span class="id">#{last_widget_created[:id]}</span>
|
250
|
-
<span class="name">#{last_widget_created[:name]}</span>
|
251
|
-
</div>
|
252
|
-
EOF
|
253
|
-
end
|
254
|
-
content << <<-EOF
|
255
|
-
<ul>
|
256
|
-
EOF
|
257
|
-
@@widgets.each do |w|
|
258
|
-
content << <<-EOF
|
259
|
-
<li class="widget_summary">
|
260
|
-
<span class="id">#{w[:id]}</span>
|
261
|
-
<span class="name">#{w[:name]}</span>
|
262
|
-
<form id="delete_#{w[:id]}" action="/widgets/#{w[:id]}" method="POST">
|
263
|
-
<button type="submit" value="Delete" />
|
264
|
-
</form>
|
265
|
-
</li>
|
266
|
-
EOF
|
267
|
-
end
|
268
|
-
content << <<-EOF
|
269
|
-
</ul>
|
270
|
-
<a href="/widgets/new">New Widget</a>
|
271
|
-
</div>
|
272
|
-
</body>
|
273
|
-
</html>
|
274
|
-
EOF
|
275
|
-
body content
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
|
280
|
-
it "runs the tests against the app" do
|
281
|
-
my_app = TestRackApp.new
|
282
|
-
|
283
|
-
server_error_detection = lambda { |browser|
|
284
|
-
browser.has_css?('h1', :text => 'Internal Server Error')
|
285
|
-
}
|
286
|
-
|
287
|
-
k = Kookaburra.new({
|
288
|
-
:ui_driver_class => MyUIDriver,
|
289
|
-
:given_driver_class => MyGivenDriver,
|
290
|
-
:api_driver_class => MyAPIDriver,
|
291
|
-
:browser => Capybara::Session.new(:rack_test, my_app),
|
292
|
-
:rack_app => my_app,
|
293
|
-
:server_error_detection => server_error_detection
|
294
|
-
})
|
295
|
-
|
296
|
-
k.given.a_user(:bob)
|
297
|
-
k.given.a_widget(:widget_a)
|
298
|
-
k.given.a_widget(:widget_b, :name => 'Foo')
|
299
|
-
|
300
|
-
k.ui.sign_in(:bob)
|
301
|
-
k.ui.widget_list.show
|
302
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b)
|
303
|
-
|
304
|
-
k.ui.create_new_widget(:widget_c, :name => 'Bar')
|
305
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b, :widget_c)
|
306
|
-
|
307
|
-
k.ui.delete_widget(:widget_b)
|
308
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_c)
|
309
|
-
end
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
describe "testing a Ruby API" do
|
315
|
-
class MyUIDriver < Kookaburra::UIDriver
|
316
|
-
end
|
317
|
-
|
318
|
-
class MyGivenDriver < Kookaburra::GivenDriver
|
319
|
-
end
|
320
|
-
|
321
|
-
class APIDriver < Kookaburra::APIDriver
|
322
|
-
end
|
323
|
-
|
324
|
-
it "runs the tests" do
|
325
|
-
k = Kookaburra.new({
|
326
|
-
:api_driver_class => MyAPIDriver,
|
327
|
-
:given_driver_class => MyGivenDriver,
|
328
|
-
:ui_driver_class => MyUIDriver,
|
329
|
-
})
|
330
|
-
|
331
|
-
pending 'WIP' do
|
332
|
-
k.given.a_user(:bob)
|
333
|
-
k.given.a_widget(:widget_a)
|
334
|
-
k.given.a_widget(:widget_b, :name => 'Foo')
|
335
|
-
|
336
|
-
k.ui.sign_in(:bob)
|
337
|
-
k.ui.widget_list.show
|
338
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b)
|
339
|
-
|
340
|
-
k.ui.create_new_widget(:widget_c, :name => 'Bar')
|
341
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_b, :widget_c)
|
342
|
-
|
343
|
-
k.ui.delete_widget(:widget_b)
|
344
|
-
k.ui.widget_list.widgets.should == k.get_data(:widgets).slice(:widget_a, :widget_c)
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|