Stale element reference exception - Selenium - selenium

so I am creating a testing framework for a webapp but first I have to login to the site in order to begin the tests. My problem is that the login is in two parts, first page where you enter your email and then click an access button. The webapp checks the email against a database and sends you forward to a new page to enter your password and to finish the login procedure. The problem I am getting is the Stale element reference exception, but no matter what I do I can not get around it. I have tried explicit waits and implicit waits, a for loop and a while loop both with and without try/excepts.
This is my code as it stands right now, it gets me to the password page but then I get the Stale element reference exception no matter how long I set the wait time or how I get the element (by xpath/css etc).
# Methods
def click(driver, locator):
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)).click()
def send_Keys(driver, locator, value):
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)).clear()
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(locator)).send_keys(value)
# Setting up Driver
s = Service('C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe')
driver = webdriver.Chrome(service=s)
url = 'http://localhost:8501/'
driver.get(url)
driver.maximize_window()
# Entering Email
send_Keys(driver, (By.XPATH, "//div/input"), username)
# Clicking Access Button
click(driver, (By.XPATH, "//div/button[#kind]"))
# Entering Password -- Getting error STALE ELEMENT
wait = WebDriverWait(driver, 60)
wait.until(EC.element_to_be_clickable(
(By.XPATH, "//input[#inputmode='text']")))
time.sleep(2)
wait.until(EC.element_to_be_clickable(
(By.XPATH, "//input[#inputmode='text']"))).send_keys(password)
# Clicking Access Button
click(driver, (By.XPATH, "//div/button[#kind]"))
Any help would be appreciated.

Related

Rotating Proxies and Selenium - Close driver and re-run script with new IP

I am running an automated script that needs to change IP every 5-6 refreshes. I understand that the it cannot be changed dynamically as it needs to re-open the webdriver with new options. I have a list of proxies in a text file and I wish to use these IPs at random every 5-6 times the driver refreshes. It would normally get stuck in a try catch statement that looks for a keyword and if it does not find the keyword it will refresh every 5 seconds until this word is found.
def find_link_by_word_in_href(driver, words):
for word in words:
try:
return driver.find_element(By.XPATH, f"//*[contains(#href,'{word}')]")
except NoSuchElementException:
pass
while True:
element = find_link_by_word_in_href(driver, ['dadsa', 'daasd', 'asdsad'])
if element is not None:
element.click()
break
else:
driver.refresh()
time.sleep(5)
I wish to break this once it hits 5 refreshes and restart the script choosing a new IP from the text file. Can anybody help or point me in the correct direction to solve this?

Selenium creating bulk email addresses

I want to use selenium to create several email addresses at once. I suppose they can be random but I already have a list of the email account names I want to create.
I know how to create 1 email using webdriver but how would I go about it if I want to sign up several, one after the other automatically, without having to always change the code?
Simple code for creating 1 email:
from selenium import webdriver
import time
url = 'https://hotmail.com/'
driver = webdriver.Chrome('/C:Users/Desktop/chromedriver')
driver.get(url)
driver.find_element_by_xpath("//a[contains(#class, 'linkButtonSigninHeader')]/#href").click()
time.sleep(2)
driver.find_element_by_id('MemberName').send_keys('usernameexample')
time.sleep(1)
driver.find_element_by_id('iSignupAction).click()
time.sleet(2)
driver.find_element_by_id('PasswordInput').send_keys('Passwordexample1')
time.sleep(1)
driver.find_element_by_id('iSignupAction').click()
time.sleep(2)
driver.find_element_by_id('FirstName').send_keys('john')
time.sleep(1)
driver.find_element_by_id('LastName').send_keys('wayne')
time.sleep(1)
driver.find_element_by_id('iSignupAction').click()
As others have pointed out, you could iterate over a data collection, such as an array:
array_of_usernames = ['username_one', 'username_two']
array_of_usernames.each do |username|
url = 'https://hotmail.com/'
driver = webdriver.Chrome('/C:Users/Desktop/chromedriver')
driver.get(url)
driver.find_element_by_xpath("//a[contains(#class, 'linkButtonSigninHeader')]/#href").click()
driver.find_element_by_id('MemberName').send_keys("#{username}") #INTERPOLATED BLOCK-LOCAL VARIABLE HERE
driver.find_element_by_id('iSignupAction).click()
driver.find_element_by_id('PasswordInput').send_keys('Passwordexample1')
driver.find_element_by_id('iSignupAction').click()
driver.find_element_by_id('FirstName').send_keys('john')
driver.find_element_by_id('LastName').send_keys('wayne')
driver.find_element_by_id('iSignupAction').click()
# some step to log out so that next username can register
end
If you aren't familiar with arrays or iteration, then I'd suggest looking at the docs to get your head around it: https://ruby-doc.org/core-2.6.1/Array.html#method-i-each

GMail - waiting for the page for fully loaded

I am trying to automate gmail page (for some kind of email verification), after input username and password, I want to wait the page to fully loaded before continuing to my next action.
This is what I tried:
Selenium2Library.Input Text //input[contains(#id, "identifierId")] ${local_email_username}
Selenium2Library.Click Element //span[text()="Berikutnya"]
Sleep 2s
Selenium2Library.Wait Until Element Is Visible //input[contains(#name, "password")] timeout=30s
Selenium2Library.Input Password //input[contains(#name, "password")] ${local_email_password}
Selenium2Library.Click Element //span[text()="Berikutnya"]
Sleep 2s
Selenium2Library.Wait Until Element Is Visible //input[contains(#aria-label, "Search")] timeout=30s
### should be logged in to gmail
Log >>> logged in to gmail. sleeping..
Sleep 5s
### make sure the email page fully loaded
Log >>> making sure the email page fully loaded.. waiting new conversation button appeared
Comment Wait Until Keyword Succeeds 10x 2s Selenium2Library.Page Should Contain ${email_name}
Wait Until Keyword Succeeds 20x 3s Selenium2Library.Page Should Contain Element //button[contains(#title, 'New conversation')]
Log >>> email page fully loaded. start searching activation email...
What I want to achieve is waiting for the new conversation button, that indicates that page is fully loaded (//button[contains(#title, 'New conversation')])
The problem is the script never finds the button. I tried to inspect and search for that xpath, and the element found.
Is there any solution for that?
Update:
i tried using Select Frame like this.. like #Gaurav said.. here's the code:|
Selenium2Library.Select Frame ${iframe_locator}
Wait Until Keyword Succeeds 20x 3s Selenium2Library.Page Should Contain Element //button[contains(#title, 'New conversation')]
Selenium2Library.Unselect Frame
where ${iframe_locator} is //body/div[7]/div[3]/div[1]/div[2]/div[1]/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/iframe[2]
but still no luck
The button is in iFrame, so you need to switch to that iFrame(there might be more iframes, so you need to switch to that specific one) and the look for //button[contains(#title, 'New conversation')]
Here is Corresponding Java Implementation
#Test
public void newConversation() throws IOException, InterruptedException{
driver.get("https://www.google.com/intl/hi/gmail/about/");
driver.findElement(By.linkText("प्रवेश करें")).click();
driver.findElement(By.id("identifierId")).sendKeys("*********#gmail.com");
driver.findElement(By.id("identifierNext")).click();
Thread.sleep(30000);
driver.switchTo().frame(5);
WebElement element = driver.findElement(By.xpath("//div[contains(#aria-label,'Change profile picture')]"));
Actions action = new Actions(driver);
action.moveToElement(element).build().perform();
driver.findElement(By.xpath("//button[contains(#title,'New conversation')]")).click();
}

Threading and Selenium

I'm trying to make multiple tabs in Selenium and open a page on each tab simultaneously. Here is the code.
CHROME_DRIVER_PATH = "C:/chromedriver.exe"
from selenium import webdriver
import threading
driver = webdriver.Chrome(CHROME_DRIVER_PATH)
links = ["https://www.google.com/",
"https://stackoverflow.com/",
"https://www.reddit.com/",
"https://edition.cnn.com/"]
def open_page(url, tab_index):
driver.switch_to_window(handles[tab_index])
driver.get(url)
return
# open a blank tab for every link in the list
for link in range(len(links)-1 ): # 1 less because first tab is already opened
driver.execute_script("window.open();")
handles = driver.window_handles # get handles
all_threads = []
for i in range(0, len(links)):
current_thread = threading.Thread(target=open_page, args=(links[i], i,))
all_threads.append(current_thread)
current_thread.start()
for thr in all_threads:
thr.join()
Execution goes without errors, and from what I understand this should logically work correctly. But, the effect of the program is not as I imagined. It only opens one page at a time, sometimes it doesn't even switch the tab... Is there a problem that I'm not aware of in my code or threading doesn't work with Selenium?
There is no need in switching to new window to get URL, you can try below to open each URL in new tab one by one:
links = ["https://www.google.com/",
"https://stackoverflow.com/",
"https://www.reddit.com/",
"https://edition.cnn.com/"]
# Open all URLs in new tabs
for link in links:
driver.execute_script("window.open('{}');".format(link))
# Closing main (empty) tab
driver.close()
Now you can handle (if you want) all the windows from driver.window_handles as usual

Check if login was successful with Selenium

I'm just getting to grips with Selenium, and have made a simple log in script using the Firefox IDE.
What want to do now is check if the log in was successful.
The simplest way I could think of was to search for a piece of text that is only visible after log in i.e. Hi, [account name].
But I'm a little unsure on how to do this with Selenium.
Is there a way you can search for a term on a page and then act, upon its presence?
Also, is this the best way to check if your logged in?
1) Yes, I am checking for sucessful login by the way that I search for specific label. In my case that label contains ID of logged in user. Example:
<span id="username">PAVEL007</span>
So, when I log in:
driver.get("http://PAVEL007:OmgTooSecretToTellYou!#my-test-site.com");
Then I search for that label
WebElement loggedInUser = driver.findElement(By.id("username"));
And verify that I am in:
Assert.assertEquals(loggedInUser.getText(),"PAVEL007");
In nutshell:
If your website shows some specific text visible only after sucessful login, use that text
Best way is not to search for that text itself, but for element containing the text
NOTE
The driver variable is assumed healthy, living instance of WebDriver
My pseudo code is Java based
Get a url which can be accessed only after login.
url = "some url accessed only after login"
driver.navigate_to url
driver.current_url == url ? "logged_in" : "not_logged_in"
if not logged in it will be redirected to some other url. This is applicable in websites where url is not created dynamically
If you're using the IDE it should be a simple case of recording your login action and then where you have your Hi [username] element, right-click on it and then in the context menu you should see additional options that are from the IDE.
One of those should be verify text or assert text. Select that, when you then run your test case it will complete the login account and verify/assert that the Hi [username] text is on the page.
If you are using selenium IDE, it should very easy case, first of all you have to recording your login action and after login you have Hi [username] text is present on the screen, right-click on that text then select verifytext in the the context menu you should see additional options that are from the IDE.
One of those should be verify text or assert text. Select that, when you then run your test case it will complete the login account and verify/assert that the Hi [username] text is on the page
open | www.gmail.com
type | id=username |usrename
type | id=password |password
Verifytext | HI[Username]|
The obvious answer is the fluent method:
driver.getSource().contains("a string");
Personally, I prefer using cssLocator to locate values:
if ( driver.findElement(myElement).getText().equalsIgnoreCase("my value") ) //do
Verify successful login through assertion. This is my code you can verify
WebElement useremail = driver.findElement(By.xpath("//input[#placeholder='Email']"));
WebElement password = driver.findElement(By.xpath("//input[#placeholder='Password']"));
WebElement login = driver.findElement(By.xpath("//a[#class='btn-signin']"));
useremail.sendKeys("abc#mailinator.com"); password.sendKeys("XXX");
login.click(); String actualurl="url";
String expectedurl= driver.getCurrentUrl();
Assert.assertEquals(expectedurl,actualurl);
You can use WebDriverWait of selenium.webdriver.support.ui to wait for login.
from selenium import webdriver
from selenium.webdriver.support import ui
wait = ui.WebDriverWait(driver, 60)
wait.until(lambda driver: driver.find_elements_by_tag_name('fieldset')) # there is also a until_not do the not condition
# do something after the login, if not login after 60 there will throw timeout exception