venmo / DVR

Network testing for Swift
http://blog.soff.es/network-testing-in-swift-with-dvr
MIT License
651 stars 86 forks source link

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

Open eimantas opened 8 years ago

eimantas commented 8 years ago

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)"
}

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:

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

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

soffes commented 8 years ago

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 commented 8 years ago

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.