開發(fā)環(huán)境
操作系統(tǒng):macOS High Sierra 10.13.6
Docker:Community Edition Version 18.03.1-ce-mac65
項(xiàng)目結(jié)構(gòu)
采用node:10-alpine鏡像
docker pull node:10-alpine
創(chuàng)建docker容器卷node_modules10,作為node10相關(guān)應(yīng)用的包引用
docker volume create node_modules10
創(chuàng)建項(xiàng)目及運(yùn)行koa2
# 創(chuàng)建項(xiàng)目目錄
mkdir /path/to/koa2-beginning
# 初始化package.json并創(chuàng)建index文件
|____src
| |____index.js
| |____package.json
# package.json指定啟動腳本
{
...
"scripts": {
"start": "node index.js"
},
...
}
# 運(yùn)行容器,指定宿主機(jī)的3001端口映射到容器的3000端口,這樣每個(gè)應(yīng)用在容器內(nèi)部都是3000,外部可根據(jù)不同項(xiàng)目指定不同端口
docker run -itd -p 3001:3000 -v ~/workspace/research/koa2_beginning/src:/koa2 -v node_modules10:/koa2/node_modules --name koa2-beginning node:10-alpine
# 安裝koa2
```text
docker exec -it -w /koa2 koa2-beginning npm install koa --save
# 修改index.js
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
# 運(yùn)行
docker exec -it -w /koa2 koa2-beginning npm start
# 訪問
curl -L 127.0.0.1:3001
自動刷新
使用nodemon幫助我們進(jìn)行自動刷新
docker exec -it -w /koa2 koa2-beginning npm install nodemon --save-dev
修改npm啟動命令,在scripts下增加dev
"dev":"./node_modules/.bin/nodemon -L index.js"
這里需要使用-L參數(shù),否則在docker容器中不會自動重啟,參考nodemon官方自述:
In some networked environments (such as a container running nodemon reading across a mounted drive), you will need to use the legacyWatch: true which enables Chokidar's polling.
Via the CLI, use either --legacy-watch or -L for short:
重新運(yùn)行容器
docker exec -it -w /koa2 koa2-beginning npm run dev
>>>
> koa2-beginning@0.0.1 dev /koa2
> nodemon -L index.js
[nodemon] 1.18.3
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node index.js`
現(xiàn)在嘗試修改代碼,發(fā)現(xiàn)已經(jīng)可以自動重啟了
[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
單元測試
單元測試框架使用 mocha + supertest
docker exec -it -w /koa2 koa2-beginning npm install supertest mocha --save-dev
添加test文件夾,添加body_parsing.js
|____src
| |____test
| | |____body_parsing.js
添加測試代碼
const app = require('../index');
const server = app.listen();
const request = require('supertest').agent(server);
describe('Body Parsing', function () {
after(function () {
server.close();
});
describe('POST /uppercase', function () {
describe('with JSON', function () {
it('should work', function (done) {
request
.post('/uppercase')
.send({ name: 'tobi' })
.expect(200)
.expect({ name: 'TOBI' }, done);
});
});
describe('with urlencoded', function () {
it('should work', function (done) {
request
.post('/uppercase')
.send('name=tj')
.expect(200)
.expect({ name: 'TJ' }, done);
});
});
describe('when length > limit', function () {
it('should 413', function (done) {
request
.post('/json')
.send({ name: Array(5000).join('a') })
.expect(413, done);
});
});
describe('when no name is sent', function () {
it('should 400', function (done) {
request
.post('/uppsercase')
.send('age=10')
.expect(400, done);
});
});
});
});
修改index.js,以適應(yīng)單元測試
const Koa = require('koa');
const koaBody = require('koa-body')
// export Koa app
const app = module.exports = new Koa();
app.use(koaBody({
jsonLimit: '1kb'
}))
app.use(async (ctx) => {
const body = ctx.request.body;
if (!body.name) ctx.throw(400, '.name required');
ctx.body = { name: body.name.toUpperCase() };
})
// if test/*.js has require('index.js'),module.parent will not be null
if (!module.parent) app.listen(3000);
修改package.json,添加test
{
...
"scripts": {
"test": "mocha",
...
},
...
}
執(zhí)行測試
docker exec -it -w /koa2 koa2-beginning npm test
>>>
> koa2-beginning@0.0.1 test /koa2
> mocha
Body Parsing
POST /uppercase
with JSON
? should work (46ms)
with urlencoded
? should work
when length > limit
? should 413
when no name is sent
? should 400
4 passing (76ms)