model tests

This commit is contained in:
antelle 2019-10-12 15:33:48 +02:00
parent 4d1cbe7f62
commit 0f5b03ce64
2 changed files with 142 additions and 12 deletions

View File

@ -5,18 +5,18 @@ const SymbolEvents = Symbol('events');
const SymbolDefaults = Symbol('defaults'); const SymbolDefaults = Symbol('defaults');
const SymbolExtensions = Symbol('extensions'); const SymbolExtensions = Symbol('extensions');
function emitPropChange(target, property, value, prevValue, receiver) { function emitPropChange(target, property, value, prevValue) {
const emitter = target[SymbolEvents]; const emitter = target[SymbolEvents];
if (!emitter.paused) { if (!emitter.paused) {
emitter.emit('change:' + property, receiver, value, prevValue); emitter.emit('change:' + property, target, value, prevValue);
if (!emitter.noChange) { if (!emitter.noChange) {
emitter.emit('change', receiver, { [property]: value }); emitter.emit('change', target, { [property]: value });
} }
} }
} }
const ProxyDef = { const ProxyDef = {
deleteProperty(target, property, receiver) { deleteProperty(target, property) {
if (Object.prototype.hasOwnProperty.call(target, property)) { if (Object.prototype.hasOwnProperty.call(target, property)) {
const defaults = target[SymbolDefaults]; const defaults = target[SymbolDefaults];
const value = defaults[property]; const value = defaults[property];
@ -27,7 +27,7 @@ const ProxyDef = {
} else { } else {
delete target[property]; delete target[property];
} }
emitPropChange(target, property, value, prevValue, receiver); emitPropChange(target, property, value, prevValue);
} }
return true; return true;
} }
@ -38,7 +38,7 @@ const ProxyDef = {
if (target[property] !== value) { if (target[property] !== value) {
const prevValue = target[property]; const prevValue = target[property];
target[property] = value; target[property] = value;
emitPropChange(target, property, value, prevValue, receiver); emitPropChange(target, property, value, prevValue);
} }
return true; return true;
} else { } else {
@ -61,6 +61,7 @@ class Model {
}; };
for (const [propName, defaultValue] of Object.entries(this[SymbolDefaults])) { for (const [propName, defaultValue] of Object.entries(this[SymbolDefaults])) {
properties[propName] = { properties[propName] = {
configurable: true,
enumerable: true, enumerable: true,
writable: true, writable: true,
value: defaultValue value: defaultValue

View File

@ -2,14 +2,143 @@ import { expect } from 'chai';
import { Model } from 'framework/model'; import { Model } from 'framework/model';
describe('Model', () => { describe('Model', () => {
class TestModel extends Model {}
TestModel.defineModelProperties({ foo: 'bar', baz: 0 });
class TestExtensibleModel extends Model {}
TestExtensibleModel.defineModelProperties({ foo: 'bar' }, { extensions: true });
it('should create a model with default properties', () => { it('should create a model with default properties', () => {
class MyModel extends Model {} const model = new TestModel();
MyModel.defineModelProperties({ prop: 'default' });
const myModel = new MyModel(); expect(model).to.be.ok;
expect(model.foo).to.eql('bar');
expect(model.baz).to.eql(0);
expect(model.another).to.be.undefined;
});
expect(myModel).to.be.ok; it('should serialize a model to JSON', () => {
expect(myModel.prop).to.eql('default'); const model = new TestModel();
expect(myModel.another).to.be.undefined;
model.baz = 1;
expect(JSON.stringify(model)).to.eql('{"foo":"bar","baz":1}');
});
it('should throw an error for unknown properties', () => {
const model = new TestModel();
expect(() => {
model.xxx = 'value';
}).to.throw();
});
it('should set properties', () => {
const model = new TestModel();
const calls = [];
const callsProp = [];
const callsAnother = [];
model.on('change', (...args) => calls.push(args));
model.on('change:foo', (...args) => callsProp.push(args));
model.on('change:baz', (...args) => callsAnother.push(args));
model.foo = 123;
expect(model.foo).to.eql(123);
expect(calls).to.eql([[model, { foo: 123 }]]);
expect(callsProp).to.eql([[model, 123, 'bar']]);
expect(callsAnother).to.eql([]);
});
it('should set properties using "set" method', () => {
const model = new TestModel();
const calls = [];
const callsProp = [];
const callsAnother = [];
model.on('change', (...args) => calls.push(args));
model.on('change:foo', (...args) => callsProp.push(args));
model.on('change:baz', (...args) => callsAnother.push(args));
model.set({ foo: 123, baz: 456 });
expect(model.foo).to.eql(123);
expect(model.baz).to.eql(456);
expect(calls).to.eql([[model, { foo: 123, baz: 456 }]]);
expect(callsProp).to.eql([[model, 123, 'bar']]);
expect(callsAnother).to.eql([[model, 456, 0]]);
});
it('should silently set properties using "set" method', () => {
const model = new TestModel();
const calls = [];
const callsProp = [];
const callsAnother = [];
model.on('change', (...args) => calls.push(args));
model.on('change:foo', (...args) => callsProp.push(args));
model.on('change:baz', (...args) => callsAnother.push(args));
model.set({ foo: 123, baz: 456 }, { silent: true });
expect(model.foo).to.eql(123);
expect(model.baz).to.eql(456);
expect(calls).to.eql([]);
expect(callsProp).to.eql([]);
expect(callsAnother).to.eql([]);
});
it('should delete properties', () => {
const model = new TestModel();
model.foo = 123;
const calls = [];
const callsProp = [];
const callsAnother = [];
model.on('change', (...args) => calls.push(args));
model.on('change:foo', (...args) => callsProp.push(args));
model.on('change:baz', (...args) => callsAnother.push(args));
delete model.foo;
expect(model.foo).to.eql('bar');
expect(calls).to.eql([[model, { foo: 'bar' }]]);
expect(callsProp).to.eql([[model, 'bar', 123]]);
expect(callsAnother).to.eql([]);
});
it('should allow extensions for extensible models', () => {
const model = new TestExtensibleModel();
expect(model.foo).to.eql('bar');
const calls = [];
model.on('change', (...args) => calls.push(args));
model.foo = 123;
model.xxx = 456;
expect(model.foo).to.eql(123);
expect(model.xxx).to.eql(456);
expect(model).to.have.property('xxx');
expect(JSON.stringify(model)).to.eql('{"foo":123,"xxx":456}');
delete model.xxx;
expect(model).to.not.have.property('xxx');
expect(model.xxx).to.be.undefined;
expect(JSON.stringify(model)).to.eql('{"foo":123}');
expect(calls).to.eql([
[model, { foo: 123 }],
[model, { xxx: 456 }],
[model, { xxx: undefined }]
]);
}); });
}); });