This repository has been archived on 2020-09-01. You can view files and clone it, but cannot push or open issues or pull requests.
reactimal/spec/stream.spec.js
Timothy Farrell 10e962e6e2 De-duplicate stream runs.
Don't eval multiple times when called multiple times in quick succession.
2018-06-13 11:07:04 -05:00

136 lines
3.0 KiB
JavaScript

import { prop, computed, stream } from '../src/index.js';
import { dirtyMock, hashSet } from '../src/testUtil.js';
describe('A stream', () => {
const add = (a, b) => a + b;
const square = a => a * a;
async function delayAdd(a, b) {
return new Promise(resolve =>
setTimeout(() => {
resolve(a + b);
}, 30)
);
}
async function delaySquare(a) {
return new Promise(resolve =>
setTimeout(() => {
resolve(a * a);
}, 30)
);
}
it('accepts prop, computed and stream dependencies', async done => {
const a = prop(0);
const b = computed(square, [a]);
const c = stream(delaySquare, [a]);
const d = stream(delayAdd, [a, c]);
const e = stream(delaySquare, [b]);
expect(await c()).toEqual(0);
expect(await d()).toEqual(0);
expect(await e()).toEqual(0);
a(1);
expect(await c()).toEqual(1);
expect(await d()).toEqual(2);
expect(await e()).toEqual(1);
a(2);
expect(await c()).toEqual(4);
expect(await d()).toEqual(6);
expect(await e()).toEqual(16);
a(3);
expect(await c()).toEqual(9);
expect(await d()).toEqual(12);
expect(await e()).toEqual(81);
done();
});
it('computes automatically when subscribed', async done => {
let runCount = 0;
let subRunCount = 0;
let currentValue = 1;
const a = prop(0);
const b = stream(
async val => {
runCount += 1;
expect(val).toEqual(currentValue);
return new Promise(resolve => setTimeout(() => resolve(val * val), 30));
},
[a]
);
// b does not evaluate
a(1);
expect(runCount).toEqual(0);
// b evaluates
expect(await b()).toEqual(1);
expect(runCount).toEqual(1);
// b does not evaluate
expect(await b()).toEqual(1);
expect(runCount).toEqual(1);
const cancelSubscription = b.subscribe(val => {
subRunCount += 1;
expect(val).toEqual(currentValue * currentValue);
});
currentValue = 3;
// b evaluates
a(3);
// b is triggered to update but hasn't yet
expect(runCount).toEqual(1);
expect(subRunCount).toEqual(0);
setTimeout(async () => {
// b should have updated now
expect(runCount).toEqual(2);
expect(subRunCount).toEqual(1);
// b does not evaluate
expect(await b()).toEqual(9);
expect(runCount).toEqual(2);
expect(subRunCount).toEqual(1);
done();
}, 40);
});
it('only computes once for overlapping calls', async done => {
let callCount = 0;
async function delayRun(a) {
return new Promise(resolve =>
setTimeout(() => {
callCount += 1;
resolve(callCount + a);
}, 10)
);
}
const a = prop(0);
const b = stream(delayRun, [a]);
expect(await b()).toEqual(1);
expect(callCount).toEqual(1);
a(1);
expect(await b()).toEqual(3);
expect(callCount).toEqual(2);
// Just calling sequentially should not re-evaluate
expect(await b()).toEqual(3);
expect(callCount).toEqual(2);
// Set b.dirty flag
a(2);
Promise.all([b(), b()])
.then(([res_1, res_2]) => {
expect(res_1).toEqual(5);
expect(res_2).toEqual(5);
expect(callCount).toEqual(3);
})
.finally(done);
});
});