-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(roc-package-web-app): Upgrade package to use Koa@2
BREAKING CHANGE: Middlewares need to be defined as an async functions instead of generators.
- Loading branch information
Showing
8 changed files
with
200 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
packages/roc-package-web-app/src/app/defaultKoaMiddlewares.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import getKoaMiddlewares from './defaultKoaMiddlewares'; | ||
import koaErrorMock from 'koa-error'; | ||
import koaHelmetMock from 'koa-helmet'; | ||
import koaEtagMock from 'koa-etag' | ||
import koaLoggerMock from 'koa-logger'; | ||
import koaCompressMock from 'koa-compress'; | ||
import koaFaviconMock from 'koa-favicon'; | ||
import accessLogMock from './middlewares/accesslog'; | ||
|
||
jest.mock('koa-error', () => jest.fn(() => function koaError(){})); | ||
jest.mock('koa-helmet', () => jest.fn(() => function koaHelmet(){})); | ||
jest.mock('koa-etag', () => jest.fn(() => function koaEtag(){})); | ||
jest.mock('koa-logger', () => jest.fn(() => function koaLogger(){})); | ||
jest.mock('koa-compress', () => jest.fn(() => function koaCompress(){})); | ||
jest.mock('koa-favicon', () => jest.fn(() => function koaFavicon(){})); | ||
jest.mock('./middlewares/accesslog', () => jest.fn(() => function accessLog(){})); | ||
|
||
|
||
describe('defaultKoaMiddleware', () => { | ||
afterEach(() => { | ||
koaErrorMock.mockClear(); | ||
koaHelmetMock.mockClear(); | ||
koaEtagMock.mockClear(); | ||
koaLoggerMock.mockClear(); | ||
koaCompressMock.mockClear(); | ||
}); | ||
|
||
it('should return default array of middlewares even when all options are falsy', () => { | ||
const middlewares = getKoaMiddlewares({}, {dev: false, dist: false}); | ||
|
||
expect(middlewares.length).toEqual(3); | ||
expect(middlewares.map(f => f.name)).toEqual(['koaHelmet', 'koaEtag', 'koaLogger']); | ||
expect(koaHelmetMock).toHaveBeenCalled(); | ||
expect(koaEtagMock).toHaveBeenCalled(); | ||
expect(koaLoggerMock).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should include koa-error when dev is set to true', () => { | ||
const middlewares = getKoaMiddlewares({}, {dev: true, dist: false}); | ||
|
||
expect(middlewares.length).toEqual(4); | ||
expect(middlewares.map(f => f.name)).toEqual(['koaError', 'koaHelmet', 'koaEtag', 'koaLogger']); | ||
expect(koaErrorMock).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should include koa-compress and accessLog instead of koa-logger when dist is set to true', () => { | ||
const middlewares = getKoaMiddlewares({}, {dev: false, dist: true}); | ||
|
||
expect(middlewares.length).toEqual(4); | ||
expect(middlewares.map(f => f.name)).toEqual(['koaHelmet', 'koaEtag', 'koaCompress', 'accessLog']); | ||
expect(koaCompressMock).toHaveBeenCalled(); | ||
expect(accessLogMock).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should include koa-favicon when favicon is specified in config', () => { | ||
const config = {favicon: './pathToFavicon.ico'}; | ||
const middlewares = getKoaMiddlewares(config, {dev: false, dist: false}); | ||
|
||
expect(middlewares.length).toEqual(4); | ||
expect(middlewares.map(f => f.name)).toEqual(['koaHelmet', 'koaEtag', 'koaFavicon', 'koaLogger']); | ||
expect(koaFaviconMock).toHaveBeenCalledWith(config.favicon); | ||
}) | ||
}); |
17 changes: 17 additions & 0 deletions
17
packages/roc-package-web-app/src/app/middlewares/accesslog.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import moment from 'moment'; | ||
import util from 'util'; | ||
|
||
/* | ||
Implementation based on koa-accesslog | ||
*/ | ||
export default function accesslog(stream = process.stdout) { | ||
return async function(ctx, next) { | ||
await next(); | ||
|
||
const format = '%s - - [%s] "%s %s HTTP/1.X" %d %s\n'; | ||
const length = ctx.length ? ctx.length.toString() : '-'; | ||
const date = moment().format('D/MMM/YYYY:HH:mm:ss ZZ'); | ||
|
||
stream.write(util.format(format, ctx.ip, date, ctx.method, ctx.path, ctx.status, length)); | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
packages/roc-package-web-app/src/app/middlewares/accesslog.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import createAccessLogMiddleware from './accesslog'; | ||
import { format as formatMock } from 'util'; | ||
|
||
jest.mock('util', () => ({ | ||
format: jest.fn(), | ||
})); | ||
|
||
describe('middlewares/accesslog', () => { | ||
const next = async () => {}; | ||
|
||
afterEach(() => { | ||
formatMock.mockClear(); | ||
}); | ||
|
||
it('should call write method of passed stream', async () => { | ||
const streamWriteMock = jest.fn(); | ||
const streamMock = { | ||
write: streamWriteMock | ||
}; | ||
const accessLogMiddleware = createAccessLogMiddleware(streamMock); | ||
await accessLogMiddleware({}, next); | ||
|
||
expect(streamWriteMock).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should call util.format with certain ctx properties', async () => { | ||
const streamWriteMock = jest.fn(); | ||
const streamMock = { | ||
write: streamWriteMock | ||
}; | ||
const accessLogMiddleware = createAccessLogMiddleware(streamMock); | ||
const ctx = { | ||
length: 42, | ||
ip: '127.0.0.1', | ||
method: 'GET', | ||
path: '/app', | ||
status: 200, | ||
}; | ||
await accessLogMiddleware(ctx, next); | ||
|
||
expect(formatMock).toHaveBeenCalledWith( | ||
'%s - - [%s] \"%s %s HTTP/1.X\" %d %s\n', | ||
ctx.ip, | ||
expect.anything(), | ||
ctx.method, | ||
ctx.path, | ||
ctx.status, | ||
ctx.length.toString(), | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
packages/roc-package-web-app/src/app/middlewares/basepathSupport.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import createBasepathSupportMiddleware from './basepathSupport'; | ||
|
||
describe('middlewares/basepathSupport', () => { | ||
const next = async () => {}; | ||
|
||
it('should throw an error when basepath does not start with "/"', () => { | ||
const veryWrongBasepath = 'veryWrongBasepath'; | ||
expect(() => { | ||
createBasepathSupportMiddleware(veryWrongBasepath); | ||
}).toThrowError(`The basepath must start with "/", was ${veryWrongBasepath}`); | ||
}); | ||
|
||
it('should set new ctx.path with eased basepath', async () => { | ||
const basepath = '/basepath'; | ||
const ctx = { path: '/basepath/application' }; | ||
const basepathMiddleware = createBasepathSupportMiddleware(basepath); | ||
await basepathMiddleware(ctx, next); | ||
|
||
expect(ctx.path).toEqual('/application'); | ||
}); | ||
|
||
it('should set new ctx.path to "/" if its the same as basepath', async () => { | ||
const basepath = '/basepath'; | ||
const ctx = { path: '/basepath' }; | ||
const basepathMiddleware = createBasepathSupportMiddleware(basepath); | ||
await basepathMiddleware(ctx, next); | ||
|
||
expect(ctx.path).toEqual('/'); | ||
}); | ||
|
||
it('should return an undefined when basepath is different than "/" and no new path is set', async () => { | ||
const basepath = '/'; | ||
const ctx = { path: '/' }; | ||
const basepathMiddleware = createBasepathSupportMiddleware(basepath); | ||
const result = await basepathMiddleware(ctx, next); | ||
|
||
expect(result).toEqual(undefined); | ||
}); | ||
}); |