diff --git a/lib/webrat/rails.rb b/lib/webrat/rails.rb index 5da0cff..197aeae 100644 --- a/lib/webrat/rails.rb +++ b/lib/webrat/rails.rb @@ -7,51 +7,53 @@ module Webrat def doc_root File.expand_path(File.join(RAILS_ROOT, 'public')) end - + def saved_page_dir File.expand_path(File.join(RAILS_ROOT, "tmp")) end - + def get(url, data, headers = nil) do_request(:get, url, data, headers) end - + def post(url, data, headers = nil) do_request(:post, url, data, headers) end - + def put(url, data, headers = nil) do_request(:put, url, data, headers) end - + def delete(url, data, headers = nil) do_request(:delete, url, data, headers) end - + def response_body response.body end - + def response_code response.code.to_i end - + def xml_content_type? response.headers["Content-Type"].to_s =~ /xml/ end - + protected - + def integration_session @context end - + def do_request(http_method, url, data, headers) #:nodoc: update_protocol(url) - url = normalize_url(url) - integration_session.request_via_redirect(http_method, url, data, headers) + + integration_session.send(http_method, normalize_url(url), data, headers) + integration_session.follow_redirect_with_headers(headers) while integration_session.internal_redirect? + integration_session.status end - + # remove protocol, host and anchor def normalize_url(href) #:nodoc: uri = URI.parse(href) @@ -61,7 +63,7 @@ module Webrat end normalized_url end - + def update_protocol(href) #:nodoc: if href =~ /^https:/ integration_session.https!(true) @@ -69,24 +71,31 @@ module Webrat integration_session.https!(false) end end - + def response #:nodoc: integration_session.response end - + end end module ActionController #:nodoc: module Integration #:nodoc: - Session.class_eval do - unless instance_methods.include?("put_via_redirect") - require "webrat/rails/redirect_actions" - include Webrat::RedirectActions + class Session #:nodoc: + def internal_redirect? + redirect? && response.redirect_url_match?(host) + end + + def follow_redirect_with_headers(h = {}) + raise "Not a redirect! #{@status} #{@status_message}" unless redirect? + h['HTTP_REFERER'] = current_url if current_url + + get(interpret_uri(headers["location"].first), {}, h) + status end end end - + IntegrationTest.class_eval do include Webrat::Methods include Webrat::Matchers diff --git a/lib/webrat/rails/redirect_actions.rb b/lib/webrat/rails/redirect_actions.rb deleted file mode 100644 index 212e537..0000000 --- a/lib/webrat/rails/redirect_actions.rb +++ /dev/null @@ -1,18 +0,0 @@ -# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed -module Webrat - module RedirectActions #:nodoc: - - def put_via_redirect(path, parameters = {}, headers = {}) - put path, parameters, headers - follow_redirect! while redirect? - status - end - - def delete_via_redirect(path, parameters = {}, headers = {}) - delete path, parameters, headers - follow_redirect! while redirect? - status - end - - end -end diff --git a/spec/webrat/rails/rails_session_spec.rb b/spec/webrat/rails/rails_session_spec.rb index e8ea061..805935b 100644 --- a/spec/webrat/rails/rails_session_spec.rb +++ b/spec/webrat/rails/rails_session_spec.rb @@ -1,88 +1,186 @@ require File.expand_path(File.dirname(__FILE__) + '/helper') describe Webrat::RailsSession do + before :each do + @integration_session = mock("integration_session") + @integration_session.stub!(:internal_redirect?) + @integration_session.stub!(:status) + end + it "should delegate response_body to the session response body" do - response = mock("response", :body => "") - integration_session = mock("integration session", :response => response) - Webrat::RailsSession.new(integration_session).response_body.should == "" + @integration_session.stub!(:response => mock("response", :body => "")) + Webrat::RailsSession.new(@integration_session).response_body.should == "" end - + it "should delegate response_code to the session response code" do - response = mock("response", :code => "42") - integration_session = mock("integration session", :response => response) - Webrat::RailsSession.new(integration_session).response_code.should == 42 + @integration_session.stub!(:response => mock("response", :code => "42")) + Webrat::RailsSession.new(@integration_session).response_code.should == 42 end - - it "should delegate get to request_via_redirect on the integration session" do - integration_session = mock("integration session") - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:get, "url", "data", "headers") + + it "should delegate get to the integration session" do + @integration_session.should_receive(:get).with("url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.get("url", "data", "headers") end - - it "should delegate post to request_via_redirect on the integration session" do - integration_session = mock("integration session") - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:post, "url", "data", "headers") + + it "should delegate post to the integration session" do + @integration_session.should_receive(:post).with("url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.post("url", "data", "headers") end - - it "should delegate put to request_via_redirect on the integration session" do - integration_session = mock("integration session") - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:put, "url", "data", "headers") + + it "should delegate put to the integration session" do + @integration_session.should_receive(:put).with("url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.put("url", "data", "headers") end - - it "should delegate delete to request_via_redirect on the integration session" do - integration_session = mock("integration session") - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:delete, "url", "data", "headers") + + it "should delegate delete to the integration session" do + @integration_session.should_receive(:delete).with("url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.delete("url", "data", "headers") end - + context "the URL is a full path" do it "should just pass on the path" do - integration_session = mock("integration session", :https! => nil) - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers") + @integration_session.stub!(:https!) + @integration_session.should_receive(:get).with("/url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.get("http://www.example.com/url", "data", "headers") end end - + context "the URL is https://" do it "should call #https! with true before the request and just pass on the path" do - integration_session = mock("integration session") - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:https!).with(true) - integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers") + @integration_session.should_receive(:https!).with(true) + @integration_session.should_receive(:get).with("/url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.get("https://www.example.com/url", "data", "headers") end end - + context "the URL is http://" do it "should call #https! with true before the request" do - integration_session = mock("integration session", :request_via_redirect => nil) - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:https!).with(false) + @integration_session.stub!(:get) + @integration_session.should_receive(:https!).with(false) + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.get("http://www.example.com/url", "data", "headers") end end - + context "the URL include an anchor" do it "should strip out the anchor" do - integration_session = mock("integration session", :https! => false) - rails_session = Webrat::RailsSession.new(integration_session) - integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers") + @integration_session.should_receive(:https!).with(false) + @integration_session.should_receive(:get).with("/url", "data", "headers") + rails_session = Webrat::RailsSession.new(@integration_session) rails_session.get("http://www.example.com/url#foo", "data", "headers") end end - + + context "following redirects" do + it "should use forward headers when following redirects" do + @integration_session.stub!(:post) + @integration_session.stub!(:host) + @integration_session.stub!(:status) + + @integration_session.should_receive(:internal_redirect?).twice.and_return(true, false) + @integration_session.should_receive(:follow_redirect_with_headers).with("headers") + + rails_session = Webrat::RailsSession.new(@integration_session) + rails_session.post("url", "data", "headers") + end + + it "should follow internal redirects" do + @integration_session.stub!(:get) + @integration_session.stub!(:host) + @integration_session.stub!(:status) + + @integration_session.should_receive(:internal_redirect?).twice.and_return(true, false) + @integration_session.should_receive(:follow_redirect_with_headers) + + rails_session = Webrat::RailsSession.new(@integration_session) + rails_session.get("url", "data", "headers") + end + + it "should not follow external redirects" do + @integration_session.stub!(:get) + @integration_session.stub!(:host) + @integration_session.stub!(:status) + + @integration_session.should_receive(:internal_redirect?).and_return(false) + @integration_session.should_not_receive(:follow_redirect_with_headers) + + rails_session = Webrat::RailsSession.new(@integration_session) + rails_session.get("url", "data", "headers") + end + end + it "should provide a saved_page_dir" do Webrat::RailsSession.new(mock("integration session")).should respond_to(:saved_page_dir) end - + it "should provide a doc_root" do Webrat::RailsSession.new(mock("integration session")).should respond_to(:doc_root) end +end + +describe ActionController::Integration::Session do + before :each do + @integration_session = ActionController::Integration::Session.new + @integration_session.stub!(:response => mock("response")) + end + + describe "internal_redirect?" do + it "should return false if the response is not a redirect" do + @integration_session.should_receive(:redirect?).and_return(false) + @integration_session.internal_redirect?.should == false + end + + it "should return false if the response was a redirect but the response location does not match the request host" do + @integration_session.should_receive(:redirect?).and_return(true) + @integration_session.response.should_receive(:redirect_url_match?).and_return(false) + @integration_session.internal_redirect?.should == false + end + + it "should return true if the response is a redirect and the response location matches the request host" do + @integration_session.should_receive(:redirect?).and_return(true) + @integration_session.response.should_receive(:redirect_url_match?).and_return(true) + @integration_session.internal_redirect?.should == true + end + end + + describe "follow_redirect_with_headers" do + before do + @integration_session.stub!(:headers).and_return({ 'location' => ["/"]}) + @integration_session.stub!(:redirect?).and_return true + @integration_session.stub!(:get) + end + + it "should raise an exception if response wasn't a redirect" do + @integration_session.stub!(:redirect?).and_return false + lambda { @integration_session.follow_redirect_with_headers }.should raise_error + end + + it "should set the HTTP referer header" do + @integration_session.stub!(:current_url).and_return "http://source.url/" + + headers = {} + + @integration_session.follow_redirect_with_headers(headers) + headers["HTTP_REFERER"].should == "http://source.url/" + end + + it "should GET the first location header" do + @integration_session.stub!("headers").and_return({ 'location' => ['/target'] }) + + @integration_session.should_receive(:get).with("/target", {}, hash_including("headers" => "foo")) + + @integration_session.follow_redirect_with_headers({"headers" => "foo"}) + end + + it "should return the status" do + @integration_session.stub!(:status).and_return "202" + @integration_session.follow_redirect_with_headers.should == "202" + end + end end \ No newline at end of file diff --git a/spec/webrat/rails/rails_spec.rb b/spec/webrat/rails/rails_spec.rb deleted file mode 100644 index 86e9855..0000000 --- a/spec/webrat/rails/rails_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# it "should default to current url" do -# # current_page.stub!(:url => "/page") -# response_body = <<-HTML -#
-# HTML -# @page.stub!(:url => "/current") -# webrat_session.should_receive(:get).with("/current", {}) -# click_button -# end -# -# it "should follow fully qualified secure local links" do -# response_body = <<-HTML -# Jump to sub page -# HTML -# webrat_session.should_receive(:https!).with(true) -# webrat_session.should_receive(:get).with("/page/sub", {}) -# click_link "Jump to sub page" -# end \ No newline at end of file