From d115d3aed60680e6437fa060f1d884e74015a0f3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 10 Oct 2018 17:45:19 +0100 Subject: util.promise: ES6-like API for promises --- spec/util_promise_spec.lua | 262 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 spec/util_promise_spec.lua (limited to 'spec/util_promise_spec.lua') diff --git a/spec/util_promise_spec.lua b/spec/util_promise_spec.lua new file mode 100644 index 00000000..f0aec64c --- /dev/null +++ b/spec/util_promise_spec.lua @@ -0,0 +1,262 @@ +local promise = require "util.promise"; + +describe("util.promise", function () + describe("new()", function () + it("returns a promise object", function () + assert(promise.new()); + end); + end); + it("notifies immediately for fulfilled promises", function () + local p = promise.new(function (resolve) + resolve("foo"); + end); + local cb = spy.new(function (v) + assert.equal("foo", v); + end); + p:next(cb); + assert.spy(cb).was_called(1); + end); + it("notifies on fulfilment of pending promises", function () + local r; + local p = promise.new(function (resolve) + r = resolve; + end); + local cb = spy.new(function (v) + assert.equal("foo", v); + end); + p:next(cb); + assert.spy(cb).was_called(0); + r("foo"); + assert.spy(cb).was_called(1); + end); + it("allows chaining :next() calls", function () + local r; + local result; + local p = promise.new(function (resolve) + r = resolve; + end); + local cb1 = spy.new(function (v) + assert.equal("foo", v); + return "bar"; + end); + local cb2 = spy.new(function (v) + assert.equal("bar", v); + result = v; + end); + p:next(cb1):next(cb2); + assert.spy(cb1).was_called(0); + assert.spy(cb2).was_called(0); + r("foo"); + assert.spy(cb1).was_called(1); + assert.spy(cb2).was_called(1); + assert.equal("bar", result); + end); + it("supports multiple :next() calls on the same promise", function () + local r; + local result; + local p = promise.new(function (resolve) + r = resolve; + end); + local cb1 = spy.new(function (v) + assert.equal("foo", v); + result = v; + end); + local cb2 = spy.new(function (v) + assert.equal("foo", v); + result = v; + end); + p:next(cb1); + p:next(cb2); + assert.spy(cb1).was_called(0); + assert.spy(cb2).was_called(0); + r("foo"); + assert.spy(cb1).was_called(1); + assert.spy(cb2).was_called(1); + assert.equal("foo", result); + end); + it("automatically rejects on error", function () + local r; + local p = promise.new(function (resolve) + r = resolve; + error("oh no"); + end); + local cb = spy.new(function () end); + local err_cb = spy.new(function (v) + assert.equal("oh no", v); + end); + p:next(cb, err_cb); + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(1); + r("foo"); + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(1); + end); + it("supports reject()", function () + local r, result; + local p = promise.new(function (resolve, reject) + r = reject; + end); + local cb = spy.new(function () end); + local err_cb = spy.new(function (v) + result = v; + assert.equal("oh doh", v); + end); + p:next(cb, err_cb); + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(0); + r("oh doh"); + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(1); + assert.equal("oh doh", result); + end); + it("supports chaining of rejected promises", function () + local r, result; + local p = promise.new(function (resolve, reject) + r = reject; + end); + local cb = spy.new(function () end); + local err_cb = spy.new(function (v) + result = v; + assert.equal("oh doh", v); + return "ok" + end); + local cb2 = spy.new(function (v) + result = v; + end); + local err_cb2 = spy.new(function (v) end); + p:next(cb, err_cb):next(cb2, err_cb2) + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(0); + assert.spy(cb2).was_called(0); + assert.spy(err_cb2).was_called(0); + r("oh doh"); + assert.spy(cb).was_called(0); + assert.spy(err_cb).was_called(1); + assert.spy(cb2).was_called(1); + assert.spy(err_cb2).was_called(0); + assert.equal("ok", result); + end); + + describe("race()", function () + it("works with fulfilled promises", function () + local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); + local p = promise.race({ p1, p2 }); + local result; + p:next(function (v) + result = v; + end); + assert.equal("yep", result); + end); + it("works with pending promises", function () + local r1, r2; + local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); + local p = promise.race({ p1, p2 }); + + local result; + local cb = spy.new(function (v) + result = v; + end); + p:next(cb); + assert.spy(cb).was_called(0); + r2("yep"); + r1("nope"); + assert.spy(cb).was_called(1); + assert.equal("yep", result); + end); + end); + describe("all()", function () + it("works with fulfilled promises", function () + local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); + local p = promise.all({ p1, p2 }); + local result; + p:next(function (v) + result = v; + end); + assert.same({ "yep", "nope" }, result); + end); + it("works with pending promises", function () + local r1, r2; + local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); + local p = promise.all({ p1, p2 }); + + local result; + local cb = spy.new(function (v) + result = v; + end); + p:next(cb); + assert.spy(cb).was_called(0); + r2("yep"); + assert.spy(cb).was_called(0); + r1("nope"); + assert.spy(cb).was_called(1); + assert.same({ "nope", "yep" }, result); + end); + it("rejects if any promise rejects", function () + local r1, r2; + local p1 = promise.new(function (resolve, reject) r1 = reject end); + local p2 = promise.new(function (resolve, reject) r2 = reject end); + local p = promise.all({ p1, p2 }); + + local result; + local cb = spy.new(function (v) + result = v; + end); + local cb_err = spy.new(function (v) + result = v; + end); + p:next(cb, cb_err); + assert.spy(cb).was_called(0); + assert.spy(cb_err).was_called(0); + r2("fail"); + assert.spy(cb).was_called(0); + assert.spy(cb_err).was_called(1); + r1("nope"); + assert.spy(cb).was_called(0); + assert.spy(cb_err).was_called(1); + assert.equal("fail", result); + end); + end); + describe("catch()", function () + it("works", function () + local result; + local p = promise.new(function (resolve) + error({ foo = true }); + end); + local cb1 = spy.new(function (v) + result = v; + end); + assert.spy(cb1).was_called(0); + p:catch(cb1); + assert.spy(cb1).was_called(1); + assert.same({ foo = true }, result); + end); + end); + it("promises may be resolved by other promises", function () + local r1, r2; + local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); + + local result; + local cb = spy.new(function (v) + result = v; + end); + p1:next(cb); + assert.spy(cb).was_called(0); + + r1(p2); + assert.spy(cb).was_called(0); + r2("yep"); + assert.spy(cb).was_called(1); + assert.equal("yep", result); + end); + describe("reject()", function () + it("returns a rejected promise", function () + local p = promise.reject("foo"); + local cb = spy.new(function (v) + result = v; + end); + p:next(cb); + assert.spy(cb).was_called(1); + assert.spy(cb).was_called_with("foo"); + end); + end); +end); -- cgit v1.2.3