Skip to content

Commit

Permalink
Test setup (#17)
Browse files Browse the repository at this point in the history
* Added factory package

* Added factories directory to service scaffold

* Added factory to generator

* Added factory to generator

* Added query test to scaffold

* Added meta factory

* Added Database cleaner

* Upgraded obsolete babel versions & config

* Separate app creation logic for testing

* Separate app creation logic for testing

* Separated test from actual code

* Separated test from actual code

* Scaffold test separation

* Added integration test helper

* Added request specs

* Reverted to test in src

* DRY hard coded strings

* Fixed endpoint tests

* Proper setup/teardown for endpoint test

* Fixed content type

* Run test in one thread

* Properly clean up DB

* Flesh out service and endpoint scaffold

* Fix error with endpoint generation

* Release 0.4.0: Integration and unit test with scaffold

* @ctt/apig@0.4.0
  • Loading branch information
Ehbraheem committed Apr 8, 2020
1 parent 2119dc5 commit f2c5ffe
Show file tree
Hide file tree
Showing 25 changed files with 553 additions and 323 deletions.
27 changes: 21 additions & 6 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"extends": "eslint:recommended",
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
],
"parser": "babel-eslint",
"env": {
"node": true,
Expand All @@ -9,18 +12,30 @@
"eslint-plugin-import",
"import",
"jest",
"prettier"
],
"globals": {
"Promise": true,
"sandbox": true
},
"rules": {
"comma-dangle": 0,
"new-cap": [2, {
"capIsNewExceptions": ["Immutable.Map"]
}],
"quotes": [2, "single"],
"new-cap": [
2,
{
"capIsNewExceptions": [
"Immutable.Map"
]
}
],
"quotes": [
2,
"single"
],
"strict": 0,
"import/no-extraneous-dependencies": [error, { devDependencies: true }]
"import/no-extraneous-dependencies": [error,
{ devDependencies: true
}
]
}
}
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"printWidth": 120,
"proseWrap": "preserve",
"singleQuote": true,
"useTabs": false,
"tabWidth": 2,
"arrowParens": "avoid",
"trailingComma": "es5"
}
21 changes: 14 additions & 7 deletions lib/endpoint/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ Object.defineProperty(exports, "__esModule", {
});
exports.generator = exports.questions = undefined;

var _promise = require('babel-runtime/core-js/promise');

var _promise2 = _interopRequireDefault(_promise);

var _extends2 = require('babel-runtime/helpers/extends');

var _extends3 = _interopRequireDefault(_extends2);
Expand All @@ -23,8 +27,6 @@ var _mustache2 = _interopRequireDefault(_mustache);

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _ramda = require('ramda');

var _mkdirp = require('mkdirp');
Expand Down Expand Up @@ -62,7 +64,7 @@ var questions = exports.questions = [{
name: 'destination',
message: 'Endpopint installation destination',
default: function _default() {
return _path2.default.resolve(__dirname, '../', './src');
return (0, _path.resolve)(__dirname, '../', './src');
}
}];

Expand All @@ -76,24 +78,29 @@ var generator = exports.generator = function generator(_ref) {
if (err) throw err;
});

var SCAFFOLD = _path2.default.resolve(__dirname, '../../', 'scaffold/endpoint');
var SCAFFOLD = (0, _path.resolve)(__dirname, '../../', 'scaffold/endpoint');
var TEST = (0, _path.resolve)(__dirname, '../../', 'scaffold/test');
var DEST_DIR = destination;
var TEST_PATH = (0, _path.resolve)(DEST_DIR, '../test');

_mustache2.default.escape = function (v) {
return v;
};

new _scaffoldGenerator2.default({
var scaffold = new _scaffoldGenerator2.default({
data: (0, _extends3.default)({}, (0, _ramda.pickBy)(function (val, key) {
return (0, _ramda.startsWith)('scaffold_', key);
}, (0, _extends3.default)({}, _config2.default, {
scaffold_entities: endpoints,
scaffold_entity: endpoint,
scaffold_entity_capitalise: title
scaffold_entity_capitalise: title,
scaffold_factory: title.toLowerCase()
}))),
ignore: _config2.default.FILES_IGNORE,
render: _mustache2.default.render
}).copy(SCAFFOLD, DEST_DIR).then(function () {
});

_promise2.default.all([scaffold.copy(SCAFFOLD, DEST_DIR), scaffold.copy(TEST, TEST_PATH)]).then(function () {
console.log('done'); // eslint-disable-line no-console
}).catch(function (e) {
console.log(e); // eslint-disable-line no-console
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ctt/apig",
"version": "0.3.5",
"version": "0.4.0",
"description": "A crud-api microservice and endpoint generator",
"main": "bin/apig",
"bin": {
Expand Down Expand Up @@ -79,11 +79,14 @@
"concurrently": "3.5.1",
"coveralls": "3.0.9",
"eslint": "5.3.0",
"eslint-config-prettier": "6.10.1",
"eslint-plugin-import": "2.13.0",
"eslint-plugin-jest": "21.20.2",
"eslint-plugin-prettier": "3.1.2",
"jest": "23.5.0",
"jest-junit": "10.0.0",
"precommit-hook-eslint": "3.0.0"
"precommit-hook-eslint": "3.0.0",
"prettier": "2.0.4"
},
"dependencies": {
"capitalize": "2.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { factory } from 'factory-girl';

import '../../../../test/factories/{{{scaffold_factory}}}';
import queries from './queries'

import { mongooseConnect, dbConfig as config } from '@ctt/crud-api';

let db, {{{scaffold_factory}}}Queries;

describe('{{{scaffold_entity_capitalise}}} queries', () => {
beforeAll(async () => {
db = await mongooseConnect(config);
{{{scaffold_factory}}}Queries = queries(db);
});

afterAll(async () => {
await db.disconnect();
});

describe('create', () => {
it('can create a {{{scaffold_entity_capitalise}}}', async () => {
const payload = await factory.attrs('{{{scaffold_entity_capitalise}}}');

const {{{scaffold_factory}}} = await {{{scaffold_factory}}}Queries.create({ payload });

expect({{{scaffold_factory}}}).toBeDefined()

expect({{{scaffold_factory}}}).toHaveProperty('name')
expect({{{scaffold_factory}}}).toHaveProperty('uuid')
expect({{{scaffold_factory}}}['name']).toEqual(payload['name'])
});

it('cannot create a {{{scaffold_entity_capitalise}}}', async () => {
const payload = await factory.attrs('{{{scaffold_entity_capitalise}}}', { name: undefined });

try {
await expect(
await (async () => {{{scaffold_factory}}}Queries.create({ payload }))(),
).resolves.toThrow();
} catch ({ errors, name, message }) {
expect(name).toBe('ValidationError');
expect(message).toMatch(/`name` is required/);
expect(errors).toHaveProperty('name')
expect(errors['name']['path']).toBe('name');
expect(errors['name']['kind']).toBe('required');
}
})
})
});
59 changes: 42 additions & 17 deletions scaffold/endpoint/{{{scaffold_entities}}}/routes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { http } from '@ctt/service-utils';
import {
makeMetaRequestPayloadSchema,
} from '../utils/schemas';

const {
response: { UNPROCESSABLE_ENTITY, BAD_REQUEST, NOT_FOUND, CREATED, OK, HAL_JSON_TYPE },
} = http;

export const ROUTE_NAME = '{{{scaffold_entities}}}';

const options = {
Expand Down Expand Up @@ -33,7 +38,11 @@ export default ({
headers: makeRequestHeaderSchema(validate),
failAction: async (request, h, err) => {
request.log([err]);
return h.response('BAD REQUEST').code(400).takeover();
return h
.response(BAD_REQUEST.message)
.code(BAD_REQUEST.code)
.type(HAL_JSON_TYPE)
.takeover();
},
payload: makeRequestPayloadSchema(validate)
.requiredKeys(
Expand All @@ -54,11 +63,11 @@ export default ({
.create({
payload: request.payload, config, json
}))
.code(201)
.type('application/hal+json');
.code(CREATED.code)
.type(HAL_JSON_TYPE);
} catch (e) {
request.log([e]);
response = h.response('UNPROCESSABLE ENTITY').code(422);
response = h.response(UNPROCESSABLE_ENTITY.message).code(UNPROCESSABLE_ENTITY.code);
}

return response;
Expand All @@ -76,7 +85,11 @@ export const find{{{scaffold_entity_capitalise}}} = ({
headers: makeRequestHeaderSchema(validate),
failAction: async (request, h, err) => {
request.log([err]);
return h.response('BAD REQUEST').code(400).takeover();
return h
.response(BAD_REQUEST.message)
.code(BAD_REQUEST.code)
.type(HAL_JSON_TYPE)
.takeover();
},
params: {
uuid: validate.string().guid({
Expand All @@ -95,11 +108,11 @@ export const find{{{scaffold_entity_capitalise}}} = ({
try {
response = h.response(await services[ROUTE_NAME]
.findById({ payload, config, json }))
.code(200)
.type('application/hal+json');
.code(OK.code)
.type(HAL_JSON_TYPE);
} catch (e) {
request.log([e]);
response = h.response('NOT FOUND').code(404);
response = h.response(NOT_FOUND.message).code(NOT_FOUND.code);
}

return response;
Expand All @@ -117,7 +130,11 @@ export const findAll{{{scaffold_entity_capitalise}}}s = ({
headers: makeRequestHeaderSchema(validate),
failAction: async (request, h, err) => {
request.log([err]);
return h.response('BAD REQUEST').code(400).takeover();
return h
.response(BAD_REQUEST.message)
.code(BAD_REQUEST.code)
.type(HAL_JSON_TYPE)
.takeover();
},
params: {
pageid: validate.number().integer().min(1),
Expand Down Expand Up @@ -146,11 +163,11 @@ export const findAll{{{scaffold_entity_capitalise}}}s = ({
try {
response = h.response(await services[ROUTE_NAME]
.findAll({ payload, config, json }))
.code(200)
.type('application/hal+json');
.code(OK.code)
.type(HAL_JSON_TYPE);
} catch (e) {
request.log([e]);
response = h.response('NOT FOUND').code(404);
response = h.response(NOT_FOUND.message).code(NOT_FOUND.code);
}

return response;
Expand All @@ -168,7 +185,11 @@ export const remove{{{scaffold_entity_capitalise}}} = ({
headers: makeRequestHeaderSchema(validate),
failAction: async (request, h, err) => {
request.log([err]);
return h.response('BAD REQUEST').code(400).takeover();
return h
.response(BAD_REQUEST.message)
.code(BAD_REQUEST.code)
.type(HAL_JSON_TYPE)
.takeover();
},
params: {
uuid: validate.string().guid({
Expand All @@ -189,7 +210,7 @@ export const remove{{{scaffold_entity_capitalise}}} = ({
.removeById({ payload, config, json }))
.code(204);
} catch (e) {
response = h.response('UNPROCESSABLE ENTITY').code(422);
response = h.response(UNPROCESSABLE_ENTITY.message).code(UNPROCESSABLE_ENTITY.code);
}

return response;
Expand All @@ -207,7 +228,11 @@ export const update{{{scaffold_entity_capitalise}}} = ({
headers: makeRequestHeaderSchema(validate),
failAction: async (request, h, err) => {
request.log([err]);
return h.response('BAD REQUEST').code(400).takeover();
return h
.response(BAD_REQUEST.message)
.code(BAD_REQUEST.code)
.type(HAL_JSON_TYPE)
.takeover();
},
params: {
uuid: validate.string().guid({
Expand All @@ -230,10 +255,10 @@ export const update{{{scaffold_entity_capitalise}}} = ({
try {
response = h.response(await services[ROUTE_NAME]
.updateById({ payload, config, json }))
.code(200);
.code(OK.code);
} catch (e) {
request.log([e]);
response = h.response('UNPROCESSABLE ENTITY').code(422);
response = h.response(UNPROCESSABLE_ENTITY.message).code(UNPROCESSABLE_ENTITY.code);
}

return response;
Expand Down
Loading

0 comments on commit f2c5ffe

Please sign in to comment.