Class: Metallize::Form

Inherits:
Object
  • Object
show all
Extended by:
ElementMatcher
Defined in:
lib/metallize/form.rb

Defined Under Namespace

Classes: Button, Field, Hidden, MultiSelectList, Option, SelectList, Submit, Text

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ElementMatcher

elements_with

Constructor Details

#initialize(driver, form) ⇒ Form

Returns a new instance of Form.



32
33
34
35
36
37
38
# File 'lib/metallize/form.rb', line 32

def initialize(driver, form)
  @driver = driver
  @form   = form
  @method = (@form.attribute('method') || 'GET').upcase
  @action = @form.attribute('action')
  parse
end

Instance Attribute Details

#actionObject

Returns the value of attribute action.



7
8
9
# File 'lib/metallize/form.rb', line 7

def action
  @action
end

#buttonsObject (readonly)

Returns the value of attribute buttons.



9
10
11
# File 'lib/metallize/form.rb', line 9

def buttons
  @buttons
end

#checkboxesObject (readonly)

Returns the value of attribute checkboxes.



9
10
11
# File 'lib/metallize/form.rb', line 9

def checkboxes
  @checkboxes
end

#encodingObject

Character encoding of form data (i.e. UTF-8)



15
16
17
# File 'lib/metallize/form.rb', line 15

def encoding
  @encoding
end

#enctypeObject

Content-Type for form data (i.e. application/x-www-form-urlencoded)



12
13
14
# File 'lib/metallize/form.rb', line 12

def enctype
  @enctype
end

#fieldsObject (readonly) Also known as: elements

Returns the value of attribute fields.



9
10
11
# File 'lib/metallize/form.rb', line 9

def fields
  @fields
end

#file_uploadsObject (readonly)

Returns the value of attribute file_uploads.



9
10
11
# File 'lib/metallize/form.rb', line 9

def file_uploads
  @file_uploads
end

#form_nodeObject (readonly)

Returns the value of attribute form_node.



23
24
25
# File 'lib/metallize/form.rb', line 23

def form_node
  @form_node
end

#ignore_encoding_errorObject

When true, character encoding errors will never be never raised on form submission. Default is false



19
20
21
# File 'lib/metallize/form.rb', line 19

def ignore_encoding_error
  @ignore_encoding_error
end

#methodObject

Returns the value of attribute method.



7
8
9
# File 'lib/metallize/form.rb', line 7

def method
  @method
end

#nameObject

Returns the value of attribute name.



7
8
9
# File 'lib/metallize/form.rb', line 7

def name
  @name
end

#pageObject (readonly)

Returns the value of attribute page.



24
25
26
# File 'lib/metallize/form.rb', line 24

def page
  @page
end

#radiobuttonsObject (readonly)

Returns the value of attribute radiobuttons.



9
10
11
# File 'lib/metallize/form.rb', line 9

def radiobuttons
  @radiobuttons
end

Instance Method Details

#[](field_name) ⇒ Object

Fetch the value of the first input field with the name passed in. Example:

puts form['name']


206
207
208
209
# File 'lib/metallize/form.rb', line 206

def [](field_name)
  f = field(field_name)
  f && f.value
end

#[]=(field_name, value) ⇒ Object

Set the value of the first input field with the name passed in. Example:

form['name'] = 'Aaron'


213
214
215
216
217
218
219
220
# File 'lib/metallize/form.rb', line 213

def []=(field_name, value)
  f = field(field_name)
  if f
    f.value = value
  else
    add_field!(field_name, value)
  end
end

#add_field!(field_name, value = nil) ⇒ Object

Add a field with field_name and value



166
167
168
# File 'lib/metallize/form.rb', line 166

def add_field!(field_name, value = nil)
  fields << Field.new({'name' => field_name}, value)
end

#dom_classObject

This method is a shortcut to get form’s DOM class. Common usage:

page.form_with(:dom_class => "foorm")

Note that you can also use :class to get to this method:

page.form_with(:class => "foorm")


161
162
163
# File 'lib/metallize/form.rb', line 161

def dom_class
  form_node['class']
end

#dom_idObject

This method is a shortcut to get form’s DOM id. Common usage:

page.form_with(:dom_id => "foorm")

Note that you can also use :id to get to this method:

page.form_with(:id => "foorm")


152
153
154
# File 'lib/metallize/form.rb', line 152

def dom_id
  form_node['id']
end

#has_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/metallize/form.rb', line 78

def has_value?(value)
  fields.find { |f| f.value == value }
end

#hidden_field?(field_name) ⇒ Boolean

Returns whether or not the form contains a Hidden field named field_name

Returns:

  • (Boolean)


138
139
140
# File 'lib/metallize/form.rb', line 138

def hidden_field?(field_name)
  hiddens.find { |f| f.name == field_name }
end

#hiddensObject

Returns all fields of type Hidden



108
109
110
# File 'lib/metallize/form.rb', line 108

def hiddens
  @hiddens ||= fields.select { |f| f.class == Hidden }
end

#keygensObject

Returns all fields of type Keygen



118
119
120
# File 'lib/metallize/form.rb', line 118

def keygens
  @keygens ||= fields.select { |f| f.class == Keygen }
end

#keysObject

Returns all field names (keys) for this form



83
84
85
# File 'lib/metallize/form.rb', line 83

def keys
  fields.map { |f| f.name }
end

#parseObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/metallize/form.rb', line 44

def parse
  @fields       = []
  @buttons      = []

  form_node = @driver.find_elements(:tag_name, 'input')
  form_node.each do |node|
    type = (node.attribute('type') || 'text').downcase
    name = node.attribute('name')
    next if name.nil? && !%w[submit button image].include?(type)
    case type
      when 'submit'
        @buttons << Submit.new(node)
      when 'button'
        @buttons << Button.new(node)
      when 'hidden'
        @fields << Hidden.new(node, node.attribute('value') || '')
      when 'text'
        @fields << Text.new(node, node.attribute('value') || '')
      else
        @fields << Field.new(node, node.attribute('value') || '')
    end

    form_node = @driver.find_elements(:tag_name, 'select')
    form_node.each do |node|
      next unless node['name']
      @fields << SelectList.new(node)
    end

    form_node = @driver.find_elements(:tag_name, 'button')
    form_node.each do |node|
      @buttons << Button.new(node)
    end
  end

  def has_value?(value)
    fields.find { |f| f.value == value }
  end

  # Returns all field names (keys) for this form
  def keys
    fields.map { |f| f.name }
  end

  # Returns all field values for this form
  def values
    fields.map { |f| f.value }
  end

  # Returns all buttons of type Submit
  def submits
    @submits ||= buttons.select { |f| f.class == Submit }
  end

  # Returns all buttons of type Reset
  def resets
    @resets ||= buttons.select { |f| f.class == Reset }
  end

  # Returns all fields of type Text
  def texts
    @texts ||= fields.select { |f| f.class == Text }
  end

  # Returns all fields of type Hidden
  def hiddens
    @hiddens ||= fields.select { |f| f.class == Hidden }
  end

  # Returns all fields of type Textarea
  def textareas
    @textareas ||= fields.select { |f| f.class == Textarea }
  end

  # Returns all fields of type Keygen
  def keygens
    @keygens ||= fields.select { |f| f.class == Keygen }
  end

  # Returns whether or not the form contains a Submit button named +button_name+
  def submit_button?(button_name)
    submits.find { |f| f.name == button_name }
  end

  # Returns whether or not the form contains a Reset button named +button_name+
  def reset_button?(button_name)
    resets.find { |f| f.name == button_name }
  end

  # Returns whether or not the form contains a Text field named +field_name+
  def text_field?(field_name)
    texts.find { |f| f.name == field_name }
  end

  # Returns whether or not the form contains a Hidden field named +field_name+
  def hidden_field?(field_name)
    hiddens.find { |f| f.name == field_name }
  end

  # Returns whether or not the form contains a Textarea named +field_name+
  def textarea_field?(field_name)
    textareas.find { |f| f.name == field_name }
  end

  # This method is a shortcut to get form's DOM id.
  # Common usage:
  #   page.form_with(:dom_id => "foorm")
  # Note that you can also use +:id+ to get to this method:
  #   page.form_with(:id => "foorm")
  def dom_id
    form_node['id']
  end

  # This method is a shortcut to get form's DOM class.
  # Common usage:
  #   page.form_with(:dom_class => "foorm")
  # Note that you can also use +:class+ to get to this method:
  #   page.form_with(:class => "foorm")
  def dom_class
    form_node['class']
  end

  # Add a field with +field_name+ and +value+
  def add_field!(field_name, value = nil)
    fields << Field.new({'name' => field_name}, value)
  end

  ##
  # This method sets multiple fields on the form.  It takes a list of +fields+
  # which are name, value pairs.
  #
  # If there is more than one field found with the same name, this method will
  # set the first one found.  If you want to set the value of a duplicate
  # field, use a value which is a Hash with the key as the index in to the
  # form.  The index is zero based.
  #
  # For example, to set the second field named 'foo', you could do the
  # following:
  #
  #   form.set_fields :foo => { 1 => 'bar' }
  def set_fields fields = {}
    fields.each do |name, v|
      case v
        when Hash
          v.each do |index, value|
            self.fields_with(:name => name.to_s)[index].value = value
          end
        else
          value = nil
          index = 0

          [v].flatten.each do |val|
            index = val.to_i if value
            value = val unless value
          end

          self.fields_with(:name => name.to_s)[index].value = value
      end
    end
  end

  # Fetch the value of the first input field with the name passed in. Example:
  #  puts form['name']
  def [](field_name)
    f = field(field_name)
    f && f.value
  end

  # Set the value of the first input field with the name passed in. Example:
  #  form['name'] = 'Aaron'
  def []=(field_name, value)
    f = field(field_name)
    if f
      f.value = value
    else
      add_field!(field_name, value)
    end
  end

end

#pretty_print(q) ⇒ Object

:nodoc:



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/metallize/form.rb', line 224

def pretty_print(q) # :nodoc:
  q.object_group(self) {
    q.breakable; q.group(1, '{name', '}') { q.breakable; q.pp name }
    q.breakable; q.group(1, '{method', '}') { q.breakable; q.pp method }
    q.breakable; q.group(1, '{action', '}') { q.breakable; q.pp action }
    q.breakable; q.group(1, '{fields', '}') {
      fields.each do |field|
        q.breakable
        q.pp field
      end
    }
    # q.breakable; q.group(1, '{radiobuttons', '}') {
    #   radiobuttons.each { |b| q.breakable; q.pp b }
    # }
    # q.breakable; q.group(1, '{checkboxes', '}') {
    #   checkboxes.each { |b| q.breakable; q.pp b }
    # }
    # q.breakable; q.group(1, '{file_uploads', '}') {
    #   file_uploads.each { |b| q.breakable; q.pp b }
    # }
    q.breakable; q.group(1, '{buttons', '}') {
      buttons.each { |b| q.breakable; q.pp b }
    }
  }
end

#reset_button?(button_name) ⇒ Boolean

Returns whether or not the form contains a Reset button named button_name

Returns:

  • (Boolean)


128
129
130
# File 'lib/metallize/form.rb', line 128

def reset_button?(button_name)
  resets.find { |f| f.name == button_name }
end

#resetsObject

Returns all buttons of type Reset



98
99
100
# File 'lib/metallize/form.rb', line 98

def resets
  @resets ||= buttons.select { |f| f.class == Reset }
end

#set_fields(fields = {}) ⇒ Object

This method sets multiple fields on the form. It takes a list of fields which are name, value pairs.

If there is more than one field found with the same name, this method will set the first one found. If you want to set the value of a duplicate field, use a value which is a Hash with the key as the index in to the form. The index is zero based.

For example, to set the second field named ‘foo’, you could do the following:

form.set_fields :foo => { 1 => 'bar' }


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/metallize/form.rb', line 183

def set_fields fields = {}
  fields.each do |name, v|
    case v
      when Hash
        v.each do |index, value|
          self.fields_with(:name => name.to_s)[index].value = value
        end
      else
        value = nil
        index = 0

        [v].flatten.each do |val|
          index = val.to_i if value
          value = val unless value
        end

        self.fields_with(:name => name.to_s)[index].value = value
    end
  end
end

#submitObject



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/metallize/form.rb', line 252

def submit
  # 1. Loop through the non hidden fields and if they're active and displayed enter the value
  @fields.each do |field|
    unless field.kind_of?(Metallize::Form::Hidden)

      element = @driver.find_element(name: field.name)
      if element.displayed? and !field.value.empty?
        element.send_keys field.value
      end

    end
  end

  # 2. Submit Form
  @buttons.first.node.click

  wait_for_page(@driver)

  # 4. Return new Page
  Metallize::Page.new(@driver)

end

#submit_button?(button_name) ⇒ Boolean

Returns whether or not the form contains a Submit button named button_name

Returns:

  • (Boolean)


123
124
125
# File 'lib/metallize/form.rb', line 123

def submit_button?(button_name)
  submits.find { |f| f.name == button_name }
end

#submitsObject

Returns all buttons of type Submit



93
94
95
# File 'lib/metallize/form.rb', line 93

def submits
  @submits ||= buttons.select { |f| f.class == Submit }
end

#text_field?(field_name) ⇒ Boolean

Returns whether or not the form contains a Text field named field_name

Returns:

  • (Boolean)


133
134
135
# File 'lib/metallize/form.rb', line 133

def text_field?(field_name)
  texts.find { |f| f.name == field_name }
end

#textarea_field?(field_name) ⇒ Boolean

Returns whether or not the form contains a Textarea named field_name

Returns:

  • (Boolean)


143
144
145
# File 'lib/metallize/form.rb', line 143

def textarea_field?(field_name)
  textareas.find { |f| f.name == field_name }
end

#textareasObject

Returns all fields of type Textarea



113
114
115
# File 'lib/metallize/form.rb', line 113

def textareas
  @textareas ||= fields.select { |f| f.class == Textarea }
end

#textsObject

Returns all fields of type Text



103
104
105
# File 'lib/metallize/form.rb', line 103

def texts
  @texts ||= fields.select { |f| f.class == Text }
end

#valuesObject

Returns all field values for this form



88
89
90
# File 'lib/metallize/form.rb', line 88

def values
  fields.map { |f| f.value }
end

#wait_for_page(driver) ⇒ Object



275
276
277
278
279
280
281
# File 'lib/metallize/form.rb', line 275

def wait_for_page(driver)
  # 3. Wait for the Page State to Return
  wait = Selenium::WebDriver::Wait.new(:timeout => 10)
  wait.until {
    driver.execute_script("return document.readyState;") == "complete"
  }
end