Sample stubs break if order of params changes #69

Closed
nickhammond opened this Issue Dec 17, 2010 · 6 comments

2 participants

@nickhammond

If you use the sample stubs that webmock outputs when a request hasn't been mocked yet such as:


You can stub this request with the following snippet:

 stub_request(:post, "https://a.infusionsoft.com/api/xmlrpc").with(:body => "<?xml version=\"1.0\" ?><first></first><second></second>")

If the order of those changes then the test will break which seems to be the case frequently when using XMLRPC. My test will run fine for a few times and then it will start failing. If I paste in the new sample stub then it passes again. This is without modification to the actual method that is calling it.

It's probably because it's seeing the body as a string and trying to match it exactly. Would it be possible to look at the Content-Type and if it's set as text/xml to handle it properly.

@nickhammond

In my full call I have the Content-Type set to text/xml in the headers hash.

@nickhammond

Can you re-open this, I accidently hit "Comment & close" instead of just comment.

@bblimke
Owner

Of course, it would be possible to generate a snippet with body declared as a ruby hash instead of raw xml string.
The problem is that sometimes the order matters. I.e often order of xml elements is important in SOAP requests.
Possibly some configuration print_stub_snippets_with_xml_body_as_hash in webmock ? ;)
Not sure what's the best way to handle it yet.

@nickhammond

hmm, well the annoying part(not webmock's fault) is xmlrpc just puts the params in any order it feels like which is only a problem because it's part of an array.

I took the XML and converted it into a hash but it's basically having problems because the index of certain elements doesn't match up I'm assuming.

Here's an example of the xml I'm dealing with(converted with XmlSimple.xml_in(xml_string):


{"methodName"=>["ContactService.add"], "params"=>[{"param"=>[{"value"=>[{"string"=>["f"]}]}, {"value"=>[{"struct"=>[{"member"=>[{"name"=>["ContactNotes"], "value"=>[{"string"=>["Some comments"]}]}, {"name"=>["_Iagree"], "value"=>[{"boolean"=>["1"]}]}, {"name"=>["FirstName"], "value"=>[{"string"=>["Jack"]}]}, {"name"=>["_Username"], "value"=>[{"string"=>["jack@example.com"]}]}, {"name"=>["LastName"], "value"=>[{"string"=>["Smith"]}]}, {"name"=>["_Password"], "value"=>[{"string"=>["password"]}]}, {"name"=>["Company"], "value"=>[{"string"=>["Example Group"]}]}, {"name"=>["_business"], "value"=>[{"string"=>["Entertainment"]}]}, {"name"=>["Email"], "value"=>[{"string"=>["jack@example.com"]}]}, {"name"=>["_ReferredBy"], "value"=>[{"string"=>["An affiliate"]}]}, {"name"=>["Phone1"], "value"=>[{"string"=>["6025551234"]}]}, {"name"=>["Phone5"], "value"=>[{"string"=>["16025551234"]}]}]}]}]}]}]}

Am I going about this wrong? What would you suggest?

@bblimke
Owner

Looks like the order of 'member' elements is not the same in every request you make
and webmock does care about the order.

Using a hash instead of raw xml also won't help i.e
stub_request(:post, "www.example.com").with(:body => Crack::XML.parse(xml) )
since the order of elements in generated 'member' array will be different.

The only thing I can suggest is to write a custom block to match the request body i.e.

stub_request(:post, "www.example.com").with { |request| your_custom_matching_method_returning_true_or_false(request.body)}

This method can for example parse xml to ruby hash and then do deep sorting of all arrays in a hash before comparing hashes.

@nickhammond

Yeah, thanks for confirming it. Just wanted to make sure I wasn't going crazy from dealing with it for a while.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment