@difizen/mana-observable
Version:
266 lines (253 loc) • 7.26 kB
text/typescript
import 'react';
import assert from 'assert';
import {
prop,
Notifiable,
Notifier,
observable,
Observability,
ObservableProperties,
} from './index';
describe('observable', () => {
it('#observable properties', () => {
class Foo {
name = '';
}
const foo = observable(new Foo());
const instanceBasic = observable(foo);
const nullInstance = observable(null as any);
assert(!Observability.marked(nullInstance));
assert(Observability.marked(instanceBasic));
assert(Observability.marked(instanceBasic, 'name'));
assert(ObservableProperties.get(instanceBasic)?.includes('name'));
});
it('#extends properties', () => {
class ClassBasic {
name = '';
name1 = '';
name2 = '';
}
class ClassBasic1 extends ClassBasic {
override name1 = '';
}
class ClassBasic2 extends ClassBasic1 {
override name1 = '';
override name2 = '';
}
const instanceBasic = observable(new ClassBasic());
const instanceBasic1 = observable(new ClassBasic1());
const instanceBasic2 = observable(new ClassBasic2());
assert(ObservableProperties.get(instanceBasic)?.includes('name'));
assert(ObservableProperties.get(instanceBasic)?.length === 1);
assert(ObservableProperties.get(instanceBasic1)?.includes('name'));
assert(ObservableProperties.get(instanceBasic1)?.includes('name1'));
assert(ObservableProperties.get(instanceBasic1)?.length === 2);
assert(ObservableProperties.get(instanceBasic2)?.includes('name'));
assert(ObservableProperties.get(instanceBasic2)?.includes('name1'));
assert(ObservableProperties.get(instanceBasic2)?.includes('name2'));
assert(ObservableProperties.get(instanceBasic2)?.length === 3);
});
it('#basic usage', () => {
class ClassBasic {
name = '';
}
const instanceBasic = observable(new ClassBasic());
let changed = false;
const tracker = Notifier.find(instanceBasic, 'name');
tracker?.onChange(() => {
changed = true;
});
instanceBasic.name = 'a';
instanceBasic.name = 'b';
assert(instanceBasic.name === 'b');
assert(changed);
});
it('#array usage', () => {
class ClassArray {
list: string[] = [];
}
const instanceArray = observable(new ClassArray());
instanceArray.list = [];
let changed = false;
if (Notifiable.is(instanceArray.list)) {
const notifier = Notifiable.getNotifier(instanceArray.list);
notifier.onChange(() => {
changed = true;
});
}
const tracker = Notifier.find(instanceArray, 'list');
tracker?.onChange(() => {
changed = true;
});
instanceArray.list.push('');
assert(changed);
instanceArray.list = [];
assert(instanceArray.list.length === 0);
});
it('#property usage', () => {
class ClassArray {
enable = false;
}
const instance = observable(new ClassArray());
assert(Observability.marked(instance, 'enable'));
// instanceArray.enable = true;
let changeTimes = 0;
const notifier = Notifier.getOrCreate(instance, 'enable');
notifier.onChange(() => {
changeTimes += 1;
});
instance.enable = true;
assert(changeTimes === 1);
});
it('#child class', (done) => {
class Foo {
fooName = 'foo';
}
class Bar extends Foo {
barName?: string;
barInfo?: string;
}
const bar = observable(new Bar());
let changed = false;
const tracker = Notifier.find(bar, 'fooName');
tracker?.onChange(() => {
changed = true;
assert(changed);
done();
});
bar.fooName = 'foo name';
});
it('#shared properties', () => {
class Foo {
list: string[] = [];
}
class Bar {
list: string[] = [];
}
const foo = observable(new Foo());
const bar = observable(new Bar());
foo.list = bar.list;
let changed = false;
const notifier = Notifier.find(bar, 'list');
notifier?.onChange(() => {
changed = true;
});
foo.list.push('');
assert(changed);
});
it('#observable notifiable', () => {
const v: any[] = [];
class Foo {}
const foo = new Foo();
const notifiable = observable(v);
const notifiable1 = observable(v);
const notifiable2 = observable(notifiable);
assert(notifiable1 === notifiable2);
assert(notifiable === notifiable1);
const observableFoo = observable(foo);
assert(Notifiable.is(notifiable));
assert(Observability.marked(v));
assert(observableFoo === foo);
let changed = false;
const notifier = Notifier.find(notifiable);
notifier?.onChange(() => {
changed = true;
});
notifiable1.push('');
assert(changed);
});
it('#get notifier', () => {
const foo = {
a: {
b: {
c: 1,
},
},
};
const f = observable(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);
});
it('#observable nested', () => {
class Foo {
info = '';
}
class Bar {
obj: { foo: Foo | undefined } = {
foo: undefined,
};
}
const bar = new Bar();
const foo = new Foo();
let bChangeTimes = 0;
const b = observable(bar);
const bNotifier = Notifier.find(b, 'obj');
bNotifier?.onChange(() => {
bChangeTimes += 1;
});
let objChangeTimes = 0;
assert(Notifiable.is(b.obj));
const objNotifier = Notifiable.getNotifier(b.obj);
objNotifier?.onChange(() => {
objChangeTimes += 1;
});
bar.obj.foo = foo;
const f = observable(foo);
let fooChangeTimes = 0;
const fooNotifier = Notifier.find(f, 'info');
fooNotifier?.onChange(() => {
fooChangeTimes += 1;
});
foo.info = 'foo';
assert(b.obj === b.obj);
assert(bChangeTimes === 1);
assert(objChangeTimes === 1);
assert(fooChangeTimes === 1);
});
it('#observable nested obj', () => {
const foo = {
a: {
b: {
c: 1,
},
},
};
const f = observable(foo);
assert(Notifiable.is(f));
const fNotifier = Notifiable.getNotifier(f);
let fChangeTimes = 0;
fNotifier?.onChange(() => {
fChangeTimes += 1;
});
assert(Notifiable.is(f.a.b));
const bNotifier = Notifiable.getNotifier(f.a.b);
let bChangeTimes = 0;
bNotifier?.onChange(() => {
bChangeTimes += 1;
});
f.a.b.c = 2;
assert(fChangeTimes === 0);
assert(bChangeTimes === 1);
});
it('#observable property set', () => {
const arr: string[] = [];
class ClassBasic {
arr = arr;
}
const instance = observable(new ClassBasic());
let times = 0;
const notifier = Notifier.find(instance, 'arr');
notifier?.onChange(() => {
times += 1;
});
const observavleArr = observable(arr);
observavleArr.push(''); // 2
assert(times === 2);
instance.arr = []; //3
observavleArr.push('');
assert((times as number) === 3);
});
});