async/await breaks the control flow · Issue #3037 · SeleniumHQ/selenium (original) (raw)

Meta -

OS:
Ubuntu
Selenium Version:
2.53.3 or 3.0.0-beta-3
Browser:
node
Browser Version:
v5.10.1 or v4.0.0

Bug

I was trying to improve async/await support for Protractor when I ran into a problem with the folllowing test:

describe('async function + control flow', function() { var val; var seven; it('should wait for this it() to finish', async function() { val = 1; seven = await webdriver.promise.fulfilled(7); controlFlow.execute(() => { return webdriver.promise.delayed(1000).then(() => { val = seven; })); });

it('should have waited for setter in previous it()', function() { expect(val).toBe(7); // <<------ This fails }); });

async/await are being compiled by the typescript compiler in this case, and jasminewd2 wraps each it() block in the control flow, so this test should have worked. However, the final assertion failed, with val still being 1.

Compiling down to ES6 and stripping out the jasmine/jasminewd2, the above translates to the following:

var webdriver = require('selenium-webdriver'), flow = webdriver.promise.controlFlow();

var val;

function runInFlow(fun, name) { return flow.execute(() => { return webdriver.promise.fulfilled(fun()); }, name); }

runInFlow(() => { val = 1; return new Promise((resolve) => { resolve(webdriver.promise.fulfilled(7)); }).then((seven) => { runInFlow(() => { return webdriver.promise.delayed(1000).then(() => { val = seven; }); }, 'set outer'); }); }, 'set inner');

runInFlow(() => { console.log('RESULT: val = ' + val); // 1, should be 7 }, 'log');

Basically, by putting a webdriver promise inside an ES6 promise inside a webdriver promise, we somehow break the control flow. This is a problem because await compiles down to an ES6 promise, and async functions then return those promises. So if you await some webdriver promise, and then wrap the async function in the control flow, you will run into this bug (as in the first example). This means that Protractor users (or any users who wrap blocks of code in the control flow) basically cannot await an element.getText() command or any other webdriver promise or else everything will become desynchronized.

I know that as per #2969 you plan on removing ManagedPromise/the control flow entirely. But in the mean time, async functions are practically unusable, so this seemed worth bringing to your attention.