Skip to content

Instantly share code, notes, and snippets.

@ifuchs
Created February 13, 2022 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ifuchs/e3ee59aec7885ec9336034ab27128f5f to your computer and use it in GitHub Desktop.
Save ifuchs/e3ee59aec7885ec9336034ab27128f5f to your computer and use it in GitHub Desktop.
$ python -m pytest wordle_new.py
============================= test session starts ==============================
platform darwin -- Python 3.9.7, pytest-7.0.1, pluggy-1.0.0
rootdir: /Users/ihf
plugins: seleniumbase-2.4.12, html-2.0.1, xdist-2.5.0, forked-1.4.0, rerunfailures-10.2, metadata-1.11.0, ordering-0.6
collected 1 item
wordle_new.py F [100%]
=================================== FAILURES ===================================
___________________________ WordleTests.test_wordle ____________________________
self = <wordle_new.WordleTests testMethod=test_wordle>
selector = 'game-app::shadow game-keyboard::shadow button[data-key="?"]'
timeout = 6, must_be_visible = True
def __get_shadow_element(
self, selector, timeout=None, must_be_visible=False
):
self.wait_for_ready_state_complete()
if timeout is None:
timeout = settings.SMALL_TIMEOUT
elif timeout == 0:
timeout = 0.1 # Use for: is_shadow_element_* (* = present/visible)
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
timeout = self.__get_new_timeout(timeout)
self.__fail_if_invalid_shadow_selector_usage(selector)
if "::shadow " not in selector:
raise Exception(
'A Shadow DOM selector must contain at least one "::shadow "!'
)
selectors = selector.split("::shadow ")
element = self.get_element(selectors[0])
selector_chain = selectors[0]
is_present = False
for selector_part in selectors[1:]:
shadow_root = None
if (
selenium4
and self.is_chromium()
and int(self.__get_major_browser_version()) >= 96
):
try:
shadow_root = element.shadow_root
except Exception:
if self.browser == "chrome":
chrome_dict = self.driver.capabilities["chrome"]
chrome_dr_version = chrome_dict["chromedriverVersion"]
chromedriver_version = chrome_dr_version.split(" ")[0]
major_c_dr_version = chromedriver_version.split(".")[0]
if int(major_c_dr_version) < 96:
upgrade_to = "latest"
major_browser_version = (
self.__get_major_browser_version()
)
if int(major_browser_version) >= 96:
upgrade_to = str(major_browser_version)
message = (
"You need to upgrade to a newer\n"
"version of chromedriver to interact\n"
"with Shadow root elements!\n"
"(Current driver version is: %s)"
"\n(Minimum driver version is: 96.*)"
"\nTo upgrade, run this:"
'\n"seleniumbase install chromedriver %s"'
% (chromedriver_version, upgrade_to)
)
raise Exception(message)
if timeout != 0.1: # Skip wait for special 0.1 (See above)
time.sleep(2)
try:
shadow_root = element.shadow_root
except Exception:
raise Exception(
"Element {%s} has no shadow root!" % selector_chain
)
else: # This part won't work on Chrome 96 or newer.
# If using Chrome 96 or newer (and on an old Python version),
# you'll need to upgrade in order to access Shadow roots.
# Firefox users will likely hit:
# https://github.com/mozilla/geckodriver/issues/1711
# When Firefox adds support, switch to element.shadow_root
try:
shadow_root = self.execute_script(
"return arguments[0].shadowRoot", element
)
except Exception:
time.sleep(2)
shadow_root = self.execute_script(
"return arguments[0].shadowRoot", element
)
if timeout == 0.1 and not shadow_root:
raise Exception(
"Element {%s} has no shadow root!" % selector_chain
)
elif not shadow_root:
time.sleep(2) # Wait two seconds for the shadow root to appear
shadow_root = self.execute_script(
"return arguments[0].shadowRoot", element
)
if not shadow_root:
raise Exception(
"Element {%s} has no shadow root!" % selector_chain
)
selector_chain += "::shadow "
selector_chain += selector_part
try:
if (
selenium4
and self.is_chromium()
and int(self.__get_major_browser_version()) >= 96
):
if timeout == 0.1:
element = shadow_root.find_element(
By.CSS_SELECTOR, value=selector_part)
else:
found = False
for i in range(int(timeout) * 4):
try:
element = shadow_root.find_element(
By.CSS_SELECTOR, value=selector_part)
is_present = True
if must_be_visible:
if not element.is_displayed():
raise Exception(
"Shadow Root element not visible!")
found = True
break
except Exception:
time.sleep(0.2)
continue
if not found:
element = shadow_root.find_element(
By.CSS_SELECTOR, value=selector_part)
/anaconda3/envs/py39/lib/python3.9/site-packages/seleniumbase/fixtures/base_case.py:6048:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.remote.shadowroot.ShadowRoot (session="ade4c90bff3d54ad0b5b90429c58abca", element="d46b2141-b2d9-4862-ac12-3337153354bc")>
using = 'css selector', value = 'button[data-key="?"]'
def find_element(self, using, value):
return self._execute(Command.FIND_ELEMENT_FROM_SHADOW_ROOT, {"using": using, "value": value})['value']
/anaconda3/envs/py39/lib/python3.9/site-packages/selenium/webdriver/remote/shadowroot.py:45:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.remote.shadowroot.ShadowRoot (session="ade4c90bff3d54ad0b5b90429c58abca", element="d46b2141-b2d9-4862-ac12-3337153354bc")>
command = 'findElementFromShadowRoot'
params = {'sessionId': 'ade4c90bff3d54ad0b5b90429c58abca', 'shadowId': 'd46b2141-b2d9-4862-ac12-3337153354bc', 'using': 'css selector', 'value': 'button[data-key="?"]'}
def _execute(self, command, params=None):
"""Executes a command against the underlying HTML element.
Args:
command: The name of the command to _execute as a string.
params: A dictionary of named parameters to send with the command.
Returns:
The command's JSON response loaded into a dictionary object.
"""
if not params:
params = {}
params['shadowId'] = self._id
return self.session.execute(command, params)
/anaconda3/envs/py39/lib/python3.9/site-packages/selenium/webdriver/remote/shadowroot.py:64:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.chrome.webdriver.WebDriver (session="ade4c90bff3d54ad0b5b90429c58abca")>
driver_command = 'findElementFromShadowRoot'
params = {'shadowId': 'd46b2141-b2d9-4862-ac12-3337153354bc', 'using': 'css selector', 'value': 'button[data-key="?"]'}
def execute(self, driver_command: str, params: dict = None) -> dict:
"""
Sends a command to be executed by a command.CommandExecutor.
:Args:
- driver_command: The name of the command to execute as a string.
- params: A dictionary of named parameters to send with the command.
:Returns:
The command's JSON response loaded into a dictionary object.
"""
if self.session_id:
if not params:
params = {'sessionId': self.session_id}
elif 'sessionId' not in params:
params['sessionId'] = self.session_id
params = self._wrap_value(params)
response = self.command_executor.execute(driver_command, params)
if response:
self.error_handler.check_response(response)
/anaconda3/envs/py39/lib/python3.9/site-packages/selenium/webdriver/remote/webdriver.py:424:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x10a0aa280>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"no such element: Unable to locate element: {\...7fff6bd96249 _pthread_start + 66\\n23 libsystem_pthread.dylib 0x00007fff6bd9240d thread_start + 13\\n"}}'}
def check_response(self, response: Dict[str, Any]) -> None:
"""
Checks that a JSON response from the WebDriver does not have an error.
:Args:
- response - The JSON response from the WebDriver server as a dictionary
object.
:Raises: If the response contains an error message.
"""
status = response.get('status', None)
if not status or status == ErrorCode.SUCCESS:
return
value = None
message = response.get("message", "")
screen: str = response.get("screen", "")
stacktrace = None
if isinstance(status, int):
value_json = response.get('value', None)
if value_json and isinstance(value_json, str):
import json
try:
value = json.loads(value_json)
if len(value.keys()) == 1:
value = value['value']
status = value.get('error', None)
if not status:
status = value.get("status", ErrorCode.UNKNOWN_ERROR)
message = value.get("value") or value.get("message")
if not isinstance(message, str):
value = message
message = message.get('message')
else:
message = value.get('message', None)
except ValueError:
pass
exception_class: Type[WebDriverException]
if status in ErrorCode.NO_SUCH_ELEMENT:
exception_class = NoSuchElementException
elif status in ErrorCode.NO_SUCH_FRAME:
exception_class = NoSuchFrameException
elif status in ErrorCode.NO_SUCH_SHADOW_ROOT:
exception_class = NoSuchShadowRootException
elif status in ErrorCode.NO_SUCH_WINDOW:
exception_class = NoSuchWindowException
elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
exception_class = StaleElementReferenceException
elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
exception_class = ElementNotVisibleException
elif status in ErrorCode.INVALID_ELEMENT_STATE:
exception_class = InvalidElementStateException
elif status in ErrorCode.INVALID_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
exception_class = InvalidSelectorException
elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
exception_class = ElementNotSelectableException
elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
exception_class = ElementNotInteractableException
elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
exception_class = InvalidCookieDomainException
elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
exception_class = UnableToSetCookieException
elif status in ErrorCode.TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.SCRIPT_TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.UNKNOWN_ERROR:
exception_class = WebDriverException
elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
exception_class = UnexpectedAlertPresentException
elif status in ErrorCode.NO_ALERT_OPEN:
exception_class = NoAlertPresentException
elif status in ErrorCode.IME_NOT_AVAILABLE:
exception_class = ImeNotAvailableException
elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
exception_class = ImeActivationFailedException
elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
exception_class = MoveTargetOutOfBoundsException
elif status in ErrorCode.JAVASCRIPT_ERROR:
exception_class = JavascriptException
elif status in ErrorCode.SESSION_NOT_CREATED:
exception_class = SessionNotCreatedException
elif status in ErrorCode.INVALID_ARGUMENT:
exception_class = InvalidArgumentException
elif status in ErrorCode.NO_SUCH_COOKIE:
exception_class = NoSuchCookieException
elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
exception_class = ScreenshotException
elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
exception_class = ElementClickInterceptedException
elif status in ErrorCode.INSECURE_CERTIFICATE:
exception_class = InsecureCertificateException
elif status in ErrorCode.INVALID_COORDINATES:
exception_class = InvalidCoordinatesException
elif status in ErrorCode.INVALID_SESSION_ID:
exception_class = InvalidSessionIdException
elif status in ErrorCode.UNKNOWN_METHOD:
exception_class = UnknownMethodException
else:
exception_class = WebDriverException
if not value:
value = response['value']
if isinstance(value, str):
raise exception_class(value)
if message == "" and 'message' in value:
message = value['message']
screen = None # type: ignore[assignment]
if 'screen' in value:
screen = value['screen']
stacktrace = None
st_value = value.get('stackTrace') or value.get('stacktrace')
if st_value:
if isinstance(st_value, str):
stacktrace = st_value.split('\n')
else:
stacktrace = []
try:
for frame in st_value:
line = self._value_or_default(frame, 'lineNumber', '')
file = self._value_or_default(frame, 'fileName', '<anonymous>')
if line:
file = "%s:%s" % (file, line)
meth = self._value_or_default(frame, 'methodName', '<anonymous>')
if 'className' in frame:
meth = "%s.%s" % (frame['className'], meth)
msg = " at %s (%s)"
msg = msg % (meth, file)
stacktrace.append(msg)
except TypeError:
pass
if exception_class == UnexpectedAlertPresentException:
alert_text = None
if 'data' in value:
alert_text = value['data'].get('text')
elif 'alert' in value:
alert_text = value['alert'].get('text')
raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here
raise exception_class(message, screen, stacktrace)
E selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"button[data-key="?"]"}
E (Session info: chrome=98.0.4758.80)
E Stacktrace:
E 0 chromedriver 0x00000001080d83c9 chromedriver + 5018569
E 1 chromedriver 0x0000000108063333 chromedriver + 4539187
E 2 chromedriver 0x0000000107c38a88 chromedriver + 170632
E 3 chromedriver 0x0000000107c6d332 chromedriver + 385842
E 4 chromedriver 0x0000000107c6d521 chromedriver + 386337
E 5 chromedriver 0x0000000107c61ed7 chromedriver + 339671
E 6 chromedriver 0x0000000107c8a80d chromedriver + 505869
E 7 chromedriver 0x0000000107c61de5 chromedriver + 339429
E 8 chromedriver 0x0000000107c8a8ee chromedriver + 506094
E 9 chromedriver 0x0000000107c9d604 chromedriver + 583172
E 10 chromedriver 0x0000000107c8a6d3 chromedriver + 505555
E 11 chromedriver 0x0000000107c6095e chromedriver + 334174
E 12 chromedriver 0x0000000107c61935 chromedriver + 338229
E 13 chromedriver 0x00000001080941ee chromedriver + 4739566
E 14 chromedriver 0x00000001080adf51 chromedriver + 4845393
E 15 chromedriver 0x00000001080b3928 chromedriver + 4868392
E 16 chromedriver 0x00000001080aea7a chromedriver + 4848250
E 17 chromedriver 0x0000000108088c31 chromedriver + 4693041
E 18 chromedriver 0x00000001080c9978 chromedriver + 4958584
E 19 chromedriver 0x00000001080c9b01 chromedriver + 4958977
E 20 chromedriver 0x00000001080df795 chromedriver + 5048213
E 21 libsystem_pthread.dylib 0x00007fff6bd932eb _pthread_body + 126
E 22 libsystem_pthread.dylib 0x00007fff6bd96249 _pthread_start + 66
E 23 libsystem_pthread.dylib 0x00007fff6bd9240d thread_start + 13
/anaconda3/envs/py39/lib/python3.9/site-packages/selenium/webdriver/remote/errorhandler.py:247: NoSuchElementException
During handling of the above exception, another exception occurred:
self = <wordle_new.WordleTests testMethod=test_wordle>
def test_wordle(self):
self.skip_if_incorrect_env()
self.open("https://www.nytimes.com/games/wordle/index.html")
self.click("game-app::shadow game-modal::shadow game-icon")
self.initalize_word_list()
keyboard_base = "game-app::shadow game-keyboard::shadow "
word = random.choice(self.word_list)
total_attempts = 0
success = False
for attempt in range(6):
total_attempts += 1
word = random.choice(self.word_list)
letters = []
for letter in word:
letters.append(letter)
button = 'button[data-key="%s"]' % letter
self.click(keyboard_base + button)
button = 'button[data-key="?"]'
self.click(keyboard_base + button)
wordle_new.py:78:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/anaconda3/envs/py39/lib/python3.9/site-packages/seleniumbase/fixtures/base_case.py:230: in click
self.__shadow_click(selector, timeout)
/anaconda3/envs/py39/lib/python3.9/site-packages/seleniumbase/fixtures/base_case.py:6089: in __shadow_click
element = self.__get_shadow_element(
/anaconda3/envs/py39/lib/python3.9/site-packages/seleniumbase/fixtures/base_case.py:6071: in __get_shadow_element
page_actions.timeout_exception(the_exception, msg)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
exception = <class 'selenium.common.exceptions.ElementNotVisibleException'>
message = '\n Shadow DOM Element {game-app::shadow game-keyboard::shadow button[data-key="?"]} was not visible after 6 seconds!'
def timeout_exception(exception, message):
exception, message = s_utils.format_exc(exception, message)
raise exception(message)
E selenium.common.exceptions.ElementNotVisibleException: Message:
E Shadow DOM Element {game-app::shadow game-keyboard::shadow button[data-key="?"]} was not visible after 6 seconds!
/anaconda3/envs/py39/lib/python3.9/site-packages/seleniumbase/fixtures/page_actions.py:163: ElementNotVisibleException
----------------------- LogPath: /Users/ihf/latest_logs/ -----------------------
=========================== short test summary info ============================
FAILED wordle_new.py::WordleTests::test_wordle - selenium.common.exceptions.E...
============================== 1 failed in 11.70s ==============================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment