dill 0.4.4 → 0.5.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/lib/dill.rb +3 -0
- data/lib/dill/auto_table.rb +3 -3
- data/lib/dill/checkpoint.rb +19 -64
- data/lib/dill/dsl.rb +2 -2
- data/lib/dill/field_group.rb +3 -3
- data/lib/dill/list.rb +147 -20
- data/lib/dill/list_item.rb +22 -0
- data/lib/dill/version.rb +1 -1
- data/lib/dill/widget.rb +183 -33
- data/lib/dill/widget_checkpoint.rb +30 -0
- data/lib/dill/widget_class.rb +11 -0
- data/lib/dill/widget_container.rb +2 -2
- metadata +21 -2
data/lib/dill.rb
CHANGED
@@ -3,12 +3,15 @@ require 'nokogiri'
|
|
3
3
|
require 'capybara'
|
4
4
|
|
5
5
|
require 'dill/checkpoint'
|
6
|
+
require 'dill/widget_class'
|
7
|
+
require 'dill/widget_checkpoint'
|
6
8
|
require 'dill/widget_container'
|
7
9
|
require 'dill/conversions'
|
8
10
|
require 'dill/instance_conversions'
|
9
11
|
require 'dill/node_text'
|
10
12
|
require 'dill/widget_name'
|
11
13
|
require 'dill/widget'
|
14
|
+
require 'dill/list_item'
|
12
15
|
require 'dill/list'
|
13
16
|
require 'dill/base_table'
|
14
17
|
require 'dill/auto_table'
|
data/lib/dill/auto_table.rb
CHANGED
@@ -50,11 +50,11 @@ module Dill
|
|
50
50
|
|
51
51
|
class Row < Widget
|
52
52
|
def initialize(settings)
|
53
|
-
|
53
|
+
root = settings.delete(:root)
|
54
54
|
|
55
|
-
self.cell_selector =
|
55
|
+
self.cell_selector = settings.delete(:cell_selector)
|
56
56
|
|
57
|
-
super
|
57
|
+
super root
|
58
58
|
end
|
59
59
|
|
60
60
|
def values
|
data/lib/dill/checkpoint.rb
CHANGED
@@ -5,25 +5,15 @@ module Dill
|
|
5
5
|
# @see http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base#synchronize-instance_method,
|
6
6
|
# which inspired this class.
|
7
7
|
class Checkpoint
|
8
|
-
class ConditionNotMet <
|
8
|
+
class ConditionNotMet < StandardError; end
|
9
9
|
class TimeFrozen < StandardError; end
|
10
10
|
|
11
11
|
# @return the configured wait time, in seconds.
|
12
12
|
attr_reader :wait_time
|
13
13
|
|
14
|
-
#
|
15
|
-
def self.
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
# Executes +block+ repeatedly until it returns a "truthy" value or +timeout+
|
20
|
-
# expires.
|
21
|
-
#
|
22
|
-
# TODO: Expand documentation.
|
23
|
-
def self.wait_for(wait_time = Capybara.default_wait_time,
|
24
|
-
raise_errors = true,
|
25
|
-
&block)
|
26
|
-
new(wait_time).wait_for(raise_errors, &block)
|
14
|
+
# Shortcut for instance level wait_for.
|
15
|
+
def self.wait_for(wait_time = Capybara.default_wait_time, &block)
|
16
|
+
new(wait_time).wait_for(&block)
|
27
17
|
end
|
28
18
|
|
29
19
|
# Initializes a new Checkpoint.
|
@@ -34,47 +24,24 @@ module Dill
|
|
34
24
|
@wait_time = wait_time
|
35
25
|
end
|
36
26
|
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# Automatically rescues some exceptions ({Capybara::ElementNotFound}, and
|
40
|
-
# driver specific exceptions) until {wait_time} is exceeded. At that point
|
41
|
-
# it raises whatever exception was raised in the condition block, or
|
42
|
-
# {ConditionNotMet}, if no exception was raised inside the block. However,
|
43
|
-
# if +raise_errors+ is set to +false+, returns +false+ instead of
|
44
|
-
# propagating any of the automatically rescued exceptions.
|
45
|
-
#
|
46
|
-
# If an "unknown" exception is raised, it is propagated immediately, without
|
47
|
-
# waiting for {wait_time} to expire.
|
48
|
-
#
|
49
|
-
# If a driver that doesn't support waiting is used, any exception raised is
|
50
|
-
# immediately propagated.
|
27
|
+
# Executes +block+ repeatedly until it returns a "truthy" value or
|
28
|
+
# +wait_time+ expires.
|
51
29
|
#
|
52
|
-
#
|
53
|
-
#
|
30
|
+
# Swallows any StandardError or StandardError descendent until +wait_time+
|
31
|
+
# expires. If an exception is raised and the time has expired, that
|
32
|
+
# exception will be raised again.
|
54
33
|
#
|
55
|
-
#
|
56
|
-
#
|
34
|
+
# If the block does not return a "truthy" value until +wait_time+ expires,
|
35
|
+
# raises a Dill::Checkpoint::ConditionNotMet error.
|
57
36
|
#
|
58
|
-
#
|
59
|
-
|
60
|
-
# +rescue_errors+ is false.
|
61
|
-
def wait_for(raise_errors = true, &condition)
|
37
|
+
# Returns whatever value is returned by the block.
|
38
|
+
def wait_for(&condition)
|
62
39
|
start
|
63
40
|
|
64
41
|
begin
|
65
42
|
yield or raise ConditionNotMet
|
66
|
-
rescue *rescuable_errors
|
67
|
-
if
|
68
|
-
raise e if raise_errors
|
69
|
-
|
70
|
-
return false
|
71
|
-
end
|
72
|
-
|
73
|
-
if expired?
|
74
|
-
raise e if raise_errors
|
75
|
-
|
76
|
-
return false
|
77
|
-
end
|
43
|
+
rescue *rescuable_errors
|
44
|
+
raise if expired?
|
78
45
|
|
79
46
|
wait
|
80
47
|
|
@@ -84,34 +51,22 @@ module Dill
|
|
84
51
|
end
|
85
52
|
end
|
86
53
|
|
54
|
+
def rescuable_errors
|
55
|
+
StandardError
|
56
|
+
end
|
57
|
+
|
87
58
|
private
|
88
59
|
|
89
60
|
attr_reader :start_time
|
90
61
|
|
91
|
-
def driver
|
92
|
-
self.class.driver
|
93
|
-
end
|
94
|
-
|
95
|
-
def driver_errors
|
96
|
-
driver.invalid_element_errors
|
97
|
-
end
|
98
|
-
|
99
62
|
def expired?
|
100
63
|
remaining_time > wait_time
|
101
64
|
end
|
102
65
|
|
103
|
-
def immediate?
|
104
|
-
! driver.wait?
|
105
|
-
end
|
106
|
-
|
107
66
|
def remaining_time
|
108
67
|
Time.now - start_time
|
109
68
|
end
|
110
69
|
|
111
|
-
def rescuable_errors
|
112
|
-
@rescuable_errors ||= [Capybara::ElementNotFound, *driver_errors]
|
113
|
-
end
|
114
|
-
|
115
70
|
def start
|
116
71
|
@start_time = Time.now
|
117
72
|
end
|
data/lib/dill/dsl.rb
CHANGED
data/lib/dill/field_group.rb
CHANGED
@@ -244,12 +244,12 @@ module Dill
|
|
244
244
|
|
245
245
|
# A form field.
|
246
246
|
class Field < Widget
|
247
|
-
def self.find_in(parent
|
248
|
-
new(
|
247
|
+
def self.find_in(parent)
|
248
|
+
new(parent.find_field(*selector))
|
249
249
|
end
|
250
250
|
|
251
251
|
def self.present_in?(parent)
|
252
|
-
parent.has_field?(selector)
|
252
|
+
parent.has_field?(*selector)
|
253
253
|
end
|
254
254
|
|
255
255
|
# @return This field's value.
|
data/lib/dill/list.rb
CHANGED
@@ -1,47 +1,174 @@
|
|
1
1
|
module Dill
|
2
|
+
# Use a List when you want to treat repeating elements as a unit.
|
3
|
+
#
|
4
|
+
# === Usage
|
5
|
+
#
|
6
|
+
# Consider the following HTML:
|
7
|
+
#
|
8
|
+
# <ul id="colors">
|
9
|
+
# <li>Red <span class="pt">Vermelho</span></li>
|
10
|
+
# <li>Green <span class="pt">Verde</span></li>
|
11
|
+
# <li>Blue <span class="pt">Azul</span></li>
|
12
|
+
# </ul>
|
13
|
+
#
|
14
|
+
# You can then define the following widget:
|
15
|
+
#
|
16
|
+
# class Colors < Dill::List
|
17
|
+
# root '#colors'
|
18
|
+
# item 'li'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Now you'll be able to iterate over each item:
|
22
|
+
#
|
23
|
+
# # prints:
|
24
|
+
# # Red Vermelho
|
25
|
+
# # Green Verde
|
26
|
+
# # Blue Azul
|
27
|
+
# widget(:colors).each do |e|
|
28
|
+
# puts e
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# This is the same as doing the following in Capybara:
|
32
|
+
#
|
33
|
+
# all('#colors li').each do |e|
|
34
|
+
# puts e.text.strip
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# Not that, by default, the root selector of a List is +ul+ and the list
|
38
|
+
# item selector is +li+. So you could wrap the +<ul>+ above simply by using
|
39
|
+
# the following:
|
40
|
+
#
|
41
|
+
# class Colors < Dill::List
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# ==== Narrowing items
|
45
|
+
#
|
46
|
+
# You can define the root selector for your list items using the ::item macro:
|
47
|
+
#
|
48
|
+
# class PortugueseColors < Dill::List
|
49
|
+
# root '#colors
|
50
|
+
# item '.pt'
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# If you iterate over this list you get the following:
|
54
|
+
#
|
55
|
+
# # prints:
|
56
|
+
# # Vermelho
|
57
|
+
# # Verde
|
58
|
+
# # Azul
|
59
|
+
# widget(:portuguese_colors).each do |e|
|
60
|
+
# puts e
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# You can make a list out of any repeating elements, as long as you can define
|
64
|
+
# parent and child selectors.
|
65
|
+
#
|
66
|
+
# <div id="not-a-list-colors">
|
67
|
+
# <div class=".child">Red</div>
|
68
|
+
# <div class=".child">Green</div>
|
69
|
+
# <div class=".child">Blue</div>
|
70
|
+
# </div>
|
71
|
+
#
|
72
|
+
# You can define the following widget:
|
73
|
+
#
|
74
|
+
# class NotAListColors < Dill::List
|
75
|
+
# root '#not-a-list-colors'
|
76
|
+
# item '.child'
|
77
|
+
# end
|
2
78
|
class List < Widget
|
3
|
-
DEFAULT_TYPE = Widget
|
4
|
-
|
5
79
|
include Enumerable
|
6
80
|
|
7
81
|
def_delegators :items, :size, :include?, :each, :empty?, :first, :last
|
8
82
|
|
9
|
-
|
10
|
-
|
11
|
-
|
83
|
+
class << self
|
84
|
+
# Configures the List item selector and class.
|
85
|
+
#
|
86
|
+
# === Usage
|
87
|
+
#
|
88
|
+
# Given the following HTML:
|
89
|
+
#
|
90
|
+
# <ul>
|
91
|
+
# <li>One</li>
|
92
|
+
# <li>Two</li>
|
93
|
+
# <li>Three</li>
|
94
|
+
# </ul>
|
95
|
+
#
|
96
|
+
# In its most basic form, allows you to configure the list item selector,
|
97
|
+
# using the default list item class (Dill::ListItem):
|
98
|
+
#
|
99
|
+
# class Numbers < Dill::List
|
100
|
+
# root 'ul'
|
101
|
+
# item 'li'
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# ==== Extending the list item class
|
105
|
+
#
|
106
|
+
# You can define the list item class for the current List:
|
107
|
+
#
|
108
|
+
# class Number < Dill::Widget
|
109
|
+
# # ...
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# class Numbers < Dill::List
|
113
|
+
# root 'ul'
|
114
|
+
# item 'li', Number
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# widget(:numbers).first.class < Number #=> true
|
118
|
+
#
|
119
|
+
# Alternatively, you can extend the list item type inline. This is useful
|
120
|
+
# when you want to add small extensions to the default list item class.
|
121
|
+
# The extensions will apply only to list items of the current List.
|
122
|
+
#
|
123
|
+
# class Numbers < Dill::List
|
124
|
+
# root 'ul'
|
125
|
+
#
|
126
|
+
# item 'li' do
|
127
|
+
# def upcase
|
128
|
+
# text.upcase
|
129
|
+
# end
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# widget(:numbers).first.upcase #=> "ONE"
|
133
|
+
# end
|
134
|
+
def item(selector, type = ListItem, &block)
|
135
|
+
self.item_factory = WidgetClass.new(selector, type, &block)
|
12
136
|
end
|
13
137
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
138
|
+
attr_writer :item_factory
|
139
|
+
|
140
|
+
def item_factory
|
141
|
+
@item_factory ||= WidgetClass.new('li', ListItem)
|
142
|
+
end
|
143
|
+
|
144
|
+
def selector
|
145
|
+
super ||
|
146
|
+
begin
|
147
|
+
root 'ul'
|
148
|
+
|
149
|
+
super
|
150
|
+
end
|
20
151
|
end
|
21
152
|
end
|
22
153
|
|
23
154
|
def to_table
|
24
|
-
items.map
|
155
|
+
items.map(&:to_row)
|
25
156
|
end
|
26
157
|
|
27
158
|
protected
|
28
159
|
|
29
|
-
|
30
|
-
|
31
|
-
def item_factory
|
32
|
-
DEFAULT_TYPE
|
33
|
-
end
|
160
|
+
def_delegator 'self.class', :item_factory
|
34
161
|
|
35
162
|
def item_for(node)
|
36
|
-
item_factory.new(
|
163
|
+
item_factory.new(node)
|
37
164
|
end
|
38
165
|
|
39
166
|
def item_selector
|
40
|
-
|
167
|
+
item_factory.selector
|
41
168
|
end
|
42
169
|
|
43
170
|
def items
|
44
|
-
root.all(item_selector).map { |node| item_for(node) }
|
171
|
+
root.all(*item_selector).map { |node| item_for(node) }
|
45
172
|
end
|
46
173
|
end
|
47
174
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Dill
|
2
|
+
class ListItem < Widget
|
3
|
+
# Returns this ListItem's contents formatted as a row, for comparison with a
|
4
|
+
# Cucumber::Ast::Table. By default, it simply returns an array with a single
|
5
|
+
# element--the widget's text.
|
6
|
+
#
|
7
|
+
# In general, this method will be called by List#to_table.
|
8
|
+
#
|
9
|
+
# === Overriding
|
10
|
+
#
|
11
|
+
# Feel free to override this method to return whatever you need it to.
|
12
|
+
# Usually, if the default return value isn't what you want, you'll probably
|
13
|
+
# want to return a Hash where both keys and values are strings, so that you
|
14
|
+
# don't need to worry about column order when you pass the table to
|
15
|
+
# Cucumber::Ast::Table#diff!.
|
16
|
+
#
|
17
|
+
# See List#to_table for more information.
|
18
|
+
def to_row
|
19
|
+
[to_cell]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/dill/version.rb
CHANGED
data/lib/dill/widget.rb
CHANGED
@@ -86,7 +86,8 @@ module Dill
|
|
86
86
|
# root selector, if +type+ has one defined.
|
87
87
|
#
|
88
88
|
# @param name the child widget's name.
|
89
|
-
# @param selector the child widget's selector.
|
89
|
+
# @param selector the child widget's selector. You can pass either a
|
90
|
+
# String or, if you want to use a composite selector, an Array.
|
90
91
|
# @param type the child widget's parent class.
|
91
92
|
#
|
92
93
|
# @overload widget(name, type)
|
@@ -119,7 +120,7 @@ module Dill
|
|
119
120
|
unless type.selector
|
120
121
|
|
121
122
|
selector = type.selector
|
122
|
-
when String
|
123
|
+
when String, Array
|
123
124
|
arg_count = rest.size + 1
|
124
125
|
|
125
126
|
case arg_count
|
@@ -139,8 +140,7 @@ module Dill
|
|
139
140
|
raise ArgumentError, "unknown method signature: #{rest.inspect}"
|
140
141
|
end
|
141
142
|
|
142
|
-
child =
|
143
|
-
child.class_eval(&block) if block_given?
|
143
|
+
child = WidgetClass.new(selector, type, &block)
|
144
144
|
|
145
145
|
const_set(Dill::WidgetName.new(name).to_sym, child)
|
146
146
|
|
@@ -181,8 +181,8 @@ module Dill
|
|
181
181
|
# @return a new instance of the current widget class.
|
182
182
|
#
|
183
183
|
# @raise [Capybara::ElementNotFoundError] if the widget can't be found
|
184
|
-
def self.find_in(node
|
185
|
-
new(
|
184
|
+
def self.find_in(node)
|
185
|
+
new(node.find(*selector))
|
186
186
|
end
|
187
187
|
|
188
188
|
# Determines if an instance of this widget class exists in
|
@@ -192,50 +192,192 @@ module Dill
|
|
192
192
|
#
|
193
193
|
# @return +true+ if a widget instance is found, +false+ otherwise.
|
194
194
|
def self.present_in?(parent_node)
|
195
|
-
parent_node.has_selector?(selector)
|
195
|
+
parent_node.has_selector?(*selector)
|
196
196
|
end
|
197
197
|
|
198
198
|
# Sets this widget's default selector.
|
199
199
|
#
|
200
|
-
#
|
201
|
-
|
202
|
-
|
200
|
+
# You can pass more than one argument to it, or a single Array. Any valid
|
201
|
+
# Capybara selector accepted by Capybara::Node::Finders#find will work.
|
202
|
+
#
|
203
|
+
# === Examples
|
204
|
+
#
|
205
|
+
# Most of the time, your selectors will be Strings:
|
206
|
+
#
|
207
|
+
# class MyWidget < Dill::Widget
|
208
|
+
# root '.selector'
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
# This will match any element with a class of "selector". For example:
|
212
|
+
#
|
213
|
+
# <span class="selector">Pick me!</span>
|
214
|
+
#
|
215
|
+
# ==== Composite selectors
|
216
|
+
#
|
217
|
+
# If you're using CSS as the query language, it's useful to be able to use
|
218
|
+
# +text: 'Some text'+ to zero in on a specific node:
|
219
|
+
#
|
220
|
+
# class MySpecificWidget < Dill::Widget
|
221
|
+
# root '.selector', text: 'Pick me!'
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# This is especially useful, e.g., when you want to create a widget
|
225
|
+
# to match a specific error or notification:
|
226
|
+
#
|
227
|
+
# class NoFreeSpace < Dill::Widget
|
228
|
+
# root '.error', text: 'No free space left!'
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# So, given the following HTML:
|
232
|
+
#
|
233
|
+
# <body>
|
234
|
+
# <div class="error">No free space left!</div>
|
235
|
+
#
|
236
|
+
# <!-- ... -->
|
237
|
+
# </body>
|
238
|
+
#
|
239
|
+
# You can test for the error's present using the following code:
|
240
|
+
#
|
241
|
+
# document.has_widget?(:no_free_space) #=> true
|
242
|
+
#
|
243
|
+
# Note: When you want to match text, consider using +I18n.t+ instead of
|
244
|
+
# hard-coding the text, so that your tests don't break when the text changes.
|
245
|
+
#
|
246
|
+
# Finally, you may want to override the query language:
|
247
|
+
#
|
248
|
+
# class MyWidgetUsesXPath < Dill::Widget
|
249
|
+
# root :xpath, '//some/node'
|
250
|
+
# end
|
251
|
+
def self.root(*selector)
|
252
|
+
@selector = selector.flatten
|
203
253
|
end
|
204
254
|
|
205
|
-
#
|
255
|
+
# Returns the selector specified with +root+.
|
206
256
|
def self.selector
|
207
257
|
@selector
|
208
258
|
end
|
209
259
|
|
210
|
-
#
|
260
|
+
# Returns the root node (a Capybara::Node::Element) of the current widget.
|
211
261
|
attr_reader :root
|
212
262
|
|
213
|
-
|
263
|
+
def initialize(root)
|
264
|
+
self.root = root
|
265
|
+
end
|
266
|
+
|
267
|
+
# Returns +true+ if this widget's representation is less than +value+.
|
268
|
+
#
|
269
|
+
# Waits for the result to be +true+ for the time defined in
|
270
|
+
# `Capybara.default_wait_time`.
|
271
|
+
def <(value)
|
272
|
+
test { cast_to_type_of(value) < value }
|
273
|
+
end
|
214
274
|
|
215
|
-
|
216
|
-
|
275
|
+
# Returns +true+ if this widget's representation is less than or equal to
|
276
|
+
# +value+.
|
277
|
+
#
|
278
|
+
# Waits for the result to be +true+ for the time defined in
|
279
|
+
# `Capybara.default_wait_time`.
|
280
|
+
def <=(value)
|
281
|
+
test { cast_to_type_of(value) <= value }
|
282
|
+
end
|
283
|
+
|
284
|
+
# Returns +true+ if this widget's representation is greater than +value+.
|
285
|
+
#
|
286
|
+
# Waits for the result to be +true+ for the time defined in
|
287
|
+
# `Capybara.default_wait_time`.
|
288
|
+
def >(value)
|
289
|
+
test { cast_to_type_of(value) > value }
|
290
|
+
end
|
291
|
+
|
292
|
+
# Returns +true+ if this widget's representation is greater than or equal to
|
293
|
+
# +value+.
|
294
|
+
#
|
295
|
+
# Waits for the result to be +true+ for the time defined in
|
296
|
+
# `Capybara.default_wait_time`.
|
297
|
+
def >=(value)
|
298
|
+
test { cast_to_type_of(value) >= value }
|
217
299
|
end
|
218
300
|
|
219
301
|
# Compares the current widget with +value+, waiting for the comparison
|
220
302
|
# to return +true+.
|
221
303
|
def ==(value)
|
222
|
-
|
304
|
+
test { cast_to_type_of(value) == value }
|
223
305
|
end
|
224
306
|
|
225
307
|
# Calls +=~+ on this widget's text content.
|
226
308
|
def =~(regexp)
|
227
|
-
|
309
|
+
test { to_s =~ regexp }
|
228
310
|
end
|
229
311
|
|
230
312
|
# Calls +!~+ on this widget's text content.
|
231
313
|
def !~(regexp)
|
232
|
-
|
314
|
+
test { to_s !~ regexp }
|
233
315
|
end
|
234
316
|
|
235
317
|
# Compares the current widget with +value+, waiting for the comparison
|
236
318
|
# to return +false+.
|
237
319
|
def !=(value)
|
238
|
-
|
320
|
+
test { cast_to_type_of(value) != value }
|
321
|
+
end
|
322
|
+
|
323
|
+
# Clicks the current widget, or the child widget given by +name+.
|
324
|
+
#
|
325
|
+
# === Usage
|
326
|
+
#
|
327
|
+
# Given the following widget definition:
|
328
|
+
#
|
329
|
+
# class Container < Dill::Widget
|
330
|
+
# root '#container'
|
331
|
+
#
|
332
|
+
# widget :link, 'a'
|
333
|
+
# end
|
334
|
+
#
|
335
|
+
# Send +click+ with no arguments to trigger a +click+ event on +#container+.
|
336
|
+
#
|
337
|
+
# widget(:container).click
|
338
|
+
#
|
339
|
+
# This is the equivalent of doing the following using Capybara:
|
340
|
+
#
|
341
|
+
# find('#container').click
|
342
|
+
#
|
343
|
+
# Send +click :link+ to trigger a +click+ event on +a+:
|
344
|
+
#
|
345
|
+
# widget(:container).click :link
|
346
|
+
#
|
347
|
+
# This is the equivalent of doing the following using Capybara:
|
348
|
+
#
|
349
|
+
# find('#container a').click
|
350
|
+
def click(name = nil)
|
351
|
+
if name
|
352
|
+
widget(name).click
|
353
|
+
else
|
354
|
+
root.click
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# Compares this widget with the given +diffable+, as long as it responds to
|
359
|
+
# the same protocol as Cucumber::Ast::Table#diff!.
|
360
|
+
#
|
361
|
+
# Waits +wait_time+ seconds for the comparison to be successful, otherwise
|
362
|
+
# raises Cucumber::Ast::Table::Different on failure.
|
363
|
+
#
|
364
|
+
# This is especially useful when you're not sure if the widget is in the
|
365
|
+
# proper state to be compared with the table.
|
366
|
+
#
|
367
|
+
# === Example
|
368
|
+
#
|
369
|
+
# Then(/^some step that takes in a cucumber table$/) do |table|
|
370
|
+
# widget(:my_widget).diff table
|
371
|
+
# end
|
372
|
+
def diff(diffable, wait_time = Capybara.default_wait_time)
|
373
|
+
# #diff! raises an exception if the comparison fails, or returns nil if it
|
374
|
+
# doesn't. We don't need to worry about failure, because that will be
|
375
|
+
# propagated, but we need to return +true+ when it succeeds, to end the
|
376
|
+
# comparison.
|
377
|
+
#
|
378
|
+
# We use WidgetCheckpoint instead of #test because we want the
|
379
|
+
# succeed-or-raise behavior.
|
380
|
+
WidgetCheckpoint.wait_for(wait_time) { diffable.diff!(to_table) || true }
|
239
381
|
end
|
240
382
|
|
241
383
|
# Determines if the widget underlying an action exists.
|
@@ -265,8 +407,6 @@ module Dill
|
|
265
407
|
end
|
266
408
|
end
|
267
409
|
|
268
|
-
class Reload < Capybara::ElementNotFound; end
|
269
|
-
|
270
410
|
# Reloads the widget, waiting for its contents to change (by default),
|
271
411
|
# or until +wait_time+ expires.
|
272
412
|
#
|
@@ -289,13 +429,13 @@ module Dill
|
|
289
429
|
# @return the current widget
|
290
430
|
#
|
291
431
|
# @see Checkpoint
|
292
|
-
def reload(wait_time = Capybara.default_wait_time, &
|
432
|
+
def reload(wait_time = Capybara.default_wait_time, &condition)
|
293
433
|
unless test
|
294
434
|
old_root = root
|
295
435
|
test = ->{ old_root != root }
|
296
436
|
end
|
297
437
|
|
298
|
-
|
438
|
+
test wait_time, &condition
|
299
439
|
|
300
440
|
begin
|
301
441
|
root.inspect
|
@@ -317,7 +457,23 @@ module Dill
|
|
317
457
|
#
|
318
458
|
# @return [MatchData] the match data from running +match+ on the text.
|
319
459
|
def match(pattern, position = 0, &block)
|
320
|
-
|
460
|
+
test { to_s.match(pattern, position, &block) }
|
461
|
+
end
|
462
|
+
|
463
|
+
def text
|
464
|
+
NodeText.new(root)
|
465
|
+
end
|
466
|
+
|
467
|
+
# Converts this widget into a string representation suitable to be displayed
|
468
|
+
# in a Cucumber table cell. By default calls #text.
|
469
|
+
#
|
470
|
+
# This method will be called by methods that build tables or rows (usually
|
471
|
+
# #to_table or #to_row) so, in general, you won't call it directly, but feel
|
472
|
+
# free to override it when needed.
|
473
|
+
#
|
474
|
+
# Returns a String.
|
475
|
+
def to_cell
|
476
|
+
to_s
|
321
477
|
end
|
322
478
|
|
323
479
|
def to_i
|
@@ -328,9 +484,7 @@ module Dill
|
|
328
484
|
to_s.to_f
|
329
485
|
end
|
330
486
|
|
331
|
-
|
332
|
-
node_text(root)
|
333
|
-
end
|
487
|
+
alias_method :to_s, :text
|
334
488
|
|
335
489
|
protected
|
336
490
|
|
@@ -347,16 +501,12 @@ module Dill
|
|
347
501
|
end
|
348
502
|
end
|
349
503
|
|
350
|
-
def node_text(node)
|
351
|
-
NodeText.new(node)
|
352
|
-
end
|
353
|
-
|
354
504
|
private
|
355
505
|
|
356
506
|
attr_writer :root
|
357
507
|
|
358
|
-
def
|
359
|
-
|
508
|
+
def test(wait_time = Capybara.default_wait_time, &block)
|
509
|
+
WidgetCheckpoint.wait_for(wait_time, &block) rescue nil
|
360
510
|
end
|
361
511
|
|
362
512
|
def page
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Dill
|
2
|
+
# A Checkpoint that bypasses the standard wait time if the current
|
3
|
+
# Capybara driver doesn't support waiting.
|
4
|
+
class WidgetCheckpoint < Checkpoint
|
5
|
+
# Returns the Capybara driver in use.
|
6
|
+
def driver
|
7
|
+
Capybara.current_session.driver
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
if immediate?
|
12
|
+
super 0
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def rescuable_errors
|
21
|
+
@rescuable_errors ||= Array(super) + driver.invalid_element_errors
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def immediate?
|
27
|
+
! driver.wait?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: dill
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.5.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- David Leal
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -107,6 +107,22 @@ dependencies:
|
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: 1.3.0
|
109
109
|
none: false
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ~>
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 1.3.0
|
116
|
+
none: false
|
117
|
+
name: cucumber
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.3.0
|
125
|
+
none: false
|
110
126
|
description: See https://github.com/mojotech/dill/README.md
|
111
127
|
email:
|
112
128
|
- dleal@mojotech.com
|
@@ -126,6 +142,7 @@ files:
|
|
126
142
|
- lib/dill/form.rb
|
127
143
|
- lib/dill/instance_conversions.rb
|
128
144
|
- lib/dill/list.rb
|
145
|
+
- lib/dill/list_item.rb
|
129
146
|
- lib/dill/node_text.rb
|
130
147
|
- lib/dill/table.rb
|
131
148
|
- lib/dill/text_table.rb
|
@@ -135,6 +152,8 @@ files:
|
|
135
152
|
- lib/dill/text_table/void_mapping.rb
|
136
153
|
- lib/dill/version.rb
|
137
154
|
- lib/dill/widget.rb
|
155
|
+
- lib/dill/widget_checkpoint.rb
|
156
|
+
- lib/dill/widget_class.rb
|
138
157
|
- lib/dill/widget_container.rb
|
139
158
|
- lib/dill/widget_name.rb
|
140
159
|
homepage: https://github.com/mojotech/dill
|