I need to wait for all elements to not be visible with an attribute 'id' that contains the word 'mask'. I have tried like this:
//*[contains(#id *= 'mask')]
However it is giving me an element not found exception.
I believe the syntax you're looking for is:
//*[contains(#id,'mask')]
I do something similar where I wait until the count is zero for classes that contain "BlockUI":
public static void waitForBlockUIToDisappear() {
// This function checks the entire currently-loaded web page for the
// presence of any web element of the
// class "blockUI" and loops until there are none. The presence of an
// element with this class does exactly
// what it implies: it blocks user input. If you get the error that a
// different web element would receive
// the click, for example, this is why and you'd need to call this
// method before doing a click. Generally,
// this function should be implemented before sending any input to a web
// page - click, sendkeys, select...
String blockUI = "//*[contains(#class,'blockUI')]";
while (true) {
if (driver.findElements(By.xpath(blockUI)).size() == 0)
break;
}
;
}
You should be able to alter that code to look for your id to contain your text.
You can use explicit wait in this case, as below.
WebDriverWait wait = new WebDriverWait(driver,15);
wait.until(ExpectedConditions.invisibilityOfAllElements(driver.findElements(By.xpath("//*[starts-with(#id,'mask')]"))));
In c# they were not implemented this method, but you can implement that.
Below is the url that can help you to write.
https://github.com/SeleniumHQ/selenium/blob/master/dotnet/src/support/UI/ExpectedConditions.cs#L140
Related
After reviewing the selenium docs, I am wondering if I am attempting to implement explicit waits incorrectly.
In the docs, it always shows identifying a new element, then assigning the defined wait to said element
WebDriver driver = new ChromeDriver();
driver.get("https://google.com/ncr");
driver.findElement(By.name("q")).sendKeys("cheese" + Keys.ENTER);
// Initialize and wait till element(link) became clickable - timeout in 10 seconds
WebElement firstResult = new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")));
// Print the first result
System.out.println(firstResult.getText());
In this example, a new element firstResult is created, then the defined wait assigned to it.
Is this required? Should always be done this way?
This is why I ask.
I am using the PageFactory model and have my elements defined via the FindBy annotation, as shown here.
// Input field for slice ID
#FindBy(how = How.XPATH, using = "//input[#name='id']")
private WebElement inputSliceId;
Then, in that same class, I have defined some convenience methods to use them.
So now, in my convenience methods, should I do things like this?
inputSliceId = new WebDriverWait(driver, Duration.ofSeconds(10))...
inputSliceId.sendKeys(...
What I have been doing, which is what I'm questioning now, is putting wait statements that are not being assigned directly to the element in question.
For example, I've been doing things like this.
buttonSubmit.click();
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#role='alertdialog']")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[#role='alertdialog']")));
Why? (could totally be wrong here)
Upon clicking the button, I need to wait for a pop-up to display
Once it does, I am then waiting for it to disappear, before proceeding
Here's the main question
Are these two wait lines not really doing anything because I am not assigning them to an element? Or are they still causing the web driver to hold until the conditions specified by the wait occur?
No, You can't assigned wait statement as above to your web element. If you want to wait for your element using Page factory model for a below element then you have to create
public void isLoaded() throws Error {
// Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible.
public class BaseClass
{
private void waitForVisibility(WebElement element) throws Error{
new WebDriverWait(driver, 60)
.until(ExpectedConditions.visibilityOf(element));
}
}
And then in your page object model class you can extend this BaseClass.
public class page extends BaseClass
{
#FindBy(how = How.XPATH, using = "//input[#name='id']")
private WebElement inputSliceId;
waitForVisibility(inputSliceId);
}
I have defined wait in the BaseClass to achieve re-usability of waitForVisibility code across all page object classes.
Also after button clicking if you want to wait for a pop up to be appear then you can include code like below:
#FindBy(xpath = "//div[#role='alertdialog']")
private WebElementFacade alertPopup;
buttonSubmit.click();
waitForVisibility(alertPopup);
There are a couple of things:
If your usecase is to invoke getText() on an element, instead of elementToBeClickable(), using visibilityOfElementLocated() would be just perfect.
To extract the text you don't have to create any new element, instead you can directly invoke visibilityOfElementLocated() once the element is returned as follows:
System.out.println(new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a/h3"))).getText());
If your usecase doesn't include any validation for the pop-up which gets displayed and disappear, you don't need to induce any waiter for it and safely ignore it. So once you invoke click() on the buttonSubmit you can proceed to your next validation point adjusting the timespan for the pop-up to be displayed and disappear.
So, your optimized code block will be:
buttonSubmit.click();
// consider the total timespan for the wait to be cumulative of: pop-up displayed + pop-up disappear + next interactable element to become clickable
new WebDriverWait(driver, Duration.ofSeconds(20)).until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_next_element_to_click")));
You can find a relevant detailed discussion in How to add explicit wait in PageFactory in PageObjectModel?
First, you can declare a method where set up the wait itself, in a separate class used like base or parent, like that:
protected void waitForElementToBeLoaded(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element));
}
Then, you can declare a second method where use the first one, in a separate class used like fictional page, like that:
public void sendMessageForm( ){
waitForElementToBeLoaded(sendBtn);
sendBtn.click();
}
Finally, every time you use the previous method the wait will be triggered, example:
contactUsPage.sendMessageForm();
clear method clears the value but retains and when send keys new value is passed the text box shows previous value + new value in selenium Appium. Kindly suggest.
Version:java-client-4.1.2
Appium Server:v1.7.2
Selenium: 3.0.1
I tried this but it did not work out.
public void clearTextBox(WebElement element,String text) throws Exception
{
element.click();
Thread.sleep(3000);
element.clear();
element.sendKeys(text);
}
Getting this
The reason your code is failing (and you should have included your code in the original question) is because you are doing it through TWO separate calls to the page object element.
Each time you call the page object, it looks-up the element freshly, so the first time you call it and issue a .clear() and then you are calling it again after an unnecesary sleep with the .sendkeys() method. The click is also unnecessary.
You should write a public method in your page object model to perform the sendkeys() for you which does the clear() and then the sendkeys(), i.e.:
public void setMsisdnValue(String text) {
Msisdn.clear();
Msisdn.sendKeys(text);
}
Personally, I use a set of helper methods so that I can error-trap and log things like sendkeys, but I would still call it from within the page object model itself. That helper would do the same two steps, but also do it inside a try/catch and report any errors, so it would be simplified to:
public void setMsisdnValue(String text) {
helper.sendKeys(Msisdn, text);
}
Hope this helps.
Before we get started let me say I have done my research on this matter, and I have seen the solutions posted here: stale element solution one, and I even came up with my own solution here: My temporary solution the problem with my solutions is that it does not work for all cases (particularly when dealing with long chains of .children()
The problem I have with "stale element solution one" is that it is not a very robust solution at all. It only works if you can put your Navigator element instantiation inside of the try catch, but if you do not have that instantiation, then this solution does no good. let me give an example of what I mean.
Lets say i have a Page class that looks something like this:
package interfaces
import geb.Page
import geb.navigator.Navigator
import org.openqa.selenium.By
class TabledPage extends Page {
static content ={
table {$(By.xpath("//tbody"))}
headers {$(By.xpath("//thead"))}
}
Navigator getAllRows(){
return table.children()
}
Navigator getRow(int index){
return table.children()[index]
}
Navigator getRow(String name){
return table.children().find{it.text().matches(~/.*\b${name}\b.*/)}
}
Navigator getColumn(Navigator row, int column){
return row.children()[column]
}
}
lets say that I have a method in my script that does what "stale element solution one" does (more or less). That looks like this:
def staleWraper(Closure c, args = null, attempts = 5){
def working = false
def trys = 0
while(!working){
try{
if(args){
return c(args)
}
else{
return c()
}
}
catch(StaleElementReferenceException se){
println("I caught me a stale element this many times: ${trys}")
if(trys>attempts){
working = true
throw se
}
else{
trys++
}
}
}
}
The way you call the above method is like this (using TabledPage as an example: staleWrapper(TabledPage.&getRow, 5) //grabs the 4th row of the table
and this works fine reason being, and this is important, the getRowmethod references an element that is in static content. When an static content element is reference, the Navigator is re-defined at run time. this is why this solution works for the getRow method. (table is re-instantiated inside of the try catch)
my problem and gripe with "stale element solution one" is that this type of implementation does not work for methods like getColumn this is because getColumn does not reference the static content itself. The Tabled page I am testing has javascript running on it that refreshes the DOM multiple times per second. so even if I use the staleWraper method it will always throw a stale element no matter how many attempts are made.
One solution to this is to add the columns as static content for the page, but I want to avoid that because it just doesn't flow with the way I have my whole project setup (I have many Page objects that implement methods in a similar way to TabledPage) If it were up to me, there would be a way to suppress the staleElelementExcpetions, but that is not an option either.
I am wondering if anyone here has a creative solution to Robustly (key word here) handle the StaleElementException, because I think looping over a try catch is already kinda hacky.
Well, I am not sure if my solution will solve your purpose. In my case I am using Page Pattern to design the tests so each method of Page class uses PageFactory to return instance of Page class. For example,
public class GoogleSearchPage {
// The element is now looked up using the name attribute
#FindBy(how = How.NAME, using = "q")
private WebElement searchBox;
public SearchResultPage searchFor(String text) {
// We continue using the element just as before
searchBox.sendKeys(text);
searchBox.submit();
// Return page instance of SearchResultPage class
return PageFactory.initElements(driver, SearchResultPage.class);
}
public GoogleSearchPage lookForAutoSuggestions(String text) {
// Do something
// Return page instance of itself as this method does not change the page
return PageFactory.initElements(driver, GoogleSearchPage.class);
}
}
The lookForAutoSuggestions may throw StaleElementException which is taken care by the returning the page instance. So if you are having page classes then ideally each page method should return an instance of page where user is supposed to land.
I ended up implementing something similar to what this guy gives as the "3rd option": Look at the answer (option 3)
I need to test it out some more but I have yet to get stale element since I implemented it this way (the key was to make my own WebElement class and then override the Navigator classes but use the NeverStaleWebElement object instead of the WebElement class
The problem: I'm crashing when I want to render my incoming data which was retrieved asynchronously.
The app starts and displays some dialog boxes using XAML. Once the user fills in their data and clicks the login button, the XAML class has in instance of a worker class that does the HTTP stuff for me (asynchronously using IXMLHTTPRequest2). When the app has successfully logged in to the web server, my .then() block fires and I make a callback to my main xaml class to do some rendering of the assets.
I am always getting crashes in the delegate though (the main XAML class), which leads me to believe that I cannot use this approach (pure virtual class and callbacks) to update my UI. I think I am inadvertently trying to do something illegal from an incorrect thread which is a byproduct of the async calls.
Is there a better or different way that I should be notifying the main XAML class that it is time for it to update it's UI? I am coming from an iOS world where I could use NotificationCenter.
Now, I saw that Microsoft has it's own Delegate type of thing here: http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx
Do you think that if I used this approach instead of my own callbacks that it would no longer crash?
Let me know if you need more clarification or what not.
Here is the jist of the code:
public interface class ISmileServiceEvents
{
public: // required methods
virtual void UpdateUI(bool isValid) abstract;
};
// In main XAML.cpp which inherits from an ISmileServiceEvents
void buttonClick(...){
_myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password);
}
void UpdateUI(String^ data) // implements ISmileServiceEvents
{
// This is where I would render my assets if I could.
// Cannot legally do much here. Always crashes.
// Follow the rest of the code to get here.
}
// In MyUser.cpp
void LoginAndGetAssets(String^ email, String^ password){
Uri^ uri = ref new URI(MY_SERVER + "login.json");
String^ inJSON = "some json input data here"; // serialized email and password with other data
// make the HTTP request to login, then notify XAML that it has data to render.
_myService->HTTPPostAsync(uri, json).then([](String^ outputJson){
String^ assets = MyParser::Parse(outputJSON);
// The Login has returned and we have our json output data
if(_delegate)
{
_delegate->UpdateUI(assets);
}
});
}
// In MyService.cpp
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json)
{
return _httpRequest.PostAsync(uri,
json->Data(),
_cancellationTokenSource.get_token()).then([this](task<std::wstring> response)
{
try
{
if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode());
String^ j = ref new String(response.get().c_str());
return j;
}
catch (Exception^ ex) .......;
return ref new String(L"");
}, task_continuation_context::use_current());
}
Edit: BTW, the error I get when I go to update the UI is:
"An invalid parameter was passed to a function that considers invalid parameters fatal."
In this case I am just trying to execute in my callback is
txtBox->Text = data;
It appears you are updating the UI thread from the wrong context. You can use task_continuation_context::use_arbitrary() to allow you to update the UI. See the "Controlling the Execution Thread" example in this document (the discussion of marshaling is at the bottom).
So, it turns out that when you have a continuation, if you don't specify a context after the lambda function, that it defaults to use_arbitrary(). This is in contradiction to what I learned in an MS video.
However by adding use_currrent() to all of the .then blocks that have anything to do with the GUI, my error goes away and everything is able to render properly.
My GUI calls a service which generates some tasks and then calls to an HTTP class that does asynchronous stuff too. Way back in the HTTP classes I use use_arbitrary() so that it can run on secondary threads. This works fine. Just be sure to use use_current() on anything that has to do with the GUI.
Now that you have my answer, if you look at the original code you will see that it already contains use_current(). This is true, but I left out a wrapping function for simplicity of the example. That is where I needed to add use_current().
How are you finding out if jqGrid is loaded and ready to be used, via selenium.
Some details :
Im using C# driver
I have a method : new WebDriverWait(driver, new TimeSpan(0, 0, 0, 30)).Until(x => loadingdissapearedcondition) which im using to wait until Loading.. element is gone.
I also sometimes use this script :
private const string script = #"return ($('#{0}').jqGrid('getGridParam', 'reccount') !=x undefined) && ($('#{0}').jqGrid('getGridParam', 'reccount') != 0) && (!$('#load_{0}').is(':visible')) && (!$('#busyIcon').is(':visible'))";
private readonly string waitScript;
waitScript = string.Format(script, jqGridId);
public void WaitUntilLoadIconDissappears()
{
driver.WaitUntil(MAXWAIT, Wait);
}
public bool Wait()
{
var executeScript = ((IJavaScriptExecutor) driver).ExecuteScript(waitScript);
bool result;
bool tryParse = bool.TryParse(executeScript.SafeToString(), out result);
return tryParse && result;
}
to find if jqGrid has records and loading done.
I require something better - as even the above two does not make driver wait until load finishes, if we are using local data for jqGrid. Im also curious what is the best way, or at the minimum, how others are dealing with this problem.
I never used Selenium before, so I'm not sure that I understood your problem correctly. jqGrid will be first initialized and then (optionally) the data can be loaded from the server. During the initializing stage the original <table id="grid"></table> element will be converted to relatively complex HTML fragment which is the grid. At the end of the initialization the DOM element of the table (the $("#grid")[0]) will get the expando grid.
So you can use the test like
if ($("#grid")[0].grid) {
// grid is initialized
}
to determine that the grid is already initialized. jqGrid uses the same test internally (see here for example).
Here is solution for Java and jqgrid.
If grid data is not loaded yet then right pager has no value, so simply check its length. Methods such as isElementPresent, isDisplayed etc. seems not to work for grid right pager object. It's always present in page code while ajax, but text value is set when dynamic data is loaded.
public void waitForGridPagerRight(String gridName) throws Exception {
for (int second = 0;; second++) {
if (second >= 15) {
fail("Timeout.");
}
try {
if (driver
.findElement(By.id("pager_" + gridName + "_right"))
.getText().length() > 2)
break;
} catch (Exception e) {
}
Thread.sleep(1000);
}
}
Not sure why #Oleg's answer didn't work for me. It seemed like grid was being populated even before the ajax call was being made. It appears there's some change in newer versions maybe. It look like the last thing to happen in the ajax call is that the "loading" block is hidden, so instead I find that element and check it's display attribute a la:
def wait_for_jqgrid(self, t=20):
def check_jqgrid(driver):
#the last thing jqgrid does after the ajax call is to turn off the loading div
#so we find it and check to see if its display attribute is no longer set to 'none'
script = 'pid = $.jgrid.jqID($(".ui-jqgrid-btable").get(0).p.id); return $("#load_"+pid).get(0).style.display == "none";'
return driver.execute_script(script)
WebDriverWait(self.driver, t).until(check_jqgrid)
When the loading div is hidden, we are done. This is python but the same javascript bit should work in Java or whatever.