150 lines
4.4 KiB
JavaScript
150 lines
4.4 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const PromiseStream = require('../promise-stream');
|
|
|
|
function cloneJSON(x) {
|
|
return JSON.parse(JSON.stringify(x));
|
|
}
|
|
|
|
function afterMicrotasks() {
|
|
return new Promise(function(resolve) {
|
|
setTimeout(resolve);
|
|
});
|
|
}
|
|
|
|
describe('PromiseStream', function() {
|
|
let stream;
|
|
|
|
it('should finish constructing the PromiseStream', function() {
|
|
stream = new PromiseStream;
|
|
});
|
|
|
|
it('should have an undefined initial value', function() {
|
|
assert.deepStrictEqual(stream.value, undefined);
|
|
});
|
|
|
|
const onceVal = [];
|
|
it('should allow setting a one-time callback', function() {
|
|
stream.once((v) => {
|
|
onceVal.push(v);
|
|
});
|
|
});
|
|
|
|
const listenVal = [];
|
|
let cancel;
|
|
it('should allow setting an ongoing callback', function() {
|
|
cancel = stream.listen((v) => {
|
|
listenVal.push(v);
|
|
});
|
|
});
|
|
|
|
it('should return a cancellation function', function() {
|
|
assert.strictEqual(typeof cancel, 'function');
|
|
});
|
|
|
|
const then0Val = [];
|
|
it('should provide access to the current promise', function() {
|
|
stream.promise.then((v) => v.value + 3).then((v) => {
|
|
then0Val.push(v);
|
|
});
|
|
});
|
|
|
|
const next0Val = [];
|
|
it('should provide access to the next promise', function() {
|
|
stream.next_promise.then((v) => v.value + 7).then((v) => {
|
|
next0Val.push(v);
|
|
});
|
|
});
|
|
|
|
it('should wait for the first update before running callbacks', async function() {
|
|
await afterMicrotasks();
|
|
assert.deepStrictEqual(onceVal, []);
|
|
assert.deepStrictEqual(listenVal, []);
|
|
assert.deepStrictEqual(then0Val, []);
|
|
assert.deepStrictEqual(next0Val, []);
|
|
});
|
|
|
|
let snapshot;
|
|
it('should allow updates', function() {
|
|
stream.update(10);
|
|
snapshot = cloneJSON({ onceVal, listenVal, then0Val, next0Val });
|
|
});
|
|
|
|
it('should hold callbacks in the microtask queue', function() {
|
|
assert.deepStrictEqual(snapshot.onceVal, []);
|
|
assert.deepStrictEqual(snapshot.listenVal, []);
|
|
assert.deepStrictEqual(snapshot.then0Val, []);
|
|
assert.deepStrictEqual(snapshot.next0Val, []);
|
|
});
|
|
|
|
it('should run callbacks after first update', async function() {
|
|
await afterMicrotasks();
|
|
assert.deepStrictEqual(onceVal, [10]);
|
|
assert.deepStrictEqual(listenVal, [10]);
|
|
assert.deepStrictEqual(then0Val, [13]);
|
|
assert.deepStrictEqual(next0Val, [17]);
|
|
});
|
|
|
|
const then1Val = [];
|
|
it('should provide access to current promise after update', async function() {
|
|
stream.promise.then((v) => v.value + 4).then((v) => {
|
|
then1Val.push(v);
|
|
});
|
|
|
|
assert.deepStrictEqual(then1Val, []);
|
|
|
|
await afterMicrotasks();
|
|
assert.deepStrictEqual(then1Val, [14]);
|
|
});
|
|
|
|
const next1Val = [];
|
|
it('should provide access to next promise after update', async function() {
|
|
stream.next_promise.then((v) => v.value + 8).then((v) => {
|
|
next1Val.push(v);
|
|
});
|
|
|
|
await afterMicrotasks();
|
|
assert.deepStrictEqual(next1Val, []);
|
|
});
|
|
|
|
it('should allow a second update', function() {
|
|
stream.update(20);
|
|
snapshot = cloneJSON({ onceVal, listenVal, then0Val, next0Val, then1Val, next1Val });
|
|
});
|
|
|
|
it('should hold callbacks in the microtask queue', function() {
|
|
assert.deepStrictEqual(snapshot.onceVal, [10]);
|
|
assert.deepStrictEqual(snapshot.listenVal, [10]);
|
|
assert.deepStrictEqual(snapshot.then0Val, [13]);
|
|
assert.deepStrictEqual(snapshot.next0Val, [17]);
|
|
assert.deepStrictEqual(snapshot.then1Val, [14]);
|
|
assert.deepStrictEqual(snapshot.next1Val, []);
|
|
});
|
|
|
|
it('should run callbacks after second update', async function() {
|
|
await afterMicrotasks();
|
|
assert.deepStrictEqual(onceVal, [10]);
|
|
assert.deepStrictEqual(listenVal, [10, 20]);
|
|
assert.deepStrictEqual(then0Val, [13]);
|
|
assert.deepStrictEqual(next0Val, [17]);
|
|
assert.deepStrictEqual(then1Val, [14]);
|
|
assert.deepStrictEqual(next1Val, [28]);
|
|
});
|
|
|
|
it('should allow listeners to be cancelled individually', async function() {
|
|
const listen2Val = [];
|
|
const cancel2 = stream.listen((v) => {
|
|
listen2Val.push(v);
|
|
});
|
|
|
|
cancel();
|
|
stream.update(30);
|
|
|
|
await afterMicrotasks();
|
|
cancel2();
|
|
assert.deepStrictEqual(listenVal, [10, 20]); /* not updated */
|
|
assert.deepStrictEqual(listen2Val, [20, 30]); /* updated w/ current and new value */
|
|
});
|
|
});
|