(fn: () => T, name: string, props: any, debug = false) {
const { 0: value, 1: render } = useState(0)
- const work = useCallback(fn, [])
+ const work = useCallback(fn, [props])
const cb = useCallback((reason?: Set) => {
- render((prev) => 1 - prev)
if (debug) {
- console.info(`${debugName} will re-render because of changes:`, reason)
+ console.info(`${name} will re-render because of changes:`, reason)
}
+ render((prev) => prev + 1) // 1 - prev
}, [])
- let renderResult!: T
- const { dispose, stats, exception, result } = ObservableTransactions.transaction(work, cb)
- renderResult = result
- if (debug) {
- const plainReads = new Map()
- stats.read.forEach((keys, adm) => {
- plainReads.set(adm[Symbol.for('whoami')], keys)
- })
- console.info(`${debugName} was rendered ${stats.count} times.`, plainReads)
- }
+ let TR!: TransactionResult
useEffect(() => {
return () => {
- dispose()
+ TR?.dispose()
if (debug) {
- console.info(`${debugName} was unmount`)
+ console.info(`${name} was unmount`)
}
}
- }, []);
+ }, []); // toDo maybe props
+
+ TR = ObservableTransactions.transaction(work, cb, false)
+
+ if (debug) {
+ const plainReads = new Map()
+ TR.stats.read.forEach((keys, adm) => {
+ plainReads.set(adm[Symbol.for('whoami')], keys)
+ })
+ console.info(`${name} was rendered ${TR.stats.count} times.`, plainReads)
+ }
- if (exception) {
- console.error(`In > ${name}`, exception)
- throw exception;
+ if (TR.exception) {
+ console.error(`In > ${name}`, TR.exception)
+ throw TR.exception;
}
- return renderResult
+ return TR.result
}
export function observer(
- rc: ForwardRefExoticComponent & RefAttributes>, options?: ObserverOptions
+ rc: ForwardRefExoticComponent & RefAttributes>, debug?: boolean
): MemoExoticComponent & RefAttributes>>
-export function observer(rc: FunctionComponent
, options?: ObserverOptions): FunctionComponent
+export function observer
(rc: FunctionComponent
, debug?: boolean): FunctionComponent
export function observer(
rc: ForwardRefRenderFunction | FunctionComponent | ForwardRefExoticComponent & RefAttributes>,
- options?: ObserverOptions
+ debug = false
) {
- let observedComponent = (props: any, ref: Ref) => useObservable(() => rc(props, ref), rc.name, options)
- observedComponent = memo(observedComponent)
- return observedComponent
+ let observedComponent = (props: any, ref: Ref) => useObservable(() => rc(props, ref), rc.name, props, debug)
+ // observedComponent = memo(observedComponent)
+ return memo(observedComponent)
}
diff --git a/src/tests/Observable.test.ts b/src/tests/Observable.test.ts
index 01a85b8..7454ea6 100644
--- a/src/tests/Observable.test.ts
+++ b/src/tests/Observable.test.ts
@@ -1,374 +1,372 @@
import { describe, test } from 'node:test'
import expect from 'node:assert';
-import { Observable, makeObservable } from '../Observable';
+import { Observable, makeObservable } from '../Observable.js';
+
+// describe('Observable', () => {
+// test('Should pass "instanceof" check',() => {
+// class Foo extends Observable {}
+// const foo = new Foo()
+// expect.equal(foo instanceof Observable, true)
+// expect.equal(foo instanceof Foo, true)
+// })
+//
+// test('Should notify sync',(ctx) => {
+// class Foo extends Observable { a = 1 }
+// const foo = new Foo()
+// const subscriber = ctx.mock.fn()
+// foo.subscribe(subscriber, new Set(['a']))
+// foo.a = 2
+// ctx.diagnostic(`${foo.a}`)
+// expect.equal(subscriber.mock.callCount(), 1)
+// })
+//
+// test('subscribe',(ctx) => {
+// class Foo extends Observable {
+// name = ''
+// age = 42
+// city = 'Moscow'
+//
+// setAll() {
+// this.city = 'Texas'
+// this.age = 52
+// this.name = 'Egor'
+// this.city = 'London'
+// }
+//
+// async setAsynchronously() {
+// this.name = 'John'
+// this.city = 'Rome'
+// return true
+// }
+// }
+// const foo = new Foo()
+//
+// const subscriber = ctx.mock.fn()
+// foo.subscribe(subscriber, new Set(['name', 'city', 'surname']))
+//
+// // foo.setAll()
+// // expect.equal(subscriber.mock.callCount(), 1)
+//
+// ctx.test('Should be called once per synchronous transaction',() => {
+// foo.setAll()
+// expect.equal(subscriber.mock.callCount(), 1)
+// })
+//
+// ctx.test('Should not be called when changing a property that we are not subscribed to',() => {
+// subscriber.mock.resetCalls()
+// foo.age = 62 // We are not subscribed to age
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+//
+// ctx.test('Should be called twice when transaction was interrupted by Promise', async () => {
+// subscriber.mock.resetCalls()
+// await foo.setAsynchronously()
+// expect.equal(subscriber.mock.callCount(), 2)
+// })
+//
+// ctx.test('Should not be called when properties were changed with same values', async () => {
+// subscriber.mock.resetCalls()
+// await foo.setAsynchronously()
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+//
+// ctx.test('Should be called for each subscriber', async () => {
+// subscriber.mock.resetCalls()
+//
+// const subscriber2 = ctx.mock.fn()
+// foo.subscribe(subscriber2, new Set(['name', 'city']))
+//
+// foo.city = 'Seoul'
+// foo.name = 'Choi'
+// expect.equal(subscriber.mock.callCount(), 1)
+// expect.equal(subscriber2.mock.callCount(), 1)
+// foo.unsubscribe(subscriber2)
+// })
+//
+// ctx.test('Should not be called after unsubscribe', async () => {
+// subscriber.mock.resetCalls()
+// foo.unsubscribe(subscriber)
+// foo.city = 'Beijing'
+// foo.name = 'Chan'
+// // await delay(10)
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+// })
+//
+// // test('listen',async (ctx) => {
+// // const listener = ctx.mock.fn()
+// // foo.listen(listener)
+// // foo.setAll()
+// //
+// // await ctx.test('Should be called on each change', () => {
+// // expect.equal(listener.mock.callCount(), 4)
+// // })
+// //
+// // await ctx.test('Should not be called after unlisten', () => {
+// // listener.mock.resetCalls()
+// // foo.unlisten(listener)
+// // foo.setAll()
+// // expect.equal(listener.mock.callCount(), 0)
+// // })
+// // })
+// })
+
+// describe('Observable Map', () => {
+// class WithMap extends Observable {
+// map = new Map()
+// }
+//
+// const firstKey = 'firstKey'
+// const secondKey = 'secondKey'
+//
+// const withMap = new WithMap()
+//
+// test('Should notify when Map changes', async (ctx) => {
+// const onSizeChange = ctx.mock.fn()
+// withMap.subscribe(onSizeChange, new Set(['map']))
+//
+// withMap.map.set('hello', 'world')
+// await delay(10)
+//
+// withMap.map.set('hello', 'javascript') // adding new value to the existed key
+// await delay(10)
+// // expected behaviour
+// // the size doesn't change, but the map in fact is
+// // because map can be used like this [...map.values()].map(...)
+// expect.equal(onSizeChange.mock.callCount(), 2)
+//
+// withMap.map.clear()
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 3)
+//
+// withMap.map = new Map()
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 4)
+// })
+//
+// test('Should notify when specific item is added, changed or removed', async (ctx) => {
+// const onFirstKeyChange = ctx.mock.fn()
+// withMap.subscribe(onFirstKeyChange, new Set(['map.firstKey']))
+//
+// withMap.map.set(firstKey, firstKey)
+// await delay(10)
+// expect.equal(onFirstKeyChange.mock.callCount(), 1)
+//
+// withMap.map.set(firstKey, 'blah blah blah')
+// await delay(10)
+// // adding new item to map doesn't trigger subscriber,
+// expect.equal(onFirstKeyChange.mock.callCount(), 2)
+//
+// withMap.map.delete(firstKey)
+// await delay(10)
+// expect.equal(onFirstKeyChange.mock.callCount(), 3)
+// withMap.unsubscribe(onFirstKeyChange)
+// })
+//
+// test('Should not notify when other items were changed', async (ctx) => {
+// const onFirstKeyChange = ctx.mock.fn()
+// withMap.subscribe(onFirstKeyChange, new Set(['map.firstKey']))
+//
+// withMap.map.set(firstKey, 'some value')
+// await delay(10)
+// expect.equal(onFirstKeyChange.mock.callCount(), 1)
+//
+// withMap.map.set(secondKey, 'blah blah blah')
+// await delay(10)
+// // adding new item to map doesn't trigger subscriber,
+// expect.equal(onFirstKeyChange.mock.callCount(), 1)
+// })
+// })
+
+// describe('Observable plain object', () => {
+// const foo = makeObservable({
+// name: '',
+// age: 42,
+// city: 'Moscow',
+//
+// setAll() {
+// this.city = 'Texas'
+// this.age = 52
+// this.name = 'Egor'
+// this.city = 'London'
+// },
+//
+// async setAsynchronously() {
+// this.name = 'John'
+// await delay(100)
+// this.city = 'Rome'
+// return true
+// }
+// })
+//
+//
+// test('subscribe',async (ctx) => {
+// const subscriber = ctx.mock.fn()
+//
+// foo.subscribe(subscriber, new Set(['name', 'city', 'surname']))
+// foo.setAll()
+//
+// await ctx.test('Should be called once per synchronous transaction', async () => {
+// await delay(10)
+// expect.equal(subscriber.mock.callCount(), 1)
+// })
+//
+// await ctx.test('Should not be called when changing a property that we are not subscribed to', async () => {
+// subscriber.mock.resetCalls()
+// foo.age = 62 // We are not subscribed to age
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+//
+// await ctx.test('Should be called twice when transaction was interrupted by Promise', async () => {
+// subscriber.mock.resetCalls()
+// await foo.setAsynchronously()
+// await delay(10)
+// expect.equal(subscriber.mock.callCount(), 2)
+// })
+//
+// await ctx.test('Should not be called when properties were changed with same values', async () => {
+// subscriber.mock.resetCalls()
+// await foo.setAsynchronously()
+// await delay(10)
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+//
+// await ctx.test('Should be called for each subscriber', async () => {
+// subscriber.mock.resetCalls()
+//
+// const subscriber2 = ctx.mock.fn()
+// foo.subscribe(subscriber2, new Set(['name', 'city']))
+//
+// foo.city = 'Seoul'
+// foo.name = 'Choi'
+//
+// await delay(10)
+// expect.equal(subscriber.mock.callCount(), 1)
+// expect.equal(subscriber2.mock.callCount(), 1)
+//
+// foo.unsubscribe(subscriber2)
+// })
+//
+// await ctx.test('Should not be called after unsubscribe', async () => {
+// subscriber.mock.resetCalls()
+// foo.unsubscribe(subscriber)
+// foo.city = 'Beijing'
+// foo.name = 'Chan'
+// await delay(10)
+// expect.equal(subscriber.mock.callCount(), 0)
+// })
+// })
+//
+// test('listen',async (ctx) => {
+// const listener = ctx.mock.fn()
+// foo.listen(listener)
+// foo.setAll()
+//
+// await ctx.test('Should be called on each change', () => {
+// expect.equal(listener.mock.callCount(), 4)
+// })
+//
+// await ctx.test('Should not be called after unlisten', () => {
+// listener.mock.resetCalls()
+// foo.unlisten(listener)
+// foo.setAll()
+// expect.equal(listener.mock.callCount(), 0)
+// })
+// })
+// })
+
+// describe('Observable Array', () => {
+//
+// test('Should notify when add item by push', async (ctx) => {
+// class WithArray extends Observable {
+// array = []
+// }
+// const withArray = new WithArray()
+// const onSizeChange = ctx.mock.fn()
+// withArray.subscribe(onSizeChange, new Set(['array']))
+// await delay(10)
+// withArray.array.push(9)
+// withArray.array.push(10)
+// withArray.array.push(11,12,13)
+// await delay(2)
+// expect.equal(onSizeChange.mock.callCount(), 1)
+// withArray.array = []
+// })
+//
+// test('Should notify when set item by index', async (ctx) => {
+// class WithArray extends Observable {
+// array: any[] = []
+// }
+// const withArray = new WithArray()
+// const onSizeChange = ctx.mock.fn()
+// withArray.subscribe(onSizeChange, new Set(['array']))
+//
+// withArray.array.set(0, { foo: 'bar' })
+// await delay(2)
+//
+// expect.equal(onSizeChange.mock.callCount(), 1)
+// onSizeChange.mock.resetCalls()
+// withArray.unsubscribe(onSizeChange)
+// withArray.array = []
+// })
+//
+// test('Should notify on splice', async (ctx) => {
+// class WithArray extends Observable {
+// array = []
+// }
+// const withArray = new WithArray()
+// const onSizeChange = ctx.mock.fn()
+// withArray.array = [1,2,3]
+// withArray.subscribe(onSizeChange, new Set(['array']))
+//
+// withArray.array.splice(0,2)
+// await delay(10)
+//
+// expect.equal(onSizeChange.mock.callCount(), 1)
+// onSizeChange.mock.resetCalls()
+// withArray.unsubscribe(onSizeChange)
+// withArray.array = []
+// })
+//
+// test('Should notify on shift and pop', async (ctx) => {
+// class WithArray extends Observable {
+// array = []
+// }
+// const withArray = new WithArray()
+// const onSizeChange = ctx.mock.fn()
+// withArray.array = [1,2,3]
+// withArray.subscribe(onSizeChange, new Set(['array']))
+//
+// withArray.array.shift()
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 1)
+//
+// withArray.array.pop()
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 2)
+// onSizeChange.mock.resetCalls()
+// withArray.unsubscribe(onSizeChange)
+// withArray.array = []
+// })
+//
+// test('Should notify on sort and reverse', async (ctx) => {
+// class WithArray extends Observable {
+// array = []
+// }
+// const withArray = new WithArray()
+// const onSizeChange = ctx.mock.fn()
+// withArray.array = [1,2,3]
+// withArray.subscribe(onSizeChange, new Set(['array']))
+//
+// withArray.array.sort((a, b) => b - a)
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 1)
+//
+// withArray.array.reverse()
+// await delay(10)
+// expect.equal(onSizeChange.mock.callCount(), 2)
+// withArray.unsubscribe(onSizeChange)
+// withArray.array = []
+// })
+// })
-// Observable notify subscribers in setTimeout. It takes some time, that's why we need delay in tests
-const delay = (ms: number) => new Promise((resolve) => setTimeout(() => resolve(true), ms));
-
-describe('Observable', () => {
- class Foo extends Observable {
- name = ''
- age = 42
- city = 'Moscow'
- arr = [1,2]
-
- swap(){
- const i = this.arr[0]
- this.arr[0] = this.arr[1]
- this.arr[1] = i
- }
-
- setAll() {
- this.city = 'Texas'
- this.age = 52
- this.name = 'Egor'
- this.city = 'London'
- }
-
- async setAsynchronously() {
- this.name = 'John'
- await delay(100)
- this.city = 'Rome'
- return true
- }
- }
- const foo = new Foo()
-
- test('Should pass "instanceof" check', async (ctx) => {
- expect.equal(foo instanceof Observable, true)
- expect.equal(foo instanceof Foo, true)
- })
-
- test('subscribe',async (ctx) => {
- const subscriber = ctx.mock.fn()
-
- foo.subscribe(subscriber, new Set(['name', 'city', 'surname']))
- foo.setAll()
-
- await ctx.test('Should be called once per synchronous transaction', async () => {
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 1)
- })
-
- await ctx.test('Should not be called when changing a property that we are not subscribed to', async () => {
- subscriber.mock.resetCalls()
- foo.age = 62 // We are not subscribed to age
- expect.equal(subscriber.mock.callCount(), 0)
- })
-
- await ctx.test('Should be called twice when transaction was interrupted by Promise', async () => {
- subscriber.mock.resetCalls()
- await foo.setAsynchronously()
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 2)
- })
-
- await ctx.test('Should not be called when properties were changed with same values', async () => {
- subscriber.mock.resetCalls()
- await foo.setAsynchronously()
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 0)
- })
-
- await ctx.test('Should be called for each subscriber', async () => {
- subscriber.mock.resetCalls()
-
- const subscriber2 = ctx.mock.fn()
- foo.subscribe(subscriber2, new Set(['name', 'city']))
-
- foo.city = 'Seoul'
- foo.name = 'Choi'
-
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 1)
- expect.equal(subscriber2.mock.callCount(), 1)
-
- foo.unsubscribe(subscriber2)
- })
-
- await ctx.test('Should not be called after unsubscribe', async () => {
- subscriber.mock.resetCalls()
- foo.unsubscribe(subscriber)
- foo.city = 'Beijing'
- foo.name = 'Chan'
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 0)
- })
- })
-
- test('listen',async (ctx) => {
- const listener = ctx.mock.fn()
- foo.listen(listener)
- foo.setAll()
-
- await ctx.test('Should be called on each change', () => {
- expect.equal(listener.mock.callCount(), 4)
- })
-
- await ctx.test('Should not be called after unlisten', () => {
- listener.mock.resetCalls()
- foo.unlisten(listener)
- foo.setAll()
- expect.equal(listener.mock.callCount(), 0)
- })
- })
-})
-
-describe('Observable Map', () => {
- class WithMap extends Observable {
- map = new Map()
- }
-
- const firstKey = 'firstKey'
- const secondKey = 'secondKey'
-
- const withMap = new WithMap()
-
- test('Should notify when Map changes', async (ctx) => {
- const onSizeChange = ctx.mock.fn()
- withMap.subscribe(onSizeChange, new Set(['map']))
-
- withMap.map.set('hello', 'world')
- await delay(10)
-
- withMap.map.set('hello', 'javascript') // adding new value to the existed key
- await delay(10)
- // expected behaviour
- // the size doesn't change, but the map in fact is
- // because map can be used like this [...map.values()].map(...)
- expect.equal(onSizeChange.mock.callCount(), 2)
-
- withMap.map.clear()
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 3)
-
- withMap.map = new Map()
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 4)
- })
-
- test('Should notify when specific item is added, changed or removed', async (ctx) => {
- const onFirstKeyChange = ctx.mock.fn()
- withMap.subscribe(onFirstKeyChange, new Set(['map.firstKey']))
-
- withMap.map.set(firstKey, firstKey)
- await delay(10)
- expect.equal(onFirstKeyChange.mock.callCount(), 1)
-
- withMap.map.set(firstKey, 'blah blah blah')
- await delay(10)
- // adding new item to map doesn't trigger subscriber,
- expect.equal(onFirstKeyChange.mock.callCount(), 2)
-
- withMap.map.delete(firstKey)
- await delay(10)
- expect.equal(onFirstKeyChange.mock.callCount(), 3)
- withMap.unsubscribe(onFirstKeyChange)
- })
-
- test('Should not notify when other items were changed', async (ctx) => {
- const onFirstKeyChange = ctx.mock.fn()
- withMap.subscribe(onFirstKeyChange, new Set(['map.firstKey']))
-
- withMap.map.set(firstKey, 'some value')
- await delay(10)
- expect.equal(onFirstKeyChange.mock.callCount(), 1)
-
- withMap.map.set(secondKey, 'blah blah blah')
- await delay(10)
- // adding new item to map doesn't trigger subscriber,
- expect.equal(onFirstKeyChange.mock.callCount(), 1)
- })
-})
-
-describe('Observable plain object', () => {
- const foo = makeObservable({
- name: '',
- age: 42,
- city: 'Moscow',
-
- setAll() {
- this.city = 'Texas'
- this.age = 52
- this.name = 'Egor'
- this.city = 'London'
- },
-
- async setAsynchronously() {
- this.name = 'John'
- await delay(100)
- this.city = 'Rome'
- return true
- }
- })
-
-
- test('subscribe',async (ctx) => {
- const subscriber = ctx.mock.fn()
-
- foo.subscribe(subscriber, new Set(['name', 'city', 'surname']))
- foo.setAll()
-
- await ctx.test('Should be called once per synchronous transaction', async () => {
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 1)
- })
-
- await ctx.test('Should not be called when changing a property that we are not subscribed to', async () => {
- subscriber.mock.resetCalls()
- foo.age = 62 // We are not subscribed to age
- expect.equal(subscriber.mock.callCount(), 0)
- })
-
- await ctx.test('Should be called twice when transaction was interrupted by Promise', async () => {
- subscriber.mock.resetCalls()
- await foo.setAsynchronously()
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 2)
- })
-
- await ctx.test('Should not be called when properties were changed with same values', async () => {
- subscriber.mock.resetCalls()
- await foo.setAsynchronously()
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 0)
- })
-
- await ctx.test('Should be called for each subscriber', async () => {
- subscriber.mock.resetCalls()
-
- const subscriber2 = ctx.mock.fn()
- foo.subscribe(subscriber2, new Set(['name', 'city']))
-
- foo.city = 'Seoul'
- foo.name = 'Choi'
-
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 1)
- expect.equal(subscriber2.mock.callCount(), 1)
-
- foo.unsubscribe(subscriber2)
- })
-
- await ctx.test('Should not be called after unsubscribe', async () => {
- subscriber.mock.resetCalls()
- foo.unsubscribe(subscriber)
- foo.city = 'Beijing'
- foo.name = 'Chan'
- await delay(10)
- expect.equal(subscriber.mock.callCount(), 0)
- })
- })
-
- test('listen',async (ctx) => {
- const listener = ctx.mock.fn()
- foo.listen(listener)
- foo.setAll()
-
- await ctx.test('Should be called on each change', () => {
- expect.equal(listener.mock.callCount(), 4)
- })
-
- await ctx.test('Should not be called after unlisten', () => {
- listener.mock.resetCalls()
- foo.unlisten(listener)
- foo.setAll()
- expect.equal(listener.mock.callCount(), 0)
- })
- })
-})
-
-describe('Observable Array', () => {
-
- test('Should notify when add item by push', async (ctx) => {
- class WithArray extends Observable {
- array = []
- }
- const withArray = new WithArray()
- const onSizeChange = ctx.mock.fn()
- withArray.subscribe(onSizeChange, new Set(['array']))
- await delay(10)
- withArray.array.push(9)
- withArray.array.push(10)
- withArray.array.push(11,12,13)
- await delay(2)
- expect.equal(onSizeChange.mock.callCount(), 1)
- withArray.array = []
- })
-
- test('Should notify when set item by index', async (ctx) => {
- class WithArray extends Observable {
- array: any[] = []
- }
- const withArray = new WithArray()
- const onSizeChange = ctx.mock.fn()
- withArray.subscribe(onSizeChange, new Set(['array']))
-
- withArray.array.set(0, { foo: 'bar' })
- await delay(2)
-
- expect.equal(onSizeChange.mock.callCount(), 1)
- onSizeChange.mock.resetCalls()
- withArray.unsubscribe(onSizeChange)
- withArray.array = []
- })
-
- test('Should notify on splice', async (ctx) => {
- class WithArray extends Observable {
- array = []
- }
- const withArray = new WithArray()
- const onSizeChange = ctx.mock.fn()
- withArray.array = [1,2,3]
- withArray.subscribe(onSizeChange, new Set(['array']))
-
- withArray.array.splice(0,2)
- await delay(10)
-
- expect.equal(onSizeChange.mock.callCount(), 1)
- onSizeChange.mock.resetCalls()
- withArray.unsubscribe(onSizeChange)
- withArray.array = []
- })
-
- test('Should notify on shift and pop', async (ctx) => {
- class WithArray extends Observable {
- array = []
- }
- const withArray = new WithArray()
- const onSizeChange = ctx.mock.fn()
- withArray.array = [1,2,3]
- withArray.subscribe(onSizeChange, new Set(['array']))
-
- withArray.array.shift()
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 1)
-
- withArray.array.pop()
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 2)
- onSizeChange.mock.resetCalls()
- withArray.unsubscribe(onSizeChange)
- withArray.array = []
- })
-
- test('Should notify on sort and reverse', async (ctx) => {
- class WithArray extends Observable {
- array = []
- }
- const withArray = new WithArray()
- const onSizeChange = ctx.mock.fn()
- withArray.array = [1,2,3]
- withArray.subscribe(onSizeChange, new Set(['array']))
-
- withArray.array.sort((a, b) => b - a)
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 1)
-
- withArray.array.reverse()
- await delay(10)
- expect.equal(onSizeChange.mock.callCount(), 2)
- withArray.unsubscribe(onSizeChange)
- withArray.array = []
- })
-})
\ No newline at end of file