ssured / callbag-to-mobx

Bindings between callbag and mobx

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add tests

ssured opened this issue · comments

const {
  pipe,
  interval,
  take,
  filter,
  map,
  forEach
} = require("callbag-basics");
const toRx = require("callbag-to-rxjs");
const {
  autorun,
  observable,
  reaction,
  configure,
  runInAction
} = require("mobx");
const { fromStream, fromResource } = require("mobx-utils");

configure({
  enforceActions: true
});

const delay = ms => new Promise(r => setTimeout(r, ms));

describe("callbag support for mobx", () => {
  let status;

  beforeEach(async () => {
    status = "initial";
  });

  const pullableAsyncSource = (ms = 5) => {
    let i = 0,
      timeout;

    return (start, sink) => {
      if (start !== 0) return;
      status = "started";
      sink(0, t => {
        if (t === 1) {
          timeout = setTimeout(() => {
            sink(1, i++);
          }, ms);
        } else if (t === 2) {
          status = "stopped";
          clearTimeout(timeout);
        }
      });
    };
  };

  it("subscribes to observables", async () => {
    const value = fromStream(
      pipe(interval(10), take(5), filter(x => x !== 0), map(x => x * 10), toRx),
      0
    );

    const values = [];
    const dispose = autorun(() => values.push(value.current));

    await delay(500);
    dispose();

    values; //?
    expect(values).toEqual([0, 10, 20, 30, 40]);
  });

  it("callbag tracks unsubscribe", async () => {
    const values = [];
    pipe(pullableAsyncSource(), take(5), forEach(value => values.push(value)));

    expect(status).toEqual("started");
    await delay(100);
    expect(status).toEqual("stopped");

    pipe(pullableAsyncSource(), take(5), forEach(value => values.push(value)));

    expect(status).toEqual("started");
    await delay(100);
    expect(status).toEqual("stopped");

    values; //?
    expect(values).toEqual([0, 1, 2, 3, 4, 0, 1, 2, 3, 4]);
  });

  it("callbag tracks unsubscribe - mobx", async () => {
    const fromCallbag = (source, initialValue = undefined) => {
      let talkback;
      return fromResource(
        sink => {
          source(0, (t, d) => {
            if (t === 0) talkback = d;
            if (t === 1) sink(d);
            if (t === 1 || t === 0) talkback(1);
          });
        },
        () => talkback(2),
        initialValue
      );
    };

    const value = fromCallbag(pullableAsyncSource(20), -1);

    // lazy initialization
    expect(status).toEqual("initial");

    const values = [];

    // starts when observed
    let runs = 0; // track number of runs for fixing timing issues in the test
    let dispose = autorun(() => {
      runs++;
      values.push(value.current());
    });
    expect(status).toEqual("started");
    await delay(70);
    expect(status).toEqual("started");
    // stops when not listened to
    dispose();
    expect(status).toEqual("stopped");

    const expectedResult1 = [-1, 0, 1, 2].slice(0, runs);
    runs; //?
    expectedResult1; //?
    expect(values).toEqual(expectedResult1);

    // restarts when observed
    dispose = autorun(() => {
      runs++;
      values.push(value.current());
    });
    expect(status).toEqual("started");
    await delay(70);
    expect(status).toEqual("started");
    dispose();
    expect(status).toEqual("stopped");

    const lastResult1 = expectedResult1.slice(-1)[0]; //?
    const expectedResult2 = expectedResult1
      .concat(
        Array(runs)
          .fill()
          .map((_, i) => i + lastResult1)
      )
      .slice(0, runs);
    runs; //?
    expectedResult2; //?
    expect(values).toEqual(expectedResult2);
  });

  it("callbag tracks unsubscribe - mobx", async () => {
    const value = observable({ a: "A" });
    let status = "initial";

    const asCallbag = (expression, fireImmediately = true) => {
      let disposer;

      return (start, sink) => {
        if (start !== 0) return;
        status = "started";
        sink(0, t => {
          if (t === 2) {
            status = "stopped";
            disposer();
          }
        });
        disposer = reaction(expression, value => sink(1, value), {
          fireImmediately
        });
      };
    };

    const values = [];
    const valueBag = asCallbag(() => value.a);

    // connecting callbag
    expect(status).toEqual("initial");
    pipe(valueBag, take(3), forEach(value => values.push(value)));
    expect(values).toEqual(["A"]);
    expect(status).toEqual("started");

    // updates are tracked
    runInAction(() => {
      value.a = "B";
    });
    expect(values).toEqual(["A", "B"]);

    // only three updates are listened to, because of take
    expect(status).toEqual("started");
    runInAction(() => {
      value.a = "C";
    });
    expect(values).toEqual(["A", "B", "C"]);
    expect(status).toEqual("stopped");

    // further changes are not handled
    runInAction(() => {
      value.a = "D";
    });
    expect(values).toEqual(["A", "B", "C"]);
  });
});