kookaburra 0.20.0 → 0.21.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 +19 -2
- data/VERSION +1 -1
- data/kookaburra.gemspec +2 -2
- data/lib/kookaburra/mental_model.rb +40 -0
- data/lib/kookaburra/null_browser.rb +1 -0
- data/lib/kookaburra/ui_driver.rb +36 -5
- data/lib/kookaburra/ui_driver/ui_component.rb +1 -0
- data/spec/kookaburra/mental_model_spec.rb +54 -0
- data/spec/kookaburra/ui_driver_spec.rb +18 -0
- metadata +4 -4
data/README.markdown
CHANGED
@@ -30,7 +30,7 @@ server could be running on the same machine, it doesn't need to be), and it is
|
|
30
30
|
the responsibility of the test implementation to ensure that the server is
|
31
31
|
running. Take a look at Kookaburra's own integration specs for one example of
|
32
32
|
how to achieve this for a [Rack-based] [Rack] application. (Note that you cannot
|
33
|
-
easily start the application server in a
|
33
|
+
easily start the application server in a separate thread. Because Ruby uses
|
34
34
|
green threads, the HTTP library used in the APIDriver will block while making
|
35
35
|
its requests and prevent the application server thread from responding.)
|
36
36
|
|
@@ -284,6 +284,13 @@ called on the object. The `MentalModel::Collection` object behaves like a `Hash`
|
|
284
284
|
for the most part, however it will raise a `Kookaburra::UnknownKeyError` if you
|
285
285
|
try to access a key that has not yet been assigned a value.
|
286
286
|
|
287
|
+
Deletions (via `#delete` or `#delete_if`) will actually remove the key/value
|
288
|
+
pair from the collection, but add it to a subcollection (available at
|
289
|
+
`MentalModel::Collection#deleted`). This reflects the fact that the user's
|
290
|
+
mental model of the dataset would also include any intentional exceptions -
|
291
|
+
the user will, for example, want to verify that an item they deleted does
|
292
|
+
not appear to be available in the system.
|
293
|
+
|
287
294
|
Here's a quick example of MentalModel behavor:
|
288
295
|
|
289
296
|
mental_model = MentalModel.new
|
@@ -292,10 +299,20 @@ Here's a quick example of MentalModel behavor:
|
|
292
299
|
|
293
300
|
mental_model.widgets[:widget_a]
|
294
301
|
#=> {'name' => 'Widget A'}
|
295
|
-
|
302
|
+
|
296
303
|
# this will raise a Kookaburra::UnknownKeyError
|
297
304
|
mental_model.widgets[:widget_b]
|
298
305
|
|
306
|
+
mental_model.widgets.delete(:widget_a)
|
307
|
+
#=> {'name' => 'Widget A'}
|
308
|
+
|
309
|
+
# this will now also raise a Kookaburra::UnknownKeyError...
|
310
|
+
mental_model.widgets[:widget_a]
|
311
|
+
|
312
|
+
# ...but the pair is now available here:
|
313
|
+
mental_model.widgets.deleted[:widget_a]
|
314
|
+
#=> {'name' => 'Widget A'}
|
315
|
+
|
299
316
|
#### Given Driver ####
|
300
317
|
|
301
318
|
The `Kookaburra::GivenDriver` is used to create a particular "preexisting" state
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.21.0
|
data/kookaburra.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "kookaburra"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.21.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-03-
|
12
|
+
s.date = "2012-03-25"
|
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 = [
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
require 'kookaburra/exceptions'
|
2
3
|
|
3
4
|
class Kookaburra
|
4
5
|
# Each instance of {Kookaburra} has its own instance of MentalModel. This object
|
@@ -81,6 +82,45 @@ class Kookaburra
|
|
81
82
|
self[key]
|
82
83
|
end
|
83
84
|
end
|
85
|
+
|
86
|
+
# Deletes a key/value pair from the collection, and persists the deleted pair
|
87
|
+
# in a subcollection.
|
88
|
+
#
|
89
|
+
# Deleting a key/value pair from a collection on the MentalModel works just
|
90
|
+
# like `Hash#delete` but with a side effect - deleted members are added to
|
91
|
+
# a subcollection, accessible at `#deleted`.
|
92
|
+
#
|
93
|
+
# @param key the key to delete from the collection
|
94
|
+
#
|
95
|
+
# @return the value of the deleted key/value pair
|
96
|
+
#
|
97
|
+
# @raise [Kookaburra::UnknownKeyError] if the specified key has not been set
|
98
|
+
def delete(key, &block)
|
99
|
+
self[key] # simple fetch to possibly trigger UnknownKeyError
|
100
|
+
deleted[key] = super
|
101
|
+
end
|
102
|
+
|
103
|
+
# Finds or initializes, and returns, the subcollection of deleted items
|
104
|
+
#
|
105
|
+
# Key/value pairs `#delete`d from a collection on the MentalModel will be added
|
106
|
+
# to this subcollection.
|
107
|
+
#
|
108
|
+
# @return [Kookaburra::MentalModel::Collection] the deleted items subcollection
|
109
|
+
def deleted
|
110
|
+
@deleted ||= self.class.new("deleted")
|
111
|
+
end
|
112
|
+
|
113
|
+
# Deletes key/value pairs from the collection for which the given block evaluates
|
114
|
+
# to true, and persists all deleted pairs in a subcollection.
|
115
|
+
#
|
116
|
+
# Works just like `Hash#delete_if` but with a side effect - deleted members are
|
117
|
+
# added to a subcollection, accessible at `#deleted`.
|
118
|
+
#
|
119
|
+
# @return [Hash] the key/value pairs still remaining after the deletion
|
120
|
+
def delete_if(&block)
|
121
|
+
move = lambda { |k,v| deleted[k] = v; true }
|
122
|
+
super { |k,v| block.call(k,v) && move.call(k,v) }
|
123
|
+
end
|
84
124
|
end
|
85
125
|
end
|
86
126
|
end
|
data/lib/kookaburra/ui_driver.rb
CHANGED
@@ -36,6 +36,25 @@ class Kookaburra
|
|
36
36
|
# end
|
37
37
|
# end
|
38
38
|
# end
|
39
|
+
#
|
40
|
+
# With larger applications, it may be beneficial to break down your business
|
41
|
+
# actions into multiple classes. The top-level {UIDriver} can have sub-drivers
|
42
|
+
# associated with it (and those can have sub-drivers, too; but let's not get
|
43
|
+
# carried away, eh?):
|
44
|
+
#
|
45
|
+
# class AccountManagementDriver < Kookaburra::UIDriver
|
46
|
+
# ui_component :account_list, AccountList
|
47
|
+
# # ...
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# class MyUIDriver < Kookaburra::UIDriver
|
51
|
+
# ui_driver :account_management, AccountManagementDriver
|
52
|
+
# # ...
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# In your test implementation, you can then do (among other things):
|
56
|
+
#
|
57
|
+
# ui.account_management.account_list.should be_visible
|
39
58
|
class UIDriver
|
40
59
|
extend DependencyAccessor
|
41
60
|
|
@@ -48,8 +67,19 @@ class Kookaburra
|
|
48
67
|
# this component.
|
49
68
|
def ui_component(component_name, component_class)
|
50
69
|
define_method(component_name) do
|
51
|
-
component_class.new(:browser
|
52
|
-
|
70
|
+
component_class.new(options.slice(:browser, :server_error_detection, :app_host))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Tells the UIDriver about sub-drivers (other {UIDriver} subclasses).
|
75
|
+
#
|
76
|
+
# @param [Symbol] driver_name Will create an instance method of this
|
77
|
+
# name that returns an instance of the driver_class
|
78
|
+
# @param [Class] driver_class The {UIDriver} subclass that defines
|
79
|
+
# this driver.
|
80
|
+
def ui_driver(driver_name, driver_class)
|
81
|
+
define_method(driver_name) do
|
82
|
+
driver_class.new(options.slice(:browser, :server_error_detection, :app_host, :mental_model))
|
53
83
|
end
|
54
84
|
end
|
55
85
|
end
|
@@ -66,14 +96,15 @@ class Kookaburra
|
|
66
96
|
# `:browser` object and should return `true` if the page indicates a server
|
67
97
|
# error has occured
|
68
98
|
def initialize(options = {})
|
69
|
-
@
|
70
|
-
@app_host = options[:app_host]
|
99
|
+
@options = options
|
71
100
|
@mental_model = options[:mental_model]
|
72
|
-
@server_error_detection = options[:server_error_detection]
|
73
101
|
end
|
74
102
|
|
75
103
|
protected
|
76
104
|
|
105
|
+
# Provides access to the options with which the object was initialized
|
106
|
+
attr_reader :options
|
107
|
+
|
77
108
|
# @attribute [r] mental_model
|
78
109
|
dependency_accessor :mental_model
|
79
110
|
end
|
@@ -23,6 +23,60 @@ describe Kookaburra::MentalModel do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
describe '#delete' do
|
27
|
+
it 'deletes and returns the item matching the specified key' do
|
28
|
+
collection[:baz] = 'baz'
|
29
|
+
collection.delete(:baz).should == 'baz'
|
30
|
+
lambda { collection[:baz] }.should raise_error(Kookaburra::UnknownKeyError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'persists the deleted key/value pair to the #deleted subcollection' do
|
34
|
+
collection[:baz] = 'baz'
|
35
|
+
collection.delete(:baz)
|
36
|
+
collection.deleted[:baz].should == 'baz'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises a Kookaburra::UnknownKeyError exception if trying to delete a missing key' do
|
40
|
+
lambda { collection.delete(:snerf) }.should \
|
41
|
+
raise_error(Kookaburra::UnknownKeyError, "Can't find mental_model.widgets[:snerf]. Did you forget to set it?")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#delete_if' do
|
46
|
+
before(:each) do
|
47
|
+
collection[:foo] = 'foo'
|
48
|
+
collection[:bar] = 'spoon'
|
49
|
+
collection[:baz] = 'baz'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'deletes all members of collection for whom given block evaluates to false' do
|
53
|
+
collection.delete_if { |k,v| k.to_s != v }
|
54
|
+
collection.keys.should =~ [:foo, :baz]
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'adds deleted members of collection to #deleted subcollection' do
|
58
|
+
collection.delete_if { |k,v| k.to_s != v }
|
59
|
+
collection.deleted.keys.should == [:bar]
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns hash of items not deleted' do
|
63
|
+
collection.delete_if { |k,v| k.to_s != v }.should == { :foo => 'foo', :baz => 'baz' }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#deleted' do
|
68
|
+
it 'generates a new subcollection if none exists' do
|
69
|
+
initialized_collection = collection
|
70
|
+
Kookaburra::MentalModel::Collection.should_receive(:new).with("deleted")
|
71
|
+
initialized_collection.deleted
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns the deleted subcollection if already initialized' do
|
75
|
+
deleted_collection = collection.deleted
|
76
|
+
collection.deleted.should === deleted_collection
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
26
80
|
it 'raises a Kookaburra::UnknownKeyError exception for #[] with a missing key' do
|
27
81
|
lambda { collection[:foo] }.should \
|
28
82
|
raise_error(Kookaburra::UnknownKeyError, "Can't find mental_model.widgets[:foo]. Did you forget to set it?")
|
@@ -20,6 +20,24 @@ describe Kookaburra::UIDriver do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
describe '.ui_driver' do
|
24
|
+
it 'adds an accessor method for the named driver that defaults to an instance of the specified class' do
|
25
|
+
foo_driver_class = mock(Class)
|
26
|
+
foo_driver_class.should_receive(:new) \
|
27
|
+
.with(:browser => :a_browser, :server_error_detection => :server_error_detection,
|
28
|
+
:app_host => :a_url, :mental_model => :a_mental_model) \
|
29
|
+
.and_return(:a_foo_driver)
|
30
|
+
|
31
|
+
ui_driver_class = Class.new(Kookaburra::UIDriver) do
|
32
|
+
ui_driver :foo, foo_driver_class
|
33
|
+
end
|
34
|
+
|
35
|
+
ui = ui_driver_class.new(:browser => :a_browser, :server_error_detection => :server_error_detection,
|
36
|
+
:app_host => :a_url, :mental_model => :a_mental_model)
|
37
|
+
ui.foo.should == :a_foo_driver
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
23
41
|
describe 'dependency accessors' do
|
24
42
|
let(:subject_class) { Kookaburra::UIDriver }
|
25
43
|
|
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: 75
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 21
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.21.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- John Wilger
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2012-03-
|
20
|
+
date: 2012-03-25 00:00:00 Z
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|