capybara-ui 0.10.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.
- checksums.yaml +7 -0
- data/lib/capybara-ui.rb +31 -0
- data/lib/capybara-ui/assertions.rb +19 -0
- data/lib/capybara-ui/capybara.rb +7 -0
- data/lib/capybara-ui/checkpoint.rb +111 -0
- data/lib/capybara-ui/conversions.rb +31 -0
- data/lib/capybara-ui/cucumber.rb +5 -0
- data/lib/capybara-ui/dsl.rb +107 -0
- data/lib/capybara-ui/instance_conversions.rb +19 -0
- data/lib/capybara-ui/matchers.rb +28 -0
- data/lib/capybara-ui/optional_dependencies.rb +5 -0
- data/lib/capybara-ui/rails.rb +5 -0
- data/lib/capybara-ui/rails/role.rb +9 -0
- data/lib/capybara-ui/role.rb +19 -0
- data/lib/capybara-ui/text_table.rb +107 -0
- data/lib/capybara-ui/text_table/cell_text.rb +7 -0
- data/lib/capybara-ui/text_table/mapping.rb +40 -0
- data/lib/capybara-ui/text_table/transformations.rb +13 -0
- data/lib/capybara-ui/text_table/void_mapping.rb +8 -0
- data/lib/capybara-ui/version.rb +3 -0
- data/lib/capybara-ui/widgets.rb +61 -0
- data/lib/capybara-ui/widgets/check_box.rb +26 -0
- data/lib/capybara-ui/widgets/cucumber_methods.rb +73 -0
- data/lib/capybara-ui/widgets/document.rb +19 -0
- data/lib/capybara-ui/widgets/dsl.rb +47 -0
- data/lib/capybara-ui/widgets/field.rb +22 -0
- data/lib/capybara-ui/widgets/field_group.rb +329 -0
- data/lib/capybara-ui/widgets/form.rb +26 -0
- data/lib/capybara-ui/widgets/list.rb +200 -0
- data/lib/capybara-ui/widgets/list_item.rb +22 -0
- data/lib/capybara-ui/widgets/parts/container.rb +46 -0
- data/lib/capybara-ui/widgets/parts/struct.rb +117 -0
- data/lib/capybara-ui/widgets/radio_button.rb +62 -0
- data/lib/capybara-ui/widgets/select.rb +57 -0
- data/lib/capybara-ui/widgets/string_value.rb +43 -0
- data/lib/capybara-ui/widgets/table.rb +76 -0
- data/lib/capybara-ui/widgets/text_field.rb +27 -0
- data/lib/capybara-ui/widgets/widget.rb +392 -0
- data/lib/capybara-ui/widgets/widget/node_filter.rb +48 -0
- data/lib/capybara-ui/widgets/widget_class.rb +11 -0
- data/lib/capybara-ui/widgets/widget_name.rb +56 -0
- metadata +240 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module CapybaraUI
|
2
|
+
class Form < FieldGroup
|
3
|
+
root 'form'
|
4
|
+
|
5
|
+
action :submit, '[type = submit]'
|
6
|
+
|
7
|
+
# Submit form with +attributes+.
|
8
|
+
#
|
9
|
+
# @param attributes [Hash] the form fields and their values
|
10
|
+
#
|
11
|
+
# @return the current widget
|
12
|
+
def submit_with(attributes)
|
13
|
+
set attributes
|
14
|
+
submit
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_table
|
18
|
+
info = self.
|
19
|
+
class.
|
20
|
+
field_names.
|
21
|
+
each_with_object({}) { |e, a| a[e.to_s] = widget(e).to_cell }
|
22
|
+
|
23
|
+
[info]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module CapybaraUI
|
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 < CapybaraUI::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
|
+
# Note 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 < CapybaraUI::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 < CapybaraUI::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 < CapybaraUI::List
|
75
|
+
# root '#not-a-list-colors'
|
76
|
+
# item '.child'
|
77
|
+
# end
|
78
|
+
class List < Widget
|
79
|
+
include Enumerable
|
80
|
+
|
81
|
+
def_delegators :items, :each, :first, :last
|
82
|
+
|
83
|
+
root 'ul' unless filter?
|
84
|
+
|
85
|
+
class << self
|
86
|
+
# Configures the List item selector and class.
|
87
|
+
#
|
88
|
+
# === Usage
|
89
|
+
#
|
90
|
+
# Given the following HTML:
|
91
|
+
#
|
92
|
+
# <ul>
|
93
|
+
# <li>One</li>
|
94
|
+
# <li>Two</li>
|
95
|
+
# <li>Three</li>
|
96
|
+
# </ul>
|
97
|
+
#
|
98
|
+
# In its most basic form, allows you to configure the list item selector,
|
99
|
+
# using the default list item class (CapybaraUI::ListItem):
|
100
|
+
#
|
101
|
+
# class Numbers < CapybaraUI::List
|
102
|
+
# root 'ul'
|
103
|
+
# item 'li'
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# ==== Extending the list item class
|
107
|
+
#
|
108
|
+
# You can define the list item class for the current List:
|
109
|
+
#
|
110
|
+
# class Number < CapybaraUI::Widget
|
111
|
+
# # ...
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# class Numbers < CapybaraUI::List
|
115
|
+
# root 'ul'
|
116
|
+
# item 'li', Number
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# widget(:numbers).first.class < Number #=> true
|
120
|
+
#
|
121
|
+
# Alternatively, you can extend the list item type inline. This is useful
|
122
|
+
# when you want to add small extensions to the default list item class.
|
123
|
+
# The extensions will apply only to list items of the current List.
|
124
|
+
#
|
125
|
+
# class Numbers < CapybaraUI::List
|
126
|
+
# root 'ul'
|
127
|
+
#
|
128
|
+
# item 'li' do
|
129
|
+
# def upcase
|
130
|
+
# text.upcase
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# widget(:numbers).first.upcase #=> "ONE"
|
135
|
+
# end
|
136
|
+
def item(selector, type = ListItem, &block)
|
137
|
+
self.item_factory = WidgetClass.new(selector, type, &block)
|
138
|
+
end
|
139
|
+
|
140
|
+
attr_writer :item_factory
|
141
|
+
|
142
|
+
def item_factory
|
143
|
+
@item_factory ||= WidgetClass.new('li', ListItem)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def count
|
148
|
+
items.count
|
149
|
+
end
|
150
|
+
|
151
|
+
# TODO: Convert value to primitive data structures.
|
152
|
+
def empty?
|
153
|
+
items.empty?
|
154
|
+
end
|
155
|
+
|
156
|
+
def exclude?(element)
|
157
|
+
! include?(element)
|
158
|
+
end
|
159
|
+
|
160
|
+
def include?(element)
|
161
|
+
value.include?(element)
|
162
|
+
end
|
163
|
+
|
164
|
+
def length
|
165
|
+
items.length
|
166
|
+
end
|
167
|
+
|
168
|
+
def size
|
169
|
+
items.size
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_row
|
173
|
+
items.map(&:to_cell)
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_table
|
177
|
+
items.map(&:to_row)
|
178
|
+
end
|
179
|
+
|
180
|
+
def value
|
181
|
+
items.map(&:value)
|
182
|
+
end
|
183
|
+
|
184
|
+
protected
|
185
|
+
|
186
|
+
def_delegator 'self.class', :item_factory
|
187
|
+
|
188
|
+
def item_for(node)
|
189
|
+
item_factory.new(node)
|
190
|
+
end
|
191
|
+
|
192
|
+
def item_filter
|
193
|
+
item_factory.filter
|
194
|
+
end
|
195
|
+
|
196
|
+
def items
|
197
|
+
item_filter.nodes(self).map { |node| item_for(node) }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CapybaraUI
|
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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CapybaraUI
|
2
|
+
module WidgetParts
|
3
|
+
module Container
|
4
|
+
include CapybaraUI
|
5
|
+
|
6
|
+
def has_widget?(name, *args)
|
7
|
+
deprecate('has_widget? and its alias widget?', 'visible?')
|
8
|
+
widget_class(name).present_in?(self, *args)
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method :widget?, :has_widget?
|
12
|
+
|
13
|
+
def visible?(name, *args)
|
14
|
+
widget_class(name).present_in?(self, *args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def not_visible?(name, *args)
|
18
|
+
widget_class(name).not_present_in?(self, *args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def widget(name, *args)
|
22
|
+
first, rest = [*name, *args]
|
23
|
+
|
24
|
+
widget_class(first).find_in(self, *rest)
|
25
|
+
end
|
26
|
+
|
27
|
+
def widgets(name, *args)
|
28
|
+
first, rest = [*name, *args]
|
29
|
+
|
30
|
+
widget_class(first).find_all_in(self, *rest)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_writer :widget_lookup_scope
|
36
|
+
|
37
|
+
def widget_class(name)
|
38
|
+
WidgetName.new(name).to_class(widget_lookup_scope)
|
39
|
+
end
|
40
|
+
|
41
|
+
def widget_lookup_scope
|
42
|
+
@widget_lookup_scope || self.class
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module CapybaraUI
|
2
|
+
module WidgetParts
|
3
|
+
module Struct
|
4
|
+
def self.included(target)
|
5
|
+
target.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def attribute(name, selector, &block)
|
10
|
+
child = widget(name, selector, &block)
|
11
|
+
|
12
|
+
class_eval <<-WIDGET
|
13
|
+
def #{name}
|
14
|
+
widget(:#{name}).value
|
15
|
+
end
|
16
|
+
WIDGET
|
17
|
+
|
18
|
+
child
|
19
|
+
end
|
20
|
+
|
21
|
+
def boolean(name, selector, &block)
|
22
|
+
child = widget(name, selector, &block)
|
23
|
+
|
24
|
+
class_eval <<-WIDGET
|
25
|
+
def #{name}?
|
26
|
+
widget(:#{name}).value
|
27
|
+
end
|
28
|
+
WIDGET
|
29
|
+
|
30
|
+
child.class_eval <<-VALUE
|
31
|
+
def value
|
32
|
+
CapybaraUI::Conversions::Boolean(text)
|
33
|
+
end
|
34
|
+
VALUE
|
35
|
+
|
36
|
+
child
|
37
|
+
end
|
38
|
+
|
39
|
+
def date(name, selector, &block)
|
40
|
+
child = attribute(name, selector, &block)
|
41
|
+
|
42
|
+
child.class_eval <<-VALUE
|
43
|
+
def value
|
44
|
+
Date.parse(text)
|
45
|
+
end
|
46
|
+
VALUE
|
47
|
+
|
48
|
+
child
|
49
|
+
end
|
50
|
+
|
51
|
+
def float(name, selector, &block)
|
52
|
+
child = attribute(name, selector, &block)
|
53
|
+
|
54
|
+
child.class_eval <<-VALUE
|
55
|
+
def value
|
56
|
+
Float(text)
|
57
|
+
end
|
58
|
+
VALUE
|
59
|
+
|
60
|
+
child
|
61
|
+
end
|
62
|
+
|
63
|
+
def integer(name, selector, &block)
|
64
|
+
child = attribute(name, selector, &block)
|
65
|
+
|
66
|
+
child.class_eval <<-VALUE
|
67
|
+
def value
|
68
|
+
Integer(text)
|
69
|
+
end
|
70
|
+
VALUE
|
71
|
+
|
72
|
+
child
|
73
|
+
end
|
74
|
+
|
75
|
+
def list(name, selector, options = {}, &block)
|
76
|
+
child = widget(name, selector, CapybaraUI::List) do
|
77
|
+
item options[:item_selector], options[:item_class] || ListItem
|
78
|
+
end
|
79
|
+
|
80
|
+
class_eval <<-WIDGET
|
81
|
+
def #{name}
|
82
|
+
widget(:#{name}).value
|
83
|
+
end
|
84
|
+
WIDGET
|
85
|
+
|
86
|
+
child.class_eval(&block) if block_given?
|
87
|
+
|
88
|
+
child
|
89
|
+
end
|
90
|
+
|
91
|
+
def string(name, *args, &block)
|
92
|
+
child = attribute(name, *args, &block)
|
93
|
+
|
94
|
+
child.class_eval <<-VALUE
|
95
|
+
def value
|
96
|
+
text
|
97
|
+
end
|
98
|
+
VALUE
|
99
|
+
|
100
|
+
child
|
101
|
+
end
|
102
|
+
|
103
|
+
def time(name, *args, &block)
|
104
|
+
child = attribute(name, *args, &block)
|
105
|
+
|
106
|
+
child.class_eval <<-VALUE
|
107
|
+
def value
|
108
|
+
Time.parse(text)
|
109
|
+
end
|
110
|
+
VALUE
|
111
|
+
|
112
|
+
child
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module CapybaraUI
|
2
|
+
# A radio button.
|
3
|
+
class RadioButton < Field
|
4
|
+
widget :checked, -> {
|
5
|
+
case Capybara.current_driver
|
6
|
+
when :rack_test
|
7
|
+
['[checked]']
|
8
|
+
else
|
9
|
+
['input:checked']
|
10
|
+
end
|
11
|
+
}
|
12
|
+
widget :checked_label_by_value, -> (val) { [:xpath, ".//label[input[@type='radio' and @value='#{val}']]"] }
|
13
|
+
widget :checked_label_by_id, -> (id) { [:xpath, ".//label[@for='#{id}']"] }
|
14
|
+
widget :button_by_value, -> (val) { "[value='#{val}']" }
|
15
|
+
|
16
|
+
def self.root(selector)
|
17
|
+
super(["#{selector}"])
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String] The text of the checked button's label.
|
21
|
+
def get
|
22
|
+
if visible?(:checked_label_by_value, value)
|
23
|
+
widget(:checked_label_by_value, value).text
|
24
|
+
elsif visible?(:checked_label_by_id, id)
|
25
|
+
widget(:checked_label_by_id, id).text
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String] The value of the checked button.
|
32
|
+
def value
|
33
|
+
visible?(:checked) ? widget(:checked).root.value : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String] The id of the checked button.
|
37
|
+
def id
|
38
|
+
visible?(:checked) ? widget(:checked).id : nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# First attempts to choose the button by id or label text
|
42
|
+
# Then attempts to choose the button by value
|
43
|
+
def set(str)
|
44
|
+
root.choose(str)
|
45
|
+
rescue
|
46
|
+
begin
|
47
|
+
widget(:button_by_value, str).root.set(true)
|
48
|
+
rescue CapybaraUI::MissingWidget => e
|
49
|
+
raise InvalidRadioButton.new(e.message).
|
50
|
+
tap { |x| x.set_backtrace e.backtrace }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return the text of the checked button, or an empty string if
|
55
|
+
# no button is checked.
|
56
|
+
def_delegator :get, :to_s
|
57
|
+
|
58
|
+
def to_cell
|
59
|
+
get
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|