UNPKG

@difizen/mana-observable

Version:

206 lines (192 loc) 6.07 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import assert from 'assert'; import { isPlainObject } from '@difizen/mana-common'; import { Notifiable, Notifier, Observability } from './index'; describe('reactivity', () => { it('#can be reactable', () => { class Foo {} const a = new Foo(); assert(!Notifiable.canBeNotifiable(a)); assert(!Notifiable.canBeNotifiable(null)); assert(!Notifiable.canBeNotifiable(undefined)); assert(Notifiable.canBeNotifiable([])); assert(Notifiable.canBeNotifiable({})); assert(Notifiable.canBeNotifiable(new Map())); const arrValue = Notifiable.transform([]); assert(Notifiable.canBeNotifiable(arrValue)); }); it('#transform base', () => { const tValue = Notifiable.transform(undefined); assert(tValue === undefined); if (tValue) { assert(Notifiable.getNotifier(tValue) === undefined); } const arr = ['a']; const arrValue = Notifiable.transform(arr); const arrNotifier = Notifiable.tryGetNotifier(arrValue); const arrValue1 = Notifiable.transform(arr); const arrNotifier1 = Notifiable.tryGetNotifier(arrValue1); assert(Notifiable.canBeNotifiable(arr)); assert(Notifiable.is(arrValue)); assert(!!arrNotifier); assert(arrValue !== arr); assert(arrValue1 === arrValue); assert(arrNotifier1 === arrNotifier); const arrValue2 = Notifiable.transform(arrValue); const arrNotifier2 = Notifiable.tryGetNotifier(arrValue2); assert(arrNotifier === arrNotifier2); assert(arrValue === arrValue2); class A {} const a = new A(); const objValue = Notifiable.transform(a); const objNotifier = Notifiable.tryGetNotifier(objValue); assert(!objNotifier); assert(a === objValue); }); it('#do not transform frozen', () => { const fObj = Object.freeze({}); const fArr = Object.freeze([fObj]); const obj = { a: fArr, o: fObj, }; const arr = [fArr, fObj]; const tValue = Notifiable.transform(obj); const tArr = Notifiable.transform(arr); const tFArr = Notifiable.transform(fArr); assert(tValue.a === fArr); assert(tValue.o === fObj); assert(tArr[0] === fArr); assert(tArr[1] === fObj); assert(tFArr[0] === fObj); }); it('#runtime frozen', () => { const obj = {}; const arr = [obj]; const foo = { a: arr, o: obj, }; Object.freeze(obj); Object.freeze(arr); const tValue = Notifiable.transform(foo); const tArr = Notifiable.transform(arr); assert(tValue.a === arr); assert(tValue.o === obj); assert(tArr[0] === obj); }); it('#transform array', () => { const v: any[] = []; const tValue = Notifiable.transform(v); assert(tValue instanceof Array); assert(Notifiable.is(tValue)); assert(Observability.getOrigin(tValue) === v); }); it('#transform array nested', () => { const v: any[] = [[]]; const tValue = Notifiable.transform(v); assert(tValue[0] instanceof Array); assert(Notifiable.is(tValue[0])); }); it('#transform map', () => { const v: Map<string, string> = new Map(); const tValue = Notifiable.transform(v); assert(tValue instanceof Map); assert(Notifiable.is(tValue)); assert(Observability.getOrigin(tValue) === v); }); it('#transform map nested', () => { const v: Map<string, any> = new Map(); v.set('a', {}); const tValue = Notifiable.transform(v); assert(tValue instanceof Map); assert(Notifiable.is(tValue.get('a'))); }); it('#transform plain object', () => { const v = {}; const tValue = Notifiable.transform(v); assert(isPlainObject(tValue)); assert(Notifiable.is(tValue)); assert(Observability.getOrigin(tValue) === v); }); it('#transform plain object nested', () => { const v = { a: {} }; const tValue = Notifiable.transform(v); assert(isPlainObject(tValue.a)); assert(Notifiable.is(tValue.a)); }); it('#array notifier', () => { const v: any[] = []; const tValue = Notifiable.transform(v); const notifier = Notifiable.tryGetNotifier(tValue); let changedTimes = 0; if (notifier) { notifier.onChange(() => { changedTimes += 1; }); } // Pushing brings changes, one is the set value and the other is the set length tValue.push('a'); tValue.pop(); assert(tValue.length === 0); assert(changedTimes === 3); }); it('#map notifier', () => { const v: Map<string, string> = new Map(); const tValue = Notifiable.transform(v); const notifier = Notifiable.tryGetNotifier(tValue); let changedTimes = 0; if (notifier) { notifier.onChange(() => { changedTimes += 1; }); } tValue.set('a', 'a'); const aValue = tValue.get('a'); assert(aValue === 'a'); assert(tValue.size === 1); tValue.set('b', 'b'); tValue.delete('a'); tValue.clear(); assert(changedTimes === 4); }); it('#plainObject notifier', () => { const v: Record<any, any> = { a: '', b: { c: '' }, d: '' }; const tValue = Notifiable.transform(v); const notifier = Notifiable.tryGetNotifier(tValue); const tValue1 = Notifiable.transform(v['b']); const notifier1 = Notifiable.tryGetNotifier(tValue1); let changedTimes = 0; if (notifier) { notifier.onChange(() => { changedTimes += 1; }); } if (notifier1) { notifier1.onChange(() => { changedTimes += 1; }); } tValue['a'] = 'a'; assert(tValue['a'] === 'a'); tValue['b'].c = 'c'; assert(tValue['b'].c === 'c'); delete tValue['d']; assert(changedTimes === 3); }); it('#get notifier', () => { const foo = { a: { b: { c: 1, }, }, }; const f = Notifiable.transform(foo); assert(Notifiable.is(f.a.b)); const notifier = Notifiable.getNotifier(f.a.b); const originalB = Observability.getOrigin(f.a.b); const maybeNewNotifier = Notifier.getOrCreate(originalB); assert(notifier === maybeNewNotifier); }); });