require File.expand_path(File.dirname(__FILE__) + '/spec_helper') unless defined? SAMPLE_HEADERS SAMPLE_HEADERS = { "Content-Length" => "8888", "Accept" => "application/json" } ESCAPED_PARAMS = "x=ab%2Bc&z=%27Stop%21%27%20said%20Fred" NOT_ESCAPED_PARAMS = "z='Stop!' said Fred&x=ab c" end class MyException < StandardError; end; describe "WebMock version" do it "should report version" do WebMock.version.should == open(File.join(File.dirname(__FILE__), "..", "VERSION")).read.strip end end describe "WebMock", :shared => true do before(:each) do WebMock.disable_net_connect! RequestRegistry.instance.reset_webmock end describe "when web connect" do describe "is allowed" do before(:each) do WebMock.allow_net_connect! end it "should make a real web request if request is not stubbed" do setup_expectations_for_real_example_com_request http_request(:get, "http://www.example.com/"). body.should =~ /.*example.*/ end it "should make a real https request if request is not stubbed" do setup_expectations_for_real_example_com_request( :host => "www.paypal.com", :port => 443, :path => "/uk/cgi-bin/webscr", :response_body => "hello paypal" ) http_request(:get, "https://www.paypal.com/uk/cgi-bin/webscr"). body.should =~ /.*paypal.*/ end it "should return stubbed response if request was stubbed" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") http_request(:get, "http://www.example.com/").body.should == "abc" end end describe "is not allowed" do before(:each) do WebMock.disable_net_connect! end it "should return stubbed response if request was stubbed" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") http_request(:get, "http://www.example.com/").body.should == "abc" end it "should raise exception if request was not stubbed" do lambda { http_request(:get, "http://www.example.com/") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string("Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/")) end end describe "is not allowed with exception for localhost" do before(:each) do WebMock.disable_net_connect!(:allow_localhost => true) end it "should return stubbed response if request was stubbed" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") http_request(:get, "http://www.example.com/").body.should == "abc" end it "should raise exception if request was not stubbed" do lambda { http_request(:get, "http://www.example.com/") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string("Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/")) end it "should allow a real request to localhost" do lambda { http_request(:get, "http://localhost:12345/") }.should raise_error(connection_refused_exception_class) end it "should allow a real request to 127.0.0.1" do lambda { http_request(:get, "http://127.0.0.1:12345/") }.should raise_error(connection_refused_exception_class) end end end describe "when matching requests" do describe "on uri" do it "should match the request by uri with non escaped params if request have escaped parameters" do stub_http_request(:get, "www.example.com/?#{NOT_ESCAPED_PARAMS}").to_return(:body => "abc") http_request(:get, "http://www.example.com/?#{ESCAPED_PARAMS}").body.should == "abc" end it "should match the request by uri with escaped parameters even if request has non escaped params" do stub_http_request(:get, "www.example.com/?#{ESCAPED_PARAMS}").to_return(:body => "abc") http_request(:get, "http://www.example.com/?#{NOT_ESCAPED_PARAMS}").body.should == "abc" end it "should match the request by regexp matching non escaped params uri if request params are escaped" do stub_http_request(:get, /.*x=ab c.*/).to_return(:body => "abc") http_request(:get, "http://www.example.com/?#{ESCAPED_PARAMS}").body.should == "abc" end end describe "on query params" do it "should match the request by query params declared as a hash" do stub_http_request(:get, "www.example.com").with(:query => {"a" => ["b", "c"]}).to_return(:body => "abc") http_request(:get, "http://www.example.com/?a[]=b&a[]=c").body.should == "abc" end it "should match the request by query declared as a string" do stub_http_request(:get, "www.example.com").with(:query => "a[]=b&a[]=c").to_return(:body => "abc") http_request(:get, "http://www.example.com/?a[]=b&a[]=c").body.should == "abc" end it "should match the request by query params declared both in uri and query option" do stub_http_request(:get, "www.example.com/?x=3").with(:query => {"a" => ["b", "c"]}).to_return(:body => "abc") http_request(:get, "http://www.example.com/?x=3&a[]=b&a[]=c").body.should == "abc" end end describe "on method" do it "should match the request by method if registered" do stub_http_request(:get, "www.example.com") http_request(:get, "http://www.example.com/").status.should == "200" end it "should not match requests if method is different" do stub_http_request(:get, "www.example.com") http_request(:get, "http://www.example.com/").status.should == "200" lambda { http_request(:delete, "http://www.example.com/") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: DELETE http://www.example.com/") ) end end describe "on body" do it "should match requests if body is the same" do stub_http_request(:post, "www.example.com").with(:body => "abc") http_request( :post, "http://www.example.com/", :body => "abc").status.should == "200" end it "should match requests if body is not set in the stub" do stub_http_request(:post, "www.example.com") http_request( :post, "http://www.example.com/", :body => "abc").status.should == "200" end it "should not match requests if body is different" do stub_http_request(:post, "www.example.com").with(:body => "abc") lambda { http_request(:post, "http://www.example.com/", :body => "def") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'def'")) end describe "with regular expressions" do it "should match requests if body matches regexp" do stub_http_request(:post, "www.example.com").with(:body => /\d+abc$/) http_request( :post, "http://www.example.com/", :body => "123abc").status.should == "200" end it "should not match requests if body doesn't match regexp" do stub_http_request(:post, "www.example.com").with(:body => /^abc/) lambda { http_request(:post, "http://www.example.com/", :body => "xabc") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'xabc'")) end end describe "when body is declared as a hash" do before(:each) do stub_http_request(:post, "www.example.com"). with(:body => {:a => '1', :b => 'five', 'c' => {'d' => ['e', 'f']} }) end describe "for request with url encoded body" do it "should match request if hash matches body" do http_request( :post, "http://www.example.com/", :body => 'a=1&c[d][]=e&c[d][]=f&b=five').status.should == "200" end it "should match request if hash matches body in different order of params" do http_request( :post, "http://www.example.com/", :body => 'a=1&c[d][]=e&b=five&c[d][]=f').status.should == "200" end it "should not match if hash doesn't match url encoded body" do lambda { http_request( :post, "http://www.example.com/", :body => 'c[d][]=f&a=1&c[d][]=e').status.should == "200" }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: "+ "POST http://www.example.com/ with body 'c[d][]=f&a=1&c[d][]=e'")) end end describe "for request with json body and content type is set to json" do it "should match if hash matches body" do http_request( :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'}, :body => "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}").status.should == "200" end it "should match if hash matches body in different form" do http_request( :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'}, :body => "{\"a\":\"1\",\"b\":\"five\",\"c\":{\"d\":[\"e\",\"f\"]}}").status.should == "200" end end describe "for request with xml body and content type is set to xml" do before(:each) do WebMock.reset_webmock stub_http_request(:post, "www.example.com"). with(:body => { "opt" => {:a => '1', :b => 'five', 'c' => {'d' => ['e', 'f']} }}) end it "should match if hash matches body" do http_request( :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/xml'}, :body => "\n \n e\n f\n \n\n").status.should == "200" end it "should match if hash matches body in different form" do http_request( :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/xml'}, :body => "\n \n e\n f\n \n\n").status.should == "200" end end end end describe "on headers" do it "should match requests if headers are the same" do stub_http_request(:get, "www.example.com").with(:headers => SAMPLE_HEADERS ) http_request( :get, "http://www.example.com/", :headers => SAMPLE_HEADERS).status.should == "200" end it "should match requests if headers are the same and declared as array" do stub_http_request(:get, "www.example.com").with(:headers => {"a" => ["b"]} ) http_request( :get, "http://www.example.com/", :headers => {"a" => "b"}).status.should == "200" end describe "when multiple headers with the same key are used" do it "should match requests if headers are the same" do stub_http_request(:get, "www.example.com").with(:headers => {"a" => ["b", "c"]} ) http_request( :get, "http://www.example.com/", :headers => {"a" => ["b", "c"]}).status.should == "200" end it "should match requests if headers are the same but in different order" do stub_http_request(:get, "www.example.com").with(:headers => {"a" => ["b", "c"]} ) http_request( :get, "http://www.example.com/", :headers => {"a" => ["c", "b"]}).status.should == "200" end it "should not match requests if headers are different" do stub_http_request(:get, "www.example.com").with(:headers => {"a" => ["b", "c"]}) lambda { http_request( :get, "http://www.example.com/", :headers => {"a" => ["b", "d"]}) }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'A'=>['b', 'd']}))) end end it "should match requests if request headers are not stubbed" do stub_http_request(:get, "www.example.com") http_request( :get, "http://www.example.com/", :headers => SAMPLE_HEADERS).status.should == "200" end it "should not match requests if headers are different" do stub_http_request(:get, "www.example.com").with(:headers => SAMPLE_HEADERS) lambda { http_request( :get, "http://www.example.com/", :headers => { 'Content-Length' => '9999'}) }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'Content-Length'=>'9999'}))) end it "should not match if accept header is different" do stub_http_request(:get, "www.example.com"). with(:headers => { 'Accept' => 'application/json'}) lambda { http_request( :get, "http://www.example.com/", :headers => { 'Accept' => 'application/xml'}) }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'Accept'=>'application/xml'}))) end describe "with regular expressions" do it "should match requests if header values match regular expression" do stub_http_request(:get, "www.example.com").with(:headers => { :user_agent => /^MyAppName$/ }) http_request( :get, "http://www.example.com/", :headers => { 'user-agent' => 'MyAppName' }).status.should == "200" end it "should not match requests if headers values do not match regular expression" do stub_http_request(:get, "www.example.com").with(:headers => { :user_agent => /^MyAppName$/ }) lambda { http_request( :get, "http://www.example.com/", :headers => { 'user-agent' => 'xMyAppName' }) }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/ with headers {'User-Agent'=>'xMyAppName'}))) end end end describe "with basic authentication" do it "should match if credentials are the same" do stub_http_request(:get, "user:pass@www.example.com") http_request(:get, "http://user:pass@www.example.com/").status.should == "200" end it "should not match if credentials are different" do stub_http_request(:get, "user:pass@www.example.com") lambda { http_request(:get, "http://user:pazz@www.example.com/").status.should == "200" }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://user:pazz@www.example.com/))) end it "should not match if credentials are stubbed but not provided in the request" do stub_http_request(:get, "user:pass@www.example.com") lambda { http_request(:get, "http://www.example.com/").status.should == "200" }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/))) end it "should not match if credentials are not stubbed but exist in the request" do stub_http_request(:get, "www.example.com") lambda { http_request(:get, "http://user:pazz@www.example.com/").status.should == "200" }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( %q(Real HTTP connections are disabled. Unregistered request: GET http://user:pazz@www.example.com/))) end end describe "with block" do it "should match if block returns true" do stub_http_request(:get, "www.example.com").with { |request| true } http_request(:get, "http://www.example.com/").status.should == "200" end it "should not match if block returns false" do stub_http_request(:get, "www.example.com").with { |request| false } lambda { http_request(:get, "http://www.example.com/") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/")) end it "should pass the request to the block" do stub_http_request(:post, "www.example.com").with { |request| request.body == "wadus" } http_request( :post, "http://www.example.com/", :body => "wadus").status.should == "200" lambda { http_request(:post, "http://www.example.com/", :body => "jander") }.should raise_error(WebMock::NetConnectNotAllowedError, client_specific_request_string( "Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'jander'")) end end end describe "raising stubbed exceptions" do it "should raise exception if declared in a stubbed response" do stub_http_request(:get, "www.example.com").to_raise(MyException) lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") end it "should raise exception if declared in a stubbed response as exception instance" do stub_http_request(:get, "www.example.com").to_raise(MyException.new("hello world")) lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "hello world") end it "should raise exception if declared in a stubbed response as exception instance" do stub_http_request(:get, "www.example.com").to_raise("hello world") lambda { http_request(:get, "http://www.example.com/") }.should raise_error("hello world") end it "should raise exception if declared in a stubbed response after returning declared response" do stub_http_request(:get, "www.example.com").to_return(:body => "abc").then.to_raise(MyException) http_request(:get, "http://www.example.com/").body.should == "abc" lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") end end describe "raising timeout errors" do it "should raise timeout exception if declared in a stubbed response" do stub_http_request(:get, "www.example.com").to_timeout lambda { http_request(:get, "http://www.example.com/") }.should raise_error(client_timeout_exception_class) end it "should raise exception if declared in a stubbed response after returning declared response" do stub_http_request(:get, "www.example.com").to_return(:body => "abc").then.to_timeout http_request(:get, "http://www.example.com/").body.should == "abc" lambda { http_request(:get, "http://www.example.com/") }.should raise_error(client_timeout_exception_class) end end describe "returning stubbed responses" do it "should return declared body" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") http_request(:get, "http://www.example.com/").body.should == "abc" end it "should return declared headers" do stub_http_request(:get, "www.example.com").to_return(:headers => SAMPLE_HEADERS) response = http_request(:get, "http://www.example.com/") response.headers["Content-Length"].should == "8888" end it "should return declared headers when there are multiple headers with the same key" do stub_http_request(:get, "www.example.com").to_return(:headers => {"a" => ["b", "c"]}) response = http_request(:get, "http://www.example.com/") response.headers["A"].should == "b, c" end it "should return declared status code" do stub_http_request(:get, "www.example.com").to_return(:status => 500) http_request(:get, "http://www.example.com/").status.should == "500" end it "should return declared status message" do stub_http_request(:get, "www.example.com").to_return(:status => [500, "Internal Server Error"]) http_request(:get, "http://www.example.com/").message.should == "Internal Server Error" end it "should return default status code" do stub_http_request(:get, "www.example.com") http_request(:get, "http://www.example.com/").status.should == "200" end it "should return default empty message" do stub_http_request(:get, "www.example.com") http_request(:get, "http://www.example.com/").message.should == "" end it "should return body declared as IO" do stub_http_request(:get, "www.example.com").to_return(:body => File.new(__FILE__)) http_request(:get, "http://www.example.com/").body.should == File.new(__FILE__).read end it "should return body declared as IO if requested many times" do stub_http_request(:get, "www.example.com").to_return(:body => File.new(__FILE__)) 2.times do http_request(:get, "http://www.example.com/").body.should == File.new(__FILE__).read end end it "should close IO declared as response body after reading" do stub_http_request(:get, "www.example.com").to_return(:body => @file = File.new(__FILE__)) @file.should be_closed end describe "dynamic response parts" do it "should return evaluated response body" do stub_http_request(:post, "www.example.com").to_return(:body => lambda { |request| request.body }) http_request(:post, "http://www.example.com/", :body => "echo").body.should == "echo" end it "should return evaluated response headers" do stub_http_request(:post, "www.example.com").to_return(:headers => lambda { |request| request.headers }) http_request(:post, "http://www.example.com/", :body => "abc", :headers => {'A' => 'B'}).headers['A'].should == 'B' end end describe "dynamic responses" do class Responder def call(request) {:body => request.body} end end it "should return evaluated response body" do stub_http_request(:post, "www.example.com").to_return(lambda { |request| {:body => request.body} }) http_request(:post, "http://www.example.com/", :body => "echo").body.should == "echo" end it "should return evaluated response headers" do stub_http_request(:get, "www.example.com").to_return(lambda { |request| {:headers => request.headers} }) http_request(:get, "http://www.example.com/", :headers => {'A' => 'B'}).headers['A'].should == 'B' end it "should create dynamic responses from blocks" do stub_http_request(:post, "www.example.com").to_return do |request| {:body => request.body} end http_request(:post, "http://www.example.com/", :body => "echo").body.should == "echo" end it "should create dynamic responses from objects responding to call" do stub_http_request(:post, "www.example.com").to_return(Responder.new) http_request(:post, "http://www.example.com/", :body => "echo").body.should == "echo" end end describe "replying raw responses from file" do before(:each) do @file = File.new(File.expand_path(File.dirname(__FILE__)) + "/example_curl_output.txt") stub_http_request(:get, "www.example.com").to_return(@file) @response = http_request(:get, "http://www.example.com/") end it "should return recorded headers" do @response.headers.should == { "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT", "Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"438", "Connection"=>"Keep-Alive", "Accept"=>"image/jpeg, image/png" } end it "should return recorded body" do @response.body.size.should == 438 end it "should return recorded status" do @response.status.should == "202" end it "should return recorded status message" do @response.message.should == "OK" end it "should ensure file is closed" do @file.should be_closed end end describe "replying responses raw responses from string" do before(:each) do @input = File.new(File.expand_path(File.dirname(__FILE__)) + "/example_curl_output.txt").read stub_http_request(:get, "www.example.com").to_return(@input) @response = http_request(:get, "http://www.example.com/") end it "should return recorded headers" do @response.headers.should == { "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT", "Content-Type"=>"text/html; charset=UTF-8", "Content-Length"=>"438", "Connection"=>"Keep-Alive", "Accept"=>"image/jpeg, image/png" } end it "should return recorded body" do @response.body.size.should == 438 end it "should return recorded status" do @response.status.should == "202" end it "should return recorded status message" do @response.message.should == "OK" end end describe "sequences of responses" do it "should return responses one by one if declared in array" do stub_http_request(:get, "www.example.com").to_return([ {:body => "1"}, {:body => "2"}, {:body => "3"} ]) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "3" end it "should repeat returning last declared response from a sequence after all responses were returned" do stub_http_request(:get, "www.example.com").to_return([ {:body => "1"}, {:body => "2"} ]) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "2" end it "should return responses one by one if declared as comma separated params" do stub_http_request(:get, "www.example.com").to_return({:body => "1"}, {:body => "2"}, {:body => "3"}) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "3" end it "should return responses one by one if declared with several to_return invokations" do stub_http_request(:get, "www.example.com"). to_return({:body => "1"}). to_return({:body => "2"}). to_return({:body => "3"}) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "3" end it "should return responses one by one if declared with to_return invocations separated with then syntactic sugar" do stub_http_request(:get, "www.example.com").to_return({:body => "1"}).then. to_return({:body => "2"}).then.to_return({:body => "3"}) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "3" end end describe "repeating declared responses more than once" do it "should repeat one response declared number of times" do stub_http_request(:get, "www.example.com"). to_return({:body => "1"}).times(2). to_return({:body => "2"}) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" end it "should repeat sequence of response declared number of times" do stub_http_request(:get, "www.example.com"). to_return({:body => "1"}, {:body => "2"}).times(2). to_return({:body => "3"}) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "2" http_request(:get, "http://www.example.com/").body.should == "3" end it "should repeat infinitely last response even if number of declared times is lower" do stub_http_request(:get, "www.example.com"). to_return({:body => "1"}).times(2) http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "1" http_request(:get, "http://www.example.com/").body.should == "1" end it "should give error if times is declared without specifying response" do lambda { stub_http_request(:get, "www.example.com").times(3) }.should raise_error("Invalid WebMock stub declaration. times(N) can be declared only after response declaration.") end end describe "raising declared exceptions more than once" do it "should repeat raising exception declared number of times" do stub_http_request(:get, "www.example.com"). to_raise(MyException).times(2). to_return({:body => "2"}) lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") http_request(:get, "http://www.example.com/").body.should == "2" end it "should repeat raising sequence of exceptions declared number of times" do stub_http_request(:get, "www.example.com"). to_raise(MyException, ArgumentError).times(2). to_return({:body => "2"}) lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") lambda { http_request(:get, "http://www.example.com/") }.should raise_error(ArgumentError) lambda { http_request(:get, "http://www.example.com/") }.should raise_error(MyException, "Exception from WebMock") lambda { http_request(:get, "http://www.example.com/") }.should raise_error(ArgumentError) http_request(:get, "http://www.example.com/").body.should == "2" end end end describe "precedence of stubs" do it "should use the last declared matching request stub" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") stub_http_request(:get, "www.example.com").to_return(:body => "def") http_request(:get, "http://www.example.com/").body.should == "def" end it "should not be affected by the type of uri or request method" do stub_http_request(:get, "www.example.com").to_return(:body => "abc") stub_http_request(:any, /.*example.*/).to_return(:body => "def") http_request(:get, "http://www.example.com/").body.should == "def" end end describe "verification of request expectation" do describe "when net connect not allowed" do before(:each) do WebMock.disable_net_connect! stub_http_request(:any, "http://www.example.com") stub_http_request(:any, "https://www.example.com") end it "should pass if request was executed with the same uri and method" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should have_been_made.once }.should_not raise_error end it "should pass if request was not expected and not executed" do lambda { request(:get, "http://www.example.com").should_not have_been_made }.should_not raise_error end it "should fail if request was not expected but executed" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should_not have_been_made }.should fail_with("The request GET http://www.example.com/ was expected to execute 0 times but it executed 1 time") end it "should fail if request was not executed" do lambda { request(:get, "http://www.example.com").should have_been_made }.should fail_with("The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times") end it "should fail if request was executed to different uri" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.org").should have_been_made }.should fail_with("The request GET http://www.example.org/ was expected to execute 1 time but it executed 0 times") end it "should fail if request was executed with different method" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") request(:get, "http://www.example.com").should have_been_made }.should fail_with("The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times") end it "should pass if request was executed with different form of uri" do lambda { http_request(:get, "http://www.example.com/") request(:get, "www.example.com").should have_been_made }.should_not raise_error end it "should pass if request was executed with different form of uri without port " do lambda { http_request(:get, "http://www.example.com/") request(:get, "www.example.com:80").should have_been_made }.should_not raise_error end it "should pass if request was executed with different form of uri with port" do lambda { http_request(:get, "http://www.example.com/") request(:get, "www.example.com:80").should have_been_made }.should_not raise_error end it "should fail if request was executed with different port" do lambda { http_request(:get, "http://www.example.com:80/") request(:get, "www.example.com:90").should have_been_made }.should fail_with("The request GET http://www.example.com:90/ was expected to execute 1 time but it executed 0 times") end it "should pass if request was executed with different form of uri with https port" do lambda { http_request(:get, "https://www.example.com/") request(:get, "https://www.example.com:443/").should have_been_made }.should_not raise_error end describe "when matching requests with escaped uris" do before(:each) do WebMock.disable_net_connect! stub_http_request(:any, "http://www.example.com/?#{NOT_ESCAPED_PARAMS}") end it "should pass if request was executed with escaped params" do lambda { http_request(:get, "http://www.example.com/?#{ESCAPED_PARAMS}") request(:get, "http://www.example.com/?#{NOT_ESCAPED_PARAMS}").should have_been_made }.should_not raise_error end it "should pass if request was executed with non escaped params but escaped expected" do lambda { http_request(:get, "http://www.example.com/?#{NOT_ESCAPED_PARAMS}") request(:get, "http://www.example.com/?#{ESCAPED_PARAMS}").should have_been_made }.should_not raise_error end it "should pass if request was executed with escaped params but uri matichg regexp expected" do lambda { http_request(:get, "http://www.example.com/?#{ESCAPED_PARAMS}") request(:get, /.*example.*/).should have_been_made }.should_not raise_error end end describe "when matching requests with query params" do before(:each) do stub_http_request(:any, /.*example.*/) end it "should pass if the request was executed with query params declared in a hash in query option" do lambda { http_request(:get, "http://www.example.com/?a[]=b&a[]=c") request(:get, "www.example.com").with(:query => {"a" => ["b", "c"]}).should have_been_made }.should_not raise_error end it "should pass if the request was executed with query params declared as string in query option" do lambda { http_request(:get, "http://www.example.com/?a[]=b&a[]=c") request(:get, "www.example.com").with(:query => "a[]=b&a[]=c").should have_been_made }.should_not raise_error end it "should pass if the request was executed with query params both in uri and in query option" do lambda { http_request(:get, "http://www.example.com/?x=3&a[]=b&a[]=c") request(:get, "www.example.com/?x=3").with(:query => {"a" => ["b", "c"]}).should have_been_made }.should_not raise_error end end it "should fail if requested more times than expected" do lambda { http_request(:get, "http://www.example.com/") http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should have_been_made }.should fail_with("The request GET http://www.example.com/ was expected to execute 1 time but it executed 2 times") end it "should fail if requested less times than expected" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should have_been_made.twice }.should fail_with("The request GET http://www.example.com/ was expected to execute 2 times but it executed 1 time") end it "should fail if requested less times than expected when 3 times expected" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should have_been_made.times(3) }.should fail_with("The request GET http://www.example.com/ was expected to execute 3 times but it executed 1 time") end it "should succeed if request was executed with the same body" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") request(:post, "www.example.com").with(:body => "abc").should have_been_made }.should_not raise_error end it "should fail if request was executed with different body" do lambda { http_request(:get, "http://www.example.com/", :body => "abc") request(:get, "www.example.com"). with(:body => "def").should have_been_made }.should fail_with('The request GET http://www.example.com/ with body "def" was expected to execute 1 time but it executed 0 times') end describe "when expected body is declared as regexp" do it "should succeed if request was executed with the same body" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") request(:post, "www.example.com").with(:body => /^abc$/).should have_been_made }.should_not raise_error end it "should fail if request was executed with different body" do lambda { http_request(:get, "http://www.example.com/", :body => /^abc/) request(:get, "www.example.com"). with(:body => "xabc").should have_been_made }.should fail_with('The request GET http://www.example.com/ with body "xabc" was expected to execute 1 time but it executed 0 times') end end describe "when expected body is declared as a hash" do let(:body_hash) { {:a => '1', :b => 'five', 'c' => {'d' => ['e', 'f']}} } let(:fail_message) {'The request POST http://www.example.com/ with body {"a"=>"1", "b"=>"five", "c"=>{"d"=>["e", "f"]}} was expected to execute 1 time but it executed 0 times'} describe "when request is executed with url encoded body matching hash" do it "should succeed" do lambda { http_request(:post, "http://www.example.com/", :body => 'a=1&c[d][]=e&c[d][]=f&b=five') request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end it "should succeed if url encoded params have different order" do lambda { http_request(:post, "http://www.example.com/", :body => 'a=1&c[d][]=e&b=five&c[d][]=f') request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end it "should fail if request is executed with url encoded body not matching hash" do lambda { http_request(:post, "http://www.example.com/", :body => 'c[d][]=f&a=1&c[d][]=e') request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should fail_with(fail_message) end end describe "when request is executed with json body matching hash and content type is set to json" do it "should succeed" do lambda { http_request(:post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'}, :body => "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}") request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end it "should succeed if json body is in different form" do lambda { http_request(:post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'}, :body => "{\"a\":\"1\",\"b\":\"five\",\"c\":{\"d\":[\"e\",\"f\"]}}") request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end end describe "when request is executed with xml body matching hash and content type is set to xml" do let(:body_hash) { { "opt" => {:a => "1", :b => 'five', 'c' => {'d' => ['e', 'f']}} }} it "should succeed" do lambda { http_request(:post, "http://www.example.com/", :headers => {'Content-Type' => 'application/xml'}, :body => "\n \n e\n f\n \n\n") request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end it "should succeed if xml body is in different form" do lambda { http_request(:post, "http://www.example.com/", :headers => {'Content-Type' => 'application/xml'}, :body => "\n \n e\n f\n \n\n") request(:post, "www.example.com").with(:body => body_hash).should have_been_made }.should_not raise_error end end end it "should succeed if request was executed with the same headers" do lambda { http_request(:get, "http://www.example.com/", :headers => SAMPLE_HEADERS) request(:get, "www.example.com"). with(:headers => SAMPLE_HEADERS).should have_been_made }.should_not raise_error end it "should succeed if request was executed with the same headers with value declared as array" do lambda { http_request(:get, "http://www.example.com/", :headers => {"a" => "b"}) request(:get, "www.example.com"). with(:headers => {"a" => ["b"]}).should have_been_made }.should_not raise_error end describe "when multiple headers with the same key are passed" do it "should succeed if request was executed with the same headers" do lambda { http_request(:get, "http://www.example.com/", :headers => {"a" => ["b", "c"]}) request(:get, "www.example.com"). with(:headers => {"a" => ["b", "c"]}).should have_been_made }.should_not raise_error end it "should succeed if request was executed with the same headers but different order" do lambda { http_request(:get, "http://www.example.com/", :headers => {"a" => ["b", "c"]}) request(:get, "www.example.com"). with(:headers => {"a" => ["c", "b"]}).should have_been_made }.should_not raise_error end it "should fail if request was executed with different headers" do lambda { http_request(:get, "http://www.example.com/", :headers => {"a" => ["b", "c"]}) request(:get, "www.example.com"). with(:headers => {"a" => ["b", "d"]}).should have_been_made }.should fail_with("The request GET http://www.example.com/ with headers {'A'=>['b', 'd']} was expected to execute 1 time but it executed 0 times") end end it "should fail if request was executed with different headers" do lambda { http_request(:get, "http://www.example.com/", :headers => SAMPLE_HEADERS) request(:get, "www.example.com"). with(:headers => { 'Content-Length' => '9999'}).should have_been_made }.should fail_with("The request GET http://www.example.com/ with headers {'Content-Length'=>'9999'} was expected to execute 1 time but it executed 0 times") end it "should fail if request was executed with less headers" do lambda { http_request(:get, "http://www.example.com/", :headers => {'A' => 'a'}) request(:get, "www.example.com"). with(:headers => {'A' => 'a', 'B' => 'b'}).should have_been_made }.should fail_with("The request GET http://www.example.com/ with headers {'A'=>'a', 'B'=>'b'} was expected to execute 1 time but it executed 0 times") end it "should succeed if request was executed with more headers" do lambda { http_request(:get, "http://www.example.com/", :headers => {'A' => 'a', 'B' => 'b'} ) request(:get, "www.example.com"). with(:headers => {'A' => 'a'}).should have_been_made }.should_not raise_error end it "should succeed if request was executed with body and headers but they were not specified in expectantion" do lambda { http_request(:get, "http://www.example.com/", :body => "abc", :headers => SAMPLE_HEADERS ) request(:get, "www.example.com").should have_been_made }.should_not raise_error end it "should succeed if request was executed with headers matching regular expressions" do lambda { http_request(:get, "http://www.example.com/", :headers => { 'user-agent' => 'MyAppName' }) request(:get, "www.example.com"). with(:headers => { :user_agent => /^MyAppName$/ }).should have_been_made }.should_not raise_error end it "should fail if request was executed with headers not matching regular expression" do lambda { http_request(:get, "http://www.example.com/", :headers => { 'user_agent' => 'xMyAppName' }) request(:get, "www.example.com"). with(:headers => { :user_agent => /^MyAppName$/ }).should have_been_made }.should fail_with("The request GET http://www.example.com/ with headers {'User-Agent'=>/^MyAppName$/} was expected to execute 1 time but it executed 0 times") end it "should suceed if request was executed and block evaluated to true" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") request(:post, "www.example.com").with { |req| req.body == "wadus" }.should have_been_made }.should_not raise_error end it "should fail if request was executed and block evaluated to false" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") request(:post, "www.example.com").with { |req| req.body == "wadus" }.should have_been_made }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 1 time but it executed 0 times") end it "should fail if request was not expected but it executed and block matched request" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") request(:post, "www.example.com").with { |req| req.body == "wadus" }.should_not have_been_made }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 0 times but it executed 1 time") end describe "with authentication" do before(:each) do stub_http_request(:any, "http://user:pass@www.example.com") stub_http_request(:any, "http://user:pazz@www.example.com") end it "should succeed if succeed if request was executed with expected credentials" do lambda { http_request(:get, "http://user:pass@www.example.com/") request(:get, "http://user:pass@www.example.com").should have_been_made.once }.should_not raise_error end it "should fail if request was executed with different credentials than expected" do lambda { http_request(:get, "http://user:pass@www.example.com/") request(:get, "http://user:pazz@www.example.com").should have_been_made.once }.should fail_with("The request GET http://user:pazz@www.example.com/ was expected to execute 1 time but it executed 0 times") end it "should fail if request was executed without credentials but credentials were expected" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://user:pass@www.example.com").should have_been_made.once }.should fail_with("The request GET http://user:pass@www.example.com/ was expected to execute 1 time but it executed 0 times") end it "should fail if request was executed with credentials but expected without" do lambda { http_request(:get, "http://user:pass@www.example.com/") request(:get, "http://www.example.com").should have_been_made.once }.should fail_with("The request GET http://www.example.com/ was expected to execute 1 time but it executed 0 times") end it "should be order insensitive" do stub_request(:post, "http://www.example.com") http_request(:post, "http://www.example.com/", :body => "def") http_request(:post, "http://www.example.com/", :body => "abc") WebMock.should have_requested(:post, "www.example.com").with(:body => "abc") WebMock.should have_requested(:post, "www.example.com").with(:body => "def") end end describe "using webmock matcher" do it "should verify expected requests occured" do lambda { http_request(:get, "http://www.example.com/") WebMock.should have_requested(:get, "http://www.example.com").once }.should_not raise_error end it "should verify expected requests occured" do lambda { http_request(:post, "http://www.example.com/", :body => "abc", :headers => {'A' => 'a'}) WebMock.should have_requested(:post, "http://www.example.com").with(:body => "abc", :headers => {'A' => 'a'}).once }.should_not raise_error end it "should verify that non expected requests didn't occur" do lambda { http_request(:get, "http://www.example.com/") WebMock.should_not have_requested(:get, "http://www.example.com") }.should fail_with("The request GET http://www.example.com/ was expected to execute 0 times but it executed 1 time") end it "should succeed if request was executed and block evaluated to true" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") WebMock.should have_requested(:post, "www.example.com").with { |req| req.body == "wadus" } }.should_not raise_error end it "should fail if request was executed and block evaluated to false" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") WebMock.should have_requested(:post, "www.example.com").with { |req| req.body == "wadus" } }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 1 time but it executed 0 times") end it "should fail if request was not expected but executed and block matched request" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") WebMock.should_not have_requested(:post, "www.example.com").with { |req| req.body == "wadus" } }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 0 times but it executed 1 time") end end describe "using assert_requested" do it "should verify expected requests occured" do lambda { http_request(:get, "http://www.example.com/") assert_requested(:get, "http://www.example.com", :times => 1) assert_requested(:get, "http://www.example.com") }.should_not raise_error end it "should verify expected requests occured" do lambda { http_request(:post, "http://www.example.com/", :body => "abc", :headers => {'A' => 'a'}) assert_requested(:post, "http://www.example.com", :body => "abc", :headers => {'A' => 'a'}) }.should_not raise_error end it "should verify that non expected requests didn't occur" do lambda { http_request(:get, "http://www.example.com/") assert_not_requested(:get, "http://www.example.com") }.should fail_with("The request GET http://www.example.com/ was expected to execute 0 times but it executed 1 time") end it "should verify if non expected request executed and block evaluated to true" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") assert_not_requested(:post, "www.example.com") { |req| req.body == "wadus" } }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 0 times but it executed 1 time") end it "should verify if request was executed and block evaluated to true" do lambda { http_request(:post, "http://www.example.com/", :body => "wadus") assert_requested(:post, "www.example.com") { |req| req.body == "wadus" } }.should_not raise_error end it "should verify if request was executed and block evaluated to false" do lambda { http_request(:post, "http://www.example.com/", :body => "abc") assert_requested(:post, "www.example.com") { |req| req.body == "wadus" } }.should fail_with("The request POST http://www.example.com/ with given block was expected to execute 1 time but it executed 0 times") end end end describe "when net connect allowed" do before(:each) do WebMock.allow_net_connect! end it "should verify expected requests occured" do setup_expectations_for_real_example_com_request lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should have_been_made }.should_not raise_error end it "should verify that non expected requests didn't occur" do lambda { http_request(:get, "http://www.example.com/") request(:get, "http://www.example.com").should_not have_been_made }.should fail_with("The request GET http://www.example.com/ was expected to execute 0 times but it executed 1 time") end end end describe "callbacks" do describe "after_request" do before(:each) do WebMock.reset_callbacks stub_request(:get, "http://www.example.com") end it "should not invoke callback unless request is made" do WebMock.after_request { @called = true } @called.should == nil end it "should invoke a callback after request is made" do WebMock.after_request { @called = true } http_request(:get, "http://www.example.com/") @called.should == true end it "should not invoke a callback if specific http library should be ignored" do WebMock.after_request(:except => [http_library()]) { @called = true } http_request(:get, "http://www.example.com/") @called.should == nil end it "should invoke a callback even if other http libraries should be ignored" do WebMock.after_request(:except => [:other_lib]) { @called = true } http_request(:get, "http://www.example.com/") @called.should == true end it "should pass request signature to the callback" do WebMock.after_request(:except => [:other_lib]) do |request_signature, _| @request_signature = request_signature end http_request(:get, "http://www.example.com/") @request_signature.uri.to_s.should == "http://www.example.com:80/" end describe "passing response to callback" do describe "for stubbed requests" do before(:each) do stub_request(:get, "http://www.example.com"). to_return( :status => ["200", "hello"], :headers => {'Content-Length' => '666', 'Hello' => 'World'}, :body => "foo bar" ) WebMock.after_request(:except => [:other_lib]) do |_, response| @response = response end http_request(:get, "http://www.example.com/") end it "should pass response with status and message" do @response.status.should == ["200", "hello"] end it "should pass response with headers" do @response.headers.should == { 'Content-Length' => '666', 'Hello' => 'World' } end it "should pass response with body" do @response.body.should == "foo bar" end end describe "for real requests" do before(:each) do WebMock.reset_webmock WebMock.allow_net_connect! WebMock.after_request(:except => [:other_lib]) do |_, response| @response = response end http_request(:get, "http://www.example.com/") end it "should pass response with status and message" do @response.status[0].should == 200 @response.status[1].should == "OK" end it "should pass response with headers" do @response.headers["Content-Length"].should == "574" end it "should pass response with body" do @response.body.size.should == 574 end end end it "should invoke multiple callbacks in order of their declarations" do WebMock.after_request { @called = 1 } WebMock.after_request { @called += 1 } http_request(:get, "http://www.example.com/") @called.should == 2 end it "should invoke callbacks only for real requests if requested" do WebMock.after_request(:real_requests_only => true) { @called = true } http_request(:get, "http://www.example.com/") @called.should == nil WebMock.allow_net_connect! http_request(:get, "http://www.example.net/") @called.should == true end it "should clear all declared callbacks on reset callbacks" do WebMock.after_request { @called = 1 } WebMock.reset_callbacks stub_request(:get, "http://www.example.com") http_request(:get, "http://www.example.com/") @called.should == nil end end end end