mkuklis-webrat 0.5.1
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.
- data/.document +4 -0
- data/.gitignore +15 -0
- data/History.txt +413 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +85 -0
- data/Rakefile +188 -0
- data/VERSION +1 -0
- data/install.rb +1 -0
- data/lib/webrat/adapters/mechanize.rb +78 -0
- data/lib/webrat/adapters/merb.rb +11 -0
- data/lib/webrat/adapters/rack.rb +25 -0
- data/lib/webrat/adapters/rails.rb +81 -0
- data/lib/webrat/adapters/sinatra.rb +9 -0
- data/lib/webrat/core/configuration.rb +92 -0
- data/lib/webrat/core/elements/area.rb +31 -0
- data/lib/webrat/core/elements/element.rb +33 -0
- data/lib/webrat/core/elements/field.rb +487 -0
- data/lib/webrat/core/elements/form.rb +103 -0
- data/lib/webrat/core/elements/label.rb +31 -0
- data/lib/webrat/core/elements/link.rb +93 -0
- data/lib/webrat/core/elements/select_option.rb +48 -0
- data/lib/webrat/core/locators/area_locator.rb +38 -0
- data/lib/webrat/core/locators/button_locator.rb +54 -0
- data/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
- data/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
- data/lib/webrat/core/locators/field_locator.rb +25 -0
- data/lib/webrat/core/locators/field_named_locator.rb +41 -0
- data/lib/webrat/core/locators/form_locator.rb +19 -0
- data/lib/webrat/core/locators/label_locator.rb +34 -0
- data/lib/webrat/core/locators/link_locator.rb +74 -0
- data/lib/webrat/core/locators/locator.rb +20 -0
- data/lib/webrat/core/locators/select_option_locator.rb +59 -0
- data/lib/webrat/core/locators.rb +20 -0
- data/lib/webrat/core/logging.rb +23 -0
- data/lib/webrat/core/matchers/have_content.rb +68 -0
- data/lib/webrat/core/matchers/have_selector.rb +74 -0
- data/lib/webrat/core/matchers/have_tag.rb +21 -0
- data/lib/webrat/core/matchers/have_xpath.rb +122 -0
- data/lib/webrat/core/matchers.rb +4 -0
- data/lib/webrat/core/methods.rb +64 -0
- data/lib/webrat/core/mime.rb +18 -0
- data/lib/webrat/core/save_and_open_page.rb +48 -0
- data/lib/webrat/core/scope.rb +365 -0
- data/lib/webrat/core/session.rb +306 -0
- data/lib/webrat/core/xml.rb +72 -0
- data/lib/webrat/core.rb +13 -0
- data/lib/webrat/core_extensions/blank.rb +58 -0
- data/lib/webrat/core_extensions/deprecate.rb +8 -0
- data/lib/webrat/core_extensions/detect_mapped.rb +12 -0
- data/lib/webrat/core_extensions/meta_class.rb +6 -0
- data/lib/webrat/core_extensions/nil_to_param.rb +5 -0
- data/lib/webrat/core_extensions/tcp_socket.rb +27 -0
- data/lib/webrat/integrations/merb.rb +10 -0
- data/lib/webrat/integrations/rails.rb +25 -0
- data/lib/webrat/integrations/rspec-rails.rb +10 -0
- data/lib/webrat/integrations/selenium.rb +11 -0
- data/lib/webrat/merb.rb +9 -0
- data/lib/webrat/rspec-rails.rb +2 -0
- data/lib/webrat/selenium/application_server_factory.rb +40 -0
- data/lib/webrat/selenium/application_servers/base.rb +54 -0
- data/lib/webrat/selenium/application_servers/external.rb +26 -0
- data/lib/webrat/selenium/application_servers/merb.rb +50 -0
- data/lib/webrat/selenium/application_servers/rails.rb +67 -0
- data/lib/webrat/selenium/application_servers/sinatra.rb +37 -0
- data/lib/webrat/selenium/application_servers.rb +5 -0
- data/lib/webrat/selenium/location_strategy_javascript/button.js +19 -0
- data/lib/webrat/selenium/location_strategy_javascript/label.js +42 -0
- data/lib/webrat/selenium/location_strategy_javascript/webrat.js +6 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratlink.js +32 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
- data/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
- data/lib/webrat/selenium/matchers/have_content.rb +66 -0
- data/lib/webrat/selenium/matchers/have_selector.rb +49 -0
- data/lib/webrat/selenium/matchers/have_tag.rb +72 -0
- data/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
- data/lib/webrat/selenium/matchers.rb +4 -0
- data/lib/webrat/selenium/selenium_extensions.js +6 -0
- data/lib/webrat/selenium/selenium_rc_server.rb +86 -0
- data/lib/webrat/selenium/selenium_session.rb +272 -0
- data/lib/webrat/selenium/silence_stream.rb +18 -0
- data/lib/webrat/selenium.rb +70 -0
- data/lib/webrat.rb +18 -0
- data/spec/fakes/test_adapter.rb +37 -0
- data/spec/integration/mechanize/Rakefile +7 -0
- data/spec/integration/mechanize/config.ru +2 -0
- data/spec/integration/mechanize/sample_app.rb +20 -0
- data/spec/integration/mechanize/spec/mechanize_spec.rb +22 -0
- data/spec/integration/mechanize/spec/spec_helper.rb +27 -0
- data/spec/integration/merb/.gitignore +21 -0
- data/spec/integration/merb/Rakefile +35 -0
- data/spec/integration/merb/app/controllers/application.rb +2 -0
- data/spec/integration/merb/app/controllers/exceptions.rb +13 -0
- data/spec/integration/merb/app/controllers/testing.rb +27 -0
- data/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb +63 -0
- data/spec/integration/merb/app/views/exceptions/not_found.html.erb +47 -0
- data/spec/integration/merb/app/views/layout/application.html.erb +12 -0
- data/spec/integration/merb/app/views/testing/show_form.html.erb +27 -0
- data/spec/integration/merb/app/views/testing/upload.html.erb +9 -0
- data/spec/integration/merb/config/environments/development.rb +15 -0
- data/spec/integration/merb/config/environments/rake.rb +11 -0
- data/spec/integration/merb/config/environments/test.rb +14 -0
- data/spec/integration/merb/config/init.rb +25 -0
- data/spec/integration/merb/config/rack.rb +11 -0
- data/spec/integration/merb/config/router.rb +34 -0
- data/spec/integration/merb/spec/spec.opts +1 -0
- data/spec/integration/merb/spec/spec_helper.rb +26 -0
- data/spec/integration/merb/spec/webrat_spec.rb +39 -0
- data/spec/integration/merb/tasks/merb.thor/app_script.rb +31 -0
- data/spec/integration/merb/tasks/merb.thor/common.rb +64 -0
- data/spec/integration/merb/tasks/merb.thor/gem_ext.rb +124 -0
- data/spec/integration/merb/tasks/merb.thor/main.thor +150 -0
- data/spec/integration/merb/tasks/merb.thor/ops.rb +93 -0
- data/spec/integration/merb/tasks/merb.thor/utils.rb +40 -0
- data/spec/integration/rack/Rakefile +5 -0
- data/spec/integration/rack/app.rb +89 -0
- data/spec/integration/rack/test/helper.rb +21 -0
- data/spec/integration/rack/test/webrat_rack_test.rb +73 -0
- data/spec/integration/rails/.gitignore +3 -0
- data/spec/integration/rails/Rakefile +30 -0
- data/spec/integration/rails/app/controllers/application.rb +15 -0
- data/spec/integration/rails/app/controllers/buttons_controller.rb +7 -0
- data/spec/integration/rails/app/controllers/fields_controller.rb +4 -0
- data/spec/integration/rails/app/controllers/links_controller.rb +7 -0
- data/spec/integration/rails/app/controllers/webrat_controller.rb +46 -0
- data/spec/integration/rails/app/helpers/buttons_helper.rb +2 -0
- data/spec/integration/rails/app/helpers/fields_helper.rb +2 -0
- data/spec/integration/rails/app/helpers/links_helper.rb +2 -0
- data/spec/integration/rails/app/views/buttons/show.html.erb +11 -0
- data/spec/integration/rails/app/views/fields/show.html.erb +9 -0
- data/spec/integration/rails/app/views/links/show.html.erb +5 -0
- data/spec/integration/rails/app/views/webrat/before_redirect_form.html.erb +4 -0
- data/spec/integration/rails/app/views/webrat/buttons.html.erb +11 -0
- data/spec/integration/rails/app/views/webrat/form.html.erb +28 -0
- data/spec/integration/rails/app/views/webrat/within.html.erb +3 -0
- data/spec/integration/rails/config/boot.rb +109 -0
- data/spec/integration/rails/config/environment.rb +12 -0
- data/spec/integration/rails/config/environments/development.rb +17 -0
- data/spec/integration/rails/config/environments/selenium.rb +22 -0
- data/spec/integration/rails/config/environments/test.rb +22 -0
- data/spec/integration/rails/config/initializers/inflections.rb +10 -0
- data/spec/integration/rails/config/initializers/mime_types.rb +5 -0
- data/spec/integration/rails/config/initializers/new_rails_defaults.rb +17 -0
- data/spec/integration/rails/config/locales/en.yml +5 -0
- data/spec/integration/rails/config/routes.rb +19 -0
- data/spec/integration/rails/public/404.html +30 -0
- data/spec/integration/rails/public/422.html +30 -0
- data/spec/integration/rails/public/500.html +33 -0
- data/spec/integration/rails/script/about +4 -0
- data/spec/integration/rails/script/console +3 -0
- data/spec/integration/rails/script/dbconsole +3 -0
- data/spec/integration/rails/script/destroy +3 -0
- data/spec/integration/rails/script/generate +3 -0
- data/spec/integration/rails/script/performance/benchmarker +3 -0
- data/spec/integration/rails/script/performance/profiler +3 -0
- data/spec/integration/rails/script/performance/request +3 -0
- data/spec/integration/rails/script/plugin +3 -0
- data/spec/integration/rails/script/process/inspector +3 -0
- data/spec/integration/rails/script/process/reaper +3 -0
- data/spec/integration/rails/script/process/spawner +3 -0
- data/spec/integration/rails/script/runner +3 -0
- data/spec/integration/rails/script/server +3 -0
- data/spec/integration/rails/test/integration/button_click_test.rb +80 -0
- data/spec/integration/rails/test/integration/fill_in_test.rb +24 -0
- data/spec/integration/rails/test/integration/link_click_test.rb +27 -0
- data/spec/integration/rails/test/integration/webrat_test.rb +122 -0
- data/spec/integration/rails/test/test_helper.rb +26 -0
- data/spec/integration/sinatra/Rakefile +5 -0
- data/spec/integration/sinatra/classic_app.rb +64 -0
- data/spec/integration/sinatra/modular_app.rb +16 -0
- data/spec/integration/sinatra/test/classic_app_test.rb +37 -0
- data/spec/integration/sinatra/test/modular_app_test.rb +18 -0
- data/spec/integration/sinatra/test/test_helper.rb +17 -0
- data/spec/private/core/configuration_spec.rb +87 -0
- data/spec/private/core/field_spec.rb +85 -0
- data/spec/private/core/link_spec.rb +24 -0
- data/spec/private/core/session_spec.rb +200 -0
- data/spec/private/mechanize/mechanize_adapter_spec.rb +73 -0
- data/spec/private/nokogiri_spec.rb +77 -0
- data/spec/private/rails/attaches_file_spec.rb +81 -0
- data/spec/private/rails/rails_adapter_spec.rb +86 -0
- data/spec/private/selenium/application_servers/rails_spec.rb +26 -0
- data/spec/public/basic_auth_spec.rb +24 -0
- data/spec/public/check_spec.rb +191 -0
- data/spec/public/choose_spec.rb +118 -0
- data/spec/public/click_area_spec.rb +106 -0
- data/spec/public/click_button_spec.rb +494 -0
- data/spec/public/click_link_spec.rb +511 -0
- data/spec/public/fill_in_spec.rb +224 -0
- data/spec/public/locators/field_by_xpath_spec.rb +19 -0
- data/spec/public/locators/field_labeled_spec.rb +172 -0
- data/spec/public/locators/field_with_id_spec.rb +16 -0
- data/spec/public/matchers/contain_spec.rb +114 -0
- data/spec/public/matchers/have_selector_spec.rb +146 -0
- data/spec/public/matchers/have_tag_spec.rb +39 -0
- data/spec/public/matchers/have_xpath_spec.rb +136 -0
- data/spec/public/reload_spec.rb +10 -0
- data/spec/public/save_and_open_spec.rb +70 -0
- data/spec/public/select_date_spec.rb +112 -0
- data/spec/public/select_datetime_spec.rb +137 -0
- data/spec/public/select_spec.rb +455 -0
- data/spec/public/select_time_spec.rb +100 -0
- data/spec/public/selenium/application_server_factory_spec.rb +49 -0
- data/spec/public/selenium/application_servers/external_spec.rb +12 -0
- data/spec/public/selenium/selenium_session_spec.rb +37 -0
- data/spec/public/set_hidden_field_spec.rb +5 -0
- data/spec/public/submit_form_spec.rb +5 -0
- data/spec/public/visit_spec.rb +58 -0
- data/spec/public/within_spec.rb +177 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +54 -0
- data/vendor/selenium-server.jar +0 -0
- metadata +409 -0
@@ -0,0 +1,487 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "webrat/core_extensions/blank"
|
3
|
+
require "webrat/core_extensions/nil_to_param"
|
4
|
+
|
5
|
+
require "webrat/core/elements/element"
|
6
|
+
|
7
|
+
module Webrat
|
8
|
+
# Raised when Webrat is asked to manipulate a disabled form field
|
9
|
+
class DisabledFieldError < WebratError
|
10
|
+
end
|
11
|
+
|
12
|
+
class Field < Element #:nodoc:
|
13
|
+
attr_reader :value
|
14
|
+
|
15
|
+
def self.xpath_search
|
16
|
+
[".//button", ".//input", ".//textarea", ".//select"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.xpath_search_excluding_hidden
|
20
|
+
[".//button", ".//input[ @type != 'hidden']", ".//textarea", ".//select"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.field_classes
|
24
|
+
@field_classes || []
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.inherited(klass)
|
28
|
+
@field_classes ||= []
|
29
|
+
@field_classes << klass
|
30
|
+
# raise args.inspect
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.load(session, element)
|
34
|
+
return nil if element.nil?
|
35
|
+
session.elements[element.path] ||= field_class(element).new(session, element)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.field_class(element)
|
39
|
+
case element.name
|
40
|
+
when "button" then ButtonField
|
41
|
+
when "select"
|
42
|
+
if element.attributes["multiple"].nil?
|
43
|
+
SelectField
|
44
|
+
else
|
45
|
+
MultipleSelectField
|
46
|
+
end
|
47
|
+
when "textarea" then TextareaField
|
48
|
+
else
|
49
|
+
case element["type"]
|
50
|
+
when "checkbox" then CheckboxField
|
51
|
+
when "hidden" then HiddenField
|
52
|
+
when "radio" then RadioField
|
53
|
+
when "password" then PasswordField
|
54
|
+
when "file" then FileField
|
55
|
+
when "reset" then ResetField
|
56
|
+
when "submit" then ButtonField
|
57
|
+
when "button" then ButtonField
|
58
|
+
when "image" then ButtonField
|
59
|
+
else TextField
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(*args)
|
65
|
+
super
|
66
|
+
@value = default_value
|
67
|
+
end
|
68
|
+
|
69
|
+
def label_text
|
70
|
+
return nil if labels.empty?
|
71
|
+
labels.first.text
|
72
|
+
end
|
73
|
+
|
74
|
+
def id
|
75
|
+
@element["id"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def disabled?
|
79
|
+
@element.attributes.has_key?("disabled") && @element["disabled"] != 'false'
|
80
|
+
end
|
81
|
+
|
82
|
+
def raise_error_if_disabled
|
83
|
+
return unless disabled?
|
84
|
+
raise DisabledFieldError.new("Cannot interact with disabled form element (#{self})")
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_param
|
88
|
+
return nil if disabled?
|
89
|
+
|
90
|
+
params = case Webrat.configuration.mode
|
91
|
+
when :rails
|
92
|
+
parse_rails_request_params("#{name}=#{escaped_value}")
|
93
|
+
when :merb
|
94
|
+
::Merb::Parse.query("#{name}=#{escaped_value}")
|
95
|
+
else
|
96
|
+
{ name => [*@value].first.to_s }
|
97
|
+
end
|
98
|
+
|
99
|
+
unescape_params(params)
|
100
|
+
end
|
101
|
+
|
102
|
+
def set(value)
|
103
|
+
@value = value
|
104
|
+
end
|
105
|
+
|
106
|
+
def unset
|
107
|
+
@value = default_value
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
def parse_rails_request_params(params)
|
113
|
+
if defined?(ActionController::AbstractRequest)
|
114
|
+
ActionController::AbstractRequest.parse_query_parameters(params)
|
115
|
+
elsif defined?(ActionController::UrlEncodedPairParser)
|
116
|
+
# For Rails > 2.2
|
117
|
+
ActionController::UrlEncodedPairParser.parse_query_parameters(params)
|
118
|
+
else
|
119
|
+
# For Rails > 2.3
|
120
|
+
Rack::Utils.parse_nested_query(params)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def form
|
125
|
+
Form.load(@session, form_element)
|
126
|
+
end
|
127
|
+
|
128
|
+
def form_element
|
129
|
+
parent = @element.parent
|
130
|
+
|
131
|
+
while parent.respond_to?(:parent)
|
132
|
+
return parent if parent.name == 'form'
|
133
|
+
parent = parent.parent
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def name
|
138
|
+
@element["name"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def escaped_value
|
142
|
+
CGI.escape(@value.to_s)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Because we have to escape it before sending it to the above case statement,
|
146
|
+
# we have to make sure we unescape each value when it gets back so assertions
|
147
|
+
# involving characters like <, >, and & work as expected
|
148
|
+
def unescape_params(params)
|
149
|
+
case params.class.name
|
150
|
+
when 'Hash', 'Mash'
|
151
|
+
params.each { |key,value| params[key] = unescape_params(value) }
|
152
|
+
params
|
153
|
+
when 'Array'
|
154
|
+
params.collect { |value| unescape_params(value) }
|
155
|
+
else
|
156
|
+
CGI.unescapeHTML(params)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def labels
|
161
|
+
@labels ||= label_elements.map do |element|
|
162
|
+
Label.load(@session, element)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def label_elements
|
167
|
+
return @label_elements unless @label_elements.nil?
|
168
|
+
@label_elements = []
|
169
|
+
|
170
|
+
parent = @element.parent
|
171
|
+
while parent.respond_to?(:parent)
|
172
|
+
if parent.name == 'label'
|
173
|
+
@label_elements.push parent
|
174
|
+
break
|
175
|
+
end
|
176
|
+
parent = parent.parent
|
177
|
+
end
|
178
|
+
|
179
|
+
unless id.blank?
|
180
|
+
@label_elements += form.element.xpath(".//label[@for = '#{id}']")
|
181
|
+
end
|
182
|
+
|
183
|
+
@label_elements
|
184
|
+
end
|
185
|
+
|
186
|
+
def default_value
|
187
|
+
@element["value"]
|
188
|
+
end
|
189
|
+
|
190
|
+
def replace_param_value(params, oval, nval)
|
191
|
+
output = Hash.new
|
192
|
+
params.each do |key, value|
|
193
|
+
case value
|
194
|
+
when Hash
|
195
|
+
value = replace_param_value(value, oval, nval)
|
196
|
+
when Array
|
197
|
+
value = value.map { |o| o == oval ? nval : oval }
|
198
|
+
when oval
|
199
|
+
value = nval
|
200
|
+
end
|
201
|
+
output[key] = value
|
202
|
+
end
|
203
|
+
output
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class ButtonField < Field #:nodoc:
|
208
|
+
|
209
|
+
def self.xpath_search
|
210
|
+
[".//button", ".//input[@type = 'submit']", ".//input[@type = 'button']", ".//input[@type = 'image']"]
|
211
|
+
end
|
212
|
+
|
213
|
+
def to_param
|
214
|
+
return nil if @value.nil?
|
215
|
+
super
|
216
|
+
end
|
217
|
+
|
218
|
+
def default_value
|
219
|
+
nil
|
220
|
+
end
|
221
|
+
|
222
|
+
def click
|
223
|
+
raise_error_if_disabled
|
224
|
+
set(@element["value"]) unless @element["name"].blank?
|
225
|
+
form.submit
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
class HiddenField < Field #:nodoc:
|
231
|
+
|
232
|
+
def self.xpath_search
|
233
|
+
".//input[@type = 'hidden']"
|
234
|
+
end
|
235
|
+
|
236
|
+
def to_param
|
237
|
+
if collection_name?
|
238
|
+
super
|
239
|
+
else
|
240
|
+
checkbox_with_same_name = form.field_named(name, CheckboxField)
|
241
|
+
|
242
|
+
if checkbox_with_same_name.to_param.blank?
|
243
|
+
super
|
244
|
+
else
|
245
|
+
nil
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
protected
|
251
|
+
|
252
|
+
def collection_name?
|
253
|
+
name =~ /\[\]/
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
class CheckboxField < Field #:nodoc:
|
259
|
+
|
260
|
+
def self.xpath_search
|
261
|
+
".//input[@type = 'checkbox']"
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_param
|
265
|
+
return nil if @value.nil?
|
266
|
+
super
|
267
|
+
end
|
268
|
+
|
269
|
+
def check
|
270
|
+
raise_error_if_disabled
|
271
|
+
set(@element["value"] || "on")
|
272
|
+
end
|
273
|
+
|
274
|
+
def checked?
|
275
|
+
@element["checked"] == "checked"
|
276
|
+
end
|
277
|
+
|
278
|
+
def uncheck
|
279
|
+
raise_error_if_disabled
|
280
|
+
set(nil)
|
281
|
+
end
|
282
|
+
|
283
|
+
protected
|
284
|
+
|
285
|
+
def default_value
|
286
|
+
if @element["checked"] == "checked"
|
287
|
+
@element["value"] || "on"
|
288
|
+
else
|
289
|
+
nil
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
class PasswordField < Field #:nodoc:
|
296
|
+
|
297
|
+
def self.xpath_search
|
298
|
+
".//input[@type = 'password']"
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
class RadioField < Field #:nodoc:
|
304
|
+
|
305
|
+
def self.xpath_search
|
306
|
+
".//input[@type = 'radio']"
|
307
|
+
end
|
308
|
+
|
309
|
+
def to_param
|
310
|
+
return nil if @value.nil?
|
311
|
+
super
|
312
|
+
end
|
313
|
+
|
314
|
+
def choose
|
315
|
+
raise_error_if_disabled
|
316
|
+
other_options.each do |option|
|
317
|
+
option.set(nil)
|
318
|
+
end
|
319
|
+
|
320
|
+
set(@element["value"] || "on")
|
321
|
+
end
|
322
|
+
|
323
|
+
def checked?
|
324
|
+
@element["checked"] == "checked"
|
325
|
+
end
|
326
|
+
|
327
|
+
protected
|
328
|
+
|
329
|
+
def other_options
|
330
|
+
form.fields.select { |f| f.name == name }
|
331
|
+
end
|
332
|
+
|
333
|
+
def default_value
|
334
|
+
if @element["checked"] == "checked"
|
335
|
+
@element["value"] || "on"
|
336
|
+
else
|
337
|
+
nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
class TextareaField < Field #:nodoc:
|
344
|
+
|
345
|
+
def self.xpath_search
|
346
|
+
".//textarea"
|
347
|
+
end
|
348
|
+
|
349
|
+
protected
|
350
|
+
|
351
|
+
def default_value
|
352
|
+
@element.inner_html
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
class FileField < Field #:nodoc:
|
358
|
+
|
359
|
+
def self.xpath_search
|
360
|
+
".//input[@type = 'file']"
|
361
|
+
end
|
362
|
+
|
363
|
+
attr_accessor :content_type
|
364
|
+
|
365
|
+
def set(value, content_type = nil)
|
366
|
+
super(value)
|
367
|
+
@content_type = content_type
|
368
|
+
end
|
369
|
+
|
370
|
+
def to_param
|
371
|
+
if @value.nil?
|
372
|
+
super
|
373
|
+
else
|
374
|
+
replace_param_value(super, @value, test_uploaded_file)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
protected
|
379
|
+
|
380
|
+
def test_uploaded_file
|
381
|
+
case Webrat.configuration.mode
|
382
|
+
when :rails
|
383
|
+
if content_type
|
384
|
+
ActionController::TestUploadedFile.new(@value, content_type)
|
385
|
+
else
|
386
|
+
ActionController::TestUploadedFile.new(@value)
|
387
|
+
end
|
388
|
+
when :rack, :merb
|
389
|
+
Rack::Test::UploadedFile.new(@value, content_type)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
class TextField < Field #:nodoc:
|
396
|
+
def self.xpath_search
|
397
|
+
[".//input[@type = 'text']", ".//input[not(@type)]"]
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
class ResetField < Field #:nodoc:
|
402
|
+
def self.xpath_search
|
403
|
+
[".//input[@type = 'reset']"]
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
class SelectField < Field #:nodoc:
|
408
|
+
|
409
|
+
def self.xpath_search
|
410
|
+
[".//select[not(@multiple)]"]
|
411
|
+
end
|
412
|
+
|
413
|
+
def options
|
414
|
+
@options ||= SelectOption.load_all(@session, @element)
|
415
|
+
end
|
416
|
+
|
417
|
+
def unset(value)
|
418
|
+
@value = nil
|
419
|
+
end
|
420
|
+
|
421
|
+
protected
|
422
|
+
|
423
|
+
def default_value
|
424
|
+
selected_options = @element.xpath(".//option[@selected = 'selected']")
|
425
|
+
selected_options = @element.xpath(".//option[position() = 1]") if selected_options.empty?
|
426
|
+
|
427
|
+
selected_options.map do |option|
|
428
|
+
return "" if option.nil?
|
429
|
+
option["value"] || option.inner_html
|
430
|
+
end.uniq.first
|
431
|
+
end
|
432
|
+
|
433
|
+
end
|
434
|
+
|
435
|
+
class MultipleSelectField < Field #:nodoc:
|
436
|
+
|
437
|
+
def self.xpath_search
|
438
|
+
[".//select[@multiple='multiple']"]
|
439
|
+
end
|
440
|
+
|
441
|
+
def options
|
442
|
+
@options ||= SelectOption.load_all(@session, @element)
|
443
|
+
end
|
444
|
+
|
445
|
+
def set(value)
|
446
|
+
@value << value
|
447
|
+
end
|
448
|
+
|
449
|
+
def unset(value)
|
450
|
+
@value.delete(value)
|
451
|
+
end
|
452
|
+
|
453
|
+
# We have to overide how the uri string is formed when dealing with multiples
|
454
|
+
# Where normally a select field might produce name=value with a multiple,
|
455
|
+
# we need to form something like name[]=value1&name[]=value2
|
456
|
+
def to_param
|
457
|
+
return nil if disabled?
|
458
|
+
|
459
|
+
uri_string = @value.collect {|value| "#{name}=#{CGI.escape(value)}"}.join("&")
|
460
|
+
params = case Webrat.configuration.mode
|
461
|
+
when :rails
|
462
|
+
parse_rails_request_params(uri_string)
|
463
|
+
when :merb
|
464
|
+
::Merb::Parse.query(uri_string)
|
465
|
+
else
|
466
|
+
{ name => @value }
|
467
|
+
end
|
468
|
+
|
469
|
+
unescape_params(params)
|
470
|
+
end
|
471
|
+
|
472
|
+
protected
|
473
|
+
|
474
|
+
# Overwrite SelectField definition because we don't want to select the first option
|
475
|
+
# (mutliples don't select the first option unlike their non multiple versions)
|
476
|
+
def default_value
|
477
|
+
selected_options = @element.xpath(".//option[@selected = 'selected']")
|
478
|
+
|
479
|
+
selected_options.map do |option|
|
480
|
+
return "" if option.nil?
|
481
|
+
option["value"] || option.inner_html
|
482
|
+
end.uniq
|
483
|
+
end
|
484
|
+
|
485
|
+
end
|
486
|
+
|
487
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require "webrat/core/elements/field"
|
2
|
+
require "webrat/core_extensions/blank"
|
3
|
+
|
4
|
+
require "webrat/core/elements/element"
|
5
|
+
require "webrat/core/locators/field_named_locator"
|
6
|
+
|
7
|
+
module Webrat
|
8
|
+
class Form < Element #:nodoc:
|
9
|
+
attr_reader :element
|
10
|
+
|
11
|
+
def self.xpath_search
|
12
|
+
[".//form"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def fields
|
16
|
+
@fields ||= Field.load_all(@session, @element)
|
17
|
+
end
|
18
|
+
|
19
|
+
def submit
|
20
|
+
@session.request_page(form_action, form_method, params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def field_named(name, *field_types)
|
24
|
+
Webrat::Locators::FieldNamedLocator.new(@session, dom, name, *field_types).locate
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def dom
|
30
|
+
@session.dom.xpath(path).first
|
31
|
+
end
|
32
|
+
|
33
|
+
def fields_by_type(field_types)
|
34
|
+
if field_types.any?
|
35
|
+
fields.select { |f| field_types.include?(f.class) }
|
36
|
+
else
|
37
|
+
fields
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def params
|
42
|
+
all_params = {}
|
43
|
+
|
44
|
+
fields.each do |field|
|
45
|
+
next if field.to_param.nil?
|
46
|
+
merge(all_params, field.to_param)
|
47
|
+
end
|
48
|
+
|
49
|
+
all_params
|
50
|
+
end
|
51
|
+
|
52
|
+
def form_method
|
53
|
+
@element["method"].blank? ? :get : @element["method"].downcase
|
54
|
+
end
|
55
|
+
|
56
|
+
def form_action
|
57
|
+
@element["action"].blank? ? @session.current_url : @element["action"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def merge(all_params, new_param)
|
61
|
+
new_param.each do |key, value|
|
62
|
+
case all_params[key]
|
63
|
+
when *hash_classes
|
64
|
+
merge_hash_values(all_params[key], value)
|
65
|
+
when Array
|
66
|
+
all_params[key] += value
|
67
|
+
else
|
68
|
+
all_params[key] = value
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def merge_hash_values(a, b) # :nodoc:
|
74
|
+
a.keys.each do |k|
|
75
|
+
if b.has_key?(k)
|
76
|
+
case [a[k], b[k]].map{|value| value.class}
|
77
|
+
when *hash_classes.zip(hash_classes)
|
78
|
+
a[k] = merge_hash_values(a[k], b[k])
|
79
|
+
b.delete(k)
|
80
|
+
when [Array, Array]
|
81
|
+
a[k] += b[k]
|
82
|
+
b.delete(k)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
a.merge!(b)
|
87
|
+
end
|
88
|
+
|
89
|
+
def hash_classes
|
90
|
+
klasses = [Hash]
|
91
|
+
|
92
|
+
case Webrat.configuration.mode
|
93
|
+
when :rails
|
94
|
+
klasses << HashWithIndifferentAccess
|
95
|
+
when :merb
|
96
|
+
klasses << Mash
|
97
|
+
end
|
98
|
+
|
99
|
+
klasses
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "webrat/core/elements/element"
|
2
|
+
|
3
|
+
module Webrat
|
4
|
+
class Label < Element #:nodoc:
|
5
|
+
|
6
|
+
attr_reader :element
|
7
|
+
|
8
|
+
def self.xpath_search
|
9
|
+
[".//label"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def for_id
|
13
|
+
@element["for"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def field
|
17
|
+
Field.load(@session, field_element)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def field_element
|
23
|
+
if for_id.blank?
|
24
|
+
@element.xpath(*Field.xpath_search_excluding_hidden).first
|
25
|
+
else
|
26
|
+
@session.current_dom.css("#" + for_id).first
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "English"
|
2
|
+
|
3
|
+
require "webrat/core_extensions/blank"
|
4
|
+
require "webrat/core/elements/element"
|
5
|
+
|
6
|
+
module Webrat
|
7
|
+
class Link < Element #:nodoc:
|
8
|
+
|
9
|
+
def self.xpath_search
|
10
|
+
[".//a[@href]"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def click(options = {})
|
14
|
+
method = options[:method] || http_method
|
15
|
+
return if href =~ /^#/ && method == :get
|
16
|
+
|
17
|
+
options[:javascript] = true if options[:javascript].nil?
|
18
|
+
|
19
|
+
if options[:javascript]
|
20
|
+
@session.request_page(absolute_href, method, data)
|
21
|
+
else
|
22
|
+
@session.request_page(absolute_href, :get, {})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def id
|
29
|
+
@element["id"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def data
|
33
|
+
authenticity_token.blank? ? {} : {"authenticity_token" => authenticity_token}
|
34
|
+
end
|
35
|
+
|
36
|
+
def title
|
37
|
+
@element["title"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def href
|
41
|
+
@element["href"]
|
42
|
+
end
|
43
|
+
|
44
|
+
def absolute_href
|
45
|
+
if href =~ /^\?/
|
46
|
+
"#{@session.current_url}#{href}"
|
47
|
+
elsif href !~ %r{^https?://} && (href !~ /^\//)
|
48
|
+
"#{@session.current_url}/#{href}"
|
49
|
+
else
|
50
|
+
href
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def authenticity_token
|
55
|
+
return unless onclick && onclick.include?("s.setAttribute('name', 'authenticity_token');") &&
|
56
|
+
onclick =~ /s\.setAttribute\('value', '([a-f0-9]{40})'\);/
|
57
|
+
$LAST_MATCH_INFO.captures.first
|
58
|
+
end
|
59
|
+
|
60
|
+
def onclick
|
61
|
+
@element["onclick"]
|
62
|
+
end
|
63
|
+
|
64
|
+
def http_method
|
65
|
+
if !onclick.blank? && onclick.include?("f.submit()")
|
66
|
+
http_method_from_js_form
|
67
|
+
else
|
68
|
+
:get
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def http_method_from_js_form
|
73
|
+
if onclick.include?("m.setAttribute('name', '_method')")
|
74
|
+
http_method_from_fake_method_param
|
75
|
+
else
|
76
|
+
:post
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def http_method_from_fake_method_param
|
81
|
+
if onclick.include?("m.setAttribute('value', 'delete')")
|
82
|
+
:delete
|
83
|
+
elsif onclick.include?("m.setAttribute('value', 'put')")
|
84
|
+
:put
|
85
|
+
elsif onclick.include?("m.setAttribute('value', 'post')")
|
86
|
+
:post
|
87
|
+
else
|
88
|
+
raise Webrat::WebratError.new("No HTTP method for _method param in #{onclick.inspect}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|