added support of request with querystring and or anchor

This commit is contained in:
Camel Aissani 2016-07-02 15:45:54 +02:00
parent f60e7f825c
commit ac746a2241
6 changed files with 164 additions and 53 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
coverage
coverage
dist

View File

@ -174,7 +174,6 @@ Object.keys(HTTP_METHODS).reduce((reqProto, method) => {
}
// HTTP methods
const transformer = HTTP_METHODS[method];
const httpMethodName = 'http'+method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
reqProto[httpMethodName] = function(request, resolve, reject) {
let {uri, headers, data} = request;
@ -185,7 +184,7 @@ Object.keys(HTTP_METHODS).reduce((reqProto, method) => {
uri,
method,
headers,
data,
data
}, resolve, reject);
}

View File

@ -4,15 +4,26 @@ export const HTTP_METHODS = {
if (!data) {
return uri;
}
return Object.keys(data).reduce((gUri, d, index) => {
if (index === 0) {
let anchor = ''
let uriWithoutAnchor = uri;
const hashIndex = uri.indexOf('#');
if (hashIndex >=1) {
uriWithoutAnchor = uri.slice(0, hashIndex);
anchor = uri.slice(hashIndex, uri.length);
}
uriWithoutAnchor = Object.keys(data).reduce((gUri, d, index) => {
if (index === 0 && gUri.indexOf('?') === -1) {
gUri += '?';
} else {
gUri += '&';
}
gUri += `${d}=${data[d]}`;
return gUri;
}, uri);
}, uriWithoutAnchor);
return uriWithoutAnchor + anchor;
},
data({uri, headers, data}) {
return undefined;
@ -54,7 +65,7 @@ export const HTTP_METHODS = {
export default class Requester {
fetch({uri, method, headers, data}, resolve, reject) {
fetch({method, uri, headers, data}, resolve, reject) {
const transformer = HTTP_METHODS[method];
uri = transformer.uri ? transformer.uri({uri, headers, data}) : uri;
headers = transformer.headers ? transformer.headers({uri, headers, data}) : headers;
@ -62,7 +73,7 @@ export default class Requester {
const success = (responseText) => {
resolve(
{uri, method, headers, data},
{method, uri, headers, data},
{status: 200, statusText: 'OK', responseText}
);
};
@ -70,7 +81,7 @@ export default class Requester {
const fail = ({status, statusText, errorThrown}) => {
const errors = this._analyzeErrors({status, statusText, errorThrown});
reject(
{uri, method, headers, data},
{method, uri, headers, data},
{status, statusText, errorThrown, errors}
);
};

View File

@ -49,15 +49,30 @@ export default class Router {
if (route.method !== method) {
return false;
}
if (route.uri instanceof RegExp) {
return uri.match(route.uri);
}
if (!route.uri) {
return true;
}
return route.uri === uri;
let uriToCheck = uri;
//remove query string from uri to test
const questionMarkIndex = uriToCheck.indexOf('?');
if (questionMarkIndex >= 0) {
uriToCheck = uriToCheck.slice(0, questionMarkIndex);
}
//remove anchor from uri to test
const hashIndex = uriToCheck.indexOf('#');
if (hashIndex >= 0) {
uriToCheck = uriToCheck.slice(0, hashIndex);
}
if (route.uri instanceof RegExp) {
return uriToCheck.match(route.uri);
}
return route.uri === uriToCheck;
});
}
@ -69,7 +84,7 @@ export default class Router {
all(...args) {
if (args.length === 0) {
throw new TypeError(`use all method takes at least a middleware`);
throw new TypeError(`use all method takes at least a middleware`);
}
let middleware;
@ -80,7 +95,7 @@ export default class Router {
}
if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) {
throw new TypeError(`use all method takes at least a middleware`);
throw new TypeError(`use all method takes at least a middleware`);
}
for (const method of Object.keys(HTTP_METHODS)) {
@ -94,7 +109,7 @@ for (const method of Object.keys(HTTP_METHODS)) {
const methodName = method.toLowerCase();
Router.prototype[methodName] = function(...args) {
if (args.length === 0) {
throw new TypeError(`use ${methodName} method takes at least a middleware`);
throw new TypeError(`use ${methodName} method takes at least a middleware`);
}
let uri, middleware;
@ -105,7 +120,11 @@ for (const method of Object.keys(HTTP_METHODS)) {
}
if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) {
throw new TypeError(`use ${methodName} method takes at least a middleware`);
throw new TypeError(`use ${methodName} method takes at least a middleware`);
}
if (uri && this.baseUri && this.baseUri instanceof RegExp) {
throw new TypeError(`router contains a regexp cannot mix with route uri/regexp`);
}
this._add(new Route(this, uri, method, middleware));

View File

@ -4,41 +4,66 @@ import {assert} from 'chai';
import sinon from 'sinon';
import jsdom from 'mocha-jsdom';
import FakeXMLHttpRequest from 'fake-xml-http-request';
import Requester from '../lib/requester';
import Requester, {HTTP_METHODS} from '../lib/requester';
function xHttpWillRespond(xhttp, readyState, status, statusText, responseText) {
const stub_send = sinon.stub(xhttp, 'send', function() {
this.readyState = readyState;
this.status = status;
this.statusText = statusText;
this.responseText = responseText;
this.onreadystatechange()
describe('HTTP_METHODS', () => {
it('GET method simple uri', () => {
const uriFn = HTTP_METHODS['GET'].uri;
const dataFn = HTTP_METHODS['GET'].data;
assert(uriFn({uri: '/route', data:{a:'b', c:'d'}}) === '/route?a=b&c=d');
assert(dataFn({uri: '/route', data:{a:'b', c:'d'}}) === undefined);
});
const stub_open = sinon.stub(xhttp, 'open', function() {});
it('GET method uri with query string', () => {
const uriFn = HTTP_METHODS['GET'].uri;
const dataFn = HTTP_METHODS['GET'].data;
const stub_setRequestHeader = sinon.stub(xhttp, 'setRequestHeader', function() {});
return {stub_open, stub_send, stub_setRequestHeader};
}
function xHttpWillThrow(xhttp, sendErrorName, openErrorName) {
const stub_send = sinon.stub(xhttp, 'send', function() {
if (sendErrorName) {
throw {name: sendErrorName};
}
assert(uriFn({uri: '/route?x=y&z=a', data:{a:'b', c:'d'}}) === '/route?x=y&z=a&a=b&c=d');
assert(dataFn({uri: '/route?x=y&z=a', data:{a:'b', c:'d'}}) === undefined);
});
const stub_open = sinon.stub(xhttp, 'open', function() {
if (openErrorName) {
throw {name: openErrorName};
}
});
it('GET method uri with query string and anchor', () => {
const uriFn = HTTP_METHODS['GET'].uri;
const dataFn = HTTP_METHODS['GET'].data;
return {stub_open, stub_send};
}
assert(uriFn({uri: '/route?x=y&z=a#anchor1', data:{a:'b', c:'d'}}) === '/route?x=y&z=a&a=b&c=d#anchor1');
assert(dataFn({uri: '/route?x=y&z=a#anchor1', data:{a:'b', c:'d'}}) === undefined);
});
});
describe('Requester', () => {
function xHttpWillRespond(xhttp, readyState, status, statusText, responseText) {
const stub_send = sinon.stub(xhttp, 'send', function() {
this.readyState = readyState;
this.status = status;
this.statusText = statusText;
this.responseText = responseText;
this.onreadystatechange()
});
const stub_open = sinon.stub(xhttp, 'open', function() {});
const stub_setRequestHeader = sinon.stub(xhttp, 'setRequestHeader', function() {});
return {stub_open, stub_send, stub_setRequestHeader};
}
function xHttpWillThrow(xhttp, sendErrorName, openErrorName) {
const stub_send = sinon.stub(xhttp, 'send', function() {
if (sendErrorName) {
throw {name: sendErrorName};
}
});
const stub_open = sinon.stub(xhttp, 'open', function() {
if (openErrorName) {
throw {name: openErrorName};
}
});
return {stub_open, stub_send};
}
let xhttp;

View File

@ -153,6 +153,39 @@ describe('Router', () => {
assert(r.length === 1);
assert(r[0].uri === '/route1');
});
it('route with query string', () => {
let router = new frontexpress.Router('/route1 ');
router.get('/subroute', new frontexpress.Middleware());
let r = router.routes('/route1/subroute?a=b&c=d', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
assert(r[0].data === undefined)
});
it('route with anchor', () => {
let router = new frontexpress.Router('/route1 ');
router.get('/subroute', new frontexpress.Middleware());
let r = router.routes('/route1/subroute#a=b&c=d', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
assert(r[0].data === undefined)
});
it('route with query string and anchor', () => {
let router = new frontexpress.Router('/route1 ');
router.get('/subroute', new frontexpress.Middleware());
let r = router.routes('/route1/subroute?a=b&c=d#anchor1', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1/subroute');
assert(r[0].data === undefined)
});
});
describe('all method', () => {
@ -244,11 +277,11 @@ describe('Router', () => {
router.get(middleware);
const r1 = router.routes('/', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === '/');
assert(r1[0].method === 'GET');
assert(r1[0].middleware === middleware);
const r = router.routes('/', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/');
assert(r[0].method === 'GET');
assert(r[0].middleware === middleware);
});
it('with path /route1 and middleware as arguments', () => {
@ -257,11 +290,34 @@ describe('Router', () => {
router.get('/route1', middleware);
const r1 = router.routes('/route1', 'GET');
assert(r1.length === 1);
assert(r1[0].uri === '/route1');
assert(r1[0].method === 'GET');
assert(r1[0].middleware === middleware);
const r = router.routes('/route1', 'GET');
assert(r.length === 1);
assert(r[0].uri === '/route1');
assert(r[0].method === 'GET');
assert(r[0].middleware === middleware);
});
it('router with regexp and route with /route1', () => {
const router = new frontexpress.Router(/^\//);
const middleware = new frontexpress.Middleware();
try {
router.get('/route1', middleware);
} catch(ex) {
assert(ex instanceof TypeError)
}
});
it('router with regexp and route without uri', () => {
const router = new frontexpress.Router(/^\/part/);
const middleware = new frontexpress.Middleware();
router.get(middleware);
const r = router.routes('/part1', 'GET');
assert(r.length === 1);
assert(r[0].uri instanceof RegExp);
assert(r[0].uri.toString() === new RegExp('^\/part').toString());
assert(r[0].method === 'GET');
assert(r[0].middleware === middleware);
});
});
});