mirror of
https://github.com/hanzoai/babel.git
synced 2026-10-30 14:46:06 +00:00
625 lines
14 KiB
JavaScript
625 lines
14 KiB
JavaScript
/**
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
var assert = require("assert");
|
|
|
|
assert(
|
|
function* () {}.toString().indexOf("regenerator") !== -1,
|
|
"regenerator-transform should be enabled",
|
|
);
|
|
|
|
describe("async functions and await expressions", function () {
|
|
describe("no-await async function", function () {
|
|
it("should return a Promise", function (done) {
|
|
var called = false;
|
|
|
|
async function noAwait(value) {
|
|
called = true;
|
|
return value;
|
|
}
|
|
|
|
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;
|
|
|
|
async function oneAwait(value) {
|
|
flag1 = true;
|
|
var result = await value;
|
|
flag2 = true;
|
|
return result;
|
|
}
|
|
|
|
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 = [];
|
|
|
|
async function innerMost(marker) {
|
|
markers.push(marker);
|
|
return await marker;
|
|
}
|
|
|
|
async function inner(marker) {
|
|
markers.push(marker);
|
|
|
|
assert.strictEqual(await innerMost(marker + 1), marker + 1);
|
|
|
|
markers.push(marker + 2);
|
|
|
|
assert.strictEqual(await innerMost(marker + 3), marker + 3);
|
|
|
|
markers.push(marker + 4);
|
|
}
|
|
|
|
async function outer() {
|
|
markers.push(0);
|
|
await inner(1);
|
|
markers.push(6);
|
|
await inner(7);
|
|
markers.push(12);
|
|
}
|
|
|
|
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) {
|
|
async function outer(value) {
|
|
var resolved = false;
|
|
var p1 = new Promise(function (resolve) {
|
|
setTimeout(function () {
|
|
resolve(value + 1);
|
|
resolved = true;
|
|
}, 0);
|
|
});
|
|
|
|
assert.strictEqual(resolved, false);
|
|
|
|
var v2 = await p1.then(function (value) {
|
|
return value + 1;
|
|
});
|
|
|
|
assert.strictEqual(resolved, true);
|
|
|
|
var v1 = await p1;
|
|
|
|
return [v1, v2];
|
|
}
|
|
|
|
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");
|
|
|
|
async function f(arg) {
|
|
try {
|
|
return await arg;
|
|
} catch (e) {
|
|
assert.strictEqual(e, error);
|
|
return "did throw";
|
|
}
|
|
}
|
|
|
|
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");
|
|
|
|
async function e(arg) {
|
|
if (arg) {
|
|
throw arg;
|
|
}
|
|
return "did not throw";
|
|
}
|
|
|
|
async function f(arg) {
|
|
return await e(arg);
|
|
}
|
|
|
|
async function g(arg) {
|
|
return await f(arg);
|
|
}
|
|
|
|
async function h(arg) {
|
|
return await Promise.all([g(arg), Promise.resolve("dummy")]);
|
|
}
|
|
|
|
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");
|
|
|
|
async function f() {
|
|
return new Promise(function (resolve, reject) {
|
|
reject(rejection);
|
|
});
|
|
}
|
|
|
|
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) {
|
|
(async function (arg) {
|
|
return await arg;
|
|
})(Promise.resolve(1234))
|
|
.then(function (value) {
|
|
assert.strictEqual(value, 1234);
|
|
done();
|
|
})
|
|
.catch(done);
|
|
});
|
|
});
|
|
|
|
describe("the this object", function () {
|
|
it("should default to undefined (strict)", function (done) {
|
|
async function f() {
|
|
"use strict";
|
|
|
|
return this;
|
|
}
|
|
|
|
f()
|
|
.then(function (value) {
|
|
assert.strictEqual(value, undefined);
|
|
done();
|
|
})
|
|
.catch(done);
|
|
});
|
|
|
|
it("should respect .call's this", function (done) {
|
|
async function f() {
|
|
return this;
|
|
}
|
|
|
|
var self = {};
|
|
f.call(self)
|
|
.then(function (value) {
|
|
assert.strictEqual(value, self);
|
|
done();
|
|
})
|
|
.catch(done);
|
|
});
|
|
|
|
it("shouldn't capture this when not needed", function () {
|
|
// https://github.com/babel/babel/issues/4056
|
|
|
|
async function f() {
|
|
return 0;
|
|
}
|
|
|
|
var source = String(f);
|
|
assert.strictEqual(source.indexOf("this"), -1);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("async generator functions", function () {
|
|
// Transforming this currently leaves behind a `regeneratorRuntime` reference,
|
|
// rather than referencing the helper.
|
|
it.skip("should return a working AsyncIterator", function () {
|
|
var markers = [];
|
|
|
|
async function* gen(arg) {
|
|
markers.push(0);
|
|
var sent = yield arg;
|
|
markers.push(1);
|
|
var result = await sent;
|
|
markers.push(2);
|
|
assert.strictEqual(await (yield "second"), "sent after second");
|
|
markers.push(3);
|
|
return result;
|
|
}
|
|
|
|
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 () {
|
|
async function* range(limit) {
|
|
var before = [];
|
|
var after = [];
|
|
for (var i = 0; i < limit; ++i) {
|
|
before.push(i);
|
|
yield i;
|
|
after.push(i);
|
|
}
|
|
assert.deepEqual(before, after);
|
|
return before;
|
|
}
|
|
|
|
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 awaitCount = 0;
|
|
|
|
function countAwait(i) {
|
|
return Promise.resolve(i).then(function () {
|
|
++awaitCount;
|
|
});
|
|
}
|
|
|
|
async function* gen(limit) {
|
|
await countAwait(0);
|
|
yield 1;
|
|
await countAwait(2);
|
|
await countAwait(3);
|
|
yield 4;
|
|
await countAwait(5);
|
|
await countAwait(6);
|
|
await countAwait(7);
|
|
yield 8;
|
|
for (var i = 0; i < limit; ++i) {
|
|
await countAwait(i);
|
|
}
|
|
return "done";
|
|
}
|
|
|
|
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 () {
|
|
async function* gen() {
|
|
yield 1;
|
|
yield 2;
|
|
}
|
|
|
|
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 yielded = new Error("yielded rejection");
|
|
var returned = new Error("returned rejection");
|
|
|
|
async function* gen() {
|
|
assert.strictEqual(yield "first yielded", "first sent");
|
|
try {
|
|
assert.strictEqual(yield Promise.reject(yielded), "not reached");
|
|
} catch (e) {
|
|
assert.strictEqual(yield e, "second sent");
|
|
return Promise.reject(returned);
|
|
}
|
|
}
|
|
|
|
var iter = gen();
|
|
|
|
return iter
|
|
.next()
|
|
.then(function (result) {
|
|
assert.deepEqual(result, {
|
|
value: "first yielded",
|
|
done: false,
|
|
});
|
|
return iter.next("first sent");
|
|
})
|
|
.then(function (result) {
|
|
assert.deepEqual(result, {
|
|
value: yielded,
|
|
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);
|
|
},
|
|
);
|
|
});
|
|
|
|
it("should work with nested arrow functions", async function () {
|
|
var a = async b => {
|
|
return await (async () => {
|
|
return await b();
|
|
})();
|
|
};
|
|
|
|
assert.strictEqual(await a(() => Promise.resolve(1234)), 1234);
|
|
});
|
|
|
|
it("should support super.method(...) in async methods", async function () {
|
|
class A {
|
|
async method() {
|
|
return "from A";
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
async method() {
|
|
return "from B " + (await super.method());
|
|
}
|
|
}
|
|
|
|
assert.strictEqual(await new B().method(), "from B from A");
|
|
});
|
|
});
|
|
|
|
describe("update operators", function () {
|
|
it("should read left side before yielding", function () {
|
|
let x = 0;
|
|
|
|
function* test() {
|
|
x += yield;
|
|
}
|
|
|
|
var gen = test();
|
|
gen.next();
|
|
x += 1;
|
|
assert.strictEqual(x, 1);
|
|
|
|
gen.next(2);
|
|
assert.strictEqual(x, 2);
|
|
});
|
|
|
|
it("should explode left side before yielding", function () {
|
|
let obj = { count: 0 };
|
|
|
|
function* test() {
|
|
obj[yield "key"] += yield "value";
|
|
}
|
|
|
|
var gen = test();
|
|
|
|
assert.deepEqual(gen.next(), { value: "key", done: false });
|
|
assert.strictEqual(obj.count, 0);
|
|
|
|
assert.deepEqual(gen.next("count"), { value: "value", done: false });
|
|
assert.strictEqual(obj.count, 0);
|
|
|
|
obj.count += 1;
|
|
assert.strictEqual(obj.count, 1);
|
|
|
|
assert.deepEqual(gen.next(2), { value: void 0, done: true });
|
|
assert.strictEqual(obj.count, 2);
|
|
});
|
|
|
|
it("should read left side before awaiting", function () {
|
|
let x = 0;
|
|
|
|
async function test(val) {
|
|
x += await val;
|
|
return x;
|
|
}
|
|
|
|
const promise = test(2);
|
|
x += 1;
|
|
|
|
return promise.then(result => {
|
|
assert.strictEqual(result, 2);
|
|
});
|
|
});
|
|
});
|