domino 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f53dbf7a0e24f6b9fe707570a47a60a4a6dcdfaa
4
- data.tar.gz: 783a69aedf7543b0e78c0e64c431ce4165252709
3
+ metadata.gz: 3059a81fc3233b83f748c35d895915d477778062
4
+ data.tar.gz: 5ba1c3b35b0b12919712ad789dd3a50d8b4d2fea
5
5
  SHA512:
6
- metadata.gz: 764cc8f1e20079d75ae4c66ec4266884431498a6ddc853926c3d74df5a836b8d11f45085c847880d716d19ef5ee5ef0cda315b19678b4fa633514d82a8847973
7
- data.tar.gz: 61f0c02649ac0a6f6f19937345ee995751f9eca029baecc6c5febc2a66a4a4b095edeccf1279dd4e075de7461cfcd82b01fe5c4c8f18f8d28a7bbaa2891ad407
6
+ metadata.gz: 629bc9d4a700d9161ba1cc46953556fb42ad6d447a5d90ee64a5d410eb416a6095ef57c9a5bf94dd96ba664d335a4e095ee4e245fec6c69298aa4211672d0e84
7
+ data.tar.gz: 9edb66f4135a320f85836e9e2c04af3f8eee8245cf8ea6c040e96da86fdf1ac30139c27c61be933bdfe63b83467b15a160ddc538a189c133207cbe1e2cfbb104
data/.travis.yml CHANGED
@@ -1,8 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
3
  - 2.0.0
5
- - 2.1.2
4
+ - 2.1.3
5
+ - 2.2.9
6
+ - 2.3.6
6
7
  - 2.4.3
7
8
  - 2.5.0
8
9
  - jruby
data/README.md CHANGED
@@ -74,6 +74,100 @@ Dom::Post.find_by_title('First Post').delete
74
74
  assert_nil Dom::Post.find_by_title('First Post')
75
75
  ```
76
76
 
77
+ ## Domino::Form
78
+
79
+ Domino makes it easy to model your forms for testing with `Domino::Form`.
80
+ To create a basic form, simply inherit from `Domino::Form` and define a
81
+ selector, a key (optional), and a set of fields.
82
+
83
+ ```ruby
84
+ module Dom
85
+ class PersonForm < Domino::Form
86
+ selector 'form.person'
87
+
88
+ # For forms with names like `person[age]`, no need to define the
89
+ # locator on each field. Define a key to automatically generate
90
+ # locators based on the field name.
91
+ key 'person'
92
+
93
+ # Define a custom selector to click to submit the form
94
+ submit_with "input[type='submit']" # this is the default
95
+
96
+ # locate field by label
97
+ field :first_name, 'First Name'
98
+
99
+ # locate field by automatically generated name (uses key, person[last_name])
100
+ field :last_name
101
+
102
+ # locate field by fully qualified name
103
+ field :biography, 'person[bio]'
104
+
105
+ # locate select field by label, acts as select
106
+ # callback mapper operates on selected option nodes
107
+ field :favorite_color, 'Favorite Color', as: :select, &:text
108
+
109
+ # automatically handles select[multiple]
110
+ # callback mapper operates on selected option nodes: &:value by default
111
+ field :allergies, as: :select
112
+
113
+ # locate by id, convert value via callback
114
+ field :age, 'person_age', &:to_i
115
+
116
+ # use a custom field type for unusual or composite fields
117
+ field :vehicles, '.input.vehicles', as: CheckBoxesField
118
+
119
+ # locate a field with a name that doesn't use the key
120
+ field :is_human, 'is_human', as: :boolean
121
+
122
+ # still supports attributes for non-input nodes
123
+ attribute :action, "&[action]"
124
+ attribute :submit_method, "&[method]"
125
+ end
126
+ end
127
+ ```
128
+
129
+ In the above example, you can define a field to get a reader and writer
130
+ method for the field. A form will also provide a mass-assignment writer
131
+ and a save method to submit the form.
132
+
133
+ ```ruby
134
+ person = Dom::PersonForm.find!
135
+ person.age #=> 25
136
+ person.vehicles #=> ["Car", "Bike"]
137
+ person.is_human #=> true
138
+ person.favorite_color #=> Blue
139
+
140
+ person.age = 35
141
+ person.age #=> 35
142
+
143
+ person.set(vehicles: ["Car", "Van"], first_name: "Jessica", last_name: "Jones")
144
+ person.attributes #=> { first_name: "Jessica", last_name: "Jones", biography: "", favorite_color: "Blue", age: 35, vehicles: ["Car", "Van"], is_human: true }
145
+ ```
146
+
147
+ `Domino::Form` provides basic field types for text inputs and textareas,
148
+ single-selects, and boolean fields. You can create custom field types
149
+ for more complex form inputs by subclassing `Domino::Form::Field` and
150
+ overriding the `read` and `write` methods. For example, if you have a
151
+ collection of check boxes, this might suit your needs:
152
+
153
+ ```ruby
154
+ class CheckBoxesField < Domino::Form::Field
155
+ def read(node)
156
+ node.find(locator).all('input[type=checkbox]').select(&:checked?).map(&:value)
157
+ end
158
+
159
+ def write(node, value)
160
+ value = Array(value)
161
+ node.find(locator).all('input[type=checkbox]').each do |box|
162
+ box.set(value.include?(box.value))
163
+ end
164
+ end
165
+ end
166
+ ```
167
+
168
+ Provide your custom class using the `:as` option when defining your field,
169
+ as shown in the example above.
170
+
77
171
  ## Integration with capybara
78
172
 
79
173
  Domino uses capybara internally to search html for nodes and
data/Rakefile CHANGED
@@ -2,7 +2,8 @@ require 'bundler/gem_tasks'
2
2
 
3
3
  desc "Run the tests"
4
4
  task :test do
5
- require File.join(File.dirname(__FILE__), 'test', 'domino_test')
5
+ require File.join(File.dirname(__FILE__), 'test', 'test_helper.rb')
6
+ Dir[File.join(File.dirname(__FILE__), "test", "**", "*.rb")].each { |f| require f }
6
7
  end
7
8
 
8
9
  task :default => :test
data/domino.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "domino"
4
- gem.version = "0.8.0"
4
+ gem.version = "0.9.0"
5
5
  gem.platform = Gem::Platform::RUBY
6
6
  gem.authors = ["Nick Gauthier"]
7
7
  gem.email = ["ngauthier@gmail.com"]
data/lib/domino.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'capybara/dsl'
2
- require 'set'
3
2
  # To create a basic Domino class, inherit from Domino and
4
3
  # define a selector and attributes:
5
4
  #
@@ -44,6 +43,9 @@ class Domino
44
43
  include Capybara::DSL
45
44
  extend Capybara::DSL
46
45
 
46
+ require 'domino/attribute'
47
+ require 'domino/form'
48
+
47
49
  # Namespaced Domino::Error
48
50
  class Error < StandardError; end
49
51
 
@@ -136,14 +138,13 @@ class Domino
136
138
 
137
139
  attribute_definitions[attribute] = Attribute.new(attribute, selector, &callback)
138
140
 
139
- class_eval %{
140
- def #{attribute}
141
- self.class.attribute_definitions[:#{attribute}].value(node)
142
- end
143
- def self.find_by_#{attribute}(value)
144
- find_by_attribute(:#{attribute}, value)
145
- end
146
- }
141
+ define_method :"#{attribute}" do
142
+ self.class.attribute_definitions[attribute].value(node)
143
+ end
144
+
145
+ define_singleton_method :"find_by_#{attribute}" do |value|
146
+ find_by_attribute(attribute, value)
147
+ end
147
148
  end
148
149
 
149
150
  private
@@ -194,55 +195,4 @@ class Domino
194
195
  def initialize(node)
195
196
  @node = node
196
197
  end
197
-
198
- class Attribute
199
- attr_reader :name, :selector, :callback
200
-
201
- def initialize(name, selector = nil, &callback)
202
- @callback = callback
203
- @name = name
204
- @selector = selector || %(.#{name.to_s.tr('_', '-')})
205
- end
206
-
207
- def value(node)
208
- val = value_before_typecast(node)
209
-
210
- if val && callback.is_a?(Proc)
211
- callback.call(val)
212
- else
213
- val
214
- end
215
- end
216
-
217
- # Get the text of the first dom element matching a selector
218
- #
219
- # Dom::Post.all.first.attribute('.title')
220
- def value_before_typecast(node)
221
- if combinator?
222
- node[node_attribute_key] || node.matches_css?(combinator)
223
- else
224
- node.find(selector).text
225
- end
226
- rescue Capybara::ElementNotFound
227
- nil
228
- end
229
-
230
- def match_value?(node, value)
231
- value === value(node)
232
- end
233
-
234
- private
235
-
236
- def combinator?
237
- selector[0] == "&".freeze
238
- end
239
-
240
- def combinator
241
- @combinator ||= selector.sub(/&/, "") if combinator?
242
- end
243
-
244
- def node_attribute_key
245
- @node_attribute_key ||= combinator.match(/(?<=\[).+?(?=\])/) { |m| m[0] }
246
- end
247
- end
248
198
  end
@@ -0,0 +1,50 @@
1
+ class Domino::Attribute
2
+ attr_reader :name, :selector, :callback
3
+
4
+ def initialize(name, selector = nil, &callback)
5
+ @callback = callback
6
+ @name = name
7
+ @selector = selector || %(.#{name.to_s.tr('_', '-')})
8
+ end
9
+
10
+ def value(node)
11
+ val = value_before_typecast(node)
12
+
13
+ if val && callback.is_a?(Proc)
14
+ callback.call(val)
15
+ else
16
+ val
17
+ end
18
+ end
19
+
20
+ # Get the text of the first dom element matching a selector
21
+ #
22
+ # Dom::Post.all.first.attribute('.title')
23
+ def value_before_typecast(node)
24
+ if combinator?
25
+ node[node_attribute_key] || node.matches_css?(combinator)
26
+ else
27
+ node.find(selector).text
28
+ end
29
+ rescue Capybara::ElementNotFound
30
+ nil
31
+ end
32
+
33
+ def match_value?(node, value)
34
+ value === value(node)
35
+ end
36
+
37
+ private
38
+
39
+ def combinator?
40
+ selector[0] == '&'.freeze
41
+ end
42
+
43
+ def combinator
44
+ @combinator ||= selector.sub(/&/, '') if combinator?
45
+ end
46
+
47
+ def node_attribute_key
48
+ @node_attribute_key ||= combinator.match(/(?<=\[).+?(?=\])/) { |m| m[0] }
49
+ end
50
+ end
@@ -0,0 +1,82 @@
1
+ class Domino::Form < Domino
2
+ require 'domino/form/field'
3
+ require 'domino/form/select_field'
4
+ require 'domino/form/boolean_field'
5
+
6
+ FIELD_TYPES = {
7
+ select: SelectField,
8
+ boolean: BooleanField
9
+ }.freeze
10
+
11
+ def self.key(k)
12
+ @key = k
13
+ end
14
+
15
+ def self.fields
16
+ field_definitions.keys
17
+ end
18
+
19
+ def self.field_definitions
20
+ @field_definitions ||= {}
21
+ end
22
+
23
+ def self.submit_with(submitter)
24
+ @submitter = submitter
25
+ end
26
+
27
+ def self.submitter
28
+ @submitter ||= "input[type='submit']"
29
+ end
30
+
31
+ def self.field(*args, &callback)
32
+ options = args.last.is_a?(::Hash) ? args.pop : {}
33
+ attribute, locator = *args
34
+
35
+ locator ||= !@key.to_s.empty? ? "#{@key}[#{attribute}]" : attribute
36
+
37
+ field_type = options.delete(:as)
38
+ field_class = field_type.is_a?(Class) && field_type.ancestors.include?(Field) ? field_type : FIELD_TYPES[field_type] || Field
39
+
40
+ field_definitions[attribute] = field_class.new(attribute, locator, options, &callback)
41
+
42
+ define_method :"#{attribute}" do
43
+ self.class.field_definitions[attribute].value(node)
44
+ end
45
+
46
+ define_method :"#{attribute}=" do |value|
47
+ self.class.field_definitions[attribute].write(node, value)
48
+ end
49
+ end
50
+
51
+ def self.create(attributes = {})
52
+ find!.create(attributes)
53
+ end
54
+
55
+ def self.update(attributes = {})
56
+ find!.update(attributes)
57
+ end
58
+
59
+ def create(attributes = {})
60
+ set(attributes)
61
+ save
62
+ end
63
+
64
+ def update(attributes = {})
65
+ set(attributes)
66
+ save
67
+ end
68
+
69
+ def set(attributes = {})
70
+ attributes.each { |k, v| send("#{k}=", v) }
71
+ end
72
+
73
+ def save
74
+ find(self.class.submitter).click
75
+ end
76
+
77
+ def fields
78
+ self.class.fields.each_with_object({}) do |field, memo|
79
+ memo[field] = send(field)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,13 @@
1
+ class Domino::Form::BooleanField < Domino::Form::Field
2
+ def read(node)
3
+ node.find_field(locator, options).checked?
4
+ end
5
+
6
+ def write(node, value)
7
+ if value
8
+ node.check(locator, options)
9
+ else
10
+ node.uncheck(locator, options)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ class Domino::Form::Field
2
+ attr_reader :name, :locator, :options, :callback
3
+
4
+ def initialize(name, locator, options = {}, &callback)
5
+ @name = name
6
+ @locator = locator
7
+ @options = options
8
+ @callback = callback
9
+ extract_field_options
10
+ end
11
+
12
+ # Delete any options for your field type that shouldn't be passed to
13
+ # the field locator.
14
+ # Default: noop
15
+ def extract_field_options
16
+ end
17
+
18
+ # Convert the value from `#read` via callback if provided.
19
+ def value(node)
20
+ val = read(node)
21
+ if val && callback.is_a?(Proc)
22
+ callback.call(val)
23
+ else
24
+ val
25
+ end
26
+ end
27
+
28
+ # Locate the field using the locator and options
29
+ def field(node)
30
+ node.find_field(locator, options)
31
+ end
32
+
33
+ # Value that will be passed to the callback.
34
+ # Default: field_node.value
35
+ def read(node)
36
+ field(node).value
37
+ end
38
+
39
+ # Sets the value on the field node.
40
+ # Default: node.fill_in for text fields.
41
+ def write(node, value)
42
+ node.fill_in(locator, with: value, **options)
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ class Domino::Form::SelectField < Domino::Form::Field
2
+ # Returns the set of selected options that can be processed in the callback.
3
+ def read(node)
4
+ s = field(node)
5
+ selected = s.all("option[selected]")
6
+ s.multiple? ? selected : selected.first
7
+ end
8
+
9
+ def write(node, value)
10
+ s = field(node)
11
+ values = Array(value)
12
+
13
+ s.all('option').each do |o|
14
+ if values.include?(o.text) || values.include?(o.value)
15
+ o.select_option
16
+ elsif s.multiple?
17
+ o.unselect_option
18
+ end
19
+ end
20
+ end
21
+
22
+ def value(node)
23
+ val = read(node)
24
+ return val unless callback
25
+ if field(node).multiple?
26
+ val.map { |opt| callback.call(opt) }
27
+ else
28
+ callback.call(val)
29
+ end
30
+ end
31
+
32
+ # Any callback mapping on a select will recieve one or more option nodes.
33
+ # Applying to one item or an Enumerable.
34
+ def callback
35
+ @callback ||= :value.to_proc
36
+ end
37
+ end
@@ -0,0 +1,206 @@
1
+ class DominoFormTest < Minitest::Test
2
+ include Capybara::DSL
3
+
4
+ module Dom
5
+ class CheckBoxesField < Domino::Form::Field
6
+ def read(node)
7
+ node.find(locator).all('input[type=checkbox]').select(&:checked?).map(&:value)
8
+ end
9
+
10
+ def write(node, value)
11
+ value = Array(value)
12
+ node.find(locator).all('input[type=checkbox]').each do |box|
13
+ box.set(value.include?(box.value))
14
+ end
15
+ end
16
+ end
17
+
18
+ class PersonForm < Domino::Form
19
+ selector 'form.person'
20
+ key 'person'
21
+
22
+ field :name, 'First Name'
23
+ field :last_name
24
+ field :biography, 'person[bio]'
25
+ field :favorite_color, 'Favorite Color', as: :select, &:text
26
+ field :age, 'person_age', &:to_i
27
+ field :vehicles, '.input.vehicles', as: CheckBoxesField
28
+ field :is_human, 'is_human', as: :boolean
29
+
30
+ attribute :action, '&[action]'
31
+ attribute :submit_method, '&[method]'
32
+ end
33
+
34
+ class PersonFormB < Domino::Form
35
+ selector 'form.person'
36
+
37
+ field :is_human, as: :boolean
38
+ field :allergies, as: :select
39
+ end
40
+ end
41
+
42
+ def setup
43
+ visit '/people/23/edit'
44
+ end
45
+
46
+ def test_form_field_with_label_locator
47
+ assert_equal 'Alice', Dom::PersonForm.find!.name
48
+ end
49
+
50
+ def test_form_field_with_default_locator_and_form_key
51
+ assert_equal 'Cooper', Dom::PersonForm.find!.last_name
52
+ end
53
+
54
+ def test_form_field_with_name_locator
55
+ assert_equal 'Alice is fun', Dom::PersonForm.find!.biography
56
+ end
57
+
58
+ def test_form_field_as_select_field_type
59
+ assert_equal 'Blue', Dom::PersonForm.find!.favorite_color
60
+ end
61
+
62
+ def test_form_field_as_multiple_select_field_type
63
+ formb = Dom::PersonFormB.find!
64
+ assert_equal [], formb.allergies
65
+ formb.allergies = %w[Peanut Corn]
66
+ assert_equal %w[peanut corn], formb.allergies
67
+ formb.allergies = ['corn']
68
+ assert_equal ['corn'], formb.allergies
69
+ end
70
+
71
+ def test_form_field_with_id_locator_and_callback
72
+ assert_equal 23, Dom::PersonForm.find!.age
73
+ end
74
+
75
+ def test_form_field_with_custom_field_type
76
+ assert_equal [], Dom::PersonForm.find!.vehicles
77
+ end
78
+
79
+ def test_form_field_with_boolean_field_type
80
+ assert_equal false, Dom::PersonForm.find!.is_human
81
+ end
82
+
83
+ def test_form_set_multiple_attributes
84
+ person = Dom::PersonForm.find!
85
+ person.set name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Red', age: 25, vehicles: %w[Bike Car], is_human: true
86
+
87
+ assert_equal 'Marie', person.name
88
+ assert_equal 'Curie', person.last_name
89
+ assert_equal 'Scientific!', person.biography
90
+ assert_equal 'Red', person.favorite_color
91
+ assert_equal 25, person.age
92
+ assert_equal %w[Bike Car], person.vehicles
93
+ assert_equal true, person.is_human
94
+ end
95
+
96
+ def test_form_fields
97
+ person = Dom::PersonForm.find!
98
+ assert_equal({ name: 'Alice', last_name: 'Cooper', biography: 'Alice is fun', favorite_color: 'Blue', age: 23, vehicles: [], is_human: false }, person.fields)
99
+ end
100
+
101
+ def test_form_set_nil_clears_field
102
+ person = Dom::PersonForm.find!
103
+ person.name = nil
104
+ assert_equal '', person.name
105
+ end
106
+
107
+ def test_form_set_by_attribute_writer
108
+ person = Dom::PersonForm.find!
109
+ assert_equal 23, person.age
110
+ person.age = 66
111
+ assert_equal 66, person.age
112
+ end
113
+
114
+ def test_form_default_selector_without_key
115
+ formb = Dom::PersonFormB.find!
116
+ assert_equal false, formb.is_human
117
+ formb.is_human = true
118
+ assert_equal true, formb.is_human
119
+ formb.is_human = false
120
+ assert_equal false, formb.is_human
121
+ end
122
+
123
+ def test_save_submits_form
124
+ person = Dom::PersonForm.find!
125
+ refute page.has_content?('Person updated successfully.')
126
+
127
+ person.set name: 'Marie', last_name: 'Curie', biography: 'Scientific!', age: 25, favorite_color: 'Green', vehicles: %w[Bike Car], is_human: true
128
+
129
+ person.save
130
+
131
+ assert page.has_content?('Person updated successfully.')
132
+
133
+ updated_person = Dom::PersonForm.find!
134
+ assert_equal 'Marie', updated_person.name
135
+ assert_equal 'Curie', updated_person.last_name
136
+ assert_equal 'Scientific!', updated_person.biography
137
+ assert_equal 'Green', updated_person.favorite_color
138
+ assert_equal 25, updated_person.age
139
+ assert_equal %w[Bike Car], updated_person.vehicles
140
+ assert_equal true, updated_person.is_human
141
+ end
142
+
143
+ def test_update_fills_and_submits_form
144
+ person = Dom::PersonForm.find!
145
+ refute page.has_content?('Person updated successfully.')
146
+
147
+ person.update name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true
148
+
149
+ assert page.has_content?('Person updated successfully.')
150
+
151
+ updated_person = Dom::PersonForm.find!
152
+ assert_equal({ name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true }, updated_person.fields)
153
+ end
154
+
155
+ def test_create_fills_and_submits_form
156
+ person = Dom::PersonForm.find!
157
+ refute page.has_content?('Person updated successfully.')
158
+
159
+ person.create name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true
160
+
161
+ assert page.has_content?('Person updated successfully.')
162
+
163
+ updated_person = Dom::PersonForm.find!
164
+ assert_equal({ name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true }, updated_person.fields)
165
+ end
166
+
167
+ def test_static_update_fills_and_submits_form
168
+ refute page.has_content?('Person updated successfully.')
169
+
170
+ Dom::PersonForm.create name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true
171
+
172
+ assert page.has_content?('Person updated successfully.')
173
+
174
+ updated_person = Dom::PersonForm.find!
175
+ assert_equal({ name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true }, updated_person.fields)
176
+ end
177
+
178
+ def test_static_create_fills_and_submits_form
179
+ refute page.has_content?('Person updated successfully.')
180
+
181
+ Dom::PersonForm.create name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true
182
+
183
+ assert page.has_content?('Person updated successfully.')
184
+
185
+ updated_person = Dom::PersonForm.find!
186
+ assert_equal({ name: 'Marie', last_name: 'Curie', biography: 'Scientific!', favorite_color: 'Green', age: 25, vehicles: %w[Bike Car], is_human: true }, updated_person.fields)
187
+ end
188
+
189
+ def test_static_create_with_no_matches
190
+ visit "/"
191
+ assert_raises Capybara::ElementNotFound do
192
+ Dom::PersonForm.create name: 'Marie', last_name: 'Curie'
193
+ end
194
+ end
195
+
196
+ def test_static_update_with_no_matches
197
+ visit "/"
198
+ assert_raises Capybara::ElementNotFound do
199
+ Dom::PersonForm.update name: 'Marie', last_name: 'Curie'
200
+ end
201
+ end
202
+
203
+ def test_supports_normal_attributes
204
+ assert_equal({ action: '/people/23', submit_method: 'post' }, Dom::PersonForm.find!.attributes)
205
+ end
206
+ end
data/test/domino_test.rb CHANGED
@@ -1,59 +1,6 @@
1
- require 'bundler/setup'
2
- unless ENV['CI']
3
- require 'simplecov'
4
- SimpleCov.start
5
- end
6
- Bundler.require
7
- require 'minitest/autorun'
8
- require 'minitest/mock'
9
-
10
- class TestApplication
11
- def call(_env)
12
- [200, { 'Content-Type' => 'text/plain' }, [%(
13
- <html>
14
- <body>
15
- <h1>Here are people and animals</h1>
16
- <div id='people'>
17
- <div class='person active' data-rank="1" data-uuid="e94bb2d3-71d2-4efb-abd4-ebc0cb58d19f">
18
- <h2 class='name'>Alice</h2>
19
- <p class='last-name'>Cooper</p>
20
- <p class='bio'>Alice is fun</p>
21
- <p class='fav-color'>Blue</p>
22
- <p class='age'>23</p>
23
- </div>
24
- <div class='person' data-rank="3" data-uuid="05bf319e-8d6a-43c2-be37-2dad8ddbe5af">
25
- <h2 class='name'>Bob</h2>
26
- <p class='last-name'>Marley</p>
27
- <p class='bio'>Bob is smart</p>
28
- <p class='fav-color'>Red</p>
29
- <p class='age'>52</p>
30
- </div>
31
- <div class='person' data-rank="2" data-uuid="4abcdeff-1d36-44a9-a05e-8fc57564d2c4">
32
- <h2 class='name'>Charlie</h2>
33
- <p class='last-name'>Murphy</p>
34
- <p class='bio'>Charlie is wild</p>
35
- <p class='fav-color'>Red</p>
36
- </div>
37
- <div class='person' data-rank="7" data-blocked data-uuid="2afccde0-5d13-41c7-ab01-7f37fb2fe3ee">
38
- <h2 class='name'>Donna</h2>
39
- <p class='last-name'>Summer</p>
40
- <p class='bio'>Donna is quiet</p>
41
- </div>
42
- </div>
43
- <div id='animals'></div>
44
- <div id='receipts'>
45
- <div class='receipt' id='receipt-72' data-store='ACME'></div>
46
- </div>
47
- </body>
48
- </html>
49
- )]]
50
- end
51
- end
52
-
53
- Capybara.app = TestApplication.new
54
-
55
- class DominoTest < MiniTest::Unit::TestCase
1
+ class DominoTest < Minitest::Test
56
2
  include Capybara::DSL
3
+
57
4
  module Dom
58
5
  class Person < Domino
59
6
  selector '#people .person'
@@ -0,0 +1,142 @@
1
+ class TestApplication
2
+ def call(env)
3
+ [200, { 'Content-Type' => 'text/plain' }, [response(env)]]
4
+ end
5
+
6
+ def response(env)
7
+ case env.fetch('PATH_INFO')
8
+ when '/'
9
+ root
10
+ when '/people/23/edit'
11
+ params = {
12
+ 'person' => {
13
+ 'id' => 23,
14
+ 'name' => 'Alice',
15
+ 'last_name' => 'Cooper',
16
+ 'bio' => 'Alice is fun',
17
+ 'fav_color' => 'blue',
18
+ 'age' => 23,
19
+ 'vehicles' => []
20
+ }, 'is_human' => false
21
+ }
22
+ edit params
23
+ when '/people/23'
24
+ params = Rack::Utils.parse_nested_query(env.fetch('rack.input').read)
25
+ edit params.merge(flash: "Person updated successfully.")
26
+ end
27
+ end
28
+
29
+ def root
30
+ <<-HTML
31
+ <html>
32
+ <body>
33
+ <h1>Here are people and animals</h1>
34
+ <div id='people'>
35
+ <div class='person active' data-rank="1" data-uuid="e94bb2d3-71d2-4efb-abd4-ebc0cb58d19f">
36
+ <h2 class='name'>Alice</h2>
37
+ <p class='last-name'>Cooper</p>
38
+ <p class='bio'>Alice is fun</p>
39
+ <p class='fav-color'>Blue</p>
40
+ <p class='age'>23</p>
41
+ </div>
42
+ <div class='person' data-rank="3" data-uuid="05bf319e-8d6a-43c2-be37-2dad8ddbe5af">
43
+ <h2 class='name'>Bob</h2>
44
+ <p class='last-name'>Marley</p>
45
+ <p class='bio'>Bob is smart</p>
46
+ <p class='fav-color'>Red</p>
47
+ <p class='age'>52</p>
48
+ </div>
49
+ <div class='person' data-rank="2" data-uuid="4abcdeff-1d36-44a9-a05e-8fc57564d2c4">
50
+ <h2 class='name'>Charlie</h2>
51
+ <p class='last-name'>Murphy</p>
52
+ <p class='bio'>Charlie is wild</p>
53
+ <p class='fav-color'>Red</p>
54
+ </div>
55
+ <div class='person' data-rank="7" data-blocked data-uuid="2afccde0-5d13-41c7-ab01-7f37fb2fe3ee">
56
+ <h2 class='name'>Donna</h2>
57
+ <p class='last-name'>Summer</p>
58
+ <p class='bio'>Donna is quiet</p>
59
+ </div>
60
+ </div>
61
+ <div id='animals'></div>
62
+ <div id='receipts'>
63
+ <div class='receipt' id='receipt-72' data-store='ACME'></div>
64
+ </div>
65
+ </body>
66
+ </html>
67
+ HTML
68
+ end
69
+
70
+ def edit(params = { 'person' => {} })
71
+ person = params['person']
72
+ <<-HTML
73
+ <html>
74
+ <body>
75
+ <div class="flash">#{params[:flash]}</div>
76
+ <h1>Edit Person</h1>
77
+
78
+ <form action="/people/#{person['id']}" method="post" class="person">
79
+ <div class="input name">
80
+ <label for="person_name">First Name</label>
81
+ <input type="text" id="person_name" name="person[name]" value="#{person['name']}" />
82
+ </div>
83
+
84
+ <div class="input last_name">
85
+ <label for="person_name">Last Name</label>
86
+ <input type="text" id="person_last_name" name="person[last_name]" value="#{person['last_name']}" />
87
+ </div>
88
+
89
+ <div class="input bio">
90
+ <label for="person_bio">Biography</label>
91
+ <textarea id="person_bio" name="person[bio]">#{person['bio']}</textarea>
92
+ </div>
93
+
94
+ <div class="input fav_color">
95
+ <label for="person_fav_color">Favorite Color</label>
96
+ <select id="person_fav_color" name="person[fav_color]">
97
+ <option value>- Select a Color -</option>
98
+ <option value="red" #{'selected="selected"' if person['fav_color'] == 'red'}>Red</option>
99
+ <option value="blue" #{'selected="selected"' if person['fav_color'] == 'blue'}>Blue</option>
100
+ <option value="green" #{'selected="selected"' if person['fav_color'] == 'green'}>Green</option>
101
+ </select>
102
+ </div>
103
+
104
+ <div class="input age">
105
+ <label for="person_age">Biography</label>
106
+ <input type="number" min="0" step="1" id="person_age" name="person[age]" value="#{person['age']}" />
107
+ </div>
108
+
109
+ <div class="input is_human">
110
+ <input type="hidden" name="is_human" value="0">
111
+ <label for="is_a_human">
112
+ <input id="is_a_human" type="checkbox" name="is_human" value="1" #{'checked' if params['is_human']}>
113
+ I'm a human
114
+ </label>
115
+ </div>
116
+
117
+ <div class="input vehicles">
118
+ <label for="person_vehicles_bike"><input id="person_vehicles_bike" type="checkbox" name="person[vehicles][]" value="Bike" #{'checked' if person['vehicles'].include?('Bike')}>Bike</label>
119
+ <label for="person_vehicles_car"><input id="person_vehicles_car" type="checkbox" name="person[vehicles][]" value="Car" #{'checked' if person['vehicles'].include?('Car')}>Car</label>
120
+ </div>
121
+
122
+ <div class="input allergies">
123
+ <label for="allergies">Allergies</label>
124
+ <select id="allergies" name="allergies" multiple="multiple">
125
+ <option value>None</option>
126
+ <option value="peanut" #{'selected="selected"' if Array(params['allergies']).include?('peanut')}>Peanut</option>
127
+ <option value="corn" #{'selected="selected"' if Array(person['allergies']).include?('corn')}>Corn</option>
128
+ <option value="wheat" #{'selected="selected"' if Array(person['allergies']).include?('wheat')}>Wheat</option>
129
+ </select>
130
+ </div>
131
+
132
+ <div class="actions">
133
+ <input type="submit" name="commit" value="Update Person" />
134
+ </div>
135
+ </form>
136
+ </body>
137
+ </html>
138
+ HTML
139
+ end
140
+ end
141
+
142
+ Capybara.app = TestApplication.new
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ unless ENV['CI']
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ end
6
+ Bundler.require
7
+ require 'minitest/autorun'
8
+ require 'minitest/mock'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Gauthier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-27 00:00:00.000000000 Z
11
+ date: 2018-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -83,7 +83,15 @@ files:
83
83
  - Rakefile
84
84
  - domino.gemspec
85
85
  - lib/domino.rb
86
+ - lib/domino/attribute.rb
87
+ - lib/domino/form.rb
88
+ - lib/domino/form/boolean_field.rb
89
+ - lib/domino/form/field.rb
90
+ - lib/domino/form/select_field.rb
91
+ - test/domino_form_test.rb
86
92
  - test/domino_test.rb
93
+ - test/test_application.rb
94
+ - test/test_helper.rb
87
95
  homepage: http://github.com/ngauthier/domino
88
96
  licenses:
89
97
  - MIT
@@ -109,4 +117,7 @@ signing_key:
109
117
  specification_version: 4
110
118
  summary: View abstraction for integration testing
111
119
  test_files:
120
+ - test/domino_form_test.rb
112
121
  - test/domino_test.rb
122
+ - test/test_application.rb
123
+ - test/test_helper.rb