diff --git a/src/lib/http/HttpRequest.ts b/src/lib/http/HttpRequest.ts index ae7a3d5..eb855e4 100644 --- a/src/lib/http/HttpRequest.ts +++ b/src/lib/http/HttpRequest.ts @@ -10,7 +10,6 @@ import IApp from "./../types/IApp"; import INext from "./../types/INext"; import IRawEvent from "./../types/IRawEvent"; import { getCookiesFromHeader, mergeParams, normalizeType } from "./../utils/utils"; -import Cookie from "./Cookie"; /** * A incoming request created when the event is APIGatewayEvent. @@ -41,7 +40,7 @@ export default class HttpRequest implements IHttpRequest { this._headers[key.toLowerCase()] = this._event.headers[key]; } - this._cookies = getCookiesFromHeader(this._headers.Cookie, app.get(configuration.COOKIE_SECRET)); + this._cookies = getCookiesFromHeader(this._headers.cookie, app.get(configuration.COOKIE_SECRET)); } get headers(): { [name: string]: string } { diff --git a/src/lib/http/HttpResponse.ts b/src/lib/http/HttpResponse.ts index 22380f8..4f9755e 100644 --- a/src/lib/http/HttpResponse.ts +++ b/src/lib/http/HttpResponse.ts @@ -267,13 +267,14 @@ export default class HttpResponse implements IHttpResponse { opts.signed = true; } - if ("maxAge" in opts) { - opts.expires = new Date(Date.now() + opts.maxAge); - opts.maxAge /= 1000; + if (cookie.expires) { + opts.expires = cookie.expires; } - if (opts.path == null) { + if (cookie.path == null) { opts.path = "/"; + } else { + opts.path = cookie.path; } this._cookies[cookie.name] = cookie; diff --git a/test/http/HttpLayer.spec.ts b/test/http/HttpLayer.spec.ts index 1708ec9..09a1be9 100644 --- a/test/http/HttpLayer.spec.ts +++ b/test/http/HttpLayer.spec.ts @@ -31,7 +31,7 @@ describe("HttpLayer", () => { const callback: DefaultCallback = new DefaultCallback(); beforeEach(() => { - req = new HttpRequest(Object.assign({}, httpEvent)); + req = new HttpRequest(app, Object.assign({}, httpEvent)); res = new HttpResponse(app, req, callback); layer = new HttpLayer(router, "/blog/:id", {}); }); diff --git a/test/http/HttpRequest.spec.ts b/test/http/HttpRequest.spec.ts index 2620acf..11b5ed0 100644 --- a/test/http/HttpRequest.spec.ts +++ b/test/http/HttpRequest.spec.ts @@ -3,6 +3,7 @@ import * as Chai from "chai"; import App from "./../../src/lib/App"; import HttpRequest from "./../../src/lib/http/HttpRequest"; import HttpResponse from "./../../src/lib/http/HttpResponse"; +import ICookie from "./../../src/lib/types/http/ICookie"; import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; import IRawEvent from "./../../src/lib/types/IRawEvent"; import DefaultCallback from "./../utils/DefaultCallback"; @@ -17,7 +18,7 @@ describe("HttpRequest", () => { const app = new App(); beforeEach((done) => { event = Object.assign({}, httpEvent); - request = new HttpRequest(event); + request = new HttpRequest(app, event); done(); }); @@ -190,4 +191,22 @@ describe("HttpRequest", () => { Chai.expect(request.stale(response)).to.be.true; }); + describe("#cookies", () => { + it("returns an object with all the cookies of the `Cookie` header.", () => { + const cookies: { [name: string]: ICookie } = request.cookies; + + Chai.expect(cookies.cookie1.name).to.be.equal("cookie1"); + Chai.expect(cookies.cookie1.value).to.be.equal("value1"); + Chai.expect(cookies.cookie2.name).to.be.equal("cookie2"); + Chai.expect(cookies.cookie2.value).to.be.equal("value2"); + }); + }); + + describe("#cookie", () => { + it("returns the cookie of the `Cookie` header with the given name.", () => { + Chai.expect(request.cookie("cookie1").name).to.be.equal("cookie1"); + Chai.expect(request.cookie("cookie1").value).to.be.equal("value1"); + }); + }); + }); diff --git a/test/http/HttpResponse.spec.ts b/test/http/HttpResponse.spec.ts index 3032a0b..157aec0 100644 --- a/test/http/HttpResponse.spec.ts +++ b/test/http/HttpResponse.spec.ts @@ -5,10 +5,12 @@ import { SinonStub, stub } from "sinon"; import App from "./../../src/lib/App"; import configuration from "./../../src/lib/configuration/configuration"; import HttpError from "./../../src/lib/exceptions/HttpError"; +import Cookie from "./../../src/lib/http/Cookie"; import HttpRequest from "./../../src/lib/http/HttpRequest"; import HttpResponse from "./../../src/lib/http/HttpResponse"; import TemplateEngine from "./../../src/lib/http/renderEngine/TemplateEngine"; import Router from "./../../src/lib/Router"; +import ICookie from "./../../src/lib/types/http/ICookie"; import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; import IApp from "./../../src/lib/types/IApp"; @@ -31,7 +33,7 @@ describe("HttpResponse", () => { beforeEach((done) => { app = new App(); event = Object.assign({}, httpEvent); - request = new HttpRequest(event); + request = new HttpRequest(app, event); callback = new DefaultCallback(); response = new HttpResponse(app, request, callback); @@ -322,28 +324,32 @@ describe("HttpResponse", () => { }); describe("#addCookie", () => { - it("should add the `name` cookie with the `value` and the `options`", () => { - response.addCookie("cookie", "cookieValue", {path: "/test"}); + it("should add the cookie to the right header.", () => { + const cookie: ICookie = new Cookie("cookie", "cookieValue", null, "/test"); + response.addCookie(cookie); Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=cookieValue; Path=/test"); }); it("should throw an error if the option `signed` is true and the app has no `secret`.", () => { + const cookie: ICookie = new Cookie("cookie", "cookieValue", null, "/", true); app.set(configuration.COOKIE_SECRET, null); - Chai.expect(() => response.addCookie("cookie", "cookieValue", {signed: true})).to.throw("app.set(\"cookie_secret\", \"SECRET\") required for signed cookies."); + Chai.expect(() => response.addCookie(cookie)).to.throw("app.set(\"cookie_secret\", \"SECRET\") required for signed cookies."); }); it("should stringify the value of the cookie if is an object.", () => { - response.addCookie("cookie", {key: "value"}); + const cookie: ICookie = new Cookie("cookie", {key: "value"}); + response.addCookie(cookie); Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=" + encodeURIComponent("j:{\"key\":\"value\"}") + "; Path=/"); }); it("should sign the value with the secret if the option `signed` is true.", () => { + const cookie: ICookie = new Cookie("cookie", "cookieValue", null, "/", true); app.set(configuration.COOKIE_SECRET, "SUPER_SECRET"); - response.addCookie("cookie", "cookieValue", {signed: true}); + response.addCookie(cookie); Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=" + encodeURIComponent("s:" + sign("cookieValue", app.get(configuration.COOKIE_SECRET))) + "; Path=/"); }); - it("should add `expires` and `maxAge` into the cookie if `maxAge` is given in options.", () => { + it("should add `expires` into the cookie header value if `expires` is given in cookie constructor.", () => { const oldDate = Date; global.Date = new Proxy(Date, { construct: (target, args) => { @@ -351,24 +357,27 @@ describe("HttpResponse", () => { } }); - response.addCookie("cookie", "cookieValue", {maxAge: 5000}); // 5 seconds - const expires = new Date(Date.now() + 5000); - Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=cookieValue; Max-Age=5; Path=/; Expires=" + expires.toUTCString()); + const expirationDate: Date = new Date(); + expirationDate.setSeconds(expirationDate.getSeconds() + 5); + const cookie: ICookie = new Cookie("cookie", "cookieValue", expirationDate); + + response.addCookie(cookie); + + Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=cookieValue; Path=/; Expires=" + expirationDate.toUTCString()); global.Date = oldDate; }); }); - it("#addCookies should add all the cookies of `obj` with the `options`", () => { - response.addCookies( - { - cookie1: "cookieValue1", - cookie2: "cookieValue2" - }, - {path: "/test"} - ); - Chai.expect(response.header("Set-Cookie")).to.contain("cookie1=cookieValue1; Path=/test"); - Chai.expect(response.header("Set-Cookie")).to.contain("cookie2=cookieValue2; Path=/test"); + it("#addCookies should add all the cookies of the cookies array with their options.", () => { + const cookies: ICookie[] = []; + cookies.push(new Cookie("cookie1", "cookieValue1", null, "/test")); + cookies.push(new Cookie("cookie2", "cookieValue2", null, "/test2")); + + response.addCookies(cookies); + + Chai.expect(response.header("Set-Cookie")[0]).to.be.equal("cookie1=cookieValue1; Path=/test"); + Chai.expect(response.header("Set-Cookie")[1]).to.be.equal("cookie2=cookieValue2; Path=/test2"); }); it("#clearCookie should add the cookie `field` with the `options` and the expires to 1 and the path to /", () => { @@ -376,15 +385,16 @@ describe("HttpResponse", () => { Chai.expect(response.header("Set-Cookie")).to.be.equal("cookie=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"); }); - it("#cookie should return the cookie `name`", () => { - response.addCookies( - { - cookie1: "cookieValue1", - cookie2: "cookieValue2" - }, - {path: "/test"} - ); - Chai.expect(response.cookie("cookie1")).to.be.equal("cookieValue1"); + it("#cookie should return the cookie object if it has been previously added.", () => { + const cookies: ICookie[] = []; + cookies.push(new Cookie("cookie1", "cookieValue1", null, "/test")); + cookies.push(new Cookie("cookie2", "cookieValue2", null, "/test2")); + + response.addCookies(cookies); + Chai.expect(response.cookie("cookie1").value).to.be.equal("cookieValue1"); + Chai.expect(response.cookie("cookie1").path).to.be.equal("/test"); + Chai.expect(response.cookie("cookie2").value).to.be.equal("cookieValue2"); + Chai.expect(response.cookie("cookie2").path).to.be.equal("/test2"); }); describe("location", () => { diff --git a/test/http/HttpRoute.spec.ts b/test/http/HttpRoute.spec.ts index 7b840ec..b17d8b3 100644 --- a/test/http/HttpRoute.spec.ts +++ b/test/http/HttpRoute.spec.ts @@ -35,7 +35,7 @@ describe("HttpRoute", () => { layer = new HttpLayer(router, "/blog/:id", {}); route = new HttpRoute(layer); layer.route = route; - req = new HttpRequest(event); + req = new HttpRequest(app, event); res = new HttpResponse(app, req, callback); }); diff --git a/test/http/HttpRouterExecutor.spec.ts b/test/http/HttpRouterExecutor.spec.ts index 6b122e8..81d3205 100644 --- a/test/http/HttpRouterExecutor.spec.ts +++ b/test/http/HttpRouterExecutor.spec.ts @@ -25,7 +25,7 @@ describe("HttpRouterExecutor", () => { beforeEach(() => { callback = new DefaultCallback(); - req = new HttpRequest(Object.assign({}, httpEvent)); + req = new HttpRequest(app, Object.assign({}, httpEvent)); res = new HttpResponse(app, req, callback); router = new Router(); }); diff --git a/test/http/bodyParsers/JsonParser.spec.ts b/test/http/bodyParsers/JsonParser.spec.ts index 8cd3c2a..25f6ad4 100644 --- a/test/http/bodyParsers/JsonParser.spec.ts +++ b/test/http/bodyParsers/JsonParser.spec.ts @@ -1,17 +1,20 @@ /* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import { SinonSpy, spy } from "sinon"; +import App from "./../../../src/lib/App"; import JsonParser from "./../../../src/lib/http/bodyParsers/JsonParser"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; +import IApp from "./../../../src/lib/types/IApp"; import httpEvent from "./../../utils/httpEvent"; /** * Test for JsonParser. */ describe("JsonParser", () => { + const app: IApp = new App(); const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; @@ -28,7 +31,7 @@ describe("JsonParser", () => { it("should call 'next' with a 400 error if the body can not be parsed and header contentType is 'application/json'.", () => { event.body = "errorBody"; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -40,7 +43,7 @@ describe("JsonParser", () => { it("should call 'next' WITHOUT an error if the body can not be parsed and header contentType is undefined.", () => { event.body = "errorBody"; event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -49,7 +52,7 @@ describe("JsonParser", () => { }); it("should set the body with the parsed body as an object if header contentType is 'application/json'.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -59,7 +62,7 @@ describe("JsonParser", () => { it("should set the body with the parsed body as an object if header contentType is undefined.", () => { event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -69,7 +72,7 @@ describe("JsonParser", () => { it("should NOT set the body if header contentType is 'text/html'.", () => { event.headers["Content-Type"] = "text/html"; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); diff --git a/test/http/bodyParsers/MultipartParser.spec.ts b/test/http/bodyParsers/MultipartParser.spec.ts index 0b3f637..9c62a27 100644 --- a/test/http/bodyParsers/MultipartParser.spec.ts +++ b/test/http/bodyParsers/MultipartParser.spec.ts @@ -1,6 +1,7 @@ /* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import { SinonSpy, spy } from "sinon"; +import App from "./../../../src/lib/App"; import MultipartParser from "./../../../src/lib/http/bodyParsers/MultipartParser"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import HttpUploadedFile from "./../../../src/lib/http/HttpUploadedFile"; @@ -8,6 +9,7 @@ import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; import IHttpUploadedFile from "./../../../src/lib/types/http/IHttpUploadedFile"; +import IApp from "./../../../src/lib/types/IApp"; const mainEvent: any = { body: "------WebKitFormBoundaryvef1fLxmoUdYZWXp\n" @@ -39,6 +41,7 @@ const mainEvent: any = { * Test for MultipartParser. */ describe("MultipartParser", () => { + const app: IApp = new App(); const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; @@ -53,7 +56,7 @@ describe("MultipartParser", () => { it("should call 'next' WITHOUT an error if the body can not be parsed and header contentType is undefined.", () => { event.body = "errorBody"; event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -62,7 +65,7 @@ describe("MultipartParser", () => { }); it("should set the body with the parsed body as an object if header contentType is 'multipart/form-data'.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -84,7 +87,7 @@ describe("MultipartParser", () => { it("should NOT set the body if header contentType is 'text/html'.", () => { event.headers["Content-Type"] = "text/html"; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); diff --git a/test/http/bodyParsers/UrlEncodedParser.spec.ts b/test/http/bodyParsers/UrlEncodedParser.spec.ts index 216543b..9cd3a00 100644 --- a/test/http/bodyParsers/UrlEncodedParser.spec.ts +++ b/test/http/bodyParsers/UrlEncodedParser.spec.ts @@ -3,11 +3,13 @@ import * as Chai from "chai"; import * as qs from "qs"; import * as querystring from "querystring"; import { SinonSpy, SinonStub, spy, stub } from "sinon"; +import App from "./../../../src/lib/App"; import UrlEncodedParser from "./../../../src/lib/http/bodyParsers/UrlEncodedParser"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; +import IApp from "./../../../src/lib/types/IApp"; const mainEvent: any = { body: "param1=Value1¶m2=value2", @@ -24,6 +26,7 @@ const mainEvent: any = { * Test for UrlEncodedParser. */ describe("UrlEncodedParser", () => { + const app: IApp = new App(); const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; @@ -38,7 +41,7 @@ describe("UrlEncodedParser", () => { it("should call 'next' WITHOUT an error if the body can not be parsed and header contentType is undefined.", () => { event.body = "errorBody"; event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -47,7 +50,7 @@ describe("UrlEncodedParser", () => { }); it("should set the body with the parsed body as an object if header contentType is 'application/x-www-form-urlencoded'.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -57,7 +60,7 @@ describe("UrlEncodedParser", () => { it("should set the body with the parsed body as an object if header contentType is undefined.", () => { event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -67,7 +70,7 @@ describe("UrlEncodedParser", () => { it("should NOT set the body if header contentType is 'text/html'.", () => { event.headers["Content-Type"] = "text/html"; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); @@ -78,7 +81,7 @@ describe("UrlEncodedParser", () => { it("should throw an exception if there are more parameters than the indicated by the limit.", () => { event.body = mainEvent.body + "¶m3=value3"; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); Chai.expect(next.called).to.be.true; @@ -96,7 +99,7 @@ describe("UrlEncodedParser", () => { it("should use `qs` library if the options extended is true or by default.", () => { const stubQS = stub(qs, "parse"); - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); handler(req, res, next); Chai.expect(stubQS.called).to.be.true; @@ -106,7 +109,7 @@ describe("UrlEncodedParser", () => { const newHandler: IHttpHandler = (new UrlEncodedParser()).create({extended: false}); const stubQS = stub(querystring, "parse"); - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); newHandler(req, res, next); Chai.expect(stubQS.called).to.be.true; diff --git a/test/http/bodyParsers/parserHelper.spec.ts b/test/http/bodyParsers/parserHelper.spec.ts index 34555d9..f2ce800 100644 --- a/test/http/bodyParsers/parserHelper.spec.ts +++ b/test/http/bodyParsers/parserHelper.spec.ts @@ -1,11 +1,13 @@ /* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import { SinonSpy, spy } from "sinon"; +import App from "./../../../src/lib/App"; import parserHelper from "./../../../src/lib/http/bodyParsers/parserHelper"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; +import IApp from "./../../../src/lib/types/IApp"; const mainEvent: any = { body: "body", @@ -22,6 +24,7 @@ const mainEvent: any = { * Test for parserHelper. */ describe("parserHelper", () => { + const app: IApp = new App(); const body: { [name: string]: any } = { param1: "value1" }; @@ -40,7 +43,7 @@ describe("parserHelper", () => { return body; }); - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const handler: IHttpHandler = parserHelper(parser); @@ -54,7 +57,7 @@ describe("parserHelper", () => { it("should call 'next' WITHOUT an error if the body does not exist.", () => { event.body = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const parser: SinonSpy = spy(); @@ -67,7 +70,7 @@ describe("parserHelper", () => { }); it("should call 'next' with a 400 error if the body can not be parsed and header contentType is NOT undefined.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const handler: IHttpHandler = parserHelper(() => { throw new Error(); @@ -81,7 +84,7 @@ describe("parserHelper", () => { it("should call 'next' WITHOUT an error if the body can not be parsed and header contentType is undefined.", () => { event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const handler: IHttpHandler = parserHelper(() => { throw new Error(); @@ -93,7 +96,7 @@ describe("parserHelper", () => { }); it("should execute the parser function and set the request body with the returned value if the header contentType is the given one in params.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const parser: SinonSpy = spy(); @@ -104,7 +107,7 @@ describe("parserHelper", () => { }); it("should execute the parser function and set the request body with the returned value if no contentType is given in params.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const parser: SinonSpy = spy(); @@ -116,7 +119,7 @@ describe("parserHelper", () => { it("should execute the parser function and set the request body with the returned value if the header contentType is undefined.", () => { event.headers["Content-Type"] = undefined; - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const parser: SinonSpy = spy(); @@ -127,7 +130,7 @@ describe("parserHelper", () => { }); it("should call 'next' WITHOUT execute the parser function otherwise.", () => { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(app, event); const parser: SinonSpy = spy(); diff --git a/test/http/httpFinalHandler.spec.ts b/test/http/httpFinalHandler.spec.ts index e2b6cf5..cfc62bf 100644 --- a/test/http/httpFinalHandler.spec.ts +++ b/test/http/httpFinalHandler.spec.ts @@ -26,7 +26,7 @@ describe("httpFinalHandler", () => { callback = new DefaultCallback(); event = Object.assign({}, httpEvent); event.headers.Accept = "application/json"; - req = new HttpRequest(Object.assign({}, event)); + req = new HttpRequest(app, Object.assign({}, event)); res = new HttpResponse(app, req, callback); }); @@ -81,7 +81,7 @@ describe("httpFinalHandler", () => { it("should send a HTML response and HTML as content type if the request accepts HTML.", () => { event.headers = Object.assign({}, event.headers); event.headers.Accept = "application/json,text/html"; - req = new HttpRequest(event); + req = new HttpRequest(app, event); const handler = httpFinalHandler(req, res, {}); handler(); @@ -97,7 +97,7 @@ describe("httpFinalHandler", () => { it("should send a PLAIN response and PLAIN as content type if the request does not accept JSON neither HTML.", () => { event.headers = Object.assign({}, event.headers); event.headers.Accept = "application/pdf"; - req = new HttpRequest(event); + req = new HttpRequest(app, event); const handler = httpFinalHandler(req, res, {}); handler(); diff --git a/test/router.spec.ts b/test/router.spec.ts index f7670e2..6116d22 100644 --- a/test/router.spec.ts +++ b/test/router.spec.ts @@ -29,7 +29,7 @@ describe("Router", () => { callback = new DefaultCallback(); router = new Router(); eventReq = new EventRequest(otherEvent); - httpReq = new HttpRequest(httpEvent); + httpReq = new HttpRequest(app, httpEvent); res = new HttpResponse(app, httpReq, callback); }); @@ -68,7 +68,7 @@ describe("Router", () => { it("should response with the available HTTP methods for the request path in the Allow header if the request method is OPTIONS.", (done) => { const newEvent = Object.assign({}, httpEvent); newEvent.httpMethod = "OPTIONS"; - const req = new HttpRequest(newEvent); + const req = new HttpRequest(app, newEvent); router.route("/blog/:id").get((request, response) => console.log("OK")); router.route("/blog/:id").post((request, response) => console.log("OK")); @@ -84,7 +84,7 @@ describe("Router", () => { it("should call #out if the request method is OPTIONS and there is no available HTTP methods for the request path.", (done) => { const newEvent = Object.assign({}, httpEvent); newEvent.httpMethod = "OPTIONS"; - const req = new HttpRequest(newEvent); + const req = new HttpRequest(app, newEvent); router.httpHandle(req, res, () => { done(); @@ -95,7 +95,7 @@ describe("Router", () => { describe("#httpProcessParams", () => { const newEvent = Object.assign({}, httpEvent); newEvent.path = "/blog/:id1/:id2"; - const req = new HttpRequest(newEvent); + const req = new HttpRequest(app, newEvent); let previouslyCalled1: boolean; let previouslyCalled2: boolean; diff --git a/test/utils/httpEvent.ts b/test/utils/httpEvent.ts index 6a8351d..f37d698 100644 --- a/test/utils/httpEvent.ts +++ b/test/utils/httpEvent.ts @@ -19,7 +19,8 @@ httpEvent.headers = { "Accept-Charset": "UTF-8, ISO-8859-1", "Accept-Language": "es,en", "If-None-Match": "etagValue", - "If-Modified-Since": "2017-10-10T10:10:10" + "If-Modified-Since": "2017-10-10T10:10:10", + "Cookie": "cookie1=value1; cookie2=value2" }; httpEvent.queryParams = { query1: "Query 1" diff --git a/test/utils/utils.spec.ts b/test/utils/utils.spec.ts index ece37c6..02e2da9 100644 --- a/test/utils/utils.spec.ts +++ b/test/utils/utils.spec.ts @@ -1,6 +1,8 @@ /* tslint:disable:no-unused-expression */ import * as Chai from "chai"; -import { setCharset, stringify } from "../../src/lib/utils/utils"; +import { sign } from "cookie-signature"; +import ICookie from "../../src/lib/types/http/ICookie"; +import { getCookiesFromHeader, setCharset, stringify } from "../../src/lib/utils/utils"; /** * Test for utils. @@ -68,4 +70,46 @@ describe("utils", () => { Chai.expect(stringify(testObject, null, null, true)).to.be.equals("{\"name\":\"Roger\",\"surname\":\"Garcia \\u0026 \\u003cGarcia\\u003e\",\"wight\":72.6}"); }); }); + + describe("#getCookiesFromHeader", () => { + it("returns an empty object if the `Cookie` header is undefined.", () => { + Chai.expect(getCookiesFromHeader(undefined, "SECRET")).to.be.empty; + }); + + it("returns an array with each cookie in the `Cookie` header.", () => { + const cookies: { [name: string]: ICookie } = getCookiesFromHeader("cookie1=value1; cookie2=value2", "SECRET"); + + Chai.expect(cookies.cookie1.name).to.be.equal("cookie1"); + Chai.expect(cookies.cookie1.value).to.be.equal("value1"); + Chai.expect(cookies.cookie2.name).to.be.equal("cookie2"); + Chai.expect(cookies.cookie2.value).to.be.equal("value2"); + }); + + it("unsigns the value of the signed cookies.", () => { + const signedValue = "s:" + sign("value", "SECRET"); + + const cookies: { [name: string]: ICookie } = getCookiesFromHeader("cookie=" + signedValue, "SECRET"); + + Chai.expect(cookies.cookie.value).to.be.equal("value"); + }); + + it("parses the value of JSON cookies.", () => { + const value = {ke1: "value1"}; + const parsedValue = "j:" + JSON.stringify(value); + + const cookies: { [name: string]: ICookie } = getCookiesFromHeader("cookie=" + parsedValue, "SECRET"); + + Chai.expect(cookies.cookie.value).to.be.deep.equal(value); + }); + + it("unsigns and then parses the value of signed JSON cookies.", () => { + const value = {ke1: "value1"}; + const parsedValue = "j:" + JSON.stringify(value); + const signedValue = "s:" + sign(parsedValue, "SECRET"); + + const cookies: { [name: string]: ICookie } = getCookiesFromHeader("cookie=" + signedValue, "SECRET"); + + Chai.expect(cookies.cookie.value).to.be.deep.equal(value); + }); + }); });