import {Suite, expect} from "cynic" import {WatchTower} from "./tower.js" import {SignalTower} from "../signals/tower.js" function setup() { const signals = new SignalTower() const watch = new WatchTower(signals) const tree = watch.stateTree({ count: 0, group: { greeting: "hello", active: false, }, }) return {watch, tree} } export default { "we can read state": async() => { const {tree} = setup() expect(tree.state.count).equals(0) expect(tree.state.group.greeting).equals("hello") }, "we can change state via transmute": async() => { const {tree} = setup() expect(tree.state.count).equals(0) tree.transmute(state => { state.count++ state.group.greeting = "bonjour" return state }) expect(tree.state.count).equals(1) expect(tree.state.group.greeting).equals("bonjour") }, "we cannot change state outside transmute": async() => { const {tree} = setup() expect(tree.state.count).equals(0) expect(() => { tree.state.count++ }).throws() expect(tree.state.count).equals(0) }, "we can track changes to state": async() => { const {watch, tree} = setup() let calls = 0 let lastCount = 0 watch.track( () => tree.state.count, count => { calls++ lastCount = count }, ) expect(calls).equals(1) expect(lastCount).equals(0) tree.transmute(state => { state.count++ return state }) await watch.wait expect(calls).equals(2) expect(lastCount).equals(1) }, "we can unsubscribe from a track to stop listening": async() => { const {watch, tree} = setup() let calls = 0 let lastCount = 0 const untrack = watch.track( () => tree.state.count, count => { calls++ lastCount = count }, ) expect(calls).equals(1) expect(lastCount).equals(0) untrack() tree.transmute(state => { state.count++ return state }) expect(calls).equals(1) expect(lastCount).equals(0) }, "we can track changes to specific state": async() => { const {watch, tree} = setup() let updates_for_count = 0 let updates_for_greeting = 0 let updates_for_active = 0 let updates_for_group = 0 watch.track( () => tree.state.count, () => { updates_for_count++ }, ) watch.track( () => tree.state.group.greeting, () => { updates_for_greeting++ }, ) watch.track( () => tree.state.group.active, () => { updates_for_active++ }, ) watch.track( () => tree.state.group, () => { updates_for_group++ }, ) function reset_counters() { updates_for_count = 0 updates_for_greeting = 0 updates_for_active = 0 updates_for_group = 0 } reset_counters() tree.transmute(state => { state.count++ return state }) await watch.wait expect(updates_for_count).equals(1) expect(updates_for_greeting).equals(0) expect(updates_for_active).equals(0) expect(updates_for_group).equals(0) reset_counters() tree.transmute(state => { state.group.greeting = "bonjour" return state }) await watch.wait expect(updates_for_count).equals(0) expect(updates_for_greeting).equals(1) expect(updates_for_active).equals(0) expect(updates_for_group).equals(1) reset_counters() tree.transmute(state => { state.group.active = true return state }) await watch.wait expect(updates_for_count).equals(0) expect(updates_for_greeting).equals(0) expect(updates_for_active).equals(1) expect(updates_for_group).equals(1) }, "we can make slices of the state": async() => { const {tree, watch} = setup() let calls_alpha = 0 watch.track( () => tree.state.group.greeting, () => { calls_alpha++ }, ) expect(calls_alpha).equals(1) const slice = tree.slice({ getter: (state) => state.group, setter: (state, group) => { state.group = group return state }, }) let calls_bravo = 0 watch.track( () => slice.state.greeting, () => { calls_bravo++ }, ) expect(calls_bravo).equals(1) slice.transmute(state => { state.greeting = "bonjour" return state }) await watch.wait expect(calls_alpha).equals(2) expect(calls_bravo).equals(2) tree.transmute(state => { state.group.greeting = "hola" return state }) await watch.wait expect(calls_alpha).equals(3) expect(calls_bravo).equals(3) }, }