UNPKG

@benev/slate

Version:
321 lines 10.5 kB
import { expect } from "cynic"; import { Flat } from "./flat.js"; export default { async "increment state count"() { const flat = new Flat(); const state = flat.state({ count: 0 }); expect(state.count).equals(0); state.count += 1; expect(state.count).equals(1); }, async "react to change"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let calls = 0; flat.reaction(() => void state.count, () => calls++); expect(state.count).equals(0); expect(calls).equals(0); state.count = 123; expect(state.count).equals(123); expect(calls).equals(0); await flat.wait; expect(state.count).equals(123); expect(calls).equals(1); }, async "lean tracking"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let collector_calls = 0; let responder_calls = 0; const lean = flat.lean(() => responder_calls++); const collector = () => { void state.count; collector_calls++; }; expect(collector_calls).equals(0); expect(responder_calls).equals(0); lean.collect(collector); await flat.wait; expect(collector_calls).equals(1); expect(responder_calls).equals(0); state.count++; await flat.wait; expect(collector_calls).equals(1); expect(responder_calls).equals(1); state.count++; await flat.wait; expect(collector_calls).equals(1); expect(responder_calls).equals(2); }, async "react to changes from two states"() { const flat = new Flat(); const stateA = flat.state({ alpha: 0 }); const stateB = flat.state({ bravo: 0 }); let calls = 0; flat.reaction(() => { void stateA.alpha; void stateB.bravo; }, () => calls++); calls = 0; stateA.alpha++; await flat.wait; expect(calls).equals(1); stateB.bravo++; await flat.wait; expect(calls).equals(2); }, async "react with only one function"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let calls = 0; flat.reaction(() => { void state.count; calls++; }); expect(calls).equals(1); state.count = 123; await flat.wait; expect(state.count).equals(123); expect(calls).equals(2); }, async "reaction collector can pass data to responder"() { const flat = new Flat(); const state = flat.state({ count: 0, greeting: "hello" }); let a = -1; let b = ""; flat.reaction(() => ({ count: state.count, greeting: state.greeting, }), ({ count, greeting }) => { a = count; b = greeting; }); expect(a).equals(-1); expect(b).equals(""); state.count++; state.greeting = "hello world"; await flat.wait; expect(a).equals(1); expect(b).equals("hello world"); }, async "track is efficient"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let collect = 0; let respond = 0; flat.reaction(() => { void state.count; collect++; }, () => { void state.count; respond++; }); expect(collect).equals(1); expect(respond).equals(0); state.count++; await flat.wait; expect(collect).equals(2); expect(respond).equals(1); }, async "circular loops are forbidden"() { await expect(async () => { const flat = new Flat(); const state = flat.state({ count: 0 }); flat.reaction(() => { state.count = 123; return { count: state.count }; }, () => { }); await flat.wait; }).throws(); await expect(async () => { const flat = new Flat(); const state = flat.state({ count: 0 }); flat.reaction(() => ({ count: state.count }), () => { state.count = 123; }); state.count++; await flat.wait; }).throws(); await expect(async () => { const flat = new Flat(); const state = flat.state({ count: 0 }); flat.reaction(() => state.count = 123); await flat.wait; }).throws(); }, async "nested rendering doesn't cause circular issues"() { const flat = new Flat(); const state = flat.state({ outer: 0, inner: 0 }); let outerCalls = 0; let innerCalls = 0; flat.reaction(() => { void state.outer; flat.reaction(() => void state.inner, () => innerCalls++); }, () => outerCalls++); state.outer++; await flat.wait; expect(outerCalls).equals(1); expect(innerCalls).equals(0); state.inner++; await flat.wait; expect(outerCalls).equals(1); expect(innerCalls).equals(2); }, async "stop a reaction"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let called = false; const stop = flat.reaction(() => { void state.count; called = true; }); called = false; state.count++; await flat.wait; expect(called).equals(true); called = false; stop(); state.count++; await flat.wait; expect(called).equals(false); }, async "debounce multiple changes"() { const flat = new Flat(); const state = flat.state({ count: 0 }); const state2 = flat.state({ count: 0 }); let a = 0; let b = 0; let c = 0; flat.reaction(() => void state.count, () => a++); flat.reaction(() => void state.count, () => b++); flat.reaction(() => { void state2.count; void state2.count; }, () => c++); state.count++; state.count++; state.count++; state2.count++; state2.count++; state2.count++; await flat.wait; expect(a).equals(1); expect(b).equals(1); expect(c).equals(1); }, async "discovery of new nested states"() { const flat = new Flat(); const outer = flat.state({ inner: undefined }); let last_count; flat.reaction(() => { last_count = outer.inner?.count; }); expect(last_count).equals(undefined); outer.inner = flat.state({ count: 0 }); await flat.wait; expect(last_count).equals(0); outer.inner.count++; await flat.wait; expect(last_count).equals(1); }, async "reactions are isolated"() { const flatA = new Flat(); const stateA1 = flatA.state({ count: 0 }); const stateA2 = flatA.state({ count: 0 }); const flatB = new Flat(); const stateB1 = flatB.state({ count: 0 }); const stateB2 = flatB.state({ count: 0 }); const reactions = { A1: false, A2: false, B1: false, B2: false, }; flatA.reaction(() => { void stateA1.count; reactions.A1 = true; }); flatA.reaction(() => { void stateA2.count; reactions.A2 = true; }); flatB.reaction(() => { void stateB1.count; reactions.B1 = true; }); flatB.reaction(() => { void stateB2.count; reactions.B2 = true; }); reactions.A1 = false; reactions.A2 = false; reactions.B1 = false; reactions.B2 = false; stateA1.count++; await Promise.all([flatA.wait, flatB.wait]); expect(reactions.A1).equals(true); expect(reactions.A2).equals(false); expect(reactions.B1).equals(false); expect(reactions.B2).equals(false); stateB1.count++; await Promise.all([flatA.wait, flatB.wait]); expect(reactions.A1).equals(true); expect(reactions.A2).equals(false); expect(reactions.B1).equals(true); expect(reactions.B2).equals(false); }, async "readonly works with reactions"() { const flat = new Flat(); const state = flat.state({ count: 0 }); const rstate = Flat.readonly(state); let called = false; flat.reaction(() => { void rstate.count; called = true; }); expect(called).equals(true); called = false; state.count++; await flat.wait; expect(called).equals(true); }, async "readonly throws errors on writes"() { const flat = new Flat(); const state = flat.state({ count: 0 }); const rstate = Flat.readonly(state); expect(() => { state.count++; }).not.throws(); expect(() => { rstate.count++; }).throws(); }, async "clear all reactions"() { const flat = new Flat(); const state = flat.state({ count: 0 }); let called = false; flat.reaction(() => { void state.count; called = true; }); called = false; state.count++; await flat.wait; expect(called).equals(true); called = false; flat.clear(); state.count++; await flat.wait; expect(called).equals(false); }, async "nested states"() { const flat = new Flat(); const outer = flat.state({ count: 0, inner: flat.state({ count: 0 }) }); let outer_called = false; let inner_called = false; flat.reaction(() => { void outer.count; outer_called = true; }); flat.reaction(() => { void outer.inner.count; inner_called = true; }); expect(outer_called).equals(true); expect(inner_called).equals(true); outer_called = false; inner_called = false; outer.count++; await flat.wait; expect(outer_called).equals(true); expect(inner_called).equals(false); outer_called = false; inner_called = false; outer.inner.count++; await flat.wait; expect(outer_called).equals(false); expect(inner_called).equals(true); }, }; //# sourceMappingURL=flat.test.js.map