UNPKG

speck-entity

Version:

Domain entities with reactive validation

282 lines (232 loc) 8.7 kB
const { expect } = require('chai') const Faker = require('faker') const sinon = require('sinon') const { defaultField, defaultValue, FakeEntityWithDefault, FakeEntityWithBoolean, FakeEntityWithObject, ProductEntity, Validatable, ChildrenEntity, ChildrenWithDependency, FatherEntity, FatherWithObjectEntity, FatherWithDependencies, FakeEntityWithExcludeContext, FakeEntityWithIncludeContext, FakeEntityWithCustomValidationWithContext, FakeEntityWithCustomElementList } = require('./fixtures/fakerClasses') describe('Speck', () => { it('validates Boolean True context', () => { const instance = new FakeEntityWithBoolean({ isDefault: true }) expect(instance.isDefault).to.equal(true) }) it('validates Boolean False context', () => { const instance = new FakeEntityWithBoolean({ isDefault: false }) expect(instance.isDefault).to.equal(false) }) describe('defaultValue', () => { it('does not change default value of field', () => { const instance1 = new FakeEntityWithObject() instance1.config.name = 'Speck' const instance2 = new FakeEntityWithObject() expect(instance2.config).to.not.have.property('name') expect(instance1.config).to.not.equal(instance2.config) }) it('merges with default data', () => { const fakeEntity = new FakeEntityWithDefault() expect(fakeEntity[defaultField]).to.equal(defaultValue) }) it('cleans data on toJSON', () => { const fakeEntity = new FakeEntityWithDefault({ fakeAttribute: 'should not come', children: [{ foo: 'bar' }], child: { foo: 'bar' } }) expect(fakeEntity.toJSON()).to.deep.equal({ [defaultField]: defaultValue, [`_${defaultField}`]: `_${defaultValue}`, child: { foo: 'bar' }, children: [{ foo: 'bar' }] }) }) it('creates set for property and call validate when change', () => { const fakeEntity = new FakeEntityWithDefault() sinon.spy(fakeEntity, '_validate') fakeEntity[`_${defaultField}`] = `_${defaultValue}` sinon.assert.notCalled(fakeEntity._validate) fakeEntity[`_${defaultField}`] = defaultValue sinon.assert.calledOnce(fakeEntity._validate) }) it('does not use defaultValue when a value is passed', () => { const newValue = Faker.name.findName() const fakeEntity = new FakeEntityWithDefault({ [defaultField]: newValue }) expect(fakeEntity[`_${defaultField}`]).to.equal(`_${defaultValue}`) expect(fakeEntity[defaultField]).to.equal(newValue) }) it('does not have default functions as objects', () => { const fakeEntity = new FakeEntityWithDefault() expect(fakeEntity.functionAsDefault).to.be.instanceOf(Function) }) }) it('validates when build', () => { // given sinon.spy(Validatable.SCHEMA, 'field') sinon.spy(Validatable.SCHEMA.otherField, 'validator') // when const instantiate = new Validatable({ field: 'value', noField: 'should not go' }) // then sinon.assert.calledWith( Validatable.SCHEMA.field, { field: 'value', otherField: 'bla' }, 'field', 'ValidatableEntity' ) sinon.assert.calledWith( Validatable.SCHEMA.otherField.validator, { field: 'value', otherField: 'bla' }, 'otherField', 'ValidatableEntity' ) expect(instantiate.valid).to.equal(false) }) it('validates automatically', () => { // when const entity = new Validatable({ field: 'invalid', otherField: 'invalid' }) expect(entity.valid).to.equal(false) entity.field = 'valid' expect(entity.valid).to.equal(false) entity.otherField = 'valid' expect(entity.valid).to.equal(true) }) describe('children', () => { it('builds Hetrogenerous types in a list automatically', () => { const elementEntity = new FakeEntityWithCustomElementList({ elements: [{ type: 'product', name: true, price: true }, { type: 'default', isDefault: true }] }) expect(elementEntity.elements[0].constructor).to.equal(ProductEntity) expect(elementEntity.elements[1].constructor).to.equal(FakeEntityWithBoolean) }) it('builds automatically child entities of array', () => { const father = new FatherEntity({ children: [ {}, {} ] }) expect(father.children[0].constructor).to.equal(ChildrenEntity) expect(father.children[1].constructor).to.equal(ChildrenEntity) }) it('builds automatically using the parameter builder', () => { const father = new FatherWithObjectEntity({ children: { content: { field: 'foo' }, tweet: { field: 'bar' } } }) expect(father.children.content.constructor).to.equal(ChildrenEntity) expect(father.children.tweet.constructor).to.equal(ChildrenEntity) }) it('builds automatically using the parameter builder and passing dependencies', () => { const father = new FatherWithDependencies({ children: { foo: 'bar' } }, { dependency: true }) expect(father.children.constructor).to.equal(ChildrenWithDependency) expect(father.children.dependency).to.equal(true) }) it('includes errors of children', () => { const father = new FatherEntity({ foo: 'test', children: [{ foo: '2bar' }, { foo: 'bar' }, { foo: '2bar' }], child: { foo: '2bar' } }) expect(father.getErrors()).to.deep.equal({ foo: { errors: [ 'foo accepts just \'bar\' as value' ] }, child: { '0': { foo: { 'errors': [ 'foo accepts just \'bar\' as value' ] } } }, children: { '0': { foo: { 'errors': [ 'foo accepts just \'bar\' as value' ] } }, '2': { foo: { 'errors': [ 'foo accepts just \'bar\' as value' ] } } } }) }) }) describe('validateContext', () => { it('sets contexts excluded', () => { const fakeEntityWithContext = new FakeEntityWithExcludeContext({ name: 'Node1' }) const contextValidated = fakeEntityWithContext.validateContext('create') expect(fakeEntityWithContext.constructor).to.equal(FakeEntityWithExcludeContext) expect(contextValidated.id).to.equal(undefined) expect(contextValidated.requiredProp1).not.to.equal(undefined) expect(contextValidated.requiredProp2).not.to.equal(undefined) expect(contextValidated.requiredProp3).to.equal(undefined) }) it('sets contexts include', () => { const fakeEntityWithContext = new FakeEntityWithIncludeContext({ name: 'Node1' }) const contextValidated = fakeEntityWithContext.validateContext('create') expect(fakeEntityWithContext.constructor).to.equal(FakeEntityWithIncludeContext) expect(contextValidated.id).to.equal(undefined) expect(contextValidated.requiredProp1).not.to.equal(undefined) expect(contextValidated.requiredProp2).not.to.equal(undefined) expect(contextValidated.requiredProp3).to.equal(undefined) }) it('sets custom validations', () => { const fakeEntityWithContext = new FakeEntityWithCustomValidationWithContext({ id: 1, requiredProp1: -1 }) const contextValidated = fakeEntityWithContext.validateContext('create') expect(fakeEntityWithContext.constructor).to.equal(FakeEntityWithCustomValidationWithContext) expect(contextValidated.id).to.equal(undefined) expect(contextValidated.requiredProp1).not.to.equal(undefined) expect(fakeEntityWithContext.errors.requiredProp1).to.equal(undefined) }) it('returns the errors when then context does not exist', () => { const entity = new ProductEntity({ foo: 'bar' }) const errors = entity.validateContext('noValidContext') expect(errors).to.deep.equal(entity.getErrors()) }) it('returns valid when validateContext has no errors', () => { const fakeEntityWithContext = new FakeEntityWithExcludeContext({ requiredProp1: 1, requiredProp2: 2 }) const contextValidated = fakeEntityWithContext.validateContext('create') expect(contextValidated.valid).to.equal(true) }) it('returns invalid when validateContext has errors', () => { const fakeEntityWithContext = new FakeEntityWithExcludeContext({ id: 1, requiredProp3: 2 }) const contextValidated = fakeEntityWithContext.validateContext('create') expect(contextValidated.valid).to.equal(false) }) }) })