Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove inline awaits #13043

Merged

Conversation

stacey-gammon
Copy link
Contributor

@stacey-gammon stacey-gammon commented Jul 21, 2017

Addresses #13041 for tests.

Turns variations of the form:
await testSubjects.find('globalTimepickerRange').getVisibleText();
into
await testSubjects.getVisibleText('globalTimepickerRange');

or simply turns one line into two by breaking up the inlining of multiple functions with an await.

Having multiple functions on the same line is confusing and can potentially lead to mistakes, especially as with this change testSubjects.find returns a promise, not a webdriver object which can be used as a promise, or as the return value (which is pretty confusing).

@stacey-gammon stacey-gammon force-pushed the tests/remove-inline-awaits branch 7 times, most recently from f430469 to df433dc Compare July 25, 2017 12:21
@stacey-gammon stacey-gammon force-pushed the tests/remove-inline-awaits branch from df433dc to 5aade92 Compare July 25, 2017 16:48
@stacey-gammon
Copy link
Contributor Author

jenkins, test this

@stacey-gammon stacey-gammon merged commit c8848a4 into elastic:master Jul 25, 2017
stacey-gammon added a commit to stacey-gammon/kibana that referenced this pull request Jul 25, 2017
* remove inline awaits

* testSubjects.find now always returns a promise, so we need to make sure there is no more inlining

* more find conversions

* need to pass property name

* Make sure async functions are awaited on.
});
it('should have index pattern in page header', async function () {
const indexPageHeading = await PageObjects.settings.getIndexPageHeading();
const patternName = await indexPageHeading.getVisibleText();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super well versed in async/await, but I thought it was basically just like wrapping the call in a then handler. If I'm right about that, couldn't this be written like so?

const patternName = await PageObjects.settings.getIndexPageHeading().getVisibleText();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like return, await affects the entire expression, not just a function invocation. So await doesn't really "kick in" until it finds a newline, a semi-colon, the closing of a block, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't want to use multiple functions on the same line as an await because it's confusing (there was a little discussion in the kibana slack room and I filed #13041). Does the await apply to the first or second? Sans parens, it applies to the second. This causes extra confusion with tests if a function returns the webdriver API - it can be used as a promise, or chained together with the call that should go after the promise.

testSubjects.find changed so that it's not returning the webdriver API, it's returning a legit promise, which means we can't get away with this subtle behavior anymore. Now, the await has to be used for the first function, not the second. So you could write it like this:

const patternName = (await PageObjects.settings.getIndexPageHeading()).getVisibleText();

But to avoid all this confusion, we just decided to not use parens and not use multiple functions on the same line when an await is required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks for the education! 👯‍♂️

await PageObjects.header.waitUntilLoadingHasFinished();
await retry.try(async () => {
return await retry.try(async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason to return here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I could have sworn you gave me feedback once that said I should add a return for an async function, e.g. like I'm doing above:

    async clickTimeFieldNameField() {
       return await testSubjects.click('createIndexPatternTimeFieldSelect');
    }

The return isn't necessary then either, right? Perhaps I misunderstood your original comment from awhile back.

log.debug(`findByCssSelector ${selector}`);
return remote
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a helper method would be useful here. Maybe something like:

class Find {
  async withTimeout(timeout, block) {
    try {
      const remoteWithTimeout = remote.setFindTimeout(timeout);
      return await block(remoteWithTimeout);
    } finally {
      remote.setFindTimeout(defaultFindTimeout);
    }
  }
}

Then these methods functions could be more focused on their specific details:

class Find {
  async byCssSelector(selector, timeout = defaultFindTimeout) {
    return await this.withTimeout(timeout, async remote => {
      return await remote.findByCssSelector(selector);
    })
  }
}

async existsByCssSelector(selector) {
log.debug(`existsByCssSelector ${selector}`);
const remoteWithTimeout = remote.setFindTimeout(1000);
const exists = await remoteWithTimeout.findByCssSelector(selector)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of mixing async/await with .then().catch(). A try/catch would probably pair nicely with this.withTimeout()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So something like:

let exists = true;
try {
  await remoteWithTimeout.findByCssSelector(selector);
} catch () {
  exists =  false;
}
remoteWithTimeout.setFindTimeout(defaultFindTimeout);
return exists;

?

Copy link
Contributor

@spalger spalger Jul 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking:

async existsByCssSelector(selector) {
  log.debug(`existsByCssSelector ${selector}`);
  return await this.withTimeout(1000, async remote => {
    try {
      await remote.findByCssSelector(selector)
      return true;
    } catch (error) {
      return false;
    }
  });
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh, wasn't aware of that function, sg!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh doh, that's the function you are saying to use above. haha, yes, sounds good!

stacey-gammon added a commit that referenced this pull request Jul 26, 2017
* remove inline awaits

* testSubjects.find now always returns a promise, so we need to make sure there is no more inlining

* more find conversions

* need to pass property name

* Make sure async functions are awaited on.
stacey-gammon added a commit to stacey-gammon/kibana that referenced this pull request Jul 28, 2017
* remove inline awaits

* testSubjects.find now always returns a promise, so we need to make sure there is no more inlining

* more find conversions

* need to pass property name

* Make sure async functions are awaited on.
stacey-gammon added a commit that referenced this pull request Jul 28, 2017
* remove inline awaits

* testSubjects.find now always returns a promise, so we need to make sure there is no more inlining

* more find conversions

* need to pass property name

* Make sure async functions are awaited on.
@stacey-gammon stacey-gammon deleted the tests/remove-inline-awaits branch October 24, 2017 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants