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/package.json b/package.json index 4d05d0f..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 --type-check --project tsconfig.json src/{,**/,**/**/,**/**/**/}*.ts", + "lint": "tslint --config tslint.json --project tsconfig.json", "coveralls": "nyc report --reporter=text-lcov | coveralls", "prepublish": "npm-auto-version" }, @@ -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" diff --git a/src/index.ts b/src/index.ts index 9e1b1b0..768c433 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"; @@ -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"; 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/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/http/HttpRequest.ts b/src/lib/http/HttpRequest.ts index f285733..eb855e4 100644 --- a/src/lib/http/HttpRequest.ts +++ b/src/lib/http/HttpRequest.ts @@ -1,12 +1,15 @@ 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"; /** * A incoming request created when the event is APIGatewayEvent. @@ -24,8 +27,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 +39,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 +91,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 +172,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 3b37e38..4f9755e 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"; @@ -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,40 +249,43 @@ 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) { - 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.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 +294,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/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; + +} 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/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`. 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; +} diff --git a/test/app.spec.ts b/test/app.spec.ts index 9172b3a..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..09a1be9 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(app, 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..11b5ed0 100644 --- a/test/http/HttpRequest.spec.ts +++ b/test/http/HttpRequest.spec.ts @@ -1,9 +1,10 @@ -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 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"; import httpEvent from "./../utils/httpEvent"; @@ -11,185 +12,201 @@ 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(app, 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; + }); + + 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 637bc3d..157aec0 100644 --- a/test/http/HttpResponse.spec.ts +++ b/test/http/HttpResponse.spec.ts @@ -1,119 +1,121 @@ -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 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"; 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(app, 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 +134,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 +154,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,118 +317,131 @@ 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 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.", () => { - var oldDate = Date; + 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: 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()); + 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 /', () => { - 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 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", () => { - 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 +450,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 +482,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 +492,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 +502,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 +513,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..b17d8b3 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(app, 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..81d3205 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)); + req = new HttpRequest(app, 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..25f6ad4 100644 --- a/test/http/bodyParsers/JsonParser.spec.ts +++ b/test/http/bodyParsers/JsonParser.spec.ts @@ -1,17 +1,21 @@ +/* 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 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 res: IHttpResponse =