How to Wait for an element and do not fail if not found after a certain time xcuitest - xctest

In my application i have a two tab buttons say Tasks and Worklist. Tasks is always loaded. But Worklist button is dynamic and loaded only after some time.
I want to click Tasks button after a certain time. ie, i need to wait for Worklist button and if it exists after a certain time then click the Tasks button. Also if the timeout exceeds and Worklist button is not loaded then i need to click Tasks button.
i cannot use sleep.
Can i use expectationForPredicate and waitForExpectationsWithTimeout. But waitForExpectationsWithTimeout gets failed if the element is not found after timeout. Even if i write
waitForExpectationsWithTimeout(120) { (error) -> Void in
click Tasks button
}
This gives stall on main thread.
I want to click Tasks button only after worklists is loaded. but if worklist is not loaded after some timeout, then also i need to click Tasks button..
Is there any solution. any help.

You can create your own custom Method to handle this:
func waitForElementToExist(
element: XCUIElement,
timeout: Int = 20,
failTestOnFailure: Bool = true)
-> Bool
{
var i = 0
let message = "Timed out while waiting for element: \(element) after \(timeout) seconds"
while !element.exists {
sleep(1)
i += 1
guard i < timeout else {
if failTestOnFailure {
XCTFail(message)
} else {
print(message)
}
return false
}
}
return true
}
you can call the method like:
if waitForElementToExist(taskButton, timeout: 20, failTestOnFailure: false) {
button.tap()
}
Hope this works for you!

Related

ProgressManager. Cancel button

In my plugin, I execute a network query, get the result
and show the processing step.
CoreProgressManager.getInstance().runProcessWithProgressSynchronously(Runnable {
//runnable block
CoreProgressManager.getInstance().progressIndicator.text = "Start loading"
val result = MyProvider.getObjects() // this network request
CoreProgressManager.getInstance().progressIndicator.text = "Finish"
result.forEach {
//processing result
CoreProgressManager.getInstance().progressIndicator.text = "Processing is $result"
}
}, taskTitle, true /* canBeCanceled */, project)
Sometimes the query is performed by the network for a long time, and I want to stop working all block (runnable block).
For this, in runProcessWithProgressSynchronously I passed the parameter canBeCanceled = true
and naively thought that IDEA would stop executing my executable block, but this did not happen.
How do I catch the clicking of a Cancel button and stop my runnable block?
You need to periodically call ProgressIndicator.checkCanceled() from your block. This method will throw a ProcessCanceledException if the Cancel button has been pressed.

How to wait until page load without browser stopped respnding?

Using C# I was trying to pause execution until the page load after login so I used this code:
for (int second = 0; ; second++)
{
if (second >= 60) Assert.Fail("timeout");
try
{
if (driver.FindElement(By.Id("footer")).Displayed) break;
}
catch (Exception)
{ }
Thread.Sleep(1000);
}
But I get system error that the browser Firefox stopped responding apparently on the Thread.Sleep(1000); line so how I prevent that ?
is there another way to pause execution other than thread.sleep() ?
Edit:
I used now
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
but it execute inconstantly without waiting 10 seconds !! why ??
One soultion is using a custom WebDriverWait with an expected condition like `titleIs'. This means the driver will poll the page for a predefined amount of time waiting for the page title to match what you expect it to be. In Java it would be like so:
public Boolean waitForPageIsLoaded(String title) {
return new WebDriverWait(driver, 60).until(ExpectedConditions.titleIs(title));
}

Selenium : Handle a window that popups up randomly

We have a feature that collects customer feedback. For this , when the user logs out , a window pops up up randomly - not every time for every customer.
I want to handle this in my automation code.
Currently, at the log out, I'm expecting a window and switching to it and that code is failing when the popup window doesn't show up.
What's the best way to handle this .
This is what I have so far ...
public static void waitForNumberOfWindowsToEqual(final int numberOfWindows) {
ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return (driver.getWindowHandles().size() == numberOfWindows);
}
};
WebDriverWait wait = new WebDriverWait(driver, BrowserFactory.explicitWait);
wait.until(expectation);
}
I would handle the absence of popup window with a try/catch. Here is an example:
try {
WebDriverWait winwait = new WebDriverWait(driver, 3);
String mainWindow = driver.getWindowHandle();
// wait for 2 windows and get the handles
Set<String> handles = winwait.until((WebDriver drv) -> {
Set<String> items = drv.getWindowHandles();
return items.size() == 2 ? items : null;
});
// set the context on the last opened window
handles.remove(mainWindow);
driver.switchTo().window(handles.iterator().next());
// close the window
driver.close();
// set the context back to the main window
driver.switchTo().window(mainWindow);
} catch (TimeoutException ex) {
System.out.println("No window present within 3 seconds");
}
If possible, the ideal thing to do would be to have a look through the source to work out whether the popup window will appear, however if this isn't achievable you could take the following approach:
// Get the number of windows open before clicking the log out button.
int numberOfWindowsBeforeLogOut = driver.getWindowHandles().size();
// Click the log out button.
logOutButton.click();
// Check how many windows are open after clicking the log out button.
int numberOfWindowsAfterLogOut = driver.getWindowHandles().size();
// Now compare the number of windows before and after clicking the log out
// button in a condition statement.
if (numberOfWindowsBeforeLogOut < numberOfWindowsAfterLogOut) {
// If there is a new window available, switch to it.
driver.switchTo().window(titleOrWindowHandle);
}
In case you don't get the required window, the code will throw a TimeoutException. So, put wait.until(expectation) inside a try block and catch the exception. In code,
try {
wait.until(expectation);
} catch (TimeoutException ex) {
System.out.println("Nowindow This Time");
}

showandwait changing variable value

I'm having a problem with a variable I'm using to track the status of a user activity. In a GUI I have a button that, on clicking the button launches a second GUI. In that GUI, the user can either complete the activity started in the first GUI or not.
If the user cancels the second GUI, then the idea is to go back to the first GUI, leaving all variables and lists with their current values. If the second GUI completes the activity of the first GUI, then all variables and lists should be reset.
To track this, I have a variable (Boolean complete) initially set to FALSE. In the second GUI, when the "OK" button is clicked (rather than the "Cancel" button), the second GUI calls a method in the first GUI, changing the value of "complete" to TRUE.
To see what the heck is going on, I have System.out.println at several points allowing me to see the value of "complete" along the way. What I see is this:
Launching first GUI - complete = FALSE
Launching second GUI - complete = FALSE
Clicking "OK" in second GUI - complete = TRUE
Second GUI closes itself, returning to complete first GUI activity
First GUI finishes activity with complete = FALSE
I'm assuming it is because I am launching the second GUI with a showandwait, and when the method containing the showandwait begins, the value of "complete" = FALSE. The value changes in the WAIT part of show and wait, then the method continues and that is where I get the value still being FALSE, though it was changed to TRUE.
Here is a summary of the code in question (if you need exact code, it's longer, but I can post on request):
completeButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
try {
System.out.println("b4 calc = " + complete); // complete = FALSE
// all the code to create the calcStage
calcStage.showAndWait(); // second GUI, which calls a method in THIS
// class that changes complete to TRUE. That method
// (in THIS file) also has a println that shows the change.
getComplete(); // tried adding this method to check the value of
// "complete" after the change made by the calcStage
// (which calls a method in this same file)
System.out.println("Complete? " + complete);
// this shows complete = FALSE,
// though in the calcStage it was changed to TRUE
if (salecomplete) {
// code that should reset all variables and lists if the activity was completed
}
}
}
}
The question here is why does the second GUI successfully change the value of "complete", but when I return to the first GUI it still sees complete as FALSE? And how can I get around this?
Try having the controller of the second GUI calling a method in the first GUI's controller to modify that complete variable
For example:
// Code to handle the OK button being pressed
#Override
public void handle(ActionEvent t) {
// Do validation and work
//reference to the first controller object
firstController.setComplete(true);
}

How to detect a click on a form reset button from QtWebKit?

Looking at the signals in the QtWebKit API, I failed to find anything that would seem to me to be what I am looking for.
QWebView
linkClicked() seems to be the closest, but a reset button is no link, and definitely does not point to an URL.
QWebPage
I considered the following signals (judging by their name), but according to their description none of them match my purpose either: contentsChanged(), contentsChanged(), contentsChanged(), selectionChanged().
QWebFrame
None of its signals matches my purpose.
QWebElement
Here I can see how to get an object representing the button(s), but it has no signals whatsoever.
I want to catch a click in a reset button in order to store the data in the form before it gets cleared, so it can be restored later.
For now, I did manage to retrieve the buttons as a QWebElementCollection of QWebElement objects, and I can modify them, but I do not know how to get them to send a signal upon click, or something similar.
// Get reset buttons.
QWebElementCollection inputResets = mainFrame()->documentElement().findAll("input[type=reset]");
inputResets += mainFrame()->documentElement().findAll("button[type=reset]");
// Change their text (just a test).
foreach(QWebElement element, inputResets)
{
element.setPlainText("Worked!");
}
Well, I got it working with this, although I do not think it is the best approach:
bool EventFilter::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton)
{
QWebView *view = dynamic_cast<QWebView*>(object);
QPoint pos = view->mapFromGlobal(mouseEvent->globalPos());
QWebFrame *frame = view->page()->frameAt(mouseEvent->pos());
if (frame != NULL)
{
// Get the existing reset buttons.
QWebElementCollection inputResets = frame->documentElement().findAll("input[type=reset]");
inputResets += frame->documentElement().findAll("button[type=reset]");
// Check if any of them is at the clicked position.
foreach(QWebElement element, inputResets)
{
if (element.geometry().contains(pos))
{
qDebug() << "Clicked element tag:" << element.localName();
return QObject::eventFilter(object, event);
}
}
}
}
}
return QObject::eventFilter(object, event);
}
You can probably accomplish this with Qt WebKit Bridge.