Gleam

Reusable models for the Node server and browsers


Project maintained by nkbt Hosted on GitHub Pages — Theme by mattgraham

I like the idea of Transfer Objects within application. In my applications I use Entities (simple TO but with some additional functions like data validation, type casting, etc). Because I planned to write modern one-page-apps I decided to have Entities on the front-end as well.

That is how the idea of Gleam was born. And now I am able to write Entity once and use it on the NodeJS side and on the browser side. Every entity is automatically serialized to JSON and deserialized on front-end to correct objects. Gleam is for now on the very early stage, it is more like "proof of concept". I still need to build some real projects based on it.

Coverage report

The Gleam test suite documentation generated with the Mocha test framework.

Gleam

should throw error if root not set
expect(Gleam).to.throw('Root');
should have private _root property
expect(gleam).to.have.property('_root', root);
should response to [entity, fromJson] instance methods
expect(Gleam).to.respondTo('entity');
expect(Gleam).to.respondTo('fromJson');
should response to [is, buildSync] static methods
expect(Gleam).itself.to.respondTo('is');
expect(Gleam).itself.to.respondTo('buildSync');

Gleam#entity

should throw error in case of incorrect namespace
function createNotExistingEntity() {
	return gleam.entity('wrongSchema');
}
expect(createNotExistingEntity).to.throw(Error);
should throw error in case of wrong Entity schema
function createEntityWithWrongSchema() {
	return gleam.entity('wrongSchema');
}
expect(createEntityWithWrongSchema).to.throw('Entity must be an object');
should throw error in case of Entity schema has properties and not methods
function createEntityWithFaultySchema() {
	return gleam.entity('schemaWithProperties');
}
expect(createEntityWithFaultySchema).to.throw('Entity schema must not have any properties');
should create UserEntity
var entity = gleam.entity('user');
expect(entity).to.be.an('object');
expect(entity).to.have.keys('id', 'name', 'email');
expect(entity.id).to.be.a('function');
expect(entity.name).to.be.a('function');
expect(entity.email).to.be.a('function');
expect(Gleam.is(entity, 'user')).to.be.true;
should create UserTestEntity
var entity = gleam.entity('user/test');
expect(entity).to.be.an('object');
expect(entity).to.have.keys('id');
expect(entity.id).to.be.a('function');
expect(Gleam.is(entity, 'user/test')).to.be.true;
should create UserEntity with defaults
var entity = gleam.entity('user', userData);
expect(entity.id()).to.equal(userData.id);
expect(entity.name()).to.equal(userData.name);
expect(entity.email()).to.equal(userData.email);
should throw Error if wrong defaults passed
function createEntityWithWrongData() {
	return gleam.entity('user', 'not an object');
}
expect(createEntityWithWrongData).to.throw('Values must be an object');
should set defaults without setting modified flag
var entity = gleam.entity('user', userData);
expect(entity.modified().id).to.be.false;
expect(entity.modified().name).to.be.false;
expect(entity.modified().email).to.be.false;
should fill initial values with defaults
var entity = gleam.entity('user', userData);
expect(entity.initial().id).to.equal(userData.id);
expect(entity.initial().name).to.equal(userData.name);
expect(entity.initial().email).to.equal(userData.email);

Gleam#fromJson

should return UserEntity from user.json
var entity = gleam.fromJson(userJson);
expect(entity).to.be.an('object');
expect(Gleam.is(entity, 'user')).to.be.true;
expect(entity.id()).to.equal(1);
should return array of UserEntity from user-list.json
var list = gleam.fromJson(userListJson);
expect(list).to.be.an('array');
expect(list).to.have.length(2);
expect(Gleam.is(list[0], 'user')).to.be.true;
expect(list[0].id()).to.equal(1);
expect(Gleam.is(list[1], 'user')).to.be.true;
expect(list[1].id()).to.equal(2);

Gleam#is

should match UserEntity to be instance of "user"
expect(Gleam.is(entity, 'user')).to.be.true;
should not match UserEntity to be instance of "not/user"
expect(Gleam.is(entity, 'not/user')).to.be.false;
should not match wrong input to be instance of "user"
expect(Gleam.is('Not an object', 'user')).to.be.false;

Gleam#build

should return spaceFix
expect(jsOut).to.be.a('string');
should return valid RequireJS module
expect(spaceFix(jsOut)).to.be.equal(spaceFix(jsIn));

Entity

#set

should only accept simple objects and throw error otherwise
expect(function () {
	return entity.set({id: 1});
}).to.not.throw(Error);
expect(function () {
	return entity.set('Hello, world!');
}).to.throw('Values must be an object');
expect(function () {
	return entity.set(['hello', 'world']);
}).to.throw('Values must be an object');
expect(function () {
	return entity.set(function () {
	});
}).to.throw('Values must be an object');
should set valid values
entity.set(userData);
expect(entity.id()).to.equal(userData.id);
expect(entity.name()).to.equal(userData.name);
expect(entity.email()).to.equal(userData.email);
should throw descriptive error for invalid data
expect(function () {
	entity.set({email: 'wrong-email'});
}).to.throw('Value [wrong-email] is not valid for [user.email]');
should set overridden value using setter _setEmail no matter what is passed, email = always@email.com
var entity = gleam.entity('setterGetter', {email: 'nik@butenko.me'});
expect(entity.email()).to.equal('always@email.com');
should set value in setter _setPassword using the context, password = context.password2
var entity = gleam.entity('setterGetter', {password: 'test', password2: 'test2'});
expect(entity.password()).to.equal('test2');
should set value in setter _setId using self data, id = self.constant() + value
var entity = gleam.entity('setterGetter', {id: 1});
expect(entity.id()).to.equal(43);

#get

should return simple object with current entity values
var entity = gleam.entity('user', userData);
expect(entity.get()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me"});
should return simple object with all nested entities simplified
var entity = gleam.fromJson(userWithTestJson);
expect(entity.get()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me", test: {id: 2}});
should return simple object with all nested arrays of entities simplified
var entity = gleam.fromJson(requireText('./fixtures/user-with-arrays.json'));
expect(entity.get()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me", tests: [
{id: 2},
{id: 3}
], messages: ["Message 1", "Message 2"]});
should return overridden value using getter _getName
var entity = gleam.entity('setterGetter');
entity.name('Me');
expect(entity.name()).to.equal('Always');
should use self instance to override value using getter _getAddress, address = self.name()
var entity = gleam.entity('setterGetter');
entity.address('Address');
expect(entity.address()).to.equal('Always');

#isValid

should return "true" for valid email passed
expect(entity.isValid('email', 'nik@butenko.me')).to.be.true;
should return "false" for invalid email passed
expect(entity.isValid('email', 'wrong@email')).to.be.false;

#getProperty

should return value for requested property
expect(entity.getProperty('id')).to.equal(1);
should throw descriptive error in case of accessing undefined property
expect(function () {
	entity.getProperty('wrong');
}).to.throw('Accessing undefined property [user.wrong]');

#getFlat

should return simple object with stripped nested entities
var entity = gleam.fromJson(userWithTestJson);
expect(entity.getFlat()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me"});
should return simple object with stripped nested entities in all Array-typed properties
var entity = gleam.fromJson(requireText('./fixtures/user-with-arrays.json'));
expect(entity.getFlat()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me", tests: [], messages: ["Message 1", "Message 2"]});

#initial

should have undefined initial values
var entity = gleam.entity('user');
expect(entity.initial()).to.deep.equal({id: undefined, name: undefined, email: undefined});
should return initial value of entity
var entity = gleam.entity('user', userData);
expect(entity.initial()).to.deep.equal({id: 1, name: "Nik", email: "nik@butenko.me"});
should not modify initial after setting new values
var entity = gleam.entity('user');
entity.set({id: 1});
expect(entity.initial().id).to.be.undefined;

#modified

should not have modified status
var entity = gleam.entity('user');
expect(entity.modified()).to.deep.equal({id: false, name: false, email: false});
should set modified flag for set values
var entity = gleam.entity('user');
entity.set({id: 1});
expect(entity.modified().id).to.be.true;
expect(entity.modified().email).to.be.false;

#is

should match UserEntity to be instance of "user"
expect(entity.is('user')).to.be.true;
should not match UserEntity to be instance of "not/user"
expect(entity.is('not/user')).to.be.false;

#toJSON

should return simple object with namespace
var entity = gleam.fromJson(userJson);
expect(entity.toJSON()).to.deep.equal(userData);
should return simple object with namespaces for nested entity
var entity = gleam.fromJson(userWithTestJson);
expect(entity.toJSON()).to.deep.equal(userWithTestData);
should support JSON.stringify
var entity = gleam.fromJson(userJson);
expect(spaceFix(JSON.stringify(entity))).to.equal(spaceFix(userJson));
should support JSON.stringify for nested entity
var entity = gleam.fromJson(userWithTestJson);
expect(spaceFix(JSON.stringify(entity))).to.equal(spaceFix(userWithTestJson));
should support JSON.stringify for arrays of nested entities
var json = requireText('./fixtures/user-with-arrays.json'),
entity = gleam.fromJson(json);
expect(spaceFix(JSON.stringify(entity))).to.equal(spaceFix(json));

#toString

should return descriptive string
var entity = gleam.entity('user');
expect(entity.toString()).to.equal('[object Gleam:user]');
should support casting to string
var entity = gleam.entity('user/test');
expect(['', entity].join('')).to.equal('[object Gleam:user/test]');