Hello I did not found answer for similar problem so I add new topic.
I have problem with bdd + appium using a page object model. When I run my script I have issue:
Traceback (most recent call last):
File "/home/mimy/.local/lib/python3.8/site-packages/behave/model.py", line 1329, in run
match.run(runner.context)
File "/home/mimy/.local/lib/python3.8/site-packages/behave/matchers.py", line 98, in run
self.func(context, *args, **kwargs)
File "features/steps/allow_to_app_steps.py", line 6, in tap_allow_when_using_app
context.app.launch_page.tap_allow_button()
File "/home/mimy/.local/lib/python3.8/site-packages/behave/runner.py", line 321, in __getattr__
raise AttributeError(msg)
AttributeError: 'Context' object has no attribute 'app'
My environment.py file looks like this:
from appium import webdriver
from app.application import Application
def before_scenario(context, scenario):
desired_capabilities = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "Pixel 2 XL",
"appPackage": "com.xxx.xxx",
"appActivity": ".ui.MainActivity",
"automationName": "UiAutomator2"
}
context.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_capabilities=desired_capabilities)
context.driver.implicitly_wait(5)
context.app = Application(context.driver)
def after_scenario(context, scenario):
context.driver.quit()
My steps file looks like this:
from behave import given, when, then, step
#given('I click on the "Allow only while using the app" button')
def tap_allow_when_using_app(context):
context.app.launch_page.tap_allow_button()
#when('I click on the "Allow" button')
def tap_allow(context):
context.app.launch_page.tap_allow()
My pages file for my page object model looks like:
###LunchPage###
from selenium.webdriver.common.by import By
from pages.base_page import Page
class LaunchPage(Page):
dialog_title = (By.XPATH, "//android.widget.TextView[contains(#text,'Allow QSpot to access this device')]")
allow_only_while_using_the_app = (By.XPATH, "//android.widget.Button[#text='Allow only while using the app']")
allow = (By.XPATH, "//android.widget.Button[#text='Allow']")
def tap_allow_button(self):
self.click(*self.allow_only_while_using_the_app)
def tap_allow(self):
self.click(*self.allow)
###BasePage###
class Page:
def __init__(self, driver):
self.driver = driver
def find_element(self, *locator):
return self.driver.find_element(*locator)
def click(self, *locator):
e = self.find_element(*locator)
e.click()
And class Application
from pages.launch_page import LaunchPage
class Application:
def __init__(self, driver):
self.launch_page = LaunchPage(driver)
As I now this issue may be related with "driver was not starting" but I am not able to fix it.
Many thanks for help!
In my case, I missed up names in architecture names.
So after changing from "enviroment" to "environment" (missing N).
it became alive.
Related
Help me, I don't know how can I implement options in my oop code, I don't want browser pop up every time I run the code, I have to add headless option but I don't know how
I do know how to make my code headless in functional or imperative paradigm, but I can't figure out how to implement this in oop paradigm, whatever I do, I approach to an error, I don't know what to do, I would be extremely thankful to who guild me to light
my code
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import os
os.environ["PATH"] = "C:\\SeleniumWebDrivers"
op = webdriver.ChromeOptions()
op.add_argument("--disable-blink-features=AutomationControlled")
op.add_argument("headless")
class Avamovie(webdriver.Opera(options=op)):
def __init__(self, teardown=False):
self.teardown = teardown
super(Avamovie, self).__init__()
self.implicitly_wait(15)
self.maximize_window()
self.minimize_window()
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
if self.teardown:
self.quit()
def get_the_page(self):
self.get("https://avamovie17.xyz")
def search_box(self, title):
sbox = self.find_element_by_css_selector("input[placeholder='جستجو']")
sbox.send_keys(title)
sbox.click()
r = self.find_element_by_css_selector("ul[class='search_result_list']")
r = r.find_element_by_tag_name("li").find_element_by_css_selector(
"span[class='title']"
)
r.click()
def download_links(self):
links = self.find_elements_by_css_selector("a[href*='.mkv']")
links = [link.get_attribute("href") for link in links]
print(links)
with Avamovie() as scraper:
scraper.get_the_page()
scraper.search_box("A hero 2021")
scraper.download_links()
my latest error:
Traceback (most recent call last):
File "c:\Users\yasin\Desktop\pf\Projects\Selena\selena.py", line 1, in <module>
from sites.avamovie import Avamovie
File "c:\Users\yasin\Desktop\pf\Projects\Selena\sites\avamovie.py", line 10, in <module>
class Avamovie(webdriver.Opera(options=op)):
File "C:\Users\yasin\AppData\Roaming\Python\Python310\site-packages\selenium\webdriver\opera\webdriver.py", line 79, in __init__
OperaDriver.__init__(self, executable_path=executable_path,
File "C:\Users\yasin\AppData\Roaming\Python\Python310\site-packages\selenium\webdriver\opera\webdriver.py", line 55, in __init__
ChromiumDriver.__init__(self,
File "C:\Users\yasin\AppData\Roaming\Python\Python310\site-packages\selenium\webdriver\chrome\webdriver.py", line 73, in __init__
self.service.start()
File "C:\Users\yasin\AppData\Roaming\Python\Python310\site-packages\selenium\webdriver\common\service.py", line 71, in start
cmd.extend(self.command_line_args())
File "C:\Users\yasin\AppData\Roaming\Python\Python310\site-packages\selenium\webdriver\chrome\service.py", line 45, in command_line_args
return ["--port=%d" % self.port] + self.service_args
TypeError: %d format: a real number is required, not dict
I would appreciate any help, thanks guys
You appear to be trying to inherit from an instance of Opera, not the class itself. The options are passed to the call to super().__init__.
class Avamovie(webdriver.Opera):
def __init__(self, options, teardown=False):
self.teardown = teardown
super(Avamovie, self).__init__(options)
self.implicitly_wait(15)
self.maximize_window()
self.minimize_window()
...
with Avamovie(op) as scraper:
scraper.get_the_page()
scraper.search_box("A hero 2021")
scraper.download_links()
I made a class as the basic setup of the selenium driver. and I added methods to it. I want to access method of the class from a context manager I tried to create an object of the class in the context manager and access the method but I failed. how do I do it?
I even do not have any idea whats wrong in this code. please help me.
class SeleniumDriver:
'''basic setup for chromedriver(selenium)'''
def __init__(self,
driversource='C:\\Users\Ewis\Downloads\chromedriver.exe',
url = ('https://realpython.com/')
):
self.driversource = driversource
self.url = url # this tuple
def __enter__(self):
self.driver = webdriver.Chrome(executable_path=self.driversource)
for urls in self.url:
self.driver.get(urls)
return self.driver, Keys
def __exit__(self, exc_type, exc_val, exc_trace):
self.driver.quit()
# and this code(another project)
from seleniumdriver import SeleniumDriver
with SeleniumDriver() as packed:
seldriver1 = SeleniumDriver()
driver = packed[0]
urls = ('https://realpython.com/','https://stackoverflow.com/')
resp = seldriver1.geturl(urls)
for url in resp:
title, url = resp.titleurl()
print(title, '\n', url,'\n')
Error :
Traceback (most recent call last):
File "C:\python\progs\web\selenium\navigation_commands\navigation_commands.py", line 9, in
for url in resp:
File "c:\python\progs\my_modules\seleniumdriver\seleniumdriver.py", line 22, in geturl
yield (self.driver).get(url)
AttributeError: 'SeleniumDriver' object has no attribute 'driver'
I'm not sure if it is enough to resolve all problems but:
You have to use packed[0] which is created using with and it executes __enter__ which creates self.driver
resp = packed[0].geturl(urls)
But you use seldriver1 which is created using seldriver1 = SeleniumDriver() which doesn't execute __enter__ so it doesn't create self.driver (seldriver1.driver) and you get error:
'SeleniumDriver' object has no attribute 'driver'
from seleniumdriver import SeleniumDriver
with SeleniumDriver() as packed:
urls = ('https://realpython.com/','https://stackoverflow.com/')
resp = packed[0].geturl(urls)
for url in resp:
title, url = resp.titleurl()
print(title, '\n', url,'\n')
Your code seems weird for me and it may need much more changes to work correctly.
EDIT: this code works for me.
Because I use Firefox on Linux and I don't have to set driversource so I added None to run without driversource
I removed get(url) from __enter__ because it is useless. You can't get two pages in __enter__ and use them later in for loop because Selenium doesn't keep information about first page when you open second page.
from selenium import webdriver
class SeleniumDriver:
'''basic setup for chromedriver(selenium)'''
def __init__(self, driversource='C:\\Users\Ewis\Downloads\chromedriver.exe'):
self.driversource = driversource
def __enter__(self):
if self.driversource:
#self.driver = webdriver.Chrome(executable_path=self.driversource)
self.driver = webdriver.Firefox(executable_path=self.driversource)
else:
#self.driver = webdriver.Chrome()
self.driver = webdriver.Firefox()
return self.driver
def __exit__(self, exc_type, exc_val, exc_trace):
self.driver.quit()
with SeleniumDriver(None) as driver:
urls = ('https://realpython.com/', 'https://stackoverflow.com/')
for url in urls:
driver.get(url)
title = driver.title
print(title, '\n', url,'\n')
*args unpacks the locators in tuple form.but is my case i have given only two arguments,but it is taking three arguments.Need help to understand.
I am newbie to selenium with python and played around some code from github,
but getting error.
TypeError: find_element_by_xpath() takes 2 positional arguments but 3 were given
locator.py
from selenium.webdriver.common.by import By
class elements(object):
Customer = (By.XPATH, "//button[contains(text(),'Customer')]")
base.py
from selenium import webdriver
from selenium.webdriver.common.by import By
class Page(object):
def __init__(self,driver,url=None):
self.url = url
self.driver = driver
def find_element_with_click(self,*locator):
self.driver.find_element_by_xpath(*locator).click()
pages.py
from selenium import webdriver
from base import Page
from locator import *
class CustomerCreation(Page):
def __init__(self, driver):
self.locator = elements
super().__init__(driver)
def create_customer(self):
self.driver.find_element_with_click(*self.locator.Customer)
testPages.py
import unittest
from selenium import webdriver
from pages import *
from locators import *
from selenium.webdriver.common.by import By
class TestPages(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome('C:\ChromeDriver\chromedriver')
cls.driver.get("#server")
def test_tes_cust(self):
page = CustomerCreation(self.driver)
res_page = page.create_customer() #Getting issue at this stage
#classmethod
def tearDownClass(cls):
cls.driver.close()
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(TestPages)
unittest.TextTestRunner(verbosity=2).run(suite)
The error log:
test_tes_cust (main.TestPages) ... ERROR
======================================================================
ERROR: test_tes_cust (main.TestPages)
----------------------------------------------------------------------
Traceback (most recent call last):
File "testPages.py", line 28, in test_tes_cust
res_page = page.create_customer()
File "C:\Users###\PycharmProjects\basics\pages.py", line 35, in create_customer
self.find_element_with_click(*self.locator.Customer)
File "C:\Users###\PycharmProjects\basics\base.py", line 21, in find_element_with_click
self.driver.find_element_by_xpath(*locator).click()
TypeError: find_element_by_xpath() takes 2 positional arguments but 3 were given
You're passing one extra argument. Your arguments are:
self
By.XPATH
"//button[contains(text(),'Customer')]"
That's what you need to pass to find_element method. While find_element_by_xpath should take two arguments only:
self
"//button[contains(text(),'Customer')]"
So try to update your code as
def find_element_with_click(self,*locator):
self.driver.find_element(*locator).click()
or you need to modify your Customer as:
Customer = "//button[contains(text(),'Customer')]"
and
def find_element_with_click(self, xpath):
self.driver.find_element_by_xpath(xpath).click()
I'm building a custom class to add feautures to selenium.webdriver.Chrome on Python 3.6.2.
from selenium import webdriver
class MyChrome:
def __init__(self):
self.mydriver = webdriver.Chrome()
So far, beside some custom methods I made myself, I used to overridden some selenium.webdriver.Chrome very standard methods like this:
def get(self, url):
self.mydriver.get(url)
Since I don't want to waste time rewriting like that methods like get, find_element_by_xpath, etc... that already works fine for me I tried the following, as suggested here and here
def __getattr__(self, name, *args, **kwargs):
return getattr(self.mydriver, name)(*args, **kwargs)
But when I run the following code
from selenium import webdriver
class MyChrome:
def __init__(self):
self.mydriver = webdriver.Chrome()
def __getattr__(self, name, *args, **kwargs):
return getattr(self.mydriver, name)(*args, **kwargs)
chrome = MyChrome()
chrome.get('https://stackoverflow.com/')
I encounter the error
Traceback (most recent call last):
File "MyChrome.py", line 11, in <module>
chrome.get('https://stackoverflow.com/')
File "MyChrome.py", line 8, in __getattr__
return getattr(self.mydriver, name)(*args, **kwargs)
TypeError: get() missing 1 required positional argument: 'url'
How do I redirect calls to unknown methods called on my object chrome to it's instance variable self.driver?
I created a custom Webdriver once to add features to selenium Chrome Webdriver and I did that by subclassing selenium Chrome Webdriver. This way you inherit all the webdriver methods without a getattr
from selenium.webdriver import Chrome
class MyChrome(Chrome):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# add all your custom features
It doesn't provide answer to your question but something you can leverage
I'm trying to subclass the Chrome WebDriver to include some initialization and cleanup code, but then Python complains that the created object is set to None:
import glob
import selenium
import subprocess
from selenium.webdriver.common.by import By
class WebDriver(selenium.webdriver.Chrome):
def __init__(self, url, *args, **kwargs):
super().__init__(*args, **kwargs)
self.url = url
def __enter__(self):
self.get(self.url)
self.implicitly_wait(15)
def __exit__(self, type, value, traceback):
self.quit()
for path in glob.glob('/tmp/.org.chromium.Chromium.*'):
subprocess.run(['rm', '-rf', path], check=True)
with WebDriver('https://google.com') as driver:
driver.find_element(By.ID, 'lst-ib').send_keys('Search')
Running the code with Python 3:
$ python3 test.py
Traceback (most recent call last):
File "test.py", line 43, in <module>
driver.find_element(By.ID, 'lst-ib').send_keys('Search')
AttributeError: 'NoneType' object has no attribute 'find_element'
Your __enter__() magic method should return self for the driver variable to be pointed to the instance of the WebDriver class:
def __enter__(self):
self.get(self.url)
self.implicitly_wait(15)
return self
To get more information about why and how this works, please see:
Understanding Python's "with" statement
Explaining Python's '__enter__' and '__exit__'