Reputation: 10431
The selenium webdriver bindings for JavaScript allow to wait for an element to be visible by combing two wait commands like in the following example:
const timeout = 1000;
const locator = webdriver.By.id('test');
driver.wait(webdriver.until.elementLocated(locator, timeout).then(function() {
that.findElement(locator).then(function(element) {
driver.wait(webdriver.until.elementIsVisible(element), timeout).then(function() {
// element is visible!
});
});
});
Is there an easier way to do this and how would this be done, when we need to wait for an array of elements to be visible all together?
Upvotes: 5
Views: 5477
Reputation: 2107
One of the great advantages of Promises is that you you can keep your async code linear rather than nested (callback hell from continuation passing style).
Promises give you return statements and error throwing, which you lose with continuation passing style.
In your case, you need to return the promise from your promise returning functions so you can chain your promises.
Example: Promise.all takes an array of promises and resolves once all promises resolve, if any are rejected, the array is rejected.
this.waitForElementsToBecomeVisible = function() {
return Promise.all([
driver.wait(webdriver.until.elementIsVisible(usernameTextField), 500),
driver.wait(webdriver.until.elementIsVisible(firstNameTextField), 500),
driver.wait(webdriver.until.elementIsVisible(lastNameTextField), 500),
driver.wait(webdriver.until.elementIsVisible(createEmployeeButton), 500)
]);
}
Then you can chain your promise.
driver.get('https://website.com/login').then(function () {
loginPage = new LoginPage(driver);
return loginPage.login('company.admin', 'password')
}).then(function () {
employeePage = new EmployeePage(driver);
return employeePage.clickAddEmployee()
}).then(function () {
addEmployeeForm = new AddEmployeeForm(driver);
/**
*
* Wait for elements to become visible
*/
return addEmployeeForm.waitForElementsToBecomeVisible();
}).then(function() {
return addEmployeeForm.completeForm(employee);
}).then(function() {
return addEmployeeForm.clickCreateEmployee();
}).then(function() {
return employeePage.searchEmployee(employee);
});
You can see how the above example isn't nested and is alot easier to maintain. You return a promise and keep chaining instead of nesting. I hope this helps you and doesn't confuse you at all.
Upvotes: 7
Reputation: 457
Simple - Write a common/global function. Take single or multiple Webdriver elements as input as well as condition if you need to vary it. Loop around till end of elements and do the same Wait until each element visible.
This is how I routinely do it in my functions. in Ruby I do this
for each element in [array of elements], Condition
[Below is same as your code if working well]
Driver - Element wait until (Condition satisfied)
element perform function
end
If you need to handle even multiple conditions, you can use a switch case statement. if you need to perform function only once keep the function outside
element perform function
Upvotes: 0