| 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.logCustomEvent = event => { |
| this.logEvent('custom', event, false); |
| }; |
| 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 customSpy = logger => event => logger.logCustomEvent(event); |
| |
| 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.custom = function (expectedValue, message = 'on custom event') { |
| |
| const msg = `step: ${index} - ${message}`; |
| let step = logger[index]; |
| |
| assert(step.type, 'custom', msg); |
| assert(step.value, expectedValue, msg); |
| assert(step.done, false, 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; |
| }); |
| }; |
| |
| var logger = new Logger(); |
| const someValue = 'some-value'; |
| const errorMessage = 'error-message'; |
| |
| async function * foo(value) { |
| let re = yield '1:' + value; |
| re = yield '2:' + re; |
| re = yield '3:' + re; |
| return 'end foo:' + re; |
| } |
| |
| async function * boo(value) { |
| let reply = yield '0:' + value; |
| reply = yield* foo(reply); |
| yield '4:' + reply; |
| } |
| |
| var b = boo('init'); |
| |
| b.next('0').then(fulfillSpy(logger)); |
| b.next('1').then(fulfillSpy(logger)); |
| b.next('2').then(fulfillSpy(logger)); |
| b.next('3').then(fulfillSpy(logger)); |
| b.next('4').then(fulfillSpy(logger)); |
| b.next('5').then(fulfillSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0:init') |
| .fullfilled('1:1') |
| .fullfilled('2:2') |
| .fullfilled('3:3') |
| .fullfilled('4:end foo:4') |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| var b2 = boo(':value'); |
| |
| b2.next(':0').then(fulfillSpy(logger)); |
| b2.next(':1').then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.return(someValue).then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.next(':2').then(fulfillSpy(logger)); |
| b2.next(':3').then(fulfillSpy(logger)); |
| b2.next(':4').then(fulfillSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0::value') |
| .fullfilled('1::1') |
| .fullfilledDone(someValue) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| var b2 = boo('#value'); |
| |
| b2.next('#0').then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.next('#1').then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.next('#2').then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.throw(new Error(errorMessage)).then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.next('#3').then(fulfillSpy(logger), rejectSpy(logger)); |
| b2.next('#4').then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0:#value') |
| .fullfilled('1:#1') |
| .fullfilled('2:#2') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| async function * bar() { |
| yield '1'; |
| yield '2'; |
| throw new Error(errorMessage); |
| yield '3'; |
| return 'end foo'; |
| } |
| |
| async function * baz() { |
| yield '0'; |
| yield* bar(); |
| yield '4'; |
| } |
| |
| logger.clear(); |
| var bz1 = baz(); |
| |
| bz1.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| bz1.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| bz1.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| bz1.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| bz1.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilled('2') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| let promiseHolder = {}; |
| |
| async function *joo() { |
| yield '1'; |
| yield getPromise(promiseHolder); |
| } |
| |
| async function *goo () { |
| yield '0'; |
| yield* joo(); |
| yield '3'; |
| } |
| |
| let g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.resolve('2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilled('2') |
| .fullfilled('3') |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.reject('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected('#2') |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.return(someValue).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilledDone(someValue) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.return(someValue).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.resolve('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilled('#2') |
| .fullfilledDone(someValue) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.return(someValue).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.reject('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected('#2') |
| .fullfilledDone(someValue) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.throw(new Error(errorMessage)).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| promiseHolder.resolve('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.throw(new Error(errorMessage)).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.resolve('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilled('#2') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| g = goo(); |
| |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.throw(new Error(errorMessage)).then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| g.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .isFinal(); |
| |
| promiseHolder.reject('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected('#2') |
| .rejected(new Error(errorMessage)) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| async function *koo() { |
| yield '1'; |
| await getPromise(promiseHolder); |
| } |
| |
| async function *loo () { |
| yield '0'; |
| yield* joo(); |
| yield '3'; |
| } |
| |
| let l = loo(); |
| |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled("0") |
| .fullfilled("1") |
| .isFinal(); |
| |
| promiseHolder.resolve('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .fullfilled('#2') |
| .fullfilled("3") |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| l = loo(); |
| |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| l.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled("0") |
| .fullfilled("1") |
| .isFinal(); |
| |
| promiseHolder.reject('#2'); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled('0') |
| .fullfilled('1') |
| .rejected('#2') |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| let asyncIter = { |
| [Symbol.asyncIterator]() { return this; }, |
| next (value) { |
| customSpy(logger)('next:' + value); |
| return { value: value, done: 'iter:Finish' === value }; |
| }, |
| throw (error) { |
| customSpy(logger)('throw:' + error); |
| return error; |
| }, |
| return(value) { |
| customSpy(logger)('return:' + value); |
| return { value: value, done: true }; |
| } |
| }; |
| |
| async function *moo () { |
| yield '0'; |
| yield* asyncIter; |
| yield '3'; |
| } |
| |
| let m = moo('Init'); |
| |
| m.next('A').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('B').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('C').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('D').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('E').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('iter:Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .custom('next:undefined') |
| .fullfilled('0') |
| .custom('next:C') |
| .fullfilled(undefined) |
| .custom('next:D') |
| .fullfilled('C') |
| .custom('next:E') |
| .fullfilled('D') |
| .custom('next:iter:Finish') |
| .fullfilled('E') |
| .fullfilled('3') |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| m = moo('Init'); |
| |
| m.next('A').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('B').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.return('C').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('D').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('E').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('iter:Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .custom('next:undefined') |
| .fullfilled('0') |
| .custom('return:C') |
| .fullfilled(undefined) |
| .fullfilledDone('C') |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| m = moo('Init'); |
| |
| m.next('A').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('B').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.throw(new Error(errorMessage)).then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('D').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('E').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('iter:Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| m.next('Finish').then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .custom('next:undefined') |
| .fullfilled('0') |
| .custom('throw:' + new Error(errorMessage)) |
| .fullfilled(undefined) |
| .custom('next:D') |
| .fullfilled(undefined) |
| .custom('next:E') |
| .fullfilled('D') |
| .custom('next:iter:Finish') |
| .fullfilled('E') |
| .fullfilled('3') |
| .fullfilledDone(undefined) |
| .isFinal(); |
| |
| logger.clear(); |
| |
| async function* noo() { |
| try { |
| await Promise.reject("doop"); |
| } finally { |
| yield* [1, 2, 3]; // Is this line reachable in this implementation? |
| } |
| } |
| |
| const n = noo(); |
| |
| n.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| n.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| n.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| n.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| n.next().then(fulfillSpy(logger), rejectSpy(logger)); |
| |
| drainMicrotasks(); |
| |
| assertLogger(logger) |
| .fullfilled(1) |
| .fullfilled(2) |
| .fullfilled(3) |
| .rejected('doop'); |