I am writing automation tests that send keys to every text box on a form (about 5 fields) and then a submit button becomes enabled and clicked. I find that the test frequently fails as only the last field is populated and the button never becomes enabled.
It seems like the method to send keys may be executing too fast for the page to be populated. So far I have attempted to click on each field before sending keys (as well as waiting for the elements to exist) and this doesn't seem to help.
I have also tried to verify the page is fully loaded by waiting for every element and button to exist on the page before proceeding.
The browser I am testing against is chrome. (Version 79.0.3945.130)
The selenium web-driver is 3.11.2
The chrome driver is up to date with chrome
private IWebElement FirstNameInput => Webdriver.FindElement(By.Id("first-name-input"));
// The remaining input fields
public void VerifyPageIsFullyLoaded()
{
// Wait until all elements exist
}
public void EnterFormDetails(FormDetail formDetail)
{
WebDriver.WaitUntilElementExists(FirstNameInput);
FirstNameInput.Click();
FirstNameInput.SendKeys(formDetail.FirstName);
WebDriver.WaitUntilElementExists(LastNameInput);
LastNameInput.Click();
LastNameInput.SendKeys(formDetail.LastName);
WebDriver.WaitUntilElementExists(DateOfBirthInput);
DateOfBirthInput.Click();
DateOfBirthInput.SendKeys(formDetail.DateOfBirth);
WebDriver.WaitUntilElementIsClickable(SubmitButton);
SubmitButton.Click();
}
Update:
Just tried the latest stable release of selenium web driver (3.141.0) and found that it is still not as reliable.
JavascriptExecutor javascript = (JavascriptExecutor)webdriver;
javascript.executeScript("document.getElementById('FirstNameInput').value='test123'");
javascript.executeScript("document.getElementById('LastNameInput').value='test123'");
javascript.executeScript("document.getElementById('DateOfBirthInput').value='test123'");
SubmitButton.Click();
and if the submit button is in form tag then you can use submit() method.
Related
I'm using selenium to automate a task on a very dynamic website with pyhton.
For this reason certain HTML elements of the current loaded page may or may not be present at the moment of the request from my code.
How exactly the webdriver instance gets updated and receives the new data from the web page?
Is it constantly connected and receive the change in the HTML code instantly?
Or it first download a first verion of the page when driver.get() is called, and then updates it whenever a function such as .find_element_by_class_name() is called?
Q. Is it constantly connected and receives the change in the HTML code instantly?
Ans. Well, for each Selenium command, there will be an HTTP request that will send to the browser driver and then to the server and the command will get, A HTTP response will be returned and the command/commands will get executed based on the response.
Now let's say in a situation you do,
driver.get()
Basically, this is a selenium command.
It would fire an HTTP request stating to launch the URL provided. Based on the response (200-Ok or anything else), you would either see the WebPage getting loaded or an error message.
Same way in Sequence all the Selenium commands will get executed.
It's obvious that we need locators to locate web elements in the UI.
Once we have them, we can tightly couple them with
driver.find_element_by_***
methods.
Things to be noted down here
You need to learn/understand :
Implicit Waits.
Explicit Waits.
Fluent Waits.
Implicit Waits :
By implicitly waiting, WebDriver polls the DOM for a certain duration when trying to find any element. This can be useful when certain elements on the webpage are not available immediately and need some time to load.
Basically what it means is, whenever you use drive.find_element it gonna look for implicit waits if you have defined one.
If you've not defined one implicit wait, then the default value is 0.
Explicit wait
They allow your code to halt program execution, or freeze the thread, until the condition you pass it resolves. The condition is called with a certain frequency until the timeout of the wait is elapsed. This means that for as long as the condition returns a falsy value, it will keep trying and waiting.
FluentWait
FluentWait instance defines the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition.
Reference Link
Updated :
PS : Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
Locators (by priority from top):
ID
name
classname
linkText
partialLinkText
tagName
css selector
xpath
Web page is loaded by driver.get().
But the driver doesn't "know" what elements are existing there. It just opens, loads the web page.
To access any element, to check element presence etc. you will need to do that particularly per each specific element / elements using commands like .find_element_by_class_name() with a specific element locator.
I was trying to capture or (find the css/xpath) the inline warning message that disappears after few seconds (BTW, I am using Selenium WebDriver / Java for my automation).
eg: In the below public link, I try to click Reset Button without entering any email. The text box briefly shows 'Please fill out this field." I want to automate if it is showing this message as expected.
https://app.shipt.com/password_resets/new
Please help.
PS: I tried to search this website and google but could not find any useful information.
For actions that appear or disappear after certain time you should use Expected Conditions:
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
And then you can click on element as usual.
However in case of the shipit page you are trying to automate the popup is a native HTML5 popup, so you cannot use Selenium directly to get the message, and you have to use this workaround:
Stackoverflow - how to get HTML5 error message in Selenium
I'm trying to test my Hotmail account using selenium Webdriver 3.0. I set my account to ask for two way authentication, which means Indeed to enter the last 4 digits of my mobile number and then send a message to me. Then I have to enter that code in order to open my email Account.
It worked good with me when I used implicit, waited for 60 seconds until i receive the code then enter it manually and so the test continues to my email page >> all works fine.
BUT my question is, is there any way to make the test wait until I enter the code rather than waiting for 60s?!
Is that acceptable to enter some things manually while using Selenium webdriver?
is that acceptable to enter some things manually while using selenium webdriver?
Yes, because this thing is made for stopping robot activity just like Captcha code entering the process. So, in this scenario, this is acceptable to enter text manually after reading the text from mail while using selenium.
You can do one thing more if you want to do it automatically, you should implement mail API to read the last mail from your provided account in the background and fetch necessary text from the last mail using some programming stuff and enter it into textbox using selenium.
is there any way to make the test wait until I enter the code rather than waiting for 60s?
Yes, to achieve this you need to create your own custom ExpectedConditions with WebDriverWait which will wait until located text box has value greater or equal 4 character or other suitable condition which you want as below :-
//Initialize WebDriverWait first which will wait maximum 60 seconds
WebDriverWait wait = new WebDriverWait(driver, 60);
//Create suitable locator to locate textbox element eg. with xpath locator
By byObject = By.xpath("enter here textbox xpath");
//This condition will wait until text box has value greater or equal 4 character
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.findElement(byObject).getAttribute ("value").length() >= 4)
}
});
Previously I have been using chrome Auto Refresh plug in. However, now my code has multiple ChromeDriver instances opening and closing and I cannot use Auto Refresh. Also, it is quite a hassle to install Auto Refresh on new computers.
Is there any way to refresh driver (simulate F5 say every 15 seconds if driver does not change remains motionless) with Selenium similar to Google Auto Refresh?
refresh is a built in command.
driver = webdriver.Chrome()
driver.get("http://www.google.com")
driver.refresh()
If you don't have the chrome driver it can be found here:
https://code.google.com/p/chromedriver/downloads/list
Put the binary in the same folder as the python script you're writing. (Or add it to the path or whatever, more information here: https://code.google.com/p/selenium/wiki/ChromeDriver)
edit:
If you want to refresh ever 10 seconds or something, just wrap the refresh line with a loop and a delay. For example:
import time
while(True):
driver.refresh()
time.sleep(refresh_time_in_seconds)
If you only want to refresh if the page hasn't changed in the meantime, keep track of the page that you're on. driver.current_url is the url of the current page. So putting it all together it would be:
import time
refresh_time_in_seconds = 15
driver = webdriver.Chrome()
driver.get("http://www.google.com")
url = driver.current_url
while(True):
if url == driver.current_url:
driver.refresh()
url = driver.current_url
time.sleep(refresh_time_in_seconds)
Well there are two ways of doing this.
1. We can use refresh method
driver.get("some website url");
driver.navigate().refresh();
We can use actions class and mimic F5 press
Actions act = new Actions(driver);
act.SendKeys(Keys.F5).perform();
If you write unit tests that must be run like if you had to open/refresh a new browser session each time, you can use a method with before annotations:
#Before
public void refreshPage() {
driver.navigate().refresh();
}
If all tests are individually successful (green) but fail all together, the reason might also been that you need to wait for some resources to be available on the page, so you also need to handle it, setting the timeout like this:
public WebElement getSaveButton() {
return findDynamicElementByXPath(By.xpath("//*[#id=\"form:btnSave\"]"), 320);
}
320 is a long time, but you must make sure that you give enough time to get all that it takes to test.
I understand that the top level webdriver API doesn't provide access to the page load event handler, but is there any way (including sending a command directly to the server through the REST interface) to make a call directly to the selenium server to force the page load block behavior? I know about the wait for element hack, but I'd rather go straight to the source if at all possible. The specific problem I'm having is a page that makes a JS call when a button is clicked that displays a modal dialog on the page while some backend processes happen, then forwards the browser to a new page once the backend work is complete. Since the click action doesn't directly trigger the new page, selenium doesn't block on the event (and I wouldn't want it to in all cases anyway).
I've looked through the Command class for any promising looking commands, but didn't see anything. I found http://code.google.com/p/selenium/wiki/JsonWireProtocol but it didn't help either...
Thats a tricky one.
Accessing the http status in selenium/webdriver is not very handy.
I would recommend a pragmatic way. IMO the wait for element approach is not a hack, its the proper way to do it. In your case I would wait for selenium.getLocation() or webdriver.getCurrentUrl() contains an expected value.
Something like this:
webDriverWait.until(new Function<WebDriver, WebElement>() {
#Override
public WebElement apply(WebDriver driver) {
//TODO: pass expected url as parameter
boolean expectedUrl = driver.getCurrentUrl().contains("your redirect url");
if (expectedUrl) {
//If not null is returned, we have found something and waitUntil stops
return new RemoteWebElement();
}
//try again
return null;
}
});