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