From fe2277d3b8f9d969c4cc31e4e0485133fde14066 Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Sat, 23 Dec 2017 12:59:37 +0100 Subject: [PATCH 01/10] Added sinon to devDependencies. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4d05d0f..f4715c6 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "nyc": "^11.3.0", "tslint": "^5.7.0", "tslint-microsoft-contrib": "^5.0.1", - "typescript": "^2.5.2" + "typescript": "^2.5.2", + "sinon": "^4.0.2" }, "dependencies": { "accepts": "^1.3.4", @@ -57,7 +58,6 @@ "qs": "^6.5.1", "querystring": "^0.2.0", "randomstring": "^1.1.5", - "sinon": "^4.0.2", "statuses": "^1.3.1", "typeis": "^1.1.1", "utils-merge": "^1.0.1" From 11eced20b7e718f8c86292c56b2470d5b26f1050 Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Sat, 23 Dec 2017 13:02:50 +0100 Subject: [PATCH 02/10] type-check is deprecated. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4715c6..2c8c055 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test": "nyc --reporter=html --reporter=text mocha --recursive dist/test/", "posttest": "npm run lint && nyc check-coverage --statements 90 --branches 90 --functions 90 --lines 90", "compile": "tsc", - "lint": "tslint --config tslint.json --type-check --project tsconfig.json src/{,**/,**/**/,**/**/**/}*.ts", + "lint": "tslint --config tslint.json --project tsconfig.json src/{,**/,**/**/,**/**/**/}*.ts", "coveralls": "nyc report --reporter=text-lcov | coveralls", "prepublish": "npm-auto-version" }, From 3eef497e007da7ac6392ea61a7a21213adbb68e2 Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Sat, 23 Dec 2017 15:31:20 +0100 Subject: [PATCH 03/10] Removed App from default export and create a new one. --- README.md | 6 +++--- src/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ece60d..fda6d1f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ lightweight. You can use the projects you need in your web application. The main object is the App. You have to instantiate a new App object and then you can do what you need with it. ```typescript -import App, { IApp } from "lambda-framework"; +import { App, IApp } from "lambda-framework"; const app: IApp = new App(); ``` @@ -55,8 +55,8 @@ app.handle(event, callback); You don't need to care about passing the event to the App handler, you can use the [AWS Lambda implementation](https://github.com/rogelio-o/lambda-framework-aws) or another provider implementation. These will manage the creation of the raw event and passing it to the handler. ```typescript -import App, { IApp } from "lambda-framework"; -import AWSHandler from "lambda-framework-aws"; +import { App, IApp } from "lambda-framework"; +import { AWSHandler } from "lambda-framework-aws"; const app: IApp = new App(); ... diff --git a/src/index.ts b/src/index.ts index 9e1b1b0..6ed2931 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ * MIT Licensed */ -export { default } from "./lib/App"; +export { default as App } from "./lib/App"; export { default as configuration } from "./lib/configuration/configuration"; export { default as IApp } from "./lib/types/IApp"; From 220b2e1aa9a65d5226063810261a85e5cd1ac13f Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Sat, 23 Dec 2017 15:34:59 +0100 Subject: [PATCH 04/10] Fixed tests after removing default export. --- test/app.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/app.spec.ts b/test/app.spec.ts index 9172b3a..74a1aa9 100644 --- a/test/app.spec.ts +++ b/test/app.spec.ts @@ -1,6 +1,6 @@ import * as Chai from 'chai' import { stub } from "sinon"; -import App from '../src/index' +import { App } from '../src/index' import Router from "../src/lib/Router"; import { configuration } from '../src/index' import defaultConfiguration from '../src/lib/configuration/defaultConfiguration' From fe94953ba51684ddfdce680f4a0c0cfa6da6ed9a Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 03:52:29 +0100 Subject: [PATCH 05/10] Tslinting tests. --- package.json | 2 +- test/app.spec.ts | 53 +- test/event/EventLayer.spec.ts | 97 ++-- test/event/EventRequest.spec.ts | 11 +- test/event/EventRouterExecutor.spec.ts | 287 +++++----- test/event/eventFinalHandler.spec.ts | 38 +- test/http/HttpLayer.spec.ts | 279 +++++----- test/http/HttpRequest.spec.ts | 210 ++++--- test/http/HttpResponse.spec.ts | 419 +++++++------- test/http/HttpRoute.spec.ts | 136 ++--- test/http/HttpRouterExecutor.spec.ts | 513 +++++++++--------- test/http/HttpUploadedFile.spec.ts | 1 - test/http/bodyParsers/JsonParser.spec.ts | 7 +- test/http/bodyParsers/MultipartParser.spec.ts | 7 +- .../http/bodyParsers/UrlEncodedParser.spec.ts | 9 +- test/http/bodyParsers/parserHelper.spec.ts | 15 +- test/http/httpFinalHandler.spec.ts | 147 ++--- .../renderEngine/DevTemplateLoader.spec.ts | 3 +- test/http/renderEngine/Template.spec.ts | 1 + test/http/renderEngine/TemplateEngine.spec.ts | 4 +- test/router.spec.ts | 309 +++++------ test/utils/DefaultCallback.ts | 13 +- test/utils/httpEvent.ts | 7 +- test/utils/otherEvent.ts | 51 +- test/utils/utils.spec.ts | 3 +- tslint.json | 4 +- 26 files changed, 1342 insertions(+), 1284 deletions(-) diff --git a/package.json b/package.json index 2c8c055..fe061bf 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test": "nyc --reporter=html --reporter=text mocha --recursive dist/test/", "posttest": "npm run lint && nyc check-coverage --statements 90 --branches 90 --functions 90 --lines 90", "compile": "tsc", - "lint": "tslint --config tslint.json --project tsconfig.json src/{,**/,**/**/,**/**/**/}*.ts", + "lint": "tslint --config tslint.json --project tsconfig.json", "coveralls": "nyc report --reporter=text-lcov | coveralls", "prepublish": "npm-auto-version" }, diff --git a/test/app.spec.ts b/test/app.spec.ts index 74a1aa9..f7bfbae 100644 --- a/test/app.spec.ts +++ b/test/app.spec.ts @@ -1,51 +1,52 @@ -import * as Chai from 'chai' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; import { stub } from "sinon"; -import { App } from '../src/index' +import { App } from "../src/index"; +import { configuration } from "../src/index"; +import defaultConfiguration from "../src/lib/configuration/defaultConfiguration"; import Router from "../src/lib/Router"; -import { configuration } from '../src/index' -import defaultConfiguration from '../src/lib/configuration/defaultConfiguration' -import DefaultCallback from './utils/DefaultCallback'; -import httpEvent from './utils/httpEvent'; -import otherEvent from './utils/otherEvent'; +import DefaultCallback from "./utils/DefaultCallback"; +import httpEvent from "./utils/httpEvent"; +import otherEvent from "./utils/otherEvent"; /** * Test for App. */ -describe('App', () => { +describe("App", () => { let app: App; beforeEach(() => { - app = new App() + app = new App(); }); - it('#init without settings should init with default configuration', async () => { - app.init() + it("#init without settings should init with default configuration", async () => { + app.init(); Object.keys(defaultConfiguration) - .forEach(param => Chai.expect(defaultConfiguration[param]).to.be.equal(app.get(param))) + .forEach((param) => Chai.expect(defaultConfiguration[param]).to.be.equal(app.get(param))); }); - it('#init with settings should init with custom configuration', async () => { - const settings = {} - settings[configuration.DEFAULT_MYME_TYPE] = 'text/html' + it("#init with settings should init with custom configuration", async () => { + const settings = {}; + settings[configuration.DEFAULT_MYME_TYPE] = "text/html"; - app.init(settings) + app.init(settings); Object.keys(settings) - .forEach(param => Chai.expect(settings[param]).to.be.equal(app.get(param))) + .forEach((param) => Chai.expect(settings[param]).to.be.equal(app.get(param))); }); - it('#enable should set the param as true', async () => { - app.enable('option1') - Chai.expect(app.get('option1')).to.be.true + it("#enable should set the param as true", async () => { + app.enable("option1"); + Chai.expect(app.get("option1")).to.be.true; }); - it('#disable should set the param as false', async () => { - app.disable('option1') - Chai.expect(app.get('option1')).to.be.false + it("#disable should set the param as false", async () => { + app.disable("option1"); + Chai.expect(app.get("option1")).to.be.false; }); - it('#set should set the param with the indicated value', async () => { - app.set('option1', 'value1') - Chai.expect(app.get('option1')).to.be.equal('value1') + it("#set should set the param with the indicated value", async () => { + app.set("option1", "value1"); + Chai.expect(app.get("option1")).to.be.equal("value1"); }); describe("#handle", () => { diff --git a/test/event/EventLayer.spec.ts b/test/event/EventLayer.spec.ts index 9df0093..a7ae5ed 100644 --- a/test/event/EventLayer.spec.ts +++ b/test/event/EventLayer.spec.ts @@ -1,78 +1,79 @@ -import * as Chai from 'chai' -import EventRequest from './../../src/lib/event/EventRequest' -import EventLayer from './../../src/lib/event/EventLayer' -import otherEvent from './../utils/otherEvent'; +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import EventLayer from "./../../src/lib/event/EventLayer"; +import EventRequest from "./../../src/lib/event/EventRequest"; +import otherEvent from "./../utils/otherEvent"; /** * Test for EventLayer. */ -describe('EventLayer', () => { - let req +describe("EventLayer", () => { + let req; beforeEach(() => { - req = new EventRequest(Object.assign({}, otherEvent)) - }) + req = new EventRequest(Object.assign({}, otherEvent)); + }); - describe('#match', () => { - it('should return true if the looking event is an event type (string) and the event type of the given #request is the same.', () => { - const layer = new EventLayer('S3CreateEvent', () => {}) - Chai.expect(layer.match(req)).to.be.true + describe("#match", () => { + it("should return true if the looking event is an event type (string) and the event type of the given #request is the same.", () => { + const layer = new EventLayer("S3CreateEvent", () => console.log("OK")); + Chai.expect(layer.match(req)).to.be.true; }); - it('should return false if the looking event is an event type (string) and the event type of the given #request is NOT the same.', () => { - const layer = new EventLayer('SNSEvent', () => {}) - Chai.expect(layer.match(req)).to.be.false + it("should return false if the looking event is an event type (string) and the event type of the given #request is NOT the same.", () => { + const layer = new EventLayer("SNSEvent", () => console.log("OK")); + Chai.expect(layer.match(req)).to.be.false; }); - it('should return true if the looking event is a predicate (function) and the result of calling that function with the given #request is true.', () => { - const predicate = (req) => req.event.original.Records[0].s3.bucket.arn == 'arn:aws:s3:::example-bucket' - const layer = new EventLayer(predicate, () => {}) - Chai.expect(layer.match(req)).to.be.true + it("should return true if the looking event is a predicate (function) and the result of calling that function with the given #request is true.", () => { + const predicate = (request) => req.event.original.Records[0].s3.bucket.arn === "arn:aws:s3:::example-bucket"; + const layer = new EventLayer(predicate, () => console.log("OK")); + Chai.expect(layer.match(req)).to.be.true; }); - it('should return false if the looking event is a predicate (function) and the result of calling that function with the given #request is false.', () => { - const predicate = (req) => req.event.original.Records[0].s3.bucket.arn == 'other-bucket' - const layer = new EventLayer(predicate, () => {}) - Chai.expect(layer.match(req)).to.be.false + it("should return false if the looking event is a predicate (function) and the result of calling that function with the given #request is false.", () => { + const predicate = (request) => req.event.original.Records[0].s3.bucket.arn === "other-bucket"; + const layer = new EventLayer(predicate, () => console.log("OK")); + Chai.expect(layer.match(req)).to.be.false; }); }); - describe('#handle', () => { - it('should call the handler if it exists.', (done) => { - const layer = new EventLayer('S3CreateEvent', () => { - done() - }) + describe("#handle", () => { + it("should call the handler if it exists.", (done) => { + const layer = new EventLayer("S3CreateEvent", () => { + done(); + }); - layer.handle(req, () => {}, null) + layer.handle(req, () => console.log("OK"), null); }); - it('should call #next if the handler does not exist.', (done) => { - const layer = new EventLayer('S3CreateEvent', null) + it("should call #next if the handler does not exist.", (done) => { + const layer = new EventLayer("S3CreateEvent", null); - layer.handle(req, () => { - done() - }, null) + layer.handle( + req, + () => { + done(); + }, + null + ); }); }); - describe('#isErrorHandler', () => { - it('should return true if the handler has 3 arguments as input.', () => { - const layer = new EventLayer('S3CreateEvent', (arg1, arg2, arg3) => { - - }) - Chai.expect(layer.isErrorHandler()).to.be.true + describe("#isErrorHandler", () => { + it("should return true if the handler has 3 arguments as input.", () => { + const layer = new EventLayer("S3CreateEvent", (arg1, arg2, arg3) => console.log("OK")); + Chai.expect(layer.isErrorHandler()).to.be.true; }); - it('should return false if the handler doesn\'t exist.', () => { - const layer = new EventLayer('S3CreateEvent', null) - Chai.expect(layer.isErrorHandler()).to.be.false + it("should return false if the handler doesn't exist.", () => { + const layer = new EventLayer("S3CreateEvent", null); + Chai.expect(layer.isErrorHandler()).to.be.false; }); - it('should return false if the handler has NOT 3 arguments as input.', () => { - const layer = new EventLayer('S3CreateEvent', (arg1, arg2) => { - - }) - Chai.expect(layer.isErrorHandler()).to.be.false + it("should return false if the handler has NOT 3 arguments as input.", () => { + const layer = new EventLayer("S3CreateEvent", (arg1, arg2) => console.log("OK")); + Chai.expect(layer.isErrorHandler()).to.be.false; }); }); diff --git a/test/event/EventRequest.spec.ts b/test/event/EventRequest.spec.ts index d95d0f9..e0fb53d 100644 --- a/test/event/EventRequest.spec.ts +++ b/test/event/EventRequest.spec.ts @@ -1,7 +1,8 @@ -import * as Chai from "chai" -import otherEvent from "./../utils/otherEvent"; +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import EventRequest from "./../../src/lib/event/EventRequest"; import RawEvent from "./../../src/lib/RawEvent"; -import EventRequest from "./../../src/lib/event/EventRequest" +import otherEvent from "./../utils/otherEvent"; /** * Test for EventRequest. @@ -10,8 +11,8 @@ describe("EventRequest", () => { describe("#eventType", () => { it("should return the type of the raw event.", () => { - const req = new EventRequest(otherEvent) - Chai.expect(req.eventType).to.be.equal("S3CreateEvent") + const req = new EventRequest(otherEvent); + Chai.expect(req.eventType).to.be.equal("S3CreateEvent"); }); describe("#context", () => { diff --git a/test/event/EventRouterExecutor.spec.ts b/test/event/EventRouterExecutor.spec.ts index 586a25d..ecfe149 100644 --- a/test/event/EventRouterExecutor.spec.ts +++ b/test/event/EventRouterExecutor.spec.ts @@ -1,207 +1,208 @@ -import * as Chai from 'chai' -import EventRouterExecutor from './../../src/lib/event/EventRouterExecutor' -import EventRequest from './../../src/lib/event/EventRequest' -import Router from './../../src/lib/Router' -import otherEvent from './../utils/otherEvent'; +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import EventRequest from "./../../src/lib/event/EventRequest"; +import EventRouterExecutor from "./../../src/lib/event/EventRouterExecutor"; +import Router from "./../../src/lib/Router"; +import otherEvent from "./../utils/otherEvent"; /** * Test for EventRouterExecutor. */ -describe('EventRouterExecutor', () => { - let req - let router +describe("EventRouterExecutor", () => { + let req; + let router; beforeEach(() => { - req = new EventRequest(otherEvent) - router = new Router - }) - - describe('#next', () => { - it('should call #handle on the first layer which match with the request (if it exists).', (done) => { - router.event('S3CreateEvent', () => { - done() - }) - - const routerExecutor = new EventRouterExecutor(router, req, () => {}) - routerExecutor.next() + req = new EventRequest(otherEvent); + router = new Router(); + }); + + describe("#next", () => { + it("should call #handle on the first layer which match with the request (if it exists).", (done) => { + router.event("S3CreateEvent", () => { + done(); + }); + + const routerExecutor = new EventRouterExecutor(router, req, () => console.log("OK")); + routerExecutor.next(); }); - it('should call #handle on the next layer (after a previous next call) which match with the request (if it exists).', (done) => { - let previouslyCalled = false + it("should call #handle on the next layer (after a previous next call) which match with the request (if it exists).", (done) => { + let previouslyCalled = false; - router.event('S3CreateEvent', (req, next) => { - previouslyCalled = true - next() - }) + router.event("S3CreateEvent", (request, next) => { + previouslyCalled = true; + next(); + }); - router.event('S3CreateEvent', () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + router.event("S3CreateEvent", () => { + Chai.expect(previouslyCalled).to.be.true; + done(); + }); - const routerExecutor = new EventRouterExecutor(router, req, () => {}) - routerExecutor.next() + const routerExecutor = new EventRouterExecutor(router, req, () => console.log("OK")); + routerExecutor.next(); }); - it('should call #next if there is no layer matching with the request.', (done) => { - let previouslyCalled = false + it("should call #next if there is no layer matching with the request.", (done) => { + let previouslyCalled = false; - router.event('SNSEvent', (req, next) => { - previouslyCalled = true - next() - }) + router.event("SNSEvent", (request, next) => { + previouslyCalled = true; + next(); + }); const routerExecutor = new EventRouterExecutor(router, req, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.false; + done(); + }); + routerExecutor.next(); }); - it('should call #next if the found layer hasn\'t an error handler and the given #error is not undefined.', (done) => { - let previouslyCalled = false + it("should call #next if the found layer hasn't an error handler and the given #error is not undefined.", (done) => { + let previouslyCalled = false; - router.event('S3CreateEvent', (req, next) => { - previouslyCalled = true - next() - }) + router.event("S3CreateEvent", (request, next) => { + previouslyCalled = true; + next(); + }); const routerExecutor = new EventRouterExecutor(router, req, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }) - routerExecutor.next(new Error) + Chai.expect(previouslyCalled).to.be.false; + done(); + }); + routerExecutor.next(new Error()); }); - it('should use the layer if the found layer has an error handler and the given #error is not undefined.', (done) => { - let previouslyCalled = false + it("should use the layer if the found layer has an error handler and the given #error is not undefined.", (done) => { + let previouslyCalled = false; - router.event('S3CreateEvent', (req, next, err) => { - previouslyCalled = true - next(err) - }) + router.event("S3CreateEvent", (request, next, err) => { + previouslyCalled = true; + next(err); + }); const routerExecutor = new EventRouterExecutor(router, req, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) - routerExecutor.next(new Error) + Chai.expect(previouslyCalled).to.be.true; + done(); + }); + routerExecutor.next(new Error()); }); - it('should call #eventHandle on the first subrouter whose event stack is not empty (if it exists) and when there is no more layer in the stack.', (done) => { - let previouslyCalled = false + it("should call #eventHandle on the first subrouter whose event stack is not empty (if it exists) and when there is no more layer in the stack.", (done) => { + let previouslyCalled = false; - router.event('S3CreateEvent', (req, next) => { - previouslyCalled = true - next() - }) + router.event("S3CreateEvent", (request, next) => { + previouslyCalled = true; + next(); + }); - const subrouter = new Router - subrouter.event('S3CreateEvent', (req) => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + const subrouter = new Router(); + subrouter.event("S3CreateEvent", (request) => { + Chai.expect(previouslyCalled).to.be.true; + done(); + }); - router.mount(subrouter) + router.mount(subrouter); - const routerExecutor = new EventRouterExecutor(router, req, () => {}) - routerExecutor.next() + const routerExecutor = new EventRouterExecutor(router, req, () => console.log("OK")); + routerExecutor.next(); }); - it('should call #eventHandle on the first subrouter whose event stack is not empty (if it exists) and when the layer stack is empty.', (done) => { - const subrouter = new Router - subrouter.event('S3CreateEvent', (req) => { - done() - }) + it("should call #eventHandle on the first subrouter whose event stack is not empty (if it exists) and when the layer stack is empty.", (done) => { + const subrouter = new Router(); + subrouter.event("S3CreateEvent", (request) => { + done(); + }); - router.mount(subrouter) + router.mount(subrouter); - const routerExecutor = new EventRouterExecutor(router, req, () => {}) - routerExecutor.next() + const routerExecutor = new EventRouterExecutor(router, req, () => console.log("OK")); + routerExecutor.next(); }); - it('should call #eventHandle on the next subrouter (after a previous next call) whose event stack is not empty (if it exists).', (done) => { - let previouslyCalled = false + it("should call #eventHandle on the next subrouter (after a previous next call) whose event stack is not empty (if it exists).", (done) => { + let previouslyCalled = false; - const subrouter1 = new Router + const subrouter1 = new Router(); - const subrouter2 = new Router - subrouter2.event('S3CreateEvent', (req, next) => { - previouslyCalled = true - next() - }) + const subrouter2 = new Router(); + subrouter2.event("S3CreateEvent", (request, next) => { + previouslyCalled = true; + next(); + }); - const subrouter3 = new Router - subrouter3.event('S3CreateEvent', (req, next) => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + const subrouter3 = new Router(); + subrouter3.event("S3CreateEvent", (request, next) => { + Chai.expect(previouslyCalled).to.be.true; + done(); + }); - router.mount(subrouter1) - router.mount(subrouter2) - router.mount(subrouter3) + router.mount(subrouter1); + router.mount(subrouter2); + router.mount(subrouter3); - const routerExecutor = new EventRouterExecutor(router, req, () => {}) - routerExecutor.next() + const routerExecutor = new EventRouterExecutor(router, req, () => console.log("OK")); + routerExecutor.next(); }); - it('should call #next if there is no subrouter whose event stack is not empty.', (done) => { - const subrouter = new Router - router.mount(subrouter) + it("should call #next if there is no subrouter whose event stack is not empty.", (done) => { + const subrouter = new Router(); + router.mount(subrouter); const routerExecutor = new EventRouterExecutor(router, req, () => { - done() - }) - routerExecutor.next() + done(); + }); + routerExecutor.next(); }); - it('should call #done if the subrouters and the layers stacks are empty.', (done) => { + it("should call #done if the subrouters and the layers stacks are empty.", (done) => { const routerExecutor = new EventRouterExecutor(router, req, () => { - done() - }) - routerExecutor.next() + done(); + }); + routerExecutor.next(); }); - it('should call #done in the following call to next when the layers and the subrouters stacks have been processed.', (done) => { - let previouslyCalledLayer = false - let previouslyCalledSubrouter = false + it("should call #done in the following call to next when the layers and the subrouters stacks have been processed.", (done) => { + let previouslyCalledLayer = false; + let previouslyCalledSubrouter = false; - router.event('S3CreateEvent', (req, next) => { - previouslyCalledLayer = true - next() - }) + router.event("S3CreateEvent", (request, next) => { + previouslyCalledLayer = true; + next(); + }); - const subrouter = new Router - subrouter.event('S3CreateEvent', (req, next) => { - previouslyCalledSubrouter = true - next() - }) - router.mount(subrouter) + const subrouter = new Router(); + subrouter.event("S3CreateEvent", (request, next) => { + previouslyCalledSubrouter = true; + next(); + }); + router.mount(subrouter); const routerExecutor = new EventRouterExecutor(router, req, () => { - Chai.expect(previouslyCalledLayer).to.be.true - Chai.expect(previouslyCalledSubrouter).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalledLayer).to.be.true; + Chai.expect(previouslyCalledSubrouter).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should reset the request params as the initial ones when #done is called.', (done) => { - const initialNext = req.next - let previouslyCalled = false + it("should reset the request params as the initial ones when #done is called.", (done) => { + const initialNext = req.next; + let previouslyCalled = false; - router.event('S3CreateEvent', (req, next) => { - previouslyCalled = true - Chai.expect(initialNext).to.be.not.equals(req.next) - next() - }) + router.event("S3CreateEvent", (request, next) => { + previouslyCalled = true; + Chai.expect(initialNext).to.be.not.equals(req.next); + next(); + }); const routerExecutor = new EventRouterExecutor(router, req, () => { - Chai.expect(previouslyCalled).to.be.true - Chai.expect(initialNext).to.be.equals(req.next) - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.true; + Chai.expect(initialNext).to.be.equals(req.next); + done(); + }); + routerExecutor.next(); }); }); diff --git a/test/event/eventFinalHandler.spec.ts b/test/event/eventFinalHandler.spec.ts index addfa38..093999d 100644 --- a/test/event/eventFinalHandler.spec.ts +++ b/test/event/eventFinalHandler.spec.ts @@ -1,41 +1,41 @@ -import * as Chai from 'chai' -import eventFinalHandler from './../../src/lib/event/eventFinalHandler' -import EventRequest from './../../src/lib/event/EventRequest' -import otherEvent from './../utils/otherEvent'; +/* tslint:disable:no-unused-expression */ +import eventFinalHandler from "./../../src/lib/event/eventFinalHandler"; +import EventRequest from "./../../src/lib/event/EventRequest"; +import otherEvent from "./../utils/otherEvent"; /** * Test for eventFinalHandler. */ -describe('eventFinalHandler', () => { - let req +describe("eventFinalHandler", () => { + let req; beforeEach(() => { - req = new EventRequest(otherEvent) + req = new EventRequest(otherEvent); }); it("should call #onerror handler if it is set in the #options when #error is undefined.", (done) => { const options = { - onerror: (err, req) => { - done() + onerror: (err, request) => { + done(); } - } - const handler = eventFinalHandler(req, options) - handler(new Error) + }; + const handler = eventFinalHandler(req, options); + handler(new Error()); }); it("should call #onerror handler if it is set in the #options when #error is NOT undefined.", (done) => { const options = { - onerror: (err, req) => { - done() + onerror: (err, request) => { + done(); } - } - const handler = eventFinalHandler(req, options) - handler() + }; + const handler = eventFinalHandler(req, options); + handler(); }); it("should do nothing without errors if no #onerror handler is given.", () => { - const handler = eventFinalHandler(req, null) - handler() + const handler = eventFinalHandler(req, null); + handler(); }); }); diff --git a/test/http/HttpLayer.spec.ts b/test/http/HttpLayer.spec.ts index 7fe1cc7..1708ec9 100644 --- a/test/http/HttpLayer.spec.ts +++ b/test/http/HttpLayer.spec.ts @@ -1,88 +1,88 @@ -import * as Chai from 'chai' -import { stub, SinonStub } from "sinon"; -import HttpError from './../../src/lib/exceptions/HttpError' -import HttpLayer from './../../src/lib/http/HttpLayer' -import IHttpLayer from './../../src/lib/types/http/IHttpLayer' -import HttpRoute from './../../src/lib/http/HttpRoute' -import IHttpRoute from './../../src/lib/types/http/IHttpRoute' -import App from './../../src/lib/App' -import IApp from './../../src/lib/types/IApp' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import IHttpResponse from './../../src/lib/types/http/IHttpResponse' -import IRouter from './../../src/lib/types/IRouter' -import Router from './../../src/lib/Router' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import App from "./../../src/lib/App"; +import HttpError from "./../../src/lib/exceptions/HttpError"; +import HttpLayer from "./../../src/lib/http/HttpLayer"; +import HttpRequest from "./../../src/lib/http/HttpRequest"; +import HttpResponse from "./../../src/lib/http/HttpResponse"; +import HttpRoute from "./../../src/lib/http/HttpRoute"; +import Router from "./../../src/lib/Router"; +import IHttpLayer from "./../../src/lib/types/http/IHttpLayer"; +import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; +import IHttpRoute from "./../../src/lib/types/http/IHttpRoute"; +import IApp from "./../../src/lib/types/IApp"; +import IRouter from "./../../src/lib/types/IRouter"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; /** * Test for HttpLayer. */ -describe('HttpLayer', () => { - let layer: IHttpLayer - const app: IApp = new App - const router: IRouter = new Router - const subrouter: IRouter = new Router - router.mount(subrouter, '/blog'); - let req: IHttpRequest - let res: IHttpResponse +describe("HttpLayer", () => { + let layer: IHttpLayer; + const app: IApp = new App(); + const router: IRouter = new Router(); + const subrouter: IRouter = new Router(); + router.mount(subrouter, "/blog"); + let req: IHttpRequest; + let res: IHttpResponse; const callback: DefaultCallback = new DefaultCallback(); beforeEach(() => { - req = new HttpRequest(Object.assign({}, httpEvent)) - res = new HttpResponse(app, req, callback) - layer = new HttpLayer(router, '/blog/:id', {}) + req = new HttpRequest(Object.assign({}, httpEvent)); + res = new HttpResponse(app, req, callback); + layer = new HttpLayer(router, "/blog/:id", {}); }); - describe('#match', () => { - it('should return true if #path match with the layer path.', () => { - Chai.expect(layer.match('/blog/1')).to.be.true + describe("#match", () => { + it("should return true if #path match with the layer path.", () => { + Chai.expect(layer.match("/blog/1")).to.be.true; }); - it('should return false if the given #path does not match with the layer path.', () => { - Chai.expect(layer.match('/blog')).to.be.false + it("should return false if the given #path does not match with the layer path.", () => { + Chai.expect(layer.match("/blog")).to.be.false; }); - it('should return true if the layer path is not defined.', () => { - const layer = new HttpLayer(router, null, {}) - Chai.expect(layer.match('/blog')).to.be.true + it("should return true if the layer path is not defined.", () => { + layer = new HttpLayer(router, null, {}); + Chai.expect(layer.match("/blog")).to.be.true; }); - it('should return true if the path is the router subpath plus the layer path.', () => { - layer = new HttpLayer(subrouter, '/:id', {}) - Chai.expect(layer.match('/blog/1')).to.be.true + it("should return true if the path is the router subpath plus the layer path.", () => { + layer = new HttpLayer(subrouter, "/:id", {}); + Chai.expect(layer.match("/blog/1")).to.be.true; }); it("should return false if the path doesn't match with the router subpath.", () => { - layer = new HttpLayer(subrouter, '/:id', {}) - Chai.expect(layer.match('/projects/1')).to.be.false + layer = new HttpLayer(subrouter, "/:id", {}); + Chai.expect(layer.match("/projects/1")).to.be.false; }); }); - describe('#parsePathParameters', () => { - it('should return the parameters of the layer path with the related values in the given #path.', () => { - Chai.expect(layer.parsePathParameters('/blog/1')).to.be.deep.equal({id: '1'}) + describe("#parsePathParameters", () => { + it("should return the parameters of the layer path with the related values in the given #path.", () => { + Chai.expect(layer.parsePathParameters("/blog/1")).to.be.deep.equal({id: "1"}); }); - it('should return an empty object if the layer path has no parameters.', () => { - const layer: IHttpLayer = new HttpLayer(router, '/blog', {}) - Chai.expect(layer.parsePathParameters('/blog')).to.be.empty + it("should return an empty object if the layer path has no parameters.", () => { + layer = new HttpLayer(router, "/blog", {}); + Chai.expect(layer.parsePathParameters("/blog")).to.be.empty; }); it("should return the path as 0 variable if the layer path is *", () => { - const layer: IHttpLayer = new HttpLayer(router, "*", {}); + layer = new HttpLayer(router, "*", {}); Chai.expect(layer.parsePathParameters("/blog")).to.be.deep.equal({0: "/blog"}); }); it("should return an empty object if the layer path is / and the layer end option is false.", () => { - const layer: IHttpLayer = new HttpLayer(router, "/", {end: false}); + layer = new HttpLayer(router, "/", {end: false}); Chai.expect(layer.parsePathParameters("/blog")).to.be.empty; }); it("should return an empty object if the layer path is not in the router subpath.", () => { - const layer: IHttpLayer = new HttpLayer(subrouter, "/:id", {}); + layer = new HttpLayer(subrouter, "/:id", {}); Chai.expect(layer.parsePathParameters("/projects/1")).to.be.empty; }); @@ -91,114 +91,129 @@ describe('HttpLayer', () => { }); }); - describe('#handle', () => { - it('should call the #route dispatcher if #error is undefined and the layer has a #route (and it hasn\'t a #handler).', (done) => { + describe("#handle", () => { + it("should call the #route dispatcher if #error is undefined and the layer has a #route (and it hasn't a #handler).", (done) => { let previouslyCalled: boolean = false; - const route: IHttpRoute = new HttpRoute(layer) - layer.route = route - route.all((req, res, next) => { - previouslyCalled = true - next() - }) + const route: IHttpRoute = new HttpRoute(layer); + layer.route = route; + route.all((request, response, next) => { + previouslyCalled = true; + next(); + }); layer.handle(req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + Chai.expect(previouslyCalled).to.be.true; + done(); + }); }); - it('should call #next if #error is NOT undefined and the layer has a #route (and it hasn\'t a #handler).', (done) => { + it("should call #next if #error is NOT undefined and the layer has a #route (and it hasn't a #handler).", (done) => { let previouslyCalled: boolean = false; - const route: IHttpRoute = new HttpRoute(layer) - layer.route = route - route.all((req, res, next) => { - previouslyCalled = true - next() - }) - layer.handle(req, res, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }, new Error) - }); - - it('should call #next if the layer hasn\'t #handler neither #route.', (done) => { + const route: IHttpRoute = new HttpRoute(layer); + layer.route = route; + route.all((request, response, next) => { + previouslyCalled = true; + next(); + }); + layer.handle( + req, + res, + () => { + Chai.expect(previouslyCalled).to.be.false; + done(); + }, + new Error() + ); + }); + + it("should call #next if the layer hasn't #handler neither #route.", (done) => { layer.handle(req, res, () => { - done() - }) + done(); + }); }); - it('should call #handler if the layer has an error #handler and there is an #error.', (done) => { + it("should call #handler if the layer has an error #handler and there is an #error.", (done) => { let previouslyCalled: boolean = false; - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next, error) => { - previouslyCalled = true - next() - }) - layer.handle(req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }, new Error) - }); - - it('should call #next with the incoming #error if the layer has a #handler without error handling and there is an #error.', (done) => { - const error: Error = new Error('Test') + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next, error) => { + previouslyCalled = true; + next(); + }); + layer.handle( + req, + res, + () => { + Chai.expect(previouslyCalled).to.be.true; + done(); + }, + new Error() + ); + }); + + it("should call #next with the incoming #error if the layer has a #handler without error handling and there is an #error.", (done) => { + const error: Error = new Error("Test"); let previouslyCalled: boolean = false; - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next) => { - previouslyCalled = true - next() - }) - layer.handle(req, res, (err) => { - Chai.expect(previouslyCalled).to.be.false - Chai.expect(err).to.be.equals(error) - done() - }, error) - }); - - it('should call #handler if the layer has #handler and there isn\'t an error.', (done) => { + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next) => { + previouslyCalled = true; + next(); + }); + layer.handle( + req, + res, + (err) => { + Chai.expect(previouslyCalled).to.be.false; + Chai.expect(err).to.be.equals(error); + done(); + }, + error + ); + }); + + it("should call #handler if the layer has #handler and there isn't an error.", (done) => { let previouslyCalled: boolean = false; - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next) => { - previouslyCalled = true - next() - }) + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next) => { + previouslyCalled = true; + next(); + }); layer.handle(req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + Chai.expect(previouslyCalled).to.be.true; + done(); + }); }); - it('should call #next with error if the #handler raise an exception.', (done) => { - const error: Error = new Error('Test') - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next) => { - throw error - }) + it("should call #next with error if the #handler raise an exception.", (done) => { + const error: Error = new Error("Test"); + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next) => { + throw error; + }); layer.handle(req, res, (err) => { - Chai.expect(err).to.be.equal(error) - done() - }) + Chai.expect(err).to.be.equal(error); + done(); + }); }); }); - describe('#isErrorHandler', () => { - it('should return false if the layer has a #route.', () => { - const route: IHttpRoute = new HttpRoute(layer) - layer.route = route - Chai.expect(layer.isErrorHandler()).to.be.false + describe("#isErrorHandler", () => { + it("should return false if the layer has a #route.", () => { + const route: IHttpRoute = new HttpRoute(layer); + layer.route = route; + Chai.expect(layer.isErrorHandler()).to.be.false; }); - it('should return false if the layer hasn\'t a #route but the #handler has 3 arguments as input.', () => { - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next) => { - - }) - Chai.expect(layer.isErrorHandler()).to.be.false + it("should return false if the layer hasn't a #route but the #handler has 3 arguments as input.", () => { + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next) => { + console.log("OK"); + }); + Chai.expect(layer.isErrorHandler()).to.be.false; }); - it('should return false if the layer hasn\'t a #route and hasn\'t a #handler.', () => { - Chai.expect(layer.isErrorHandler()).to.be.false + it("should return false if the layer hasn't a #route and hasn't a #handler.", () => { + Chai.expect(layer.isErrorHandler()).to.be.false; }); - it('should return true if the layer hasn\'t a #route and the #handler has 4 arguments as input.', () => { - const layer: IHttpLayer = new HttpLayer(router, '/blog/:id', {}, (req, res, next, err) => { - - }) - Chai.expect(layer.isErrorHandler()).to.be.true + it("should return true if the layer hasn't a #route and the #handler has 4 arguments as input.", () => { + layer = new HttpLayer(router, "/blog/:id", {}, (request, response, next, err) => { + console.log("OK"); + }); + Chai.expect(layer.isErrorHandler()).to.be.true; }); }); }); diff --git a/test/http/HttpRequest.spec.ts b/test/http/HttpRequest.spec.ts index 03f7ec8..2620acf 100644 --- a/test/http/HttpRequest.spec.ts +++ b/test/http/HttpRequest.spec.ts @@ -1,9 +1,9 @@ -import * as Chai from 'chai' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import HttpRoute from './../../src/lib/http/HttpRoute' -import App from './../../src/lib/App' +/* tslint:disable:no-unused-expression */ +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 IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; import IRawEvent from "./../../src/lib/types/IRawEvent"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; @@ -11,185 +11,183 @@ import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRequest. */ -describe('HttpRequest', () => { - let request: IHttpRequest - let nextResult +describe("HttpRequest", () => { + let request: IHttpRequest; let event: IRawEvent; - const app = new App() - beforeEach(function(done) { - nextResult = undefined + const app = new App(); + beforeEach((done) => { event = Object.assign({}, httpEvent); - request = new HttpRequest(event) + request = new HttpRequest(event); - done() + done(); }); - it('#headers should return the incoming request headers', () => { - const headers = {} - for(let key in event.headers) { - headers[key.toLowerCase()] = event.headers[key] + it("#headers should return the incoming request headers", () => { + const headers = {}; + for (const key of Object.keys(event.headers)) { + headers[key.toLowerCase()] = event.headers[key]; } - Chai.expect(request.headers).includes(headers) + Chai.expect(request.headers).includes(headers); }); - it('#protocol should return the incoming request protocol', () => { - Chai.expect(request.protocol).to.be.equal(event.headers['X-Forwarded-Proto']) + it("#protocol should return the incoming request protocol", () => { + Chai.expect(request.protocol).to.be.equal(event.headers["X-Forwarded-Proto"]); }); - it('#secure should return true if the incoming request is secure', () => { - Chai.expect(request.secure).to.be.true + it("#secure should return true if the incoming request is secure", () => { + Chai.expect(request.secure).to.be.true; }); - it('#secure should return false if the incoming request is not secure', () => { - request.headers['x-forwarded-proto'] = 'http' - Chai.expect(request.secure).to.be.false + it("#secure should return false if the incoming request is not secure", () => { + request.headers["x-forwarded-proto"] = "http"; + Chai.expect(request.secure).to.be.false; }); - it('#ip should return the incoming request user ip', () => { - Chai.expect(request.ip).to.be.equal('197.0.0.0') + it("#ip should return the incoming request user ip", () => { + Chai.expect(request.ip).to.be.equal("197.0.0.0"); }); - it('#ip should return the incoming request user ip although the app is through a proxy', () => { - request.headers['x-forwarded-for'] = '197.0.0.0, 197.0.0.1, 197.0.0.2' - Chai.expect(request.ip).to.be.equal('197.0.0.2') + it("#ip should return the incoming request user ip although the app is through a proxy", () => { + request.headers["x-forwarded-for"] = "197.0.0.0, 197.0.0.1, 197.0.0.2"; + Chai.expect(request.ip).to.be.equal("197.0.0.2"); }); - it('#path should return the incoming request path', () => { - Chai.expect(request.path).to.be.equals(event.path) + it("#path should return the incoming request path", () => { + Chai.expect(request.path).to.be.equals(event.path); }); - it('#method should return the incoming request method', () => { - Chai.expect(request.method).to.be.equal(event.httpMethod) + it("#method should return the incoming request method", () => { + Chai.expect(request.method).to.be.equal(event.httpMethod); }); - it('#hostname should return the incoming request hostname', () => { - Chai.expect(request.hostname).to.be.equal(event.headers['Host']) + it("#hostname should return the incoming request hostname", () => { + Chai.expect(request.hostname).to.be.equal(event.headers.Host); }); - it('#xhr should return true if the incoming request is an AJAX request', () => { - request.headers['x-requested-with'] = 'xmlhttprequest' - Chai.expect(request.xhr).to.be.true + it("#xhr should return true if the incoming request is an AJAX request", () => { + request.headers["x-requested-with"] = "xmlhttprequest"; + Chai.expect(request.xhr).to.be.true; }); - it('#xhr should return false if the incoming request is not an AJAX request', () => { - Chai.expect(request.xhr).to.be.false + it("#xhr should return false if the incoming request is not an AJAX request", () => { + Chai.expect(request.xhr).to.be.false; }); - it('#params should return the intersection between the query, body and stage params (the path params will be included in router)', () => { + it("#params should return the intersection between the query, body and stage params (the path params will be included in router)", () => { Chai.expect(request.params).to.include({ - query1: 'Query 1', - stage1: 'Stage 1' - }) + query1: "Query 1", + stage1: "Stage 1" + }); }); - it('#header should return the value of the header given as argument', () => { - Chai.expect(request.header('header1')).to.be.equal('HEADER VALUE 1') + it("#header should return the value of the header given as argument", () => { + Chai.expect(request.header("header1")).to.be.equal("HEADER VALUE 1"); }); - it('#accepts should return the same type given as argument if it is accepted as response mime type', () => { - Chai.expect(request.accepts('text/html')).to.be.equal('text/html') + it("#accepts should return the same type given as argument if it is accepted as response mime type", () => { + Chai.expect(request.accepts("text/html")).to.be.equal("text/html"); }); - it('#accepts should return false if the type given as argument is not accepted as response mime type', () => { - Chai.expect(request.accepts('application/xml')).to.be.false + it("#accepts should return false if the type given as argument is not accepted as response mime type", () => { + Chai.expect(request.accepts("application/xml")).to.be.false; }); - it('#accepts should return the preferred type to be used as response mime type between the ones given in the parameter', () => { - Chai.expect(request.accepts(['application/json', 'text/html'])).to.be.equal('application/json') + it("#accepts should return the preferred type to be used as response mime type between the ones given in the parameter", () => { + Chai.expect(request.accepts(["application/json", "text/html"])).to.be.equal("application/json"); }); - it('#acceptsEncodings should return the same encoding given as argument if it is accepted as response encoding', () => { - Chai.expect(request.acceptsEncodings('deflate')).to.be.equal('deflate') + it("#acceptsEncodings should return the same encoding given as argument if it is accepted as response encoding", () => { + Chai.expect(request.acceptsEncodings("deflate")).to.be.equal("deflate"); }); - it('#acceptsEncodings should return false if the encoding given as argument is not accepted as response encoding', () => { - Chai.expect(request.acceptsEncodings('enc')).to.be.false + it("#acceptsEncodings should return false if the encoding given as argument is not accepted as response encoding", () => { + Chai.expect(request.acceptsEncodings("enc")).to.be.false; }); - it('#acceptsEncodings should return the preferred encoding to be used as response encoding between the ones given in the parameter', () => { - Chai.expect(request.acceptsEncodings(['gzip', 'deflate'])).to.be.equal('gzip') + it("#acceptsEncodings should return the preferred encoding to be used as response encoding between the ones given in the parameter", () => { + Chai.expect(request.acceptsEncodings(["gzip", "deflate"])).to.be.equal("gzip"); }); - it('#acceptsCharsets should return the same charset given as argument if it is accepted as response charset', () => { - Chai.expect(request.acceptsCharsets('ISO-8859-1')).to.be.equal('ISO-8859-1') + it("#acceptsCharsets should return the same charset given as argument if it is accepted as response charset", () => { + Chai.expect(request.acceptsCharsets("ISO-8859-1")).to.be.equal("ISO-8859-1"); }); - it('#acceptsCharsets should return false if the charset given as argument is not accepted as response charset', () => { - Chai.expect(request.acceptsCharsets('UTF-6')).to.be.false + it("#acceptsCharsets should return false if the charset given as argument is not accepted as response charset", () => { + Chai.expect(request.acceptsCharsets("UTF-6")).to.be.false; }); - it('#acceptsCharsets should return the preferred charset to be used as response charset between the ones given in the parameter', () => { - Chai.expect(request.acceptsCharsets(['UTF-8', 'ISO-8859-1'])).to.be.equal('UTF-8') + it("#acceptsCharsets should return the preferred charset to be used as response charset between the ones given in the parameter", () => { + Chai.expect(request.acceptsCharsets(["UTF-8", "ISO-8859-1"])).to.be.equal("UTF-8"); }); - it('#acceptsLanguages should return the same language given as argument if it is accepted as response language', () => { - Chai.expect(request.acceptsLanguages('en')).to.be.equal('en') + it("#acceptsLanguages should return the same language given as argument if it is accepted as response language", () => { + Chai.expect(request.acceptsLanguages("en")).to.be.equal("en"); }); - it('#acceptsLanguages should return false if the language given as argument is not accepted as response language', () => { - Chai.expect(request.acceptsLanguages('de')).to.be.false + it("#acceptsLanguages should return false if the language given as argument is not accepted as response language", () => { + Chai.expect(request.acceptsLanguages("de")).to.be.false; }); - it('#acceptsLanguages should return the preferred language to be used as response language between the ones given in the parameter', () => { - Chai.expect(request.acceptsLanguages(['es', 'en'])).to.be.equal('es') + it("#acceptsLanguages should return the preferred language to be used as response language between the ones given in the parameter", () => { + Chai.expect(request.acceptsLanguages(["es", "en"])).to.be.equal("es"); }); - it('#param should return the value of the param given as argument if it is into the query params', () => { - Chai.expect(request.param('query1')).to.be.equal('Query 1') + it("#param should return the value of the param given as argument if it is into the query params", () => { + Chai.expect(request.param("query1")).to.be.equal("Query 1"); }); - it('#param should return the value of the param given as argument if it is into the stage variables', () => { - Chai.expect(request.param('stage1')).to.be.equal('Stage 1') + it("#param should return the value of the param given as argument if it is into the stage variables", () => { + Chai.expect(request.param("stage1")).to.be.equal("Stage 1"); }); - it('#param should return the default value if the value of the param given as argument does not exist', () => { - Chai.expect(request.param('noParam', '0')).to.be.equal('0') + it("#param should return the default value if the value of the param given as argument does not exist", () => { + Chai.expect(request.param("noParam", "0")).to.be.equal("0"); }); - it('#param should return null if the value of the param given as argument does not exist and no default value is given', () => { - Chai.expect(request.param('noParam')).to.be.undefined + it("#param should return null if the value of the param given as argument does not exist and no default value is given", () => { + Chai.expect(request.param("noParam")).to.be.undefined; }); - it('#is should return true if the types given as parameter are accepted as response mime types', () => { - Chai.expect(request.is('application/json')) - Chai.expect(request.is(['application/json','text/html'])) + it("#is should return true if the types given as parameter are accepted as response mime types", () => { + Chai.expect(request.is("application/json")); + Chai.expect(request.is(["application/json", "text/html"])); }); - it('#is should return false if the types given as parameter are not accepted as response mime types', () => { - Chai.expect(request.is('application/xml')) - Chai.expect(request.is(['application/xml','text/html'])) + it("#is should return false if the types given as parameter are not accepted as response mime types", () => { + Chai.expect(request.is("application/xml")); + Chai.expect(request.is(["application/xml", "text/html"])); }); - it('#fresh should return true if the request is "fresh"', () => { + it("#fresh should return true if the request is 'fresh'", () => { const callback: DefaultCallback = new DefaultCallback(); - const response = new HttpResponse(app, request, callback) - response.status(200) - response.putHeader('ETag', 'etagValue') - response.putHeader('Last-Modified', '2017-10-10T10:10:09'); - Chai.expect(request.fresh(response)).to.be.true + const response = new HttpResponse(app, request, callback); + response.status(200); + response.putHeader("ETag", "etagValue"); + response.putHeader("Last-Modified", "2017-10-10T10:10:09"); + Chai.expect(request.fresh(response)).to.be.true; }); - it('#fresh should return false if the request is not "fresh"', () => { + it("#fresh should return false if the request is not 'fresh'", () => { const callback: DefaultCallback = new DefaultCallback(); - const response = new HttpResponse(app, request, callback) - response.status(200) - Chai.expect(request.fresh(response)).to.be.false + const response = new HttpResponse(app, request, callback); + response.status(200); + Chai.expect(request.fresh(response)).to.be.false; }); - it('#stale should return true if the request is "stale"', () => { + it("#stale should return true if the request is 'stale'", () => { const callback: DefaultCallback = new DefaultCallback(); - const response = new HttpResponse(app, request, callback) - response.status(200) - response.putHeader('ETag', 'etagValue') - response.putHeader('Last-Modified', '2017-10-10T10:10:09') - Chai.expect(request.stale(response)).to.be.false + const response = new HttpResponse(app, request, callback); + response.status(200); + response.putHeader("ETag", "etagValue"); + response.putHeader("Last-Modified", "2017-10-10T10:10:09"); + Chai.expect(request.stale(response)).to.be.false; }); - it('#stale should return false if the request is not "stale"', () => { + it("#stale should return false if the request is not 'stale'", () => { const callback: DefaultCallback = new DefaultCallback(); - const response = new HttpResponse(app, request, callback) - response.status(200) - Chai.expect(request.stale(response)).to.be.true + const response = new HttpResponse(app, request, callback); + response.status(200); + Chai.expect(request.stale(response)).to.be.true; }); }); diff --git a/test/http/HttpResponse.spec.ts b/test/http/HttpResponse.spec.ts index 637bc3d..3032a0b 100644 --- a/test/http/HttpResponse.spec.ts +++ b/test/http/HttpResponse.spec.ts @@ -1,119 +1,119 @@ -import * as Chai from 'chai' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; import { sign } from "cookie-signature"; -import { stub, SinonStub } from "sinon"; +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 Router from './../../src/lib/Router' -import IRouter from './../../src/lib/types/IRouter' -import configuration from './../../src/lib/configuration/configuration' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import IHttpResponse from './../../src/lib/types/http/IHttpResponse' -import HttpRoute from './../../src/lib/http/HttpRoute' -import TemplateEngine from './../../src/lib/http/renderEngine/TemplateEngine' -import App from './../../src/lib/App' -import IApp from './../../src/lib/types/IApp' -import { stringify } from './../../src/lib/utils/utils' +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 IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; +import IApp from "./../../src/lib/types/IApp"; import IRawEvent from "./../../src/lib/types/IRawEvent"; +import IRouter from "./../../src/lib/types/IRouter"; +import { stringify } from "./../../src/lib/utils/utils"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; /** * Test for HttpResponse. */ -describe('HttpResponse', () => { - let request: IHttpRequest - let response: IHttpResponse +describe("HttpResponse", () => { + let request: IHttpRequest; + let response: IHttpResponse; let event: IRawEvent; let app: IApp; let callback: DefaultCallback; - beforeEach(function(done) { - app = new App() + beforeEach((done) => { + app = new App(); event = Object.assign({}, httpEvent); - request = new HttpRequest(event) + request = new HttpRequest(event); callback = new DefaultCallback(); response = new HttpResponse(app, request, callback); - done() + done(); }); - it('#status should set the outcoming response status code', () => { - response.status(302) - response.send('') - Chai.expect(callback.successResult.statusCode).to.be.equal(302) + it("#status should set the outcoming response status code", () => { + response.status(302); + response.send(""); + Chai.expect(callback.successResult.statusCode).to.be.equal(302); }); - it('#statusCode should returns the outcoming response status code previously set', () => { - response.status(302) - Chai.expect(response.statusCode).to.be.equal(302) + it("#statusCode should returns the outcoming response status code previously set", () => { + response.status(302); + Chai.expect(response.statusCode).to.be.equal(302); }); describe("#send", () => { - it('should set the outcoming response body to the given string with "html" content type header and the right content length header', () => { - response.send('ABC') - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('text/html; charset=utf-8') - Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('3') - Chai.expect(response.isSent).to.be.true + it("should set the outcoming response body to the given string with 'html' content type header and the right content length header", () => { + response.send("ABC"); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("text/html; charset=utf-8"); + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.equal("3"); + Chai.expect(response.isSent).to.be.true; }); - it('should set the outcoming response body to the given number with no content type header and the right content length header', () => { - response.send(false) - Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined - Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('5') - Chai.expect(callback.successResult.body).to.be.equal('false') - Chai.expect(response.isSent).to.be.true + it("should set the outcoming response body to the given number with no content type header and the right content length header", () => { + response.send(false); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.equal("5"); + Chai.expect(callback.successResult.body).to.be.equal("false"); + Chai.expect(response.isSent).to.be.true; }); - it('should set the outcoming response body to the given boolean with no content type header and the right content length header', () => { - response.send(1) - Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined - Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('1') - Chai.expect(callback.successResult.body).to.be.equal('1') - Chai.expect(response.isSent).to.be.true + it("should set the outcoming response body to the given boolean with no content type header and the right content length header", () => { + response.send(1); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.equal("1"); + Chai.expect(callback.successResult.body).to.be.equal("1"); + Chai.expect(response.isSent).to.be.true; }); - it('should set the outcoming response body to the given Buffer with "bin" content type header and the right content length header', () => { - response.send(new Buffer('test')) - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('bin') - Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('4') - Chai.expect(callback.successResult.body).to.be.equal('test') - Chai.expect(response.isSent).to.be.true + it("should set the outcoming response body to the given Buffer with 'bin' content type header and the right content length header", () => { + response.send(new Buffer("test")); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("bin"); + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.equal("4"); + Chai.expect(callback.successResult.body).to.be.equal("test"); + Chai.expect(response.isSent).to.be.true; }); - it('should set the outcoming response header ETag to the generated with the function in #app.get(Configuration.ETAG_FN)', () => { - app.set(configuration.ETAG_FN, (buff, encoding) => 'ETAG' + buff.toString(encoding)) - response.send('test') - Chai.expect(callback.successResult.headers['ETag']).to.be.equal('ETAGtest') + it("should set the outcoming response header ETag to the generated with the function in #app.get(Configuration.ETAG_FN)", () => { + app.set(configuration.ETAG_FN, (buff, encoding) => "ETAG" + buff.toString(encoding)); + response.send("test"); + Chai.expect(callback.successResult.headers.ETag).to.be.equal("ETAGtest"); }); - it('should set the outcoming response status code to 304 if the response is not fresh', () => { - app.set(configuration.ETAG_FN, (buff, encoding) => 'etagValue') - response.putHeader('Last-Modified', '2017-10-10T10:10:09') - response.send('test') - Chai.expect(callback.successResult.statusCode).to.be.equal(304) + it("should set the outcoming response status code to 304 if the response is not fresh", () => { + app.set(configuration.ETAG_FN, (buff, encoding) => "etagValue"); + response.putHeader("Last-Modified", "2017-10-10T10:10:09"); + response.send("test"); + Chai.expect(callback.successResult.statusCode).to.be.equal(304); }); - it('should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 204', () => { - response.status(204) - response.send('') - Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined - Chai.expect(callback.successResult.headers['Content-Length']).to.be.undefined - Chai.expect(callback.successResult.headers['Transfer-Encoding']).to.be.undefined + it("should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 204", () => { + response.status(204); + response.send(""); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Transfer-Encoding"]).to.be.undefined; }); - it('should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 304', () => { - response.status(304) - response.send('') - Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined - Chai.expect(callback.successResult.headers['Content-Length']).to.be.undefined - Chai.expect(callback.successResult.headers['Transfer-Encoding']).to.be.undefined + it("should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 304", () => { + response.status(304); + response.send(""); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Transfer-Encoding"]).to.be.undefined; }); - it('should set the outcoming response body to null if the request method is HEAD', () => { - event.httpMethod = 'HEAD' - response.send('test') - Chai.expect(callback.successResult.body).to.be.undefined + it("should set the outcoming response body to null if the request method is HEAD", () => { + event.httpMethod = "HEAD"; + response.send("test"); + Chai.expect(callback.successResult.body).to.be.undefined; }); it("should set content type to bin if the sent body is a buffer and there is no previous set content type into the response.", () => { @@ -132,7 +132,7 @@ describe('HttpResponse', () => { }); response.send("test"); - Chai.expect(callback.successResult.headers["ETag"]).to.be.equal("test-undefined"); + Chai.expect(callback.successResult.headers.ETag).to.be.equal("test-undefined"); }); it("should pass the error param to the callback function if an error is set.", () => { @@ -152,142 +152,148 @@ describe('HttpResponse', () => { }); describe("#json", () => { - it('should set the outcoming response header Content-Type to "application/json"', () => { - response.json({}) - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/json; charset=utf-8') + it("should set the outcoming response header Content-Type to 'application/json'", () => { + response.json({}); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("application/json; charset=utf-8"); }); it("should keep the previous set content type if exists.", () => { response.contentType("text/plain"); - response.json({}) - Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("text/plain; charset=utf-8") + response.json({}); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("text/plain; charset=utf-8"); }); - it('should set the outcoming response header Content-Length to the right length', () => { - const body = {test: 'test1'} - const parsedBody = stringify(body, undefined, undefined, undefined) - response.json(body) - Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal(parsedBody.length.toString()) - Chai.expect(callback.successResult.body).to.be.equal(parsedBody) + it("should set the outcoming response header Content-Length to the right length", () => { + const body = {test: "test1"}; + const parsedBody = stringify(body, undefined, undefined, undefined); + response.json(body); + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.equal(parsedBody.length.toString()); + Chai.expect(callback.successResult.body).to.be.equal(parsedBody); }); }); describe("#sendStatus", () => { - it('should set the outcoming response header Content-Length to "txt", the body to the status code body and the satus code to the given status code', () => { - response.sendStatus(404) - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('text/plain; charset=utf-8') - Chai.expect(callback.successResult.body).to.be.equal('Not Found') + it("should set the outcoming response header Content-Length to 'txt', the body to the status code body and the satus code to the given status code", () => { + response.sendStatus(404); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("text/plain; charset=utf-8"); + Chai.expect(callback.successResult.body).to.be.equal("Not Found"); }); it("should set the status code as response body if there is no message for it.", () => { - response.sendStatus(1) + response.sendStatus(1); Chai.expect(callback.successResult.body).to.be.equal("1"); }); }); - it('#contentType should set content type to the given one', () => { - const contentType = 'application/xml' - response.contentType(contentType) - response.send('test') - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') + it("#contentType should set content type to the given one", () => { + const contentType = "application/xml"; + response.contentType(contentType); + response.send("test"); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("application/xml; charset=utf-8"); }); - it('#contentType should set content type to the given one and transform it to a full mime type if it does not have /', () => { - const contentType = 'xml' - response.contentType(contentType) - response.send('test') - Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') + it("#contentType should set content type to the given one and transform it to a full mime type if it does not have /", () => { + const contentType = "xml"; + response.contentType(contentType); + response.send("test"); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("application/xml; charset=utf-8"); }); - it('#format should execute the first function which key (mime type) is accepted by the incoming request', () => { + it("#format should execute the first function which key (mime type) is accepted by the incoming request", () => { let result; response.format({ - 'application/xml': (req, res) => { - result = 'NO'; + "application/xml": (req, res) => { + result = "NO"; }, - 'application/json': (req, res) => { - result = 'YES'; + "application/json": (req, res) => { + result = "YES"; } - }) - Chai.expect(result).to.be.equal('YES') + }); + Chai.expect(result).to.be.equal("YES"); }); - it('#format should execute the default function if it exists and no key is accepted by the incoming request', () => { + it("#format should execute the default function if it exists and no key is accepted by the incoming request", () => { let result; response.format({ - 'application/xml': (req, res) => { - result = 'NO'; + "application/xml": (req, res) => { + result = "NO"; }, - default: (req, res) => { - result = 'YES'; + "default": (req, res) => { + result = "YES"; } - }) - Chai.expect(result).to.be.equal('YES') + }); + Chai.expect(result).to.be.equal("YES"); }); - it('#format can execute #next if the function is given as argument', () => { + it("#format can execute #next if the function is given as argument", () => { let result; - response.format({ - 'application/json': (req, res, next) => { - next(); - } - }, (err) => { result = 'YES' }) - Chai.expect(result).to.be.equal('YES') + response.format( + { + "application/json": (req, res, next) => { + next(); + } + }, + (err) => result = "YES" + ); + Chai.expect(result).to.be.equal("YES"); }); - it('#format should execute #next with the "Not Acceptable" error if no key is accepted by the incoming request and #next is given as argument', () => { + it("#format should execute #next with the 'Not Acceptable' error if no key is accepted by the incoming request and #next is given as argument", () => { let err; - response.format({ - 'application/xml': (req, res, next) => { - next(); - } - }, (e) => { err = e }) - Chai.expect(err).to.not.be.undefined - Chai.expect(err.statusCode).to.be.equal(406) + response.format( + { + "application/xml": (req, res, next) => { + next(); + } + }, + (e) => err = e + ); + Chai.expect(err).to.not.be.undefined; + Chai.expect(err.statusCode).to.be.equal(406); }); - it('#format should throw "Not Acceptable" error if no key is accepted by the incoming request and #next is not given as argument', () => { + it("#format should throw 'Not Acceptable' error if no key is accepted by the incoming request and #next is not given as argument", () => { let err; try { response.format({ - 'application/xml': (req, res, next) => { + "application/xml": (req, res, next) => { next(); } - }) - } catch(e) { + }); + } catch (e) { err = e; } - Chai.expect(err).to.not.be.undefined - Chai.expect(err.statusCode).to.be.equal(406) + Chai.expect(err).to.not.be.undefined; + Chai.expect(err.statusCode).to.be.equal(406); }); - it('#putHeader should set the header `field` to `value`', () => { - response.putHeader('field', 'value'); - response.send('test'); - Chai.expect(callback.successResult.headers['field']).to.be.equal('value') + it("#putHeader should set the header `field` to `value`", () => { + response.putHeader("field", "value"); + response.send("test"); + Chai.expect(callback.successResult.headers.field).to.be.equal("value"); }); - it('#putHeaders should set each header of `obj`', () => { + it("#putHeaders should set each header of `obj`", () => { response.putHeaders({ - 'field1': 'value1', - 'field2': 'value2' + field1: "value1", + field2: "value2" }); - response.send('test'); - Chai.expect(callback.successResult.headers['field1']).to.be.equal('value1') - Chai.expect(callback.successResult.headers['field2']).to.be.equal('value2') + response.send("test"); + Chai.expect(callback.successResult.headers.field1).to.be.equal("value1"); + Chai.expect(callback.successResult.headers.field2).to.be.equal("value2"); }); - it('#header should return a previously set header', () => { - response.putHeader('field', 'value'); - Chai.expect(response.header('field')).to.be.equal('value') + it("#header should return a previously set header", () => { + response.putHeader("field", "value"); + Chai.expect(response.header("field")).to.be.equal("value"); }); describe("#appendHeader", () => { - it('should append a header to a previously set header', () => { - response.putHeader('field', 'value1'); - response.appendHeader('field', 'value2'); - Chai.expect(response.header('field')).to.be.contain('value1') - Chai.expect(response.header('field')).to.be.contain('value2') + it("should append a header to a previously set header", () => { + response.putHeader("field", "value1"); + response.appendHeader("field", "value2"); + Chai.expect(response.header("field")).to.be.contain("value1"); + Chai.expect(response.header("field")).to.be.contain("value2"); }); it("should add append a header to a list of headers previously set.", () => { @@ -309,16 +315,16 @@ describe('HttpResponse', () => { }); }); - it('#removeHeader should remove a previously set header', () => { - response.putHeader('field', 'value1'); - response.removeHeader('field'); - Chai.expect(response.header('field')).to.be.undefined + it("#removeHeader should remove a previously set header", () => { + response.putHeader("field", "value1"); + response.removeHeader("field"); + Chai.expect(response.header("field")).to.be.undefined; }); describe("#addCookie", () => { - it('should add the `name` cookie with the `value` and the `options`', () => { - response.addCookie('cookie', 'cookieValue', {path: '/test'}) - Chai.expect(response.header('Set-Cookie')).to.be.equal('cookie=cookieValue; Path=/test') + it("should add the `name` cookie with the `value` and the `options`", () => { + response.addCookie("cookie", "cookieValue", {path: "/test"}); + 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`.", () => { @@ -338,14 +344,13 @@ describe('HttpResponse', () => { }); it("should add `expires` and `maxAge` into the cookie if `maxAge` is given in options.", () => { - var oldDate = Date; + const oldDate = Date; global.Date = new Proxy(Date, { - construct: function(target, args) { + construct: (target, args) => { return new oldDate(2017, 11, 19, 0, 0, 0, 0); } }); - var x = new Date(); 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()); @@ -354,73 +359,79 @@ describe('HttpResponse', () => { }); }); - 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 `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('#clearCookie should add the cookie `field` with the `options` and the expires to 1 and the path to /', () => { - response.clearCookie('cookie') - Chai.expect(response.header('Set-Cookie')).to.be.equal('cookie=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT') + it("#clearCookie should add the cookie `field` with the `options` and the expires to 1 and the path to /", () => { + response.clearCookie("cookie"); + 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 `name`", () => { + response.addCookies( + { + cookie1: "cookieValue1", + cookie2: "cookieValue2" + }, + {path: "/test"} + ); + Chai.expect(response.cookie("cookie1")).to.be.equal("cookieValue1"); }); describe("location", () => { - it('should set the header Location to the given URL', () => { - response.location('/test'); - Chai.expect(response.header('Location')).to.be.equal('/test') + it("should set the header Location to the given URL", () => { + response.location("/test"); + Chai.expect(response.header("Location")).to.be.equal("/test"); }); it("should set the header Location to the Referrer URL if it exists and the given URL is \"back\".", () => { - request.headers["referrer"] = "/previous-url"; + request.headers.referrer = "/previous-url"; response.redirect("back"); - Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/previous-url"); + Chai.expect(callback.successResult.headers.Location).to.be.equal("/previous-url"); }); it("should set the header Location to / if the Referrer URL does not exist and the given URL is \"back\".", () => { response.redirect("back"); - Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/"); + Chai.expect(callback.successResult.headers.Location).to.be.equal("/"); }); }); describe("#redirect", () => { - it('should set the header Location to the given URL and the status code to 302', () => { - response.redirect('/test'); - Chai.expect(callback.successResult.headers['Location']).to.be.equal('/test') - Chai.expect(callback.successResult.statusCode).to.be.equal(302) + it("should set the header Location to the given URL and the status code to 302", () => { + response.redirect("/test"); + Chai.expect(callback.successResult.headers.Location).to.be.equal("/test"); + Chai.expect(callback.successResult.statusCode).to.be.equal(302); }); - it('should set the header Location to the given URL and the status code to the given one', () => { - response.redirect('/test', 301); - Chai.expect(callback.successResult.headers['Location']).to.be.equal('/test') - Chai.expect(callback.successResult.statusCode).to.be.equal(301) + it("should set the header Location to the given URL and the status code to the given one", () => { + response.redirect("/test", 301); + Chai.expect(callback.successResult.headers.Location).to.be.equal("/test"); + Chai.expect(callback.successResult.statusCode).to.be.equal(301); }); it("should set the body to HTML text if the request accepts text/html.", () => { - request.headers["accept"] = "text/html"; + request.headers.accept = "text/html"; response.redirect("/test"); Chai.expect(callback.successResult.body).to.be.equal("

Found. Redirecting to /test

"); }); it("should set the body to plain text if the request accepts text/plain.", () => { - request.headers["accept"] = "text/plain"; + request.headers.accept = "text/plain"; response.redirect("/test"); Chai.expect(callback.successResult.body).to.be.equal("Found. Redirecting to /test."); }); it("should set the body to empty string if the request doesn't accepts neither text/html nor text/plain.", () => { - request.headers["accept"] = "application/json"; + request.headers.accept = "application/json"; response.redirect("/test"); Chai.expect(callback.successResult.body).to.be.equal(""); }); @@ -429,7 +440,7 @@ describe('HttpResponse', () => { event.httpMethod = "HEAD"; response.redirect("/test"); Chai.expect(callback.successResult.body).to.be.undefined; - Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/test"); + Chai.expect(callback.successResult.headers.Location).to.be.equal("/test"); Chai.expect(callback.successResult.statusCode).to.be.equal(302); }); }); @@ -461,7 +472,7 @@ describe('HttpResponse', () => { it("should call the `callback` with the result of `templateEngine.render`.", (done) => { const expectedResult: string = "Result of render."; - renderStub.callsFake((view, params, callback) => callback(null, expectedResult)); + renderStub.callsFake((view, params, renderCallback) => renderCallback(null, expectedResult)); response.render("fileName", {}, (err, result) => { Chai.expect(result).to.be.equal(expectedResult); Chai.expect(err).to.be.null; @@ -471,7 +482,7 @@ describe('HttpResponse', () => { it("should call the `callback` with the error if the `templateEngine.render` method returns an error and a `callback` is given.", (done) => { const expectedError: Error = new Error("Render error."); - renderStub.callsFake((view, params, callback) => callback(expectedError, null)); + renderStub.callsFake((view, params, renderCallback) => renderCallback(expectedError, null)); response.render("fileName", {}, (err, result) => { Chai.expect(err).to.be.equal(expectedError); Chai.expect(result).to.be.null; @@ -481,7 +492,7 @@ describe('HttpResponse', () => { it("should call the `next` handler with the error if the `templateEngine.render` method returns an error and no `callback` is given.", (done) => { const expectedError: Error = new Error("Render error."); - renderStub.callsFake((view, params, callback) => callback(expectedError, null)); + renderStub.callsFake((view, params, renderCallback) => renderCallback(expectedError, null)); request.next = (err) => { Chai.expect(err).to.be.equal(expectedError); request.next = undefined; @@ -492,7 +503,7 @@ describe('HttpResponse', () => { it("should response with the html code and the 'text/html' content-type header if the `templateEngine.render` method returns no error and no `callback` is given.", () => { const expectedResult: string = "Result of render."; - renderStub.callsFake((view, params, callback) => callback(null, expectedResult)); + renderStub.callsFake((view, params, renderCallback) => renderCallback(null, expectedResult)); response.render("fileName"); Chai.expect(callback.successResult.headers["Content-Type"]).to.contain("text/html"); Chai.expect(callback.successResult.body).to.be.equal(expectedResult); diff --git a/test/http/HttpRoute.spec.ts b/test/http/HttpRoute.spec.ts index 43ea13f..7b840ec 100644 --- a/test/http/HttpRoute.spec.ts +++ b/test/http/HttpRoute.spec.ts @@ -1,100 +1,102 @@ -import * as Chai from 'chai' -import HttpLayer from './../../src/lib/http/HttpLayer' -import IHttpLayer from './../../src/lib/types/http/IHttpLayer' -import HttpRoute from './../../src/lib/http/HttpRoute' -import IHttpRoute from './../../src/lib/types/http/IHttpRoute' -import App from './../../src/lib/App' -import IApp from './../../src/lib/types/IApp' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import IHttpResponse from './../../src/lib/types/http/IHttpResponse' -import IRawEvent from './../../src/lib/types/IRawEvent' -import IRouter from './../../src/lib/types/IRouter' -import Router from './../../src/lib/Router' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import App from "./../../src/lib/App"; +import HttpLayer from "./../../src/lib/http/HttpLayer"; +import HttpRequest from "./../../src/lib/http/HttpRequest"; +import HttpResponse from "./../../src/lib/http/HttpResponse"; +import HttpRoute from "./../../src/lib/http/HttpRoute"; +import Router from "./../../src/lib/Router"; +import IHttpLayer from "./../../src/lib/types/http/IHttpLayer"; +import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; +import IHttpRoute from "./../../src/lib/types/http/IHttpRoute"; +import IApp from "./../../src/lib/types/IApp"; +import IRawEvent from "./../../src/lib/types/IRawEvent"; +import IRouter from "./../../src/lib/types/IRouter"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRoute. */ -describe('HttpRoute', () => { - const app: IApp = new App - const router: IRouter = new Router - let layer: IHttpLayer, route: IHttpRoute - let req: IHttpRequest, res: IHttpResponse +describe("HttpRoute", () => { + const app: IApp = new App(); + const router: IRouter = new Router(); + let layer: IHttpLayer; + let route: IHttpRoute; + let req: IHttpRequest; + let res: IHttpResponse; let event: IRawEvent; let callback: DefaultCallback; beforeEach(() => { event = Object.assign({}, httpEvent); callback = new DefaultCallback(); - layer = new HttpLayer(router, '/blog/:id', {}) - route = new HttpRoute(layer) - layer.route = route - req = new HttpRequest(event) + layer = new HttpLayer(router, "/blog/:id", {}); + route = new HttpRoute(layer); + layer.route = route; + req = new HttpRequest(event); res = new HttpResponse(app, req, callback); - }) - + }); - describe('#hasMethod', () => { - it('should return true if the has a handler for the given #method.', () => { - route.get((req, res, next) => {}) - Chai.expect(route.hasMethod('GET')).to.be.true + describe("#hasMethod", () => { + it("should return true if the has a handler for the given #method.", () => { + route.get((request, response, next) => { console.log("OK"); }); + Chai.expect(route.hasMethod("GET")).to.be.true; }); - it('should return false if the has NOT a handler for the given #method.', () => { - route.get((req, res, next) => {}) - Chai.expect(route.hasMethod('POST')).to.be.false + it("should return false if the has NOT a handler for the given #method.", () => { + route.get((request, response, next) => { console.log("OK"); }); + Chai.expect(route.hasMethod("POST")).to.be.false; }); - it('should return true if the has a handler for all.', () => { - route.all((req, res, next) => {}) - Chai.expect(route.hasMethod('POST')).to.be.true + it("should return true if the has a handler for all.", () => { + route.all((request, response, next) => { console.log("OK"); }); + Chai.expect(route.hasMethod("POST")).to.be.true; }); }); - describe('#dispatch', () => { - it('should call the handler for the request method (if it exists).', (done) => { - let previouslyCalled: boolean = false - route.get((req, res, next) => { - previouslyCalled = true - next() - }) + describe("#dispatch", () => { + it("should call the handler for the request method (if it exists).", (done) => { + let previouslyCalled: boolean = false; + route.get((request, response, next) => { + previouslyCalled = true; + next(); + }); route.dispatch(req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + Chai.expect(previouslyCalled).to.be.true; + done(); + }); }); - it('should call the handler for ALL the methods if it exists and there is no handler for the request method.', (done) => { - let previouslyCalled: boolean = false - route.all((req, res, next) => { - previouslyCalled = true - next() - }) + it("should call the handler for ALL the methods if it exists and there is no handler for the request method.", (done) => { + let previouslyCalled: boolean = false; + route.all((request, response, next) => { + previouslyCalled = true; + next(); + }); route.dispatch(req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) + Chai.expect(previouslyCalled).to.be.true; + done(); + }); }); - it('should call next if there is no handler for the request method neither for ALL.', (done) => { - let previouslyCalled: boolean = false - route.post((req, res, next) => { - previouslyCalled = true - next() - }) + it("should call next if there is no handler for the request method neither for ALL.", (done) => { + let previouslyCalled: boolean = false; + route.post((request, response, next) => { + previouslyCalled = true; + next(); + }); route.dispatch(req, res, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }) + Chai.expect(previouslyCalled).to.be.false; + done(); + }); }); }); describe("#get", () => { it("should set a handler for the method GET.", (done) => { - route.get((req, res, next) => { + route.get((request, response, next) => { done(); }); event.httpMethod = "GET"; @@ -104,7 +106,7 @@ describe('HttpRoute', () => { describe("#post", () => { it("should set a handler for the method POST.", (done) => { - route.post((req, res, next) => { + route.post((request, response, next) => { done(); }); event.httpMethod = "POST"; @@ -114,7 +116,7 @@ describe('HttpRoute', () => { describe("#put", () => { it("should set a handler for the method PUT.", (done) => { - route.put((req, res, next) => { + route.put((request, response, next) => { done(); }); event.httpMethod = "PUT"; @@ -124,7 +126,7 @@ describe('HttpRoute', () => { describe("#delete", () => { it("should set a handler for the method DELETE.", (done) => { - route.delete((req, res, next) => { + route.delete((request, response, next) => { done(); }); event.httpMethod = "DELETE"; diff --git a/test/http/HttpRouterExecutor.spec.ts b/test/http/HttpRouterExecutor.spec.ts index 6a5fd46..6b122e8 100644 --- a/test/http/HttpRouterExecutor.spec.ts +++ b/test/http/HttpRouterExecutor.spec.ts @@ -1,182 +1,185 @@ -import * as Chai from 'chai' -import App from './../../src/lib/App' -import IApp from './../../src/lib/types/IApp' -import HttpRouterExecutor from './../../src/lib/http/HttpRouterExecutor' -import IHttpRouterExecutor from './../../src/lib/types/http/IHttpRouterExecutor' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import IHttpResponse from './../../src/lib/types/http/IHttpResponse' -import Router from './../../src/lib/Router' -import IRouter from './../../src/lib/types/IRouter' +/* tslint:disable:no-unused-expression */ +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 HttpRouterExecutor from "./../../src/lib/http/HttpRouterExecutor"; +import Router from "./../../src/lib/Router"; +import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; +import IHttpRouterExecutor from "./../../src/lib/types/http/IHttpRouterExecutor"; +import IApp from "./../../src/lib/types/IApp"; +import IRouter from "./../../src/lib/types/IRouter"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRouterExecutor. */ -describe('HttpRouterExecutor', () => { - const app: IApp = new App - let req: IHttpRequest, res: IHttpResponse, router: IRouter; +describe("HttpRouterExecutor", () => { + const app: IApp = new App(); + let req: IHttpRequest; + let res: IHttpResponse; + let router: IRouter; let callback: DefaultCallback; beforeEach(() => { callback = new DefaultCallback(); req = new HttpRequest(Object.assign({}, httpEvent)); res = new HttpResponse(app, req, callback); - router = new Router - }) + router = new Router(); + }); - describe('#next', () => { - it('should call #handle on the first layer which match with the request path (if it exists).', (done) => { - let previouslyCalled: boolean = false + describe("#next", () => { + it("should call #handle on the first layer which match with the request path (if it exists).", (done) => { + let previouslyCalled: boolean = false; - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled = true - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #handle on the next layer (after a previous next call) which match with the request path (if it exists).', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should call #handle on the next layer (after a previous next call) which match with the request path (if it exists).", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.use((req, res, next) => { - previouslyCalled1 = true - next() - }) + router.use((request, response, next) => { + previouslyCalled1 = true; + next(); + }); - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #next if there is no layer matching with the request path.', (done) => { - let previouslyCalled: boolean = false + it("should call #next if there is no layer matching with the request path.", (done) => { + let previouslyCalled: boolean = false; - router.route('/blog').get((req, res, next) => { - previouslyCalled = true - next() - }) + router.route("/blog").get((request, response, next) => { + previouslyCalled = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.false; + done(); + }); + routerExecutor.next(); }); - it('should call #next if the found layer hasn\'t an error handler and the given #error is not undefined.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should call #next if the found layer hasn\'t an error handler and the given #error is not undefined.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.use((req, res, next) => { - previouslyCalled1 = true - next() - }) + router.use((request, response, next) => { + previouslyCalled1 = true; + next(); + }); - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.false - Chai.expect(previouslyCalled2).to.be.false - done() - }) - routerExecutor.next(new Error) + Chai.expect(previouslyCalled1).to.be.false; + Chai.expect(previouslyCalled2).to.be.false; + done(); + }); + routerExecutor.next(new Error()); }); - it('should use the layer if the found layer has an error handler and the given #error is not undefined.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should use the layer if the found layer has an error handler and the given #error is not undefined.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.use((req, res, next, error) => { - previouslyCalled1 = true - next(error) - }) + router.use((request, response, next, error) => { + previouslyCalled1 = true; + next(error); + }); - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.false - done() - }) - routerExecutor.next(new Error) + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.false; + done(); + }); + routerExecutor.next(new Error()); }); - it('should set the request route to the route of the layer before call the layer handler.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should set the request route to the route of the layer before call the layer handler.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled1 = true - Chai.expect(req.route).to.be.not.undefined - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled1 = true; + Chai.expect(req.route).to.be.not.undefined; + next(); + }); - router.use((req, res, next) => { - previouslyCalled2 = true - Chai.expect(req.route).to.be.undefined - next() - }) + router.use((request, response, next) => { + previouslyCalled2 = true; + Chai.expect(req.route).to.be.undefined; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should set the request params to the params of the layer merged with the initial request params before call the layer handler.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should set the request params to the params of the layer merged with the initial request params before call the layer handler.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled1 = true - Chai.expect(req.params).to.deep.include({id: '1', query1: 'Query 1'}) - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled1 = true; + Chai.expect(req.params).to.deep.include({id: "1", query1: "Query 1"}); + next(); + }); - router.use((req, res, next) => { - previouslyCalled2 = true - Chai.expect(req.params).to.deep.include({query1: 'Query 1'}) - Chai.expect(req.params).to.not.deep.include({id: '1'}) - next() - }) + router.use((request, response, next) => { + previouslyCalled2 = true; + Chai.expect(req.params).to.deep.include({query1: "Query 1"}); + Chai.expect(req.params).to.not.deep.include({id: "1"}); + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should set the request params to the params of the layer only if the initial request params is null before call the layer handler.', (done) => { + it("should set the request params to the params of the layer only if the initial request params is null before call the layer handler.", (done) => { let previouslyCalled: boolean = false; - router.route("/blog/:id").get((req, res, next) => { + router.route("/blog/:id").get((request, response, next) => { previouslyCalled = true; Chai.expect(req.params).to.deep.include({id: "1"}); next(); @@ -190,177 +193,183 @@ describe('HttpRouterExecutor', () => { routerExecutor.next(); }); - it('should "process the layer params" with the router before call the layer handler.', (done) => { - let previouslyCalled: boolean = false + it("should 'process the layer params' with the router before call the layer handler.", (done) => { + let previouslyCalled: boolean = false; - router.param('id', (req, res, next, value) => { - req.context.idValue = value - next() - }) + router.param("id", (request, response, next, value) => { + req.context.idValue = value; + next(); + }); - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled = true - Chai.expect(req.context.idValue).to.be.equal('1') - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled = true; + Chai.expect(req.context.idValue).to.be.equal("1"); + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #next with error if there was an error processing the params before call the layer handler.', (done) => { - let previouslyCalled: boolean = false + it("should call #next with error if there was an error processing the params before call the layer handler.", (done) => { + let previouslyCalled: boolean = false; - router.param('id', (req, res, next, value) => { - next(new Error) - }) + router.param("id", (request, response, next, value) => { + next(new Error()); + }); - router.route('/blog/:id').get((req, res, next) => { - previouslyCalled = true - next() - }) + router.route("/blog/:id").get((request, response, next) => { + previouslyCalled = true; + next(); + }); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, (error) => { - Chai.expect(previouslyCalled).to.be.false - Chai.expect(error).to.be.not.undefined - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.false; + Chai.expect(error).to.be.not.undefined; + done(); + }); + routerExecutor.next(); }); - it('should call #httpHandle on the first subrouter which match with the request path (if it exists) and when there is no more layer in the stack.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should call #httpHandle on the first subrouter which match with the request path (if it exists) and when there is no more layer in the stack.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - router.use((req, res, next) => { - previouslyCalled1 = true - next() - }) + router.use((request, response, next) => { + previouslyCalled1 = true; + next(); + }); - const subrouter = new Router - subrouter.route('/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) - router.mount(subrouter, '/blog') + const subrouter = new Router(); + subrouter.route("/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); + router.mount(subrouter, "/blog"); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #httpHandle on the first subrouter which match with the request path (if it exists) and when the layer stack is empty.', (done) => { - let previouslyCalled: boolean = false + it("should call #httpHandle on the first subrouter which match with the request path (if it exists) and when the layer stack is empty.", (done) => { + let previouslyCalled: boolean = false; - const subrouter = new Router - subrouter.route('/blog/:id').get((req, res, next) => { - previouslyCalled = true - next() - }) - router.mount(subrouter) + const subrouter = new Router(); + subrouter.route("/blog/:id").get((request, response, next) => { + previouslyCalled = true; + next(); + }); + router.mount(subrouter); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #httpHandle on the next subrouter (after a previous next call) which match with the request path (if it exists).', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false + it("should call #httpHandle on the next subrouter (after a previous next call) which match with the request path (if it exists).", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; - const subrouter1 = new Router - subrouter1.use((req, res, next) => { - previouslyCalled1 = true - next() - }) + const subrouter1 = new Router(); + subrouter1.use((request, response, next) => { + previouslyCalled1 = true; + next(); + }); - const subrouter2 = new Router - subrouter2.route('/blog/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) - router.mount(subrouter1) - router.mount(subrouter2) + const subrouter2 = new Router(); + subrouter2.route("/blog/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); + router.mount(subrouter1); + router.mount(subrouter2); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should call #next if there is no subrouter matching with the request path.', (done) => { - let previouslyCalled: boolean = false - const subrouter = new Router - subrouter.route('/:id').get((req, res, next) => { - previouslyCalled = true - next() - }) - router.mount(subrouter, '/contact') + it("should call #next if there is no subrouter matching with the request path.", (done) => { + let previouslyCalled: boolean = false; + const subrouter = new Router(); + subrouter.route("/:id").get((request, response, next) => { + previouslyCalled = true; + next(); + }); + router.mount(subrouter, "/contact"); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.false - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.false; + done(); + }); + routerExecutor.next(); }); - it('should call #done if the subrouters and the layers stacks are empty.', (done) => { + it("should call #done if the subrouters and the layers stacks are empty.", (done) => { const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - done() - }) - routerExecutor.next() + done(); + }); + routerExecutor.next(); }); - it('should call #done in the following call to next when the layers and the subrouters stacks have been processed.', (done) => { - let previouslyCalled1: boolean = false - let previouslyCalled2: boolean = false - - router.use((req, res, next) => { - previouslyCalled1 = true - next() - }, '/blog/:id') - - const subrouter = new Router - subrouter.route('/:id').get((req, res, next) => { - previouslyCalled2 = true - next() - }) - router.mount(subrouter, '/blog') + it("should call #done in the following call to next when the layers and the subrouters stacks have been processed.", (done) => { + let previouslyCalled1: boolean = false; + let previouslyCalled2: boolean = false; + + router.use( + (request, response, next) => { + previouslyCalled1 = true; + next(); + }, + "/blog/:id" + ); + + const subrouter = new Router(); + subrouter.route("/:id").get((request, response, next) => { + previouslyCalled2 = true; + next(); + }); + router.mount(subrouter, "/blog"); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + done(); + }); + routerExecutor.next(); }); - it('should reset the request params as the initial ones when #done is called.', (done) => { - const initialParams = req.params - let previouslyCalled: boolean = false + it("should reset the request params as the initial ones when #done is called.", (done) => { + const initialParams = req.params; + let previouslyCalled: boolean = false; - router.use((req, res, next) => { - previouslyCalled = true - Chai.expect(req.params).to.be.not.equal(initialParams) - next() - }, '/blog/:id') + router.use( + (request, response, next) => { + previouslyCalled = true; + Chai.expect(req.params).to.be.not.equal(initialParams); + next(); + }, + "/blog/:id" + ); const routerExecutor: IHttpRouterExecutor = new HttpRouterExecutor(router, req, res, () => { - Chai.expect(previouslyCalled).to.be.true - Chai.expect(req.params).to.be.equal(initialParams) - done() - }) - routerExecutor.next() + Chai.expect(previouslyCalled).to.be.true; + Chai.expect(req.params).to.be.equal(initialParams); + done(); + }); + routerExecutor.next(); }); }); diff --git a/test/http/HttpUploadedFile.spec.ts b/test/http/HttpUploadedFile.spec.ts index 8e3eb77..02dbbb3 100644 --- a/test/http/HttpUploadedFile.spec.ts +++ b/test/http/HttpUploadedFile.spec.ts @@ -8,7 +8,6 @@ const FILE_NAME: string = "fileName.txt"; const CONTENT: string = "Amazin content."; const HEADERS: {[name: string]: string} = {header1: "value 1"}; - /** * Test for HttpUploadedFile. */ diff --git a/test/http/bodyParsers/JsonParser.spec.ts b/test/http/bodyParsers/JsonParser.spec.ts index b2568ac..8cd3c2a 100644 --- a/test/http/bodyParsers/JsonParser.spec.ts +++ b/test/http/bodyParsers/JsonParser.spec.ts @@ -1,17 +1,18 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; -import { spy, SinonSpy } from "sinon"; -import httpEvent from "./../../utils/httpEvent"; +import { SinonSpy, spy } from "sinon"; 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 httpEvent from "./../../utils/httpEvent"; /** * Test for JsonParser. */ describe("JsonParser", () => { - const res: IHttpResponse = {}; + const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; const handler: IHttpHandler = (new JsonParser()).create(); diff --git a/test/http/bodyParsers/MultipartParser.spec.ts b/test/http/bodyParsers/MultipartParser.spec.ts index eae2e43..0b3f637 100644 --- a/test/http/bodyParsers/MultipartParser.spec.ts +++ b/test/http/bodyParsers/MultipartParser.spec.ts @@ -1,8 +1,9 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; -import { spy, SinonSpy } from "sinon"; +import { SinonSpy, spy } from "sinon"; import MultipartParser from "./../../../src/lib/http/bodyParsers/MultipartParser"; -import HttpUploadedFile from "./../../../src/lib/http/HttpUploadedFile"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; +import HttpUploadedFile from "./../../../src/lib/http/HttpUploadedFile"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; @@ -38,7 +39,7 @@ const mainEvent: any = { * Test for MultipartParser. */ describe("MultipartParser", () => { - const res: IHttpResponse = {}; + const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; const handler: IHttpHandler = (new MultipartParser()).create(); diff --git a/test/http/bodyParsers/UrlEncodedParser.spec.ts b/test/http/bodyParsers/UrlEncodedParser.spec.ts index 8c28bc0..216543b 100644 --- a/test/http/bodyParsers/UrlEncodedParser.spec.ts +++ b/test/http/bodyParsers/UrlEncodedParser.spec.ts @@ -1,7 +1,8 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; -import { spy, SinonSpy, stub, SinonStub } from "sinon"; import * as qs from "qs"; import * as querystring from "querystring"; +import { SinonSpy, SinonStub, spy, stub } from "sinon"; import UrlEncodedParser from "./../../../src/lib/http/bodyParsers/UrlEncodedParser"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; @@ -23,7 +24,7 @@ const mainEvent: any = { * Test for UrlEncodedParser. */ describe("UrlEncodedParser", () => { - const res: IHttpResponse = {}; + const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; const handler: IHttpHandler = (new UrlEncodedParser()).create({parameterLimit: 2}); @@ -102,11 +103,11 @@ describe("UrlEncodedParser", () => { }); it("should use `querystring` library if it is NOT extended.", () => { - const handler: IHttpHandler = (new UrlEncodedParser()).create({extended: false}); + const newHandler: IHttpHandler = (new UrlEncodedParser()).create({extended: false}); const stubQS = stub(querystring, "parse"); const req: IHttpRequest = new HttpRequest(event); - handler(req, res, next); + 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 e0b8b42..34555d9 100644 --- a/test/http/bodyParsers/parserHelper.spec.ts +++ b/test/http/bodyParsers/parserHelper.spec.ts @@ -1,5 +1,6 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; -import { spy, SinonSpy } from "sinon"; +import { SinonSpy, spy } from "sinon"; import parserHelper from "./../../../src/lib/http/bodyParsers/parserHelper"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; @@ -22,9 +23,9 @@ const mainEvent: any = { */ describe("parserHelper", () => { const body: { [name: string]: any } = { - "param1": "value1" + param1: "value1" }; - const res: IHttpResponse = {}; + const res: IHttpResponse = {} as IHttpResponse; let next: SinonSpy; let event: any; @@ -69,7 +70,7 @@ describe("parserHelper", () => { const req: IHttpRequest = new HttpRequest(event); const handler: IHttpHandler = parserHelper(() => { - throw new Error; + throw new Error(); }); handler(req, res, next); @@ -79,11 +80,11 @@ 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; + event.headers["Content-Type"] = undefined; const req: IHttpRequest = new HttpRequest(event); const handler: IHttpHandler = parserHelper(() => { - throw new Error; + throw new Error(); }); handler(req, res, next); @@ -114,7 +115,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; + event.headers["Content-Type"] = undefined; const req: IHttpRequest = new HttpRequest(event); const parser: SinonSpy = spy(); diff --git a/test/http/httpFinalHandler.spec.ts b/test/http/httpFinalHandler.spec.ts index ad688a6..e2b6cf5 100644 --- a/test/http/httpFinalHandler.spec.ts +++ b/test/http/httpFinalHandler.spec.ts @@ -1,128 +1,129 @@ -import * as Chai from 'chai' -import App from './../../src/lib/App' -import IApp from './../../src/lib/types/IApp' -import HttpRequest from './../../src/lib/http/HttpRequest' -import IHttpRequest from './../../src/lib/types/http/IHttpRequest' -import HttpResponse from './../../src/lib/http/HttpResponse' -import IHttpResponse from './../../src/lib/types/http/IHttpResponse' -import httpFinalHandler from './../../src/lib/http/httpFinalHandler' -import HttpError from './../../src/lib/exceptions/HttpError' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import App from "./../../src/lib/App"; +import HttpError from "./../../src/lib/exceptions/HttpError"; +import httpFinalHandler from "./../../src/lib/http/httpFinalHandler"; +import HttpRequest from "./../../src/lib/http/HttpRequest"; +import HttpResponse from "./../../src/lib/http/HttpResponse"; +import IHttpRequest from "./../../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../../src/lib/types/http/IHttpResponse"; +import IApp from "./../../src/lib/types/IApp"; +import IRawEvent from "./../../src/lib/types/IRawEvent"; import DefaultCallback from "./../utils/DefaultCallback"; import httpEvent from "./../utils/httpEvent"; -import IRawEvent from "./../../src/lib/types/IRawEvent"; /** * Test for httpFinalHandler. */ -describe('httpFinalHandler', () => { - const app: IApp = new App - let req: IHttpRequest - let res: IHttpResponse +describe("httpFinalHandler", () => { + const app: IApp = new App(); + let req: IHttpRequest; + let res: IHttpResponse; let callback: DefaultCallback; let event: IRawEvent; beforeEach(() => { callback = new DefaultCallback(); event = Object.assign({}, httpEvent); - event.headers['Accept'] ='application/json'; + event.headers.Accept = "application/json"; req = new HttpRequest(Object.assign({}, event)); res = new HttpResponse(app, req, callback); }); - it('should send a response with the headers: Content-Security-Policy, X-Content-Type-Options, Content-Type and Content-Length.', () => { - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(callback.successResult.headers['Content-Security-Policy']).to.be.not.empty - Chai.expect(callback.successResult.headers['X-Content-Type-Options']).to.be.not.empty - Chai.expect(callback.successResult.headers['Content-Type']).to.be.not.empty - Chai.expect(callback.successResult.headers['Content-Length']).to.be.not.empty + it("should send a response with the headers: Content-Security-Policy, X-Content-Type-Options, Content-Type and Content-Length.", () => { + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(callback.successResult.headers["Content-Security-Policy"]).to.be.not.empty; + Chai.expect(callback.successResult.headers["X-Content-Type-Options"]).to.be.not.empty; + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.not.empty; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.not.empty; }); - it('should not send a response if a response is prevously sent.', () => { - res.send('') - Chai.expect(callback.successResult).to.be.not.undefined - callback.successResult.body = null + it("should not send a response if a response is prevously sent.", () => { + res.send(""); + Chai.expect(callback.successResult).to.be.not.undefined; + callback.successResult.body = null; - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(callback.successResult.body).to.be.null + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(callback.successResult.body).to.be.null; }); - it('should call #onerror handler if it is set in the #options.', (done) => { + it("should call #onerror handler if it is set in the #options.", (done) => { const handler = httpFinalHandler(req, res, { onerror: () => { - done() + done(); } - }) - handler() + }); + handler(); }); - it('should set the response status code as 404 and acording message if #err is undefined.', () => { - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(callback.successResult.statusCode).to.be.equals(404) - console.log(callback.successResult.body) - Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals('Cannot GET /blog/1') - Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(404) + it("should set the response status code as 404 and acording message if #err is undefined.", () => { + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(callback.successResult.statusCode).to.be.equals(404); + console.log(callback.successResult.body); + Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals("Cannot GET /blog/1"); + Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(404); }); - it('should set the response status code, headers and body from #err if it is not undefined.', () => { - const handler = httpFinalHandler(req, res, {}) - const error = new HttpError('Test msg', 403) - error.headers = {errorHeader: 'test'} - handler(error) - Chai.expect(callback.successResult.statusCode).to.be.equals(403) - Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals('Test msg') - Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(403) - Chai.expect(callback.successResult.headers.errorHeader).to.be.equals('test') + it("should set the response status code, headers and body from #err if it is not undefined.", () => { + const handler = httpFinalHandler(req, res, {}); + const error = new HttpError("Test msg", 403); + error.headers = {errorHeader: "test"}; + handler(error); + Chai.expect(callback.successResult.statusCode).to.be.equals(403); + Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals("Test msg"); + Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(403); + Chai.expect(callback.successResult.headers.errorHeader).to.be.equals("test"); }); - 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' - const req = new HttpRequest(event) + 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); - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(callback.successResult.body).to.contain('') + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(callback.successResult.body).to.contain(""); }); - it('should send a JSON response and JSON as content type if the request accepts JSON and it does not accept HTML.', () => { - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(JSON.parse(callback.successResult.body)).to.be.a('object') + it("should send a JSON response and JSON as content type if the request accepts JSON and it does not accept HTML.", () => { + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(JSON.parse(callback.successResult.body)).to.be.a("object"); }); - 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' - const req = new HttpRequest(event) + 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); - const handler = httpFinalHandler(req, res, {}) - handler() - Chai.expect(callback.successResult.body).to.be.equals('Cannot GET /blog/1') + const handler = httpFinalHandler(req, res, {}); + handler(); + Chai.expect(callback.successResult.body).to.be.equals("Cannot GET /blog/1"); }); it("should set status code from res if it is higher than 400, lower than 600 and the error is not of type HttpError.", () => { - const handler = httpFinalHandler(req, res, {}) + const handler = httpFinalHandler(req, res, {}); res.status(404); const error = new Error("No HTTP error."); - handler(error) + handler(error); Chai.expect(callback.successResult.statusCode).to.be.equals(404); }); it("should set status code 500 if the res status code is lower than 400 or higher than 600 and the error is not of type HttpError.", () => { - const handler = httpFinalHandler(req, res, {}) + const handler = httpFinalHandler(req, res, {}); res.status(300); const error = new Error("No HTTP error."); - handler(error) + handler(error); Chai.expect(callback.successResult.statusCode).to.be.equals(500); }); it("should set status code 500 if the status code of HttpError is not set.", () => { - const handler = httpFinalHandler(req, res, {}) + const handler = httpFinalHandler(req, res, {}); const error = new HttpError("HTTP error.", null); - handler(error) + handler(error); Chai.expect(callback.successResult.statusCode).to.be.equals(500); }); diff --git a/test/http/renderEngine/DevTemplateLoader.spec.ts b/test/http/renderEngine/DevTemplateLoader.spec.ts index 178b825..24860bd 100644 --- a/test/http/renderEngine/DevTemplateLoader.spec.ts +++ b/test/http/renderEngine/DevTemplateLoader.spec.ts @@ -1,3 +1,4 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import * as mock from "mock-fs"; import DevTemplateLoader from "./../../../src/lib/http/renderEngine/DevTemplateLoader"; @@ -14,7 +15,7 @@ describe("DevTemplateLoader", () => { mock({ "/base/path": { "prueba.pug": new Buffer("Test content.", "utf8") - }, + } }); }); diff --git a/test/http/renderEngine/Template.spec.ts b/test/http/renderEngine/Template.spec.ts index 5955bb1..6d84e7e 100644 --- a/test/http/renderEngine/Template.spec.ts +++ b/test/http/renderEngine/Template.spec.ts @@ -1,3 +1,4 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import Template from "./../../../src/lib/http/renderEngine/Template"; import ITemplate from "./../../../src/lib/types/http/renderEngine/ITemplate"; diff --git a/test/http/renderEngine/TemplateEngine.spec.ts b/test/http/renderEngine/TemplateEngine.spec.ts index 8fdabcc..9e9d147 100644 --- a/test/http/renderEngine/TemplateEngine.spec.ts +++ b/test/http/renderEngine/TemplateEngine.spec.ts @@ -1,3 +1,4 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import { SinonStub, stub } from "sinon"; import Template from "./../../../src/lib/http/renderEngine/Template"; @@ -10,7 +11,7 @@ import ITemplateRenderer from "./../../../src/lib/types/http/renderEngine/ITempl * Test for TemplateEngine. */ describe("TemplateEngine", () => { - const templateRenderer: ITemplateRenderer = stub(); + const templateRenderer: ITemplateRenderer = stub() as any as ITemplateRenderer; const templateRendererFunc = templateRenderer.render = stub(); const expectedEngineConfig: {[name: string]: any} = {conf1: "value 1"}; const templateEngine: ITemplateEngine = new TemplateEngine(templateRenderer, expectedEngineConfig); @@ -35,7 +36,6 @@ describe("TemplateEngine", () => { }); it("should call the `templateRenderer` function with the `fileName`, the `params`, the `engineConfig`, and the `callback` if the template has been successfully loaded.", (done) => { - const expectedContent = "PRUEBA"; const expectedParams = {param1: "value1"}; templateRendererFunc.callsFake((fileName: string, params: {[name: string]: any}, engineConfig: {[name: string]: any}, callback: (err: Error, template: ITemplate) => void) => { diff --git a/test/router.spec.ts b/test/router.spec.ts index 934c519..f7670e2 100644 --- a/test/router.spec.ts +++ b/test/router.spec.ts @@ -1,227 +1,230 @@ -import * as Chai from 'chai' -import Router from './../src/lib/Router' -import IRouter from './../src/lib/types/IRouter' -import HttpRequest from './../src/lib/http/HttpRequest' -import IHttpRequest from './../src/lib/types/http/IHttpRequest' -import EventRequest from './../src/lib/event/EventRequest' -import IEventRequest from './../src/lib/types/event/IEventRequest' -import HttpResponse from './../src/lib/http/HttpResponse' -import IHttpResponse from './../src/lib/types/http/IHttpResponse' -import App from './../src/lib/App' -import IApp from './../src/lib/types/IApp' +/* tslint:disable:no-unused-expression */ +import * as Chai from "chai"; +import App from "./../src/lib/App"; +import EventRequest from "./../src/lib/event/EventRequest"; +import HttpRequest from "./../src/lib/http/HttpRequest"; +import HttpResponse from "./../src/lib/http/HttpResponse"; +import Router from "./../src/lib/Router"; +import IEventRequest from "./../src/lib/types/event/IEventRequest"; +import IHttpRequest from "./../src/lib/types/http/IHttpRequest"; +import IHttpResponse from "./../src/lib/types/http/IHttpResponse"; +import IApp from "./../src/lib/types/IApp"; +import IRouter from "./../src/lib/types/IRouter"; +import DefaultCallback from "./utils/DefaultCallback"; import httpEvent from "./utils/httpEvent"; import otherEvent from "./utils/otherEvent"; -import DefaultCallback from "./utils/DefaultCallback"; /** * Test for Router. */ -describe('Router', () => { - const app: IApp = new App - let router: IRouter, eventReq: IEventRequest - let httpReq: IHttpRequest, res: IHttpResponse +describe("Router", () => { + const app: IApp = new App(); + let router: IRouter; + let eventReq: IEventRequest; + let httpReq: IHttpRequest; + let res: IHttpResponse; let callback: DefaultCallback; beforeEach(() => { callback = new DefaultCallback(); - router = new Router - eventReq = new EventRequest(otherEvent) - httpReq = new HttpRequest(httpEvent) - res = new HttpResponse(app, httpReq, callback) - }) + router = new Router(); + eventReq = new EventRequest(otherEvent); + httpReq = new HttpRequest(httpEvent); + res = new HttpResponse(app, httpReq, callback); + }); - describe('#fullSubpath', () => { - it('should return each parent subpath concadenated with the current subrouter subpath.', () => { - const subrouter = new Router - router.mount(subrouter, '/path1') + describe("#fullSubpath", () => { + it("should return each parent subpath concadenated with the current subrouter subpath.", () => { + const subrouter = new Router(); + router.mount(subrouter, "/path1"); - const subsubrouter = new Router - subrouter.mount(subsubrouter, '/path2') + const subsubrouter = new Router(); + subrouter.mount(subsubrouter, "/path2"); - Chai.expect(subsubrouter.fullSubpath).to.be.equal('/path1/path2') + Chai.expect(subsubrouter.fullSubpath).to.be.equal("/path1/path2"); }); - it('should return the current subpath if the router hasn\'t a parent.', () => { - Chai.expect(router.fullSubpath).to.be.undefined + it("should return the current subpath if the router hasn't a parent.", () => { + Chai.expect(router.fullSubpath).to.be.undefined; }); - it('should return undefined if the subpath is undefined.', () => { - const subrouter = new Router - router.mount(subrouter) + it("should return undefined if the subpath is undefined.", () => { + const subrouter = new Router(); + router.mount(subrouter); - Chai.expect(subrouter.fullSubpath).to.be.undefined + Chai.expect(subrouter.fullSubpath).to.be.undefined; }); }); - describe('#httpHandle', () => { - it('should create and start a #HttpRouterExecutor if the request method is NOT OPTIONS', (done) => { - router.use((req, res, next) => { - done() - }) + describe("#httpHandle", () => { + it("should create and start a #HttpRouterExecutor if the request method is NOT OPTIONS", (done) => { + router.use((request, response, next) => { + done(); + }); - router.httpHandle(httpReq, res, () => {}) + router.httpHandle(httpReq, res, () => console.log("OK")); }); - 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) + 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); - router.route('/blog/:id').get((req, res) => {}) - router.route('/blog/:id').post((req, res) => {}) + router.route("/blog/:id").get((request, response) => console.log("OK")); + router.route("/blog/:id").post((request, response) => console.log("OK")); callback.setCallback(() => { - Chai.expect(callback.successResult.headers['Allow']).to.be.equals('GET,POST') - done() + Chai.expect(callback.successResult.headers.Allow).to.be.equals("GET,POST"); + done(); }); - router.httpHandle(req, res, () => {}) + router.httpHandle(req, res, () => console.log("OK")); }); - 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) + 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); router.httpHandle(req, res, () => { - done() - }) + done(); + }); }); }); - describe('#httpProcessParams', () => { - const newEvent = Object.assign({}, httpEvent) - newEvent.path = '/blog/:id1/:id2' - const req = new HttpRequest(newEvent) + describe("#httpProcessParams", () => { + const newEvent = Object.assign({}, httpEvent); + newEvent.path = "/blog/:id1/:id2"; + const req = new HttpRequest(newEvent); - let previouslyCalled1: boolean - let previouslyCalled2: boolean - let previouslyCalled3: boolean + let previouslyCalled1: boolean; + let previouslyCalled2: boolean; + let previouslyCalled3: boolean; beforeEach(() => { - previouslyCalled1 = false - previouslyCalled2 = false - previouslyCalled3 = false - - router.param('id1', (req, res, next, value) => { - Chai.expect(value).to.be.equal('1') - previouslyCalled1 = true - next() - }) - - router.param('id1', (req, res, next, value) => { - Chai.expect(value).to.be.equal('1') - previouslyCalled2 = true - next() - }) - - router.param('id2', (req, res, next, value) => { - Chai.expect(value).to.be.equal('2') - previouslyCalled3 = true - next() - }) - }) - - it('should call each handlers for each param in #layerParams.', (done) => { - router.httpProcessParams({id1: '1', id2: '2'}, [], req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - Chai.expect(previouslyCalled3).to.be.true - done() - }) + previouslyCalled1 = false; + previouslyCalled2 = false; + previouslyCalled3 = false; + + router.param("id1", (request, response, next, value) => { + Chai.expect(value).to.be.equal("1"); + previouslyCalled1 = true; + next(); + }); + + router.param("id1", (request, response, next, value) => { + Chai.expect(value).to.be.equal("1"); + previouslyCalled2 = true; + next(); + }); + + router.param("id2", (request, response, next, value) => { + Chai.expect(value).to.be.equal("2"); + previouslyCalled3 = true; + next(); + }); }); - it('should NOT call the handlers for the params in #executedParams.', (done) => { - router.httpProcessParams({id1: '1', id2: '2'}, ['id2'], req, res, () => { - Chai.expect(previouslyCalled1).to.be.true - Chai.expect(previouslyCalled2).to.be.true - Chai.expect(previouslyCalled3).to.be.false - done() - }) + it("should call each handlers for each param in #layerParams.", (done) => { + router.httpProcessParams({id1: "1", id2: "2"}, [], req, res, () => { + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + Chai.expect(previouslyCalled3).to.be.true; + done(); + }); + }); + + it("should NOT call the handlers for the params in #executedParams.", (done) => { + router.httpProcessParams({id1: "1", id2: "2"}, ["id2"], req, res, () => { + Chai.expect(previouslyCalled1).to.be.true; + Chai.expect(previouslyCalled2).to.be.true; + Chai.expect(previouslyCalled3).to.be.false; + done(); + }); }); - it('should add the processed params into #executedParams.', (done) => { - const executed: Array = [] - router.httpProcessParams({id1: '1', id2: '2'}, executed, req, res, () => { - Chai.expect(executed).to.contain('id1') - Chai.expect(executed).to.contain('id2') - done() - }) + it("should add the processed params into #executedParams.", (done) => { + const executed: string[] = []; + router.httpProcessParams({id1: "1", id2: "2"}, executed, req, res, () => { + Chai.expect(executed).to.contain("id1"); + Chai.expect(executed).to.contain("id2"); + done(); + }); }); - it('should execute #done if there is no params in #layerParams.', (done) => { + it("should execute #done if there is no params in #layerParams.", (done) => { router.httpProcessParams({}, [], req, res, () => { - done() - }) + done(); + }); }); - it('should finalize calling #done when there is params without related handlers.', (done) => { - const router = new Router // Clean router without params handlers - router.httpProcessParams({id1: '1', id2: '2'}, [], req, res, () => { - done() - }) + it("should finalize calling #done when there is params without related handlers.", (done) => { + const newRouter = new Router(); // Clean router without params handlers + newRouter.httpProcessParams({id1: "1", id2: "2"}, [], req, res, () => { + done(); + }); }); - it('should finalize calling #done when there is params with related handlers.', (done) => { - router.httpProcessParams({id1: '1', id2: '2'}, [], req, res, () => { - done() - }) + it("should finalize calling #done when there is params with related handlers.", (done) => { + router.httpProcessParams({id1: "1", id2: "2"}, [], req, res, () => { + done(); + }); }); }); - describe('#getAvailableMethodsForPath', () => { - it('should return each HTTP method of each route that match with the request path', () => { - router.route('/blog/:id').get((req, res) => {}) - router.route('/blog/:id').post((req, res) => {}) + describe("#getAvailableMethodsForPath", () => { + it("should return each HTTP method of each route that match with the request path", () => { + router.route("/blog/:id").get((request, response) => console.log("OK")); + router.route("/blog/:id").post((request, response) => console.log("OK")); - const methods = router.getAvailableMethodsForPath('/blog/1') + const methods = router.getAvailableMethodsForPath("/blog/1"); - Chai.expect(methods).to.contain('GET') - Chai.expect(methods).to.contain('POST') + Chai.expect(methods).to.contain("GET"); + Chai.expect(methods).to.contain("POST"); }); - it('should NOT return HTTP method of the routes that doesn\'t match with the request path', () => { - router.route('/blog/:id').get((req, res) => {}) - router.route('/blog/a/:id').post((req, res) => {}) + it("should NOT return HTTP method of the routes that doesn't match with the request path", () => { + router.route("/blog/:id").get((request, response) => console.log("OK")); + router.route("/blog/a/:id").post((request, response) => console.log("OK")); - const methods = router.getAvailableMethodsForPath('/blog/1') + const methods = router.getAvailableMethodsForPath("/blog/1"); - Chai.expect(methods).to.contain('GET') - Chai.expect(methods).to.not.contain('POST') + Chai.expect(methods).to.contain("GET"); + Chai.expect(methods).to.not.contain("POST"); }); - it('should return each HTTP method of each route that match with the request path which are in a subrouter that match with request path.', () => { - const subrouter = new Router - subrouter.route('/:id').get((req, res) => {}) - subrouter.route('/:id').post((req, res) => {}) - router.mount(subrouter, '/blog') + it("should return each HTTP method of each route that match with the request path which are in a subrouter that match with request path.", () => { + const subrouter = new Router(); + subrouter.route("/:id").get((request, response) => console.log("OK")); + subrouter.route("/:id").post((request, response) => console.log("OK")); + router.mount(subrouter, "/blog"); - const methods = router.getAvailableMethodsForPath('/blog/1') + const methods = router.getAvailableMethodsForPath("/blog/1"); - Chai.expect(methods).to.contain('GET') - Chai.expect(methods).to.contain('POST') + Chai.expect(methods).to.contain("GET"); + Chai.expect(methods).to.contain("POST"); }); - it('should NOT return HTTP method of the routes that match with the request path which are in a subrouter that doesn\'t match with request path.', () => { - const subrouter = new Router - subrouter.route('/:id').get((req, res) => {}) - subrouter.route('/a/:id').post((req, res) => {}) - router.mount(subrouter, '/blog') + it("should NOT return HTTP method of the routes that match with the request path which are in a subrouter that doesn't match with request path.", () => { + const subrouter = new Router(); + subrouter.route("/:id").get((request, response) => console.log("OK")); + subrouter.route("/a/:id").post((request, response) => console.log("OK")); + router.mount(subrouter, "/blog"); - const methods = router.getAvailableMethodsForPath('/blog/1') + const methods = router.getAvailableMethodsForPath("/blog/1"); - Chai.expect(methods).to.contain('GET') - Chai.expect(methods).to.not.contain('POST') + Chai.expect(methods).to.contain("GET"); + Chai.expect(methods).to.not.contain("POST"); }); }); - describe('#eventHandle', () => { - it('should create and start a #EventRouterExecutor.', (done) => { - router.event('S3CreateEvent', (req, next) => { - done() - }) + describe("#eventHandle", () => { + it("should create and start a #EventRouterExecutor.", (done) => { + router.event("S3CreateEvent", (req, next) => { + done(); + }); - router.eventHandle(eventReq, () => {}) + router.eventHandle(eventReq, () => console.log("OK")); }); }); diff --git a/test/utils/DefaultCallback.ts b/test/utils/DefaultCallback.ts index 5aa568e..668b3f9 100644 --- a/test/utils/DefaultCallback.ts +++ b/test/utils/DefaultCallback.ts @@ -1,5 +1,8 @@ import IRawCallback from "./../../src/lib/types/IRawCallback"; +/** + * A callback for testing purposes. + */ export default class DefaultCallback implements IRawCallback { private _errorResult: Error; @@ -16,18 +19,18 @@ export default class DefaultCallback implements IRawCallback { return this._successResult; } - sendError(error: Error): void { + public sendError(error: Error): void { this._errorResult = error; } - send(statusCode: number, headers: {[name: string]: string|string[]}, body: object|Buffer): void { + public send(statusCode: number, headers: {[name: string]: string|string[]}, body: object|Buffer): void { this._successResult = {statusCode, headers, body}; - if(this._callback) { - this._callback() + if (this._callback) { + this._callback(); } } - setCallback(callback: () => void) { + public setCallback(callback: () => void): void { this._callback = callback; } diff --git a/test/utils/httpEvent.ts b/test/utils/httpEvent.ts index 1937915..6a8351d 100644 --- a/test/utils/httpEvent.ts +++ b/test/utils/httpEvent.ts @@ -1,13 +1,16 @@ import RawEvent from "./../../src/lib/RawEvent"; import IRawEvent from "./../../src/lib/types/IRawEvent"; +/** + * HTTP event. + */ const httpEvent: IRawEvent = new RawEvent(); httpEvent.type = "APIGatewayEvent"; httpEvent.original = {}; httpEvent.isHttp = true; httpEvent.headers = { - header1: "HEADER VALUE 1", - header2: "HEADER VALU 2", + "header1": "HEADER VALUE 1", + "header2": "HEADER VALU 2", "X-Forwarded-Proto": "https", "Host": "localhost", "Content-Type": "application/json,text/html", diff --git a/test/utils/otherEvent.ts b/test/utils/otherEvent.ts index e7d15b2..8a34a47 100644 --- a/test/utils/otherEvent.ts +++ b/test/utils/otherEvent.ts @@ -1,43 +1,46 @@ import RawEvent from "./../../src/lib/RawEvent"; import IRawEvent from "./../../src/lib/types/IRawEvent"; +/** + * Not HTTP event. + */ const otherEvent: IRawEvent = new RawEvent(); otherEvent.type = "S3CreateEvent"; otherEvent.original = { - "Records": [ + Records: [ { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" + eventVersion: "2.0", + eventTime: "1970-01-01T00:00:00.000Z", + requestParameters: { + sourceIPAddress: "127.0.0.1" }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 + s3: { + configurationId: "testConfigRule", + object: { + eTag: "0123456789abcdef0123456789abcdef", + sequencer: "0A1B2C3D4E5F678901", + key: "test/key", + size: 1024 }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" + bucket: { + arn: "arn:aws:s3:::example-bucket", + name: "example-bucket", + ownerIdentity: { + principalId: "EXAMPLE" } }, - "s3SchemaVersion": "1.0" + s3SchemaVersion: "1.0" }, - "responseElements": { + responseElements: { "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", "x-amz-request-id": "EXAMPLE123456789" }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" + awsRegion: "us-east-1", + eventName: "ObjectCreated:Put", + userIdentity: { + principalId: "EXAMPLE" }, - "eventSource": "aws:s3" + eventSource: "aws:s3" } ] }; diff --git a/test/utils/utils.spec.ts b/test/utils/utils.spec.ts index d8f5dfe..ece37c6 100644 --- a/test/utils/utils.spec.ts +++ b/test/utils/utils.spec.ts @@ -1,3 +1,4 @@ +/* tslint:disable:no-unused-expression */ import * as Chai from "chai"; import { setCharset, stringify } from "../../src/lib/utils/utils"; @@ -38,7 +39,7 @@ describe("utils", () => { const replacer = (key, value) => { if (key && key !== "name") { return undefined; - } else if(key === "name") { + } else if (key === "name") { return "test"; } else { return value; diff --git a/tslint.json b/tslint.json index f6fd344..eb805c1 100644 --- a/tslint.json +++ b/tslint.json @@ -29,14 +29,14 @@ * Common Bugs and Correctness. The following rules should be turned on because they find * common bug patterns in the code or enforce type safety. */ - "chai-vague-errors": true, + "chai-vague-errors": false, "forin": true, "jquery-deferred-must-complete": true, "label-position": true, "mocha-avoid-only": true, "no-any": false, "no-arg": true, - "no-backbone-get-set-outside-model": true, + "no-backbone-get-set-outside-model": false, "no-bitwise": true, "no-conditional-assignment": true, "no-console": [true, "debug", "info", /*"log",*/ "time", "timeEnd", "trace"], From f982d717dba9af14b96ce94a0b785512e247f55f Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 13:24:01 +0100 Subject: [PATCH 06/10] Added cookie model. --- src/lib/http/Cookie.ts | 46 +++++++++++++++++++++++++++++++++++ src/lib/types/http/ICookie.ts | 16 ++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/lib/http/Cookie.ts create mode 100644 src/lib/types/http/ICookie.ts diff --git a/src/lib/http/Cookie.ts b/src/lib/http/Cookie.ts new file mode 100644 index 0000000..4b522d7 --- /dev/null +++ b/src/lib/http/Cookie.ts @@ -0,0 +1,46 @@ +import ICookie from "./../types/http/ICookie"; + +/** + * This object represents a browser cookie. + */ +export default class Cookie implements ICookie { + + private _name: string; + + private _value: string|{[name: string]: any}; + + private _expires: Date; + + private _path: string; + + private _signed: boolean; + + constructor(name: string, value: string|{[name: string]: any}, expires?: Date, path?: string, signed?: boolean) { + this._name = name; + this._value = value; + this._expires = expires; + this._path = path; + this._signed = signed; + } + + get name(): string { + return this._name; + } + + get value(): string|{[name: string]: any} { + return this._value; + } + + get expires(): Date { + return this._expires; + } + + get path(): string { + return this._path; + } + + get signed(): boolean { + return this._signed; + } + +} diff --git a/src/lib/types/http/ICookie.ts b/src/lib/types/http/ICookie.ts new file mode 100644 index 0000000..57e62dd --- /dev/null +++ b/src/lib/types/http/ICookie.ts @@ -0,0 +1,16 @@ +/** + * This object represents a browser cookie. + */ +export default interface ICookie { + + readonly name: string; + + readonly value: string|{[name: string]: any}; + + readonly expires: Date; + + readonly path: string; + + readonly signed: boolean; + +} From a249699ea33d77d39cf8752b4f1f93d0db628cdc Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 13:24:20 +0100 Subject: [PATCH 07/10] Exported cookie model. --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 6ed2931..768c433 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,8 @@ export { default as IHttpRequest } from "./lib/types/http/IHttpRequest"; export { default as IHttpResponse } from "./lib/types/http/IHttpResponse"; export { default as IHttpRoute } from "./lib/types/http/IHttpRoute"; export { default as IHttpRouterExecutor } from "./lib/types/http/IHttpRouterExecutor"; +export { default as ICookie } from "./lib/types/http/ICookie"; +export { default as Cookie } from "./lib/http/Cookie"; export { default as IBodyParser } from "./lib/types/http/IBodyParser"; export { default as JsonParser } from "./lib/http/bodyParsers/JsonParser"; From eb6f6357f4c9313be17700bc1493de674ec3f41b Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 13:24:33 +0100 Subject: [PATCH 08/10] Adapted HTTP response to use cookie model. --- src/lib/http/HttpResponse.ts | 39 +++++++++++++++-------------- src/lib/types/http/IHttpResponse.ts | 23 ++++++++--------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/lib/http/HttpResponse.ts b/src/lib/http/HttpResponse.ts index 3b37e38..b293b52 100644 --- a/src/lib/http/HttpResponse.ts +++ b/src/lib/http/HttpResponse.ts @@ -6,6 +6,7 @@ import * as statuses from "statuses"; import configuration from "./../configuration/configuration"; import HttpError from "./../exceptions/HttpError"; import IHttpError from "./../types/exceptions/IHttpError"; +import ICookie from "./../types/http/ICookie"; import IHttpHandler from "./../types/http/IHttpHandler"; import IHttpRequest from "./../types/http/IHttpRequest"; import IHttpResponse from "./../types/http/IHttpResponse"; @@ -15,6 +16,7 @@ import INext from "./../types/INext"; import IRawCallback from "./../types/IRawCallback"; import IRouter from "./../types/IRouter"; import { merge, normalizeType, setCharset, stringify } from "./../utils/utils"; +import Cookie from "./Cookie"; /** * This class represents an HTTP response, with the helpers to be sent. @@ -30,6 +32,7 @@ export default class HttpResponse implements IHttpResponse { private _headers: { [name: string]: string|string[] }; private _error: IHttpError; private _isSent: boolean; + private _cookies: { [name: string]: ICookie }; constructor(app: IApp, request: IHttpRequest, callback: IRawCallback) { this._app = app; @@ -37,6 +40,7 @@ export default class HttpResponse implements IHttpResponse { this._callback = callback; this._headers = {}; this._isSent = false; + this._cookies = {}; } get statusCode(): number { @@ -245,21 +249,22 @@ export default class HttpResponse implements IHttpResponse { return this; } - public addCookie(name: string, value: string|object, options?: object): IHttpResponse { - const opts = merge({}, options); + public addCookie(cookie: ICookie): IHttpResponse { + const opts: {[name: string]: any} = {}; const secret = this._app.get(configuration.COOKIE_SECRET); - const signed = opts.signed; + const signed = cookie.signed; if (signed && !secret) { throw new Error("app.set(\"cookie_secret\", \"SECRET\") required for signed cookies."); } - let val = typeof value === "object" - ? "j:" + JSON.stringify(value) - : String(value); + let val = typeof cookie.value === "object" + ? "j:" + JSON.stringify(cookie.value) + : String(cookie.value); if (signed) { val = "s:" + sign(val, secret); + opts.signed = true; } if ("maxAge" in opts) { @@ -271,14 +276,15 @@ export default class HttpResponse implements IHttpResponse { opts.path = "/"; } - this.appendHeader("Set-Cookie", serialize(name, String(val), opts)); + this._cookies[cookie.name] = cookie; + this.appendHeader("Set-Cookie", serialize(cookie.name, String(val), opts)); return this; } - public addCookies(obj: object, options?: object): IHttpResponse { - for (const key of Object.keys(obj)) { - this.addCookie(key, obj[key], options); + public addCookies(cookies: ICookie[]): IHttpResponse { + for (const cookie of cookies) { + this.addCookie(cookie); } return this; @@ -287,19 +293,14 @@ export default class HttpResponse implements IHttpResponse { public clearCookie(name: string, options?: object): IHttpResponse { const opts = merge({ expires: new Date(1), path: "/" }, options); - this.addCookie(name, "", opts); + const cookie: ICookie = new Cookie(name, "", opts.expires, opts.path); + this.addCookie(cookie); return this; } - public cookie(name: string): string { - const cookiesHeader = this.header("Set-Cookie"); - - const cookies = parse(Array.isArray(cookiesHeader) ? - cookiesHeader.join("; ") : cookiesHeader - ); - - return cookies[name]; + public cookie(name: string): ICookie { + return this._cookies[name]; } public location(url: string): IHttpResponse { diff --git a/src/lib/types/http/IHttpResponse.ts b/src/lib/types/http/IHttpResponse.ts index 5aa4822..60d3d1a 100644 --- a/src/lib/types/http/IHttpResponse.ts +++ b/src/lib/types/http/IHttpResponse.ts @@ -1,6 +1,7 @@ import IHttpError from "./../exceptions/IHttpError"; import INext from "./../INext"; import IRouter from "./../IRouter"; +import ICookie from "./ICookie"; import IHttpHandler from "./IHttpHandler"; /** @@ -146,32 +147,28 @@ export default interface IHttpResponse { clearCookie(name: string, options?: object): IHttpResponse; /** - * Set cookie `name` to `value`, with the given `options`. + * Add the given cookie to response header. * - * @param {string} name - * @param {string|object} value - * @param {object} options + * @param {ICookie} cookie * @return {IHttpResponse} */ - addCookie(name: string, value: string|object, options?: object): IHttpResponse; + addCookie(cookie: ICookie): IHttpResponse; /** - * Set each cookie indicated by the key of `object` to the value indicated - * by the value of the key. + * Add the given cookies to response header. * - * @param {object} name - * @param {object} options + * @param {ICookie[]} cookies * @return {IHttpResponse} */ - addCookies(name: object, options?: object): IHttpResponse; + addCookies(cookies: ICookie[]): IHttpResponse; /** - * Get the value of the cookie `name`. + * Get the cookie with the given `name`. * * @param {string} name - * @return {string} + * @return {ICookie} */ - cookie(name: string): string; + cookie(name: string): ICookie; /** * Set the location header to `url`. From f04ac3bc0b9d2fcda0a1964c49334d3382d3fb41 Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 13:48:51 +0100 Subject: [PATCH 09/10] Added get cookies to request object. --- src/lib/App.ts | 2 +- src/lib/http/HttpRequest.ts | 19 +++++++++++++-- src/lib/http/HttpResponse.ts | 2 +- src/lib/types/http/IHttpRequest.ts | 17 +++++++++++++ src/lib/utils/utils.ts | 38 ++++++++++++++++++++++++++++-- 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/lib/App.ts b/src/lib/App.ts index 12efa0a..f865b81 100644 --- a/src/lib/App.ts +++ b/src/lib/App.ts @@ -56,7 +56,7 @@ export default class App implements IApp { public handle(event: IRawEvent, callback: IRawCallback): void { if (event.isHttp) { - const req: IHttpRequest = new HttpRequest(event); + const req: IHttpRequest = new HttpRequest(this, event); const res: IHttpResponse = new HttpResponse(this, req, callback); const done = httpFinalHandler(req, res, { env: this.get(configuration.ENVIRONMENT), diff --git a/src/lib/http/HttpRequest.ts b/src/lib/http/HttpRequest.ts index f285733..ae7a3d5 100644 --- a/src/lib/http/HttpRequest.ts +++ b/src/lib/http/HttpRequest.ts @@ -1,12 +1,16 @@ import * as accepts from "accepts"; import * as fresh from "fresh"; +import configuration from "./../configuration/configuration"; +import ICookie from "./../types/http/ICookie"; import IHttpRequest from "./../types/http/IHttpRequest"; import IHttpResponse from "./../types/http/IHttpResponse"; import IHttpRoute from "./../types/http/IHttpRoute"; import IHttpUploadedFile from "./../types/http/IHttpUploadedFile"; +import IApp from "./../types/IApp"; import INext from "./../types/INext"; import IRawEvent from "./../types/IRawEvent"; -import { mergeParams, normalizeType } from "./../utils/utils"; +import { getCookiesFromHeader, mergeParams, normalizeType } from "./../utils/utils"; +import Cookie from "./Cookie"; /** * A incoming request created when the event is APIGatewayEvent. @@ -24,8 +28,9 @@ export default class HttpRequest implements IHttpRequest { private _event: IRawEvent; private _headers: { [name: string]: string }; private _context: { [name: string]: any }; + private _cookies: { [name: string]: ICookie }; - constructor(event: IRawEvent) { + constructor(app: IApp, event: IRawEvent) { this.body = event.body; // Default body this._event = event; this._context = {}; @@ -35,6 +40,8 @@ export default class HttpRequest implements IHttpRequest { for (const key of Object.keys(this._event.headers)) { this._headers[key.toLowerCase()] = this._event.headers[key]; } + + this._cookies = getCookiesFromHeader(this._headers.Cookie, app.get(configuration.COOKIE_SECRET)); } get headers(): { [name: string]: string } { @@ -85,6 +92,10 @@ export default class HttpRequest implements IHttpRequest { return this._context; } + get cookies(): { [name: string]: ICookie } { + return this._cookies; + } + public header(key: string): string { return this.headers[key.toLowerCase()]; } @@ -162,4 +173,8 @@ export default class HttpRequest implements IHttpRequest { return !this.fresh(response); } + public cookie(name: string): ICookie { + return this._cookies[name]; + } + } diff --git a/src/lib/http/HttpResponse.ts b/src/lib/http/HttpResponse.ts index b293b52..22380f8 100644 --- a/src/lib/http/HttpResponse.ts +++ b/src/lib/http/HttpResponse.ts @@ -1,4 +1,4 @@ -import { parse, serialize } from "cookie"; +import { serialize } from "cookie"; import { sign } from "cookie-signature"; import * as encodeUrl from "encodeurl"; import * as escapeHtml from "escape-html"; diff --git a/src/lib/types/http/IHttpRequest.ts b/src/lib/types/http/IHttpRequest.ts index 64e105d..e97ecc8 100644 --- a/src/lib/types/http/IHttpRequest.ts +++ b/src/lib/types/http/IHttpRequest.ts @@ -1,4 +1,5 @@ import INext from "./../INext"; +import ICookie from "./ICookie"; import IHttpResponse from "./IHttpResponse"; import IHttpRoute from "./IHttpRoute"; import IHttpUploadedFile from "./IHttpUploadedFile"; @@ -94,6 +95,13 @@ export default interface IHttpRequest { */ readonly context: { [name: string]: any }; + /** + * Returns the all the cookies retrieving their values and + * options from the HTTP request header. The key will be the name of + * the cookie and the value the object representing the cookie. + */ + readonly cookies: {[name: string]: ICookie}; + /** * Return request header. * @@ -180,4 +188,13 @@ export default interface IHttpRequest { */ stale(response: IHttpResponse): boolean; + /** + * Returns the cookie with the given `name` retrieving the value and + * options from the HTTP request header. + * + * @param {string} name + * @return {ICookie} + */ + cookie(name: string): ICookie; + } diff --git a/src/lib/utils/utils.ts b/src/lib/utils/utils.ts index 0d11f56..cc05152 100644 --- a/src/lib/utils/utils.ts +++ b/src/lib/utils/utils.ts @@ -1,5 +1,9 @@ -import { format, parse } from "content-type"; +import { format, parse as parseContentType } from "content-type"; +import { parse as parseCookie } from "cookie"; +import { unsign } from "cookie-signature"; import { lookup } from "mime-types"; +import Cookie from "./../http/Cookie"; +import ICookie from "./../types/http/ICookie"; import IRawEvent from "./../types/IRawEvent"; /** @@ -12,7 +16,7 @@ export function setCharset(contentType: string, charset: string): string { } // parse type - const parsed = parse(contentType); + const parsed = parseContentType(contentType); // set charset parsed.parameters.charset = charset; @@ -71,3 +75,33 @@ export function normalizeType(type: string): string { ? lookup(type) : type; } + +const parseCookieValue = (rawValue: string, secret: string): string | { [name: string]: any } => { + let result: string | { [name: string]: any } = rawValue; + + if (result.startsWith("s:")) { + result = unsign(result.substr(2), secret) as string; + } + + if (result.startsWith("j:")) { + result = JSON.parse(result.substr(2)); + } + + return result; +}; + +export function getCookiesFromHeader(header: string, secret: string): { [name: string]: ICookie } { + const result: { [name: string]: ICookie } = {}; + + if (header) { + const cookiesAsObject: { [name: string]: string } = parseCookie(header); + + for (const cookieName of Object.keys(cookiesAsObject)) { + const cookieValue: string | { [name: string]: any } = parseCookieValue(cookiesAsObject[cookieName], secret); + + result[cookieName] = new Cookie(cookieName, cookieValue); + } + } + + return result; +} From 4428710199e915071a798a39e68ae54460a8a39a Mon Sep 17 00:00:00 2001 From: rogelio-o Date: Mon, 25 Dec 2017 14:46:02 +0100 Subject: [PATCH 10/10] Added tests for cookies. --- src/lib/http/HttpRequest.ts | 3 +- src/lib/http/HttpResponse.ts | 9 +-- test/http/HttpLayer.spec.ts | 2 +- test/http/HttpRequest.spec.ts | 21 +++++- test/http/HttpResponse.spec.ts | 68 +++++++++++-------- test/http/HttpRoute.spec.ts | 2 +- test/http/HttpRouterExecutor.spec.ts | 2 +- test/http/bodyParsers/JsonParser.spec.ts | 13 ++-- test/http/bodyParsers/MultipartParser.spec.ts | 9 ++- .../http/bodyParsers/UrlEncodedParser.spec.ts | 17 +++-- test/http/bodyParsers/parserHelper.spec.ts | 19 +++--- test/http/httpFinalHandler.spec.ts | 6 +- test/router.spec.ts | 8 +-- test/utils/httpEvent.ts | 3 +- test/utils/utils.spec.ts | 46 ++++++++++++- 15 files changed, 157 insertions(+), 71 deletions(-) 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); + }); + }); });