stateshot
Version:
💾 Non-aggressive history state management with structure sharing.
226 lines (206 loc) • 5.53 kB
JavaScript
/* global test expect */
import { state2Record, record2State } from './transform'
test('transform between state and record', () => {
const state = {
id: 0,
name: 'root',
children: [
{ id: 1, name: 'a', children: [] },
{ id: 2, name: 'b', children: [] },
{
id: 3,
name: 'c',
children: [
{ id: 4, name: 'd', children: [] },
{ id: 5, name: 'e', children: [] }
]
}
]
}
const chunks = {}
const record = state2Record(state, chunks)
const resultState = record2State(record, chunks)
expect(resultState).toEqual(state)
})
test('transform invalid children data', () => {
const state = {
id: 0,
name: 'root',
children: [
{ id: 1, name: 'a', children: [] },
{ id: 2, name: 'b', children: [] },
{
id: 3,
name: 'c'
// no children
}
]
}
const chunks = {}
const record = state2Record(state, chunks)
const resultState = record2State(record, chunks)
expect(resultState).toEqual(state)
})
test('custom match children props', () => {
const state = {
id: 0,
name: 'root',
elements: [
{ id: 1, name: 'a', elements: [] },
{ id: 2, name: 'b', elements: [] },
{
id: 3,
name: 'c',
elements: [
{ id: 4, name: 'd', elements: [] },
{ id: 5, name: 'e', elements: [] }
]
}
]
}
const rules = [{
match: () => true,
toRecord: node => ({
chunks: [{ ...node, elements: undefined }],
children: node.elements
}),
fromRecord: ({ chunks, children }) => ({
...chunks[0],
elements: children
})
}]
const chunks = {}
const record = state2Record(state, chunks, rules)
const resultState = record2State(record, chunks, rules)
expect(resultState).toEqual(state)
})
test('support node splitting', () => {
const state = {
type: 'container',
children: [
{ type: 'image', left: 100, top: 100, image: 'foo' },
{ type: 'image', left: 200, top: 200, image: 'bar' },
{ type: 'image', left: 300, top: 300, image: 'baz' }
]
}
const rule = {
match: ({ type }) => type === 'image',
toRecord: node => ({
chunks: [
{ ...node, image: null },
node.image
]
}),
fromRecord: ({ chunks, children }) => ({
...chunks[0],
image: chunks[1]
})
}
const chunks = {}
const record = state2Record(state, chunks, [rule])
const resultState = record2State(record, chunks, [rule])
expect(resultState).toEqual(state)
expect(Object.keys(chunks).length).toEqual(1 + 3 * 2) // root + 2 * leaves
})
test('support multi rules', () => {
const state = {
type: 'container',
elements: [
{ type: 'image', left: 100, top: 100, image: 'foo' },
{ type: 'image', left: 200, top: 200, image: 'bar' },
{ type: 'image', left: 300, top: 300, image: 'baz' }
]
}
const rules = [
{
match: ({ type }) => type === 'image',
toRecord: node => ({
chunks: [
{ ...node, image: undefined },
node.image
]
// Omit children props.
}),
fromRecord: ({ chunks, children }) => ({
...chunks[0],
image: chunks[1]
})
},
{
match: ({ type }) => type === 'container',
toRecord: node => ({
chunks: [{ ...node, elements: undefined }],
children: node.elements
}),
fromRecord: ({ chunks, children }) => ({
...chunks[0],
elements: children
})
}
]
const chunks = {}
const record = state2Record(state, chunks, rules)
const resultState = record2State(record, chunks, rules)
expect(resultState).toEqual(state)
})
test('support single object', () => {
const state = {
type: 'image', left: 100, top: 100, image: 'foo'
}
const chunks = {}
const record = state2Record(state, chunks)
const resultState = record2State(record, chunks)
expect(resultState).toEqual(state)
})
test('support incremental chunk update', () => {
const state = {
id: 0,
name: 'root',
children: [
{ id: 1, name: 'a', children: [] },
{ id: 2, name: 'b', children: [] },
{
id: 3,
name: 'c',
children: [
{ id: 4, name: 'd', children: [] },
{ id: 5, name: 'e', children: [] }
]
}
]
}
const chunks = {}
state2Record(state, chunks)
expect(Object.keys(chunks).length).toEqual(6)
state.id = 100
state2Record(state, chunks)
expect(Object.keys(chunks).length).toEqual(7)
})
test('support record root children copy', () => {
const state = {
id: 0,
name: 'root',
children: [
{ id: 1, name: 'a', children: [] },
{ id: 2, name: 'b', children: [] },
{ id: 3, name: 'c', children: [] }
]
}
const chunks = {}
const record = state2Record(state, chunks)
state.children[0].id = 100
const newRecord = state2Record(state, chunks, [], record, 0)
const resultState = record2State(newRecord, chunks)
expect(resultState).toEqual(state)
})
test('support circular structure to JSON', () => {
const parent = { children: [], name: 'foo' }
const child = { parent, name: 'boo' }
parent.children.push(child)
const state = { parent }
const chunks = {}
const record = state2Record(state, chunks)
const resultState = record2State(record, chunks)
expect(resultState.parent.name).toEqual(parent.name)
expect(resultState.parent.children[0].name).toEqual(child.name)
})