blob: cf694764bae22e902db3995c882e8c5f1444435d [file] [log] [blame]
var assert = function (result, expected, message = "") {
if (result !== expected) {
throw new Error('Error in assert. Expected "' + expected + '" but was "' + result + '":' + message );
}
};
const Logger = function () {
var log = [];
this.logEvent = (type, value, done) => {
log.push({ type, value, done});
};
this.logFulfilledEvent = (value, done) => {
this.logEvent('fulfilled', value, done);
};
this.logRejectEvent = error => {
this.logEvent('reject', error.toString(), true);
};
this.logCatchEvent = value => {
this.logEvent('catch', value, true);
};
this.getLogger = () => log;
this.clear = () => {
log = [];
}
};
const fulfillSpy = logger => result => logger.logFulfilledEvent(result.value, result.done);
const rejectSpy = logger => error => logger.logRejectEvent(error);
const catchSpy = logger => error => logger.logCatchEvent(error);
const assertLogger = function (loggerObject) {
const logger = loggerObject.getLogger();
var _assertLogger = function () {
let index = 0;
const isNotOutOfLength = () => {
assert(index < logger.length, true, `Index is greater then log length`);
}
this.fullfilled = function (expectedValue, message = 'on fulfill') {
isNotOutOfLength();
const msg = `step: ${index} - ${message}`;
let step = logger[index];
assert(step.type, 'fulfilled', msg);
assert(step.value, expectedValue, msg);
assert(step.done, false, msg);
index++;
return this;
};
this.fullfilledDone = function (expectedValue, message = 'on fulfill with done true') {
isNotOutOfLength();
const msg = `step: ${index} - ${message}`;
let step = logger[index];
assert(step.type, 'fulfilled', msg);
assert(step.value, expectedValue, msg);
assert(step.done, true, msg);
index++;
return this;
};
this.rejected = function (error, message = 'on reject') {
isNotOutOfLength();
const msg = `step: ${index} - ${message}`;
let step = logger[index];
assert(step.type, 'reject', msg);
assert(step.value, error.toString(), msg);
assert(step.done, true, msg);
index++;
return this;
};
this.catched = function (expectedError, message = 'on catch') {
isNotOutOfLength();
const msg = `step: ${index} - ${message}`;
let step = logger[index];
assert(step.type, 'catch', msg);
assert(step.value, expectedError, msg);
assert(step.done, true, msg);
index++;
return this;
};
this.isFinal = function (message = '') {
assert(index, logger.length, `expected final step: ${message}`);
};
};
return new _assertLogger();
};
const getPromise = promiseHolder => {
return new Promise((resolve, reject) => {
promiseHolder.resolve = resolve;
promiseHolder.reject = reject;
});
};
async function*generator () {
yield 42;
}
var passed = false;
var iterator = generator();
iterator.next().then(function(step) {
if(iterator[Symbol.asyncIterator]() === iterator && step.done === false && step.value === 42) passed = true;
});
drainMicrotasks();
assert(passed, true, '');
assert(generator[Symbol.toStringTag], 'AsyncGeneratorFunction');
assert(Object.prototype.toString.call(generator), '[object AsyncGeneratorFunction]');
var holder = {};
var promise = getPromise(holder);
var logger = new Logger();
async function * baz(value) {
var t = await promise;
let reply = yield t + ' data-0' + value;
let last = yield t + ' data-1' + reply;
return 'data-result' + last;
}
var bz1 = baz(':init');
bz1.next(':0').then(fulfillSpy(logger), rejectSpy(logger));
bz1.next(':1').then(fulfillSpy(logger), rejectSpy(logger));
bz1.next(':2').then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.isFinal();
holder.resolve('abcd');
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-0:init')
.fullfilled('abcd data-1:1')
.fullfilledDone('data-result:2')
.isFinal();
logger.clear();
promise = getPromise(holder);
var bz2 = baz(':init');
bz2.next(':0').then(fulfillSpy(logger), rejectSpy(logger));
bz2.next(':1').then(fulfillSpy(logger), rejectSpy(logger));
bz2.next(':2').then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.isFinal();
holder.reject('abcd');
drainMicrotasks();
assertLogger(logger)
.rejected('abcd')
.fullfilledDone()
.fullfilledDone()
.isFinal();
var holder1 = {}; holder2 = {};
var promise1 = getPromise(holder1);
var promise2 = getPromise(holder2);
logger.clear();
async function *boo() {
var t1 = await promise1;
yield t1 + ' data-1';
yield t1 + ' data-2';
var t2 = await promise2;
yield t2 + ' data-3';
yield t2 + ' data-4';
return 'data-5';
};
var b = boo();
b.next().then(fulfillSpy(logger));
b.next().then(fulfillSpy(logger));
b.next().then(fulfillSpy(logger));
b.next().then(fulfillSpy(logger));
b.next().then(fulfillSpy(logger));
b.next().then(fulfillSpy(logger));
assertLogger(logger)
.isFinal('async generator should not resolve any promise until await is no resolved');
holder1.resolve('abcd');
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-1')
.fullfilled('abcd data-2')
.isFinal();
holder2.resolve('efgh');
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-1')
.fullfilled('abcd data-2')
.fullfilled('efgh data-3')
.fullfilled('efgh data-4')
.fullfilledDone('data-5')
.fullfilledDone(undefined, error => print(error))
.isFinal();
holder = {};
promise = getPromise(holder);
async function *foo() {
var t = await 'abcd';
yield t + ' data-5';
var t2 = await promise;
yield t2 + ' data-6';
};
logger.clear();
var f = foo();
f.next().then(fulfillSpy(logger));
f.next().then(fulfillSpy(logger));
f.next().then(fulfillSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-5')
.isFinal('async generator should not resolve any promise until await is not resolved');
holder.resolve('xyz');
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-5')
.fullfilled('xyz data-6')
.fullfilledDone(undefined)
.isFinal('async generator should not resolve any promise until await is not resolved');
holder = {};
promise = getPromise(holder);
async function *goo() {
yield 'data-5';
var t = await promise;
yield t + ' data-6';
yield t + ' data-7';
};
logger.clear();
var errorText = 'error-reject';
var g = goo();
drainMicrotasks();
g.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled('data-5')
.isFinal('async generator should not resolve any promise until await is not resolved');
g.next().then(fulfillSpy(logger), rejectSpy(logger));
g.next().then(fulfillSpy(logger), rejectSpy(logger));
assertLogger(logger)
.fullfilled('data-5')
.isFinal('async generator should not resolve any promise until await is not resolved');
holder.reject(errorText);
drainMicrotasks();
assertLogger(logger)
.fullfilled('data-5')
.rejected(errorText)
.fullfilledDone(undefined, 'After reject all resolved value have undefined')
.isFinal();
/* Method in class */
const someText = 'foo';
const resolveText = 'bar';
logger.clear();
holder = {};
promise = getPromise(holder);
class A {
async * foo() { yield someText; }
async * boo() { var text = await promise; yield text + someText; }
}
var a = new A;
var gf = a.foo();
gf.next().then(fulfillSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(someText)
.isFinal();
const gb = a.boo();
gb.next().then(fulfillSpy(logger));
assertLogger(logger)
.fullfilled(someText)
.isFinal();
holder.resolve(resolveText);
drainMicrotasks();
assertLogger(logger)
.fullfilled(someText)
.fullfilled(resolveText + someText)
.isFinal();
/* Async generator function expression */
logger.clear();
holder = {};
promise = getPromise(holder);
var asyncGenExp = async function *() { var t = await promise; yield t + someText + someText; };
var gAsyncGenExp = asyncGenExp();
gAsyncGenExp.next().then(fulfillSpy(logger));
holder.resolve(resolveText);
drainMicrotasks();
assertLogger(logger)
.fullfilled(resolveText + someText + someText)
.isFinal();
logger.clear();
/*Test throw*/
async function *joo() {
yield 'data-1';
yield 'data-2';
yield 'data-3';
};
var j = joo();
var errorTextInFunction = "ErrorInFunction";
const errorWrongGenerator = "|this| should be an async generator";
let errorRaised = false;
j.next()
.then(function(value) {
fulfillSpy(logger)(value);
return j.throw(new Error(errorTextInFunction));
})
.then(function (value) {
fulfillSpy(logger)(value);
}, function (error) {
rejectSpy(logger)(error);
return j.next();
})
.then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled('data-1')
.rejected((new Error(errorTextInFunction)).toString())
.fullfilledDone(undefined)
.isFinal();
logger.clear();
var j1 = joo();
j1.throw(new Error(errorText)).then(fulfillSpy(logger), rejectSpy(logger));
j1.next().then(fulfillSpy(logger), rejectSpy(logger));
j1.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
var j2 = joo();
const returnValue = 'return-value';
j1.return(returnValue).then(fulfillSpy(logger), rejectSpy(logger));
j1.throw(new Error(errorText)).then(fulfillSpy(logger), rejectSpy(logger));
j1.next().then(fulfillSpy(logger), rejectSpy(logger));
j1.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilledDone(returnValue)
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
let j3 = joo();
j3.next.call(undefined).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
.isFinal();
logger.clear();
j3 = joo();
j3.next.call(undefined).then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
.fullfilled('data-1')
.fullfilled('data-2')
.fullfilled('data-3')
.isFinal();
logger.clear();
j3 = joo();
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next.call(undefined).then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
.fullfilled('data-1')
.fullfilled('data-2')
.fullfilled('data-3')
.isFinal();
logger.clear();
j3 = joo();
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
j3.next.call(undefined).then(fulfillSpy(logger), rejectSpy(logger));
j3.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
.fullfilled('data-1')
.fullfilled('data-2')
.fullfilled('data-3')
.isFinal();
logger.clear();
j3 = joo();
j3.next.call({}).catch(rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
logger.clear();
j3 = joo();
j3.next.call('string').then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new TypeError(errorWrongGenerator))
.isFinal();
logger.clear();
j3 = joo();
let gen = generator();
j3.next.call(gen).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(42)
.isFinal();
logger.clear();
holder = {};
promise = getPromise(holder);
async function *koo() {
var t = await 'abcd';
yield t + ' data-first';
var t2 = await promise;
yield t2 + ' data-second';
yield t2 + ' data-third';
};
const k1 = koo();
k1.next().then(fulfillSpy(logger));
k1.next().then(fulfillSpy(logger));
k1.throw(new Error(errorText)).then(fulfillSpy(logger), rejectSpy(logger));
k1.next().then(fulfillSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-first')
.isFinal();
holder.resolve('xyz');
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-first')
.fullfilled('xyz data-second')
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.isFinal();
logger.clear();
holder = {};
promise = getPromise(holder);
const k2 = koo();
k2.next().then(fulfillSpy(logger));
k2.next().then(fulfillSpy(logger));
k2.return(returnValue).then(fulfillSpy(logger));
holder.resolve('xyz');
k2.throw(new Error(errorText)).then(fulfillSpy(logger), rejectSpy(logger));
k2.next().then(fulfillSpy(logger));
k2.next().then(fulfillSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled('abcd data-first')
.fullfilled('xyz data-second')
.fullfilledDone(returnValue)
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
holder = {};
promise = getPromise(holder);
async function *loo() {
var t = await promise;
throw new Error(errorText);
yield t + 'data-first';
yield t + 'data-second';
};
const l1 = loo();
l1.next().then(fulfillSpy(logger), rejectSpy(logger));
l1.next().then(fulfillSpy(logger), rejectSpy(logger));
l1.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.isFinal();
holder.resolve('qwe');
drainMicrotasks();
assertLogger(logger)
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
holder = {};
promise = getPromise(holder);
const l2 = loo();
l2.throw(new Error('another error')).then(fulfillSpy(logger), rejectSpy(logger));
l2.next().then(fulfillSpy(logger), rejectSpy(logger));
l2.next().then(fulfillSpy(logger), rejectSpy(logger));
holder.resolve('abc');
drainMicrotasks();
assertLogger(logger)
.rejected(new Error('another error'))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
holder = {};
promise = getPromise(holder);
const l3 = loo();
l3.return(someText).then(fulfillSpy(logger), rejectSpy(logger));
l3.next().then(fulfillSpy(logger), rejectSpy(logger));
l3.next().then(fulfillSpy(logger), rejectSpy(logger));
holder.resolve(resolveText);
drainMicrotasks();
assertLogger(logger)
.fullfilledDone(someText)
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
async function *moo() {
throw new Error(errorText);
yield t + 'data-first';
yield t + 'data-second';
};
const m1 = moo();
m1.next().then(fulfillSpy(logger), rejectSpy(logger));
m1.next().then(fulfillSpy(logger), rejectSpy(logger));
m1.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new Error(errorText))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
const m2 = moo();
m2.throw(new Error('another error')).then(fulfillSpy(logger), rejectSpy(logger));
m2.next().then(fulfillSpy(logger), rejectSpy(logger));
m2.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.rejected(new Error('another error'))
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
const m3 = moo();
m3.return(someText).then(fulfillSpy(logger), rejectSpy(logger));
m3.next().then(fulfillSpy(logger), rejectSpy(logger));
m3.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilledDone(someText)
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
async function* noo() {
const x = Promise.resolve(1);
const y = Promise.resolve(2);
const fromX = yield x;
return y;
}
const n1 = noo();
let value1 = Promise.resolve("a");
let value2 = Promise.resolve("b");
n1.next(value1).then(fulfillSpy(logger), rejectSpy(logger));
n1.next(value2).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone(2)
.isFinal();
logger.clear();
const n2 = noo();
value1 = Promise.resolve("a");
value2 = Promise.resolve("b");
n2.return(value1).then(fulfillSpy(logger), rejectSpy(logger));
n2.next(value2).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilledDone('a')
.fullfilledDone()
.isFinal();
logger.clear();
promise = getPromise(holder);
async function *ooo() {
yield promise;
}
const o1 = ooo();
o1.next(value1).then(fulfillSpy(logger), rejectSpy(logger));
holder.reject("a");
drainMicrotasks();
assertLogger(logger)
.rejected('a')
.isFinal();
logger.clear();
promise = getPromise(holder);
async function *roo() {
try {
yield promise;
} catch (e) {
yield e;
}
}
const r1 = roo();
value1 = 'value-1';
value2 = 'value-2';
value3 = 'value-3';
r1.next().then(fulfillSpy(logger), rejectSpy(logger));
r1.next(value1).then(fulfillSpy(logger), rejectSpy(logger));
r1.next(value1).then(fulfillSpy(logger), rejectSpy(logger));
holder.reject("abc");
drainMicrotasks();
assertLogger(logger)
.fullfilled('abc')
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
logger.clear();
holder1 = {};
holder2 = {};
promise1 = getPromise(holder1);
promise2 = getPromise(holder2);
async function *poo() {
try {
yield promise1;
} catch (e) {
yield promise2;
}
}
const p1 = poo();
p1.next().then(fulfillSpy(logger), rejectSpy(logger));
p1.next(value3).then(fulfillSpy(logger), rejectSpy(logger));
p1.next(value3).then(fulfillSpy(logger), rejectSpy(logger));
holder1.reject(value1);
holder2.reject(value2);
drainMicrotasks();
assertLogger(logger)
.rejected(value2)
.fullfilledDone(undefined)
.fullfilledDone(undefined)
.isFinal();
async function *soo() {
yield 1;
}
const endValue = 'end-value-1';
logger.clear();
const s1 = soo();
s1.next().then(fulfillSpy(logger), rejectSpy(logger));
s1.next().then(fulfillSpy(logger), rejectSpy(logger));
s1.return(Promise.resolve(endValue)).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone()
.fullfilledDone(endValue)
.isFinal();
logger.clear();
const s2 = soo();
s2.next().then(fulfillSpy(logger), rejectSpy(logger));
s2.next().then(fulfillSpy(logger), rejectSpy(logger));
s2.return(Promise.reject(endValue)).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone()
.rejected(endValue)
.isFinal();
logger.clear();
const s3 = soo();
s3.next().then(fulfillSpy(logger), rejectSpy(logger));
s3.next().then(fulfillSpy(logger), rejectSpy(logger));
s3.return(endValue).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone()
.fullfilledDone(endValue)
.isFinal();
logger.clear();
const s4 = soo();
promise1 = Promise.resolve(endValue);
s4.next().then(fulfillSpy(logger), rejectSpy(logger));
s4.next().then(fulfillSpy(logger), rejectSpy(logger));
s4.throw(promise1).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone()
.rejected(promise1)
.isFinal();
logger.clear();
const s5 = soo();
s5.next().then(fulfillSpy(logger), rejectSpy(logger));
s5.next().then(fulfillSpy(logger), rejectSpy(logger));
s5.throw(endValue).then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilled(1)
.fullfilledDone()
.rejected(endValue)
.isFinal();
async function *too() {
return Promise.resolve('abcd');
}
logger.clear();
const t = too();
t.next().then(fulfillSpy(logger), rejectSpy(logger));
drainMicrotasks();
assertLogger(logger)
.fullfilledDone('abcd')
.isFinal();