miter
Version:
A typescript web framework based on ExpressJs based loosely on SailsJs
854 lines • 65.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const sinon = require("sinon");
const sinonChai = require("sinon-chai");
chai_1.use(sinonChai);
const crud_controller_1 = require("../crud-controller");
const fake_db_1 = require("../../core/test/fake-db");
const fake_request_1 = require("../../router/test/fake-request");
const fake_response_1 = require("../../router/test/fake-response");
const http_status_type_1 = require("../../util/http-status-type");
let any = sinon.match.any;
class TestModel {
}
class TestCrudController extends crud_controller_1.CrudController {
constructor(pluralName, singularName) {
super(TestModel, `TestModel`, pluralName, singularName);
}
}
describe('CrudController', () => {
let inst;
beforeEach(() => {
inst = new TestCrudController();
TestModel.db = new fake_db_1.FakeDb();
});
describe('.ctor', () => {
it('should create the singular name from the model name if one is not provided', () => {
chai_1.expect(inst.singularName).to.eq(`test-model`);
});
it('should use the provided singular name if one is provided', () => {
let inst = new TestCrudController(undefined, 'my-singular-name');
chai_1.expect(inst.singularName).to.eq(`my-singular-name`);
});
it('should create the plural name from the model name if one is not provided', () => {
chai_1.expect(inst.pluralName).to.eq(`test-models`);
});
it('should use the provided plural name if one is provided', () => {
let inst = new TestCrudController('my-plural-name');
chai_1.expect(inst.pluralName).to.eq(`my-plural-name`);
});
});
describe('.splitOnWords', () => {
let splitOnWords;
beforeEach(() => {
splitOnWords = inst.splitOnWords.bind(inst);
});
it('should yield an empty sequence on an empty input', () => {
chai_1.expect([...splitOnWords('')]).to.deep.eq([]);
});
it('should consider an uppercase letter the start of a new word', () => {
chai_1.expect([...splitOnWords('ABCdeF')]).to.deep.eq(['A', 'B', 'Cde', 'F']);
});
it('should consider an underscore the start of a new word', () => {
chai_1.expect([...splitOnWords('what_about_fish')]).to.deep.eq(['what', 'about', 'fish']);
});
it('should remove all underscores', () => {
chai_1.expect([...splitOnWords('___a_very___ODD_model_name____')]).to.deep.eq(['a', 'very', 'O', 'D', 'D', 'model', 'name']);
});
});
describe('.getSingularPath', () => {
let getSingularPath;
beforeEach(() => {
getSingularPath = inst.getSingularPath.bind(inst);
});
it('should return the input string if words cannot be parsed from it', () => {
chai_1.expect(getSingularPath('')).to.eq('');
chai_1.expect(getSingularPath('___')).to.eq('___');
});
it('should singularize the last word', () => {
chai_1.expect(getSingularPath('apples')).to.eq('apple');
chai_1.expect(getSingularPath('dog_orange_apples')).to.eq('dog-orange-apple');
});
it('should not modify any but the last word', () => {
chai_1.expect(getSingularPath('dogs_oranges_apples')).to.eq('dogs-oranges-apple');
});
it('should join the words using dashes', () => {
chai_1.expect(getSingularPath('ABCDE')).to.eq('a-b-c-d-e');
});
it('should transform all letters to lowercase', () => {
chai_1.expect(getSingularPath('YellowBrickRoad')).to.eq('yellow-brick-road');
});
});
describe('.getPluralPath', () => {
let getPluralPath;
beforeEach(() => {
getPluralPath = inst.getPluralPath.bind(inst);
});
it('should return the input string if words cannot be parsed from it', () => {
chai_1.expect(getPluralPath('')).to.eq('');
chai_1.expect(getPluralPath('___')).to.eq('___');
});
it('should pluralize the last word', () => {
chai_1.expect(getPluralPath('apple')).to.eq('apples');
chai_1.expect(getPluralPath('dogs_oranges_apple')).to.eq('dogs-oranges-apples');
});
it('should not modify any but the last word', () => {
chai_1.expect(getPluralPath('dog_orange_apple')).to.eq('dog-orange-apples');
});
it('should join the words using dashes', () => {
chai_1.expect(getPluralPath('ABCDQueue')).to.eq('a-b-c-d-queues');
});
it('should transform all letters to lowercase', () => {
chai_1.expect(getPluralPath('YellowBrickRoad')).to.eq('yellow-brick-roads');
});
});
describe('.transformRoutePathPart', () => {
it('should replace %%PLURAL_NAME%% with the plural route path', () => {
chai_1.expect(inst.transformRoutePathPart('blah', `one/%%PLURAL_NAME%%/three`)).to.eq(`one/${inst.pluralName}/three`);
});
it('should replace %%SINGULAR_NAME%% with the singular route path', () => {
chai_1.expect(inst.transformRoutePathPart('blah', `one/%%SINGULAR_NAME%%/three`)).to.eq(`one/${inst.singularName}/three`);
});
it('should replace all instances of both route paths', () => {
chai_1.expect(inst.transformRoutePathPart('blah', `one/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/%%SINGULAR_NAME%%/%%PLURAL_NAME%%/three`))
.to.eq(`one/${inst.singularName}/${inst.pluralName}/${inst.singularName}/${inst.pluralName}/three`);
});
});
describe('.transformRoutePolicies', () => {
let routes = [
['destroy', 'getDestroyPolicies'],
['create', 'getCreatePolicies'],
['update', 'getMutatePolicies'],
['get', 'getReadPolicies'],
['find', 'getQueryPolicies'],
['count', 'getQueryPolicies'],
['', '']
];
let defaultPolicy = Symbol();
let extraPolicy = Symbol();
routes.forEach(([routeFnName, extraPolicyFnName]) => {
describe(`when transforming policies for ${routeFnName ? 'the \'' + routeFnName + '\'' : 'any other'} route`, () => {
let stub = null;
beforeEach(() => {
if (extraPolicyFnName)
stub = sinon.stub(inst, extraPolicyFnName).returns([extraPolicy]);
});
afterEach(() => {
if (stub)
stub.restore();
});
it('should include the policies passed in', () => {
let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
chai_1.expect(policies.indexOf(defaultPolicy)).not.to.eq(-1);
});
if (extraPolicyFnName) {
it(`should include the policies from ${extraPolicyFnName}`, () => {
let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
chai_1.expect(policies.indexOf(extraPolicy)).not.to.eq(-1);
});
}
else {
it(`should not include any other policies`, () => {
let policies = inst.transformRoutePolicies(routeFnName || 'zzyzx', `one/two/three`, [defaultPolicy]);
chai_1.expect(policies.length).to.eq(1);
});
}
});
});
});
describe('create', () => {
describe('.create', () => {
let req;
let res;
let payload = Symbol();
beforeEach(() => {
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.body = payload;
req.path = 'user/create';
});
it('should return a promise', () => {
let result = inst.create();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should invoke transformCreateQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformCreateQuery');
yield inst.create(req, res);
chai_1.expect(inst.transformCreateQuery).to.have.been.calledOnce;
}));
it('should use the original create query if transformCreateQuery returns a falsey value', () => __awaiter(this, void 0, void 0, function* () {
sinon.spy(inst, 'performCreate');
sinon.stub(inst, 'transformCreateQuery').returns(undefined);
yield inst.create(req, res);
chai_1.expect(inst.performCreate).to.have.been.calledOnce.calledWith(req, res, payload);
}));
it('should use the transformed query returned by transformCreateQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.spy(inst, 'performCreate');
let newPayload = Symbol();
sinon.stub(inst, 'transformCreateQuery').returns(newPayload);
yield inst.create(req, res);
chai_1.expect(inst.performCreate).to.have.been.calledOnce.calledWith(req, res, newPayload);
}));
it('should short circuit if transformCreateQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'beforeCreate');
sinon.stub(inst, 'transformCreateQuery').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.create(req, res);
chai_1.expect(inst.beforeCreate).not.to.have.been.called;
}));
it('should send HTTP_STATUS_ERROR if there is no create query', () => __awaiter(this, void 0, void 0, function* () {
delete req.body;
yield inst.create(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should throw an error if the create body is an array', () => __awaiter(this, void 0, void 0, function* () {
req.body = [{}, {}];
try {
yield inst.create(req, res);
}
catch (e) {
if (e instanceof Error && e.message.match(/createMany not supported/i))
return;
}
chai_1.expect(false).to.be.true;
}));
it('should invoke beforeCreate', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'beforeCreate');
yield inst.create(req, res);
chai_1.expect(inst.beforeCreate).to.have.been.calledOnce;
}));
it('should short circuit if beforeCreate sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'beforeCreate').callsFake((req, res) => {
res.status(123).send('FISH');
});
sinon.stub(inst, 'performCreate');
yield inst.create(req, res);
chai_1.expect(inst.performCreate).not.to.have.been.called;
}));
it('should invoke performCreate', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'performCreate');
yield inst.create(req, res);
chai_1.expect(inst.performCreate).to.have.been.calledOnce;
}));
it('should short circuit if performCreate sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'performCreate').callsFake((req, res) => {
res.status(123).send('FISH');
});
sinon.stub(inst, 'transformCreateResult');
yield inst.create(req, res);
chai_1.expect(inst.transformCreateResult).not.to.have.been.called;
}));
it('should invoke transformCreateResult', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformCreateResult');
yield inst.create(req, res);
chai_1.expect(inst.transformCreateResult).to.have.been.calledOnce;
}));
it('should short circuit if transformCreateResult sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformCreateResult').callsFake((req, res) => {
res.status(123).send('FISH');
});
sinon.stub(inst, 'afterCreate');
yield inst.create(req, res);
chai_1.expect(inst.afterCreate).not.to.have.been.called;
}));
it('should invoke afterCreate', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'afterCreate');
yield inst.create(req, res);
chai_1.expect(inst.afterCreate).to.have.been.calledOnce;
}));
it('should short circuit if afterCreate sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'afterCreate').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.create(req, res);
chai_1.expect(res.statusCode).to.eq(123);
}));
it('should send HTTP_STATUS_OK with the value returned by transformCreateResult', () => __awaiter(this, void 0, void 0, function* () {
sinon.spy(res, 'status');
sinon.spy(res, 'json');
let expectedResult = Symbol();
sinon.stub(inst, 'transformCreateResult').returns(expectedResult);
yield inst.create(req, res);
chai_1.expect(res.status).to.have.been.calledOnce.calledWith(http_status_type_1.HTTP_STATUS_OK);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(expectedResult);
}));
});
});
describe('.beforeCreate', () => {
it('should return a promise', () => {
let result = inst.beforeCreate();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve', () => __awaiter(this, void 0, void 0, function* () {
yield inst.beforeCreate(void (0), void (0), 42, {});
}));
});
});
describe('.afterCreate', () => {
it('should return a promise', () => {
let result = inst.afterCreate();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve', () => __awaiter(this, void 0, void 0, function* () {
yield inst.afterCreate(void (0), void (0), 42, {});
}));
});
});
describe('.transformCreateQuery', () => {
it('should return a promise', () => {
let result = inst.transformCreateQuery();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the original passed-in query', () => __awaiter(this, void 0, void 0, function* () {
let query = Symbol();
let promise = inst.transformCreateQuery(void (0), void (0), query);
let result = yield promise;
chai_1.expect(result).to.eq(query);
}));
});
});
describe('.performCreate', () => {
it('should return a promise', () => {
let result = inst.performCreate();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the results of querying the model DB', () => __awaiter(this, void 0, void 0, function* () {
let data = Symbol();
let expectedResult = Symbol();
sinon.stub(TestModel.db, 'create').returns(Promise.resolve(expectedResult));
let promise = inst.performCreate(void (0), void (0), data);
let result = yield promise;
chai_1.expect(result).to.eq(expectedResult);
}));
});
});
describe('.transformCreateResult', () => {
it('should return a promise', () => {
let result = inst.transformCreateResult();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the original passed-in result', () => __awaiter(this, void 0, void 0, function* () {
let origResult = Symbol();
let promise = inst.transformCreateResult(void (0), void (0), origResult);
let result = yield promise;
chai_1.expect(result).to.eq(origResult);
}));
});
});
});
describe('read', () => {
describe('.find', () => {
it('should return a promise', () => {
let result = inst.find();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
let req;
let res;
let payload;
let performQueryStub;
beforeEach(() => {
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.query.query = JSON.stringify(payload = { column: 'POISSON' });
req.path = 'users/find';
performQueryStub = sinon.stub(inst, 'performQuery').returns({ results: [1, 2, 3], count: 3 });
});
it('should send HTTP_STATUS_ERROR if there is an error parsing request params', () => __awaiter(this, void 0, void 0, function* () {
req.query.query = '{Sdf38--s=-?';
yield inst.find(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should use the include array from the query if there is no standalone include array', () => __awaiter(this, void 0, void 0, function* () {
let expectedInclude = ['one', 'deux', 'tres'];
req.query.query = JSON.stringify({ column: 'POISSON', include: expectedInclude });
sinon.stub(inst, 'transformInclude');
yield inst.find(req, res);
chai_1.expect(inst.transformInclude).to.have.been.calledOnce.calledWith(req, res, expectedInclude);
}));
it('should use the order array from the query if there is no standalone order array', () => __awaiter(this, void 0, void 0, function* () {
let expectedOrder = [['one', 'ASC'], ['deux', 'DESC'], ['tres', 'ASC']];
req.query.query = JSON.stringify({ column: 'POISSON', order: expectedOrder });
yield inst.find(req, res);
let actualOrder;
chai_1.expect(performQueryStub).to.have.been.calledOnce.calledWith(any, any, sinon.match.has('order', sinon.match((val) => actualOrder = val)));
chai_1.expect(actualOrder).to.deep.eq(expectedOrder);
}));
it('should use the standalone include array if it exists', () => __awaiter(this, void 0, void 0, function* () {
let expectedInclude = ['one', 'deux', 'tres'];
req.query.include = JSON.stringify(expectedInclude);
sinon.stub(inst, 'transformInclude');
yield inst.find(req, res);
chai_1.expect(inst.transformInclude).to.have.been.calledOnce.calledWith(req, res, expectedInclude);
}));
it('should use the standalone order array if it exists', () => __awaiter(this, void 0, void 0, function* () {
let expectedOrder = [['one', 'ASC'], ['deux', 'DESC'], ['tres', 'ASC']];
req.query.order = JSON.stringify(expectedOrder);
yield inst.find(req, res);
let actualOrder;
chai_1.expect(performQueryStub).to.have.been.calledOnce.calledWith(any, any, sinon.match.has('order', sinon.match((val) => actualOrder = val)));
chai_1.expect(actualOrder).to.deep.eq(expectedOrder);
}));
it('should invoke transformQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformQuery');
yield inst.find(req, res);
chai_1.expect(inst.transformQuery).to.have.been.calledOnce;
}));
it('should use the original query if transformQuery returns a falsey value', () => __awaiter(this, void 0, void 0, function* () {
let actualQuery;
sinon.stub(inst, 'transformQuery').callsFake((req, res, query) => (actualQuery = query, undefined));
yield inst.find(req, res);
chai_1.expect(inst.performQuery).to.have.been.calledOnce.calledWith(any, any, sinon.match.has('where', actualQuery));
}));
it('should short circuit if transformQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformInclude');
sinon.stub(inst, 'transformQuery').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(inst.transformInclude).not.to.have.been.called;
}));
it('should invoke transformInclude', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformInclude');
yield inst.find(req, res);
chai_1.expect(inst.transformInclude).to.have.been.calledOnce;
}));
it('should use the original include array if transformInclude returns a falsey value', () => __awaiter(this, void 0, void 0, function* () {
let actualInclude;
sinon.stub(inst, 'transformInclude').callsFake((req, res, include) => (actualInclude = include, undefined));
yield inst.find(req, res);
chai_1.expect(inst.performQuery).to.have.been.calledOnce.calledWith(any, any, sinon.match.has('include', actualInclude));
}));
it('should short circuit if transformInclude sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformInclude').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(inst.performQuery).not.to.have.been.called;
}));
describe('when the query is a find-one query', () => {
beforeEach(() => {
req.path = req.path.replace(/find$/, 'find-one');
});
it('should invoke performFindOneQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'performFindOneQuery');
yield inst.find(req, res);
chai_1.expect(inst.performFindOneQuery).to.have.been.calledOnce;
}));
it('should short circuit if performFindOneQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformResult');
sinon.stub(inst, 'performFindOneQuery').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(inst.transformResult).not.to.have.been.called;
}));
it('should invoke transformResult', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformResult');
yield inst.find(req, res);
chai_1.expect(inst.transformResult).to.have.been.calledOnce;
}));
it('should short circuit if transformResult sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformResult').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(res.statusCode).to.eq(123);
}));
it('should send HTTP_STATUS_OK with the value returned by transformResult', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(res, 'json');
let expectedResult = Symbol();
sinon.stub(inst, 'transformResult').returns(expectedResult);
yield inst.find(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_OK);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(expectedResult);
}));
});
describe('when the query is a find-many query', () => {
it('should default to page 0 with 10 items per page', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(res, 'json');
yield inst.find(req, res);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(sinon.match.has('perPage', 10).and(sinon.match.has('page', 0)));
}));
it('should use the page and per-page values included in the query, if they exist', () => __awaiter(this, void 0, void 0, function* () {
[req.query.perPage, req.query.page] = ['14', '12'];
sinon.stub(res, 'json');
yield inst.find(req, res);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(sinon.match.has('perPage', 14).and(sinon.match.has('page', 12)));
}));
it('should invoke performQuery', () => __awaiter(this, void 0, void 0, function* () {
yield inst.find(req, res);
chai_1.expect(inst.performQuery).to.have.been.calledOnce;
}));
it('should short circuit if performQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformQueryResults');
performQueryStub.callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(inst.transformQueryResults).not.to.have.been.called;
}));
it('should invoke transformQueryResults', () => __awaiter(this, void 0, void 0, function* () {
sinon.spy(inst, 'transformQueryResults');
yield inst.find(req, res);
chai_1.expect(inst.transformQueryResults).to.have.been.calledOnce;
}));
it('should short circuit if transformQueryResults sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformQueryResults').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(res.statusCode).to.eq(123);
}));
it('should send HTTP_STATUS_OK with the value returned by transformQueryResults', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(res, 'json');
let expectedResult = { results: [1, 2, 3], count: 3 };
sinon.stub(inst, 'transformQueryResults').returns(expectedResult);
yield inst.find(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_OK);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(sinon.match.has('results', expectedResult.results).and(sinon.match.has('total', expectedResult.count)));
}));
});
});
});
describe('.count', () => {
it('should return a promise', () => {
let result = inst.count();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
let req;
let res;
let payload;
beforeEach(() => {
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.query.query = JSON.stringify(payload = { column: 'POISSON' });
req.path = 'users/count';
});
it('should send HTTP_STATUS_ERROR if there is an error parsing request params', () => __awaiter(this, void 0, void 0, function* () {
req.query.query = '{Sdf38--s=-?';
yield inst.count(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should invoke transformQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformQuery');
yield inst.count(req, res);
chai_1.expect(inst.transformQuery).to.have.been.calledOnce;
}));
it('should use the original query if transformQuery returns a falsey value', () => __awaiter(this, void 0, void 0, function* () {
let actualQuery;
sinon.stub(inst, 'transformQuery').callsFake((req, res, query) => (actualQuery = query, undefined));
sinon.stub(TestModel.db, 'count');
yield inst.count(req, res);
chai_1.expect(TestModel.db.count).to.have.been.calledOnce.calledWith(sinon.match.has('where', actualQuery));
}));
it('should short circuit if transformQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(TestModel.db, 'count');
sinon.stub(inst, 'transformQuery').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.find(req, res);
chai_1.expect(TestModel.db.count).not.to.have.been.called;
}));
it('should invoke db.count', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(TestModel.db, 'count');
yield inst.count(req, res);
chai_1.expect(TestModel.db.count).to.have.been.calledOnce;
}));
it('should send HTTP_STATUS_OK with the value returned by db.count', () => __awaiter(this, void 0, void 0, function* () {
let expectedCount = 42;
sinon.stub(TestModel.db, 'count').returns(expectedCount);
sinon.stub(res, 'send');
yield inst.count(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_OK);
chai_1.expect(res.send).to.have.been.calledOnce.calledWith(`${expectedCount}`);
}));
});
});
describe('.get', () => {
it('should return a promise', () => {
let result = inst.get();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
let req;
let res;
let payload;
beforeEach(() => {
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.path = 'user/42';
req.params.id = `42`;
});
it('should send HTTP_STATUS_ERROR if the ID is missing or invalid', () => __awaiter(this, void 0, void 0, function* () {
req.params.id = '';
yield inst.get(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should send HTTP_STATUS_ERROR if there is an error parsing the include query', () => __awaiter(this, void 0, void 0, function* () {
req.query.include = '{Sdf38--s=-?';
yield inst.get(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should invoke transformInclude', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformInclude');
yield inst.get(req, res);
chai_1.expect(inst.transformInclude).to.have.been.calledOnce;
}));
it('should use the standalone include array if it exists', () => __awaiter(this, void 0, void 0, function* () {
let expectedInclude = ['one', 'deux', 'tres'];
req.query.include = JSON.stringify(expectedInclude);
sinon.stub(inst, 'transformInclude');
yield inst.get(req, res);
chai_1.expect(inst.transformInclude).to.have.been.calledOnce.calledWith(req, res, expectedInclude);
}));
it('should short circuit if transformInclude sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(TestModel.db, 'findById');
sinon.stub(inst, 'transformInclude').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.get(req, res);
chai_1.expect(TestModel.db.findById).not.to.have.been.called;
}));
it('should invoke db.findById with the model ID', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(TestModel.db, 'findById');
yield inst.get(req, res);
chai_1.expect(TestModel.db.findById).to.have.been.calledOnce.calledWith(+req.params.id);
}));
it('should invoke transformResult', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformResult');
yield inst.get(req, res);
chai_1.expect(inst.transformResult).to.have.been.calledOnce;
}));
it('should short circuit if transformResult sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformResult').callsFake((req, res) => {
res.status(123).send('FISH');
});
yield inst.get(req, res);
chai_1.expect(res.statusCode).to.eq(123);
}));
it('should send HTTP_STATUS_OK with the value returned by transformResult', () => __awaiter(this, void 0, void 0, function* () {
let expectedResult = Symbol();
sinon.stub(res, 'json');
sinon.stub(inst, 'transformResult').returns(expectedResult);
yield inst.get(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_OK);
chai_1.expect(res.json).to.have.been.calledOnce.calledWith(expectedResult);
}));
});
});
describe('.transformQuery', () => {
it('should return a promise', () => {
let result = inst.transformQuery();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the original passed-in query', () => __awaiter(this, void 0, void 0, function* () {
let query = Symbol();
let promise = inst.transformQuery(void (0), void (0), query);
let result = yield promise;
chai_1.expect(result).to.eq(query);
}));
});
});
describe('.transformInclude', () => {
it('should return a promise', () => {
let result = inst.transformInclude();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the original passed-in include or to undefined', () => __awaiter(this, void 0, void 0, function* () {
let include = Symbol();
let promise = inst.transformInclude(void (0), void (0), include);
let result = yield promise;
chai_1.expect(typeof result === 'undefined' || result === include).to.be.true;
}));
});
});
describe('.performQuery', () => {
it('should return a promise', () => {
let result = inst.performQuery();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the results of querying the model DB', () => __awaiter(this, void 0, void 0, function* () {
let query = Symbol();
let expectedResult = Symbol();
sinon.stub(TestModel.db, 'findAndCountAll').returns(Promise.resolve(expectedResult));
let promise = inst.performQuery(void (0), void (0), query);
let result = yield promise;
chai_1.expect(result).to.eq(expectedResult);
}));
});
});
describe('.performFindOneQuery', () => {
it('should return a promise', () => {
let result = inst.performFindOneQuery();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the results of querying the model DB', () => __awaiter(this, void 0, void 0, function* () {
let query = Symbol();
let expectedResult = Symbol();
sinon.stub(TestModel.db, 'findOne').returns(Promise.resolve(expectedResult));
let promise = inst.performFindOneQuery(void (0), void (0), query);
let result = yield promise;
chai_1.expect(result).to.eq(expectedResult);
}));
});
});
describe('.transformQueryResults', () => {
let transformQueryResults;
let req;
let res;
let payload = Symbol();
beforeEach(() => {
transformQueryResults = inst.transformQueryResults.bind(inst);
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.body = payload;
});
it('should return a promise', () => {
let result = transformQueryResults(req, res, { results: [], count: 0 });
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should call transformResult on each result', () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult');
yield transformQueryResults(req, res, { results: results, count: results.length });
chai_1.expect(trStub.callCount).to.eq(results.length);
}));
it('should not include results that are removed by transformResult', () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult').callsFake((req, res, val) => val % 2 === 0 ? val : undefined);
let finalResults = yield transformQueryResults(req, res, { results: results, count: results.length });
chai_1.expect(finalResults.results).to.deep.eq([2, 4, 6]);
}));
it('should change the result count if any results are trimmed', () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult').callsFake((req, res, val) => val % 2 === 0 ? val : undefined);
let finalResults = yield transformQueryResults(req, res, { results: results, count: results.length });
chai_1.expect(finalResults.count).to.eq(3);
}));
it(`should return the original result's 'total' if it is defined but 'count' is not`, () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult').callThrough();
let finalResults = yield transformQueryResults(req, res, { results: results, total: 42 });
chai_1.expect(finalResults.count).to.eq(42);
}));
it(`should return length of the results array as 'count' if neither 'count' nor 'total' is defined`, () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult').callThrough();
let finalResults = yield transformQueryResults(req, res, { results: results });
chai_1.expect(finalResults.count).to.eq(results.length);
}));
it('should short circuit if transformResult sets a new status code or sends headers', () => __awaiter(this, void 0, void 0, function* () {
let results = [1, 2, 3, 4, 5, 6];
let trStub = sinon.stub(inst, 'transformResult').callsFake((req, res) => {
res.status(123).send('FISH');
});
let finalResults = yield transformQueryResults(req, res, { results: results, count: results.length });
chai_1.expect(trStub.callCount).to.eq(1);
chai_1.expect(finalResults).not.to.be.ok;
}));
});
});
describe('.transformResult', () => {
it('should return a promise', () => {
let result = inst.transformResult();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
it('should resolve to the original passed-in result', () => __awaiter(this, void 0, void 0, function* () {
let origResult = Symbol();
let promise = inst.transformResult(void (0), void (0), origResult);
let result = yield promise;
chai_1.expect(result).to.eq(origResult);
}));
});
});
});
describe('update', () => {
describe('.update', () => {
it('should return a promise', () => {
let result = inst.update();
chai_1.expect(result).to.be.an.instanceOf(Promise);
});
describe('that promise', () => {
let req;
let res;
let payload;
let performUpdateStub;
beforeEach(() => {
req = fake_request_1.FakeRequest();
res = fake_response_1.FakeResponse();
req.body = payload = { column: 'POISSON' };
req.path = 'user/42';
req.params.id = `42`;
performUpdateStub = sinon.stub(inst, 'performUpdate').returns([true, [{}]]);
});
it('should send HTTP_STATUS_ERROR if the ID is missing or invalid', () => __awaiter(this, void 0, void 0, function* () {
req.params.id = '';
yield inst.update(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should invoke transformUpdateQuery', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformUpdateQuery');
yield inst.update(req, res);
chai_1.expect(inst.transformUpdateQuery).to.have.been.calledOnce;
}));
it('should use the original update query if transformUpdateQuery returns a falsey value', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformUpdateQuery').returns(undefined);
yield inst.update(req, res);
chai_1.expect(inst.performUpdate).to.have.been.calledWith(any, any, +req.params.id, payload);
}));
it('should short circuit if transformUpdateQuery sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'transformUpdateQuery').callsFake((req, res) => {
res.status(123).send(`C'est le meme`);
});
sinon.stub(inst, 'beforeUpdate');
yield inst.update(req, res);
chai_1.expect(inst.beforeUpdate).not.to.have.been.called;
}));
it('should send HTTP_STATUS_ERROR if there is no update query', () => __awaiter(this, void 0, void 0, function* () {
req.body = undefined;
yield inst.update(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should send HTTP_STATUS_ERROR if there is an invalid returning query param', () => __awaiter(this, void 0, void 0, function* () {
req.query.returning = 'FISH and CHIPS';
yield inst.update(req, res);
chai_1.expect(res.statusCode).to.eq(http_status_type_1.HTTP_STATUS_ERROR);
}));
it('should invoke beforeUpdate', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'beforeUpdate');
yield inst.update(req, res);
chai_1.expect(inst.beforeUpdate).to.have.been.calledOnce;
}));
it('should short circuit if beforeUpdate sends a response', () => __awaiter(this, void 0, void 0, function* () {
sinon.stub(inst, 'beforeUpdate').callsFake((req, res) => {
res.status(123).send('Quoi?');
});
yield inst.update(req, res);
chai_1.expect(performUpdateStub).not.to.have.been.called;
}));
it('should invoke performUpdate', () => __awaiter(this, void 0, void 0, function* () {
yield