@dvo/raven
Version:
A simple store and databinding tool for vanilla applications.
384 lines (354 loc) • 10 kB
JavaScript
import raven from '../src/index.js'
const evChange = (el, value) => {
el.value = value
const ev = new Event('change')
el.dispatchEvent(ev)
}
describe('Testing functionalities.', () => {
test('Store can be loaded.', () => {
const store = { a: 1 }
raven.load(store)
expect(raven.store).toEqual(store)
})
test('Store can be reloaded.', () => {
const storeA = { a: 1 }
raven.load(storeA)
const storeB = { b: 1 }
raven.load(storeB)
expect(raven.store).toEqual(storeB)
})
test('Can use set to add simple data to the store with object request.', () => {
const store = { a: 1 }
raven.load(store)
raven.set({ b: 2 })
expect(raven.store).toEqual({ a: 1, b: 2 })
})
test('Can use set to add simple data to the store with string request.', () => {
const store = { a: 1}
raven.load(store)
raven.set('b.c', 2)
expect(raven.store).toEqual({ a: 1, b: { c: 2 } })
})
test('Can use set to add complex data to the store with object request.', () => {
const store = { a: { b: 1, c: 2 } }
raven.load(store)
raven.set({ a: { c: 10, d: 20 } })
expect(raven.store).toEqual({ a: { b: 1, c: 10, d: 20 } })
})
test('Can use set to add complex data to the store with string request.', () => {
const store = { a: { b: 1, c: 2 } }
raven.load(store)
raven.set('a.c', 10)
expect(raven.store).toEqual({ a: { b: 1, c: 10 } })
})
test('Can subscribe a callback.', () => {
const fakeFunction = () => {}
raven.clear()
raven.subscribe({ a: { b: 1 } }, fakeFunction)
expect(raven.funcs.subscriptions).toEqual({
'a.b': [fakeFunction]
})
})
test('Can subscribe a callback to multiple targets.', () => {
const fakeFunction = () => {}
raven.clear()
raven.subscribe({ a: { b: 1, c: 2 }, d: 3 }, fakeFunction)
expect(raven.funcs.subscriptions).toEqual({
'a.b': [fakeFunction],
'a.c': [fakeFunction],
'd': [fakeFunction]
})
})
test('Can subscribe a callback using a string path.', () => {
const fakeFunction = () => {}
raven.clear()
raven.subscribe('a.b', fakeFunction)
expect(raven.funcs.subscriptions).toEqual({
'a.b': [fakeFunction]
})
})
test('Can clear all subscribed callbacks.', () => {
const fakeFunction = () => {}
raven.subscribe({ a: 1 }, fakeFunction)
raven.clear()
expect(raven.funcs.subscriptions).toEqual({})
})
test('Can execute a simple callback.', () => {
let flag = false
raven.clear()
raven.load({ a: 1 })
raven.subscribe({ a: 1 }, () => flag = true)
raven.set('a', 2)
expect(flag).toBe(true)
})
test('Can execute a multiple callbacks.', () => {
let count = 0
raven.clear()
raven.load({
a: {
b: {
c: 1,
d: 2,
e: 3
},
f: {
g: 4,
h: 5
}
}
})
raven.subscribe({
a: {
b: {
c: 1,
e: 3
},
f: {
g: 4
}
}
}, () => count += 1)
raven.set({
a: {
b: {
c: 8
},
f: {
g: 9,
},
i: 10
},
j: 11
})
expect(count).toBe(2)
})
test('Executes callbacks of partial paths.', () => {
let count = 0
raven.clear()
raven.load({
a: { b: { c: 1 } }
})
raven.subscribe('a', () => count += 1)
raven.set('a.b.c', 2)
expect(count).toBe(1)
})
test('Callbacks are executed with new simple state as parameter.', () => {
raven.clear()
raven.load({
a: {
b: 1
}
})
let argument = false
const callback = x => argument = x
raven.subscribe('a.b', callback)
raven.set('a.b', 'newValue')
expect(argument).toBe('newValue')
})
test('Callbacks are executed with new complex state as parameter.', () => {
raven.clear()
raven.load({
a: {
b: 1
}
})
let argument = false
const callback = x => argument = x
raven.subscribe('a', callback)
raven.set('a.b', 'newValue')
expect(argument).toEqual({ b: 'newValue' })
})
test('Callbacks are executed when array changes.', () => {
const state = {
a: {
b: [1, 2]
}
}
raven.clear()
raven.load(state)
let argument = false
const callback = x => argument = x
raven.subscribe('a', callback)
raven.set('a.b', [...state.a.b, 3])
expect(argument).toEqual({ b: [1, 2, 3] })
})
test('Callbacks are executed when object inside array changes.', () => {
const state = {
a: {
b: [{ c: 3 }]
}
}
raven.clear()
raven.load(state)
let argument = false
const callback = x => argument = x
raven.subscribe('a', callback)
raven.set('a.b', [{...state.a.b[0], d: 4 } ])
expect(argument).toEqual({ b: [{ c: 3, d: 4 }] })
})
test('Can push data change from object to store.', () => {
const state = { a: { b: 'original' } }
const externalObject = { prop: 'toBeOverWritten' }
raven.clear()
raven.load(state)
raven.push({
target: externalObject,
prop: 'prop'
}, { a : { b: 1 } })
expect(raven.store.a.b).toBe('toBeOverWritten')
externalObject.prop = 'overWrittenValue'
expect(raven.store).toEqual({ a: { b: 'overWrittenValue' } })
})
test('Can push data change from object to store with a string path.', () => {
const state = { a: { b: 'original' } }
const externalObject = { prop: 'toBeOverWritten' }
raven.clear()
raven.load(state)
raven.push({
target: externalObject,
prop: 'prop'
}, 'a.b')
expect(raven.store.a.b).toBe('toBeOverWritten')
externalObject.prop = 'overWrittenValue'
expect(raven.store).toEqual({ a: { b: 'overWrittenValue' } })
})
test('Can pull data from store.', () => {
const store = { a: { b: 'beforeChange' } }
document.body.innerHTML = `<div id="dom-element"></div>`
const div = document.querySelector('#dom-element')
raven.clear()
raven.load(store)
raven.pull('a.b', {
target: div,
prop: 'textContent'
})
expect(div.textContent).toBe('beforeChange')
raven.set({
a: { b: 'afterChange' }
})
expect(div.textContent).toBe('afterChange')
})
test('Can pull data from store using simple object.', () => {
const store = { a: { b: 'beforeChange' } }
document.body.innerHTML = `<div id="dom-element"></div>`
const div = document.querySelector('#dom-element')
raven.clear()
raven.load(store)
raven.pull({ a: { b: true } }, {
target: div,
prop: 'textContent'
})
expect(div.textContent).toBe('beforeChange')
raven.set({
a: { b: 'afterChange' }
})
expect(div.textContent).toBe('afterChange')
})
test('Expect an error is pulled ambiguous object.', () => {
const store = { a: 1, b: 2 }
document.body.innerHTML = `<div id="dom-element"></div>`
const div = document.querySelector('#dom-element')
raven.clear()
raven.load(store)
expect(() =>
raven.pull(
{ a: 3, b: 4 },
{
target: div,
prop: 'textContent'
},
x => x
)
).toThrow()
})
test("Sync'd element can push changes to the store.", () => {
document.body.innerHTML = `<input id="dom-input"></div>`
const element = document.querySelector('#dom-input')
raven.clear()
raven.load({
value: 'beforeChange'
})
raven.sync('value', {
target: element,
prop: 'value'
})
evChange(element, 'afterChange')
expect(raven.store.value).toBe('afterChange')
})
test("Sync'd element can pull changes from the store.", () => {
document.body.innerHTML = `<input id="dom-input">`
const element = document.querySelector('#dom-input')
raven.clear()
raven.load({
value: 'beforeChange'
})
raven.sync('value', {
target: element,
prop: 'value'
})
raven.set({ 'value': 'afterChange' })
expect(element.value).toBe('afterChange')
})
test("Sync'd element stays in sync after data goes both ways.", () => {
document.body.innerHTML = `<input id="dom-input">`
const element = document.querySelector('#dom-input')
raven.clear()
raven.load({
value: 'beforeChange'
})
raven.sync('value', {
target: element,
prop: 'value'
})
raven.set({ 'value': 'afterChange' })
expect(element.value).toBe('afterChange')
evChange(element, 'afterSecondChange')
expect(raven.store.value).toBe('afterSecondChange')
})
test("Can clear all registered callbaks.", () => {
const func = () => {}
raven.clear()
raven.load({ a: 0, b: 0 })
raven.subscribe('a', func)
raven.subscribe('b', func)
raven.clear()
expect(raven.funcs.subscriptions).toEqual({})
})
test("Can clear registered callbaks from a specific path.", () => {
const func = () => {}
raven.clear()
raven.load({ a: 0, b: 0 })
raven.subscribe('a', func)
raven.subscribe('b', func)
raven.clear('b')
expect(Object.keys(raven.funcs.subscriptions)).toEqual(['a'])
})
test("Can clear registered callbaks by function.", () => {
const funcA = () => {}
const funcB = () => {}
raven.clear()
raven.load({ a: 0 })
raven.subscribe('a', funcA)
raven.subscribe('a', funcB)
raven.clear(funcA)
expect(raven.funcs.subscriptions.a).toEqual([funcB])
})
test("Can clear callbacks with an array of conditions.", () => {
const funcA = () => {}
const funcB = () => {}
const funcC = () => {}
raven.clear()
raven.load({ a: 0, b: 0, c: 0 })
raven.subscribe('a', funcA)
raven.subscribe('a', funcB)
raven.subscribe('b', funcB)
raven.subscribe('b', funcC)
raven.subscribe('c', funcA)
raven.subscribe('c', funcC)
raven.clear(['a', funcB])
expect(raven.funcs.subscriptions).toEqual({
b: [funcC],
c: [funcA, funcC]
})
})
})