From 80daf7c749298b72cd5722f81bcb8c9c543b3c52 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 16 Oct 2018 06:37:21 +0900 Subject: [PATCH] Implement API tests --- package.json | 3 + src/server/api/index.ts | 2 +- src/server/index.ts | 3 +- test/api.ts | 151 ++++++++++++++++++++++++++++++++++++++++ test/mfm.ts | 4 ++ 5 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 test/api.ts diff --git a/package.json b/package.json index f1d83507d..3cd8e3b0e 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@prezzemolo/rap": "0.1.2", "@prezzemolo/zip": "0.0.3", "@types/bcryptjs": "2.4.2", + "@types/chai-http": "3.0.5", "@types/dateformat": "1.0.1", "@types/debug": "0.0.31", "@types/deep-equal": "1.0.1", @@ -90,6 +91,8 @@ "bee-queue": "1.2.2", "bootstrap-vue": "2.0.0-rc.11", "cafy": "11.3.0", + "chai": "4.2.0", + "chai-http": "4.2.0", "chalk": "2.4.1", "chart.js": "2.7.3", "commander": "2.19.0", diff --git a/src/server/api/index.ts b/src/server/api/index.ts index a8f6455d9..c68f109ae 100644 --- a/src/server/api/index.ts +++ b/src/server/api/index.ts @@ -54,4 +54,4 @@ router.all('*', async ctx => { // Register router app.use(router.routes()); -module.exports = app; +export default app; diff --git a/src/server/index.ts b/src/server/index.ts index dc60b0d9e..e9b2e2440 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -18,6 +18,7 @@ import activityPub from './activitypub'; import webFinger from './webfinger'; import config from '../config'; import { updateNetworkStats } from '../services/update-chart'; +import apiServer from './api'; // Init app const app = new Koa(); @@ -47,7 +48,7 @@ if (config.url.startsWith('https')) { }); } -app.use(mount('/api', require('./api'))); +app.use(mount('/api', apiServer)); app.use(mount('/files', require('./file'))); // Init router diff --git a/test/api.ts b/test/api.ts new file mode 100644 index 000000000..ee90da561 --- /dev/null +++ b/test/api.ts @@ -0,0 +1,151 @@ +/* + * Tests of API + */ + +import * as http from 'http'; +import * as assert from 'chai'; + +assert.use(require('chai-http')); +const expect = assert.expect; + +//#region process +Error.stackTraceLimit = Infinity; + +// During the test the env variable is set to test +process.env.NODE_ENV = 'test'; + +// Display detail of unhandled promise rejection +process.on('unhandledRejection', console.dir); +//#endregion + +const app = require('../built/server/api').default; +const db = require('../built/db/mongodb').default; + +const server = http.createServer(app.callback()); + +//#region Utilities +const async = (fn: Function) => (done: Function) => { + fn().then(() => { + done(); + }, (err: Error) => { + done(err); + }); +}; + +const request = (endpoint: string, params: any, me?: any): Promise => new Promise((ok, ng) => { + const auth = me ? { + i: me.account.token + } : {}; + + assert.request(server) + .post(endpoint) + .send(Object.assign(auth, params)) + .end((err, res) => { + ok(res); + }); +}); + +const signup = async (params?: any) => { + const q = Object.assign({ + username: 'test', + password: 'test' + }, params); + + const res = await request('/signup', q); + + return res.body; +}; +//#endregion + +describe('API', () => { + // Reset database each test + beforeEach(() => Promise.all([ + db.get('users').drop(), + db.get('posts').drop(), + db.get('driveFiles.files').drop(), + db.get('driveFiles.chunks').drop(), + db.get('driveFolders').drop(), + db.get('apps').drop(), + db.get('accessTokens').drop(), + db.get('authSessions').drop() + ])); + + describe('signup', () => { + it('不正なユーザー名でアカウントが作成できない', async(async () => { + const res = await request('/signup', { + username: 'test.', + password: 'test' + }); + expect(res).to.have.status(400); + })); + + it('空のパスワードでアカウントが作成できない', async(async () => { + const res = await request('/signup', { + username: 'test', + password: '' + }); + expect(res).to.have.status(400); + })); + + it('正しくアカウントが作成できる', async(async () => { + const me = { + username: 'test', + password: 'test' + }; + const res = await request('/signup', me); + expect(res).to.have.status(200); + expect(res.body).be.a('object'); + expect(res.body).have.property('username').eql(me.username); + })); + + it('同じユーザー名のアカウントは作成できない', async(async () => { + await signup({ + username: 'test' + }); + const res = await request('/signup', { + username: 'test', + password: 'test' + }); + expect(res).to.have.status(400); + })); + }); + + describe('signin', () => { + it('間違ったパスワードでサインインできない', async(async () => { + await signup({ + username: 'test', + password: 'foo' + }); + const res = await request('/signin', { + username: 'test', + password: 'bar' + }); + expect(res).to.have.status(403); + })); + + it('クエリをインジェクションできない', async(async () => { + await signup({ + username: 'test' + }); + const res = await request('/signin', { + username: 'test', + password: { + $gt: '' + } + }); + expect(res).to.have.status(400); + })); + + it('正しい情報でサインインできる', async(async () => { + await signup({ + username: 'test', + password: 'foo' + }); + const res = await request('/signin', { + username: 'test', + password: 'foo' + }); + expect(res).to.have.status(204); + })); + }); +}); diff --git a/test/mfm.ts b/test/mfm.ts index f9cb56a00..ad12eac7b 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -1,3 +1,7 @@ +/* + * Tests of MFM + */ + import * as assert from 'assert'; import analyze from '../src/mfm/parse';