osync
Version:
Plain Javascript object synchronization framework
513 lines (505 loc) • 18.5 kB
JavaScript
var expect = require('unexpected/unexpected');
var ObservableObject = require('../../src/observable/observables').ObservableObject;
describe('ObservableObject', function() {
describe('create', function() {
it('can create observable object on data', function() {
var obj = {
property1: 0
};
var observable = new ObservableObject(obj);
expect(observable, 'to be defined');
});
it('contains all properties of a source object', function() {
var obj = {
property1: 0,
property2: 1,
array1: [1, 2, 3, 4],
object1: {
id: 1
}
};
var observable = new ObservableObject(obj);
expect(observable.property1, 'to be defined');
expect(observable.property2, 'to be defined');
expect(observable.array1, 'to equal', [1, 2, 3, 4]);
expect(observable.object1.id, 'to equal', 1);
});
});
describe('subscribe', function() {
it('can subscribe to its own plain property changes', function() {
var obj = {
property1: 0
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1 = 2;
expect(result.property1, 'to equal', 2);
});
it('can subscribe to its own array property changes', function() {
var obj = {
array1: [1, 2, 3, 4]
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.array1 = [1];
expect(result.array1, 'to equal', [1]);
});
it('can subscribe to its own object property changes', function() {
var obj = {
id: 1
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.id = 2;
expect(result.id, 'to equal', 2);
});
});
describe('hierarchical simple object subscription', function() {
it('receives events about nested property changes - 2 levels', function() {
var obj = {
property1: {
property2: 0
}
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1.property2 = 2;
expect(result['property1.property2'], 'to equal', 2);
});
it('receives events about nested property changes - 3 levels', function() {
var obj = {
property1: {
property2: {
property3: 0
}
}
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1.property2.property3 = 2;
expect(result['property1.property2.property3'], 'to equal', 2);
});
});
describe('hierarchical complex object subscription', function() {
it('receives events about nested object changes - 2 levels', function() {
var obj = {
property1: {
property2: 0
}
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1 = {
property3: 2
};
expect(result.property1, 'to equal', {
property3: 2
});
});
it('receives events about nested object changes - 3 levels', function() {
var obj = {
property1: {
property2: {
id: 1
}
}
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1.property2 = {
id: 2
};
expect(result['property1.property2'], 'to equal', {
id: 2
});
});
it('receives events about nested object changes - 4 levels', function() {
var obj = {
property1: {
property2: {
property3: {
id: 1
}
}
}
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(evt) {
result[evt.key] = evt.value;
});
observable.property1.property2.property3 = {
id: 2
};
expect(result['property1.property2.property3'], 'to equal', {
id: 2
});
});
});
describe('array subscription', function() {
it('receives events about single array push changes', function() {
var obj = {
array: []
};
var observable = new ObservableObject(obj);
observable.on('change', function(evt) {
expect(evt, 'to equal', {
key: 'array',
type: 'push',
args: [1],
result: 1,
target: observable
});
});
observable.array.push(1);
});
it('receives events about multiple array push changes', function() {
var obj = {
array: []
};
var observable = new ObservableObject(obj);
observable.on('change', function(evt) {
expect(evt, 'to equal', {
key: 'array',
type: 'push',
args: [1, 2],
result: 2,
target: observable
});
});
observable.array.push(1, 2);
});
it('receives events about nested array property changes', function() {
var obj = {
property1: {
array: []
}
};
var observable = new ObservableObject(obj);
observable.on('change', function(evt) {
expect(evt.key, 'to equal', 'property1.array');
expect(evt.type, 'to equal', 'push');
expect(evt.args, 'to equal', [1]);
expect(evt.result, 'to equal', 1);
expect(evt.target, 'to be', observable.property1);
});
observable.property1.array.push(1);
});
it('receives events about array objects changes', function() {
var obj = {
array: [{
id: 1
}, {
id: 2
}]
};
var observable = new ObservableObject(obj);
observable.on('change', function(evt) {
expect(evt, 'to equal', {
key: 'array[0].id',
type: 'set',
value: 1,
target: observable.array[0]
});
});
observable.array[0].id = 1;
});
it('receives events about nested array objects changes', function() {
var obj = {
array: [{
array: [{
id: 2
}]
}]
};
var observable = new ObservableObject(obj);
observable.on('change', function(evt) {
expect(evt.key, 'to equal', 'array[0].array[0].id');
expect(evt.type, 'to equal', 'set');
expect(evt.value, 'to equal', 1);
expect(evt.target, 'to equal', observable.array[0].array[0]);
});
observable.array[0].array[0].id = 1;
});
/*
it('receives events about new object assignment', function() {
var obj = {
array: [ {id: 2}]
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(key, value) {
result[key] = value;
});
obj.array[0] = {id: 3};
expect(result['array[0]'], 'to equal', {id: 3});
});
it('receives events about nested object assignment', function() {
var obj = {
array: [
{ array: [{id: 2}] }
]
};
var observable = new ObservableObject(obj);
var result = {};
observable.on('change', function(key, value) {
result[key] = value;
});
obj.array[0].array[0] = {id: 3};
expect(result['array[0].array[0]'], 'to equal', {id: 3});
});*/
});
describe('obejct subscription', function() {
it('fire "change" event on pushed single array items', function() {
var obj = {
array: [{
object: {
id: 1
}
}, {
id: 2
}]
};
var observable = new ObservableObject(obj);
var spy = sinon.spy();
observable.on('change', function(evt) {
expect(evt, 'to equal', {
key: 'array[0].object.id',
type: 'set',
value: 1,
target: obj.array[0].object
});
spy();
});
observable.array[0].object.id = 1;
expect(spy.called, 'to be true');
});
});
describe('new item subscriptions', function() {
it('fire "change" event on pushed single array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.push({
_uri: 'object/2',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
expect(callback.called, 'to be true');
});
it('fire "change" event on pushed multiple array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.push({
_uri: 'object/2',
property: false
}, {
_uri: 'object/3',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
observable.object.array[1].property = true;
expect(callback.calledTwice, 'to be true');
});
it('fire "change" event on unshifted single array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.unshift({
_uri: 'object/2',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
expect(callback.called, 'to be true');
});
it('fire "change" event on unshifted multiple array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.unshift({
_uri: 'object/2',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
expect(callback.called, 'to be true');
});
it('fire "change" event on unshifted multiple array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.unshift({
_uri: 'object/2',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
expect(callback.called, 'to be true');
});
it('fire "change" event on spliced single array item', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: []
}
});
observable.object.array.splice(0, 0, {
_uri: 'object/2',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[0].property = true;
expect(callback.called, 'to be true');
});
it('fire "change" event on spliced multiple array items', function() {
var observable = new ObservableObject({
_uri: 'object/1',
object: {
array: [{_uri: 'object/2'}, {_uri: 'object/3'}, {_uri: 'object/4'}]
}
});
observable.object.array.splice(1, 0, {
_uri: 'object/5',
property: false
}, {
_uri: 'object/6',
property: false
});
var callback = sinon.spy();
observable.on('change', callback);
observable.object.array[1].property = true;
observable.object.array[2].property = true;
expect(callback.calledTwice, 'to be true');
});
});
describe('dispose', function() {
it('contains dispose method', function() {
var obj = {};
var observable = new ObservableObject(obj);
var result = {};
expect(observable.dispose, 'to be defined');
});
it('disposes children', function() {
var obj = {
obj: {
obj: {}
}
};
var observable = new ObservableObject(obj);
var spy = sinon.spy();
obj.obj.obj.addDisposer(spy);
observable.dispose();
expect(spy.called, 'to be true');
});
it('disposes array children', function() {
var obj = {
obj: {
array: [{}]
}
};
var observable = new ObservableObject(obj);
var spy = sinon.spy();
obj.obj.array[0].addDisposer(spy);
observable.dispose();
expect(spy.called, 'to be true');
});
it('does not fire "change" event after disposing', function() {
var obj = {
property: true
};
var observable = new ObservableObject(obj);
var callback = sinon.spy();
observable.on('change', callback);
observable.dispose();
obj.property = false;
expect(callback.called, 'to be false');
});
it('does not fire "change" event after disposing - 2nd level', function() {
var obj = {
object: {
property: true
}
};
var observable = new ObservableObject(obj);
var callback = sinon.spy();
observable.on('change', callback);
observable.dispose();
obj.object.property = false;
expect(callback.called, 'to be false');
});
it('does not fire "change" event after disposing - array methods', function() {
var obj = {
object: {
array: []
}
};
var observable = new ObservableObject(obj);
var callback = sinon.spy();
observable.on('change', callback);
observable.dispose();
obj.object.array.push(0);
expect(callback.called, 'to be false');
});
it('does not fire "change" event after disposing - array object assignments', function() {
var obj = {
object: {
array: [{
id: 1
}]
}
};
var observable = new ObservableObject(obj);
var callback = sinon.spy();
observable.on('change', callback);
observable.dispose();
obj.object.array[0].property = false;
expect(callback.called, 'to be false');
});
});
});