capybara-ui 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/lib/capybara-ui.rb +31 -0
  3. data/lib/capybara-ui/assertions.rb +19 -0
  4. data/lib/capybara-ui/capybara.rb +7 -0
  5. data/lib/capybara-ui/checkpoint.rb +111 -0
  6. data/lib/capybara-ui/conversions.rb +31 -0
  7. data/lib/capybara-ui/cucumber.rb +5 -0
  8. data/lib/capybara-ui/dsl.rb +107 -0
  9. data/lib/capybara-ui/instance_conversions.rb +19 -0
  10. data/lib/capybara-ui/matchers.rb +28 -0
  11. data/lib/capybara-ui/optional_dependencies.rb +5 -0
  12. data/lib/capybara-ui/rails.rb +5 -0
  13. data/lib/capybara-ui/rails/role.rb +9 -0
  14. data/lib/capybara-ui/role.rb +19 -0
  15. data/lib/capybara-ui/text_table.rb +107 -0
  16. data/lib/capybara-ui/text_table/cell_text.rb +7 -0
  17. data/lib/capybara-ui/text_table/mapping.rb +40 -0
  18. data/lib/capybara-ui/text_table/transformations.rb +13 -0
  19. data/lib/capybara-ui/text_table/void_mapping.rb +8 -0
  20. data/lib/capybara-ui/version.rb +3 -0
  21. data/lib/capybara-ui/widgets.rb +61 -0
  22. data/lib/capybara-ui/widgets/check_box.rb +26 -0
  23. data/lib/capybara-ui/widgets/cucumber_methods.rb +73 -0
  24. data/lib/capybara-ui/widgets/document.rb +19 -0
  25. data/lib/capybara-ui/widgets/dsl.rb +47 -0
  26. data/lib/capybara-ui/widgets/field.rb +22 -0
  27. data/lib/capybara-ui/widgets/field_group.rb +329 -0
  28. data/lib/capybara-ui/widgets/form.rb +26 -0
  29. data/lib/capybara-ui/widgets/list.rb +200 -0
  30. data/lib/capybara-ui/widgets/list_item.rb +22 -0
  31. data/lib/capybara-ui/widgets/parts/container.rb +46 -0
  32. data/lib/capybara-ui/widgets/parts/struct.rb +117 -0
  33. data/lib/capybara-ui/widgets/radio_button.rb +62 -0
  34. data/lib/capybara-ui/widgets/select.rb +57 -0
  35. data/lib/capybara-ui/widgets/string_value.rb +43 -0
  36. data/lib/capybara-ui/widgets/table.rb +76 -0
  37. data/lib/capybara-ui/widgets/text_field.rb +27 -0
  38. data/lib/capybara-ui/widgets/widget.rb +392 -0
  39. data/lib/capybara-ui/widgets/widget/node_filter.rb +48 -0
  40. data/lib/capybara-ui/widgets/widget_class.rb +11 -0
  41. data/lib/capybara-ui/widgets/widget_name.rb +56 -0
  42. 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