The last step requires us to wait for the API server to respond to our request, after which we should display a success message.
A naive, but very common, approach would be to wait a few seconds before making an assertion. However, this has two disadvantages:
- If the time set is too short, it can lead to flaky tests where the tests would pass on some instances, and fail on others.
- If the time set is too long, it'll lengthen the test duration. In practice, lengthy tests means the tests are ran less often, and less useful in providing feedback to the developer.
Luckily, Selenium provides the driver.wait method, which has the following signature:
driver.wait(<condition>, <timeout>, <message>)
condition can be a Condition instance, a function, or a promise-like thenable. driver.wait will repeatedly evaluate the value of condition until it returns a truthy value. If condition is a promise, it will wait until the promise is resolved and check the resolved value to see if it is truthy. timeout is the time (in milliseconds) for which driver.wait will keep trying.
In spec/cucumber/steps/assertions/index.js, add the following step definition:
import chai, { expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { By, until } from 'selenium-webdriver';
chai.use(chaiAsPromised);
Then(/^the (?:"|')([\.#\w-]+)(?:"|') element should appear within (\d+) milliseconds$/, function (selector, timeout) {
return expect(this.driver.wait(until.elementLocated(By.css(selector)), timeout)).to.be.fulfilled;
});
We are using until.elementLocated as the condition, which will resolve to a truthy value if the element is located. We are also using chai and chai-as-promised as our assertion library (instead of assert); they provide us with the expect and .to.be.fulfilled syntax which makes tests involving promises much more readable.
Run the tests, and the last step should fail. This is because we haven't implemented the #registration-success element yet:
---------- firefox test start ----------
........................F.
Failures:
1) Scenario: Valid Input # spec/cucumber/features/users/register/main.feature:24
Before # spec/cucumber/steps/index.js:5
When user navigates to / # spec/cucumber/steps/interactions/navigation.js:3
When user types in a valid email in the "#email" element # spec/cucumber/steps/interactions/input.js:10
And user types in a valid password in the "#password" element # spec/cucumber/steps/interactions/input.js:10
Then the "#register-button" element should not have a "disabled" attribute # spec/cucumber/steps/assertions/index.js:9
When user clicks on the "#register-button" element # spec/cucumber/steps/interactions/element.js:4
Then the "#registration-success" element should appear within 2000 milliseconds # spec/cucumber/steps/assertions/index.js:16
AssertionError: expected promise to be fulfilled but it was rejected with 'TimeoutError: Waiting for element to be located By(css selector, #registration-success)\nWait timed out after 2002ms'
After # spec/cucumber/steps/index.js:12
4 scenarios (1 failed, 3 passed)
18 steps (1 failed, 17 passed)
0m10.403s
----------- firefox test end -----------
Before # spec/cucumber/steps/index.js:5
Then the "#registration-success" element should appear within 2000 milliseconds # spec/cucumber/steps/assertions/index.js:16