Codeception function to seeOrWaitForElement - selenium

I've got an application which I want to test with selenium/codeception. It has a lot of ajax function which changes the pages (show/hide sections of the page) which codeception at the moment doesn't handle well.
The problem I am having is I want to click on buttons/elements which either
are already on the page (ajax calls finished early)
which are not yet on the page (waiting for ajax response)
If I use waitForElement() it only seems to works in the second case (it waits for the element to appear and continues) but if the element is already present waitForElement will timeout and fire an Fail.
What I am looking for is a seeOrWaitForElement() function but I can't figure out how to insert logic in codeception.
Is this function available somewhere or how can I solve this problem in another way?

You could use
waitForJs("return document.querySelector('".$element."') != null", $seconds);
which will wait until the element exists (and returns instantly if the element already is present).

Codeception introduced a feature called SmartWait in version 2.3.4 which seems like an elegant solution to your problem. Note that it does not work for all kind of locators.
From the Codeception documentation:
SmartWait
since 2.3.4 version
It is possible to wait for elements pragmatically. If a test uses element which is not on a page yet, Codeception will wait for few extra seconds before failing. This feature is based on Implicit Wait of Selenium. Codeception enables implicit wait only when searching for a specific element and disables in all other cases. Thus, the performance of a test is not affected.
SmartWait can be enabled by setting wait option in WebDriver config. It expects the number of seconds to wait. Example:
wait: 5
With this config we have the following test:
<?php
// we use wait: 5 instead of
// $I->waitForElement(['css' => '#click-me'], 5);
// to wait for element on page
$I->click(['css' => '#click-me']);
It is important to understand that SmartWait works only with a specific locators:
#locator - CSS ID locator, works
//locator - general XPath locator, works
['css' => 'button''] - strict locator, works
But it won’t be executed for all other locator types. See the example:
<?php
$I->click('Login'); // DISABLED, not a specific locator
$I->fillField('user', 'davert'); // DISABLED, not a specific locator
$I->fillField(['name' => 'password'], '123456'); // ENABLED, strict locator
$I->click('#login'); // ENABLED, locator is CSS ID
$I->see('Hello, Davert'); // DISABLED, Not a locator
$I->seeElement('#userbar'); // ENABLED
$I->dontSeeElement('#login'); // DISABLED, can't wait for element to hide
$I->seeNumberOfElements(['css' => 'button.link'], 5); // DISABLED, can wait only for one element

I used waitForJS from the docs and it worked. Example:
$I->see('Jane Doe', '#table tbody tr');
$I->click(['css' => '#reload-ajax']); // Ajax trigger here
$I->waitForJS("return $.active == 0;", 60);
$I->see('John Doe', '#table tbody tr');

Related

Robot Framework: How to make Wait until keyword from selenium library return true or false

I would like to Run a keyword if an element is present on page.
I try using Selenium library's Wait Until Page Contains Element keyword, but it will always return "None", whether or not the element is present. I tried setting custom error, but that won't work either:
${condition} = Wait Until Page Contains Element ${locator} timeout=5 error=false
Run Keyword if '${condition}'=='false' click element ${some_refreshButton_locator}
Keyword click element ${locator} will run only when I make condition '${condition}'=='None'
Am I doing something wrong and how can I make a Selenium Library Wait until... keyword return true or false.
Thanks!
Wait Until Page Contains Element does not return anything but will raise error if element is not found. One workaround is to wrap Run Keyword And Ignore Error around it.
*** Settings ***
Library Selenium2Library
*** Test Cases ***
Test wait
Open Browser http://www.google.com/ gc
${result} ${condition}= Run Keyword And Ignore Error Wait Until Page Contains Stackoverflow timeout=2 error=false
Run Keyword if '${condition}'=='false' Log clicking
Close All Browsers
"Run Keyword And Return Status" can also be used to get True/False status as below:
${condition} = Run keyword And Return Status Wait Until Page Contains Element ${locator} timeout=5 error=false

Can't access WebDriverJS wait 'until' in Protractor and CoffeeScript

I need to wait for a modal to close so I am waiting for the absence of an element. I'm trying to do something like this:
browser.driver.wait until.stalenessOf(By.css '.modal-header')
Unfortunately Coffeescript has reserved until. So I tried using:
browser.driver.wait browser.driver.until.stalenessOf(By.css '.modal-header')
but it is undefined (until that is). browser.driver exists but it doesn't contain until.
How can I access the until object? Also, is there another way to wait until an element is no longer on the page?
You can use the isPresent() function instead:
browser.wait ->
not element(By.css '.modal-header').isPresent()
,
5000
NOTE: isPresent() will not return false until it has finished implicitly waiting for the element, so if you have set the browser.manage().timeouts().implicitlyWait property very high you may want to temporarily decrease its value.

GEB assertion, waitFor

I'm learning GEB in IntelliJ and have two issues.
When I click button on the top of the page I'm redirected to very bottom of the page.
After this I need to do assertion that the site slided down.
I try to do assertion in this example:
assert page.element_on_the bottom.isDisplayed() == true
// element_on_the bottom {$('css_selector)
The above assertion always returns true even I don't click button to slide down.
I need to check if element is visible on the part of website which is actually displayed on my monitor screen. Is there a way to do this?
I try to use waitFor statement in example:
waitFor{page.element.isDisplayed()}
but it doesn't work:
geb.waiting.WaitTimeoutException: condition did not pass in 5.0 seconds (failed with exception)
instead of this I use:
Thread.sleep(3000) //which is not desirable here
and then my test passes. I think my element don't trigger any js or ajax script actions.
I'm not sure how to use waitFor that should wait for all elements to load.
Element doesn't have to be in view for is isDisplayed() to return true - it will return true as long as the element is visible on page, e.g. it's display property is not set to hidden. You will need to detect your scroll position using javascript because WebDriver does not expose scroll information. See this response for how to detect that scroll is at the bottom of the page and see this section of the Book of Geb for how to execute javascript code in the browser.
What is the exception and its stacktrace that you're getting from your waitFor {} call? It probably contains the clue on what is actually going on.
For your first problem, can you please try the following as displayed should work fine for the visibility and present should be good to check the presence of the css selector in the DOM:
waitFor { page.element_on_the bottom.isDisplayed() }
or
waitFor { page.element_on_the bottom.displayed() }
For the second problem, you need to edit your Gebconfig file, like below as the waiting time you have right now is 5 seconds that's why it's failing whereas your sleep time is way more than 5 seconds:
waiting {
timeout = 30
retryInterval = 0.1
}
or, you can also try that at the same line of the code as below:
waitFor (30, 0.1) {page.element.isDisplayed()}
Please let us know if that worked fine or not! On another note, why don't you simply write the function name from the imported class instead of always writing className.functionName()? Best of luck and Cheers!!

Wait for an element using Selenium webdriver

What is the best way to wait for an element to appear on a web page? I have read that we can use implicit wait and functions like webdriverwait, fluentwait etc and last but not the least thread.sleep()...which i use the most but want to stop using at all.
My scenario:
User logs in to a website...website checks the credentials and provides an offer to the user in the form of an overlay (kind of popup but not a separate window). I need to verify text on the the overlay.
There is a time gap between user signing in and the overlay getting displayed. what is the best approach so that selenium waits only till the time the element is not visible. As the overlay is not a separate page but part of the main page, implicit wait does not work at all.
All suggestions are welcome...:)
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(By.id("optionsBuilderSelect_input")));
I'm a professional scraper (http://nitinsurana.com) I've written 30+ softwares using selenium and I've never faced any such issue, anyways above is a sample code.
All I can think of is that what until condition has to be checked because many a times elements are already visible, but they are not clickable and things like that. I guess you should give different options a try and I hope you'll find the one required.
Always start by using a implicit wait. I think Selenium defaults to 5 seconds and so if you do a driver.findElement(), the implication is that it will wait up to 5 seconds. That should do it. If you are experiencing a scenario where the time it takes is unpredictable, then use FluentWait (with the same 5 second timeout) but also using the .ignoring method and wrap that inside a while loop . Here is the basic idea:
int tries=0;
while ( tries < 3 ) {
//fluent wait (with .ignoring) inside here
tries ++1;
}
public boolean waitForElement(WebElement ele, String xpath, int seconds) throws InterruptedException{
//returns true if the xpath appears in the webElement within the time
//false when timed out
int t=0;
while(t<seconds*10){
if(ele.findElements(By.xpath(xpath)).size()>0)
return true;
else{
Thread.sleep(100);
t++;
continue;
}
}
System.out.println("waited for "+seconds+"seconds. But couldn't find "+xpath+ " in the element specified");
return false;
}
You could wait for the presence of the element to appear as follows:
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.id("someId")));

Explicit in selenium

I am using Selenium to get div value, but the fallowing code is not waiting for the page, just for URL. I used time.sleep, which is very primitive and totally not flexible. I want to change it on the explicit, but I am not too experienced in Python and I have a problem with that.
The website name has been changed just in case :
def repeat():
import wx
while True:
botloc = driver.find_element_by_id('botloc').text
print botloc
botX,botY = map(int,botloc.split(','))
print botX
print botY
wx.Yield()
def checker():
if driver.current_url == 'logged.example.com':
time.sleep(5)
repeat()
else:
checker()
checker()
How can I replace time.sleep with something flexible to wait the shortest time as possible after the page will be loaded? How to use explicit correctly with my code?
I know that's possible with using an element from the website, but I can't write anything sensible, I just need an example.
Is possibility to use element_by_id('botloc') for wait till it will be visible then start repeat() ?
How can i replace time.sleep with something flexible to wait shortest
time as possible after the page will be loaded?
I suppose you use get(url) to load the page. Generally you don't have to do anything, WebDriver automatically waits until page is being loaded. So you can remove time.sleep(). However there are some issues reported when loading the page using get with firefox driver, because of that you will have to wait for some target element which is supposed to be in the loaded page as mentioned below.
How to use explicit correctly with my code?
Have you checked Selenium webdriver documentation ? you can wait for botloc element explicitly as below
//assuming you have a valid webdriver reference
//Ex: DEFAULT_WAIT = 10 means
//waits up to 10 seconds before throwing a TimeoutException or if it finds the element will return it in 0 - 10 seconds.
element = WebDriverWait(webdriver, DEFAULT_WAIT).until(EC.presence_of_element_located((By.ID, "botloc")))
Refer this page for more information