2015-10-29 18:29:32 +00:00

805 lines
21 KiB
JavaScript

/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
describe("async functions and await expressions", function () {
Promise = require("promise");
describe("regeneratorRuntime", function () {
it("should be defined globally", function () {
var global = Function("return this")();
assert.ok("regeneratorRuntime" in global);
assert.strictEqual(global.regeneratorRuntime, regeneratorRuntime);
});
it("should have a .wrap method", function () {
assert.strictEqual(typeof regeneratorRuntime.wrap, "function");
});
});
describe("Promise", function () {
it("should be defined globally", function () {
var global = Function("return this")();
assert.ok("Promise" in global);
assert.strictEqual(global.Promise, Promise);
});
it("should be a function", function () {
assert.strictEqual(typeof Promise, "function");
});
});
describe("no-await async function", function () {
it("should return a Promise", function (done) {
var called = false;
function noAwait(value) {
return regeneratorRuntime.async(function noAwait$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
called = true;
return _context.abrupt("return", value);
case 2:
case "end":
return _context.stop();
}
}, null, this);
}
var promise = noAwait("asdf");
assert.strictEqual(called, true);
promise.then(function (value) {
assert.strictEqual(called, true);
assert.strictEqual(value, "asdf");
done();
}).catch(done);
});
});
describe("one-await async function", function () {
it("should finish asynchronously", function (done) {
var flag1 = false;
var flag2 = false;
function oneAwait(value) {
var result;
return regeneratorRuntime.async(function oneAwait$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
flag1 = true;
_context2.next = 3;
return regeneratorRuntime.awrap(value);
case 3:
result = _context2.sent;
flag2 = true;
return _context2.abrupt("return", result);
case 6:
case "end":
return _context2.stop();
}
}, null, this);
}
var promise = oneAwait("asdf");
assert.strictEqual(flag1, true);
assert.strictEqual(flag2, false);
promise.then(function (value) {
assert.strictEqual(flag2, true);
assert.strictEqual(value, "asdf");
done();
}).catch(done);
});
});
describe("nested async function calls", function () {
it("should evaluate in the right order", function (done) {
var markers = [];
function innerMost(marker) {
return regeneratorRuntime.async(function innerMost$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
markers.push(marker);
_context3.next = 3;
return regeneratorRuntime.awrap(marker);
case 3:
return _context3.abrupt("return", _context3.sent);
case 4:
case "end":
return _context3.stop();
}
}, null, this);
}
function inner(marker) {
return regeneratorRuntime.async(function inner$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
markers.push(marker);
_context4.t0 = assert;
_context4.next = 4;
return regeneratorRuntime.awrap(innerMost(marker + 1));
case 4:
_context4.t1 = _context4.sent;
_context4.t2 = marker + 1;
_context4.t0.strictEqual.call(_context4.t0, _context4.t1, _context4.t2);
markers.push(marker + 2);
_context4.t3 = assert;
_context4.next = 11;
return regeneratorRuntime.awrap(innerMost(marker + 3));
case 11:
_context4.t4 = _context4.sent;
_context4.t5 = marker + 3;
_context4.t3.strictEqual.call(_context4.t3, _context4.t4, _context4.t5);
markers.push(marker + 4);
case 15:
case "end":
return _context4.stop();
}
}, null, this);
}
function outer() {
return regeneratorRuntime.async(function outer$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
markers.push(0);
_context5.next = 3;
return regeneratorRuntime.awrap(inner(1));
case 3:
markers.push(6);
_context5.next = 6;
return regeneratorRuntime.awrap(inner(7));
case 6:
markers.push(12);
case 7:
case "end":
return _context5.stop();
}
}, null, this);
}
outer().then(function () {
var expected = [];
for (var i = 0; i <= 12; ++i) expected.push(i);
assert.deepEqual(markers, expected);
done();
}).catch(done);
});
});
describe("dependent promises", function () {
it("should be awaitable out of order", function (done) {
function outer(value) {
var resolved, p1, v2, v1;
return regeneratorRuntime.async(function outer$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
resolved = false;
p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve(value + 1);
resolved = true;
}, 0);
});
assert.strictEqual(resolved, false);
_context6.next = 5;
return regeneratorRuntime.awrap(p1.then(function (value) {
return value + 1;
}));
case 5:
v2 = _context6.sent;
assert.strictEqual(resolved, true);
_context6.next = 9;
return regeneratorRuntime.awrap(p1);
case 9:
v1 = _context6.sent;
return _context6.abrupt("return", [v1, v2]);
case 11:
case "end":
return _context6.stop();
}
}, null, this);
}
outer(1).then(function (pair) {
assert.deepEqual(pair, [2, 3]);
done();
}).catch(done);
});
});
describe("rejected promises", function () {
it("should cause await expressions to throw", function (done) {
var error = new Error("rejected");
function f(arg) {
return regeneratorRuntime.async(function f$(_context7) {
while (1) switch (_context7.prev = _context7.next) {
case 0:
_context7.prev = 0;
_context7.next = 3;
return regeneratorRuntime.awrap(arg);
case 3:
return _context7.abrupt("return", _context7.sent);
case 6:
_context7.prev = 6;
_context7.t0 = _context7["catch"](0);
assert.strictEqual(_context7.t0, error);
return _context7.abrupt("return", "did throw");
case 10:
case "end":
return _context7.stop();
}
}, null, this, [[0, 6]]);
}
Promise.all([f(Promise.reject(error)), f(Promise.resolve("did not throw"))]).then(function (results) {
assert.deepEqual(results, ["did throw", "did not throw"]);
done();
}).catch(done);
});
it("should be returned by exceptional async functions", function (done) {
var error = new Error("rejected");
function e(arg) {
return regeneratorRuntime.async(function e$(_context8) {
while (1) switch (_context8.prev = _context8.next) {
case 0:
if (!arg) {
_context8.next = 2;
break;
}
throw arg;
case 2:
return _context8.abrupt("return", "did not throw");
case 3:
case "end":
return _context8.stop();
}
}, null, this);
}
function f(arg) {
return regeneratorRuntime.async(function f$(_context9) {
while (1) switch (_context9.prev = _context9.next) {
case 0:
_context9.next = 2;
return regeneratorRuntime.awrap(e(arg));
case 2:
return _context9.abrupt("return", _context9.sent);
case 3:
case "end":
return _context9.stop();
}
}, null, this);
}
function g(arg) {
return regeneratorRuntime.async(function g$(_context10) {
while (1) switch (_context10.prev = _context10.next) {
case 0:
_context10.next = 2;
return regeneratorRuntime.awrap(f(arg));
case 2:
return _context10.abrupt("return", _context10.sent);
case 3:
case "end":
return _context10.stop();
}
}, null, this);
}
function h(arg) {
return regeneratorRuntime.async(function h$(_context11) {
while (1) switch (_context11.prev = _context11.next) {
case 0:
_context11.next = 2;
return regeneratorRuntime.awrap(Promise.all([g(arg), Promise.resolve("dummy")]));
case 2:
return _context11.abrupt("return", _context11.sent);
case 3:
case "end":
return _context11.stop();
}
}, null, this);
}
Promise.all([h(error).then(function () {
done(new Error("should not have resolved"));
}, function (e) {
assert.strictEqual(e, error);
return "ok1";
}), h(null).then(function (result) {
assert.deepEqual(result, ["did not throw", "dummy"]);
return "ok2";
})]).then(function (results) {
assert.deepEqual(results, ["ok1", "ok2"]);
done();
}).catch(done);
});
it("should propagate failure when returned", function () {
var rejection = new Error("rejection");
function f() {
return regeneratorRuntime.async(function f$(_context12) {
while (1) switch (_context12.prev = _context12.next) {
case 0:
return _context12.abrupt("return", new Promise(function (resolve, reject) {
reject(rejection);
}));
case 1:
case "end":
return _context12.stop();
}
}, null, this);
}
return f().then(function (result) {
assert.ok(false, "should have been rejected");
}, function (error) {
assert.strictEqual(error, rejection);
});
});
});
describe("async function expressions", function () {
it("should be allowed", function (done) {
(function _callee(arg) {
return regeneratorRuntime.async(function _callee$(_context13) {
while (1) switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return regeneratorRuntime.awrap(arg);
case 2:
return _context13.abrupt("return", _context13.sent);
case 3:
case "end":
return _context13.stop();
}
}, null, this);
})(Promise.resolve(1234)).then(function (value) {
assert.strictEqual(value, 1234);
done();
}).catch(done);
});
});
});
describe("async generator functions", function () {
it("should return a working AsyncIterator", function () {
var _marked = [gen].map(regeneratorRuntime.mark);
var markers = [];
function gen(arg) {
var sent, result;
return regeneratorRuntime.async(function gen$(_context14) {
while (1) switch (_context14.prev = _context14.next) {
case 0:
markers.push(0);
_context14.next = 3;
return arg;
case 3:
sent = _context14.sent;
markers.push(1);
_context14.next = 7;
return regeneratorRuntime.awrap(sent);
case 7:
result = _context14.sent;
markers.push(2);
_context14.t0 = assert;
_context14.t1 = regeneratorRuntime;
_context14.next = 13;
return "second";
case 13:
_context14.t2 = _context14.sent;
_context14.next = 16;
return _context14.t1.awrap.call(_context14.t1, _context14.t2);
case 16:
_context14.t3 = _context14.sent;
_context14.t0.strictEqual.call(_context14.t0, _context14.t3, "sent after second");
markers.push(3);
return _context14.abrupt("return", result);
case 20:
case "end":
return _context14.stop();
}
}, _marked[0], this);
}
var iter = gen("initial argument");
assert.deepEqual(markers, []);
var firstPromise = iter.next();
assert.deepEqual(markers, [0]);
return firstPromise.then(function (firstResult) {
assert.deepEqual(firstResult, {
value: "initial argument",
done: false
});
assert.deepEqual(markers, [0]);
return iter.next(new Promise(function (resolve) {
setTimeout(resolve, 100);
}).then(function () {
assert.deepEqual(markers, [0, 1]);
return "will become final result";
}));
}).then(function (secondResult) {
assert.deepEqual(secondResult, {
value: "second",
done: false
});
assert.deepEqual(markers, [0, 1, 2]);
return iter.next("sent after second");
}).then(function (finalResult) {
assert.deepEqual(markers, [0, 1, 2, 3]);
assert.deepEqual(finalResult, {
value: "will become final result",
done: true
});
});
});
it("should keep results in order", function () {
var _marked2 = [range].map(regeneratorRuntime.mark);
function range(limit) {
var before, after, i;
return regeneratorRuntime.async(function range$(_context15) {
while (1) switch (_context15.prev = _context15.next) {
case 0:
before = [];
after = [];
i = 0;
case 3:
if (!(i < limit)) {
_context15.next = 11;
break;
}
before.push(i);
_context15.next = 7;
return i;
case 7:
after.push(i);
case 8:
++i;
_context15.next = 3;
break;
case 11:
assert.deepEqual(before, after);
return _context15.abrupt("return", before);
case 13:
case "end":
return _context15.stop();
}
}, _marked2[0], this);
}
var limit = 10;
var iter = range(limit);
var promises = [];
var results = [];
for (var i = 0; i < limit; ++i) {
var promise = iter.next();
promises.push(promise);
promise.then(function (result) {
assert.strictEqual(result.done, false);
results.push(result);
});
}
assert.deepEqual(results, []);
return Promise.all(promises).then(function (promiseResults) {
assert.deepEqual(results, promiseResults);
return iter.next();
}).then(function (finalResult) {
assert.deepEqual(results.map(function (result) {
return result.value;
}), finalResult.value);
assert.strictEqual(finalResult.done, true);
});
});
it("should be able to handle many awaits", function () {
var _marked3 = [gen].map(regeneratorRuntime.mark);
var awaitCount = 0;
function countAwait(i) {
return Promise.resolve(i).then(function () {
++awaitCount;
});
}
function gen(limit) {
var i;
return regeneratorRuntime.async(function gen$(_context16) {
while (1) switch (_context16.prev = _context16.next) {
case 0:
_context16.next = 2;
return regeneratorRuntime.awrap(countAwait(0));
case 2:
_context16.next = 4;
return 1;
case 4:
_context16.next = 6;
return regeneratorRuntime.awrap(countAwait(2));
case 6:
_context16.next = 8;
return regeneratorRuntime.awrap(countAwait(3));
case 8:
_context16.next = 10;
return 4;
case 10:
_context16.next = 12;
return regeneratorRuntime.awrap(countAwait(5));
case 12:
_context16.next = 14;
return regeneratorRuntime.awrap(countAwait(6));
case 14:
_context16.next = 16;
return regeneratorRuntime.awrap(countAwait(7));
case 16:
_context16.next = 18;
return 8;
case 18:
i = 0;
case 19:
if (!(i < limit)) {
_context16.next = 25;
break;
}
_context16.next = 22;
return regeneratorRuntime.awrap(countAwait(i));
case 22:
++i;
_context16.next = 19;
break;
case 25:
return _context16.abrupt("return", "done");
case 26:
case "end":
return _context16.stop();
}
}, _marked3[0], this);
}
var iter = gen(100);
return iter.next().then(function (result) {
assert.strictEqual(awaitCount, 1);
assert.deepEqual(result, {
value: 1,
done: false
});
return iter.next();
}).then(function (result) {
assert.strictEqual(awaitCount, 3);
assert.deepEqual(result, {
value: 4,
done: false
});
return iter.next();
}).then(function (result) {
assert.strictEqual(awaitCount, 6);
assert.deepEqual(result, {
value: 8,
done: false
});
return iter.next();
}).then(function (result) {
assert.strictEqual(awaitCount, 6 + 100);
assert.deepEqual(result, {
value: "done",
done: true
});
return iter.next();
}).then(function (result) {
assert.deepEqual(result, {
value: void 0,
done: true
});
});
});
it("should not propagate exceptions between iterations", function () {
var _marked4 = [gen].map(regeneratorRuntime.mark);
function gen() {
return regeneratorRuntime.async(function gen$(_context17) {
while (1) switch (_context17.prev = _context17.next) {
case 0:
_context17.next = 2;
return 1;
case 2:
_context17.next = 4;
return 2;
case 4:
case "end":
return _context17.stop();
}
}, _marked4[0], this);
}
var iter = gen();
return iter.next().then(function (result) {
assert.deepEqual(result, {
value: 1,
done: false
});
return iter.throw(new Error("thrown from first yield"));
}).then(function () {
throw new Error("should have thrown");
}, function (error) {
assert.strictEqual(error.message, "thrown from first yield");
return iter.next();
}).then(function (result) {
assert.deepEqual(result, {
value: void 0,
done: true
});
});
});
it("should allow yielding a rejected Promise", function () {
var _marked5 = [gen].map(regeneratorRuntime.mark);
var yielded = new Error("yielded rejection");
var returned = new Error("returned rejection");
function gen() {
return regeneratorRuntime.async(function gen$(_context18) {
while (1) switch (_context18.prev = _context18.next) {
case 0:
_context18.t0 = assert;
_context18.next = 3;
return Promise.reject(yielded);
case 3:
_context18.t1 = _context18.sent;
_context18.t0.strictEqual.call(_context18.t0, _context18.t1, "first sent");
_context18.t2 = assert;
_context18.next = 8;
return "middle";
case 8:
_context18.t3 = _context18.sent;
_context18.t2.strictEqual.call(_context18.t2, _context18.t3, "second sent");
return _context18.abrupt("return", Promise.reject(returned));
case 11:
case "end":
return _context18.stop();
}
}, _marked5[0], this);
}
var iter = gen();
return iter.next().then(function (result) {
assert.ok(false, "should have yielded a rejected Promise");
}, function (error) {
assert.strictEqual(error, yielded);
return iter.next("first sent");
}).then(function (result) {
assert.deepEqual(result, {
value: "middle",
done: false
});
return iter.next("second sent");
}).then(function (result) {
assert.ok(false, "should have returned a rejected Promise");
}, function (error) {
assert.strictEqual(error, returned);
});
});
});