domino 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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