webrat 0.7.0 → 0.7.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.
Files changed (40) hide show
  1. data/Gemfile +0 -6
  2. data/History.txt +17 -0
  3. data/Rakefile +7 -9
  4. data/lib/webrat.rb +1 -1
  5. data/lib/webrat/adapters/mechanize.rb +22 -6
  6. data/lib/webrat/adapters/rack.rb +4 -0
  7. data/lib/webrat/adapters/rails.rb +4 -0
  8. data/lib/webrat/core/configuration.rb +16 -1
  9. data/lib/webrat/core/elements/field.rb +40 -89
  10. data/lib/webrat/core/elements/form.rb +55 -31
  11. data/lib/webrat/core/locators/form_locator.rb +1 -1
  12. data/lib/webrat/core/matchers/have_xpath.rb +4 -2
  13. data/lib/webrat/core/methods.rb +1 -1
  14. data/lib/webrat/core/mime.rb +2 -2
  15. data/lib/webrat/core/scope.rb +1 -0
  16. data/lib/webrat/core/session.rb +4 -3
  17. data/lib/webrat/core_extensions/{nil_to_param.rb → nil_to_query_string.rb} +1 -1
  18. data/lib/webrat/selenium/location_strategy_javascript/label.js +9 -3
  19. data/lib/webrat/selenium/selenium_rc_server.rb +4 -1
  20. data/lib/webrat/selenium/selenium_session.rb +9 -4
  21. data/spec/fakes/test_adapter.rb +1 -1
  22. data/spec/integration/mechanize/sample_app.rb +16 -1
  23. data/spec/integration/mechanize/spec/mechanize_spec.rb +9 -1
  24. data/spec/integration/rack/app.rb +2 -2
  25. data/spec/integration/rack/test/helper.rb +0 -1
  26. data/spec/integration/rack/test/webrat_rack_test.rb +3 -2
  27. data/spec/integration/sinatra/classic_app.rb +0 -1
  28. data/spec/integration/sinatra/modular_app.rb +0 -1
  29. data/spec/integration/sinatra/test/classic_app_test.rb +1 -0
  30. data/spec/integration/sinatra/test/test_helper.rb +0 -1
  31. data/spec/private/core/field_spec.rb +1 -1
  32. data/spec/private/core/form_spec.rb +51 -0
  33. data/spec/private/core/session_spec.rb +5 -18
  34. data/spec/private/mechanize/mechanize_adapter_spec.rb +24 -1
  35. data/spec/private/rails/attaches_file_spec.rb +33 -0
  36. data/spec/public/matchers/have_xpath_spec.rb +6 -0
  37. data/spec/public/submit_form_spec.rb +52 -1
  38. data/spec/spec_helper.rb +0 -1
  39. data/webrat.gemspec +6 -4
  40. metadata +38 -18
@@ -38,15 +38,24 @@ module Webrat
38
38
  end
39
39
  end
40
40
 
41
+ # iterate over all form fields to build a request querystring to get params from it,
42
+ # for file_field we made a work around to pass a digest as value to later replace it
43
+ # in params hash with the real file.
41
44
  def params
42
- all_params = {}
45
+ query_string = []
46
+ replaces = {}
43
47
 
44
48
  fields.each do |field|
45
- next if field.to_param.nil?
46
- merge(all_params, field.to_param)
49
+ next if field.to_query_string.nil?
50
+ replaces.merge!({field.digest_value => field.test_uploaded_file}) if field.is_a?(FileField)
51
+ query_string << field.to_query_string
47
52
  end
48
53
 
49
- all_params
54
+ query_params = self.class.query_string_to_params(query_string.join('&'))
55
+
56
+ query_params = self.class.replace_params_values(query_params, replaces)
57
+
58
+ self.class.unescape_params(query_params)
50
59
  end
51
60
 
52
61
  def form_method
@@ -57,47 +66,62 @@ module Webrat
57
66
  @element["action"].blank? ? @session.current_url : @element["action"]
58
67
  end
59
68
 
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)
69
+ def self.replace_param_value(params, oval, nval)
70
+ output = Hash.new
71
+ params.each do |key, value|
72
+ case value
73
+ when Hash
74
+ value = replace_param_value(value, oval, nval)
65
75
  when Array
66
- all_params[key] += value
67
- else
68
- all_params[key] = value
76
+ value = value.map { |o| o == oval ? nval : ( o.is_a?(Hash) ? replace_param_value(o, oval, nval) : o) }
77
+ when oval
78
+ value = nval
69
79
  end
80
+ output[key] = value
70
81
  end
82
+ output
71
83
  end
72
84
 
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
+ def self.replace_params_values(params, values)
86
+ values.each do |key, value|
87
+ params = replace_param_value(params, key, value)
85
88
  end
86
- a.merge!(b)
89
+ params
87
90
  end
88
91
 
89
- def hash_classes
90
- klasses = [Hash]
92
+ def self.unescape_params(params)
93
+ case params.class.name
94
+ when 'Hash', 'Mash'
95
+ params.each { |key,value| params[key] = unescape_params(value) }
96
+ params
97
+ when 'Array'
98
+ params.collect { |value| unescape_params(value) }
99
+ else
100
+ params.is_a?(String) ? CGI.unescapeHTML(params) : params
101
+ end
102
+ end
91
103
 
104
+ def self.query_string_to_params(query_string)
92
105
  case Webrat.configuration.mode
93
106
  when :rails
94
- klasses << HashWithIndifferentAccess
107
+ parse_rails_request_params(query_string)
95
108
  when :merb
96
- klasses << Mash
109
+ ::Merb::Parse.query(query_string)
110
+ when :rack, :sinatra
111
+ Rack::Utils.parse_nested_query(query_string)
112
+ else
113
+ query_string.split('&').map {|query| { query.split('=').first => query.split('=').last }}
97
114
  end
98
-
99
- klasses
100
115
  end
101
116
 
117
+ def self.parse_rails_request_params(query_string)
118
+ if defined?(ActionController::AbstractRequest)
119
+ ActionController::AbstractRequest.parse_query_parameters(query_string)
120
+ elsif defined?(ActionController::UrlEncodedPairParser)
121
+ ActionController::UrlEncodedPairParser.parse_query_parameters(query_string)
122
+ else
123
+ Rack::Utils.parse_nested_query(query_string)
124
+ end
125
+ end
102
126
  end
103
127
  end
@@ -10,7 +10,7 @@ module Webrat
10
10
  end
11
11
 
12
12
  def form_element
13
- @dom.css("#" + @value).first
13
+ @dom.css("#" + @value).first || @dom.css(@value).first
14
14
  end
15
15
 
16
16
  end
@@ -14,10 +14,12 @@ module Webrat
14
14
  @block ||= block
15
15
  matched = matches(stringlike)
16
16
 
17
+ @block.call(matched) if @block
18
+
17
19
  if @options[:count]
18
- matched.size == @options[:count].to_i && (!@block || @block.call(matched))
20
+ matched.size == @options[:count].to_i
19
21
  else
20
- matched.any? && (!@block || @block.call(matched))
22
+ matched.any?
21
23
  end
22
24
  end
23
25
 
@@ -3,7 +3,7 @@ module Webrat
3
3
 
4
4
  def self.delegate_to_session(*meths)
5
5
  meths.each do |meth|
6
- self.class_eval <<-RUBY
6
+ self.class_eval(<<-RUBY, __FILE__, __LINE__)
7
7
  def #{meth}(*args, &blk)
8
8
  webrat_session.#{meth}(*args, &blk)
9
9
  end
@@ -8,8 +8,8 @@ module Webrat #:nodoc:
8
8
  def mime_type(type)
9
9
  return type if type.nil? || type.to_s.include?("/")
10
10
  type = ".#{type}" unless type.to_s[0] == ?.
11
- MIME_TYPES.fetch(type) { |type|
12
- raise ArgumentError.new("Invalid Mime type: #{type}")
11
+ MIME_TYPES.fetch(type) { |invalid_type|
12
+ raise ArgumentError.new("Invalid Mime type: #{invalid_type}")
13
13
  }
14
14
  end
15
15
 
@@ -28,6 +28,7 @@ module Webrat
28
28
  attr_reader :session
29
29
 
30
30
  def initialize(session, &block) #:nodoc:
31
+ @selector, @dom = nil
31
32
  @session = session
32
33
  instance_eval(&block) if block_given?
33
34
 
@@ -65,7 +65,7 @@ For example:
65
65
  attr_reader :current_url
66
66
  attr_reader :elements
67
67
 
68
- def_delegators :@adapter, :response, :response_code, :response_body,
68
+ def_delegators :@adapter, :response, :response_code, :response_body, :response_headers,
69
69
  :response_body=, :response_code=,
70
70
  :get, :post, :put, :delete
71
71
 
@@ -75,6 +75,7 @@ For example:
75
75
  @data = {}
76
76
  @default_headers = {}
77
77
  @custom_headers = {}
78
+ @current_url = nil
78
79
  reset
79
80
  end
80
81
 
@@ -155,7 +156,7 @@ For example:
155
156
  end
156
157
 
157
158
  def redirect? #:nodoc:
158
- (response_code / 100).to_i == 3
159
+ [301, 302, 303, 307].include?(response_code)
159
160
  end
160
161
 
161
162
  def internal_redirect?
@@ -281,7 +282,7 @@ For example:
281
282
  end
282
283
 
283
284
  def response_location
284
- response.headers["Location"]
285
+ response_headers['Location']
285
286
  end
286
287
 
287
288
  def current_host
@@ -1,5 +1,5 @@
1
1
  class NilClass #:nodoc:
2
- def to_param
2
+ def to_query_string
3
3
  nil
4
4
  end
5
5
  end
@@ -10,7 +10,7 @@ RegExp.escape = function(text) {
10
10
  );
11
11
  }
12
12
  return text.replace(arguments.callee.sRE, '\\$1');
13
- }
13
+ };
14
14
 
15
15
  var allLabels = inDocument.getElementsByTagName("label");
16
16
  var regExp = new RegExp('^\\W*' + RegExp.escape(locator) + '(\\b|$)', 'i');
@@ -21,7 +21,7 @@ var candidateLabels = $A(allLabels).select(function(candidateLabel){
21
21
  });
22
22
 
23
23
  if (candidateLabels.length == 0) {
24
- return null;
24
+ return null;
25
25
  }
26
26
 
27
27
  //reverse length sort
@@ -30,7 +30,13 @@ candidateLabels = candidateLabels.sortBy(function(s) {
30
30
  });
31
31
 
32
32
  var locatedLabel = candidateLabels.first();
33
- var labelFor = locatedLabel.getAttribute('for');
33
+ var labelFor = null;
34
+
35
+ if (locatedLabel.getAttribute('for')) {
36
+ labelFor = locatedLabel.getAttribute('for');
37
+ } else if (locatedLabel.attributes['for']) { // IE
38
+ labelFor = locatedLabel.attributes['for'].nodeValue;
39
+ }
34
40
 
35
41
  if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
36
42
  return locatedLabel.getElementsByTagName('button')[0]
@@ -31,10 +31,13 @@ module Webrat
31
31
 
32
32
  def remote_control
33
33
  return @remote_control if @remote_control
34
+ server_options = { :timeout => Webrat.configuration.selenium_browser_startup_timeout }
35
+ server_options[:firefox_profile] = Webrat.configuration.selenium_firefox_profile if Webrat.configuration.selenium_firefox_profile
34
36
 
35
37
  @remote_control = ::Selenium::RemoteControl::RemoteControl.new("0.0.0.0",
36
38
  Webrat.configuration.selenium_server_port,
37
- :timeout => Webrat.configuration.selenium_browser_startup_timeout)
39
+ server_options)
40
+
38
41
  @remote_control.jar_file = jar_path
39
42
 
40
43
  return @remote_control
@@ -3,7 +3,12 @@ require "webrat/selenium/selenium_rc_server"
3
3
  require "webrat/selenium/application_server_factory"
4
4
  require "webrat/selenium/application_servers/base"
5
5
 
6
- require "selenium"
6
+ begin
7
+ require "selenium"
8
+ rescue LoadError => e
9
+ e.message << " (You may need to install the selenium-rc gem)"
10
+ raise e
11
+ end
7
12
 
8
13
  module Webrat
9
14
  class TimeoutError < WebratError
@@ -170,8 +175,8 @@ module Webrat
170
175
  end
171
176
 
172
177
  error_message = "#{message} (after #{timeout} sec)"
173
-
174
- if $browser
178
+
179
+ if $browser && Webrat.configuration.selenium_verbose_output
175
180
  error_message += <<-EOS
176
181
 
177
182
 
@@ -232,7 +237,7 @@ EOS
232
237
 
233
238
  def create_browser
234
239
  $browser = ::Selenium::Client::Driver.new(Webrat.configuration.selenium_server_address || "localhost",
235
- Webrat.configuration.selenium_server_port, Webrat.configuration.selenium_browser_key, "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port}")
240
+ Webrat.configuration.selenium_server_port, Webrat.configuration.selenium_browser_key, "http://#{Webrat.configuration.application_address}:#{Webrat.configuration.application_port_for_selenium}")
236
241
  $browser.set_speed(0) unless Webrat.configuration.selenium_server_address
237
242
 
238
243
  at_exit do
@@ -15,7 +15,7 @@ module Webrat #:nodoc:
15
15
  end
16
16
 
17
17
  def response_code
18
- @response_code || 200
18
+ @response_code ||= 200
19
19
  end
20
20
 
21
21
  def get(url, data, headers = nil)
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "sinatra/base"
3
2
 
4
3
  class SampleApp < Sinatra::Default
@@ -17,4 +16,20 @@ class SampleApp < Sinatra::Default
17
16
  get "/redirected" do
18
17
  "Redirected"
19
18
  end
19
+
20
+ get "/form" do
21
+ <<-EOS
22
+ <html>
23
+ <form action="/form" method="post">
24
+ <input type="hidden" name="_method" value="put" />
25
+ <label for="email">Email:</label> <input type="text" id="email" name="email" /></label>
26
+ <input type="submit" value="Add" />
27
+ </form>
28
+ </html>
29
+ EOS
30
+ end
31
+
32
+ put "/form" do
33
+ "Welcome #{params[:email]}"
34
+ end
20
35
  end
@@ -12,7 +12,15 @@ describe "Webrat's Mechanize mode" do
12
12
  end
13
13
 
14
14
  it "should follow links"
15
- it "should submit forms"
15
+
16
+ it "should submit forms" do
17
+ visit "http://localhost:9292/form"
18
+ fill_in "Email", :with => "albert@example.com"
19
+ response = click_button "Add"
20
+
21
+ response.should contain("Welcome albert@example.com")
22
+ end
23
+
16
24
  it "should not follow external redirects" do
17
25
  pending do
18
26
  response = visit("http://localhost:9292/external_redirect")
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "sinatra/base"
3
2
 
4
3
  class RackApp < Sinatra::Base
@@ -39,7 +38,8 @@ class RackApp < Sinatra::Base
39
38
  end
40
39
 
41
40
  post "/upload" do
42
- params[:uploaded_file].to_yaml
41
+ uploaded_file = params[:uploaded_file]
42
+ Marshal.dump(:tempfile => uploaded_file[:tempfile].read, :type => uploaded_file[:type], :filename => uploaded_file[:filename])
43
43
  end
44
44
  end
45
45
 
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "test/unit"
3
2
  require "rack/test"
4
3
  # require "redgreen"
@@ -1,3 +1,4 @@
1
+ require "rubygems"
1
2
  require File.dirname(__FILE__) + "/helper"
2
3
 
3
4
  class WebratRackTest < Test::Unit::TestCase
@@ -52,10 +53,10 @@ class WebratRackTest < Test::Unit::TestCase
52
53
  attach_file "File", __FILE__, "text/ruby"
53
54
  click_button "Upload"
54
55
 
55
- upload = YAML.load(response_body)
56
+ upload = Marshal.load(response_body)
56
57
  assert_equal "text/ruby", upload[:type]
57
58
  assert_equal "webrat_rack_test.rb", upload[:filename]
58
- assert upload[:tempfile].respond_to?(:read)
59
+ assert_equal File.read(__FILE__), upload[:tempfile]
59
60
  end
60
61
  end
61
62
 
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "sinatra"
3
2
 
4
3
  use_in_file_templates!
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "sinatra/base"
3
2
 
4
3
  class MyModularApp < Sinatra::Default
@@ -1,3 +1,4 @@
1
+ require "rubygems"
1
2
  require File.dirname(__FILE__) + "/test_helper"
2
3
  require File.dirname(__FILE__) + "/../classic_app"
3
4
 
@@ -1,4 +1,3 @@
1
- require "rubygems"
2
1
  require "test/unit"
3
2
  # require "redgreen"
4
3
 
@@ -77,7 +77,7 @@ module Webrat
77
77
 
78
78
  element = Webrat::XML.document(html).css('input').first
79
79
  text_field = TextField.new(nil, element)
80
- text_field.to_param.should == { 'email' => 'user@example.com' }
80
+ text_field.to_query_string.should == 'email=user@example.com'
81
81
  end
82
82
  end
83
83
  end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Multiple nested params" do
4
+ it "should be corretly posted" do
5
+ Webrat.configuration.mode = :rails
6
+
7
+ with_html <<-HTML
8
+ <html>
9
+ <form method="post" action="/family">
10
+ <div class="couple">
11
+ <div class="parent">
12
+ <select name="user[family][parents][0][][gender]">
13
+ <option selected="selected" value="Mother">Mother</option>
14
+ <option value="Father">Father</option>
15
+ </select>
16
+ <input type="text" value="Alice" name="user[family][parents][0][][name]" />
17
+ </div>
18
+ <div class="parent">
19
+ <select name="user[family][parents][0][][gender]">
20
+ <option value="Mother">Mother</option>
21
+ <option selected="selected" value="Father">Father</option>
22
+ </select>
23
+ <input type="text" value="Michael" name="user[family][parents][0][][name]" />
24
+ </div>
25
+ </div>
26
+ <div class="couple">
27
+ <div class="parent">
28
+ <select name="user[family][parents][1][][gender]">
29
+ <option selected="selected" value="Mother">Mother</option>
30
+ <option value="Father">Father</option>
31
+ </select>
32
+ <input type="text" value="Jenny" name="user[family][parents][1][][name]" />
33
+ </div>
34
+ </div>
35
+ <input type="submit" />
36
+ </form>
37
+ </html>
38
+ HTML
39
+
40
+ params = { "user" => { "family" => { "parents" => {
41
+ "0" => [ {"name" => "Alice", "gender"=>"Mother"}, {"name" => "Michael", "gender"=>"Father"} ],
42
+ "1" => [ {"name" => "Jenny", "gender"=>"Mother"} ]
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ webrat_session.should_receive(:post).with("/family", params)
49
+ click_button
50
+ end
51
+ end