mutant
Version:
Create observables and map them to DOM elements. Massively inspired by hyperscript and observ-*. No virtual dom, just direct observable bindings. Unnecessary garbage collection is avoided by using mutable objects instead of blasting immutable junk all ove
138 lines (107 loc) • 3.08 kB
JavaScript
require('setimmediate')
require('source-map-support').install()
var test = require('tape')
var TypedCollection = require('../typed-collection')
var Struct = require('../struct')
var Value = require('../value')
var resolve = require('../resolve')
test('typed-collection', function(t) {
var types = {
Cat () {
return Struct({
id: Value(),
age: Value()
})
},
Dog () {
return Struct({
id: Value(),
age: Value()
})
}
}
var added = []
var removed = []
var state = TypedCollection((value) => types[value.type](), {
matcher: (value) => value.id,
invalidator: (current, newValue) => current.type != newValue.type,
onAdd: (obj) => added.push(obj),
onRemove: (obj) => removed.push(obj),
})
state.set([
{id: 1, age: 2, type: 'Dog'},
{id: 2, age: 9, type: 'Cat'}
])
t.deepEqual(state(), [
{id: 1, age: 2, type: 'Dog'},
{id: 2, age: 9, type: 'Cat'}
], 'Initial state')
t.equal(added.length, 2, 'Two new items added')
added.length = 0
// reverse order, dog is now one year older!
state.set([
{id: 2, age: 9, type: 'Cat'},
{id: 1, age: 3, type: 'Dog'}
])
// no new items created
t.equal(added.length, 0, 'No new items added')
added.length = 0
t.deepEqual(state(), [
{id: 2, age: 9, type: 'Cat'},
{id: 1, age: 3, type: 'Dog'}
], 'Order reversed, 2 is updated')
// model order changed
t.equal(state.get(0).id(), 2, 'item moved')
t.equal(state.get(1).id(), 1, 'item moved')
state.set([
{id: 1, age: 3, type: 'Cat'},
{id: 2, age: 9, type: 'Cat'}
])
t.deepEqual(state(), [
{id: 1, age: 3, type: 'Cat'},
{id: 2, age: 9, type: 'Cat'}
], 'Order updated, both items are now cats')
t.deepEqual(removed.map(resolve), [
{id: 1, age: 3, type: 'Dog'}
])
t.deepEqual(added.map(resolve), [
{id: 1, age: 3, type: 'Cat'}
])
added.length = 0
removed.length = 0
t.equal(state.get(0).id(), 1)
t.equal(state.get(1).id(), 2)
state.move(state.get(1), 0)
t.deepEqual(state(), [
{id: 2, age: 9, type: 'Cat'},
{id: 1, age: 3, type: 'Cat'}
], 'Item moved')
state.insert({id: 0, type: 'Dog', age: 1}, 0)
t.deepEqual(state(), [
{id: 0, age: 1, type: 'Dog'},
{id: 2, age: 9, type: 'Cat'},
{id: 1, age: 3, type: 'Cat'}
], 'Item inserted')
t.deepEqual(added.map(resolve), [
{id: 0, age: 1, type: 'Dog'}
])
added.length = 0
let addCount = 0
const removeAddListener = state.onAdd((item) => {addCount += 1})
state.push({id: 3, type: 'Dog', age: 2})
t.equal(addCount, 1, 'onAdd listener got event')
t.deepEqual(added.map(resolve), [
{id: 3, age: 2, type: 'Dog'}
], 'item added')
t.deepEqual(state(), [
{id: 0, age: 1, type: 'Dog'},
{id: 2, age: 9, type: 'Cat'},
{id: 1, age: 3, type: 'Cat'},
{id: 3, age: 2, type: 'Dog'}
], 'Item pushed')
added.length = 0
removeAddListener()
state.push({id: 4, type: 'Dog', age: 2})
t.equal(addCount, 1, 'onAdd not called after remove listener')
t.end()
})