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,9 @@
1
+ module Capybara
2
+ module UI
3
+ class TextTable
4
+ class CellText < String
5
+ include InstanceConversions
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module Capybara
2
+ module UI
3
+ class TextTable
4
+ class Mapping
5
+ def initialize(settings = {})
6
+ self.key = settings[:key]
7
+ self.value_transformer = transformer(settings[:value_transformer], :pass)
8
+ self.key_transformer = transformer(settings[:key_transformer], :keyword)
9
+ end
10
+
11
+ def set(instance, row, key, value)
12
+ row[transform_key(instance, key)] = transform_value(instance, value)
13
+ end
14
+
15
+ private
16
+
17
+ attr_accessor :key, :value_transformer, :key_transformer
18
+
19
+ def transform_key(_, k)
20
+ key || key_transformer.(k)
21
+ end
22
+
23
+ def transform_value(instance, value)
24
+ instance.instance_exec(value, &value_transformer)
25
+ end
26
+
27
+ def transformer(set, fallback)
28
+ case set
29
+ when Symbol
30
+ Transformations.send(set)
31
+ when Proc
32
+ set
33
+ when nil
34
+ Transformations.send(fallback)
35
+ else
36
+ raise ArgumentError, "can't convert #{set.inspect} to transformer"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Capybara
2
+ module UI
3
+ class TextTable
4
+ module Transformations
5
+ def self.keyword
6
+ ->(val) { val.squeeze(' ').strip.gsub(' ', '_').sub(/\?$/, '').to_sym }
7
+ end
8
+
9
+ def self.pass
10
+ ->(val) { val }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module Capybara
2
+ module UI
3
+ class TextTable
4
+ class VoidMapping
5
+ def set(*)
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Capybara
2
+ module UI
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,63 @@
1
+ # This file describes the organization of the major Widget API components.
2
+ #
3
+ # === Parts
4
+ #
5
+ # Widget parts encapsulate the set of behaviours that constitute a widget.
6
+ module Capybara
7
+ module UI
8
+ module Constructors
9
+ def Widget(*selector, &block)
10
+ if block_given?
11
+ WidgetClass.new(selector.flatten) do
12
+ define_method :value do
13
+ block.call(text)
14
+ end
15
+ end
16
+ else
17
+ WidgetClass.new(selector.flatten)
18
+ end
19
+ end
20
+
21
+ alias_method :String, :Widget
22
+
23
+ def Integer(*selector)
24
+ Widget(selector) { |text| Kernel::Integer(text) }
25
+ end
26
+
27
+ require 'bigdecimal'
28
+
29
+ def Decimal(*selector)
30
+ Widget(selector) { |text|
31
+ # ensure we can convert to float first
32
+ Float(text) && BigDecimal.new(text)
33
+ }
34
+ end
35
+ end
36
+
37
+ extend Constructors
38
+ end
39
+ end
40
+
41
+ module Capybara::UI::WidgetParts; end
42
+
43
+ require 'capybara/ui/widgets/parts/struct'
44
+ require 'capybara/ui/widgets/parts/container'
45
+
46
+ require 'capybara/ui/widgets/cucumber_methods'
47
+ require 'capybara/ui/widgets/dsl'
48
+ require 'capybara/ui/widgets/widget_class'
49
+ require 'capybara/ui/widgets/widget_name'
50
+ require 'capybara/ui/widgets/widget'
51
+ require 'capybara/ui/widgets/widget/node_filter'
52
+ require 'capybara/ui/widgets/list_item'
53
+ require 'capybara/ui/widgets/list'
54
+ require 'capybara/ui/widgets/field'
55
+ require 'capybara/ui/widgets/check_box'
56
+ require 'capybara/ui/widgets/radio_button'
57
+ require 'capybara/ui/widgets/select'
58
+ require 'capybara/ui/widgets/text_field'
59
+ require 'capybara/ui/widgets/field_group'
60
+ require 'capybara/ui/widgets/form'
61
+ require 'capybara/ui/widgets/document'
62
+ require 'capybara/ui/widgets/table'
63
+ require 'capybara/ui/widgets/string_value'
@@ -0,0 +1,28 @@
1
+ module Capybara
2
+ module UI
3
+ # A check box.
4
+ class CheckBox < Field
5
+ # @!method set(value)
6
+ # Checks or unchecks the current checkbox.
7
+ #
8
+ # @param value [Boolean] +true+ to check the checkbox, +false+
9
+ # otherwise.
10
+ def_delegator :root, :set
11
+
12
+ # @return [Boolean] +true+ if the checkbox is checked, +false+
13
+ # otherwise.
14
+ def get
15
+ !! root.checked?
16
+ end
17
+
18
+ def to_cell
19
+ to_s
20
+ end
21
+
22
+ # @return +"yes"+ if the checkbox is checked, +"no"+ otherwise.
23
+ def to_s
24
+ get ? 'yes' : 'no'
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,75 @@
1
+ module Capybara
2
+ module UI
3
+ module CucumberMethods
4
+ begin
5
+ require 'cucumber/ast/table'
6
+
7
+ # Compares this widget with the given Cucumber +table+.
8
+ #
9
+ # === Example
10
+ #
11
+ # Then(/^some step that takes in a cucumber table$/) do |table|
12
+ # widget(:my_widget).diff table
13
+ # end
14
+ #
15
+ # Pass +ignore_case: true+, for a case-insensitive table match
16
+ #
17
+ # === Example
18
+ #
19
+ # Then(/^some step that takes in a cucumber table$/) do |table|
20
+ # widget(:my_widget).diff table, ignore_case: true
21
+ # end
22
+ #
23
+ def diff(table, wait_time = Capybara.default_max_wait_time, ignore_case: false)
24
+ to_table = self.to_table
25
+
26
+ if ignore_case == true
27
+ table = downcase_table(table)
28
+ to_table = downcase_array(to_table)
29
+ end
30
+
31
+ table.diff!(to_table) || true
32
+ end
33
+
34
+ private
35
+
36
+ def downcase_table(table)
37
+ new_cucumber_table downcase_array(table.raw)
38
+ end
39
+
40
+ def downcase_array(array)
41
+ array.map do |item|
42
+ case item
43
+ when String
44
+ item.downcase
45
+ when Array
46
+ downcase_array(item)
47
+ when Hash
48
+ downcase_hash(item)
49
+ end
50
+ end
51
+ end
52
+
53
+ def downcase_hash(hash)
54
+ hash.each do |k, v|
55
+ case v
56
+ when String
57
+ hash[k] = v.downcase
58
+ when Array
59
+ downcase_array(v)
60
+ when Hash
61
+ downcase_hash(v)
62
+ end
63
+ end
64
+ end
65
+
66
+ def new_cucumber_table(table)
67
+ Cucumber::Ast::Table.new(table)
68
+ end
69
+
70
+ rescue LoadError
71
+ # *crickets*
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,21 @@
1
+ module Capybara
2
+ module UI
3
+ class Document
4
+ include WidgetParts::Container
5
+
6
+ def initialize(widget_lookup_scope)
7
+ self.widget_lookup_scope = widget_lookup_scope or raise 'No scope given'
8
+ end
9
+
10
+ def root
11
+ Capybara.current_session
12
+ end
13
+
14
+ def body
15
+ xml = Nokogiri::HTML(Capybara.page.body).to_xml
16
+
17
+ Nokogiri::XML(xml, &:noblanks).to_xhtml
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module Capybara
2
+ module UI
3
+ module Widgets
4
+ module DSL
5
+ # Declares a new form widget.
6
+ #
7
+ # See features/role.feature.
8
+ def form(name, *rest, &block)
9
+ widget name, *rest, Capybara::UI::Form, &block
10
+ end
11
+
12
+ # Declares a new list widget.
13
+ #
14
+ # See features/roles/list.feature.
15
+ def list(name, *rest, &block)
16
+ widget name, *rest, Capybara::UI::List, &block
17
+ end
18
+
19
+ # Declares a new child widget.
20
+ #
21
+ # See https://github.com/mojotech/capybara-ui/blob/master/features/roles/widget.feature
22
+ def widget(name, selector_or_parent, parent = Widget, &block)
23
+ raise ArgumentError, "`#{name}' is a reserved name" \
24
+ if WidgetParts::Container.instance_methods.include?(name.to_sym)
25
+
26
+ case selector_or_parent
27
+ when String, Array, Proc
28
+ selector, type = selector_or_parent, parent
29
+ when Class
30
+ selector, type = selector_or_parent.selector, selector_or_parent
31
+ else
32
+ raise ArgumentError, "wrong number of arguments (#{rest.size} for 1)"
33
+ end
34
+
35
+ raise TypeError, "can't convert `#{type}' to Widget" \
36
+ unless type.methods.include?(:selector)
37
+
38
+ raise ArgumentError, "missing selector" unless selector || type.selector
39
+
40
+ child = WidgetClass.new(selector, type, &block)
41
+
42
+ const_set(Capybara::UI::WidgetName.new(name).to_sym, child)
43
+
44
+ child
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Capybara
2
+ module UI
3
+ # A form field.
4
+ class Field < Widget
5
+ def self.root(selector)
6
+ super String === selector ? [:field, selector] : selector
7
+ end
8
+
9
+ # @return This field's value.
10
+ #
11
+ # Override this to get the actual value.
12
+ def get
13
+ raise NotImplementedError
14
+ end
15
+
16
+ # Sets the field value.
17
+ #
18
+ # Override this to set the value.
19
+ def set(value)
20
+ raise NotImplementedError
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,331 @@
1
+ module Capybara
2
+ module UI
3
+ # A group of form fields.
4
+ #
5
+ # @todo Explain how to use locators when defining fields, including what
6
+ # happens when locators are omitted.
7
+ class FieldGroup < Widget
8
+ root 'fieldset'
9
+
10
+ def self.default_locator(type = nil, &block)
11
+ alias_method :name_to_locator, type if type
12
+
13
+ define_method :name_to_locator, &block if block
14
+ end
15
+
16
+ # The names of all the fields that belong to this field group.
17
+ #
18
+ # Field names are automatically added to this group as long as you use
19
+ # the field definition macros.
20
+ #
21
+ # @return [Set] the field names.
22
+ #
23
+ # @see field
24
+ def self.field_names
25
+ @field_names ||= Set.new
26
+ end
27
+
28
+ # @!group Field definition macros
29
+
30
+ # Creates a new checkbox accessor.
31
+ #
32
+ # Adds the following methods to the widget:
33
+ #
34
+ # <name>:: Gets the current checkbox state, as a boolean. Returns +true+
35
+ # if the corresponding check box is checked, +false+ otherwise.
36
+ # <name>=:: Sets the current checkbox state. Pass +true+ to check the
37
+ # checkbox, +false+ otherwise.
38
+ #
39
+ # @example
40
+ # # Given the following HTML:
41
+ # #
42
+ # # <form>
43
+ # # <p>
44
+ # # <label for="checked-box">
45
+ # # <input type="checkbox" value="1" id="checked-box" checked>
46
+ # # </p>
47
+ # # <p>
48
+ # # <label for="unchecked-box">
49
+ # # <input type="checkbox" value="1" id="unchecked-box">
50
+ # # </p>
51
+ # # </form>
52
+ # class MyFieldGroup < Capybara::UI::FieldGroup
53
+ # root 'form'
54
+ #
55
+ # check_box :checked_box, 'checked-box'
56
+ # check_box :unchecked_box, 'unchecked-box'
57
+ # end
58
+ #
59
+ # form = widget(:my_field_group)
60
+ #
61
+ # form.checked_box #=> true
62
+ # form.unchecked_box #=> false
63
+ #
64
+ # form.unchecked_box = true
65
+ # form.unchecked_box #=> true
66
+ #
67
+ # @param name the name of the checkbox accessor.
68
+ # @param locator the locator for the checkbox. If +nil+ the locator will
69
+ # be derived from +name+.
70
+ #
71
+ # @todo Handle checkbox access when the field is disabled (raise an
72
+ # exception?)
73
+ def self.check_box(name, locator = nil)
74
+ field name, locator, CheckBox
75
+ end
76
+
77
+ # Defines a new field.
78
+ #
79
+ # @param name the name of the field accessor.
80
+ # @param locator the field locator.
81
+ # @param type the field class name.
82
+ #
83
+ # @api private
84
+ def self.field(name, locator, type)
85
+ raise TypeError, "can't convert `#{name}' to Symbol" \
86
+ unless name.respond_to?(:to_sym)
87
+
88
+ field_names << name.to_sym
89
+
90
+ label = name.to_s.gsub(/_/, ' ').capitalize
91
+ locator ||= label
92
+
93
+ widget name, locator, type do
94
+ define_method :label do
95
+ label
96
+ end
97
+ end
98
+
99
+ define_method "#{name}=" do |val|
100
+ widget(name).set val
101
+ end
102
+
103
+ define_method name do
104
+ widget(name).get
105
+ end
106
+ end
107
+
108
+ # Creates a new select accessor.
109
+ #
110
+ # Adds the following methods to the widget:
111
+ #
112
+ # <name>:: Gets the text of the current selected option, or +nil+,
113
+ # if no option is selected.
114
+ # <name>_value:: Gets the value of the current selected option, or
115
+ # +nil+, if no option is selected.
116
+ # <name>=:: Selects an option on the current select. Pass the text or
117
+ # value of the option you want to select.
118
+ #
119
+ # @example
120
+ # # Given the following HTML:
121
+ # #
122
+ # # <form>
123
+ # # <p>
124
+ # # <label for="selected">
125
+ # # <select id="selected">
126
+ # # <option value ="1s" selected>Selected option</option>
127
+ # # <option value ="2s">Selected option two</option>
128
+ # # </select>
129
+ # # </p>
130
+ # # <p>
131
+ # # <label for="unselected">
132
+ # # <select id="unselected">
133
+ # # <option value="1u">Unselected option</option>
134
+ # # <option value="2u">Unselected option two</option>
135
+ # # </select>
136
+ # # </p>
137
+ # # </form>
138
+ # class MyFieldGroup < Capybara::UI::FieldGroup
139
+ # root 'form'
140
+ #
141
+ # select :selected, 'selected'
142
+ # select :unselected, 'unselected'
143
+ # end
144
+ #
145
+ # form = widget(:my_field_group)
146
+ #
147
+ # form.selected #=> "Selected option"
148
+ # form.selected_value #=> "1s"
149
+ #
150
+ # # Select by text
151
+ # form.unselected #=> nil
152
+ # form.unselected = "Unselected option"
153
+ # form.unselected #=> "Unselected option"
154
+ #
155
+ # # Select by value
156
+ # form.unselected = "2u"
157
+ # form.unselected #=> "Unselected option two"
158
+ # form.unselected_value #=> "2u"
159
+ #
160
+ # @param name the name of the select accessor.
161
+ # @param locator the locator for the select. If +nil+ the locator will
162
+ # be derived from +name+.
163
+ #
164
+ # @todo Handle select access when the field is disabled (raise an
165
+ # exception?)
166
+ # @todo Raise an exception when an option doesn't exist.
167
+ # @todo Allow passing the option value to set an option.
168
+ # @todo Ensure an option with no text returns the empty string.
169
+ # @todo What to do when +nil+ is passed to the writer?
170
+ def self.select(name, locator = nil)
171
+ field name, locator, Select
172
+
173
+ define_method "#{name}_value" do
174
+ widget(name).value
175
+ end
176
+ end
177
+
178
+ # Creates a new radio button group accessor.
179
+ #
180
+ # Adds the following methods to the widget:
181
+ #
182
+ # <name>:: Gets the text of the current checked button, or +nil+,
183
+ # if no button is checked.
184
+ # <name>_value:: Gets the value of the current checked button, or +nil+,
185
+ # if no button is checked.
186
+ # <name>=:: Checks a button in the current container. Pass the text of
187
+ # the label or the id or value of the button you want to choose.
188
+ #
189
+ # @example
190
+ # # Given the following HTML:
191
+ # #
192
+ # # <form>
193
+ # # <p class='checked'>
194
+ # # <label for="checked">Checked button</label>
195
+ # # <input type="radio" id="checked" name="c" value="checked_value" checked>
196
+ # # <label for="checked_two">Checked button two</label>
197
+ # # <input type="radio" id="checked_two" name="c" value="checked_two_value">
198
+ # # </p>
199
+ # # <p class='unchecked'>
200
+ # # <label for="unchecked">Unchecked button</label>
201
+ # # <input type="radio" id="unchecked" name="u" value="unchecked_value_one">
202
+ # # <label for="unchecked_two">Unchecked button two</label>
203
+ # # <input type="radio" id="unchecked_two" name="u" value="unchecked_value_two">
204
+ # # </p>
205
+ # # </form>
206
+ # class MyFieldGroup < Capybara::UI::FieldGroup
207
+ # root 'form'
208
+ #
209
+ # radio_button :checked, '.checked'
210
+ # radio_button :unchecked, '.unchecked'
211
+ # end
212
+ #
213
+ # form = widget(:my_field_group)
214
+ #
215
+ # form.checked #=> "Checked button"
216
+ # form.unchecked #=> nil
217
+ #
218
+ # form.unchecked = "Unchecked button" # Choose by label text
219
+ # form.unchecked #=> "Unchecked button"
220
+ # form.unchecked_value #=> "unchecked_value_one"
221
+ #
222
+ # form.unchecked = "unchecked_two" # Choose by id
223
+ # form.unchecked #=> "Unchecked button two"
224
+ # form.unchecked_value #=> "unchecked_value_two"
225
+ #
226
+ # form.unchecked = "unchecked_value_one" # Choose by value
227
+ # form.unchecked #=> "Unchecked button"
228
+ #
229
+ # @param name the name of the radio_button group accessor.
230
+ # @param locator the locator for the radio_button group.
231
+ #
232
+ def self.radio_button(name, locator = nil)
233
+ field name, locator, RadioButton
234
+
235
+ define_method "#{name}_value" do
236
+ widget(name).value
237
+ end
238
+ end
239
+
240
+ # Creates a new text field accessor.
241
+ #
242
+ # Adds the following methods to the widget:
243
+ #
244
+ # <name>:: Returns the current text field value, or +nil+ if no value
245
+ # has been set.
246
+ # <name>=:: Sets the current text field value.
247
+ # <name>? Returns +true+ if the current text field has content or
248
+ # +false+ otherwise
249
+ #
250
+ # @example
251
+ # # Given the following HTML:
252
+ # #
253
+ # # <form>
254
+ # # <p>
255
+ # # <label for="text-field">
256
+ # # <input type="text" value="Content" id="text-field">
257
+ # # </p>
258
+ # # <p>
259
+ # # <label for="empty-field">
260
+ # # <input type="text" id="empty-field">
261
+ # # </p>
262
+ # # </form>
263
+ # class MyFieldGroup < Capybara::UI::FieldGroup
264
+ # root 'form'
265
+ #
266
+ # text_field :filled_field, 'text-field'
267
+ # text_field :empty_field, 'empty-field'
268
+ # end
269
+ #
270
+ # form = widget(:my_field_group)
271
+ #
272
+ # form.filled_field #=> "Content"
273
+ # form.empty_field #=> nil
274
+ #
275
+ # form.filled_field? #=> true
276
+ # form.empty_field? #=> false
277
+ #
278
+ # form.empty_field = "Not anymore"
279
+ # form.empty_field #=> "Not anymore"
280
+ #
281
+ # @param name the name of the text field accessor.
282
+ # @param locator the locator for the text field. If +nil+ the locator
283
+ # will be derived from +name+.
284
+ #
285
+ # @todo Handle text field access when the field is disabled (raise an
286
+ # exception?)
287
+ def self.text_field(name, locator = nil)
288
+ define_method "#{name}?" do
289
+ widget(name).content?
290
+ end
291
+
292
+ field name, locator, TextField
293
+ end
294
+
295
+ # @!endgroup
296
+
297
+ # @return This field group's field widgets.
298
+ def fields
299
+ self.class.field_names.map { |name| widget(name) }
300
+ end
301
+
302
+ # Sets the given form attributes.
303
+ #
304
+ # @param attributes [Hash] the attributes and values we want to set.
305
+ #
306
+ # @return the current widget.
307
+ def set(attributes)
308
+ attributes.each do |k, v|
309
+ send "#{k}=", v
310
+ end
311
+
312
+ self
313
+ end
314
+
315
+ # Converts the current field group into a table suitable for diff'ing
316
+ # with Cucumber::Ast::Table.
317
+ #
318
+ # Field labels are determined by the widget name.
319
+ #
320
+ # Field values correspond to the return value of each field's +to_s+.
321
+ #
322
+ # @return [Array<Array>] the table.
323
+ def to_table
324
+ headers = fields.map { |field| field.label.downcase }
325
+ body = fields.map { |field| field.to_s.downcase }
326
+
327
+ [headers, body]
328
+ end
329
+ end
330
+ end
331
+ end