A Future is a placeholder object for a value that may not yet exist
Futures are well known data structures, at it's core, futures, are simply promises. This simple package exposes a simple interface on top of promises to leverage a them as boxed value placeholders.
npm install fp-future
function future<T>(): IFuture<T>;
type IFuture<T> = Promise<T> & {
resolve: (x: T) => void;
reject: (x: Error) => void;
finally: (fn: () => void) => void;
isPending: boolean;
}
const loading = future()
loading.resolve(123)
assert(await loading == 123)
const loading = future()
loading.reject(new Error('It did fail'))
try {
await loading
} catch(e) {
assert(e.message == 'It did fail')
}
const loadingFuture = future()
// load(successCallback, errorCallback)
load(loadingFuture.resolve, loadingFuture.reject)
await loadingFuture
It is useful for blackbox testing without weird injections and other magical things.
it("executes the callback", async () => {
const didClickFuture = future();
// happy path
entity.onClick(clickId => {
didClickFuture.resolve(clickId);
// ^^^^^^^^^^^^^^
// Here we resolve the future with a click
});
// unhappy path
setTimeout(() => {
didClickFuture.reject(new Error("Timeout"))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Timeout, just in case we don't receive the event
}, 1000);
// Generate synthetic event and trigger the event
const clickId = Math.random()
entity.triggerClick(clickId);
// Await the value or fail!
const receivedNonce = await somethingToBeResolved;
// Assertion
expect(receivedNonce).toEq(clickId);
});
async function injectScript(url: string) {
const theFuture = future<Event>();
const theScript = document.createElement("script");
theScript.src = url;
theScript.async = true;
theScript.type = "application/javascript";
theScript.addEventListener("load", theFuture.resolve);
theScript.addEventListener("error", e => theFuture.reject(e.error));
document.body.appendChild(theScript);
return theFuture;
}
async function main() {
await injectScript("https://www.gstatic.com/firebasejs/7.12.0/firebase-app.js");
await injectScript("https://www.gstatic.com/firebasejs/7.12.0/firebase-analytics.js");
await injectScript("https://www.gstatic.com/firebasejs/7.12.0/firebase-auth.js");
// use the injected scripts
firebase.initializeApp(firebaseConfig);
firebase.analytics();
}
async function loadImageData(src: string): Promise<ImageData> {
const futureColors = future<ImageData>();
var img = new Image();
img.crossOrigin = "Anonymous"
img.onload = function() {
var imageData = loadingContext.getImageData(0, 0, img.width, img.height);
futureColors.resolve(imageData);
};
img.src = src;
return futureColors;
}