Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nightwatch: Better way than `.pause(1000)` to avoid brittle tests?

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...

like image 912
Peter V. Mørch Avatar asked Oct 19 '15 21:10

Peter V. Mørch


People also ask

What is Nightwatch in testing?

Nightwatch. js is an integrated, easy to use End-to-End testing solution for web applications and websites, written in Node. js. It uses the W3C WebDriver API to drive browsers and perform commands and assertions on DOM elements.

What is Nightwatch used for?

Nightwatch. js facilitates end-to-end testing of web applications and websites, by utilizing W3C Webdriver API (also known as Selenium Webdriver) as Selenium wrapper for interacting with different browsers. It helps in making the implementation of CI/CD much easier.

What is Nightwatch in Selenium?

Nightwatch. js framework is a Selenium-based test automation framework, written in Node. js and uses the W3C WebDriver API (formerly Selenium WebDriver). It works by communicating over a restful HTTP API with a WebDriver server (such as ChromeDriver or Selenium Server).


1 Answers

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)
  }
};
like image 136
Stuart Brock Avatar answered Oct 27 '22 19:10

Stuart Brock