trivialmodels
Version:
A trivial javascript model system, designed to be easy to build backends for.
451 lines (378 loc) • 15.3 kB
JavaScript
// ---------------------------------------------------------------------------------------------------------------------
// Unit Tests for the types.spec.js module.
//
// @module types.spec.js
// ---------------------------------------------------------------------------------------------------------------------
var _ = require('lodash');
var expect = require('chai').expect;
var types = require('../../src/lib/types').default;
var errors = require('../../src/lib/errors').default;
// ---------------------------------------------------------------------------------------------------------------------
describe('Types', () =>
{
var inst;
var BaseType, StringType, NumberType, BooleanType, DateType, ObjectType, ArrayType, EnumType, AnyType;
beforeEach(() =>
{
BaseType = new types.Base();
StringType = new types.String();
NumberType = new types.Number();
BooleanType = new types.Boolean();
DateType = new types.Date();
ObjectType = new types.Object();
ArrayType = new types.Array();
EnumType = new types.Enum({ values: ['foo', 'bar'] });
AnyType = new types.Any();
inst = { $values: { test: { foo: 123} } };
});
it('has property `$isType` equal to true', () =>
{
expect(BaseType.$isType).to.equal(true);
});
it('can be converted to a string', () =>
{
expect(BaseType.toString()).to.equal('BaseType');
});
describe('BaseType', () =>
{
it('casts to the string \'BaseType\'', () =>
{
expect(BaseType.toString()).to.equal('BaseType');
});
describe('#get()', () =>
{
it('retrieves the value from the model instance', () =>
{
var val = BaseType.get(inst, 'test');
expect(val).to.deep.equal(inst.$values.test);
});
it('returns the default when the value is undefined', () =>
{
inst = { $values: { test2: false } };
var test = { foo: 123 };
BaseType = new types.Base({ default: test });
var val = BaseType.get(inst, 'test');
var val2 = BaseType.get(inst, 'test2');
expect(val).to.deep.equal(test);
expect(val2).to.not.deep.equal(test);
});
});
describe('#set()', () =>
{
it('sets the value on the model instance', () =>
{
var test2 = { foo: 'apples' };
BaseType.set(inst, 'test2', test2);
expect(inst.$values.test2).to.equal(test2);
});
it('sets the $dirty flag', () =>
{
var test2 = { foo: 'apples' };
BaseType.set(inst, 'test2', test2);
expect(inst.$dirty).to.equal(true);
});
});
describe('#validate()', () =>
{
it('throws a RequiredError if the value is null or undefined, and required', () =>
{
BaseType = new types.Base({ required: true });
// Test undefined
expect(() => BaseType.validate(inst, 'dne')).to.throw(errors.Required);
// Test null
inst.$values.isnull = null;
expect(() => BaseType.validate(inst, 'isnull')).to.throw(errors.Required);
});
it('calls type specific `$validate()` function', () =>
{
inst.$values.test2 = 12345;
BaseType.$validate = (item) => { return _.isString(item); };
expect(() => BaseType.validate(inst, 'test2')).to.throw(errors.Validation);
});
it('supports user defined sanitize functions', () =>
{
inst.$values.test2 = 12345;
BaseType = new types.Base({ sanitize: (item) => { return "" + item; } });
BaseType.$validate = (item) => { return _.isString(item); };
expect(BaseType.validate(inst, 'test2')).to.equal(true);
});
it('supports user defined validation functions', () =>
{
inst.$values.test2 = { admin: true };
inst.$values.test3 = { admin: false };
BaseType = new types.Base({ validate: (item) => item.admin });
expect(BaseType.validate(inst, 'test2')).to.equal(true);
expect(() => BaseType.validate(inst, 'test3')).to.throw(errors.CustomValidation);
});
});
});
describe('StringType', () =>
{
it('casts to the string \'StringType\'', () =>
{
expect(StringType.toString()).to.equal('StringType');
});
describe('#validate()', () =>
{
it('only validates strings', () =>
{
inst.$values = {
test: '1234567890',
test2: 1234567890
};
expect(StringType.validate(inst, 'test')).to.equal(true);
expect(() => StringType.validate(inst, 'test2')).to.throw(errors.Validation);
});
});
});
describe('NumberType', () =>
{
it('casts to the string \'NumberType\'', () =>
{
expect(NumberType.toString()).to.equal('NumberType');
});
describe('#validate()', () =>
{
it('only validates numbers', () =>
{
inst.$values = {
test: 1234567890,
test2: 12345.67890,
test3: '1234567890'
};
expect(NumberType.validate(inst, 'test')).to.equal(true);
expect(NumberType.validate(inst, 'test2')).to.equal(true);
expect(() => NumberType.validate(inst, 'test3')).to.throw(errors.Validation);
});
it('supports restricting to integer', () =>
{
var IntegerType = new types.Number({ integer: true });
inst.$values = {
test: 1234567890,
test2: 12345.67890,
test3: '1234567890'
};
expect(IntegerType.validate(inst, 'test')).to.equal(true);
expect(() => IntegerType.validate(inst, 'test2')).to.throw(errors.Validation);
expect(() => IntegerType.validate(inst, 'test3')).to.throw(errors.Validation);
});
});
});
describe('BooleanType', () =>
{
it('casts to the string \'BooleanType\'', () =>
{
expect(BooleanType.toString()).to.equal('BooleanType');
});
describe('#validate()', () =>
{
it('only validates boolean values', () =>
{
inst.$values = {
test: true,
test2: false,
test3: 'not a boolean'
};
expect(BooleanType.validate(inst, 'test')).to.equal(true);
expect(BooleanType.validate(inst, 'test2')).to.equal(true);
expect(() => BooleanType.validate(inst, 'test3')).to.throw(errors.Validation);
});
});
});
describe('DateType', () =>
{
it('casts to the string \'DateType\'', () =>
{
expect(DateType.toString()).to.equal('DateType');
});
describe('#get', () =>
{
it('always returns a Date object', () =>
{
inst.$values = {
test: new Date(),
test2: 1452908075801,
test3: 'not a valid date'
};
expect(DateType.get(inst, 'test')).to.be.instanceOf(Date);
expect(DateType.get(inst, 'test2')).to.be.instanceOf(Date);
expect(DateType.get(inst, 'test3')).to.be.instanceOf(Date);
});
it('returns the current timestamp if the `auto` option is set, and no value for the field exists', () =>
{
inst.$values = {};
DateType.options.auto = true;
expect(DateType.get(inst, 'test')).to.be.instanceOf(Date);
expect(typeof (DateType.get(inst, 'test').getTime())).to.equal('number');
expect(Date.now() - DateType.get(inst, 'test').getTime()).to.be.closeTo(0, 1);
});
});
describe('#set', () =>
{
it('converts to a timestamp for storage', () =>
{
var date = new Date();
DateType.set(inst, 'test', date);
expect(inst.$values.test).to.equal(date.getTime());
});
it('does not attempt to store an InvalidDate', () =>
{
var date = new Date('not a valid date');
DateType.set(inst, 'test', date);
expect(inst.$values.test).to.deep.equal({ foo: 123 });
});
});
describe('#validate()', () =>
{
it('only validates dates', () =>
{
inst.$values = {
test: new Date(),
test2: 1452908075801,
test3: 'not a valid date'
};
expect(DateType.validate(inst, 'test')).to.equal(true);
expect(DateType.validate(inst, 'test2')).to.equal(true);
expect(() => DateType.validate(inst, 'test3')).to.throw(errors.Validation);
});
});
});
describe('ObjectType', () =>
{
it('casts to the string \'ObjectType\'', () =>
{
expect(ObjectType.toString()).to.equal('ObjectType');
});
describe('#validate()', () =>
{
it('only validates strings', () =>
{
inst.$values = {
test: {},
test2: '1234567890'
};
expect(ObjectType.validate(inst, 'test')).to.equal(true);
expect(() => ObjectType.validate(inst, 'test2')).to.throw(errors.Validation);
});
it('supports the `schema` option', () =>
{
ObjectType = new types.Object({
schema: {
num: new types.Number(),
name: new types.String({ required: true })
}
});
inst.$values = {
test: {
num: 12345,
name: 'foobar'
},
test2: {
num: 12345,
name: 'foobar',
other: 'apples'
},
test3: {
num: 2345
},
test4: {
num: '???',
name: 'omgbbq'
},
test5: {}
};
expect(ObjectType.validate(inst, 'test')).to.equal(true);
expect(ObjectType.validate(inst, 'test2')).to.equal(true);
expect(() => ObjectType.validate(inst, 'test3')).to.throw(errors.Required);
expect(() => ObjectType.validate(inst, 'test4')).to.throw(errors.Validation);
expect(() => ObjectType.validate(inst, 'test5')).to.throw(errors.Required);
});
});
});
describe('ArrayType', () =>
{
it('casts to the string \'ArrayType\'', () =>
{
expect(ArrayType.toString()).to.equal('ArrayType');
});
describe('#validate()', () =>
{
it('only validates arrays', () =>
{
inst.$values = {
test: [],
test2: '1234567890'
};
expect(ArrayType.validate(inst, 'test')).to.equal(true);
expect(() => ArrayType.validate(inst, 'test2')).to.throw(errors.Validation);
});
it('validates the type of array elements', () =>
{
ArrayType = new types.Array({ type: new types.String() });
inst.$values = {
test: [],
test2: ['1234567890', 'apples', 'foobar'],
test3: [1234567890, 'apples', 'foobar'],
test4: [{ foo: 'bar' }, { foo: 'apples' }],
test5: [{ foo: 'bar' }, { foo: 12345 }]
};
expect(ArrayType.validate(inst, 'test')).to.equal(true);
expect(ArrayType.validate(inst, 'test2')).to.equal(true);
expect(() => ArrayType.validate(inst, 'test3')).to.throw(errors.Validation);
// Test Objects
ArrayType = new types.Array({ type: new types.Object({ schema: { foo: new types.String() } }) });
expect(ArrayType.validate(inst, 'test4')).to.equal(true);
expect(() => ArrayType.validate(inst, 'test5')).to.throw(errors.Validation);
});
});
});
describe('EnumType', () =>
{
it('casts to the string \'EnumType\'', () =>
{
expect(EnumType.toString()).to.equal('EnumType');
});
describe('#validate()', () =>
{
it('only validates to specific values', () =>
{
inst.$values = {
test: 'foo',
test2: 'cat'
};
expect(EnumType.validate(inst, 'test')).to.equal(true);
expect(() => EnumType.validate(inst, 'test2')).to.throw(errors.Validation);
});
});
});
describe('AnyType', () =>
{
it('casts to the string \'AnyType\'', () =>
{
expect(AnyType.toString()).to.equal('AnyType');
});
describe('#validate()', () =>
{
it('validates any type', () =>
{
inst.$values = {
string: 'is string',
number: 123456,
float: 12.45,
bool: false,
date: new Date(),
object: {},
array: []
};
expect(AnyType.validate(inst, 'string')).to.equal(true);
expect(AnyType.validate(inst, 'number')).to.equal(true);
expect(AnyType.validate(inst, 'float')).to.equal(true);
expect(AnyType.validate(inst, 'bool')).to.equal(true);
expect(AnyType.validate(inst, 'date')).to.equal(true);
expect(AnyType.validate(inst, 'object')).to.equal(true);
expect(AnyType.validate(inst, 'array')).to.equal(true);
});
});
});
});
// ---------------------------------------------------------------------------------------------------------------------