14

Is .pause(1000) really the best-practice there is to wait for form submission? I'm looking for a way to reliably submit a form without having to know details about the page appearing as a result of the form submission.

The example from the home page uses .pause(1000) to wait for form submissions, and ironically doesn't work any longer, but this version with a modified css-selector version does:

module.exports = {
  'Demo test Google' : function (client) {
    client
      .url('http://www.google.com')
      .waitForElementVisible('body', 1000)
      .assert.title('Google')
      .assert.visible('input[type=text]')
      .setValue('input[type=text]', 'rembrandt van rijn')
      .waitForElementVisible('button[name=btnG]', 1000)
      .click('button[name=btnG]')
      .pause(1000)
      // This selector is different from the home page's - this one
      // works...
      .assert.containsText('ol#rso div.g:first-of-type',
        'Rembrandt - Wikipedia')
  }
};

The problem with .pause(1000) to ensure the form gets submitted is how to determine the timeout. It is either going to make our tests slow if the timeout is too long or make them brittle if the timeout is too short. Slow hardware, other processes on the server, moon alignment, you name it can influence what "good" timeout values should be.

Is there a better way to say: "Wait for the form to be submitted before continuing"?

We've experimented with .waitForElementVisible('body', VERY_LONG_TIMEOUT) instead, and it seems to work and not take longer than necessary, but I'm guessing this also isn't reliable. That it only works because the "current" page has disappeared (this time) and so we're waiting for the "new" page's body to appear. And that tomorrow some oddity will occur and it'll be faster than normal and .waitForElementVisible('body') will return immediately because the old page is still there. == also brittle. Is that correct?

If so, is there some less brittle way than .pause(1000) or .waitForElementVisible('body')? Especially if we don't know much about the page returned after the submission, so we can't .waitForElementVisible('.element-only-on-new-page')?

The reason I'm asking is that our tests actually looked more like:

module.exports = {
  'Test1 - submit form' : function (client) {
    client
      .url('http://some/url')
      .waitForElementVisible('body', 1000)
      .assert.title('MyTitle')
      .setValue('input[name="widget"]', 'value')
      // Click to submit the form to change some internal state
      .click('button[name="postForm"]')

      // Form got submitted fine in chromium 42 every single time. chromium
      // 45 needs additionally:
      //
      // .pause(1000)
      // or
      // .waitForElementVisible('body', 1000)
  }
  'Test2 - continue using new value' : function (client) {
    client
      .url('http://some/other/url')
      .waitForElementVisible('body', 1000)
      .assert.title('MyOtherTitle')
      .setValue('input[name="widget2"]', 'value2')
      .waitForElementVisible('.bla-bla', 1000)
  }
};

This broke because the form at 'http://some/url' no longer gets submitted in chromium 45 :-( We'd like find a good solution, not just one that seems to work under today's conditions...

Peter V. Mørch
  • 9,433
  • 5
  • 46
  • 65
  • I've since been thinking: Before posting, add a hidden element with a randomly generated ID. Post. Wait for body to be present but the random element to be absent. Then we know the new page has loaded. – Peter V. Mørch Sep 12 '19 at 07:31

1 Answers1

9

Have you tried chaining waitForElementNotVisible with waitForElementVisible for the body html? This should only wait for the appropriate time at each step. I'd do some testing to make sure it isn't brittle though. We're using this to monitor a "simulated page transition" in a Single Page Application.

e.g.

module.exports = {
  'Test1 - submit form' : function (client) {
    client
      .url('http://some/url')
      .waitForElementVisible('body', 1000)
      .assert.title('MyTitle')
      .setValue('input[name="widget"]', 'value')
      // Click to submit the form to change some internal state
      .click('button[name="postForm"]')
      .waitForElementNotVisible('body', 5000)
      .waitForElementVisible('body', 10000)
  }
};
Stuart Brock
  • 2,676
  • 1
  • 18
  • 20
  • There's an idea. I'm wondering whether this won't be brittle in another way: What if the machine running nightwatch is slow and the ones running selenium and the webserver are fast. I imagine that then the page could refresh quickly, so that the `.waitForElementNotVisible()` call times out. – Peter V. Mørch Aug 22 '16 at 22:54
  • 1
    `` disappears and re-appears in the SPA? funKY! :-) – Peter V. Mørch Aug 22 '16 at 22:58
  • Perhaps, I'd recommend testing. Maybe try a VM and throttle it somehow? We've found Nightwatch to be very quick at picking up DOM changes. I adapted the code from our SPA, we have a `#content div` that is updated (hidden and shown) for page transitions not the `body`. I also do a check for title to make sure it's on the right page when it "reappears". – Stuart Brock Aug 23 '16 at 08:30
  • An added complexity in using stuff like elementVisible and elementNotVisibile is when you're using weak hosting and chaingunning tests. 500s make your elementNotVisibile call pass but the next call bomb out. – RobotHumans May 06 '17 at 21:54