diff --git a/index.js b/index.js index 64d53cf..aa8f837 100644 --- a/index.js +++ b/index.js @@ -89,7 +89,13 @@ function mock(superagent) { try { var response = current(request); if (response.status !== 200) { - cb && cb(response, null); + // superagent puts status and response on the error it returns, + // which should be an actual instance of Error + // See http://visionmedia.github.io/superagent/#error-handling + var error = new Error(response.status); + error.status = response.status; + error.response = response; + cb && cb(error, null); } else { cb && cb(null, response); } @@ -134,6 +140,24 @@ function mock(superagent) { return this; }; + // Patch Request.query() + var oldQuery = originalMethods.query = reqProto.query; + reqProto.query = function(objectOrString) { + var state = this._superagentMockerState; + if (!state || !state.current) { + return oldQuery.call(this, objectOrString); + } + var obj = {}; + if (isString(objectOrString)) { + obj = parseQueryString(objectOrString); + } + else if (isObject(objectOrString)) { + obj = stringifyValues(objectOrString); + } + state.request.query = mergeObjects(state.request.query, obj); + return this; + } + return mock; // chaining } @@ -187,7 +211,8 @@ function patch(superagent, prop, method) { current: current, request: { headers: {}, - body: {} + body: {}, + query: {} }, }; return orig; @@ -225,7 +250,8 @@ Route.prototype.match = function(method, url, body) { url: url, params: params || {}, body: mergeObjects(body, req.body), - headers: req.headers + headers: req.headers, + query: req.query }); return mergeObjects({ status: 200 @@ -247,6 +273,15 @@ function isObject(obj) { return null != obj && 'object' == typeof obj; } +/** + * Simple string test + * @param any val Variable to test + * @return bool True if variable is a string + */ +function isString(val) { + return 'string' === typeof val; +} + /** * Exec function and return value, or just return arg * @param {fn|any} val Value or fn to exec @@ -257,6 +292,30 @@ function value(val) { : val; } +/** + * Parses a query string like "foo=bar&baz=bat" into objects like + * { foo: 'bar', baz: 'bat' } + * @param s string + */ +function parseQueryString(s) { + return s.split('&').reduce(function (obj, param) { + var parts = param.split('='); + var key = parts.shift(); + var val = parts.shift(); + if (key && val) { + obj[key] = val; + } + return obj; + }, {}); +} + +function stringifyValues(oldObj) { + return Object.keys(oldObj).reduce(function(obj, key) { + obj[key] = String(oldObj[key]); + return obj; + }, {}); +} + /** * Object.assign replacement * This will always create a new object which has all of the own diff --git a/test.js b/test.js index cdb4727..b99bacd 100644 --- a/test.js +++ b/test.js @@ -119,6 +119,7 @@ describe('superagent mock', function() { it('should work correct with unmocked requests', function(done) { request .get('http://example.com') + .query({ foo: 'bar' }) .end(function(err, res) { done(err); }); @@ -208,6 +209,8 @@ describe('superagent mock', function() { request.get('/topics/1') .end(function(err, data) { err.should.have.property('status', 500); + err.should.have.property('response'); + should.deepEqual(err.response, {body: {}, status: 500}); done(); }); }); @@ -286,6 +289,31 @@ describe('superagent mock', function() { ; }); + it('should parse parameters from query()', function(done) { + mock.get('/topics/:id', function(req) { + return req; + }); + request + .get('/topics/5') + .query('hello=world') + .query('xx=yy&zz=0') + .query({ test: 'yay' }) + .query({ foo: 'bar', baz: 'bat' }) + .end(function(_, data) { + data.should.have.property('query'); + should.deepEqual(data.query, { + hello: 'world', + xx: 'yy', + zz: '0', + test: 'yay', + foo: 'bar', + baz: 'bat' + }); + done(); + }) + ; + }); + it('should remove patches by unmock()', function() { mock.unmock(request); (request._patchedBySuperagentMocker === void 0).should.be.true;