Nock: query strings and ordering

Created on 3 Dec 2012  路  23Comments  路  Source: nock/nock

I'm having some trouble with query strings. I wish to intercept a path like '/path/load' which can accept multiple parameters, like '?b=123&a=456'. The trouble is that "a" "b" could be in any order (since it'd still be a valid URL). Is there some way I could do parameter matching like the POST request using an object map instead of constructing this string?

help wanted

All 23 comments

You can use a path filtering regexp or function that will be called on every request by using .filteringPath():
https://github.com/flatiron/nock#path-filtering

You can then take that chance to reorder the query string if you will.

That is what I ended up doing. I created a filtering function like below.

function normalize_get_path( str ) {
    var u = url.parse( str );
    var query = querystring.parse( u.query );

    var params = [];
    for( var param in query )
        params.push( param );
    params.sort();

    var oqs = '';
    for( var param in params ) {
        if( oqs.length )
            oqs += '&';

        oqs += encodeURIComponent( params[param] );
        oqs += "=";
        oqs += encodeURIComponent( query[params[param]] );
    }

    var c = url.format( { pathname: u.pathname, search: oqs } ); //NODE: 'query' is ignored, must use search
    return c;
}

Closing #82.

Shouldn't this be in the library? Query strings are pretty common things.

Agree with @jtremback.

Something like the body matcher code would be awesome for query params as well.

:+1: to this idea / problem

@pgte would you be open to something like

.get("/x/x")
.allowAnyQueryString()
.reply(..............)

If so I can do this

:+1:

:+1:

I'm mocking an external ugly API which has a lot of query string stuffs...
At this time we write that:

var data =聽{ foo: 'bar' };
nock.get('/some/path' + querystring.stringify(data))

which is quite ugly but now, ordering is the problem.

As @wejendorp said, marcher like body would be great! :+1:

:+1:

:100: Any plans on this?

Nock is currently not query-string aware, but I agree this is annoying.

We can either
a) make a scope query-string aware by defau (making it match the query object instead of the string). Here an option would be needed to switch this off.
b) make it easy for the programmer to create a query string filter that they can activate with something like this:

scope.filteringPath(nock.orderQueryString);

I'm inclined to support the first option since it's more friendly and I suspect covers most of the cases.
@ierceg @svnlto thoughts?

I also think the first option fits nicer into nock's api.

@pgte I agree.

The way I was imagining, was an extension to the API. Similar to the above proposal for .allowAnyQueryString():

.query() // Allow any query string
.query(true) // Allow any query string
.query(false) // Disallow any query string
.query({key: "value"}) // Match query object

This matches up with the superagent syntax used in nock's test suite.

In the best case, we could parse the query string from the existing path, and treat that path as a shorthand for .query, enabling backwards compatibility. i.e.:

.get('/users/1?password=XXX')
.get('/users/1').query({password: "XXX"}) // same result

And also imagining filteringQuery() as in:

.filteringQuery(function(queryObj) {
    if (queryObj.password == ...);
});

_EDIT: added .query() and .query(false)_

Has anyone started a branch for this? I'm happy to give it a crack, from a first look at the codebase we'd want to extend the scope => intercept function with a .query(), but then it should probably use a lot of the .match() functionality, any thoughts/ideas on the best solution let me know.

In terms of the interface, the best solutions are not gonna be backwards compatible, something like

var google = nock('http://www.google.com')
.get( '/', {
  body: {
    foo: 'bar'
  },
  query: {
    foo: 'bar'
  }
}

feels quite nice.

@kevinhodges I wouldn't want to break backwards compatibility.

One way I see this working is if, instead of a string with the path you provide an object like this:

var google = nock('http://www.google.com')
.get({
  path:  '/',
  query: {
    foo: 'bar',
    bar: 'foo'
  }
});

this should also work:

var google = nock('http://www.google.com')
.get({
  path:  '/',
  query: 'foo=bar&bar=foo'
});

Care to give it a go?

@pgte what is the news about this issue? Is this implemented?

It's not implemented. Would appreciate some help here.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue and add a reference to this one if it鈥檚 related. Thank you!

Was this page helpful?
0 / 5 - 0 ratings