Skip to content

Commit

Permalink
test: add unit tests for route definitions (#443)
Browse files Browse the repository at this point in the history
* test: add unit tests for route action utils/enhancers

* test: use .at.least() instead of .within()

* test: add unit test for action factory

* fix: give track-perf duration assertions some wiggle room

* test: add unit tests for resource action enhancer and route definition utils

* test: add unit tests for route definitions
  • Loading branch information
zacharygolba authored Oct 10, 2016
1 parent ec18b7a commit c8995a2
Show file tree
Hide file tree
Showing 25 changed files with 694 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* @private
*/
class ControllerMissingError extends Error {
class ControllerMissingError extends ReferenceError {
constructor(resource: string) {
super(`Could not resolve controller by name '${resource}'`);
}
Expand Down
1 change: 0 additions & 1 deletion src/errors/index.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { line } from '../packages/logger';
/**
* @private
*/
class ModuleMissingError extends Error {
class ModuleMissingError extends ReferenceError {
constructor(name: string) {
super(line`
${red(`Could not find required module '${name}'.`)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* @private
*/
class SerializerMissingError extends Error {
class SerializerMissingError extends ReferenceError {
constructor(resource: string) {
super(`Could not resolve serializer by name '${resource}'`);
}
Expand Down
3 changes: 0 additions & 3 deletions src/packages/application/errors/index.js

This file was deleted.

1 change: 0 additions & 1 deletion src/packages/application/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,4 @@ class Application {
}

export default Application;

export type { Application$opts, Application$factoryOpts } from './interfaces';
2 changes: 1 addition & 1 deletion src/packages/application/initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import Router from '../router';
import Server from '../server';
import { build, createLoader } from '../loader';
import { freezeProps, deepFreezeProps } from '../freezeable';
import ControllerMissingError from '../../errors/controller-missing-error';

import { ControllerMissingError } from './errors';
import normalizePort from './utils/normalize-port';
import createController from './utils/create-controller';
import createSerializer from './utils/create-serializer';
Expand Down
7 changes: 3 additions & 4 deletions src/packages/application/utils/create-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,16 @@ export default function createController<T: Controller>(
const instance: T = Reflect.construct(constructor, [{
model,
namespace,
serializer,
serializers
serializer
}]);

if (serializer) {
if (!instance.filter.length) {
instance.filter = [].concat(serializer.attributes);
instance.filter = [...serializer.attributes];
}

if (!instance.sort.length) {
instance.sort = [].concat(serializer.attributes);
instance.sort = [...serializer.attributes];
}
}

Expand Down
14 changes: 11 additions & 3 deletions src/packages/database/model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ class Model {
*/
dirtyAttributes: Set<string>;

/**
* @private
*/
isModelInstance: boolean;

/**
* @private
*/
Expand Down Expand Up @@ -145,21 +150,24 @@ class Model {
enumerable: false,
configurable: false
},

initialValues: {
value: new Map(),
writable: false,
enumerable: false,
configurable: false
},

dirtyAttributes: {
value: new Set(),
writable: false,
enumerable: false,
configurable: false
},

isModelInstance: {
value: true,
writable: false,
enumerable: false,
configurable: false
},
prevAssociations: {
value: new Set(),
writable: false,
Expand Down
2 changes: 1 addition & 1 deletion src/packages/database/relationship/utils/validate-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import isNull from '../../../../utils/is-null';
import type { Model } from '../../index';

function validateOne(model: Class<Model>, value: void | ?mixed) {
return isNull(value) || value instanceof model;
return isNull(value) || model.isInstance(value);
}

export default function validateType(model: Class<Model>, value: mixed) {
Expand Down
2 changes: 1 addition & 1 deletion src/packages/database/utils/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { join as joinPath } from 'path';
import { NODE_ENV, DATABASE_URL } from '../../../constants';
import { VALID_DRIVERS } from '../constants';
import { tryCatchSync } from '../../../utils/try-catch';
import { ModuleMissingError } from '../../../errors';
import { InvalidDriverError } from '../errors';
import ModuleMissingError from '../../../errors/module-missing-error';

/**
* @private
Expand Down
5 changes: 2 additions & 3 deletions src/packages/loader/builder/utils/create-children-builder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @flow
import setType from '../../../../utils/set-type';
import type { Builder$Construct, Builder$ChildrenBuilder } from '../interfaces';

export default function createChildrenBuilder<T>(
Expand All @@ -15,13 +14,13 @@ export default function createChildrenBuilder<T>(
if (parent && normalized.endsWith('application')) {
return [
normalized,
setType(() => constructor)
parent
];
}

return [
normalized,
construct(name, constructor, parent)
construct(normalized, constructor, parent)
];
}));
}
13 changes: 9 additions & 4 deletions src/packages/router/definitions/context/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import Namespace from '../../namespace';
import K from '../../../../utils/k';
import type { Router$Namespace } from '../../index'; // eslint-disable-line max-len, no-unused-vars
import type { Router$DefinitionBuilder } from '../interfaces';
import {
default as ControllerMissingError
} from '../../../../errors/controller-missing-error';

import createDefinitionGroup from './utils/create-definition-group';
import normalizeResourceArgs from './utils/normalize-resource-args';
Expand Down Expand Up @@ -48,10 +51,11 @@ export function contextFor(build: Router$DefinitionBuilder<*>) {

path = isRoot ? `/${name}` : `${path}/${name}`;

let controller = controllers.get(`${path.substr(1)}/application`);
const controllerKey = `${path.substr(1)}/application`;
const controller = controllers.get(controllerKey);

if (!controller) {
controller = namespace.controller;
throw new ControllerMissingError(controllerKey);
}

const child = new Namespace({
Expand All @@ -77,10 +81,11 @@ export function contextFor(build: Router$DefinitionBuilder<*>) {
path = namespace.path + opts.path;
}

let controller = controllers.get(path.substr(1));
const controllerKey = path.substr(1);
const controller = controllers.get(controllerKey);

if (!controller) {
controller = namespace.controller;
throw new ControllerMissingError(controllerKey);
}

const child = new Resource({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Controller$builtIn } from '../../../../controller'; // eslint-disa
*/
export default function normalizeResourceArgs(args: [
string,
?{ path: string, only: Array<Controller$builtIn> },
{ path: string, only: Array<Controller$builtIn> },
Function
]): [{
name: string,
Expand Down
107 changes: 107 additions & 0 deletions src/packages/router/definitions/test/normalize-resource-args.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// @flow
import { expect } from 'chai';
import { it, describe, before } from 'mocha';

import { BUILT_IN_ACTIONS } from '../../../controller';

import normalizeResourceArgs from '../context/utils/normalize-resource-args';

describe('module "router/definitions/context"', () => {
describe('util normalizeResourceArgs()', () => {
it('normalizes arguments with a name only', () => {
// $FlowIgnore
const result = normalizeResourceArgs(['posts']);

expect(result).to.be.an('array');

expect(result)
.to.have.property('0')
.and.deep.equal({
name: 'posts',
path: '/posts',
only: BUILT_IN_ACTIONS
});

expect(result)
.to.have.property('1')
.and.be.a('function');
});

it('normalizes arguments with a name and options', () => {
// $FlowIgnore
const result = normalizeResourceArgs(['posts', {
only: [
'show',
'index'
]
}]);

expect(result).to.be.an('array');

expect(result)
.to.have.property('0')
.and.deep.equal({
name: 'posts',
path: '/posts',
only: [
'show',
'index'
]
});

expect(result)
.to.have.property('1')
.and.be.a('function');
});

it('normalizes arguments with a name and builder', () => {
// $FlowIgnore
const result = normalizeResourceArgs(['posts', function () {
return undefined;
}]);

expect(result).to.be.an('array');

expect(result)
.to.have.property('0')
.and.deep.equal({
name: 'posts',
path: '/posts',
only: BUILT_IN_ACTIONS
});

expect(result)
.to.have.property('1')
.and.be.a('function');
});

it('normalizes arguments with a name, options, and builder', () => {
// $FlowIgnore
const result = normalizeResourceArgs(['posts', {
only: [
'show',
'index'
]
}, function () {
return undefined;
}]);

expect(result).to.be.an('array');

expect(result)
.to.have.property('0')
.and.deep.equal({
name: 'posts',
path: '/posts',
only: [
'show',
'index'
]
});

expect(result)
.to.have.property('1')
.and.be.a('function');
});
});
});
2 changes: 1 addition & 1 deletion src/packages/router/route/action/constants.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// @flow
export const FINAL_HANDLER = '__FINAL__HANDLER__';
export const FINAL_HANDLER = '__FINAL_HANDLER__';
6 changes: 2 additions & 4 deletions src/packages/router/route/action/enhancers/resource.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow
import { Model, Query } from '../../../../database';
import { Query } from '../../../../database';
import { getDomain } from '../../../../server';
import createPageLinks from '../utils/create-page-links';
import type { Action } from '../interfaces';
Expand All @@ -24,17 +24,15 @@ export default function resource(action: Action<any>): Action<any> {
data = await result;
}

if (Array.isArray(data) || data instanceof Model) {
if (Array.isArray(data) || (data && data.isModelInstance)) {
const domain = getDomain(req);

const {
params,

url: {
path,
pathname
},

route: {
controller: {
namespace,
Expand Down
13 changes: 7 additions & 6 deletions src/packages/router/route/action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ export function createAction(
fn = resource(fn);
}

// eslint-disable-next-line no-underscore-dangle
function __FINAL__HANDLER__(req, res) {
return fn(req, res);
}

return [...controller.beforeAction, __FINAL__HANDLER__].map(trackPerf);
return [
...controller.beforeAction,
// eslint-disable-next-line no-underscore-dangle
function __FINAL_HANDLER__(req, res) {
return fn(req, res);
}
].map(trackPerf);
}

export { default as createPageLinks } from './utils/create-page-links';
Expand Down
Loading

0 comments on commit c8995a2

Please sign in to comment.