UNPKG

@tldraw/state

Version:

tldraw infinite canvas SDK (state).

200 lines (139 loc) • 4.57 kB
import { atom } from '../Atom' import { reactor } from '../EffectScheduler' import { getGlobalEpoch, transact, transaction } from '../transactions' import { RESET_VALUE } from '../types' describe('atoms', () => { it('contain data', () => { const a = atom('', 1) expect(a.get()).toBe(1) }) it('can be updated', () => { const a = atom('', 1) a.set(2) expect(a.get()).toBe(2) }) it('will not advance the global epoch on creation', () => { const startEpoch = getGlobalEpoch() atom('', 3) expect(getGlobalEpoch()).toBe(startEpoch) }) it('will advance the global epoch on .set', () => { const startEpoch = getGlobalEpoch() const a = atom('', 3) a.set(4) expect(getGlobalEpoch()).toBe(startEpoch + 1) }) it('can store history', () => { const a = atom('', 1, { historyLength: 3, computeDiff: (a, b) => b - a }) const startEpoch = getGlobalEpoch() expect(a.getDiffSince(startEpoch)).toEqual([]) a.set(5) expect(a.getDiffSince(startEpoch)).toEqual([+4]) a.set(10) expect(a.getDiffSince(startEpoch)).toEqual([+4, +5]) a.set(20) expect(a.getDiffSince(startEpoch)).toEqual([+4, +5, +10]) a.set(30) // will be RESET_VALUE because we don't have enough history expect(a.getDiffSince(startEpoch)).toEqual(RESET_VALUE) }) it('has history independent of other atoms', () => { const a = atom('', 1, { historyLength: 3, computeDiff: (a, b) => b - a }) const b = atom('', 1, { historyLength: 3, computeDiff: (a, b) => b - a }) const startEpoch = getGlobalEpoch() b.set(-5) b.set(-10) b.set(-20) expect(b.getDiffSince(startEpoch)).toEqual([-6, -5, -10]) expect(b.getDiffSince(getGlobalEpoch())).toEqual([]) expect(a.getDiffSince(startEpoch)).toEqual([]) a.set(5) expect(a.getDiffSince(startEpoch)).toEqual([+4]) expect(b.getDiffSince(startEpoch)).toEqual([-6, -5, -10]) expect(b.getDiffSince(getGlobalEpoch())).toEqual([]) }) it('still updates history during transactions', () => { const a = atom('', 1, { historyLength: 3, computeDiff: (a, b) => b - a }) const startEpoch = getGlobalEpoch() transact(() => { expect(a.getDiffSince(startEpoch)).toEqual([]) a.set(5) expect(a.getDiffSince(startEpoch)).toEqual([+4]) a.set(10) expect(a.getDiffSince(startEpoch)).toEqual([+4, +5]) a.set(20) expect(a.getDiffSince(startEpoch)).toEqual([+4, +5, +10]) }) expect(a.getDiffSince(startEpoch)).toEqual([+4, +5, +10]) }) it('will clear the history if the transaction aborts', () => { const a = atom('', 1, { historyLength: 3, computeDiff: (a, b) => b - a }) const startEpoch = getGlobalEpoch() transaction((rollback) => { expect(a.getDiffSince(startEpoch)).toEqual([]) a.set(5) expect(a.getDiffSince(startEpoch)).toEqual([+4]) rollback() }) expect(a.getDiffSince(startEpoch)).toEqual(RESET_VALUE) }) it('supports an update operation', () => { const startEpoch = getGlobalEpoch() const a = atom('', 1) a.update((value) => value + 1) expect(a.get()).toBe(2) expect(getGlobalEpoch()).toBe(startEpoch + 1) }) it('supports passing diffs in .set', () => { const a = atom('', 1, { historyLength: 3 }) const startEpoch = getGlobalEpoch() a.set(5, +4) expect(a.getDiffSince(startEpoch)).toEqual([+4]) a.set(6, +1) expect(a.getDiffSince(startEpoch)).toEqual([+4, +1]) }) it('does not push history if nothing changed', () => { const a = atom('', 1, { historyLength: 3 }) const startEpoch = getGlobalEpoch() a.set(5, +4) expect(a.getDiffSince(startEpoch)).toEqual([+4]) a.set(5, +4) expect(a.getDiffSince(startEpoch)).toEqual([+4]) }) it('clears the history buffer if you fail to provide a diff', () => { const a = atom('', 1, { historyLength: 3 }) const startEpoch = getGlobalEpoch() a.set(5, +4) expect(a.getDiffSince(startEpoch)).toEqual([+4]) a.set(6) expect(a.getDiffSince(startEpoch)).toEqual(RESET_VALUE) }) }) describe('reacting to atoms', () => { it('should work', async () => { const a = atom('', 234) let val = 0 const r = reactor('', () => { val = a.get() }) expect(val).toBe(0) r.start() expect(val).toBe(234) a.set(939) expect(val).toBe(939) r.stop() a.set(2342) expect(val).toBe(939) expect(a.get()).toBe(2342) }) }) test('isEqual can provide custom equality checks', () => { const foo = { hello: true } const bar = { hello: true } const a = atom('a', foo) a.set(bar) expect(a.get()).toBe(bar) const b = atom('b', foo, { isEqual: (a, b) => a.hello === b.hello }) b.set(bar) expect(b.get()).toBe(foo) })