Selenium actions - are they logged and where? - selenium

I'm having some issues in finding Selenium logs of actions performed on the browser.
My situation is the following:
I have a canvas with some clickable elements (it's a map).
I click on a specific point through actions.moveByOffset(pointToClick.getX(), pointToClick.getY()).click().build().perform(). Sometimes the point gets clicked, sometimes it seems not and I need to figure out what exactly happens.
How can I make sure that the click has indeed been performed? I set up the LoggingPreferences in the WebDriver configuration class
LoggingPreferences logPrefs = new LoggingPreferences();
logPrefs.enable(LogType.PERFORMANCE, Level.ALL);
logPrefs.enable(LogType.PROFILER, Level.ALL);
logPrefs.enable(LogType.BROWSER, Level.ALL);
logPrefs.enable(LogType.CLIENT, Level.ALL);
logPrefs.enable(LogType.DRIVER, Level.ALL);
logPrefs.enable(LogType.SERVER, Level.ALL);
capabilities.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);
but some of them (server, performance) are empty, while the browser logs contain data similar to what I see in the browser console. Since those are all the LogTypes available, I'm not even sure I'm looking at the correct direction. Do you have any suggestion?
Thank you for your help!

There are a few advanced libraries built-in to Selenium such as EventFiringWebDriver, AbstractEventListener, etc, which can be used to log all Selenium actions being performed.
Relevant Java Docs can be found here: https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/events/EventFiringWebDriver.html
https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/events/EventFiringDecorator.html
https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/events/WebDriverListener.html
I also have a working Python SeleniumBase example from here, which performs actions that get recorded and printed out. To run that example, you'll first need to pip install seleniumbase, then run the test with pytest: pytest test_event_firing.py -s.
from selenium.webdriver.support.events import EventFiringWebDriver
from selenium.webdriver.support.events import AbstractEventListener
from seleniumbase import BaseCase
class MyListener(AbstractEventListener):
def before_navigate_to(self, url, driver):
print("Before navigating to: %s" % url)
def after_navigate_to(self, url, driver):
print("After navigating to: %s" % url)
def before_find(self, by, value, driver):
print('Before find "%s" (by = %s)' % (value, by))
def after_find(self, by, value, driver):
print('After find "%s" (by = %s)' % (value, by))
def before_click(self, element, driver):
print('Before clicking on element with text: "%s"' % element.text)
def after_click(self, element, driver):
print("Click complete!")
class EventFiringTests(BaseCase):
def test_event_firing_webdriver(self):
self.driver = EventFiringWebDriver(self.driver, MyListener())
print("\n* EventFiringWebDriver example *")
self.open("https://xkcd.com/1862/")
self.click("link=About")
self.open("https://store.xkcd.com/search")
self.type('input[name="q"]', "xkcd book\n")
self.open("https://xkcd.com/1822/")
The output of that prints the Selenium actions that were detected via the EventListener:
* EventFiringWebDriver example *
Before navigating to: https://xkcd.com/1862/
After navigating to: https://xkcd.com/1862/
Before find "About" (by = link text)
After find "About" (by = link text)
Before find "About" (by = link text)
After find "About" (by = link text)
Before clicking on element with text: "About"
Click complete!
Before navigating to: https://store.xkcd.com/search
After navigating to: https://store.xkcd.com/search
Before find "input[name="q"]" (by = css selector)
After find "input[name="q"]" (by = css selector)
Before navigating to: https://xkcd.com/1822/
After navigating to: https://xkcd.com/1822/
Similar solutions exist for the other Selenium language bindings.

Related

Webdriver Selenium not loading new page after click()

I´m using selenium to scrape a webpage and it finds the elements on the main page, but when I use the click() function, the driver never finds the elements on the new page. I used beautifulSoup to see if it´s getting the html, but the html is always from the main. (When I see the driver window it shows that the page is opened).
html = driver.execute_script('return document.documentElement.outerHTML')
soup = bs.BeautifulSoup(html, 'html.parser')
print(soup.prettify)
I´ve used webDriverWait() to see if it´s not loading but even after 60 seconds it never does,
element = WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.ID, "ddlProducto")))
also execute_script() to check if by clicking the button using javascript loads the page, but it returns None when I print a variable saving the new page.
selectProducto = driver.execute_script("return document.getElementById('ddlProducto');")
print(selectProducto)
Also used chwd = driver.window_handles and driver.switch_to_window(chwd[1]) but it says that the index is out of range.
chwd = driver.window_handles
driver.switch_to.window(chwd[1])

Locating elements in section with selenium

I'm trying to enter text into a field (the subject field in the image) in a section using Selenium .
I've tried locating by Xpath , ID and a few others but it looks like maybe I need to switch context to the section. I've tried the following, errors are in comments after lines.
from selenium.webdriver import Firefox
from selenium.webdriver.firefox.options import Options
opts = Options()
browser = Firefox(options=opts)
browser.get('https://www.linkedin.com/feed/')
sign_in = '/html/body/div[1]/main/p/a'
browser.find_element_by_xpath(sign_in).click()
email = '//*[#id="username"]'
browser.find_element_by_xpath(email).send_keys(my_email)
pword = '//*[#id="password"]'
browser.find_element_by_xpath(pword).send_keys(my_pword)
signin = '/html/body/div/main/div[2]/div[1]/form/div[3]/button'
browser.find_element_by_xpath(signin).click()
search = '/html/body/div[8]/header/div[2]/div/div/div[1]/div[2]/input'
name = 'John McCain'
browser.find_element_by_xpath(search).send_keys(name+"\n")#click()
#click on first result
first_result = '/html/body/div[8]/div[3]/div/div[1]/div/div[1]/main/div/div/div[1]/div/div/div/div[2]/div[1]/div[1]/span/div/span[1]/span/a/span/span[1]'
browser.find_element_by_xpath(first_result).click()
#hit message button
msg_btn = '/html/body/div[8]/div[3]/div/div/div/div/div[2]/div/div/main/div/div[1]/section/div[2]/div[1]/div[2]/div/div/div[2]/a'
browser.find_element_by_xpath(msg_btn).click()
sleep(10)
## find subject box in section
section_class = '/html/body/div[3]/section'
browser.find_element_by_xpath(section_class) # no such element
browser.switch_to().frame('/html/body/div[3]/section') # no such frame
subject = '//*[#id="compose-form-subject-ember156"]'
browser.find_element_by_xpath(subject).click() # no such element
compose_class = 'compose-form__subject-field'
browser.find_element_by_class_name(compose_class) # no such class
id = 'compose-form-subject-ember156'
browser.find_element_by_id(id) # no such element
css_selector= 'compose-form-subject-ember156'
browser.find_element_by_css_selector(css_selector) # no such element
wind = '//*[#id="artdeco-hoverable-outlet__message-overlay"]
browser.find_element_by_xpath(wind) #no such element
A figure showing the developer info for the text box in question is attached.
How do I locate the text box and send keys to it? I'm new to selenium but have gotten thru login and basic navigation to this point.
I've put the page source (as seen by the Selenium browser object at this point) here.
The page source (as seen when I click in the browser window and hit 'copy page source') is here .
Despite the window in focus being the one I wanted it seems like the browser object saw things differently . Using
window_after = browser.window_handles[1]
browser.switch_to_window(window_after)
allowed me to find the element using an Xpath.

Different test behavior in Chrome and Firefox [duplicate]

I have a rather complex webpage setup I need to test, containing nested frames.
In the actual problem the selenium code is loading new webpage contents containing a frame, which I want to switch to. In order to avoid any explicit waits, I tried the following code snippet:
self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).\
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).\
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))
However, this snippet always fails and results in the following error:
...
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/wait.py", line 71, in until
value = method(self._driver)
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 247, in __call__
self.frame_locator))
File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 402, in _find_element
raise e
WebDriverException: Message: TypeError: can't access dead object
However, if I use a sleep in addition:
time.sleep(30)
self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).\
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).\
until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))
selenium is able to find the frame inside the frame and switch to it. It looks like in the error case selenium switches to 'frame1' while 'frame2' is not yet loaded, but 'frame2' gets loaded in some other instance of 'frame1', or not recognized by selenium (maybe a bug?). So now selenium is inside some 'frame1' and for some reasons does not realize that the 'frame2' has been loaded.
The only way I can fix this (without using a long sleep) is by using this ugly piece of code:
mustend = time.time() + 300
while time.time() < mustend:
try:
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
break
except WebDriverException as e:
self.log("Sleeping 1 sec")
time.sleep(1)
if time.time() > mustend:
raise TimeoutException
So whenever I get a WebDriverException (dead object), I go to the top-level frame and try to switch to the inner frame - frame by frame.
Is there any other approach I can try?
Additional information
The iframes are nested, i.e. 'frame2' is inside 'frame1'.
Better approach is to make your own expected_condition.
For example:
class nested_frames_to_be_available_and_switch:
def __init__(self, *args):
"""
:param args: locators tuple of nested frames (BY.ID, "ID1"), (BY.ID, "ID2"), ...
"""
self.locators = args
def __call__(self, driver):
try:
for locator in self.locators:
driver.switch_to.frame(driver.find_element(*locator))
except WebDriverException:
driver.switch_to_default_content()
return False
return True
WebDriverWait(driver, 300).until(nested_frames_to_be_available_and_switch((By.ID, 'frame1'), (By.ID, 'frame1')))
But maybe there is no need for that.. To tell so I need to see your html DOM.
This error message...
WebDriverException: Message: TypeError: can't access dead object
...implies that there was an error while switching between <iframes>.
Some more information in terms of:
The relevant HTML
Presence of Frameset
Presence of Frames
Hierarchy of Nested Frames
Sequence of Frame Loading
Presence of JavaScript and AJAX Calls within the respective <iframe> tags
would have helped us to analyze the issue in a better way. However, at this point it is worth to mention that initially Selenium always gets the focus on the default_content. Here are a few approaches to work with nested <frames> and <framesets>:
If both frame1 and frame2 are at same level i.e. under the Top Level Browsing Context you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
If frame2 is nested within frame1, to switch from frame1 to frame2 you need to:
self.driver.switch_to_default_content()
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
//code
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
If frame2 and frame3 is within frame1 then, to switch from frame2 to frame3 you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))
If frame2 and frame3 is within a frameset23 which is within frame1 then, to switch from frame2 to frame3 you need to:
self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
#ignore presence of frameset23
self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
#ignore presence of frameset23
self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))
Better approach with proper WebDriverWait
While dealing with iframe and frameset you need to induce WebDriverWait inconjunction with expected_conditions:
frame_to_be_available_and_switch_to_it()
As an example to switch from Top Level Browsing Context to an <iframe> an effective line of code will be:
Using frame ID:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"frameID")))
Using frame NAME:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,"frameNAME")))
Using frame CLASS_NAME:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.frame_CLASS_NAME,"u_0_f")))
Using frame CSS_SELECTOR:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame_CSS_SELECTOR")))
Using frame XPATH:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"frame_XPATH")))
tl; dr
Ways to deal with #document under iframe

From which place Selenium Webdriver gets title - using driver.title

From which place Selenium Webdriver usually gets title - using driver.title ?
from Page Source
or from DOM structure
title
title returns the title of the current page.
Usage:
title = driver.title
Defination:
def title(self):
"""Returns the title of the current page.
:Usage:
title = driver.title
"""
resp = self.execute(Command.GET_TITLE)
Details: When you invoke driver.title the HTTP GET request is invoked through the /session/{session id}/title URI Template.
NOTE: This command returns the document title of the current top-level browsing context, equivalent to calling document.title.
The remote end steps are:
If the current top-level browsing context is no longer open, return error with error code no such window.
Handle any user prompts and return its value if it is an error.
Let title be the result of calling the algorithm for getting the title attribute of the current top-level browsing context's active document.
Return success with data title.

Selenium, Autoit and iframe

I was trying to automate the control on a page, on where there is a iframe and an element that can be controlled with AutoIT. I need to click the Scan button within the iframe. I used driver.switch_to.frame("frmDemo") to switch frame, but it seemed not working. Any idea please?
Here is the code:
import win32com.client
import time
from selenium import webdriver
autoit = win32com.client.Dispatch("AutoItX3.Control")
# create a new Firefox session
driver = webdriver.Firefox()
driver.implicitly_wait(30)
driver.get("http://example.com")
time.sleep(2)
driver.switch_to.frame("frmDemo")
scanButton = driver.find_element_by_css_selector('body.input[type="button"]')
scanButton.click()
input is not class, its child element of body. Try without body
scanButton = driver.find_element_by_css_selector('input[type="button"]')
You can also try by the value attribute
scanButton = driver.find_element_by_css_selector('value="Scan"')