mirror of https://github.com/keeweb/keeweb.git
collection tests
This commit is contained in:
parent
0fce37cc73
commit
50976b2d09
|
@ -15,7 +15,7 @@ function emitSet(target, value, prevValue) {
|
||||||
emitter.emit('add', value, target);
|
emitter.emit('add', value, target);
|
||||||
updates.added.push(value);
|
updates.added.push(value);
|
||||||
}
|
}
|
||||||
emitter.emit('change', updates, this);
|
emitter.emit('change', updates, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ function emitRemoved(target, removed) {
|
||||||
for (const item of removed) {
|
for (const item of removed) {
|
||||||
emitter.emit('remove', item, target);
|
emitter.emit('remove', item, target);
|
||||||
}
|
}
|
||||||
emitter.emit('change', { added: [], removed }, this);
|
emitter.emit('change', { added: [], removed }, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +127,7 @@ class Collection {
|
||||||
this[SymbolEvents].emit('remove', item, this);
|
this[SymbolEvents].emit('remove', item, this);
|
||||||
this[SymbolEvents].emit('change', { added: [], removed: [item] }, this);
|
this[SymbolEvents].emit('change', { added: [], removed: [item] }, this);
|
||||||
}
|
}
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
shift() {
|
shift() {
|
||||||
|
@ -137,6 +138,7 @@ class Collection {
|
||||||
this[SymbolEvents].emit('remove', item, this);
|
this[SymbolEvents].emit('remove', item, this);
|
||||||
this[SymbolEvents].emit('change', { added: [], removed: [item] }, this);
|
this[SymbolEvents].emit('change', { added: [], removed: [item] }, this);
|
||||||
}
|
}
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
unshift(...items) {
|
unshift(...items) {
|
||||||
|
@ -197,7 +199,7 @@ class Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
sort() {
|
sort() {
|
||||||
this[SymbolArray].sort(this.comparator);
|
return this[SymbolArray].sort(this.comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fill() {
|
fill() {
|
||||||
|
|
|
@ -0,0 +1,373 @@
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { Model } from 'framework/model';
|
||||||
|
import { Collection } from 'framework/collection';
|
||||||
|
|
||||||
|
describe('Collection', () => {
|
||||||
|
class TestModel extends Model {
|
||||||
|
constructor(id) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestModel.defineModelProperties({ id: 'bar' });
|
||||||
|
|
||||||
|
class TestCollection extends Collection {
|
||||||
|
static model = TestModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should create a collection without models', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
expect(collection).to.be.ok;
|
||||||
|
expect(collection.length).to.eql(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a collection with models', () => {
|
||||||
|
const collection = new TestCollection([new TestModel('1'), new TestModel('2')]);
|
||||||
|
|
||||||
|
expect(collection).to.be.ok;
|
||||||
|
expect(collection.length).to.eql(2);
|
||||||
|
expect(collection[0]).to.be.ok;
|
||||||
|
expect(collection[0].id).to.eql('1');
|
||||||
|
expect(collection[1]).to.be.ok;
|
||||||
|
expect(collection[1].id).to.eql('2');
|
||||||
|
expect(collection[2]).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check types when adding new items', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
collection.push({ id: 'bar' });
|
||||||
|
}).to.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize a collection to JSON', () => {
|
||||||
|
const collection = new TestCollection([new TestModel('1'), new TestModel('2')]);
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":"1"},{"id":"2"}]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add models with push', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsAdd = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('add', (...args) => callsAdd.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
collection.push(model1);
|
||||||
|
expect(callsChange).to.eql([[{ added: [model1], removed: [] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[model1, collection]]);
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsAdd.length = 0;
|
||||||
|
|
||||||
|
const modelA = new TestModel('a');
|
||||||
|
const modelB = new TestModel('b');
|
||||||
|
collection.push(modelA, modelB);
|
||||||
|
expect(callsChange).to.eql([[{ added: [modelA, modelB], removed: [] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[modelA, collection], [modelB, collection]]);
|
||||||
|
expect(collection.length).to.eql(3);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":"a"},{"id":"b"}]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add models with unshift', () => {
|
||||||
|
const collection = new TestCollection([new TestModel(1)]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsAdd = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('add', (...args) => callsAdd.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
collection.unshift(model2);
|
||||||
|
expect(callsChange).to.eql([[{ added: [model2], removed: [] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[model2, collection]]);
|
||||||
|
expect(collection.length).to.eql(2);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":2},{"id":1}]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsAdd.length = 0;
|
||||||
|
|
||||||
|
const modelA = new TestModel('a');
|
||||||
|
const modelB = new TestModel('b');
|
||||||
|
collection.unshift(modelA, modelB);
|
||||||
|
expect(callsChange).to.eql([[{ added: [modelA, modelB], removed: [] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[modelA, collection], [modelB, collection]]);
|
||||||
|
expect(collection.length).to.eql(4);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":"a"},{"id":"b"},{"id":2},{"id":1}]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove models with pop', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2}]');
|
||||||
|
|
||||||
|
const popped1 = collection.pop();
|
||||||
|
expect(popped1).to.eql(model2);
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model2] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection]]);
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
const popped2 = collection.pop();
|
||||||
|
expect(popped2).to.eql(model1);
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model1] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model1, collection]]);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
const popped3 = collection.pop();
|
||||||
|
expect(popped3).to.be.undefined;
|
||||||
|
expect(callsChange).to.eql([]);
|
||||||
|
expect(callsRemove).to.eql([]);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove models with shift', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2}]');
|
||||||
|
|
||||||
|
const shifted1 = collection.shift();
|
||||||
|
expect(shifted1).to.eql(model1);
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model1] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model1, collection]]);
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":2}]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
const shifted2 = collection.shift();
|
||||||
|
expect(shifted2).to.eql(model2);
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model2] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection]]);
|
||||||
|
expect(collection.length).to.eql(0);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
const shifted3 = collection.shift();
|
||||||
|
expect(shifted3).to.be.undefined;
|
||||||
|
expect(callsChange).to.eql([]);
|
||||||
|
expect(callsRemove).to.eql([]);
|
||||||
|
expect(collection.length).to.eql(0);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove models by setting length', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const model3 = new TestModel(3);
|
||||||
|
const collection = new TestCollection([model1, model2, model3]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2},{"id":3}]');
|
||||||
|
|
||||||
|
collection.length = 1;
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model2, model3] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection], [model3, collection]]);
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
collection.length = 1;
|
||||||
|
expect(callsChange).to.eql([]);
|
||||||
|
expect(callsRemove).to.eql([]);
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
|
||||||
|
collection.length = 0;
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model1] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model1, collection]]);
|
||||||
|
expect(collection.length).to.eql(0);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set custom properties', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
const calls = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => calls.push(args));
|
||||||
|
collection.on('add', (...args) => calls.push(args));
|
||||||
|
collection.on('remove', (...args) => calls.push(args));
|
||||||
|
|
||||||
|
collection.prop = 'val';
|
||||||
|
|
||||||
|
expect(collection.prop).to.eql('val');
|
||||||
|
|
||||||
|
expect(collection.length).to.eql(0);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
expect(calls).to.eql([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check types when setting items', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
collection[0] = { id: 'bar' };
|
||||||
|
}).to.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set new items', () => {
|
||||||
|
const collection = new TestCollection();
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsAdd = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('add', (...args) => callsAdd.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
const model = new TestModel(1);
|
||||||
|
collection[0] = model;
|
||||||
|
|
||||||
|
expect(collection.length).to.eql(1);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1}]');
|
||||||
|
expect(callsChange).to.eql([[{ added: [model], removed: [] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[model, collection]]);
|
||||||
|
expect(callsRemove).to.eql([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set existing items', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsAdd = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('add', (...args) => callsAdd.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2}]');
|
||||||
|
|
||||||
|
const model3 = new TestModel(3);
|
||||||
|
collection[1] = model3;
|
||||||
|
|
||||||
|
expect(collection.length).to.eql(2);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":3}]');
|
||||||
|
expect(callsChange).to.eql([[{ added: [model3], removed: [model2] }, collection]]);
|
||||||
|
expect(callsAdd).to.eql([[model3, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get items by id', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
expect(collection.get(1)).to.eql(model1);
|
||||||
|
expect(collection.get(2)).to.eql(model2);
|
||||||
|
expect(collection.get(3)).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove items', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
collection.remove(1);
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":2}]');
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model1] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model1, collection]]);
|
||||||
|
callsChange.length = 0;
|
||||||
|
callsRemove.length = 0;
|
||||||
|
|
||||||
|
collection.remove(model2);
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[]');
|
||||||
|
expect(callsChange).to.eql([[{ added: [], removed: [model2] }, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sort items by comparator', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const collection = new TestCollection([model1, model2]);
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2}]');
|
||||||
|
|
||||||
|
collection.comparator = (x, y) => x.id - y.id;
|
||||||
|
collection.sort();
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2}]');
|
||||||
|
|
||||||
|
collection.comparator = (x, y) => y.id - x.id;
|
||||||
|
collection.sort();
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":2},{"id":1}]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should splice items', () => {
|
||||||
|
const model1 = new TestModel(1);
|
||||||
|
const model2 = new TestModel(2);
|
||||||
|
const model3 = new TestModel(3);
|
||||||
|
const collection = new TestCollection([model1, model2, model3]);
|
||||||
|
|
||||||
|
const callsChange = [];
|
||||||
|
const callsAdd = [];
|
||||||
|
const callsRemove = [];
|
||||||
|
|
||||||
|
collection.on('change', (...args) => callsChange.push(args));
|
||||||
|
collection.on('add', (...args) => callsAdd.push(args));
|
||||||
|
collection.on('remove', (...args) => callsRemove.push(args));
|
||||||
|
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":2},{"id":3}]');
|
||||||
|
|
||||||
|
const model4 = new TestModel(4);
|
||||||
|
const model5 = new TestModel(5);
|
||||||
|
const model6 = new TestModel(6);
|
||||||
|
collection.splice(1, 1, model4, model5, model6);
|
||||||
|
|
||||||
|
expect(collection.length).to.eql(5);
|
||||||
|
expect(JSON.stringify(collection)).to.eql('[{"id":1},{"id":4},{"id":5},{"id":6},{"id":3}]');
|
||||||
|
expect(callsChange).to.eql([
|
||||||
|
[{ added: [model4, model5, model6], removed: [model2] }, collection]
|
||||||
|
]);
|
||||||
|
expect(callsAdd).to.eql([[model4, collection], [model5, collection], [model6, collection]]);
|
||||||
|
expect(callsRemove).to.eql([[model2, collection]]);
|
||||||
|
});
|
||||||
|
});
|
|
@ -11,6 +11,7 @@ const rootDir = path.join(__dirname, '..');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
|
devtool: 'source-map',
|
||||||
entry: path.resolve(__dirname, 'index.js'),
|
entry: path.resolve(__dirname, 'index.js'),
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
@ -22,5 +23,8 @@ module.exports = {
|
||||||
...appConfig.resolve.alias,
|
...appConfig.resolve.alias,
|
||||||
test: path.resolve(rootDir, 'test')
|
test: path.resolve(rootDir, 'test')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: appConfig.module.rules
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue