Appium + Python on Android - scrolling
I have an app to automate tests for. Scenario looks like this:
I tap on date picker > calendar appears
I tap on the year > a list of years appears
I want to scroll until '1993' is visible
the year '1993' is not visible on the screen and I want to keep scrolling until it is. I've tried
TouchAction(driver).press(x=746, y=1351).move_to(x=755, y=588).release().perform()
^but I don't want to use coordinates, plus I'd have to repeat that line several times.
def set_year(self):
visibility = self.driver.find_element(By.XPATH, "//android.widget.TextView[#text='1993']").is_displayed()
while not visibility:
TouchAction(self.driver).press(x=746, y=1351).move_to(x=755, y=588).release().perform()
visibility = self.driver.find_element(By.XPATH, "//android.widget.TextView[#text='1993']").is_displayed()
else:
print("not found")
^but it keeps throwing me selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters error, since as I said, it's not visible
What is the best approach for this?
el = self.driver.find_element_by_xpath(<your_xpath>) driver.execute_script("mobile: scrollTo", {"element": el.id})
^this one gives me an error saying that a tuple does not have id
Appium will throw an error each time an element is not find.
So, your script stops before swiping, when you define your variable visibility.
Try this :
def set_year(self):
visibility = False
i = 0
while not visibility or i<100:
i += 1
try:
visibility = self.driver.find_element(By.XPATH,
"//android.widget.TextView[#text='1993']").is_displayed()
except:
TouchAction(self.driver).press(x=746, y=1351).move_to(x=755,
y=588).release().perform()
if not visibility:
print("not found")
Your script will scroll down until the year 1993 is found.
Related
I'm trying to write a selenium script with python that downloads my bills from a website. There are more bills (rows) that can fit in the view port, and when the script reaches the end of the view port it fails. So I tried:
ActionChains(self.driver).move_to_element(element).perform() ==> NOK
element.location_once_scolled_into_view ==> OK in console
self.driver.execute_script("window.scrollTo({});") ==> OK in console
Number 2. and 3. worked like a charm when I ran it in the pycharm python console line-by-line:
the sidebar scroll moves down to the target element
can .click() the element in question.
When used in a class
the scroll bar does not move at all, and throws this error:
selenium.common.exceptions.ElementClickInterceptedException: Message:
element click intercepted: Element is not clickable at point (1187,
642)
def downloader(self, count, provider):
print("count: ", count) # count is the number of row for a
provider
for number in range(1, (count + 1)) :
#sleep(2)
element = self.wait.until(EC.visibility_of(
self.driver.find_element(By.XPATH,
"//table/tbody/tr[{}]/td[6]".format(number))))
location = element.location_once_scolled_into_view
# ActionChains(self.driver).move_to_element(element)
.perform()
#self.driver.execute_script("arguments[0]
.scrollIntoView(true);",element);
# self.wait.until(EC.element_to_be_clickable(element))
# sleep(1)
self.driver.execute_script("window.scrollTo({});"
.format(location))
element.click()
The issue could be due to the fact that the element is not being scrolled into view completely when being executed as part of a class. When you're executing the script line by line in the console, it has enough time to complete the scroll before the element is clicked.
To resolve the issue, you can try adding an explicit wait after scrolling to give the page enough time to load before attempting to click the element.
Here's an updated version of your code with the added explicit wait:
def downloader(self, count, provider):
print("count: ", count) # count is the number of row for a provider
for number in range(1, (count + 1)):
element = self.wait.until(EC.visibility_of(
self.driver.find_element(By.XPATH, "//table/tbody/tr[{}]/td[6]".format(number))))
location = element.location_once_scolled_into_view
self.driver.execute_script("window.scrollTo({});".format(location))
# Add explicit wait
self.wait.until(EC.element_to_be_clickable(element))
element.click()
Helllo everyone,
Can you please anyone help to calculate the load time of each page. I want to do with performance analysis of web page. This below code works with the Complete execution time. But i want to calculate the each loading page after everyclick.
navigationStart = driver.execute_script("return window.performance.timing.navigationStart")
responseStart = driver.execute_script("return window.performance.timing.responseStart")
domComplete = driver.execute_script("return window.performance.timing.domComplete")
backendPerformance_calc = responseStart - navigationStart
frontendPerformance_calc = domComplete - responseStart
print("Back End: %s" % backendPerformance_calc)
print("Front End: %s" % frontendPerformance_calc)
Can you anyone help me solve this problem.
You can use this js to perform this check:
state = driver.execute_script(" return document.readyState; ")
Or, you can simple add an explicit wait after a specific element and see when it was displayed, then do some math (when you clicked and when the element was displayed)
I am new to python and managed to write a little program (using python3) to retrieve information from a website. I have two problems:
I do not know how to tell python to wait each 80th step, so when i = 80, 160, 240 etc.
I do not know how to tell python to retrieve the information from the website how many steps exist in total (as this varies from page to page), see image below. I can see in the picture that the maximum amount of 260 is "hard-coded" in this example? Can I tell python to retrieve the 260 by itself (or any other number if this changes on another web page)?
How can I tell python to check which is the current page the script starts, so that it can adjust i to the page`s number? Normally I presume to start at page 0 (i = 0), but for example, if I were to start at page 30, my script shall be able to make i = 30 or if I start at 200, it shall be able to adjust i = 200 etc before it goes to the while loop.
Is it clear what I am troubling with?
This is the pseudo code:
import time
from selenium import webdriver
url = input('Please, enter url: ')
driver = webdriver.Firefox()
driver.get(url)
i = 0
while i > 260: # how to determine (book 1 = 260 / book 2 = 500)?
# do something
if i == 80: # each 80th page?
# pause
else:
# do something else
i = i + 1
else:
quit()
1) sleep
import time
....
if i % 80 == 0: # each 80th page?
# Wait for 5 seconds
time.sleep(5)
2) element selectors
html = driver.find_element_by_css_selector('afterInput').get_attribute('innerHTML')
3) arguments
import sys
....
currentPage = sys.argv[2]
or extract it from the source (see 2)
First, if you want to know if your i is "step"(devision) of 80 you can use the modulo sign, and check if it equal to 0, for instance:
if i % 80 == 0:
time.sleep(1) # One second
Second, you need to query the html you receive from the server, for instance:
from selenium import webdriver
url = input('Please, enter url: ')
driver = webdriver.Firefox()
driver.get(url)
total_pages = driver.find_element_by_css_selector('afterInput').get_attribute('innerHTML').split()[1] # Take only the number
after your edit: All you have to do is to is to assign i with this value you want by defining a variable in your script/parsing the arguments from the command line/scrape it from the website. This is Depends on your implementation and needs.
Other notes
I know you're on your beginning steps, but if you want to improve your code and make it a bit more pythonic I would do the following changes:
Using while and i = i + 1 is not a common pattern in python, instead use for i in range(total_pages) - of course you need to know the number of pages (from your second question)
There is no need to call quit(), your script will end anyway in the end of the file.
I think you meant while i < 260.
I have created a keyword for RF and Selenium2Library. It is supposed to wait for some element by clicking periodically on some other element which will renew the area where the element is supposed to appear. I use it for example for waiting for mails in postbox.
The problem is that pretty often the "renew element" cannot be found and clicked on some loop iteration however it exists on the screenshot. Any ideas why it can happen?
def check_if_element_appeared(self, element_locator, renew_locator, renew_interval=10, wait_interval=300):
if not self.is_visible(renew_locator):
raise AssertionError("Error Message")
start_time=int(time())
scan_time = start_time
if not self.is_visible(element_locator):
while int(time())<=start_time+wait_interval:
if int(time()) >= scan_time + renew_interval:
scan_time = int(time())
self.click_element(renew_locator)
if self.is_visible(element_locator):
break
if not self.is_visible(element_locator):
raise AssertionError("Error Message")
self._info("Message")
else:
self._info("Current page contains element '%s'." % element_locator)
Shouldn't be using the keywords Wait Until Page Contains Element or Wait Until Element Is Visible of the Selenium2Library for this purpose:
*** Test cases ***
Your Test Case
Prerequisite steps
Wait Until Page Contains Element ${locator}
Succeeding steps
Edit: Below is what your Python code might look like in pure Robot syntax.
${iteration}= Evaluate ${wait_interval} / ${renew_interval}
: FOR ${i} IN RANGE 0 ${iteration}
\ Click Element ${renew_locator}
\ Sleep 1
\ ${is_visible}= Run Keyword And Return Status Element Should Be Visible ${element_locator}
\ Exit For Loop If ${is_visible}
\ Run Keyword If '${is_visible}' == 'False' Sleep ${renew_interval}
Click Element ${element_locator}
I need to check if user has already logged into the application. So I have to check for any of the 3 elements below mentioned are present. If anyone of them is present, user is logged in and I need to click sign out button.
The elements are :
1. sign out button already present(since user is already signed in )
2. Account name
My script is like :
if(wd.find_element_by_name("sign out").is_displayed()):
wd.find_element_by_name("sign out").click()
elif(wd.find_element_by_name("usr_name").is_displayed()):
wd.find_element_by_name("usr_name").click()
wd.find_element_by_name("menu_close").click()
wait("sign out")
wd.find_element_by_name("sign out").click()
else:
print"NOt Signed in"
But what happens is my appium is executing the first IF Loop and waiting for the element sign out and ends with an error message.
An element could not be located on the page using the given search parameters.
Where I am doing wrong ? Usually how can I check if an element is present then click it, like that. Please help me.
shouldn't the elif be unindented like this:
if(wd.find_element_by_name("sign out").is_displayed()):
wd.find_element_by_name("sign out").click()
elif(wd.find_element_by_name("usr_name").is_displayed()):
wd.find_element_by_name("usr_name").click()
wd.find_element_by_name("menu_close").click()
wait("sign out")
wd.find_element_by_name("sign out").click()
else:
print"NOt Signed in"
You should use wd.implicitly_wait(30) after each command, so that the appium server waits for next element to be visble
If you want to check an element is present before firing an action just create a method which returns a boolean value based on the isDisplayed property for the element.
Something like this :
def IsElementDisplayed():
try:
return wd.find_element_by_name("sign out").is_displayed()
except:
return false
And call the IsElementDisplayed before each action from the test sript.
Because there's no element that has the name "sign out", find_element_by_name() is throwing an exception that isn't being handled. One way to solve this is to write a wrapper for searching for elements that includes exception handling. As mentioned in another answer, setting the implicit wait bakes in waiting for elements to be present and repeatedly searches for the element until the timer expires (20s in the code below)
from selenium.common.exceptions import NoSuchElementException
wd.implicitly_wait(20)
sign_out = find_element("sign out")
usr_name = find_element("usr_name")
if sign_out is not None and sign_out.is_displayed():
sign_out.click()
elif usr_name is not None and usr_name.is_displayed():
usr_name.click()
menu_close = find_element("menu_close")
menu_close.click()
sign_out = find_element("sign out")
sign_out.click()
else:
print("Not signed in")
def find_element(self, element_text):
try:
element = wd.find_element_by_name(element_text)
except NoSuchElementException:
return None
return element