Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore URL's query string when checking for interaction presence. #50

Open
eimantas opened this issue Jun 23, 2016 · 2 comments
Open

Ignore URL's query string when checking for interaction presence. #50

eimantas opened this issue Jun 23, 2016 · 2 comments

Comments

@eimantas
Copy link

eimantas commented Jun 23, 2016

So this is a bug that has been haunting me for a few weeks now. And was the cause of me not running my service classes' specs unless I wasn't too lazy to recreate the cassettes.

Here's a snippet from my project that creates a get request with query parameters:

if let p = params where method == "GET" {
    let charset = NSCharacterSet.URLQueryAllowedCharacterSet()
    var query = ""
    for key,value in p {
        if let escapedValue = String(p[key]!).stringByAddingPercentEncodingWithAllowedCharacters(charset) {
            query += "\(key)=\(escapedValue)&"
        }
    }
    urlString += "?\(query)"
}
  • param is a [String : AnyObject] dictionary;
  • method is a string defining http verb

So this snippet constructs a query string and appends it to urlString variable that has the base url and resource path combined.

This urlString is then passed to NSURLRequest initializer that creates a request to perform with a session that holds a cassette.

And this is where the trouble comes in. DVR check's for presence of interaction in the cassette by looking at the request's URL. And by definition dictionary does not guarantee the order of the keys in which they will be passed in iteration.

If you have ["foo": 5, "bar" : true] the resulting query string can have two variations:

  • let query1 = "foo=5&bar=true&"
  • let query2 = "bar=true&foo=5&"

In the end they mean the same thing and will be interpreted correctly by the server, but the check will fail since query1 != query2.

I'm not sure how people construct requests in their code, but the solution can be achieved in two ways

  • make sure that query string key-values have deterministic order (e.g. alpahbetically a-z) and construct query string always in the same matter;
  • Add code in DVR interaction's check that ignores the query string when comparing URLs (split by ?) and compare the key values that are stored in the query string (reconstruct the dict by splitting by & and then by =).

If this project is still alive, I'd like to hear anyones thoughts.

@soffes
Copy link
Contributor

soffes commented Jun 23, 2016

First off, creating NSURLs by hand using string manipulation is strongly discouraged. You should seriously considering switching to NSURLComponents and NSURLQueryItem. This would eliminate things being non-deterministic as well.

As far as why it's not matching, can you please provide a sample cassette and a sample test that isn't matching so we can debug it?

@eimantas
Copy link
Author

The problem with the test case is that it may pass sometimes because the query parameters will be constructed in the order that is stored in the cassette. But I will change my code to use NSURLComponents and NSURLQueryItem to see if this avoids the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants