I am running a django app and in that scope I have a page with a navigation bar and when I click on my contact-tab this automatically scrolls down to my contact-section.
I am trying to test this behaviour with selenium but I can't seem to figure out how I can test the actual position of the page. Or, in other words, I want to verify that the page actually scrolled down to the contact-section.
Right now I am doing this:
def test_verify_position(
self, browser, live_server
):
""""""
browser.get(live_server.url)
contact_section = browser.find_element_by_id("contact").click()
assert ????
I think I somehow have to get the current scroll location-coordinates. I know I can get the location of an element using .location. But the relative position of an element is always the same no matter the scroll-position. I tried this to debug:
def test_verify_position(
self, browser, live_server
):
""""""
browser.get(live_server.url)
e = browser.find_element_by_xpath(
"/html/body/section[4]/div/div[1]/h2/strong")
location = e.location
print(location)
browser.find_element_by_css_selector(".nav-contact").click()
e = browser.find_element_by_xpath("/html/body/section[4]/div/div[1]/h2/strong")
location = e.location
print(location)
This prints the same coordinates for before and after the scroll.
I also searched the official doc https://www.selenium.dev/documentation/en/webdriver/web_element/ but couldn't find a better solution or any solution for that matter.
Anyone knows how to do this? Help is very much appreciated. Thanks in advance!
Did you want to click on it and check if it moved there? Cause you can return the current scroll height to match with the element location. You could get x,y offset if you want to as well.
height = driver.execute_script("return document.body.scrollHeight")
print(height)
nav = browser.find_element_by_css_selector(".nav-contact")
location = nav.location
print(location)
browser.execute_script("arguments[0].scrollIntoView();",nav)
nav.click()
Assert.assertTrue(height.equals(location['y']));
#what the answer was
browser.execute_script("return window.pageYOffset")
Edit : You can identify one of element in screen loading after click on Contact nav and wait till its visible.
try:
WebDriverWait(driver.visibility_of_element_located, 60).until(EC.presence_of_element_located((By.XPATH, '<xpath>')))
except TimeoutException:
assert False
Need to Import:
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
Related
so I am trying to automate a program that would log in to a google account I created, go to this canvas website, and draw a circle,
(Circle just as a placeholder because im trying to make it draw some cool stuff like a car, just to test if it will work first.) But the main issue is when you first go into the website, there is a pop up that displays and that pop up has 2 options, "learn more" and "Get started". I tried to make selenium click on the "Get started" using driver.find_element_by_id('Get-started').click but it does not seem to work, I also tried to use CSS selector but that does not seem to work either. So, I'm stuck on this. Any advice or help to click the get started button? (Feel free to also give me advice on how to draw in the canvas as well!)
Here's the HTML:
<paper-button id="get-started" dialog-confirm="" class="primary" aria-label="Get started" role="button" tabindex="0" animated="" elevation="0" aria-disabled="false">
Get started
</paper-button>
here's the code:
from selenium import webdriver
import time
from PrivateInfo import*
driver = webdriver.Chrome(r"D:\chromeDriver\chromedriver.exe")
link = "https://www.google.com/"
driver.get(link)
def linkText(element):
button = driver.find_element_by_link_text(element)
button.click()
def byClass(className):
button2 = driver.find_element_by_class_name(className)
button2.click()
def type(text, elements):
input = driver.find_elements_by_name(elements)
for element in input:
driver.implicitly_wait(2)
element.send_keys(text)
linkText("Sign in")
type(email, "identifier")
byClass("VfPpkd-vQzf8d")
type(pw, "password")
driver.find_element_by_id("passwordNext").click()
time.sleep(1)
driver.get("https://canvas.apps.chrome/")
driver.implicitly_wait(3)
driver.find_element_by_css_selector('paper-button[id="get-started"]').click()
edit: I also tried this
getStart = driver.find_elements_by_css_selector('paper-button[id="get-started"]')
for start in getStart:
start.click()
it doesn't give me any errors but it does not do anything.
Ah yeah, forgot to mention but im new to using selenium.
The content of the popup is nested inside shadowRoots.
More on ShadowRoot here:
The ShadowRoot interface of the Shadow DOM API is the root node of a
DOM subtree that is rendered separately from a document's main DOM
tree.
To be able to control the element you will need to switch between DOMs. Here's how:
drawing_app_el = driver.execute_script("return arguments[0].shadowRoot", driver.find_element(By.CSS_SELECTOR, 'drawing-app'))
This code will retrieve the drawing_app first and then return the content of the shadowRoot.
To have access to the button getStarted, here's how:
# Get the shadowRoot of drawing-app
drawing_app_el = driver.execute_script("return arguments[0].shadowRoot", driver.find_element(By.CSS_SELECTOR, 'drawing-app'))
# Get the shadowRoot of welcome-dialog within drawing_app
welcome_dialog_el = driver.execute_script("return arguments[0].shadowRoot", drawing_app_el.find_element(By.CSS_SELECTOR, 'welcome-dialog'))
# Get the paper-dialog from welcome_dialog
paper_dialog_el = welcome_dialog_el.find_element(By.CSS_SELECTOR, 'paper-dialog')
# Finally, retrieve the getStarted button
get_started_button = paper_dialog_el.find_element(By.CSS_SELECTOR, '#get-started')
get_started_button.click()
I wanted to know that how can one get the coordinates of a element according to the screen resolution rather than the browser windows size, I have tried this already (code block), but it provides coordinates according to the browser window rather than the screen
element = driver.find_element_by_xpath("//*[#id='search_form_input_homepage']")
print(element.location)
Any alternatives that I can use?
A terrible attempt to explain what I mean :
note: driver.execute_script is not allowed, as the website has a bot blocker :(
You can use .size and .location to get the sizes.
Try this:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep, strftime
url = "some url"
webdriver = webdriver.Chrome()
webdriver.get(url)
webdriver.fullscreen_window()
cookies = webdriver.find_element_by_xpath("xome xpath")
location = cookies.location
size = cookies.size
w, h = size['width'], size['height']
print(location)
print(size)
print(w, h)
print(element.location_once_scrolled_into_view)
Try if this helps , more available methods like size rect etc can be found at:
https://www.selenium.dev/selenium/docs/api/py/webdriver_remote/selenium.webdriver.remote.webelement.html#module-selenium.webdriver.remote.webelement
I try find target element by xpath so that I can click on it. But can't find it when run code, although can find it by right-click option manually on chrome browser.
detail: I am using
driver.get('chrome://settings/clearBrowserData')
to get history pop-up from chrome, then wait element by selenium,
and next action I try to click it by:
driver.find_element_by_css_selector('* /deep/ #clearBrowsingDataConfirm').click()
or by:
driver.find_element_by_xpath(r'//paper-button[#id="clearBrowsingDataConfirm"]').click()
both does not work
Could you tell solution by xpath if possible because I am more familiar with it. Or any other way to clear history on chrome, thank
Looking into Chrome Settings page source it looks like the button, you're looking for is hidden in the ShadowDOM
So you need to iterate down several levels of ShadowRoot
So the algorithm looks like:
Locate parent WebElement
Locate its shadow-root and cast it to the WebElement
Use WebElement.find_element() function to locate the next WebElement which is the parent for the ShadowRoot
Repeat steps 1-3 until you're in the same context with the element you want to interact with
Example code:
from selenium import webdriver
def expand_root_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
driver = webdriver.Chrome("c:\\apps\\webdriver\\chromedriver.exe")
driver.maximize_window()
driver.get("chrome://settings/clearBrowserData")
settingsUi = driver.find_element_by_tag_name("settings-ui")
settingsUiShadowRoot = expand_root_element(settingsUi)
settingsMain = settingsUiShadowRoot.find_element_by_tag_name("settings-main")
settingsShadowRoot = expand_root_element(settingsMain)
settingsBasicPage = settingsShadowRoot.find_element_by_tag_name("settings-basic-page")
settingsBasicPageShadowroot = expand_root_element(settingsBasicPage)
settingsPrivacyPage = settingsBasicPageShadowroot.find_element_by_tag_name("settings-privacy-page")
settingsPrivacyShadowRoot = expand_root_element(settingsPrivacyPage)
settingsClearBrowsingDataDialog = settingsPrivacyShadowRoot.find_element_by_tag_name(
"settings-clear-browsing-data-dialog")
settingsClearBrowsingDataDialogShadowRoot = expand_root_element(settingsClearBrowsingDataDialog)
settingsClearBrowsingDataDialogShadowRoot.find_element_by_id("clearBrowsingDataConfirm").click()
I got it to work by doing this:
driver.ExecuteScript("return document.querySelector('body > settings-ui').shadowRoot.querySelector('#main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('#advancedPage > settings-section:nth-child(1) > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataConfirm').click();");
I want to locate the elements of a popup on some page,
the popup html is written in an iframe,
also the popup is triggered by clicking a link on the main page.
The weird thing is, if I run the whole code, I can not locate the 'target' element:
dr = webdriver.Chrome('chromedriver.exe', options=chrome_options)
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
def ec_visible(driver, locator):
return WebDriverWait(driver, 5).until(EC.visibility_of_element_located(locator))
But, if I first open the popup then locate, it works.
First:
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
#popup = (By.CLASS_NAME, "add-addr-iframe")
#dr.switch_to.frame(ec_visible(dr, popup))
#target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
#ec_visible(dr, target).click()
Then: (works too if I manually open the popup and run this code)
#modify = (By.CLASS_NAME, "modify")
#ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
Appreciate if you can point out my problem!
Here is the exception from shell:
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
This is the html screenshot,
sometimes the content in iframe can not even be seen.
iframe not extendable
when iframe extendable
7/26 update
I am wondering whether I asked the right question which may lead you guys just focusing on my code part. Since my code works(seperately), the elements and frames approach are good.
I step back and find one detail which may help but I don't know how it matters.
Here are the two shots about ctrl-F some element in the page source:
Normal result: target found and highlighted
Weird result: target found and no highlight
I mean when the page exists 'weird result', my code does not work.
PS. The page is the order-confirmation part of an e-commerical site, but the site groups its goods into two types which led to TWO types order page.
For ifarmes you have frame_to_be_available_and_switch_to_it as the EC.
So try this:
WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.CLASS_NAME, "add-addr-iframe")))
target = (By.CLASS_NAME, "span.cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
I have a HTML code like this:
<div class="links nopreview"><span><a class="csiAction"
href="/WebAccess/home.html#URL=centric://REFLECTION/INSTANCE/_CS_Data/null">Home</a></span> • <span><span><a class="csiAction"
href="/WebAccess/home.html#URL=centric://SITEADMIN/_CS_Site">Setup</a></span> • </span><span><a
title="Sign Out" class="csiAction csiActionLink">Sign Out</a></span></div>
I would like to click on the link that has the text Home. As this Home link appears after login, I have a code like this:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import re
browser = webdriver.Firefox() # Get local session of firefox
browser.get("http://myServer/WebAccess/login.html") # Load App page
elem = browser.find_element_by_name("LoginID") # Find the Login box
elem.send_keys("Administrator")
elem = browser.find_element_by_name("Password") # Find the Password box
elem.send_keys("Administrator" + Keys.RETURN)
#try:
elem = browser.find_element_by_link_text("Home")
elem.click()
The part till login works great. However the last but one line is problematic
elem = browser.find_element_by_link_text("Home")
It raises this NoSuchElementException where the Home link is there as you can see from the HTML code.
raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: u'Unable to locate element: {"method":"link text","selector":"Home"}'
Any guidance as to what I am doing wrong, please?
Have you tried adding an implicit wait to this so that it waits instead of running to quickly.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import re
browser = webdriver.Firefox() # Get local session of firefox
browser.implicitly_wait(10) #wait 10 seconds when doing a find_element before carrying on
browser.get("http://myServer/WebAccess/login.html") # Load App page
elem = browser.find_element_by_name("LoginID") # Find the Login box
elem.send_keys("Administrator")
elem = browser.find_element_by_name("Password") # Find the Password box
elem.send_keys("Administrator" + Keys.RETURN)
#try:
elem = browser.find_element_by_link_text("Home")
elem.click()
The implicitly_wait call makes the browser poll until the item is on the page and visible to be interacted with.
The most common issues with NoSuchElementException while the element is there are:
the element is in different window/frame, so you've to switch to it first,
your page is not loaded or your method of page load is not reliable.
Solution could include:
check if you're using the right frame/window by: driver.window_handles,
write a wait wrapper to wait for an element to appear,
try XPath instead, like: driver.find_element_by_xpath(u'//a[text()="Foo"]').click(),
use pdb to diagnose your problem more efficiently.
See also: How to find_element_by_link_text while having: NoSuchElement Exception?
Maybe the element you are looking for doesn't exactly match that text string?
I know it can be tricky if it looks like it does on-screen, but sometimes there are oddities embedded like this simple markup "Home" or "Home" which makes the first char italic:
"<i>H</i>ome" is visually identical to "<em>H</em>ome" but does not match text.
Edit: after writing the above answer, I studied the question closer and discovered the HTML sample does show "Home" in plain text, but was not visible due to long lines not wrapping. So I edited the OP to wrap the line for readability.
New observation: I noticed that the Logout element has a "title" attribute, but the Home link element lacks such--try giving it one and using that.
Try adding an implicit wait to this in order to wait, instead of running too quickly.
Or
else you can import time and use time.sleep(25)