Closed bitsByB closed 7 months ago
It looks like you overwrote seleniumbase
by naming your file seleniumbase.py
:
/home/bangbuild/Documents/dev/cucumber/seleniumbase.py
Don't name your Python files with the same name as your import libraries!
Also, here's a newer example that uses uc_open_with_reconnect
(which lets you customize the reconnect time, and starts with a newer tab for better anti-detection):
from seleniumbase import Driver
driver = Driver(uc=True)
try:
driver.uc_open_with_reconnect("https://top.gg/", 6)
finally:
driver.quit()
aha! great, thanks a lot @mdmintz very cool! Everything works but I don't see chrome opening right? Michael while I have your attention, what's your favorite resource to point to to learn about this technology ? (besides seleniumbase docs of course ;) cheers
"Everything works"
... Great! So what do you mean by "I don't see chrome opening"
?
For SeleniumBase UC Mode, here are the docs: help_docs/uc_mode.md
There's also the video: https://www.youtube.com/watch?v=5dMFI3e85ig
A newer video is coming soon.
@mdmintz found the --gui
option (i'm on linux).
Yes I'm watching the video right now, it's how I discovered seleniumbase.
I'm digging into the doc as well and your other videos.
It's really cool what you have done here! thank you
@mdmintz, I see in your doc you talk about behave and not about cucumber... why this choice? what's your take on that?
behave
is a Python implementation of the Gherkin syntax for BDD.
Cucumber is a generic implementation of the Gherkin syntax for BDD.
SeleniumBase utilizes the behave
version by adding specific code around browser automation:
SeleniumBase/examples/behave_bdd
You can also generate behave
scripts from existing tests: pytest --rec-behave
Or use the Recorder to generate behave
scripts: sbase recorder --behave
Thanks for the explanation! man I really appreciate you taking the time :) Watching the selenium conf, pretty cool Michael
Thank you! GitHub Stars are always appreciated. ⭐
aha! of course, done!
One last question and I stop bothering you for today! How can I combine the updated code you gave me at the beginning which avoid to be blocked with this other piece I'm working on:
from seleniumbase import Driver
driver = Driver(uc=True)
try:
driver.uc_open_with_reconnect("https://engage.metmuseum.org/account/login/", 6)
print(driver.title)
finally:
driver.quit()
when I run this by itself I'm being blocked on the second page...
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class MyTestClass(BaseCase):
def test_met_signin(self):
self.open("https://www.metmuseum.org/")
self.click(".masthead__membership")
self.assert_exact_text("Join/Renew", "p.button")
self.click("button#Member_with_Early_Views_0")
thanks!
Like this:
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__, "--uc", "-s")
class MyTestClass(BaseCase):
def test_met_signin(self):
if not self.undetectable:
self.get_new_driver(undetectable=True)
self.driver.uc_open_with_reconnect("https://www.metmuseum.org/", 2)
self.click("a.masthead__membership")
self.assert_exact_text("Join/Renew", "button#Member_with_Early_Views_0")
self.click("button#Member_with_Early_Views_0")
breakpoint()
If you run it with python
, it will automatically use pytest --uc
. If you run it with pytest
without the --uc
, then the line with get_new_driver
will correct it.
Also, I didn't encounter any CAPTCHAs on that site. Maybe they happen later, but if they don't happen at all, then UC Mode wouldn't be needed.
Amazing!! thanks so much Michael! have a great one :) I was getting this message:
This thing is so intuitive! Everything works perfectly for a proof of concept!
"""A complete end-to-end test for a membership recurring customer."""
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__, "--uc", "-s")
class MyTestClass(BaseCase):
def test_recurring_custommer_wrong_login(self):
if not self.undetectable:
self.get_new_driver(undetectable=True)
self.driver.uc_open_with_reconnect("https://www.metmuseum.org/", 2)
self.click("a.masthead__membership")
self.assert_exact_text("Join/Renew", "button#Member_with_Early_Views_0")
self.click("button#Member_with_Early_Views_0")
self.assert_exact_text("Log in", "button.btn-primary")
self.type("#LoginRequest_Username", "john@doe.com")
self.type("#LoginRequest_Password", "fromAMNHwithL@ve")
self.click("button.btn-primary")
breakpoint()
How could I link that with Behave and produce a Gherkin .feature file? It's the way around usually right?
Have you tried running any of the examples in the examples/behave_bdd/features folder, such as examples/behave_bdd/features/realworld.feature yet? If you haven't, clone SeleniumBase from GitHub and try some of those examples:
> behave realworld.feature
Feature: SeleniumBase scenarios for the RealWorld App # realworld.feature:1
Scenario: Verify RealWorld App (log in / sign out) # realworld.feature:3
Given Open "seleniumbase.io/realworld/login" # ../../../sbase/steps.py:10
And Clear Session Storage # ../../../sbase/steps.py:669
When Type "demo_user" into "#username" # ../../../sbase/steps.py:40
And Type "secret_pass" into "#password" # ../../../sbase/steps.py:40
And Do MFA "GAXG2MTEOR3DMMDG" into "#totpcode" # ../../../sbase/steps.py:322
Then Assert exact text "Welcome!" in "h1" # ../../../sbase/steps.py:157
And Highlight "img#image1" # ../../../sbase/steps.py:184
And Click 'a:contains("This Page")' # ../../../sbase/steps.py:27
And Save screenshot to logs # ../../../sbase/steps.py:239
When Click link "Sign out" # ../../../sbase/steps.py:195
Then Assert element 'a:contains("Sign in")' # ../../../sbase/steps.py:120
And Assert text "You have been signed out!" # ../../../sbase/steps.py:145
✅ Scenario Passed!
It can't handle UC Mode yet though, but it can handle any other SeleniumBase actions.
I'm on it. If I'm able to pull that off and get the job I owe you big time Michael!
How could I target:
<div class="error-summary validation-summary-errors">
self.assert_exact_text
to have the warning highlighted? from seleniumbase import BaseCase
BaseCase.main(__name__, __file__, "--uc", "-s")
class MyTestClass(BaseCase):
def test_met_signin(self):
if not self.undetectable:
self.get_new_driver(undetectable=True)
self.driver.uc_open_with_reconnect("https://www.metmuseum.org/", 2)
self.click("a.masthead__membership")
self.assert_exact_text("Join/Renew", "button#Member_with_Early_Views_0")
self.click("button#Member_with_Early_Views_0")
self.assert_exact_text("Email", "div.form-item")
self.type("#LoginRequest_Username", "john@doe.com")
# self.assert_exact_text("Password", "div.form-item")
self.type("#LoginRequest_Password", "fromAMNHwithL@ve")
self.click("button.btn-primary")
self.assert_exact_text("We couldn't find an account with this email address and password combination. Please check your information and try again. If you forgot your password click on ", "div.error-summary validation-summary-errors")
# self.assert_true(self.is_element_visible(".text-utility"))
breakpoint()
I managed to do it in the previous line of code but I find no "grip" on this one... Also I couldn't find in the doc how to add a sleep of 5 seconds at the end before to close the browser. Thanks
There's a lot of text under <div class="error-summary validation-summary-errors">
, so instead of trying to assert all of it with assert_exact_text()
, you could do assert_text()
instead for a substring match:
self.assert_text("Please check your information and try again.", "div.validation-summary-errors")
You mentioned something about having "the warning highlighted"? Do you mean --demo
mode? That inserts JavaScript into the page, which can make you detected. You can also do self.activate_demo_mode()
to activate Demo Mode in the middle of a test.
For the 5-second sleep at the end, just add: self.sleep(5)
That's PERFEEECT! So cool, thanks a lot! Still struggling with the behave files but will share with you when I'm stuck :)
Morning Michael,
I can tick that box by either clicking inside the square or the Non-Residents
text
But it has this weird state of ::before
and ::after
(I have noticed it's always complicated when those guys are in the mix and I didn't find anything about it in the docs)
I'm trying a whole bunch of ways of clicking it but nothing works. (self.click("#check_other")
doesn't work for example)
Could you suggest something? Thank you
If that element is in an iframe, you'll need to switch into the iframe first. When you say it doesn't work
, I need more details, such as what the error message says.
I'm not yet familiar with iframe but I don't see any iframe tags in the devtool. https://tickets.amnh.org/select
python3 demo-amnh.py --demo --gui
=============================== test session starts ================================
platform linux -- Python 3.10.12, pytest-8.0.2, pluggy-1.4.0
rootdir: /home/bangbuild/Documents/dev/Python/seleniumbase
plugins: xdist-3.5.0, rerunfailures-13.0, ordering-0.6, metadata-3.1.1, html-2.0.1, seleniumbase-4.24.2
collected 1 item
demo-amnh.py F
===================================== FAILURES =====================================
______________________ MyTestClass.test_purchase_ticket_guest ______________________
self = <demo-amnh.MyTestClass testMethod=test_purchase_ticket_guest>
def test_purchase_ticket_guest(self):
if not self.undetectable:
self.get_new_driver(undetectable=True)
self.driver.uc_open_with_reconnect("https://tickets.amnh.org/select", 2)
> self.click("div#check_other")
demo-amnh.py:11:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/base_case.py:409: in click
element = page_actions.wait_for_element_visible(
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/page_actions.py:508: in wait_for_element_visible
timeout_exception(NoSuchElementException, message)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exception = <class 'selenium.common.exceptions.NoSuchElementException'>
message = 'Element {div#check_other} was not present after 7 seconds!'
def timeout_exception(exception, message):
exc, msg = shared_utils.format_exc(exception, message)
> raise exc(msg)
E seleniumbase.common.exceptions.NoSuchElementException: Message:
E Element {div#check_other} was not present after 7 seconds!
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/page_actions.py:266: NoSuchElementException
- Latest Logs dir: /home/bangbuild/Documents/dev/Python/seleniumbase/latest_logs/ --
============================= short test summary info ==============================
FAILED demo-amnh.py::MyTestClass::test_purchase_ticket_guest - seleniumbase.common.exceptions.NoSuchElementException: Message:
================================ 1 failed in 11.29s ================================
You changed the selector you used between the first time you posted and just now. Show me the error message that appears when you just use #check_other
. (It's the ID of the input
field, not the div
)
python3 demo-amnh.py --demo --gui
================== test session starts ==================
platform linux -- Python 3.10.12, pytest-8.0.2, pluggy-1.4.0
rootdir: /home/bangbuild/Documents/dev/Python/seleniumbase
plugins: xdist-3.5.0, rerunfailures-13.0, ordering-0.6, metadata-3.1.1, html-2.0.1, seleniumbase-4.24.2
collected 1 item
demo-amnh.py F
======================= FAILURES ========================
________ MyTestClass.test_purchase_ticket_guest _________
self = <demo-amnh.MyTestClass testMethod=test_purchase_ticket_guest>
def test_purchase_ticket_guest(self):
if not self.undetectable:
self.get_new_driver(undetectable=True)
self.driver.uc_open_with_reconnect("https://tickets.amnh.org/select", 2)
> self.click("#check_other")
demo-amnh.py:11:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/base_case.py:409: in click
element = page_actions.wait_for_element_visible(
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/page_actions.py:515: in wait_for_element_visible
timeout_exception(ElementNotVisibleException, message)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exception = <class 'selenium.common.exceptions.ElementNotVisibleException'>
message = 'Element {#check_other} was not visible after 7 seconds!'
def timeout_exception(exception, message):
exc, msg = shared_utils.format_exc(exception, message)
> raise exc(msg)
E seleniumbase.common.exceptions.ElementNotVisibleException: Message:
E Element {#check_other} was not visible after 7 seconds!
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/page_actions.py:266: ElementNotVisibleException
- Latest Logs dir: /home/bangbuild/Documents/dev/Python/seleniumbase/latest_logs/ -
================ short test summary info ================
FAILED demo-amnh.py::MyTestClass::test_purchase_ticket_guest - seleniumbase.common.exceptions.ElementNotVisibleExce...
================== 1 failed in 10.50s ===================
self.click("input#check_other")
doesn't work neither
That helps. Try self.js_click("input#check_other")
Let's go! that did the trick!
What is the difference between this and the simple .click
?
Being able to access those ::before
and ::after
state?
js_click(selector)
lets you click on "hidden" elements. From your error message, it said ElementNotVisibleException
, which is different from NoSuchElementException
.
I see, thank you so much Michael for your time, I really appreciate your help on this one! I just discovered the recorder! I should be able to bother you way less ;) I watched the video about it and I'm ready to use it but I'm getting this code and the browser window and SeleniumBase recorder App don't pop up...? (it hangs there until I press c + return) How can I have this working? Thanks
[33] > /home/bangbuild/Documents/dev/Python/seleniumbase/TEST_NAME.py(9)
.
5 def test_recording(self):
6 if self.recorder_ext:
7 # When done recording actions,
8 # type "c", and press [Enter].
9 -> import pdb; pdb.set_trace()
return None
(Pdb+)
it gives me those errors:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB continue >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
F
====================================================================================== FAILURES ======================================================================================
____________________________________________________________________________ RecorderTest.test_recording _____________________________________________________________________________
self = <urllib3.connection.HTTPConnection object at 0x7f6046fe4790>
def _new_conn(self) -> socket.socket:
"""Establish a socket connection and set nodelay settings on it.
:return: New socket connection.
"""
try:
> sock = connection.create_connection(
(self._dns_host, self.port),
self.timeout,
source_address=self.source_address,
socket_options=self.socket_options,
)
../../../../.local/lib/python3.10/site-packages/urllib3/connection.py:198:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.local/lib/python3.10/site-packages/urllib3/util/connection.py:85: in create_connection
raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
address = ('localhost', 50825), timeout = None, source_address = None, socket_options = [(6, 1, 1)]
def create_connection(
address: tuple[str, int],
timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
source_address: tuple[str, int] | None = None,
socket_options: _TYPE_SOCKET_OPTIONS | None = None,
) -> socket.socket:
"""Connect to *address* and return the socket object.
Convenience function. Connect to *address* (a 2-tuple ``(host,
port)``) and return the socket object. Passing the optional
*timeout* parameter will set the timeout on the socket instance
before attempting to connect. If no *timeout* is supplied, the
global default timeout setting returned by :func:`socket.getdefaulttimeout`
is used. If *source_address* is set it must be a tuple of (host, port)
for the socket to bind as a source address before making the connection.
An host of '' or port 0 tells the OS to use the default.
"""
host, port = address
if host.startswith("["):
host = host.strip("[]")
err = None
# Using the value from allowed_gai_family() in the context of getaddrinfo lets
# us select whether to work with IPv4 DNS records, IPv6 records, or both.
# The original create_connection function always returns all records.
family = allowed_gai_family()
try:
host.encode("idna")
except UnicodeError:
raise LocationParseError(f"'{host}', label empty or too long") from None
for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
sock = None
try:
sock = socket.socket(af, socktype, proto)
# If provided, set socket level options before connecting.
_set_socket_options(sock, socket_options)
if timeout is not _DEFAULT_TIMEOUT:
sock.settimeout(timeout)
if source_address:
sock.bind(source_address)
> sock.connect(sa)
E ConnectionRefusedError: [Errno 111] Connection refused
../../../../.local/lib/python3.10/site-packages/urllib3/util/connection.py:73: ConnectionRefusedError
The above exception was the direct cause of the following exception:
self = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f6048b40490>, method = 'GET', url = '/session/fb8201d3d37ec55e388d6392adb794ed/window/handles', body = None
headers = {'Accept': 'application/json', 'Connection': 'keep-alive', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'selenium/4.18.1 (python linux)'}
retries = Retry(total=0, connect=None, read=None, redirect=None, status=None), redirect = False, assert_same_host = False, timeout = <_TYPE_DEFAULT.token: -1>, pool_timeout = None
release_conn = True, chunked = False, body_pos = None, preload_content = True, decode_content = True, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/session/fb8201d3d37ec55e388d6392adb794ed/window/handles', query=None, fragment=None), destination_scheme = None
conn = None, release_this_conn = True, http_tunnel_required = False, err = None, clean_exit = False
def urlopen( # type: ignore[override]
self,
method: str,
url: str,
body: _TYPE_BODY | None = None,
headers: typing.Mapping[str, str] | None = None,
retries: Retry | bool | int | None = None,
redirect: bool = True,
assert_same_host: bool = True,
timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
pool_timeout: int | None = None,
release_conn: bool | None = None,
chunked: bool = False,
body_pos: _TYPE_BODY_POSITION | None = None,
preload_content: bool = True,
decode_content: bool = True,
**response_kw: typing.Any,
) -> BaseHTTPResponse:
"""
Get a connection from the pool and perform an HTTP request. This is the
lowest level call for making a request, so you'll need to specify all
the raw details.
.. note::
More commonly, it's appropriate to use a convenience method
such as :meth:`request`.
.. note::
`release_conn` will only behave as expected if
`preload_content=False` because we want to make
`preload_content=False` the default behaviour someday soon without
breaking backwards compatibility.
:param method:
HTTP request method (such as GET, POST, PUT, etc.)
:param url:
The URL to perform the request on.
:param body:
Data to send in the request body, either :class:`str`, :class:`bytes`,
an iterable of :class:`str`/:class:`bytes`, or a file-like object.
:param headers:
Dictionary of custom headers to send, such as User-Agent,
If-None-Match, etc. If None, pool headers are used. If provided,
these headers completely replace any pool-specific headers.
:param retries:
Configure the number of retries to allow before raising a
:class:`~urllib3.exceptions.MaxRetryError` exception.
If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a
:class:`~urllib3.util.retry.Retry` object for fine-grained control
over different types of retries.
Pass an integer number to retry connection errors that many times,
but no other types of errors. Pass zero to never retry.
If ``False``, then retries are disabled and any exception is raised
immediately. Also, instead of raising a MaxRetryError on redirects,
the redirect response will be returned.
:type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
:param redirect:
If True, automatically handle redirects (status codes 301, 302,
303, 307, 308). Each redirect counts as a retry. Disabling retries
will disable redirect, too.
:param assert_same_host:
If ``True``, will make sure that the host of the pool requests is
consistent else will raise HostChangedError. When ``False``, you can
use the pool on an HTTP proxy and request foreign hosts.
:param timeout:
If specified, overrides the default timeout for this one
request. It may be a float (in seconds) or an instance of
:class:`urllib3.util.Timeout`.
:param pool_timeout:
If set and the pool is set to block=True, then this method will
block for ``pool_timeout`` seconds and raise EmptyPoolError if no
connection is available within the time period.
:param bool preload_content:
If True, the response's body will be preloaded into memory.
:param bool decode_content:
If True, will attempt to decode the body based on the
'content-encoding' header.
:param release_conn:
If False, then the urlopen call will not release the connection
back into the pool once a response is received (but will release if
you read the entire contents of the response such as when
`preload_content=True`). This is useful if you're not preloading
the response's content immediately. You will need to call
``r.release_conn()`` on the response ``r`` to return the connection
back into the pool. If None, it takes the value of ``preload_content``
which defaults to ``True``.
:param bool chunked:
If True, urllib3 will send the body using chunked transfer
encoding. Otherwise, urllib3 will send the body using the standard
content-length form. Defaults to False.
:param int body_pos:
Position to seek to in file-like body in the event of a retry or
redirect. Typically this won't need to be set because urllib3 will
auto-populate the value when needed.
"""
parsed_url = parse_url(url)
destination_scheme = parsed_url.scheme
if headers is None:
headers = self.headers
if not isinstance(retries, Retry):
retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
if release_conn is None:
release_conn = preload_content
# Check host
if assert_same_host and not self.is_same_host(url):
raise HostChangedError(self, url, retries)
# Ensure that the URL we're connecting to is properly encoded
if url.startswith("/"):
url = to_str(_encode_target(url))
else:
url = to_str(parsed_url.url)
conn = None
# Track whether `conn` needs to be released before
# returning/raising/recursing. Update this variable if necessary, and
# leave `release_conn` constant throughout the function. That way, if
# the function recurses, the original value of `release_conn` will be
# passed down into the recursive call, and its value will be respected.
#
# See issue #651 [1] for details.
#
# [1] <https://github.com/urllib3/urllib3/issues/651>
release_this_conn = release_conn
http_tunnel_required = connection_requires_http_tunnel(
self.proxy, self.proxy_config, destination_scheme
)
# Merge the proxy headers. Only done when not using HTTP CONNECT. We
# have to copy the headers dict so we can safely change it without those
# changes being reflected in anyone else's copy.
if not http_tunnel_required:
headers = headers.copy() # type: ignore[attr-defined]
headers.update(self.proxy_headers) # type: ignore[union-attr]
# Must keep the exception bound to a separate variable or else Python 3
# complains about UnboundLocalError.
err = None
# Keep track of whether we cleanly exited the except block. This
# ensures we do proper cleanup in finally.
clean_exit = False
# Rewind body position, if needed. Record current position
# for future rewinds in the event of a redirect/retry.
body_pos = set_file_position(body, body_pos)
try:
# Request a connection from the queue.
timeout_obj = self._get_timeout(timeout)
conn = self._get_conn(timeout=pool_timeout)
conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment]
# Is this a closed/new connection that requires CONNECT tunnelling?
if self.proxy is not None and http_tunnel_required and conn.is_closed:
try:
self._prepare_proxy(conn)
except (BaseSSLError, OSError, SocketTimeout) as e:
self._raise_timeout(
err=e, url=self.proxy.url, timeout_value=conn.timeout
)
raise
# If we're going to release the connection in ``finally:``, then
# the response doesn't need to know about the connection. Otherwise
# it will also try to release it and we'll have a double-release
# mess.
response_conn = conn if not release_conn else None
# Make the request on the HTTPConnection object
> response = self._make_request(
conn,
method,
url,
timeout=timeout_obj,
body=body,
headers=headers,
chunked=chunked,
retries=retries,
response_conn=response_conn,
preload_content=preload_content,
decode_content=decode_content,
**response_kw,
)
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:793:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:496: in _make_request
conn.request(
../../../../.local/lib/python3.10/site-packages/urllib3/connection.py:400: in request
self.endheaders()
/usr/lib/python3.10/http/client.py:1278: in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
/usr/lib/python3.10/http/client.py:1038: in _send_output
self.send(msg)
/usr/lib/python3.10/http/client.py:976: in send
self.connect()
../../../../.local/lib/python3.10/site-packages/urllib3/connection.py:238: in connect
self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <urllib3.connection.HTTPConnection object at 0x7f6046fe4790>
def _new_conn(self) -> socket.socket:
"""Establish a socket connection and set nodelay settings on it.
:return: New socket connection.
"""
try:
sock = connection.create_connection(
(self._dns_host, self.port),
self.timeout,
source_address=self.source_address,
socket_options=self.socket_options,
)
except socket.gaierror as e:
raise NameResolutionError(self.host, self, e) from e
except SocketTimeout as e:
raise ConnectTimeoutError(
self,
f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
) from e
except OSError as e:
> raise NewConnectionError(
self, f"Failed to establish a new connection: {e}"
) from e
E urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7f6046fe4790>: Failed to establish a new connection: [Errno 111] Connection refused
../../../../.local/lib/python3.10/site-packages/urllib3/connection.py:213: NewConnectionError
The above exception was the direct cause of the following exception:
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/base_case.py:15718: in tearDown
self.__process_recorded_actions()
../../../../.local/lib/python3.10/site-packages/seleniumbase/fixtures/base_case.py:4579: in __process_recorded_actions
for window in self.driver.window_handles:
../../../../.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py:494: in window_handles
return self.execute(Command.W3C_GET_WINDOW_HANDLES)["value"]
../../../../.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py:345: in execute
response = self.command_executor.execute(driver_command, params)
../../../../.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py:302: in execute
return self._request(command_info[0], url, body=data)
../../../../.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py:322: in _request
response = self._conn.request(method, url, body=body, headers=headers)
../../../../.local/lib/python3.10/site-packages/urllib3/_request_methods.py:136: in request
return self.request_encode_url(
../../../../.local/lib/python3.10/site-packages/urllib3/_request_methods.py:183: in request_encode_url
return self.urlopen(method, url, **extra_kw)
../../../../.local/lib/python3.10/site-packages/urllib3/poolmanager.py:444: in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:877: in urlopen
return self.urlopen(
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:877: in urlopen
return self.urlopen(
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:877: in urlopen
return self.urlopen(
../../../../.local/lib/python3.10/site-packages/urllib3/connectionpool.py:847: in urlopen
retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Retry(total=0, connect=None, read=None, redirect=None, status=None), method = 'GET', url = '/session/fb8201d3d37ec55e388d6392adb794ed/window/handles', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f6046fe4790>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f6048b40490>, _stacktrace = <traceback object at 0x7f6046e2d2c0>
def increment(
self,
method: str | None = None,
url: str | None = None,
response: BaseHTTPResponse | None = None,
error: Exception | None = None,
_pool: ConnectionPool | None = None,
_stacktrace: TracebackType | None = None,
) -> Retry:
"""Return a new Retry object with incremented retry counters.
:param response: A response object, or None, if the server did not
return a response.
:type response: :class:`~urllib3.response.BaseHTTPResponse`
:param Exception error: An error encountered during the request, or
None if the response was received successfully.
:return: A new ``Retry`` object.
"""
if self.total is False and error:
# Disabled, indicate to re-raise the error.
raise reraise(type(error), error, _stacktrace)
total = self.total
if total is not None:
total -= 1
connect = self.connect
read = self.read
redirect = self.redirect
status_count = self.status
other = self.other
cause = "unknown"
status = None
redirect_location = None
if error and self._is_connection_error(error):
# Connect retry?
if connect is False:
raise reraise(type(error), error, _stacktrace)
elif connect is not None:
connect -= 1
elif error and self._is_read_error(error):
# Read retry?
if read is False or method is None or not self._is_method_retryable(method):
raise reraise(type(error), error, _stacktrace)
elif read is not None:
read -= 1
elif error:
# Other retry?
if other is not None:
other -= 1
elif response and response.get_redirect_location():
# Redirect retry?
if redirect is not None:
redirect -= 1
cause = "too many redirects"
response_redirect_location = response.get_redirect_location()
if response_redirect_location:
redirect_location = response_redirect_location
status = response.status
else:
# Incrementing because of a server error like a 500 in
# status_forcelist and the given method is in the allowed_methods
cause = ResponseError.GENERIC_ERROR
if response and response.status:
if status_count is not None:
status_count -= 1
cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)
status = response.status
history = self.history + (
RequestHistory(method, url, error, status, redirect_location),
)
new_retry = self.new(
total=total,
connect=connect,
read=read,
redirect=redirect,
status=status_count,
other=other,
history=history,
)
if new_retry.is_exhausted():
reason = error or ResponseError(cause)
> raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
E urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=50825): Max retries exceeded with url: /session/fb8201d3d37ec55e388d6392adb794ed/window/handles (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f6046fe4790>: Failed to establish a new connection: [Errno 111] Connection refused'))
../../../../.local/lib/python3.10/site-packages/urllib3/util/retry.py:515: MaxRetryError
============================================================================== short test summary info ===============================================================================
FAILED TEST_NAME.py::RecorderTest::test_recording - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=50825): Max retries exceeded with url: /session/fb8201d3d37ec55e388d6392adb794ed/window/handles (Caus...
1 failed in 209.12s (0:03:29)
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/__main__.py", line 21, in <module>
main()
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/run.py", line 1105, in main
sb_print.main()
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/sb_print.py", line 132, in main
with open(
FileNotFoundError: [Errno 2] No such file or directory: '/home/bangbuild/Documents/dev/Python/seleniumbase/recordings/TEST_NAME_rec.py'
Traceback (most recent call last):
File "/home/bangbuild/.local/bin/sbase", line 8, in <module>
sys.exit(main())
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/run.py", line 1054, in main
sb_mkrec.main()
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/sb_mkrec.py", line 231, in main
shutil.copy(recorded_file, file_path)
File "/usr/lib/python3.10/shutil.py", line 417, in copy
copyfile(src, dst, follow_symlinks=follow_symlinks)
File "/usr/lib/python3.10/shutil.py", line 254, in copyfile
with open(src, 'rb') as fsrc:
FileNotFoundError: [Errno 2] No such file or directory: '/home/bangbuild/Documents/dev/Python/seleniumbase/recordings/TEST_NAME_rec.py'
Looks like there's a bunch of errors:
Yes the desktop recorder app definitely not showing up, getting this error:
~/Documents/dev/Python/seleniumbase$ sbase recorder
Traceback (most recent call last):
File "/home/bangbuild/.local/bin/sbase", line 8, in <module>
sys.exit(main())
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/run.py", line 1043, in main
from seleniumbase.console_scripts import sb_recorder
File "/home/bangbuild/.local/lib/python3.10/site-packages/seleniumbase/console_scripts/sb_recorder.py", line 36, in <module>
import tkinter as tk # noqa: E402
ModuleNotFoundError: No module named 'tkinter'
I'm on seleniumbase 4.24.2
~/Documents/dev/Python/seleniumbase$ pip install tkinter
Defaulting to user installation because normal site-packages is not writeable
ERROR: Could not find a version that satisfies the requirement tkinter (from versions: none)
ERROR: No matching distribution found for tkinter
tkinter
is a built-in Python library for both Mac and Windows. Not sure if it's on Linux. What OS did you use?
To end the recording, make sure you type c
in the console and press Enter
to continue from the breakpoint after you are done recording. All the browser windows need to remain open during tearDown()
, so don't close them manually.
You can activate the Recorder without the GUI by calling:
sbase record SOMETEST.py --url=URL
Man it's amazing!!! (got it working with sudo apt install python3.10-tk
)
Everything is so smooth!! That's it the test path is perfect :+1:
Now I need to find how to record this window session to share it...
Michael I can't thank you enough for this amazing piece of software, truly magic ! 🙏
Have a great weekend my friend 😃
Is there an easy way to screen record the demo mode with SeleniumBase?
Video recording info: https://github.com/seleniumbase/SeleniumBase/discussions/2370#discussioncomment-7877316
Hi there, just discovered seleniumbase. trying out the first example of the last video:
getting the error:
what am I missing?! thanks