From 0e049b76066f0ca35c04329bbdb148f288849982 Mon Sep 17 00:00:00 2001 From: Manthan Mallikarjun Date: Sun, 25 Aug 2019 02:04:09 -0700 Subject: [PATCH] reach 100% code coverage --- src/utils/glob.ts | 1 + tests/plugins/error-handler.ts | 86 +++++++-------- tests/plugins/request-logger.ts | 32 +++--- tests/seeds/server/routes/index.ts | 13 +++ .../seeds/utils/add-routes/routes/default.ts | 7 ++ tests/seeds/utils/add-routes/routes/index.ts | 5 + tests/seeds/utils/add-routes/routes/throw.ts | 1 + tests/server.ts | 68 ++++++++++++ tests/serverless/aws.ts | 30 +++--- tests/serverless/netlify.ts | 30 +++--- tests/serverless/now.ts | 28 ++--- tests/serverless/runkit.ts | 30 +++--- tests/utils/add-route.ts | 102 ++++++++++++++++++ tests/utils/import-routes.ts | 34 ++++++ 14 files changed, 355 insertions(+), 112 deletions(-) create mode 100644 tests/seeds/server/routes/index.ts create mode 100644 tests/seeds/utils/add-routes/routes/default.ts create mode 100644 tests/seeds/utils/add-routes/routes/index.ts create mode 100644 tests/seeds/utils/add-routes/routes/throw.ts create mode 100644 tests/server.ts create mode 100644 tests/utils/add-route.ts create mode 100644 tests/utils/import-routes.ts diff --git a/src/utils/glob.ts b/src/utils/glob.ts index 93a10d7b..7639cbb1 100644 --- a/src/utils/glob.ts +++ b/src/utils/glob.ts @@ -9,6 +9,7 @@ const ls: (dir: string, filelist: string[]) => any = (dir, filelist = []): any[] ? ls(path.join(dir, file), filelist) : filelist.concat(path.join(dir, file))[0])); +/* istanbul ignore next */ const flatten = (arr: any[]): any[] => arr.reduce((acc: any, val: any): any[] => (Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val)), []); export default (url: string, glob: string): string[] => { diff --git a/tests/plugins/error-handler.ts b/tests/plugins/error-handler.ts index aad5be6e..303c0116 100644 --- a/tests/plugins/error-handler.ts +++ b/tests/plugins/error-handler.ts @@ -20,57 +20,59 @@ afterEach(async () => { server.close(); }); -describe('error handler', () => { - describe('with standard error', () => { - beforeAll(() => { - error = () => { throw new Error('message'); }; - }); +describe('plugins', () => { + describe('error handler', () => { + describe('with standard error', () => { + beforeAll(() => { + error = () => { throw new Error('message'); }; + }); - it('returns a 500 error', async () => { - expect.assertions(2); - const req = await fetch(server.url); - const res = await req.json(); - expect(req.status).toStrictEqual(500); - expect(res).toMatchObject({ - error: 'Internal Server Error', - message: 'An internal server error occurred', - statusCode: 500, + it('returns a 500 error', async () => { + expect.assertions(2); + const req = await fetch(server.url); + const res = await req.json(); + expect(req.status).toStrictEqual(500); + expect(res).toMatchObject({ + error: 'Internal Server Error', + message: 'An internal server error occurred', + statusCode: 500, + }); }); }); - }); - describe('with a custom error created with createError', () => { - beforeAll(() => { - error = () => { throw createError(400, 'custom error message'); }; - }); + describe('with a custom error created with createError', () => { + beforeAll(() => { + error = () => { throw createError(400, 'custom error message'); }; + }); - it('returns a 500 error', async () => { - expect.assertions(2); - const req = await fetch(server.url); - const res = await req.json(); - expect(req.status).toStrictEqual(400); - expect(res).toMatchObject({ - error: 'Bad Request', - message: 'custom error message', - statusCode: 400, + it('returns a 500 error', async () => { + expect.assertions(2); + const req = await fetch(server.url); + const res = await req.json(); + expect(req.status).toStrictEqual(400); + expect(res).toMatchObject({ + error: 'Bad Request', + message: 'custom error message', + statusCode: 400, + }); }); }); - }); - describe('with error handler disabled', () => { - beforeAll(() => { - disableErrorHandler = true; - error = () => { throw new Error('message'); }; - }); + describe('with error handler disabled', () => { + beforeAll(() => { + disableErrorHandler = true; + error = () => { throw new Error('message'); }; + }); - it('returns an internal server error in text', async () => { - expect.assertions(2); - const spy = jest.spyOn(console, 'error').mockImplementation(); - const req = await fetch(server.url); - const res = await req.text(); - expect(req.status).toStrictEqual(500); - expect(res).toBe('Internal Server Error'); - spy.mockRestore(); + it('returns an internal server error in text', async () => { + expect.assertions(2); + const spy = jest.spyOn(console, 'error').mockImplementation(); + const req = await fetch(server.url); + const res = await req.text(); + expect(req.status).toStrictEqual(500); + expect(res).toBe('Internal Server Error'); + spy.mockRestore(); + }); }); }); }); diff --git a/tests/plugins/request-logger.ts b/tests/plugins/request-logger.ts index c05a4d0b..d3845557 100644 --- a/tests/plugins/request-logger.ts +++ b/tests/plugins/request-logger.ts @@ -19,21 +19,23 @@ afterEach(async () => { server.close(); }); -describe('request logger', () => { - describe('with logger enabled', () => { - it('logs', async () => { - expect.assertions(6); - const spy = jest.spyOn(process.stdout, 'write').mockImplementation(); - const req = await fetch(server.url); - const res = await req.json(); - expect(req.status).toStrictEqual(200); - expect(res).toMatchObject({ hello: 'world' }); - expect(spy).toHaveBeenCalledTimes(1); - const log = JSON.parse(spy.mock.calls[0][0]); - expect(log.req).toHaveProperty('method', 'GET'); - expect(log.req).toHaveProperty('url', '/'); - expect(log.res).toHaveProperty('statusCode', 200); - spy.mockRestore(); +describe('plugins', () => { + describe('request logger', () => { + describe('with logger enabled', () => { + it('logs', async () => { + expect.assertions(6); + const spy = jest.spyOn(process.stdout, 'write').mockImplementation(); + const req = await fetch(server.url); + const res = await req.json(); + expect(req.status).toStrictEqual(200); + expect(res).toMatchObject({ hello: 'world' }); + expect(spy).toHaveBeenCalledTimes(1); + const log = JSON.parse(spy.mock.calls[0][0]); + expect(log.req).toHaveProperty('method', 'GET'); + expect(log.req).toHaveProperty('url', '/'); + expect(log.res).toHaveProperty('statusCode', 200); + spy.mockRestore(); + }); }); }); }); diff --git a/tests/seeds/server/routes/index.ts b/tests/seeds/server/routes/index.ts new file mode 100644 index 00000000..23b4896e --- /dev/null +++ b/tests/seeds/server/routes/index.ts @@ -0,0 +1,13 @@ +import { light, Route } from '../../../../src/index'; + +class Index extends Route { + public disableRequestLogger = true; + + public async handler() { + return { + hello: 'server', + }; + } +} + +module.exports = light(Index); diff --git a/tests/seeds/utils/add-routes/routes/default.ts b/tests/seeds/utils/add-routes/routes/default.ts new file mode 100644 index 00000000..0de1c069 --- /dev/null +++ b/tests/seeds/utils/add-routes/routes/default.ts @@ -0,0 +1,7 @@ +import { light, Route } from '../../../../../src/index'; + +class Index extends Route {} + +module.exports = { + default: light(Index), +}; diff --git a/tests/seeds/utils/add-routes/routes/index.ts b/tests/seeds/utils/add-routes/routes/index.ts new file mode 100644 index 00000000..5e137c64 --- /dev/null +++ b/tests/seeds/utils/add-routes/routes/index.ts @@ -0,0 +1,5 @@ +import { light, Route } from '../../../../../src/index'; + +class Index extends Route {} + +export default light(Index); diff --git a/tests/seeds/utils/add-routes/routes/throw.ts b/tests/seeds/utils/add-routes/routes/throw.ts new file mode 100644 index 00000000..8107f88d --- /dev/null +++ b/tests/seeds/utils/add-routes/routes/throw.ts @@ -0,0 +1 @@ +throw new Error('error'); diff --git a/tests/server.ts b/tests/server.ts new file mode 100644 index 00000000..7ec8c189 --- /dev/null +++ b/tests/server.ts @@ -0,0 +1,68 @@ +import fetch from 'node-fetch'; +import listen from 'test-listen'; +import { join } from 'path'; + +import { + server, + light, + Route, +} from '../src/index'; + +let app: any; +let url: any; + +beforeEach(async () => { + url = await listen(app.server); +}); + +afterEach(async () => { + app.server.close(); +}); + +describe('server', () => { + describe('with functions as routes', () => { + beforeAll(() => { + app = server({ + routes: [ + { + handler: light(class Index extends Route { + public disableRequestLogger = true; + + public async handler() { + return { + hello: 'server', + }; + } + }), + method: 'GET', + path: '/', + }, + ], + }); + }); + + it('returns an object', async () => { + expect.assertions(2); + const req = await fetch(url); + const res = await req.json(); + expect(req.status).toStrictEqual(200); + expect(res).toMatchObject({ hello: 'server' }); + }); + }); + + describe('with string as routes', () => { + beforeAll(() => { + app = server({ + routes: join(__dirname, './seeds/server/routes'), + }); + }); + + it('returns an object', async () => { + expect.assertions(2); + const req = await fetch(url); + const res = await req.json(); + expect(req.status).toStrictEqual(200); + expect(res).toMatchObject({ hello: 'server' }); + }); + }); +}); diff --git a/tests/serverless/aws.ts b/tests/serverless/aws.ts index e2978607..fcbb2c38 100644 --- a/tests/serverless/aws.ts +++ b/tests/serverless/aws.ts @@ -1,20 +1,22 @@ import { light, Route } from '../../src/index'; -describe('aws', () => { - process.env.LIGHT_ENVIRONMENT = 'aws'; +describe('serverless', () => { + describe('aws', () => { + process.env.LIGHT_ENVIRONMENT = 'aws'; - const server: any = light(class Index extends Route { - public async handler() { - return { - hello: 'world', - }; - } - }); + const server: any = light(class Index extends Route { + public async handler() { + return { + hello: 'world', + }; + } + }); - it('exports a handler', async () => { - expect.assertions(3); - expect(server).toBeTruthy(); - expect(server.handler).toBeTruthy(); - expect(typeof server.handler).toBe('function'); + it('exports a handler', async () => { + expect.assertions(3); + expect(server).toBeTruthy(); + expect(server.handler).toBeTruthy(); + expect(typeof server.handler).toBe('function'); + }); }); }); diff --git a/tests/serverless/netlify.ts b/tests/serverless/netlify.ts index 890dfcd7..5cf60d34 100644 --- a/tests/serverless/netlify.ts +++ b/tests/serverless/netlify.ts @@ -1,20 +1,22 @@ import { light, Route } from '../../src/index'; -describe('netlify', () => { - process.env.LIGHT_ENVIRONMENT = 'netlify'; +describe('serverless', () => { + describe('netlify', () => { + process.env.LIGHT_ENVIRONMENT = 'netlify'; - const server: any = light(class Index extends Route { - public async handler() { - return { - hello: 'world', - }; - } - }); + const server: any = light(class Index extends Route { + public async handler() { + return { + hello: 'world', + }; + } + }); - it('exports a handler', async () => { - expect.assertions(3); - expect(server).toBeTruthy(); - expect(server.handler).toBeTruthy(); - expect(typeof server.handler).toBe('function'); + it('exports a handler', async () => { + expect.assertions(3); + expect(server).toBeTruthy(); + expect(server.handler).toBeTruthy(); + expect(typeof server.handler).toBe('function'); + }); }); }); diff --git a/tests/serverless/now.ts b/tests/serverless/now.ts index bb47c892..a1d4b6f8 100644 --- a/tests/serverless/now.ts +++ b/tests/serverless/now.ts @@ -1,19 +1,21 @@ import { light, Route } from '../../src/index'; -describe('now', () => { - process.env.LIGHT_ENVIRONMENT = 'now'; +describe('serverless', () => { + describe('now', () => { + process.env.LIGHT_ENVIRONMENT = 'now'; - const server: any = light(class Index extends Route { - public async handler() { - return { - hello: 'world', - }; - } - }); + const server: any = light(class Index extends Route { + public async handler() { + return { + hello: 'world', + }; + } + }); - it('exports a function', async () => { - expect.assertions(2); - expect(server).toBeTruthy(); - expect(typeof server).toBe('function'); + it('exports a function', async () => { + expect.assertions(2); + expect(server).toBeTruthy(); + expect(typeof server).toBe('function'); + }); }); }); diff --git a/tests/serverless/runkit.ts b/tests/serverless/runkit.ts index 383616c0..5403b698 100644 --- a/tests/serverless/runkit.ts +++ b/tests/serverless/runkit.ts @@ -1,20 +1,22 @@ import { light, Route } from '../../src/index'; -describe('runkit', () => { - process.env.LIGHT_ENVIRONMENT = 'runkit'; +describe('serverless', () => { + describe('runkit', () => { + process.env.LIGHT_ENVIRONMENT = 'runkit'; - const server: any = light(class Index extends Route { - public async handler() { - return { - hello: 'world', - }; - } - }); + const server: any = light(class Index extends Route { + public async handler() { + return { + hello: 'world', + }; + } + }); - it('exports a function', async () => { - expect.assertions(3); - expect(server).toBeTruthy(); - expect(server.endpoint).toBeTruthy(); - expect(typeof server.endpoint).toBe('function'); + it('exports a function', async () => { + expect.assertions(3); + expect(server).toBeTruthy(); + expect(server.endpoint).toBeTruthy(); + expect(typeof server.endpoint).toBe('function'); + }); }); }); diff --git a/tests/utils/add-route.ts b/tests/utils/add-route.ts new file mode 100644 index 00000000..9c877e96 --- /dev/null +++ b/tests/utils/add-route.ts @@ -0,0 +1,102 @@ +import addRoute from '../../src/utils/add-route'; + +describe('utils', () => { + describe('add route', () => { + describe('with basic route', () => { + const router = { + on: jest.fn(), + }; + + const route = { + path: '/', + method: 'GET', + handler: jest.fn(), + }; + + it('adds the route', async () => { + expect.assertions(2); + addRoute(router, route); + expect(router.on.mock.calls.length).toBe(1); + expect(router.on).toHaveBeenCalledWith(['GET'], '/', route.handler); + }); + }); + + describe('with array of methods', () => { + const router = { + on: jest.fn(), + }; + + const route = { + path: '/', + method: ['GET', 'POST', 'PUT', 'patch', 'OPTIONS'], + handler: jest.fn(), + }; + + it('adds the route', async () => { + expect.assertions(2); + addRoute(router, route); + expect(router.on.mock.calls.length).toBe(1); + expect(router.on).toHaveBeenCalledWith(['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS'], '/', route.handler); + }); + }); + + describe('without method', () => { + const router = { + on: jest.fn(), + }; + + const route = { + path: '/', + handler: jest.fn(), + }; + + it('adds the route', async () => { + expect.assertions(2); + addRoute(router, (route as any)); + expect(router.on.mock.calls.length).toBe(1); + expect(router.on).toHaveBeenCalledWith(['GET'], '/', route.handler); + }); + }); + + describe('with array of paths', () => { + const router = { + on: jest.fn(), + }; + + const route = { + path: ['/', '/a', '/b'], + method: 'GET', + handler: jest.fn(), + }; + + it('adds the routes', async () => { + expect.assertions(4); + addRoute(router, route); + expect(router.on.mock.calls.length).toBe(3); + expect(router.on).toHaveBeenCalledWith(['GET'], '/', route.handler); + expect(router.on).toHaveBeenCalledWith(['GET'], '/a', route.handler); + expect(router.on).toHaveBeenCalledWith(['GET'], '/b', route.handler); + }); + }); + + describe('with index route', () => { + const router = { + on: jest.fn(), + }; + + const route = { + path: '/index', + method: 'GET', + handler: jest.fn(), + }; + + it('adds root and index routes', async () => { + expect.assertions(3); + addRoute(router, route); + expect(router.on.mock.calls.length).toBe(2); + expect(router.on).toHaveBeenCalledWith(['GET'], '/index', route.handler); + expect(router.on).toHaveBeenCalledWith(['GET'], '/', route.handler); + }); + }); + }); +}); diff --git a/tests/utils/import-routes.ts b/tests/utils/import-routes.ts new file mode 100644 index 00000000..b5aa83b3 --- /dev/null +++ b/tests/utils/import-routes.ts @@ -0,0 +1,34 @@ +import { join } from 'path'; +import importRoutes from '../../src/utils/import-routes'; + +const routesPath = join(__dirname, '../seeds/utils/add-routes/routes'); + +describe('utils', () => { + describe('import routes', () => { + describe('with regular route', () => { + it('returns a route', async () => { + expect.assertions(1); + const route = importRoutes([join(routesPath, './index.ts')], routesPath); + expect(route.length).toBe(1); + }); + }); + + describe('with default route', () => { + it('returns a route', async () => { + expect.assertions(1); + const route = importRoutes([join(routesPath, './default.ts')], routesPath); + expect(route.length).toBe(1); + }); + }); + + describe('with an invalid route', () => { + it('throws', async () => { + expect.assertions(2); + const spy = jest.spyOn(process.stdout, 'write').mockImplementation(); + expect(() => importRoutes([join(routesPath, './throw.ts')], routesPath)).toThrow('please fix the route and try again'); + expect(spy).toHaveBeenCalledTimes(2); + spy.mockRestore(); + }); + }); + }); +});