UNPKG

@dhmk/atom

Version:

Lightweight mobx-like observable values, computed values and side-effects

221 lines (220 loc) 7.19 kB
import { atom, observe, act } from "./"; describe("atom", function () { test("basic", function () { var a = atom(1); var b = atom(function () { return a() + 1; }); expect(a()).toEqual(1); expect(b()).toEqual(2); act(function () { return a.set(2); }); expect(a()).toEqual(2); expect(b()).toEqual(3); }); test("oldValue eq newValue == don`t invalidate children", function () { var a = atom(1); var b = atom(function () { return a() % 2; }); var spy = jest.fn(); var c = atom(function () { return spy(b()); }); observe(c); // if comment this, total called times should be 4 c(); // b = 1 expect(spy).toBeCalledTimes(1); act(function () { return a.set(3); }); // b = 1 c(); expect(spy).toBeCalledTimes(1); act(function () { return a.set(5); }); // b = 0 c(); act(function () { return a.set(6); }); // b = 0 c(); expect(spy).toBeCalledTimes(2); }); test("diamond", function () { var computeSpy = jest.fn(); var observeSpy = jest.fn(); var a = atom(1); var b = atom(function () { return a() + 1; }); var c = atom(function () { return a() * 10; }); var d = atom(function () { computeSpy(); return b() + c(); }); observe(function () { d(); observeSpy(); }); expect(d()).toEqual(12); expect(computeSpy).toBeCalledTimes(1); expect(observeSpy).toBeCalledTimes(1); act(function () { return a.set(2); }); expect(d()).toEqual(23); expect(computeSpy).toBeCalledTimes(2); expect(observeSpy).toBeCalledTimes(2); }); test("onBO/onBUO", function () { var onBOspy = jest.fn(); var onBUOspy = jest.fn(); var a = atom(1, { onBecomeObserved: onBOspy, onBecomeUnobserved: onBUOspy, }); expect(onBOspy).toBeCalledTimes(0); expect(onBUOspy).toBeCalledTimes(0); // irrelevant act(function () { return a.set(2); }); expect(onBOspy).toBeCalledTimes(0); expect(onBUOspy).toBeCalledTimes(0); // BO var d = observe(a); expect(onBOspy).toBeCalledTimes(1); expect(onBUOspy).toBeCalledTimes(0); // irrelevant act(function () { return a.set(3); }); expect(onBOspy).toBeCalledTimes(1); expect(onBUOspy).toBeCalledTimes(0); // BUO d(); expect(onBOspy).toBeCalledTimes(1); expect(onBUOspy).toBeCalledTimes(1); // irrelevant d(); expect(onBOspy).toBeCalledTimes(1); expect(onBUOspy).toBeCalledTimes(1); // irrelevant act(function () { return a.set(4); }); expect(onBOspy).toBeCalledTimes(1); expect(onBUOspy).toBeCalledTimes(1); // BO var d2 = observe(a); expect(onBOspy).toBeCalledTimes(2); expect(onBUOspy).toBeCalledTimes(1); // BUO d2(); expect(onBOspy).toBeCalledTimes(2); expect(onBUOspy).toBeCalledTimes(2); }); }); describe("observe", function () { test("basic", function () { var a = atom(1); var b = atom(2); var spy = jest.fn(); observe(function () { a() + b(); spy(); }); expect(spy).toBeCalledTimes(1); act(function () { return a.set(2); }); act(function () { return b.set(3); }); expect(spy).toBeCalledTimes(3); }); test("re-runs if atoms changed in-flight", function () { var a = atom(1); var spy = jest.fn(); observe(function () { if (a() === 1) a.set(2); if (a() === 10) a.set(11); spy(); }); expect(spy).toBeCalledTimes(2); act(function () { return a.set(3); }); expect(spy).toBeCalledTimes(3); act(function () { return a.set(10); }); expect(spy).toBeCalledTimes(5); var b = atom(1); var c = atom(function () { return b().toString().length; }); var once = false; observe(function () { if (!once) { once = true; b.set(2); } c(); spy(); }); expect(spy).toHaveBeenCalledTimes(6); }); test("dispose", function () { var a = atom(1); var spy = jest.fn(); observe(function (d) { a(); d(); spy(); }); act(function () { return a.set(2); }); act(function () { return a.set(3); }); expect(spy).toBeCalledTimes(1); var d = observe(function () { a(); spy(); }); d(); act(function () { return a.set(4); }); act(function () { return a.set(5); }); expect(spy).toBeCalledTimes(2); }); test("custom async scheduler", function (done) { var a = atom(1); var spy = jest.fn(); var sch = function (x) { return x(); }; observe(function () { if (a() === 11) { // the end // 1 - initial pass // 2 - after a.set(2) // 3 - after a.set(10) expect(spy).toBeCalledTimes(3); done(); } if (a() === 1) { a.set(2); setTimeout(function () { // 1. now, observe will run outside `runPendingAtoms` (and batching) sch = function (x) { return setTimeout(x); }; act(function () { return a.set(10); }); }); } if (a() === 10) { // 2. still outside `runPendingAtoms` // call `observe` immediately // this will fail if g_batchCount === 0 sch = function (x) { return x(); }; a.set(11); } spy(); }, { scheduler: function (run) { return sch(run); }, }); }); test("force run in batch", function () { var a = atom(1); var spy = jest.fn(); var d = observe(function () { a(); spy(); }); expect(spy).toBeCalledTimes(1); act(function () { d.invalidate( /*false*/); expect(spy).toBeCalledTimes(1); d.invalidate( /*true*/); expect(spy).toBeCalledTimes(1); }); expect(spy).toBeCalledTimes(2); }); }); test("action", function () { var a = atom(1); var b = atom(2); var spy = jest.fn(); observe(function () { a() + b(); spy(); }); expect(spy).toBeCalledTimes(1); act(function () { a.set(2); b.set(3); }); expect(spy).toBeCalledTimes(2); });