UNPKG

miter

Version:

A typescript web framework based on ExpressJs based loosely on SailsJs

854 lines 65.2 kB
"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