Added Jest for testing both front and backend
This commit is contained in:
parent
f4d1e62c13
commit
458735f341
|
@ -22,9 +22,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"jest": true,
|
||||
},
|
||||
"globals": {
|
||||
__DEV__: true,
|
||||
SLACK_KEY: true,
|
||||
SLACK_REDIRECT_URI: true,
|
||||
|
||||
afterAll: true
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// Mock for node-uuid
|
||||
global.console.warn = () => {};
|
|
@ -0,0 +1,7 @@
|
|||
const ctx = {
|
||||
cache: {
|
||||
set: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
export default ctx;
|
|
@ -0,0 +1 @@
|
|||
export default '';
|
|
@ -0,0 +1,2 @@
|
|||
import idObj from 'identity-obj-proxy';
|
||||
export default idObj;
|
|
@ -0,0 +1 @@
|
|||
window.matchMedia = (data) => data;
|
|
@ -0,0 +1,29 @@
|
|||
/* eslint-disable */
|
||||
import React from 'react';
|
||||
import { snap } from 'utils/testUtils';
|
||||
|
||||
import Alert from '.';
|
||||
|
||||
test('renders default as info', () => {
|
||||
snap(<Alert>default</Alert>);
|
||||
});
|
||||
|
||||
test('renders success', () => {
|
||||
snap(<Alert success>success</Alert>);
|
||||
});
|
||||
|
||||
test('renders info', () => {
|
||||
snap(<Alert info>info</Alert>);
|
||||
});
|
||||
|
||||
test('renders warning', () => {
|
||||
snap(<Alert warning>warning</Alert>);
|
||||
});
|
||||
|
||||
test('renders danger', () => {
|
||||
snap(<Alert danger>danger</Alert>);
|
||||
});
|
||||
|
||||
test('renders offline', () => {
|
||||
snap(<Alert offline>offline</Alert>);
|
||||
});
|
|
@ -0,0 +1,113 @@
|
|||
exports[`test renders danger 1`] = `
|
||||
<div
|
||||
className="Flex container danger"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
danger
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`test renders default as info 1`] = `
|
||||
<div
|
||||
className="Flex container info"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
default
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`test renders info 1`] = `
|
||||
<div
|
||||
className="Flex container info"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
info
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`test renders offline 1`] = `
|
||||
<div
|
||||
className="Flex container offline"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
offline
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`test renders success 1`] = `
|
||||
<div
|
||||
className="Flex container success"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
success
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`test renders warning 1`] = `
|
||||
<div
|
||||
className="Flex container warning"
|
||||
style={
|
||||
Object {
|
||||
"WebkitAlignItems": "center",
|
||||
"WebkitJustifyContent": "center",
|
||||
"alignItems": "center",
|
||||
"boxSizing": "border-box",
|
||||
"display": "flex",
|
||||
"justifyContent": "center",
|
||||
"msAlignItems": "center",
|
||||
"msJustifyContent": "center"
|
||||
}
|
||||
}>
|
||||
warning
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,10 @@
|
|||
import renderer from 'react-test-renderer';
|
||||
|
||||
const snap = (children) => {
|
||||
const component = renderer.create(children);
|
||||
expect(component).toMatchSnapshot();
|
||||
};
|
||||
|
||||
export {
|
||||
snap,
|
||||
};
|
46
package.json
46
package.json
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"name": "BeautifulAtlas",
|
||||
"version": "0.0.1",
|
||||
"description": "For writing",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
|
@ -13,7 +12,29 @@
|
|||
"lint": "eslint frontend",
|
||||
"deploy": "git push heroku master",
|
||||
"heroku-postbuild": "npm run build && npm run sequelize db:migrate",
|
||||
"sequelize": "./node_modules/.bin/sequelize"
|
||||
"sequelize": "./node_modules/.bin/sequelize",
|
||||
"test": "npm run test:frontend && npm run test:server",
|
||||
"test:frontend": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:server": "jest --config=server/.jest-config"
|
||||
},
|
||||
"jest": {
|
||||
"verbose": false,
|
||||
"testPathDirs": [
|
||||
"frontend"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^.*[.](s?css|css)$": "<rootDir>/__mocks__/styleMock.js",
|
||||
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js"
|
||||
},
|
||||
"moduleFileExtensions": ["js", "jsx", "json"],
|
||||
"moduleDirectories": ["node_modules", "server"],
|
||||
"modulePaths": [
|
||||
"frontend"
|
||||
],
|
||||
"setupFiles": [
|
||||
"<rootDir>/__mocks__/window.js"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": "6.x"
|
||||
|
@ -22,12 +43,6 @@
|
|||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/jorilallo/atlas.git"
|
||||
},
|
||||
"author": "Jori Lallo",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jorilallo/atlas/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jorilallo/atlas#readme",
|
||||
"dependencies": {
|
||||
"babel-core": "6.13.2",
|
||||
"babel-eslint": "6.1.2",
|
||||
|
@ -99,10 +114,10 @@
|
|||
"query-string": "^4.2.2",
|
||||
"querystring": "0.2.0",
|
||||
"randomstring": "1.1.5",
|
||||
"react": "15.1.0",
|
||||
"react-codemirror": "0.2.5",
|
||||
"react": "15.3.1",
|
||||
"react-codemirror": "0.2.6",
|
||||
"react-dom": "15.1.0",
|
||||
"react-dropzone": "3.3.2",
|
||||
"react-dropzone": "3.6.0",
|
||||
"react-helmet": "3.1.0",
|
||||
"react-keydown": "^1.6.1",
|
||||
"react-router": "2.5.1",
|
||||
|
@ -125,11 +140,16 @@
|
|||
"webpack": "1.13.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "^15.0.0",
|
||||
"fetch-test-server": "^1.1.0",
|
||||
"fsevents": "1.0.14",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"ignore-loader": "0.1.1",
|
||||
"jest-cli": "^15.1.1",
|
||||
"koa-webpack-dev-middleware": "1.2.0",
|
||||
"koa-webpack-hot-middleware": "1.0.3",
|
||||
"node-dev": "3.1.0",
|
||||
"nodemon": "1.9.1"
|
||||
"nodemon": "1.9.1",
|
||||
"react-test-renderer": "^15.3.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"verbose": true,
|
||||
"testPathDirs": [
|
||||
"<rootDir>/server"
|
||||
],
|
||||
"setupFiles": [
|
||||
"<rootDir>/__mocks__/console.js",
|
||||
"./server/test/helper.js"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
exports[`test should require authentication 1`] = `
|
||||
Object {
|
||||
"message": "Authentication required"
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`test should return known user 1`] = `
|
||||
Object {
|
||||
"data": Object {
|
||||
"avatarUrl": "http://example.com/avatar.png",
|
||||
"id": "86fde1d4-0050-428f-9f0b-0bf77f8bdf61",
|
||||
"name": "User 1",
|
||||
"username": "user1"
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -10,8 +10,6 @@ export default function auth({ require = true } = {}) {
|
|||
return async function authMiddleware(ctx, next) {
|
||||
let token;
|
||||
|
||||
console.log(ctx.body);
|
||||
|
||||
const authorizationHeader = ctx.request.get('authorization');
|
||||
if (authorizationHeader) {
|
||||
const parts = authorizationHeader.split(' ');
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import TestServer from 'fetch-test-server';
|
||||
|
||||
import app from '..';
|
||||
import { User } from '../models';
|
||||
|
||||
import { flushdb, seed, sequelize } from '../test/support';
|
||||
|
||||
const server = new TestServer(app.callback());
|
||||
|
||||
beforeEach(seed);
|
||||
afterEach(flushdb);
|
||||
afterAll(() => server.close());
|
||||
afterAll(() => sequelize.close());
|
||||
|
||||
it('should return known user', async () => {
|
||||
const user = await User.findOne({
|
||||
where: {
|
||||
email: 'user1@example.com',
|
||||
},
|
||||
});
|
||||
|
||||
const res = await server.post('/api/user.info', {
|
||||
body: { token: user.getJwtToken() },
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should require authentication', async () => {
|
||||
const res = await server.post('/api/user.info');
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(401);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
|
@ -2,7 +2,7 @@ import crypto from 'crypto';
|
|||
import {
|
||||
DataTypes,
|
||||
sequelize,
|
||||
encryptedFields
|
||||
encryptedFields,
|
||||
} from '../sequelize';
|
||||
|
||||
import JWT from 'jsonwebtoken';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Sequelize from 'sequelize';
|
||||
import _orderBy from 'lodash.orderby';
|
||||
import _ from 'lodash';
|
||||
import { Document, Atlas, User, Revision } from './models';
|
||||
|
||||
export function presentUser(ctx, user) {
|
||||
|
@ -123,7 +123,7 @@ export function presentCollection(ctx, collection, includeRecentDocuments=false)
|
|||
includeCollaborators: true,
|
||||
}));
|
||||
}));
|
||||
data.recentDocuments = _orderBy(recentDocuments, ['updatedAt'], ['desc']);
|
||||
data.recentDocuments = _.orderBy(recentDocuments, ['updatedAt'], ['desc']);
|
||||
}
|
||||
|
||||
resolve(data);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
exports[`test presents a user 1`] = `
|
||||
Object {
|
||||
"avatarUrl": "http://example.com/avatar.png",
|
||||
"id": "123",
|
||||
"name": "Test User",
|
||||
"username": "testuser"
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,15 @@
|
|||
const presentUser = (ctx, user) => {
|
||||
ctx.cache.set(user.id, user);
|
||||
|
||||
return new Promise(async (resolve, _reject) => {
|
||||
const data = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
avatarUrl: user.slackData.image_192,
|
||||
};
|
||||
resolve(data);
|
||||
});
|
||||
};
|
||||
|
||||
export default presentUser;
|
|
@ -0,0 +1,19 @@
|
|||
import presentUser from './user';
|
||||
|
||||
import ctx from '../../__mocks__/ctx';
|
||||
|
||||
it('presents a user', async () => {
|
||||
const user = await presentUser(
|
||||
ctx,
|
||||
{
|
||||
id: '123',
|
||||
name: 'Test User',
|
||||
username: 'testuser',
|
||||
slackData: {
|
||||
image_192: 'http://example.com/avatar.png',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(user).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
require('localenv');
|
||||
|
||||
// test environment variables
|
||||
process.env.DATABASE_URL = process.env.DATABASE_URL_TEST;
|
||||
process.env.NODE_ENV = 'test';
|
||||
|
||||
const Sequelize = require('sequelize');
|
||||
const sequelize = require('../sequelize').sequelize;
|
||||
const Umzug = require('umzug');
|
||||
|
||||
const queryInterface = sequelize.getQueryInterface();
|
||||
|
||||
function runMigrations() {
|
||||
const umzug = new Umzug({
|
||||
storage: 'sequelize',
|
||||
storageOptions: {
|
||||
sequelize,
|
||||
},
|
||||
migrations: {
|
||||
params: [queryInterface, Sequelize],
|
||||
path: './server/migrations',
|
||||
},
|
||||
});
|
||||
umzug.up()
|
||||
.then(() => {
|
||||
sequelize.close();
|
||||
});
|
||||
}
|
||||
|
||||
runMigrations();
|
|
@ -0,0 +1,29 @@
|
|||
import { User } from '../models';
|
||||
import { sequelize } from '../sequelize';
|
||||
|
||||
export function flushdb() {
|
||||
const sql = sequelize.getQueryInterface();
|
||||
const tables = Object.keys(sequelize.models).map((model) =>
|
||||
sql.quoteTable(sequelize.models[model].getTableName()));
|
||||
const query = `TRUNCATE ${tables.join(', ')} CASCADE`;
|
||||
|
||||
return sequelize.query(query);
|
||||
}
|
||||
|
||||
const seed = async () => {
|
||||
await User.create({
|
||||
id: '86fde1d4-0050-428f-9f0b-0bf77f8bdf61',
|
||||
email: 'user1@example.com',
|
||||
username: 'user1',
|
||||
name: 'User 1',
|
||||
slackId: '123',
|
||||
slackData: {
|
||||
image_192: 'http://example.com/avatar.png',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
seed,
|
||||
sequelize,
|
||||
};
|
Reference in New Issue