Commit 174b26d6 authored by David Tseng's avatar David Tseng Committed by Commit Bot

Add support to MockFeedback for promises

This change adds support for MockFeedback.prototype.replay() to be used in an async function.

For example:
async function test() {
  await doSomething();
  await mockFeedback.expectSpeech('foo')
      .call(() => doSomethingElse)
      .replay();
}

Alternatively, the following is similar, but bad usage:
async function test() {
  await doSomething();
  mockFeedback.expectSpeech('foo')
      .call(() => doSomethingElse)
      .replay();
}

because the return statement is |undefined|. In CallbackHelper, test functions are only expected to return promises, and an async function that returns undefined automatically converts that value to a promise which automatically gets resolved.
Such a promise passes the test incorrectly even if the test throws an assertion. THis occurs when MockFeedback which loops over all actions, gets an assertion, and does not hault execution and keeps trying to match expectations. If at some point, the expectation is matched in the future, the test passes.

For existing tests that are not async, this change does not make any diffference.

e.g.

function test() {
  mockFeedback.call(() => doSomething)
      .expectSpeech('foo')
      .call(() => doSomethingElse)
      .replay();
}

because CallbackHelper, when it receives no return value, goes back to the standard way of counting callbacks; when it hits zero, it finishes the test.
The promise returned by replay doesn't make any impact on the test since the test is not async so returning undefined (implicitly here) does not convert it to a promise.

AX-Relnotes: n/a

Change-Id: I61509222a28730ee3bf8b80349bd11f4b9516636
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2473805
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#818083}
parent c3c27885
......@@ -507,7 +507,7 @@ TEST_F('ChromeVoxTutorialTest', 'QuickOrientationLessonTest', function() {
};
let firstLessonNode;
mockFeedback.expectSpeech('Choose your tutorial experience')
await mockFeedback.expectSpeech('Choose your tutorial experience')
.call(doCmd('nextObject'))
.expectSpeech('Quick orientation')
.call(doCmd('forceClickOnCurrentItem'))
......
......@@ -371,11 +371,20 @@ MockFeedback = class {
* When all expectations are satisfied and registered callbacks called,
* the finish callbcak, if any, is called.
* This function may only be called once.
* @return {!Promise} Mandatory to await on if used in async functions.
*/
replay() {
assertFalse(this.replaying_);
this.replaying_ = true;
const promise = new Promise((resolve, reject) => {
this.resolve_ = resolve;
this.reject_ = reject;
});
this.process_();
return promise;
}
/**
......@@ -448,6 +457,7 @@ MockFeedback = class {
this.finishedCallback_();
this.finishedCallback_ = null;
}
this.resolve_();
} else {
// If there are pending actions and no matching feedback for a few
// seconds, log the pending state to ease debugging.
......@@ -456,6 +466,9 @@ MockFeedback = class {
window.setTimeout(this.logPendingState_.bind(this), 2000);
}
}
} catch (e) {
this.reject_(e);
throw e;
} finally {
this.inProcess_ = false;
}
......
......@@ -35,11 +35,19 @@ CallbackHelper.prototype = {
if (!(result instanceof Promise)) {
throw new Error('Only support return type of Promise');
}
result.then(() => {
if (--this.pendingCallbacks_ <= 0) {
CallbackHelper.testDone_();
}
});
result
.then(
() => {
if (--this.pendingCallbacks_ <= 0) {
CallbackHelper.testDone_();
}
},
reason => {
CallbackHelper.testDone_([false, reason.toString()]);
})
.catch(reason => {
CallbackHelper.testDone_([false, reason.toString()]);
});
} else {
if (--this.pendingCallbacks_ <= 0) {
CallbackHelper.testDone_();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment