How to use Device Farm desktop browser session with Python - python-3.x

I'm trying to run a Selenium test in Python using Device Farm desktop browser session, but with the lack of resources (official or not), and my lack of knowledge, I can't figure it out.
I used these documentations:
https://docs.aws.amazon.com/devicefarm/latest/testgrid/getting-started-migration.html
https://selenium-python.readthedocs.io/getting-started.html#simple-usage
I installed the GeckoDriver, and ran the following code:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()
I saw a web browser appear for about a second.
I then decided to use Device Farm. I setup my AWS env vars, tested the connectivity, and ran the following code:
import boto3
import pytest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class test_url:
def setup_method(self, method):
devicefarm_client = boto3.client("devicefarm", region_name="eu-west-1")
testgrid_url_response = devicefarm_client.create_test_grid_url(
projectArn="arn:aws:devicefarm:us-west-2:1234567890:testgrid-project:some-id-string",
expiresInSeconds=300)
self.driver = webdriver.Remote(
"http://www.python.org", webdriver.DesiredCapabilities.FIREFOX)
# later, make sure to end your WebDriver session:
def teardown_method(self, method):
self.driver.quit()
Here's the result:
$ pytest -s
====================================================================================== test session starts =======================================================================================
platform linux -- Python 3.8.2, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /home/eric/nuage/devicefarm-poc
collected 0 items
===================================================================================== no tests ran in 0.07s ======================================================================================
I saw nothing happen in the AWS Management Console.
Why did no test run? Shouldn't this code perform an URL test? Shouldn't something happen in the AWS Management Console when I run this?

There appears to be a few issues with your code.
According to the pytest documentaion it seems like you need to put your tests into a file starting with the name test and to put your tests in methods starting with the word test as well. This is why none of your code is executing.
The line driver = webdriver.Firefox() tries to create a local firefox driver. What you want is a remote driver using the URL that AWS Device Farm provides (which you do at the line self.driver = webdriver.Remote("http://www.python.org", webdriver.DesiredCapabilities.FIREFOX)
The line self.driver = webdriver.Remote("http://www.python.org", webdriver.DesiredCapabilities.FIREFOX) is incorrect. The first argument is supposed to be the URL of the remote endpoint used to execute your tests. In this case, its AWS Device Farm's endpoint that is given in the CreateTestGridUrl API response. Selenium is basically just a REST service, so it performs actions via REST calls to an endpoint that tells the driver which actions to perform.
AWS Device Farm is currently only in us-west-2.
I suggest you go through the pytest, Selenium, and AWS docs again to understand how it all works together. Its not too complex, but it may get confusing if you do not know how all the working parts interact with each other.
Here's a "minimal" example with pytest to get you started.
import logging
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.keys import Keys
import boto3
import pytest
PROJECT_ARN = # Your project ARN
# Currently, AWS Device Farm is only in us-west-2
devicefarm = boto3.client('devicefarm', region_name='us-west-2')
remote_url = devicefarm.create_test_grid_url(
projectArn=PROJECT_ARN,
expiresInSeconds=600 # 10 minutes. Increase to longer if needed
)['url']
#pytest.fixture(scope="module") # Specify "module" to reuse the same session
def firefox_driver(request):
# Start fixture setup
logging.info("Creating a new session with remote URL: " + remote_url)
remote_web_driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=DesiredCapabilities.FIREFOX)
logging.info("Created the remote webdriver session: " + remote_web_driver.session_id)
yield remote_web_driver # Returns driver fixture and waits for tests to run
logging.info("Teardown the remote webdriver session: " + remote_web_driver.session_id)
remote_web_driver.quit()
logging.info("Done tearing down")
#pytest.mark.usefixtures("firefox_driver")
def test_search_in_python_org(firefox_driver):
driver = firefox_driver
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
# driver.close() // This is done in the fixture instead of here now
#pytest.mark.usefixtures("firefox_driver")
def test_aws_console_title(firefox_driver):
driver = firefox_driver
driver.get("https://aws.amazon.com/")
assert "Amazon Web Services" in driver.title
if __name__ == '__main__':
unittest.main()

Related

Unable to fetch web elements in pytest-bdd behave in python

So, I'm in the middle of creating a test-automation framework using pytest-bdd and behave in python 3.10.
I have some codes, but the thing is, I'm not able to fetch the web element from the portal. The error doesn't say anything about it. Here is the error I'm getting in the console.
Let me share the codes here too for better understanding.
demo.feature
Feature: Simple first feature
#test1
Scenario: Very first test scenario
Given Launch Chrome browser
When open my website
Then verify that the logo is present
And close the browser
test_demo.py
from behave import *
from selenium import webdriver
from selenium.webdriver.common.by import By
# from pytest_bdd import scenario, given, when, then
import time
import variables
import xpaths
from pages.functions import *
import chromedriver_autoinstaller
# #scenario('../features/demo.feature', 'Very first test scenario')
# def test_eventLog():
# pass
#given('Launch Chrome browser')
def given_launchBrowser(context):
launchWebDriver(context)
print("DEBUG >> Browser launches successfully.")
#when('Open my website')
def when_openSite(context):
context.driver.get(variables.link)
# context.driver.get(variables.nitsanon)
print("DEBUG >> Portal opened successfully.")
#then('verify that the logo is present')
def then_verifyLogo(context):
time.sleep(5)
status = context.driver.find_element(By.XPATH, xpaths.logo_xpath)
# status = findElement(context, xpaths.logo_xpath)
print('\n\n\n\n', status, '\n\n\n\n')
assert status is True, 'No logo present'
print("DEBUG >> Logo validated successfully.")
#then('close the browser')
def then_closeBrowser(context):
context.driver.close()
variables.py
link = 'https://nitin-kr.onrender.com/'
xpaths.py
logo_xpath = "//*[#id='logo']/div"
requirements.txt
behave~=1.2.6
selenium~=4.4.3
pytest~=7.1.3
pytest-bdd~=6.0.1
Let me know if you need any more information. I'm very eager to create an automation testing framework without any OOPs concept used.
Just the thing is, I'm not able to fetch the web elements. Not able to use find_element(By.XPATH, XPATH).send_keys(VALUE) like methods of selenium.

Why doesn't my Selenium session stay logged in?

I'm working on using selenium to sign into GitHub and create a repository. A similar project that I had found, after login used "https://github.com/new" to go to the repo creation page. However, when I try to do that, it returns to an empty login page with the following url: "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fnew".
I'm pretty lost and haven't found a good reason yet for why this would be happening.
PS. This is connected to a shell script, but the shell script is doing what it's supposed to so I didn't attach that code along with the Python that's being troublesome.
import sys
from selenium import webdriver
browser = webdriver.Safari()
def createProj():
folder_name = str(sys.argv[0])
browser.get("https://github.com/login")
try:
login_button = browser.find_elements_by_xpath("//*[#id='login_field']")[0]
login_button.click()
login_button.send_keys("Insert email here")
pass_button = browser.find_elements_by_xpath("//*[#id='password']")[0]
pass_button.click()
pass_button.send_keys("Insert password here")
submit_button = browser.find_elements_by_xpath("//*[#id='login']/form/div[4]/input[9]")[0]
submit_button.click()
except:
print("You're already signed in, no need to log in.")
browser.get("https://github.com/new")
if __name__ == "__main__":
createProj()

Is there a way to set a global variable to be used with aiortc?

I'm trying to have a python RTC client use a global variable so that I can reuse it for multiple functions.
I'm using this for a RTC project I¨ve been working on, I have a functioning js Client, but the functions work differently from python.
The functions on the server and js client side are my own, and do not have have parameters, and I hope to avoid having to use them on the python client I'm making.
I've been using the aiortc Cli.py from their github as a basis for how my python clien should work. But I don't run it asynchronous, because I am trying to learn and control when events happen.
the source code can be found here, I am referring to the codes in line 71-72
https://github.com/aiortc/aiortc/blob/master/examples/datachannel-cli/cli.py
this is the code I'm trying to run properly
I've only inserted the code relevant to my current issue
import argparse
import asyncio
import logging
import time
from aiortc import RTCIceCandidate, RTCPeerConnection, RTCSessionDescription
from aiortc.contrib.signaling import add_signaling_arguments, create_signaling
pc = None
channel = None
def createRTCPeer():
print("starting RTC Peer")
pc = RTCPeerConnection()
print("created Peer", pc)
return pc
def pythonCreateDataChannel():
print("creating datachannel")
channel = pc.CreateDataChannel("chat")
the createRTCPeer function works as intended, with it creating an RTC Object, but my pythonCreateDataChannel reports an error, if I have it set to "None" before using it
AttributeError: 'NoneType' object has no attribute 'CreateDataChannel'
and it will report
NameError: name 'channel' is not defined
same goes for pc if I don't set it in the global scope before hand
Have you tried this:
import argparse
import asyncio
import logging
import time
from aiortc import RTCIceCandidate, RTCPeerConnection, RTCSessionDescription
from aiortc.contrib.signaling import add_signaling_arguments, create_signaling
pc = None
channel = None
def createRTCPeer():
print("starting RTC Peer")
global pc
pc = RTCPeerConnection()
print("created Peer", pc)
def pythonCreateDataChannel():
print("creating datachannel")
global channel
channel = pc.CreateDataChannel("chat")

Selenium - Logging Into Facebook Causes Web Driver to Stall Indefinitely

I have a simple program that logs into Facebook and gets 3 urls:
def setup_driver():
prefs = {"profile.default_content_setting_values.notifications": 2}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("prefs", prefs)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
driver = webdriver.Chrome(executable_path="./chromedriver_linux",
chrome_options=chrome_options)
return driver
def log_into_facebook(driver):
driver.get("https://www.facebook.com/")
email_field = driver.find_element_by_id("email")
email_field.send_keys("<MY EMAIL ADDRESS>")
password_field = driver.find_element_by_id("pass")
password_field.send_keys("<MY FB PASSWORD>")
driver.find_element_by_id("loginbutton").click()
if __name__ == "__main__":
driver = setup_driver()
log_into_facebook(driver)
print("before getting url 1")
driver.get('https://facebook.com/2172111592857876')
print("before getting url 2")
#Stackoverflow is breaking indentation
driver.get('https://www.facebook.com/beaverconfessions/posts/2265225733546461')
print("before getting url 3")
driver.get('https://www.facebook.com/beaverconfessions/posts/640487179353666')
print("finished getting 3 urls")
On my local machine, this program runs fine. However, on my AWS EC2 instance, this program makes my instance unusable (the Python script will hang/stall after "before getting url 2" is printed to the console. While the script is hanging, the EC2 instance will become so slow that other programs on the instance will also stop working properly. I need to forcefully close the program with Ctrl-C in order for the instance to start being responsive again.). However, if I comment out log_into_facebook(driver), then the program runs fine.
I would try to get an stacktrace, but the program doesn't actually crash, rather it just never reaches "before getting url 3".
It is worth nothing, previously I was getting "invalid session id" errors with a program that was similar to this (it also logged into Facebook and then called driver.get several times).
Update: Removing the --no-sandbox option from the webdriver seemed to fix the problem. I'm not sure why. I originally had this option in place because I was previously having a "unable to fix open pages" error, and I read that "--no-sandbox" would fix the error.
chrome_options.add_argument('--no-sandbox')
Roymunson reports that the appropriate way to fix the hanging problem is:
Avoid specifying the --no-sandbox option in the webdriver.

Using stem to control Tor in python33

I am trying to use stem to have a small script run through Tor. I can't seem to get stem to work. Here is my code:
import urllib.request
import re
from stem.connection import connect_port
from stem import Signal
from stem.control import Controller
controller = connect_port(port=9151)
def change():
controller.authenticate()
controller.signal(Signal.NEWNYM)
def getIp():
print (urllib.request.urlopen("http://my-ip.heroku.com").read(30).decode('utf-8'))
def connectTor():
controller = connect_port(port=9151)
controller.connect()
getIp()
if not controller:
sys.exit(1)
print("nope")
def disconnect():
controller.close()
if __name__ == '__main__':
connectTor()
getIP()
change()
getIp()
disconnect()
Basically, all of the IPs that display are the same, when in theory, they should all be different. What can I do to make this code work?
To use Tor you need to direct traffic through its SocksPort (Tor acts as a local socks proxy). In your code above you don't have anything attempting to make urllib go through Tor.
For examples see Stem's client usage tutorials. I'm not sure offhand if SocksiPy or PycURL have Python 3.x counterparts. If not then you'll need to find an alternative.

Resources