a
    7ñ»júY ã                   @   sb  d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlmZmZ ddlmZmZmZmZmZmZmZmZmZ ddlmZ ddl m!Z! ddl"m#Z# ddl$m%Z% dd	l&m'Z' dd
l(m)Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9 ddl8m:Z: ddl8m;Z; ddl8m<Z< ddl8m=Z= ddl>m?Z? ddl>m@Z@ ddl>mAZA ddl>mBZB ddl>mCZC ddl>mDZD ddl>mEZE ddl>mFZF dgZGe Hd¡ IejJ¡ e Hd¡ IejJ¡ e Hd¡ IejK¡ e L¡  e% IejM¡ eD N¡ ZNeD O¡ ZOd ZPe	jQd!k�rDd"ZPe?jRjSZTG d#d„ dejUƒZVdS )$a´  ----------------------------------------------------------------->
|    ______     __           _                  ____                 |
|   / ____/__  / /__  ____  (_)_  ______ ___   / _  \____  ________  |
|   \__ \/ _ \/ / _ \/ __ \/ / / / / __ `__ \ / /_) / __ \/ ___/ _ \ |
|  ___/ /  __/ /  __/ / / / / /_/ / / / / / // /_) / (_/ /__  /  __/ |
| /____/\___/_/\___/_/ /_/_/\__,_/_/ /_/ /_//_____/\__,_/____/\___/  |
|                                                                    |
--------------------------------------------------------------------->

The BaseCase class is the main gateway for using The SeleniumBase Framework.
It inherits Python's unittest.TestCase class and runs with pytest or pynose.
All tests using BaseCase automatically launch WebDriver browsers for tests.

Example Test:

# --------------------------------------------------------------
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class MyTestClass(BaseCase):
    def test_anything(self):
        # Write your code here. Example:
        self.open("https://github.com/")
        self.click('span[data-target*="inputButtonText"]')
        self.type("input#query-builder-test", "SeleniumBase\n")
        self.click('a[href="/seleniumbase/SeleniumBase"]')
        self.assert_element("div.repository-content")
        self.assert_text("SeleniumBase", "strong a")
# --------------------------------------------------------------

SeleniumBase methods expand and improve on existing WebDriver commands.
Improvements include making WebDriver more robust, reliable, and flexible.
Page elements are given enough time to load before WebDriver acts on them.
Code becomes greatly simplified and easier to maintain.é    N)ÚcontextmanagerÚsuppress)	Ú ElementClickInterceptedExceptionÚElementNotInteractableExceptionÚInvalidArgumentExceptionÚMoveTargetOutOfBoundsExceptionÚNoSuchElementExceptionÚNoSuchWindowExceptionÚStaleElementReferenceExceptionÚTimeoutExceptionÚWebDriverException)ÚActionChains)ÚBy)ÚKeys)ÚLOGGER)Ú
WebElement)Úconfig)Ú__version__)Ú
decorators)ÚNotConnectedExceptionÚNotUsingChromeExceptionÚNotUsingChromiumExceptionÚProxyConnectionExceptionÚOutOfScopeExceptionÚVisualException)Úsettings)Úbrowser_launcher)Údownload_helper)Ú
log_helper)Úsession_helper)Úvisual_helper)Ú	constants)Úcss_to_xpath)Újs_utils)Úpage_actions)Ú
page_utils)Úshared_utils)Úunittest_helper)Úxpath_to_cssÚBaseCaseÚrequestsÚurllib3Z	websocketF)é   é   Tc                8       sÒ   e Zd ZdZ‡ fdd„Zdd„ Zedd„ ƒZdd	„ Zd
d„ Z	�d“dd„Z
�d”dd„Z�d•dd„Z�d–dd„Z�d—dd„Z�d˜dd„Z�d™dd„Z�dšdd „Z�d›d!d"„Z�dœd#d$„Z�d�d%d&„Z�džd'd(„Z�dŸd)d*„Zd+d,„ Zd-d.„ Zd/d0„ Zd1d2„ Zd3d4„ Zd5d6„ Zd7d8„ Zd9d:„ Zd;d<„ Zd=d>„ Z d?d@„ Z!dAdB„ Z"dCdD„ Z#dEdF„ Z$�d dGdH„Z%�d¡dIdJ„Z&�d¢dKdL„Z'�d£dMdN„Z(�d¤dPdQ„Z)�d¥dRdS„Z*�d¦dTdU„Z+�d§dVdW„Z,dXdY„ Z-dZd[„ Z.d\d]„ Z/d^d_„ Z0�d¨d`da„Z1�d©dbdc„Z2�dªddde„Z3�d«dfdg„Z4�d¬dhdi„Z5�d­djdk„Z6�d®dldm„Z7�d¯dndo„Z8�d°dpdq„Z9�d±drds„Z:�d²dtdu„Z;�d³dvdw„Z<dxdy„ Z=�d´dzd{„Z>�dµd|d}„Z?�d¶d~d„Z@�d·d€d�„ZA�d¸d‚dƒ„ZB�d¹d„d…„ZC�dºd†d‡„ZD�d»dˆd‰„ZE�d¼dŠd‹„ZF�d½dŒd�„ZGdŽd�„ ZH�d¾d�d‘„ZI�d¿d’d“„ZJ�dÀd”d•„ZK�dÁd–d—„ZL�dÂd˜d™„ZM�dÃdšd›„ZN�dÄdœd�„ZO�dÅdždŸ„ZP�dÆd d¡„ZQ�dÇd¢d£„ZR�dÈd¤d¥„ZS�dÉd¦d§„ZT�dÊd¨d©„ZU�dËdªd«„ZV�dÌd¬d­„ZW�dÍd®d¯„ZXd°d±„ ZY�dÎd³d´„ZZ�dÏdµd¶„Z[�dÐd·d¸„Z\�dÑd¹dº„Z]�dÒd»d¼„Z^�dÓd½d¾„Z_�dÔd¿dÀ„Z`�dÕdÁdÂ„ZadÃdÄ„ ZbdÅdÆ„ ZcdÇdÈ„ ZddÉdÊ„ Ze�dÖdËdÌ„ZfdÍdÎ„ ZgdÏdÐ„ Zh�d×dÑdÒ„Zi�dØdÓdÔ„ZjdÕdÖ„ Zkd×dØ„ ZldÙdÚ„ ZmdÛdÜ„ ZndÝdÞ„ Zodßdà„ Zpdádâ„ Zqdãdä„ Zrdådæ„ Zsdçdè„ Ztdédê„ Zudëdì„ Zv�dÙdîdï„Zwdðdñ„ Zxdòdó„ Zyez�dÚdôdõ„ƒZ{�dÛdöd÷„Z|�dÜdødù„Z}�dÝdúdû„Z~düdý„ Zdþdÿ„ Z€�dÞ�d �d„Z��dß�d�d„Z‚�d�d„ Zƒ�d�d„ Z„�dà�d�d	„Z…�d
�d„ Z†�d�d„ Z‡�dá�d�d„Zˆ�dâ�d�d„Z‰�dã�d�d„ZŠ�dä�d�d„Z‹�då�d�d„ZŒ�dæ�d�d„Z��dç�d�d„ZŽ�dè�d�d„Z��dé�d�d „Z��dê�d!�d"„Z‘�d#�d$„ Z’�dë�d%�d&„Z“�dì�d'�d(„Z”�d)�d*„ Z•�d+�d,„ Z–�d-�d.„ Z—�dí�d/�d0„Z˜�dî�d1�d2„Z™�d3�d4„ Zš�d5�d6„ Z›�dï�d7�d8„Zœ�dð�d9�d:„Z��d;�d<„ Zž�d=�d>„ ZŸ�d?�d@„ Z �dA�dB„ Z¡�dC�dD„ Z¢�dE�dF„ Z£�dñ�dG�dH„Z¤�dò�dI�dJ„Z¥�dK�dL„ Z¦�dM�dN„ Z§�dO�dP„ Z¨�dQ�dR„ Z©�dS�dT„ Zª�dU�dV„ Z«�dW�dX„ Z¬�dó�dY�dZ„Z­�dô�d\�d]„Z®�dõ�d^�d_„Z¯�dö�d`�da„Z°�d÷�dc�dd„Z±�dø�de�df„Z²�dù�dg�dh„Z³�dú�di�dj„Z´�dû�dk�dl„Zµ�dü�dn�do„Z¶�dý�dp�dq„Z·�dþ�dr�ds„Z¸�dÿ�dt�du„Z¹�d �dv�dw„Zº�d�dx�dy„Z»�d�dz�d{„Z¼�d�d|�d}„Z½�d�d~�d„Z¾�d€�d�„ Z¿�d‚�dƒ„ ZÀ�d„�d…„ ZÁ�d†�d‡„ ZÂ�d�d‰�dŠ„ZÃ�d�d‹�dŒ„ZÄ�d��dŽ„ ZÅ�d�d��d�„ZÆ�d�d‘�d’„ZÇ�d	�d“�d”„ZÈ�d
�d•�d–„ZÉ�d�d—�d˜„ZÊ�d�d™�dš„ZË�d�d›�dœ„ZÌ�d�d��dž„ZÍ�d�dŸ�d „ZÎ�d�d¡�d¢„ZÏ�d�d£�d¤„ZÐ�d�d¥�d¦„ZÑ�d§�d¨„ ZÒ�d©�dª„ ZÓ�d«�d¬„ ZÔ�d­�d®„ ZÕ�d¯�d°„ ZÖ�d�d±�d²„Z×�d³�d´„ ZØ�d�d¶�d·„ZÙ�d¸�d¹„ ZÚ�dº�d»„ ZÛ�d�d¼�d½„ZÜ�d¾�d¿„ ZÝ�dÀ�dÁ„ ZÞ�dÂ�dÃ„ Zß�d�dÅ�dÆ„Zà�d�dÇ�dÈ„Zá�dÉ�dÊ„ Zâ�d�dË�dÌ„Zã�d�dÎ�dÏ„Zä�d�dÐ�dÑ„Zå�d�dÒ�dÓ„Zæ�d�dÔ�dÕ„Zç�d�dÖ�d×„Zè�d�dØ�dÙ„Zé�d�dÚ�dÛ„Zê�dÜ�dÝ„ Zë�dÞ�dß„ Zì�d �dà�dá„Zí�d!�dâ�dã„Zî�d"�dä�då„Zï�d#�dæ�dç„Zð�d$�dè�dé„Zñ�d%�dê�dë„Zò�d&�dì�dí„Zó�d'�dî�dï„Zô�d(�dð�dñ„Zõ�d)�dò�dó„Zö�d*�dô�dõ„Z÷�d+�dö�d÷„Zø�d,�dø�dù„Zù�d-�dú�dû„Zú�d.�dü�dý„Zû�d/�dþ�dÿ„Zü�d �d„ Zý�d0�d�d„Zþ�d1�d�d„Zÿ�d�d„ �Z �d�d	„ �Z�d
�d„ �Z�d�d„ �Zg f�d�d„�Z�d�d„ �Z�d�d„ �Z�d�d„ �Z�d�d„ �Z�d�d„ �Z	�d�d„ �Z
�d�d„ �Z�d�d„ �Z�d �d!„ �Z�d"�d#„ �Z�d$�d%„ �Z�d&�d'„ �Z�d(�d)„ �Z�d2�d*�d+„�Z�d3�d,�d-„�Z�d.�d/„ �Z�d0�d1„ �Z�d2�d3„ �Z�d4�d4�d5„�Z�d5�d6�d7„�Z�d6�d8�d9„�Z�d7�d:�d;„�Z�d8�d<�d=„�Z�d9�d>�d?„�Z�d:�d@�dA„�Z�d;�dB�dC„�Z�dD�dE„ �Z�dF�dG„ �Z �dH�dI„ �Z!�d<‡ f�dK�dL„	�Z"�d=�dM�dN„�Z#�dO�dP„ �Z$�dQ�dR„ �Z%�dS�dT„ �Z&�dU�dV„ �Z'�dW�dX„ �Z(�dY�dZ„ �Z)�d[�d\„ �Z*�d]�d^„ �Z+�d_�d`„ �Z,�da�db„ �Z-�dc�dd„ �Z.�de�df„ �Z/�dg�dh„ �Z0�di�dj„ �Z1�dk�dl„ �Z2�dm�dn„ �Z3�do�dp„ �Z4�dq�dr„ �Z5�ds�dt„ �Z6�du�dv„ �Z7�dw�dx„ �Z8�dy�dz„ �Z9�d{�d|„ �Z:�d}�d~„ �Z;�d�d€„ �Z<�d>�d��d‚„�Z=�d?�dƒ�d„„�Z>�d…�d†„ �Z?�d‡�dˆ„ �Z@�d@�d‰�dŠ„�ZA�dA�d‹�dŒ„�ZB�dB�d��dŽ„�ZC�dC�d��d�„�ZD�dD�d‘�d’„�ZE�dE�d“�d”„�ZF�dF�d•�d–„�ZG�dG�d—�d˜„�ZH�dH�d™�dš„�ZI�dI�d›�dœ„�ZJ�dJ�d��dž„�ZK�dK�dŸ�d „�ZL�dL�d¡�d¢„�ZM�d£�d¤„ �ZN�d¥�d¦„ �ZO�d§�d¨„ �ZP�d©�dª„ �ZQ�dM�d«�d¬„�ZR�dN�d­�d®„�ZS�dO�d¯�d°„�ZT�dP�d±�d²„�ZU�dQ�d³�d´„�ZV�dR�dµ�d¶„�ZW�dS�d·�d¸„�ZX�d¹�dº„ �ZY�d»�d¼„ �ZZ�d½�d¾„ �Z[�dT�d¿�dÀ„�Z\�dÁ�dÂ„ �Z]�dÃ�dÄ„ �Z^�dÅ�dÆ„ �Z_�dÇ�dÈ„ �Z`�dÉ�dÊ„ �Za�dË�dÌ„ �Zb�dÍ�dÎ„ �Zc�dÏ�dÐ„ �Zd�dÑ�dÒ„ �Ze�dU�dÓ�dÔ„�Zf�dÕ�dÖ„ �Zg�dV�dØ�dÙ„�Zh�dW�dÛ�dÜ„�Zi�dX�dÝ�dÞ„�Zj�dY�dß�dà„�Zk�dZ�dá�dâ„�Zl�d[�dã�dä„�Zm�d\�då�dæ„�Zn�dç�dè„ �Zo�d]�dé�dê„�Zp�d^�dë�dì„�Zq�d_�dí�dî„�Zr�d`�dï�dð„�Zs�da�dñ�dò„�Zt�db�dó�dô„�Zu�dc�dõ�dö„�Zv�dd�d÷�dø„�Zw�dù�dú„ �Zx�de�dû�dü„�Zy�df�dý�dþ„�Zz�dg�dÿ�d „�Z{�d�d„ �Z|�d�d„ �Z}�dh�d�d„�Z~�di�d�d„�Z�dj�d	�d
„�Z€�dk�d�d„�Z��dl�d�d„�Z‚�dm�d�d„�Zƒ�dn�d�d„�Z„�do�d�d„�Z…�dp�d�d„�Z†�dq�d�d„�Z‡�dr�d�d„�Zˆ�ds�d�d„�Z‰�dt�d�d„�ZŠ�du�d�d „�Z‹�dv�d!�d"„�ZŒ�dw�d#�d$„�Z��dx�d%�d&„�ZŽ�dy�d'�d(„�Z��dz�d)�d*„�Z��d{�d+�d,„�Z‘�d|�d-�d.„�Z’�d}�d/�d0„�Z“�d~�d1�d2„�Z”�d�d3�d4„�Z•�d€�d5�d6„�Z–�d��d7�d8„�Z—�d‚�d9�d:„�Z˜�dƒ�d;�d<„�Z™�d„�d=�d>„�Zš�d…�d?�d@„�Z›�d†�dA�dB„�Zœ�d‡�dC�dD„�Z��dˆ�dE�dF„�Zž�d‰�dG�dH„�ZŸ�dŠ�dI�dJ„�Z �d‹�dK�dL„�Z¡�dŒ�dM�dN„�Z¢�d��dO�dP„�Z£�dŽ�dQ�dR„�Z¤�dS�dT„ �Z¥�dU�dV„ �Z¦�dW�dX„ �Z§�d��dY�dZ„�Z¨�d[�d\„ �Z©�d]�d^„ �Zª�d_�d`„ �Z«�da�db„ �Z¬�d��dc�dd„�Z­�d‘�de�df„�Z®�d’�dg�dh„�Z¯�d“�di�dj„�Z°�d”�dk�dl„�Z±�d•�dm�dn„�Z²�d–�do�dp„�Z³�d—�dq�dr„�Z´�d˜�ds�dt„�Zµ�d™�du�dv„�Z¶�dš�dw�dx„�Z·�d›�dy�dz„�Z¸�dœ�d{�d|„�Z¹�d��d}�d~„�Zº�dž�d�d€„�Z»�dŸ�d��d‚„�Z¼�d �dƒ�d„„�Z½�d¡�d…�d†„�Z¾�d¢�d‡�dˆ„�Z¿�d£�d‰�dŠ„�ZÀ�d¤�d‹�dŒ„�ZÁ�d¥�d��dŽ„�ZÂ�d¦�d��d�„�ZÃ�d§�d‘�d’„�ZÄ�d¨�d“�d”„�ZÅ�d©�d•�d–„�ZÆ�dª�d—�d˜„�ZÇ�d«�d™�dš„�ZÈ�d¬�d›�dœ„�ZÉ�d­�d��dž„�ZÊ�d®�dŸ�d „�ZË�d¯�d¡�d¢„�ZÌ�d°�d£�d¤„�ZÍ�d±�d¥�d¦„�ZÎ�d²�d§�d¨„�ZÏ�d³�d©�dª„�ZÐ�d´�d«�d¬„�ZÑ�dµ�d­�d®„�ZÒ�d¶�d¯�d°„�ZÓ�d·�d±�d²„�ZÔ�d¸�d³�d´„�ZÕ�d¹�dµ�d¶„�ZÖ�dº�d·�d¸„�Z×�d»�d¹�dº„�ZØ�d¼�d»�d¼„�ZÙ�d½�d¾�d¿„�ZÚ�dÀ�dÁ„ �ZÛ�d¾�dÂ�dÃ„�ZÜ�dÄ�dÅ„ �ZÝ�d¿�dÆ�dÇ„�ZÞ�dÀ�dÈ�dÉ„�Zß�dÁ�dÊ�dË„�Zà�dÌ�dÍ„ �Zá�dÎ�dÏ„ �Zâ�dÐ�dÑ„ �Zã�dÂ�dÒ�dÓ„�Zä�dÔ�dÕ„ �Zå�dÃ�dÖ�d×„�Zæ�dÄ�dØ�dÙ„�Zç�dÅ�dÚ�dÛ„�Zè�dÆ�dÜ�dÝ„�Zé�dÞ�dß„ �Zê�dÇ�dà�dá„�Zë�dâ�dã„ �Zì�dÈ�dä�då„�Zí�dæ�dç„ �Zî�dÉ�dè�dé„�Zï�dê�dë„ �Zð�dì�dí„ �Zñ�dî�dï„ �Zò�dð�dñ„ �Zó�dÊ�dò�dó„�Zô�dô�dõ„ �Zõ�dö�d÷„ �Zö�dø�dù„ �Z÷�dË�dú�dû„�Zø�dü�dý„ �Zù�dþ�dÿ„ �Zú�d �d„ �Zû�d�d„ �Zü�d�d„ �Zý�d�d„ �Zþ�d�d	„ �Zÿ�dÌ�d
�d„�Z �d�d„ �Z�d�d„ �Z�d�d„ �Z�d�d„ �Z�d�d„ �Z�e� �d¡�d�d„ ƒ�Z�dÍ�d�d„�Z	�d�d„ �Z
�d�d„ �Z�d�d „ �Z�dÎ�d!�d"„�Z�d#�d$„ �Z�d%�d&„ �Z�d'�d(„ �Z�d)�d*„ �Z�d+�d,„ �Z�d-�d.„ �Z�d/�d0„ �Z�d1�d2„ �Z�d3�d4„ �Z�d5�d6„ �Z�d7�d8„ �Z�d9�d:„ �Z�d;�d<„ �Z�d=�d>„ �Z�d?�d@„ �Z�dA�dB„ �Z�dÏ�dC�dD„�Z�dE�dF„ �Z�dG�dH„ �Z �dÐ�dI�dJ„�Z!�dK�dL„ �Z"�dM�dN„ �Z#�dÑ�dO�dP„�Z$�dQ�dR„ �Z%�dS�dT„ �Z&�dU�dV„ �Z'�dW�dX„ �Z(�dY�dZ„ �Z)�d[�d\„ �Z*�d]�d^„ �Z+�d_�d`„ �Z,�da�db„ �Z-�dc�dd„ �Z.�de�df„ �Z/�dg�dh„ �Z0�di�dj„ �Z1�dk�dl„ �Z2�dm�dn„ �Z3�dÒ�do�dp„�Z4�dÓ�dq�dr„�Z5�ds�dt„ �Z6�du�dv„ �Z7�dw�dx„ �Z8�dy�dz„ �Z9�d{�d|„ �Z:�d}�d~„ �Z;�d�d€„ �Z<�d��d‚„ �Z=�dƒ�d„„ �Z>�d…�d†„ �Z?�d‡�dˆ„ �Z@�d‰�dŠ„ �ZA�dÔ‡ f�d‹�dŒ„	�ZB�d��dŽ„ �ZCe�d��d�„ ƒ�ZDe�d‘�d’„ ƒ�ZE‡  �ZFS (Õ  r)   z<Class seleniumbase.BaseCase>c                    s   t ƒ j|i |¤Ž |  ¡  d S ©N)ÚsuperÚ__init__Ú_BaseCase__initialize_variables©ÚselfÚargsÚkwargs©Ú	__class__© úEE:\soccer\ml_env\Lib\site-packages\seleniumbase/fixtures/base_case.pyr0   m   s    zBaseCase.__init__c                 C   sè  d | _ d | _d | _t t¡| _t| jƒ| _| j| _	t
j
| _
g | _g | _d| _d| _d| _d| _d | _d| _d| _d| _tt
 
¡ d ƒ| _d | _d| _d| _d| _d| _d | _d| _d| _d| _g | _ d| _!d| _"d | _#d | _$d | _%d | _&d | _'g | _(g | _)d| _*d| _+d| _,d| _-d | _.d| _/g | _0d | _1d | _2d | _3d| _4d | _5d | _6d | _7d | _8d| _9i | _:i | _;d| _<d| _=d | _>g | _?d | _@d | _Ad | _Bd | _Cg | _Di | _Ed| _Fi | _Gd| _Hi | _Id| _Ji | _Ki | _Li | _Md | _Nd | _Od | _Pd S )Nr   Fç     @�@úabout:blankTÚEnglish)QÚdriverÚenvironmentÚenvr&   Zmake_version_listr   Úversion_listÚtupleÚversion_tupleÚversion_infoÚtimeÚ_BaseCase__page_sourcesÚ_BaseCase__extra_actionsÚ_BaseCase__js_start_timeÚ_BaseCase__set_c_from_switchÚ_BaseCase__frame_switch_layerÚ_BaseCase__frame_switch_multiÚ_BaseCase__last_saved_urlÚ_BaseCase__uc_frame_layerÚ_BaseCase__called_setupÚ_BaseCase__called_teardownÚintÚ_BaseCase__start_time_msÚ_BaseCase__requests_timeoutÚ_BaseCase__page_source_countÚ_BaseCase__screenshot_countÚ_BaseCase__saved_pdf_countÚ_BaseCase__logs_data_countÚ_BaseCase__last_data_fileÚ_BaseCase__level_0_visual_fÚ_BaseCase__will_be_skippedÚ_BaseCase__passed_then_skippedÚ!_BaseCase__visual_baseline_copiesÚ&_BaseCase__last_url_of_deferred_assertÚ_BaseCase__last_page_load_urlÚ_BaseCase__last_page_screenshotÚ#_BaseCase__last_page_screenshot_pngÚ_BaseCase__last_page_urlÚ_BaseCase__last_page_sourceÚ_BaseCase__skip_reasonÚ_BaseCase__origins_to_saveÚ_BaseCase__actions_to_saveÚ_BaseCase__dont_record_openÚ_BaseCase__dont_record_js_clickÚ!_BaseCase__new_window_on_rec_openÚ%_BaseCase__overrided_default_timeoutsÚ"_BaseCase__added_pytest_html_extraÚ _BaseCase__deferred_assert_countÚ#_BaseCase__deferred_assert_failuresÚ_BaseCase__device_widthÚ_BaseCase__device_heightÚ_BaseCase__device_pixel_ratioÚ_BaseCase__changed_jqc_themeÚ_BaseCase__jqc_default_themeÚ_BaseCase__jqc_default_colorÚ_BaseCase__jqc_default_widthÚ_BaseCase__saved_idÚ	_languageÚ_presentation_slidesÚ_presentation_transitionÚ_output_file_savesÚ_rec_overrides_switchÚ_sb_test_identifierÚ_html_report_extraÚ_last_page_screenshotÚ_last_page_urlÚ_final_debugÚ_default_driverÚ_drivers_listÚ_drivers_browser_mapÚ_was_skippedÚ_chart_dataÚ_chart_countÚ_chart_labelÚ_chart_xcountÚ_chart_first_seriesÚ_chart_series_countÚ_tour_stepsÚ_xvfb_displayÚ_xvfb_widthÚ_xvfb_height©r3   r8   r8   r9   Z__initialize_variablesq   s˜    zBaseCase.__initialize_variablesc                 G   sd   |dkr`ddl }g }|D ]}| |¡ qtjdd… D ]}| |¡ q6| tjdd|dg|¢¡ dS )aˆ  Run pytest if file was called with "python".
        Usage example:

            from seleniumbase import BaseCase
            BaseCase.main(__name__, __file__)

            class MyTestClass(BaseCase):
                def test_example(self):
                    pass

        The run command:
            python my_test.py  # (Instead of "pytest my_test.py")

        This is useful when sharing code with people who may not be aware
        that SeleniumBase tests are run with "pytest" instead of "python".
        Now, if they accidentally type "python", the tests will still run.
        Eg. "python my_test.py" instead of "pytest my_test.py".Ú__main__r   Né   z-mZpytestz-s)Ú
subprocessÚappendÚsysÚargvÚcallÚ
executable)r3   ÚnameÚfiler4   rŽ   Úall_argsÚargr8   r8   r9   ÚmainÀ   s    ÿzBaseCase.mainc                 K   sø  |   ¡  |  ¡ r(| jj|fi |¤Ž dS t| jddƒrdt| jddƒsdt d¡ | j|fi |¤Ž dS t| jddƒr t| jddƒr |  	¡  | jj|fi |¤Ž dS |  
¡  |  ¡ rºt d¡ d}ttƒ� | jj}W d  ƒ n1 sä0    Y  t|ƒ ¡ }|  |¡�s,t d| ¡�r d| }ntd| ƒ‚d| _t | j¡ | d¡�rRd	| }| j�r°| j�s°|  d
¡}|  ¡ }d||tt|ƒd ƒg}| j  |¡ d|||g}| j  |¡ | j�r| j!�r| jj}d|v �sæd|v �sæd|v �r|  "|¡|  "|¡k�r| j#dd� z| j $|¡ W �nœ t�y¶ } �z€t%|dƒ�s˜t%| jdƒ�r˜z|  
¡  t d¡ W n( t�y†   t &d¡ |  '¡ | _Y n0 | j (|¡ �n
d|j)v �sÈd|j)v �sÈd|j)v �sÈd|j)v �ròt* +¡  |  
¡  t d¡ | j $|¡ �n°d|j)v �sd|j)v �sd|j)v �r¼t* +¡  |  
¡  t d¡ z| j $|¡ W nx t�y¸ }	 z^d|	j)v �sjd|	j)v �r€d }
|
d!7 }
t,|
ƒ‚n$d|	j)v �r¢d"}
|
d#7 }
t-|
ƒ‚n‚ W Y d}	~	n
d}	~	0 0 næd$|j)v �r6| jj.j/}t d%| ¡ z| j $|¡ W nB t�y2 } z(d$|j)v �rtd&| ƒ‚n‚ W Y d}~n
d}~0 0 nld'|j)v �sNd(|j)v �rr|  ¡ �r¢t d)¡ | j $|¡ n n0d*|j)v �r t &d+¡ |  '¡ | _| j $|¡ n‚ W Y d}~n
d}~0 0 z&| jj|k�rÜ||k�rÜt d,¡ W np t�yN   t d,¡ z|  
¡  | jj�std-ƒ‚W n2 t�yH   |  '¡ | _| j $|¡ |  
¡  Y n0 Y n0 t0j1�rh| j2�sh|  3¡  |  ¡ �r|t d.¡ | j2�rŠd/| _4| j5�rô| jj d0¡�rìt 6| j¡�sìttƒ�" t 7| jt8j9j:¡ W d  ƒ n1 �sâ0    Y  |  ;¡  dS )1z;Navigates the current browser window to the specified page.NÚ_is_using_ucÚ_is_using_cdpz0open() in UC Mode now always activates CDP Mode.ç{®Gáz¤?úhttps://úInvalid URL: "%s"!ú://Úhttpsúreturn Date.now();Úo_urlr�   Ú_url_úhttp:úhttps:úfile:T©Ú	switch_toÚmsgÚdefault_getçš™™™™™Ù?z'Browser crashed! Will open new browser!ZERR_CONNECTION_TIMED_OUTZERR_CONNECTION_CLOSEDZERR_CONNECTION_RESETZERR_NAME_NOT_RESOLVEDgš™™™™™é?ZERR_INTERNET_DISCONNECTEDzneterror?e=dnsNotFoundZERR_PROXY_CONNECTION_FAILEDçÍÌÌÌÌÌð?zERR_INTERNET_DISCONNECTED: zInternet unreachable!zERR_PROXY_CONNECTION_FAILED: z*Internet unreachable and/or invalid proxy!z)Timed out receiving message from rendererz7The page load timed out after %s seconds! Will retry...z.Retry of page load timed out after %s seconds!úcannot determine loading statusúunexpected command responseçš™™™™™É?zinvalid session idz*Invalid session id. Will open new browser.çš™™™™™¹?zNo current URL!ç{®Gáz´?r   )Úhttpr•   Údata)<Ú_BaseCase__check_scopeÚ_BaseCase__is_cdp_swap_neededÚcdpÚopenÚgetattrr=   ÚloggingÚinfoÚactivate_cdp_modeÚ
disconnectÚ_check_browserÚ_BaseCase__needs_minimum_waitrD   Úsleepr   Ú	ExceptionÚcurrent_urlÚstrÚstripÚ _BaseCase__looks_like_a_page_urlr%   Úis_valid_urlr\   r#   Úclear_out_console_logsÚ
startswithÚrecorder_moderd   Úexecute_scriptÚ
get_originrO   rF   r�   rf   Úget_domain_urlÚopen_new_windowÚgetÚhasattrÚdebugÚget_new_driverr©   r¨   r&   Úcheck_if_time_limit_exceededr   r   ÚtimeoutsZ	page_loadr   ÚWAIT_FOR_RSC_ON_PAGE_LOADSÚundetectableÚwait_for_ready_state_completerL   Ú	demo_modeÚis_jquery_activatedÚadd_js_linkr!   ÚJQueryÚMIN_JSÚ$_BaseCase__demo_mode_pause_if_active)r3   Úurlr5   Úpre_action_urlÚ
time_stampÚoriginÚactionZc_urlÚeÚe2ÚmessageZpage_load_timeoutr8   r8   r9   r¶   á   s2   ÿý
ÿþ

&


ÿþýü
ÿþý
ÿþ


ÿÿÿÿÿþ




ÿþ






ÿ$zBaseCase.openc                 C   s,   |   ¡  |  |¡r|  |¡ n
|  |¡S dS )a!  If "url" looks like a page URL, open the URL in the web browser.
        Otherwise, return self.get_element(URL_AS_A_SELECTOR)
        Examples:
            self.get("https://seleniumbase.io")  # Navigates to the URL
            self.get("input.class")  # Finds and returns the WebElement N)r³   rÃ   r¶   Úget_element©r3   rÛ   r8   r8   r9   rÌ   …  s    
zBaseCase.getúcss selectorNr   Tc                 C   s¸
  |   ¡  |  ¡  |stj}| jr4|tjkr4|  |¡}|}|}|  ||¡\}}|  ¡ rj| jj	|||d� d S |r�t
|ƒttfv r�|dkr�t |¡ t |¡s¤|tjkrÀ|  |¡sÀ| j||d� d S t |¡sÔ|tjkrð|  |¡sð| j||d� d S |  |¡�r|  ||¡ d S |  ¡ �s"| jdk�r,t d¡ tj| j||||d�}|   ||¡ |�rr| j!�sr| j"�sr|  #|||¡ d }	t$t%ƒ� | jj&}	W d   ƒ n1 �sž0    Y  t'| jj(ƒ}
�zŽ|tjk�rî| jdk�sÜ| jdk�rî| j)||d� �nR| jdk�r
|  *d	|¡ �n6d }d
}d }t$t%ƒ�� | j+�r|j, -¡ dk�r| .d¡ /¡ }| .d¡}| .d¡}|dk�rjd}|�r|  0|¡�r|�r¶t$t%ƒ� |  *|¡ W d   ƒ n1 �s¬0    Y  | jj1}|  2¡  t$t%ƒ� |  3|¡ W d   ƒ n1 �sð0    Y  |  4|¡ W d   ƒ W d S W d   ƒ n1 �s,0    Y  |  5|¡ W �n: t6�y   |  7¡  t d¡ tj8| j||||d�}t$t%ƒ� |  #|||¡ W d   ƒ n1 �sª0    Y  | jdk�rÜ|tjk�rÜ| j)||d� n$| jdk�rö|  *d	|¡ n
|  5|¡ Y �nz t9�y> } �zt$t%ƒ�‚ d|j:v �r”|j, -¡ dk�r”d|v�rX| j;||d� n| j<||d� |  ¡ �rzt d¡ W d   ƒ W Y d }~d S W d   ƒ n1 �sª0    Y  |  7¡  t d¡ tj| j||||d�}t =| j||¡�s>t$t%ƒ�  | j8||dd� W d   ƒ n1 �s0    Y  tj| j||||d�}d }d
}d }t$t%ƒ�� |j, -¡ dk�rJ| .d¡ /¡ }| .d¡}| .d¡}|dk�r–d}|�rJ|  0|¡�rJ|�rât$t%ƒ� |  *|¡ W d   ƒ n1 �sØ0    Y  | jj1}|  2¡  t$t%ƒ� |  3|¡ W d   ƒ n1 �s0    Y  |  4|¡ W d   ƒ W Y d }~d S W d   ƒ n1 �s`0    Y  |�rŽ| j!�sŽ| j"�sŽ|  #|||¡ | jdk�s¦| jdk�rÜ|tjk�s¼d|v �rÌ| j)||d� n| j>||d� nLz|  5|¡ W n< t%�y&   |  7¡  tj| j||||d�}|  5|¡ Y n0 W Y d }~�nJd }~0  t?�yÈ   |  7¡  z| j>||d� W n\ t%�yÂ   z| j)||d� W n4 t%�y¼   tj8| j||||d�}|  5|¡ Y n0 Y n0 Y n¸ t@�y~ } zžd|j:v �sjd|j:v �rònx|  7¡  z| j>||d� W n\ t%�yh   z| j)||d� W n4 t%�yb   tj| j||||d�}|  5|¡ Y n0 Y n0 W Y d }~n
d }~0 0 t'| jj(ƒ}||
k�r¾| jA�s´tjB�r¾| jj&|	k�r¾|  C¡  n"||
d k�rà|dk�rà|  4d¡ tjD�	rP| jE�	sDt$t%ƒ� |  7¡  W d   ƒ n1 �	s0    Y  |  ¡ �	s8| jdk�	rNt d¡ n
t d¡ nþ| jE�
sDt$t%ƒ� | jFtjGd� W d   ƒ n1 �	s†0    Y  |  ¡ �	s¦| jdk�	r°t d¡ z6| jj&|	k�	rä|  H¡  |  I¡  |  ¡ �	rät d¡ W nZ t%�
y@   t$t%ƒ� |  7¡  W d   ƒ n1 �
s0    Y  |  ¡ �
r<t d¡ Y n0 n
t d¡ | j!�
rœ| jj&|	k�
rŽtJ K| j¡�
s„tJ L| jtMjNjO¡ |  P¡  n| jPdd � n| j"�
r¬|  Q¡  |  R¡  d S )!N©ÚtimeoutÚscrollr   ©rç   Úsafariçš™™™™™©?©rç   Úoriginal_selectorÚie©Úbyúarguments[0].click();FÚaÚhrefÚonclickÚtargetÚ_blankTç{®GázÄ?zelement has zero sizeú	contains(r›   r¯   çÍÌÌÌÌÌü?Úfirefoxr¬   r­   r�   éÿÿÿÿr°   g
×£p=
§?g333333³?gÃõ(\�Âµ?©Útiny)Sr³   Ú_BaseCase__skip_if_escr   ÚSMALL_TIMEOUTÚtimeout_multiplierÚ_BaseCase__get_new_timeoutÚ_BaseCase__recalculate_selectorr´   rµ   ÚclickÚtyperO   ÚfloatrD   r¾   r%   Zis_link_text_selectorr   Ú	LINK_TEXTÚis_link_text_visibleÚclick_link_textZis_partial_link_text_selectorÚPARTIAL_LINK_TEXTÚis_partial_link_text_visibleÚclick_partial_link_textÚ_BaseCase__is_shadow_selectorÚ_BaseCase__shadow_clickr½   Úbrowserr$   Úwait_for_element_visibler=   Ú(_BaseCase__demo_mode_highlight_if_activerÕ   Ú	slow_modeÚ_BaseCase__scroll_to_elementr   r¿   rÀ   ÚlenÚwindow_handlesÚ_BaseCase__jquery_clickrÈ   ÚheadlessÚtag_nameÚlowerÚget_attributerÂ   rÃ   Úcurrent_window_handlerË   r¶   Úswitch_to_windowÚ_BaseCase__element_clickÚStale_ExceptionrÔ   Úwait_for_element_clickableÚENI_Exceptionr¨   Újs_clickÚjquery_clickÚis_element_clickableÚ_BaseCase__js_clickr   r   rÇ   ÚSWITCH_TO_NEW_TABS_ON_CLICKÚ/_BaseCase__switch_to_newest_window_if_not_blankÚWAIT_FOR_RSC_ON_CLICKSrÓ   Úwait_for_angularjsÚMINI_TIMEOUTÚ_BaseCase__ad_block_as_neededÚ)_BaseCase__disable_beforeunload_as_neededr#   rÖ   r×   r!   rØ   rÙ   rÚ   Ú$_BaseCase__slow_mode_pause_if_activeÚ_BaseCase__set_esc_skip)r3   Úselectorrð   rç   Údelayrè   rí   Úoriginal_byÚelementrÜ   Úpre_window_countró   Znew_tabrô   rõ   Úcurrent_windowrà   Úlatest_window_countr8   r8   r9   r  ‘  sô   


ÿþ

û
(ÿþþ



*
*
2
û
.
ÿþ


:
ûÿ
ÿ&û



*
*
:û&ûÿþû,ÿýû
ú


ÿþ

(
.


(


zBaseCase.clickc                 C   s|   |   ¡  |stj}| jr,|tjkr,|  |¡}| jsL| jsL| j|||dd� n,| jrf| j|||dd� n| j|||dd� dS )a×  Similar to click(), but pauses for a brief moment before clicking.
        When used in combination with setting the user-agent, you can often
        bypass bot-detection by tricking websites into thinking that you're
        not a bot. (Useful on websites that block web automation tools.)
        To set the user-agent, use: ``--agent=AGENT``.
        Here's an example message from GitHub's bot-blocker:
        ``You have triggered an abuse detection mechanism...`` r«   )rð   rç   r.  gÍÌÌÌÌÌä?ç      Ð?N)r³   r   rÿ   r   r  rÕ   r  r  ©r3   r-  rð   rç   r8   r8   r9   Ú
slow_click£  s    
zBaseCase.slow_clickc                 C   s.  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}tj| j||||d�}|  	||¡ | j
s€| js€|  |||¡ |  ¡  |  ¡ ršt d¡ tj| j||||d�}d }ttƒ� | jj}W d   ƒ n1 sÚ0    Y  z.| jdkrøtdƒ‚t| jƒ}| |¡ ¡  W nd t�yv   | j||d�}	t |	¡}	|  |	¡}	d|	 }
d|	v�rb|  |
¡ nd}
|  |
|¡ Y n0 tj�rŠ|  ¡  n,| jtjd	� | jj|k�r¶|   ¡  |  !¡  | j
�r| jj|k�röt" #| j¡�sìt" $| jt%j&j'¡ |  (¡  n| j(d
d� n&| j�r|  )¡  n|  ¡ �r*t d¡ d S )Nrì   ç{®Gáz”?rê   úThis Exception will be caught.rï   zóvar targetElement1 = document.querySelector('%s');
                var clickEvent1 = document.createEvent('MouseEvents');
                clickEvent1.initEvent('dblclick', true, true);
                targetElement1.dispatchEvent(clickEvent1);ú:contains\(zïvar targetElement1 = arguments[0];
                    var clickEvent1 = document.createEvent('MouseEvents');
                    clickEvent1.initEvent('dblclick', true, true);
                    targetElement1.dispatchEvent(clickEvent1);ré   Trü   )*r³   r   rÿ   r   r  r  r$   r  r=   r  rÕ   r  r  rÔ   r½   rD   r¾   r   r¿   rÀ   r  r   Údouble_clickÚperformÚconvert_to_css_selectorÚreÚescapeÚ"_BaseCase__escape_quotes_if_neededrÈ   r&  r'  r(  r)  r*  r#   rÖ   r×   r!   rØ   rÙ   rÚ   r+  )r3   r-  rð   rç   rí   r/  r0  rÜ   ÚactionsÚcss_selectorZdouble_click_scriptr8   r8   r9   r:  ¸  s‚    
û
û
&



üÿ
ÿ



zBaseCase.double_clickc                 C   sŠ  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}tj| j||||d�}|  	||¡ | j
s€| js€|  |||¡ |  ¡  |  ¡ ršt d¡ tj| j||||d�}d}ttƒ� | jj}W d  ƒ n1 sÚ0    Y  z.| jdkrøtdƒ‚t| jƒ}| |¡ ¡  W nd t�yv   | j||d�}	t |	¡}	|  |	¡}	d|	 }
d|	v�rb|  |
¡ nd	}
|  |
|¡ Y n0 tj�rŠ|  ¡  n,| jtjd
� | jj|k�r¶|   ¡  |  !¡  | j
�r| jj|k�röt" #| j¡�sìt" $| jt%j&j'¡ |  (¡  n| j(dd� n&| j�r|  )¡  n|  ¡ �r*t d¡ | j*�r†|  +¡ �r†|  ,d¡dk�r†|t-j.k�r\|}|  d¡}|  /¡ }d|||g}| j0 1|¡ dS )z=(A context click is a right-click that opens a context menu.)rì   r7  Nrê   r8  rï   zövar targetElement1 = document.querySelector('%s');
                var clickEvent1 = document.createEvent('MouseEvents');
                clickEvent1.initEvent('contextmenu', true, true);
                targetElement1.dispatchEvent(clickEvent1);r9  zòvar targetElement1 = arguments[0];
                    var clickEvent1 = document.createEvent('MouseEvents');
                    clickEvent1.initEvent('contextmenu', true, true);
                    targetElement1.dispatchEvent(clickEvent1);ré   Trü   Úpause_recorderÚnor    Úr_clk)2r³   r   rÿ   r   r  r  r$   r  r=   r  rÕ   r  r  rÔ   r½   rD   r¾   r   r¿   rÀ   r  r   Úcontext_clickr;  r<  r=  r>  r?  rÈ   r&  r'  r(  r)  r*  r#   rÖ   r×   r!   rØ   rÙ   rÚ   r+  rÇ   Ú$_BaseCase__current_url_is_recordableÚget_session_storage_itemr   ÚXPATHrÉ   rF   r�   )r3   r-  rð   rç   rí   r/  r0  rÜ   r@  rA  Zright_click_scriptrÝ   rÞ   rß   r8   r8   r9   rE    s’    
û
û
&



üÿ
ÿ





zBaseCase.context_clickc                 C   s\   |   ¡  |stj}| jr,|tjkr,|  |¡}|D ]&}| j|||d� |dkr0t |¡ q0dS )aZ  This method clicks on a list of elements in succession.
        @Params
        selectors_list - The list of selectors to click on.
        by - The type of selector to search by (Default: "css selector").
        timeout - How long to wait for the selector to be visible.
        spacing - The amount of time to wait between clicks (in seconds).©rð   rç   r   N)r³   r   rÿ   r   r  r  rD   r¾   )r3   Úselectors_listrð   rç   Úspacingr-  r8   r8   r9   Úclick_chaina  s    	
zBaseCase.click_chainFc           
      C   sN  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rZ| jj|||d� dS |  	|¡rv|  
|||¡ dS | j|||d�}|  ||¡ | js¾| js¾|  |||¡ |  ¡ r¾t d¡ z | ¡  tjd }| |¡ W n~ ttf�yJ   |  ¡  t d¡ | j|||d�}ttƒ� | ¡  W d  ƒ n1 �s<0    Y  Y n t�y\   Y n0 | jdd� d}| j�r¨ttƒ� | jj}W d  ƒ n1 �sž0    Y  |  |¡}zà|  d	¡�sÜ| |¡ tj!�rŽ|  ¡  n²| |dd
… ¡ | j�sþ| j�r| jdd� n
t d¡ z| tj"¡ W nB t#�yh }	 z(d|	j$v �sTd|	j$v �rRn‚ W Y d}	~	n
d}	~	0 0 tj!�rŽ|  ¡  |  ¡ �rŽt d¡ W �n t�y®   |  ¡  t d¡ | j%|||d�}t d¡ |  d	¡�sæ| |¡ nÄ| |dd
… ¡ | j�s| j�r| jdd� n
t d¡ z| tj"¡ W nB t#�yr }	 z(d|	j$v �s^d|	j$v �r\n‚ W Y d}	~	n
d}	~	0 0 tj!�rª|  ¡  |  ¡ �rªt d¡ | j&�rªt d¡ Y n0 |�rì| 'd¡|k�rì|  d	¡�sìt( )d¡ | j*|||d� | j�r:| jj|k�r,t+ ,| j¡�s"t+ -| jt.j/j0¡ |  ¡  n| jdd� n| j�rJ|  1¡  dS )a}  This method updates an element's text field with new text.
        Has multiple parts:
        * Waits for the element to be visible.
        * Waits for the element to be interactive.
        * Clears the text field.
        * Types in the new text.
        * Hits Enter/Submit (if the text ends in "
").
        @Params
        selector - The selector of the text field.
        text - The new text to type into the text field.
        by - The type of selector to search by. (Default: "css selector")
        timeout - How long to wait for the selector to be visible.
        retry - If True, use JS if the Selenium text update fails.ré   NrI  r›   é*   r÷   Trü   Ú
rû   çÙÎ÷Sã¥‹?r¬   r­   çìQ¸…ëÁ?ç¸…ëQ¸ž?çš™™™™™™?Úvaluez,update_text() is falling back to JavaScript!rï   )2r³   r   ÚLARGE_TIMEOUTr   r  r  r´   rµ   r  r  Ú_BaseCase__shadow_typer  r  rÕ   r  r  r½   rD   r¾   Úclearr   Ú
BACK_SPACEÚ	send_keysr  r  rÔ   r   r¿   rÚ   r=   rÀ   Ú _BaseCase__get_type_checked_textÚendswithrÒ   ÚRETURNr   r¨   r  rÓ   r  r¸   rÎ   Ú	set_valuer#   rÖ   r×   r!   rØ   rÙ   r+  )
r3   r-  Útextrð   rç   Úretryr0  Ú
backspacesrÜ   rà   r8   r8   r9   Úupdate_textt  sÔ    

ÿ


ÿ
,
(



ÿþ

ÿ

ÿþ

ÿþý

zBaseCase.update_textc              	   C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rV| j ||¡ dS |  	|¡rv| j
|||dd� dS |dkrœ|dtjtjfv rœ|  ¡  dS | j|||d�}|dk�r.| d¡dk�r.| d¡dk�r.| d¡�r.| dd	¡ dd	¡ d
d	¡d	k�r.|  ¡  | tj| d¡ ¡ |  ¡  dS |  ||¡ | j�sX| j�sX|  |||¡ d}| j�r–ttƒ� | jj}W d  ƒ n1 �sŒ0    Y  |  |¡}zr| d¡�sº| |¡ nV| |dd… ¡ | j�sÜ| j�rê| jdd� n
t  d¡ | tj¡ tj!�r|  ¡  W n¨ t"t#f�yº   |  ¡  t  d¡ | j$|||d�}| d¡�s`| |¡ nV| |dd… ¡ | j�s‚| j�r�| jdd� n
t  d¡ | tj¡ tj!�r¶|  ¡  Y n0 | j�r
| jj|k�rüt% &| j¡�sòt% '| jt(j)j*¡ |  ¡  n| jdd� n| j�r|  +¡  dS )zwThe more-reliable version of driver.send_keys()
        Similar to update_text(), but won't clear the text field first.NF)Úclear_firstÚhtmlrN  rI  ú	r�   Ú ú rû   Trü   rO  r÷   ),r³   r   rT  r   r  r  r´   rµ   rX  r  rU  r   ZENTERr[  Úclick_active_elementÚwait_for_element_presentÚcountrZ  ÚreplacerÔ   ZTABr  rÕ   r  r  r   r¿   r=   rÀ   rY  rÚ   rD   r¾   rÒ   r  r  r  r#   rÖ   r×   r!   rØ   rÙ   r+  )r3   r-  r]  rð   rç   r0  rÜ   r8   r8   r9   Úadd_textõ  s’    

ÿÿÿþþý
(


ÿ

zBaseCase.add_textc                 C   sT   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j|||||d� dS )aô  Same as self.update_text()
        This method updates an element's text field with new text.
        Has multiple parts:
        * Waits for the element to be visible.
        * Waits for the element to be interactive.
        * Clears the text field.
        * Types in the new text.
        * Hits Enter/Submit (if the text ends in "
").
        @Params
        selector - The selector of the text field.
        text - The new text to type into the text field.
        by - The type of selector to search by. (Default: "css selector")
        timeout - How long to wait for the selector to be visible.
        retry - If True, use JS if the Selenium text update fails.
        DO NOT confuse self.type() with Python type()! They are different!
        ©rð   rç   r^  N)r³   r   rT  r   r  r  r`  ©r3   r-  r]  rð   rç   r^  r8   r8   r9   r  E  s    
zBaseCase.typec                 C   sR   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j||||d� dS )z_Same as self.add_text()
        Similar to update_text(), but won't clear the text field first.rI  N)r³   r   rT  r   r  r  rj  ©r3   r-  r]  rð   rç   r8   r8   r9   rX  `  s    
zBaseCase.send_keysc                 C   s¶  |   ¡ r| jj|||d� dS |  ¡  | j|||d�}| jrh|  ||¡\}}| j||d�}|  |t	j
¡ | jrÄ|  ¡ rÄ|  d¡dkrÄ| j||d�}|  d¡}|  ¡ }||g}	d|	||g}
| j |
¡ d	}| d
¡râ|dd… }d}|D ]}| |¡ qæ|�rT| j�s| j�r| jdd� n
t d¡ | tj¡ tj�rT| j�sJ|  ¡  n
t d¡ | j�rz|�rl|  ¡  n| jdd� n8| j�rŒ|  ¡  n&|  ¡ �r²t d¡ | j�r²t d¡ dS )z+Use send_keys() to press one key at a time.ré   NrI  rï   rB  rC  r    ÚpkeysFrN  rû   Trü   rO  ç333333Ã?rë   r7  )r´   rµ   Ú
press_keysrÔ   rg  rÕ   r  r<  r  r   ÚCSS_SELECTORrÇ   rF  rG  rÈ   rÉ   rF   r�   rZ  rX  r  rÚ   rD   r¾   r   r[  r   rÒ   rÓ   r+  r½   )r3   r-  r]  rð   rç   r0  rA  rÝ   rÞ   Úsel_texrß   Zpress_enterÚkeyr8   r8   r9   rp  k  sX    ÿ








zBaseCase.press_keysc                 C   sV   |   ¡  |  ||¡\}}|  ¡ r0| j |¡ dS | j||tjd�}| ¡  |  ¡  dS )z?Alternative to self.driver.find_element_by_*(SELECTOR).submit()NrI  )	r³   r  r´   rµ   Úsubmitr  r   rÿ   rÚ   )r3   r-  rð   r0  r8   r8   r9   rt  �  s    ÿzBaseCase.submitc                 C   sN  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rT| j |¡ dS |  	|¡rn|  
||¡ dS | j|||d�}| j|||d� z | ¡  tjd }| |¡ W nš ttf�y.   |  ¡  t d¡ | j|||d�}| ¡  ttƒ�$ tjd }| |¡ W d  ƒ n1 �s 0    Y  Y n t�yH   | ¡  Y n0 dS )aÓ  This method clears an element's text field.
        A clear() is already included with most methods that type text,
        such as self.type(), self.update_text(), etc.
        Does not use Demo Mode highlights, mainly because we expect
        that some users will be calling an unnecessary clear() before
        calling a method that already includes clear() as part of it.
        In case websites trigger an autofill after clearing a field,
        add backspaces to make sure autofill doesn't undo the clear.
        @Params
        selector - The selector of the text field.
        by - The type of selector to search by. (Default: "css selector")
        timeout - How long to wait for the selector to be visible.NrI  rM  r÷   )r³   r   rT  r   r  r  r´   rµ   Zclear_inputr  Ú_BaseCase__shadow_clearr  Ú	scroll_torV  r   rW  rX  r  r  rÔ   rD   r¾   r   r¿   )r3   r-  rð   rç   r0  r_  r8   r8   r9   rV  ª  s@    

ÿ

ÿ

.zBaseCase.clearc                 C   s:  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rT| j |¡ dS | j	|||d�}| 
¡ s¬| j||d�}t |¡}|  |¡}d| }|  |¡ |  ¡  dS | j|||d� z| tj¡ W n` ttf�y,   |  ¡  t d¡ | j|||d�}z| tj¡ W n t�y&   Y n0 Y n0 |  ¡  dS )z·Make the current page focus on an interactable element.
        If the element is not interactable, only scrolls to it.
        The "tab" key is another way of setting the page focus.NrI  rï   z%document.querySelector('%s').focus();ç¸…ëQ¸¾?)r³   r   rT  r   r  r  r´   rµ   Úfocusrg  Úis_displayedr<  r=  r>  r?  rÈ   rÚ   rv  rX  r   ÚNULLr  r  rÔ   rD   r¾   r  )r3   r-  rð   rç   r0  rA  Úscriptr8   r8   r9   rx  Ø  sD    
ÿ



ÿzBaseCase.focusc                 C   sF   |   ¡  d | _|  ¡ r$| j ¡  d S t | j¡ | j ¡  |  	¡  d S r.   )
r³   r\   r´   rµ   Úreloadr#   rÅ   r=   ÚrefreshrÔ   r‹   r8   r8   r9   Úrefresh_page   s    

zBaseCase.refresh_pagec                 C   s   |   ¡  dS )z*The shorter version of self.refresh_page()N©r~  r‹   r8   r8   r9   r}  
  s    zBaseCase.refreshc                 C   sd   |   ¡  d }|  ¡ r | j ¡ }n| jj}d|v r`zddlm} ||dd�}W n ty^   Y n0 |S )Nú%r   )ÚunquoteÚstrict)Úerrors)	r³   r´   rµ   Úget_current_urlr=   rÀ   Úurllib.parser�  r¿   )r3   rÀ   r�  r8   r8   r9   r„    s    zBaseCase.get_current_urlc                 C   s   |   ¡  |  d¡S )Nzreturn window.location.origin;)r³   rÈ   r‹   r8   r8   r9   rÉ     s    zBaseCase.get_originc                 O   s   | j |i |¤ŽS r.   )Úget_page_sourcer2   r8   r8   r9   Úget_html"  s    zBaseCase.get_htmlc                 O   s:   | j |i |¤Žr| j ¡ S |  ¡  | jr2t d¡ | jjS )NrR  )	r´   rµ   r†  rÔ   r½   rD   r¾   r=   Úpage_sourcer2   r8   r8   r9   r†  %  s    

zBaseCase.get_page_sourcec                 C   sf   |   ¡ r| j ¡ S |  ¡  ttƒ�, | jddtjd� t	 
d¡ W d   ƒ n1 sT0    Y  | jjS )NÚtitlerå   rI  rR  )r´   rµ   Ú	get_titlerÔ   r   r¿   rg  r   r(  rD   r¾   r=   r‰  r‹   r8   r8   r9   Úget_page_title-  s    

ÿ(zBaseCase.get_page_titlec                 C   s   |   ¡ S )z,The shorter version of self.get_page_title())r‹  r‹   r8   r8   r9   rŠ  8  s    zBaseCase.get_titlec                 C   s   |   ¡ r| j ¡ S |  d¡S )Nzreturn navigator.userAgent;)r´   rµ   Úget_user_agentrÈ   r‹   r8   r8   r9   rŒ  <  s    
zBaseCase.get_user_agentc                 C   s   |   ¡ r| j ¡ S |  d¡S )Nz4return navigator.language || navigator.languages[0];)r´   rµ   Úget_locale_coderÈ   r‹   r8   r8   r9   r�  A  s
    
ÿzBaseCase.get_locale_codec                 C   s*  |   ¡  |  ¡ r| j ¡  d S t| dd ƒr2|  ¡  d }ttƒ� | jj	}W d   ƒ n1 s\0    Y  d | _
| j ¡  ttƒ�& || jj	kr–| j ¡  W d   ƒ n1 sª0    Y  | jrä|  d¡}|  ¡ }dd||g}| j |¡ | jdk�r|  ¡  t d¡ | j ¡  t d¡ |  ¡  |  ¡  d S )NrÇ   r    Úgo_bkrd  rê   r7  )r³   r´   rµ   Úgo_backr·   Úsave_recorded_actionsr   r¿   r=   rÀ   r\   ÚbackrÇ   rÈ   rÉ   rF   r�   r  rÔ   rD   r¾   r}  rÚ   )r3   rÜ   rÝ   rÞ   rß   r8   r8   r9   r�  H  s4    

&

(



zBaseCase.go_backc                 C   s†   |   ¡  |  ¡ r| j ¡  d S t| dd ƒr2|  ¡  d | _| j ¡  | j	rr|  
d¡}|  ¡ }dd||g}| j |¡ |  ¡  |  ¡  d S )NrÇ   r    Úgo_fwrd  )r³   r´   rµ   Ú
go_forwardr·   r�  r\   r=   ÚforwardrÇ   rÈ   rÉ   rF   r�   rÔ   rÚ   ©r3   rÝ   rÞ   rß   r8   r8   r9   r“  d  s    


zBaseCase.go_forwardc                 C   s°   |   ¡  | j}t|tƒr | ¡ }|r–t|ƒdkr–t |¡rF|  |¡ q¬d| }t |¡rpd| _	|  |¡ d| _	q¬t
 d| ¡ |  ¡ dkr¬|  d¡ n|  ¡ dkr¬|  d¡ dS )a  Navigates the current browser window to the start_page.
        You can set the start_page on the command-line in three ways:
        '--start_page=URL', '--start-page=URL', or '--url=URL'.
        If the start_page is not set, then "about:blank" will be used.é   rœ   TFr�   r;   N)r³   Ú
start_pageÚ
isinstancerÁ   rÂ   r  r%   rÄ   r¶   rd   r¸   r¹   r„  )r3   r—  Únew_start_pager8   r8   r9   Úopen_start_pageu  s"    



zBaseCase.open_start_pagec                 C   s\   |   ¡  |  ¡ }||krXd|vsNd|vsN| d¡| d¡ksN| d¡d |krX|  |¡ dS )a:  Opens the url in the browser if it's not the current url (*).
        Parameters tagged on by search engines are ignored for this method.
        Eg. If the current url is:
            * https://www.bing.com/search?q=SeleniumBase&source=hp
            And the url privided by this method call is:
            * https://www.bing.com/search?q=SeleniumBase
            Then the urls will be considered the same,
            and no open() action will be performed.
        This method is primarily used by Recorder Mode script generation,
        where both clicks and opens are recorded. So if a click() action
        leads to an open() action, then the script generator will attempt
        to convert the open() action into open_if_not_url() so that the
        same page isn't opened again if the user is already on the page.ú?q=ú&r   N)r³   r„  ÚfindÚsplitr¶   )r3   rÛ   rÀ   r8   r8   r9   Úopen_if_not_url�  s    ÿþýüzBaseCase.open_if_not_urlc                 C   sP   |   ¡ r| j |¡S |  ¡  |  ||¡\}}|  |¡r@|  |¡S t | j||¡S )z/Returns whether the element exists in the HTML.)	r´   rµ   Úis_element_presentrÔ   r  r  Ú$_BaseCase__is_shadow_element_presentr$   r=   ©r3   r-  rð   r8   r8   r9   r   ¨  s    

zBaseCase.is_element_presentc                 C   sP   |   ¡ r| j |¡S |  ¡  |  ||¡\}}|  |¡r@|  |¡S t | j||¡S )z3Returns whether the element is visible on the page.)	r´   rµ   Úis_element_visiblerÔ   r  r  Ú$_BaseCase__is_shadow_element_visibler$   r=   r¢  r8   r8   r9   r£  ²  s    

zBaseCase.is_element_visiblec                 C   s<   |   ¡  |  ||¡\}}|  |¡r,|  |¡S t | j||¡S r.   )rÔ   r  r  Ú&_BaseCase__is_shadow_element_clickabler$   r"  r=   r¢  r8   r8   r9   r"  ¼  s
    

zBaseCase.is_element_clickablec                 C   s<   |   ¡  |  ||¡\}}|  |¡r,|  |¡S t | j||¡S r.   )rÔ   r  r  Ú$_BaseCase__is_shadow_element_enabledr$   Úis_element_enabledr=   r¢  r8   r8   r9   r§  Ã  s
    

zBaseCase.is_element_enabledÚbodyc                 C   s`   |   ¡ r| j ||¡S |  ¡  t d¡ |  ||¡\}}|  |¡rN|  ||¡S t	 | j
|||¡S )z=Returns whether the text substring is visible in the element.ç{®Gáz„?)r´   rµ   Úis_text_visiblerÔ   rD   r¾   r  r  Ú!_BaseCase__is_shadow_text_visibler$   r=   ©r3   r]  r-  rð   r8   r8   r9   rª  Ê  s    

zBaseCase.is_text_visiblec                 C   s`   |   ¡ r| j ||¡S |  ¡  t d¡ |  ||¡\}}|  |¡rN|  ||¡S t	 | j
|||¡S )zˆReturns whether the text is exactly equal to the element text.
        (Leading and trailing whitespace is ignored in the verification.)r©  )r´   rµ   Úis_exact_text_visiblerÔ   rD   r¾   r  r  Ú'_BaseCase__is_shadow_exact_text_visibler$   r=   r¬  r8   r8   r9   r­  Õ  s    


ÿzBaseCase.is_exact_text_visiblec                 C   sH   |   ¡  t d¡ |  ||¡\}}|  |¡r6|  |¡S tj| j||d�S )zrReturns whether the element has any non-empty text visible.
        Whitespace-only text is considered empty text.r©  rï   )	rÔ   rD   r¾   r  r  Ú+_BaseCase__is_shadow_non_empty_text_visibler$   Úis_non_empty_text_visibler=   r¢  r8   r8   r9   r°  ã  s    


ÿz"BaseCase.is_non_empty_text_visiblec                 C   sh   |   ¡ r| jj|||d�S |  ¡  t d¡ |  ||¡\}}|  |¡rT|  |||¡S t	 | j
||||¡S )zReturns True if the element attribute/value is found.
        If the value is not specified, the attribute only needs to exist.©rS  r©  )r´   rµ   Úis_attribute_presentrÔ   rD   r¾   r  r  Ú&_BaseCase__is_shadow_attribute_presentr$   r=   ©r3   r-  Ú	attributerS  rð   r8   r8   r9   r²  ï  s    ÿ

ÿÿzBaseCase.is_attribute_presentc                 C   s$   |   ¡  t d¡ tj| j|dd�S )z9Returns whether there's an exact match for the link text.r©  ú	link textrï   ©rÔ   rD   r¾   r$   r£  r=   )r3   Ú	link_textr8   r8   r9   r    s
    
ÿzBaseCase.is_link_text_visiblec                 C   s$   |   ¡  t d¡ tj| j|dd�S )z<Returns whether there's a substring match for the link text.r©  úpartial link textrï   r·  )r3   Úpartial_link_textr8   r8   r9   r
    s
    
ÿz%BaseCase.is_partial_link_text_visiblec                 C   s@   |   ¡  |  ¡ }| d¡}|D ]}|j ¡ | ¡ kr dS qdS )z«Returns True if the link text appears in the HTML of the page.
        The element doesn't need to be visible,
        such as elements hidden inside a dropdown selection.rò   TF)rÔ   Úget_beautiful_soupÚfind_allr]  rÂ   ©r3   r¸  ÚsoupÚ
html_linksÚ	html_linkr8   r8   r9   Úis_link_text_present  s    
zBaseCase.is_link_text_presentc                 C   s@   |   ¡  |  ¡ }| d¡}|D ]}| ¡ |j ¡ v r dS qdS )z®Returns True if the partial link appears in the HTML of the page.
        The element doesn't need to be visible,
        such as elements hidden inside a dropdown selection.rò   TF)rÔ   r»  r¼  rÂ   r]  r½  r8   r8   r9   Úis_partial_link_text_present  s    
z%BaseCase.is_partial_link_text_presentc                 C   sˆ   |   ¡  |  ¡ }| d¡}|D ]N}|j ¡ | ¡ kr| |¡rP| |¡}|  S |rftd||f ƒ‚q dS q|r€td| ƒ‚ndS dS )zÐFinds a link by link text and then returns the attribute's value.
        If the link text or attribute cannot be found, an exception will
        get raised if hard_fail is True (otherwise None is returned).rò   z2Unable to find attribute {%s} from link text {%s}!NúLink text {%s} was not found!)rÔ   r»  r¼  r]  rÂ   Úhas_attrrÌ   r¿   )r3   r¸  rµ  Ú	hard_failr¾  r¿  rÀ  Úattribute_valuer8   r8   r9   Úget_link_attribute+  s$    


ÿÿzBaseCase.get_link_attributec                 C   s   |   |||¡S )zúSame as self.get_link_attribute()
        Finds a link by link text and then returns the attribute's value.
        If the link text or attribute cannot be found, an exception will
        get raised if hard_fail is True (otherwise None is returned).)rÇ  )r3   r¸  rµ  rÅ  r8   r8   r9   Úget_link_text_attributeC  s    z BaseCase.get_link_text_attributec           	      C   s�   |   ¡  |  ¡ }| d¡}|D ]N}| ¡ |j ¡ v r| |¡rP| |¡}|  S |rftd||f ƒ‚q dS q|rˆd| }t 	d|¡ ndS dS )zèFinds a link by partial link text and then returns the attribute's
        value. If the partial link text or attribute cannot be found, an
        exception will get raised if hard_fail is True (otherwise None
        is returned).rò   z:Unable to find attribute {%s} from partial link text {%s}!Nú%Partial Link text {%s} was not found!ÚLinkTextNotFoundException)
rÔ   r»  r¼  rÂ   r]  rÄ  rÌ   r¿   r$   Útimeout_exception)	r3   r¸  rµ  rÅ  r¾  r¿  rÀ  rÆ  r¨   r8   r8   r9   Úget_partial_link_text_attributeJ  s&    


ÿÿz(BaseCase.get_partial_link_text_attributec              
   C   sb  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rL| jj||d� ¡  dS |  	¡  |  
|¡}|  ¡ rv| j |¡ dS | jdk�rF| j�r4| j||d� z| j|dd� W n* tyÔ   | j||d�}|  |¡ Y n0 d}tj}| j|dd�}|  |¡}z&t |¡}|  |¡}|  |||¡ W n t�y2   Y n0 | j|dd� dS |  |¡�s`| j||d� | j�s„| j�s„|  ¡ �r„t d¡ d}t tƒ� | j!j"}W d  ƒ n1 �s°0    Y  t#| j!j$ƒ}zv| j|dd�}| j%|dd� z|  &|¡ W nD t't(t)f�y6   |  *¡  t d	¡ | j||d�}|  &|¡ Y n0 W �n t�yN   d
}	|  +|dd
¡}
|
�rpd| }d}	|	�s¬|  ,|d
¡}|�r¬| -d¡�s t. /|¡�r¬d| }d}	|	�sÒ|  +|dd
¡}|�rÒd| }d}	|	�sø|  +|dd
¡}|�rød| }d}	d
}|	�r*|  0|¡�r|  |¡ d}n|  1||¡}|�sJ| j|tj2d�}|  &|¡ Y n0 t#| j!j$ƒ}||k�rŽ| j3�s„tj4�rŽ| j!j"|k�rŽ|  5¡  n"||d k�r°|dk�r°|  6d¡ tj7�rêt tƒ� |  *¡  W d  ƒ n1 �sà0    Y  | j�r8| j!j"|k�r*t8 9| j!¡�s t8 :| j!t;j<j=¡ |  >¡  n| j>dd� n&| j�rJ|  ?¡  n|  ¡ �r^t d¡ dS )z'This method clicks link text on a page.ré   Nrê   r¶  rï   rd  r›   r®   r÷   FÚidú	[id="%s"]Tú/ú[href="%s"]úng-clickú[ng-click="%s"]rô   ú[onclick="%s"]r�   r   rû   rü   )@r³   r   rÿ   r   r  r´   rµ   Úfind_elementr  rþ   rY  Ú
click_linkr  rÕ   Úwait_for_link_text_presentÚ _BaseCase__jquery_slow_scroll_tor¿   Úwait_for_link_text_visibleÚ!_BaseCase__slow_scroll_to_elementÚ
HIGHLIGHTSr<  Ú,_BaseCase__make_css_match_first_element_onlyr=  r>  r?  Ú _BaseCase__highlight_with_jqueryr  rÁ  r  r½   rD   r¾   r   r=   rÀ   r  r  r  r  r  r  ÚECI_ExceptionrÔ   rÇ  Ú"_BaseCase__get_href_from_link_textrÆ   r%   rÄ   r£  Ú#_BaseCase__click_dropdown_link_textr(  rÇ   r$  r%  r  rÒ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r+  )r3   r¸  rç   r0  Úo_bsÚloopsr-  rÜ   r1  Ú	found_cssÚtext_idÚlink_cssró   Úngclickrô   Úsuccessr3  r8   r8   r9   r  f  sò    

ÿÿ





(
ÿ
ÿÿÿýû
ú


ÿþ

(


zBaseCase.click_link_textc              
   C   s4  |   ¡  |stj}| jr,|tjkr,|  |¡}|  |¡}|  ¡ rV| jj||d� 	¡  dS |  
|¡sn| j||d� d}ttƒ� | jj}W d  ƒ n1 s˜0    Y  t| jjƒ}zv| j|dd�}| j|dd� z|  |¡ W nD tttf�y   |  ¡  t d¡ | j||d�}|  |¡ Y n0 W �n t�y6   d}|  |dd¡}|�rXd	| }d
}|�s”|  |d¡}	|	�r”|	 d¡�sˆt |	¡�r”d|	 }d
}|�sº|  |dd¡}
|
�rºd|
 }d
}|�sà|  |dd¡}|�ràd| }d
}d}|�r|   |¡�r|  	|¡ d
}n|  !||¡}|�s2| j|tj"d�}|  |¡ Y n0 t| jjƒ}||k�rv| j#�sltj$�rv| jj|k�rv|  %¡  n"||d k�r˜|dk�r˜|  &d¡ tj'�rÒttƒ� |  ¡  W d  ƒ n1 �sÈ0    Y  | j(�r | jj|k�rt) *| j¡�st) +| jt,j-j.¡ |  /¡  n| j/d
d� n| j0�r0|  1¡  dS )z3This method clicks the partial link text on a page.ré   Nr®   r¶  rï   r÷   FrÍ  rÎ  TrÏ  rÐ  rÑ  rÒ  rô   rÓ  r�   r   rû   rü   )2r³   r   rÿ   r   r  rY  r´   rµ   rÔ  r  rÂ  Ú"wait_for_partial_link_text_presentr   r¿   r=   rÀ   r  r  Úwait_for_partial_link_textr  r  r  r  rÝ  rÔ   rD   r¾   rÌ  Ú*_BaseCase__get_href_from_partial_link_textrÆ   r%   rÄ   r£  Ú+_BaseCase__click_dropdown_partial_link_textr(  rÇ   r$  r%  r  rÒ   rÕ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r  r+  )r3   rº  rç   rÜ   r1  r0  râ  rã  rä  ró   rå  rô   ræ  r3  r8   r8   r9   r  é  sÌ    


ÿ
&ÿÿ
ÿÿÿÿÿ
ÿÿÿýû
ú


ÿþ

(
z BaseCase.click_partial_link_textc              
   C   st  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rP| j |¡S |  	|¡rf|  
||¡S |  ¡  t d¡ t | j|||¡}zR|j}| jdkrÂ|j ¡ dv r¶| d¡}qÚ| d¡}n|j ¡ dv rÚ| d¡}W n’ tttf�yn   |  ¡  t d¡ t | j|||¡}|j}| jdk�rP|j ¡ dv �rD| d¡}n
| d¡}n|j ¡ dv �rj| d¡}Y n0 |S )Nr©  rê   ©ÚinputÚtextarearS  Ú	innerTextrP  )r³   r   rT  r   r  r  r´   rµ   Úget_textr  Ú_BaseCase__get_shadow_textrÔ   rD   r¾   r$   r  r=   r]  r  r  r  r  Úget_propertyr  r  r   )r3   r-  rð   rç   r0  Úelement_textr8   r8   r9   rï  Y  sJ    



ÿ


ÿzBaseCase.get_textc              
   C   s&  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rd|rV| j ||¡S | j 	||¡S |  
¡  t d¡ |  |¡r�| j|||d�S t | j|||¡}z| 	|¡}W nF tttfyö   |  
¡  t d¡ t | j|||¡}| 	|¡}Y n0 |du�r|S |�rtd||f ƒ‚ndS dS )zÌThis method uses JavaScript to get the value of an attribute.
        If the attribute doesn't exist or isn't found, an exception will
        get raised if hard_fail is True (otherwise None is returned).r©  ré   rP  Nz#Element {%s} has no attribute {%s}!)r³   r   rT  r   r  r  r´   rµ   Zget_element_attributer  rÔ   rD   r¾   r  Ú_BaseCase__get_shadow_attributer$   rg  r=   r  r  r   r¿   )r3   r-  rµ  rð   rç   rÅ  r0  rÆ  r8   r8   r9   r  ‚  sJ    


ÿ
ÿ

ÿ
ÿÿzBaseCase.get_attributec                 C   sJ  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|}|}|rŽ| j||d�rŽttƒ�  | j	|||d� W d  ƒ n1 s„0    Y  t
 |¡}|  |¡}t
 |¡}|  |¡}| j||d�}	t
 |	¡}	|  |	¡}	d|	||f }
|  |
¡ | j�rF|  ¡ �rF|  d¡dk�rF|  d¡}|  ¡ }|||g}d|||g}| j |¡ dS )	z~This method uses JavaScript to set/update an attribute.
        Only the first matching selector from querySelector() is used.rï   rI  Nz5document.querySelector('%s').setAttribute('%s','%s');rB  rC  r    Ús_at_)r³   r   rT  r   r  r  r£  r   r¿   rv  r=  r>  r?  r<  rÈ   rÇ   rF  rG  rÉ   rF   r�   )r3   r-  rµ  rS  rð   rç   rè   Úoriginal_attributeÚoriginal_valuerA  r{  rÝ   rÞ   Úsele_attr_valrß   r8   r8   r9   Úset_attributeµ  s<    

.





ÿÿ


zBaseCase.set_attributec                 C   s   |   ¡  |  ||¡\}}|  ¡ r4| j |||¡ dS |}|}t |¡}|  |¡}t |¡}|  |¡}| j||d�}t |¡}|  |¡}d|||f }t	t
ƒ� |  |¡ W d  ƒ n1 s¼0    Y  | j�r|  ¡ �r|  d¡dk�r|  d¡}	|  ¡ }
|||g}d||
|	g}| j |¡ dS )a  This method uses JavaScript to set/update a common attribute.
        All matching selectors from querySelectorAll() are used.
        Example => (Make all links on a website redirect to Google):
        self.set_attributes("a", "href", "https://google.com")Nrï   zÛvar $elements = document.querySelectorAll('%s');
                  var index = 0, length = $elements.length;
                  for(; index < length; index++){
                  $elements[index].setAttribute('%s','%s');}rB  rC  r    Ús_ats)r³   r  r´   rµ   Úset_attributesr=  r>  r?  r<  r   r¿   rÈ   rÇ   rF  rG  rÉ   rF   r�   )r3   r-  rµ  rS  rð   rõ  rö  rA  r{  rÝ   rÞ   r÷  rß   r8   r8   r9   rú  ß  s:    





ýý
(

zBaseCase.set_attributesc                 C   s   | j ||||d� dS )aQ  Same as set_attributes(), but using querySelectorAll naming scheme.
        This method uses JavaScript to set/update a common attribute.
        All matching selectors from querySelectorAll() are used.
        Example => (Make all links on a website redirect to Google):
        self.set_attribute_all("a", "href", "https://google.com")rï   N)rú  r´  r8   r8   r9   Úset_attribute_all  s    zBaseCase.set_attribute_allc                 C   sÒ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j||d�r‚ttƒ�  | j	|||d� W d  ƒ n1 sx0    Y  t
 |¡}|  |¡}| j||d�}t
 |¡}|  |¡}d||f }|  |¡ dS )zzThis method uses JavaScript to remove an attribute.
        Only the first matching selector from querySelector() is used.rï   rI  Nz3document.querySelector('%s').removeAttribute('%s');)r³   r   rT  r   r  r  r£  r   r¿   rv  r=  r>  r?  r<  rÈ   )r3   r-  rµ  rð   rç   rA  r{  r8   r8   r9   Úremove_attribute  s&    

.



þzBaseCase.remove_attributec                 C   s�   |   ¡  |  ||¡\}}t |¡}|  |¡}| j||d�}t |¡}|  |¡}d||f }ttƒ� |  |¡ W d  ƒ n1 s‚0    Y  dS )zzThis method uses JavaScript to remove a common attribute.
        All matching selectors from querySelectorAll() are used.rï   zÙvar $elements = document.querySelectorAll('%s');
                  var index = 0, length = $elements.length;
                  for(; index < length; index++){
                  $elements[index].removeAttribute('%s');}N)	r³   r  r=  r>  r?  r<  r   r¿   rÈ   )r3   r-  rµ  rð   rA  r{  r8   r8   r9   Úremove_attributes%  s    



þý
zBaseCase.remove_attributesc                 C   s(   |   ¡ r| j ¡  dS |  ddd¡ dS )zqAll `target="_blank"` links become `target="_self"`.
        This prevents those links from opening in a new tab.Nz[target="_blank"]rõ   Ú_self)r´   rµ   Úinternalize_linksrú  r‹   r8   r8   r9   rÿ  9  s    
zBaseCase.internalize_linksc                 C   sF   |   ¡ r| j |¡S t|tƒr8|s(tj}| j|||d�}|jddd�S )zbReturns the parent element.
        If element is a string, then finds element first via selector.rI  Úxpathz..©rð   rS  )	r´   rµ   Ú
get_parentr˜  rÁ   r   rT  rg  rÔ  )r3   r0  rð   rç   r8   r8   r9   r  A  s    
ÿzBaseCase.get_parentc              
   C   sÂ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡  t d¡ t	 
| j|||¡}z| |¡}W nF tttfy´   |  ¡  t d¡ t	 
| j|||¡}| |¡}Y n0 |s¾dS |S )ac  Returns the property value of an element.
        This is not the same as self.get_property_value(), which returns
        the value of an element's computed style using a different algorithm.
        If no result is found, an empty string (instead of None) is returned.
        Example:
            html_text = self.get_property(SELECTOR, "textContent") r©  rP  rd  )r³   r   rT  r   r  r  rÔ   rD   r¾   r$   rg  r=   rñ  r  r  r   )r3   r-  Úpropertyrð   rç   r0  Zproperty_valuer8   r8   r9   rñ  N  s.    	


ÿ

ÿzBaseCase.get_propertyc                 C   s   |   ¡  | j|d||d�S )a  Returns the text that appears in the HTML for an element.
        This is different from "self.get_text(selector, by="css selector")"
        because that only returns the visible text on a page for an element,
        rather than the HTML text that's being returned from this method.ZtextContent)r  rð   rç   )r³   rñ  r5  r8   r8   r9   Úget_text_contento  s    ÿzBaseCase.get_text_contentc                 C   sä   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡  t | j	|||¡}z| j
||d�}W n< ty¤   d| }|  ||¡}|durš| Y S Y dS Y n0 t |¡}|  |¡}d||f }|  |¡}|durÜ|S dS dS )zàReturns the property value of a page element's computed style.
        Example:
            opacity = self.get_property_value("html body a", "opacity")
            self.assertTrue(float(opacity) > 0, "Element not visible!") rï   z‚var $elm = arguments[0];
                $val = window.getComputedStyle($elm).getPropertyValue('%s');
                return $val;Nrd  z–var $elm = document.querySelector('%s');
                  $val = window.getComputedStyle($elm).getPropertyValue('%s');
                  return $val;)r³   r   rT  r   r  r  rÔ   r$   rg  r=   r<  r¿   rÈ   r=  r>  r?  )r3   r-  r  rð   rç   r0  r{  rS  r8   r8   r9   Úget_property_value{  s<    

ÿþÿ

þ
zBaseCase.get_property_valuec                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|d||d�S )z3Extracts the URL from an image element on the page.Úsrc)rµ  rð   rç   )r³   r   rT  r   r  r  r5  r8   r8   r9   Úget_image_url¥  s    
ÿzBaseCase.get_image_urlc                 C   s–   |   ||¡\}}|  ¡ rL| j |¡}|rH|dkrHt|ƒ|krH|d|… }|S |  ¡  t d¡ | jj	||d�}|r’|dkr’t|ƒ|kr’|d|… }|S )z¯Returns a list of matching WebElements.
        Elements could be either hidden or visible on the page.
        If "limit" is set and > 0, will only return that many elements.r   Nrë   r  )
r  r´   rµ   Ú
select_allr  rÔ   rD   r¾   r=   Úfind_elements©r3   r-  rð   ÚlimitÚelementsr8   r8   r9   r	  °  s    
zBaseCase.find_elementsc                 C   sp   |   ||¡\}}|  ¡ rL| j |¡}|rH|dkrHt|ƒ|krH|d|… }|S |  ¡  t d¡ t | j	|||¡S )z€Returns a list of matching WebElements that are visible.
        If "limit" is set and > 0, will only return that many elements.r   Nrë   )
r  r´   rµ   Úfind_visible_elementsr  rÔ   rD   r¾   r$   r=   r
  r8   r8   r9   r  Á  s    

ÿzBaseCase.find_visible_elementsc                 C   sà  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rZ| jj|||d� dS |  	¡  |  
¡ r„t d¡ | jr„t d¡ | j|||d�}ttƒ�2 | ¡ sÀt d¡ | jrÀt d¡ W d  ƒ n1 sÔ0    Y  | j||d�}d}ttƒ� | jj}W d  ƒ n1 �s0    Y  t| jjƒ}	d}
|D �]f}|�r\|dk�r\|
|k�r\ dS zP| ¡ �rª|�rx|  |¡ | jd	k�r’|  d
|¡ n| ¡  |
d7 }
|  	¡  W nî t�yÆ   Y �q6Y nÖ ttf�yš   |  	¡  t d¡ zP| ¡ �r8|�r|  |¡ | jd	k�r |  d
|¡ n| ¡  |
d7 }
|  	¡  W nZ ttf�y”   t| jjƒ}||	k�rŠ| j�s‚tj�rŠ| jj|k�rŠ|   ¡  Y Y  dS 0 Y n0 �q6t| jjƒ}||	k�rÜ| j�sÔtj�rÜ| jj|k�rÜ|   ¡  dS )aî  Finds all matching page elements and clicks visible ones in order.
        If a click reloads or opens a new page, the clicking will stop.
        If no matching elements appear, an Exception will be raised.
        If "limit" is set and > 0, will only click that many elements.
        Also clicks elements that become visible from previous clicks.
        Works best for actions such as clicking all checkboxes on a page.
        Example: self.click_visible_elements('input[type="checkbox"]')©rè   Nrw  ç¸…ëQ¸®?rI  r÷   rï   r   rê   rñ   r�   )!r³   r   rÿ   r   r  r  r´   rµ   Úclick_visible_elementsrÔ   r½   rD   r¾   rÓ   rg  r   r¿   ry  r	  r=   rÀ   r  r  r  r  rÈ   r  rÝ  r  r  rÇ   r$  r%  )r3   r-  rð   r  rç   rè   r0  r  rÜ   r1  Zclick_countr3  r8   r8   r9   r  Ð  sœ    



ÿ

(
(






ÿÿýû
ú
ÿýû
ú
zBaseCase.click_visible_elementsc              
   C   sì  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rZ| jj|||d� dS |  	¡  | j
|||d� | j||d�}t|ƒ|k ržtd|||f ƒ‚|d }|dk r²d}|| }d}ttƒ� | jj}W d  ƒ n1 sä0    Y  t| jjƒ}	z|�r|  |¡ |  |¡ W n’ tttf�yª   t d¡ |  	¡  | j
|||d� | j||d�}t|ƒ|k �r~td|||f ƒ‚|d }|dk �r”d}|| }|  |¡ Y n0 t| jjƒ}
|
|	k�rè| j�sàtj�rè| jj|k�rè|  ¡  dS )	zÇFinds all matching page elements and clicks the nth visible one.
        Example: self.click_nth_visible_element('[type="checkbox"]', 5)
                (Clicks the 5th visible checkbox on the page.)r  NrI  rï   zBNot enough matching {%s} elements of type {%s} to click number %s!r�   r   rw  )r³   r   rÿ   r   r  r  r´   rµ   Úclick_nth_visible_elementrÔ   rg  r  r  r¿   r   r=   rÀ   r  r  r  r  r  rÝ  rD   r¾   rÇ   r$  r%  )r3   r-  Únumberrð   rç   rè   r  r0  rÜ   r1  r3  r8   r8   r9   r  0	  sp    
ÿÿ
&

ÿÿ
ÿýû
ú
z"BaseCase.click_nth_visible_elementc                 C   s²   |   ¡ r| jj|||d� dS |  ¡  | j||d�rF| j|||d� nh|dkr®ttƒ�* | j|||d� |  	d¡ W d  ƒ n1 s†0    Y  | j||d�r®| j|||d� dS )aT  If the page selector exists and is visible, clicks on the element.
        This method only clicks on the first matching element found.
        Use click_visible_elements() to click all matching elements.
        If a "timeout" is provided, waits that long for the element
        to appear before giving up and returning without a click().ræ   Nrï   )rð   rè   r   rI  r®   )
r´   rµ   Úclick_if_visiblerÔ   r£  r  r   r¿   r  r¾   )r3   r-  rð   rç   rè   r8   r8   r9   r  o	  s    
ÿ(zBaseCase.click_if_visiblec                 C   sX  |   ¡ r| j ¡  d S |  ¡  d }ttƒ� | jj}W d   ƒ n1 sH0    Y  t| jj	ƒ}| j
r~t | j¡}|  |¡ d S |  d¡ t| jj	ƒ}||kr¼| j
s´tjr¼| jj|kr¼|  ¡  tjrÌ|  ¡  n*| jtjd� | jj|krö|  ¡  |  ¡  | j�rD| jj|k�r6t | j¡�s,t | jtjj¡ |  ¡  n| jdd� n| j�rT|  ¡  d S )Nzdocument.activeElement.click();ré   Trü   ) r´   rµ   rf  rÔ   r   r¿   r=   rÀ   r  r  rÇ   r#   Úget_active_element_cssr  rÈ   r   r$  r%  r&  r'  r(  r)  r*  rÕ   rÖ   r×   r!   rØ   rÙ   rÚ   r  r+  )r3   rÜ   r1  r-  r3  r8   r8   r9   rf  †	  sJ    

&

ÿýû
ú


zBaseCase.click_active_elementc	           	      C   s(   |   ¡  | j||||d||||d�	 dS )a<  Click an element at an {X,Y}-offset location.
        {0,0} is the top-left corner of the element.
        If center==True, {0,0} becomes the center of the element.
        If mark==True, will draw a dot at location. (Useful for debugging)
        In Demo Mode, mark becomes True unless set to False. (Default: None)F©rð   ÚdoubleÚmarkrç   Úcenterrè   N©r³   Ú_BaseCase__click_with_offset©	r3   r-  ÚxÚyrð   r  rç   r  rè   r8   r8   r9   Úclick_with_offset³	  s    ÷zBaseCase.click_with_offsetc	           	      C   s(   |   ¡  | j||||d||||d�	 dS )aC  Double click an element at an {X,Y}-offset location.
        {0,0} is the top-left corner of the element.
        If center==True, {0,0} becomes the center of the element.
        If mark==True, will draw a dot at location. (Useful for debugging)
        In Demo Mode, mark becomes True unless set to False. (Default: None)Tr  Nr  r  r8   r8   r9   Údouble_click_with_offsetÐ	  s    ÷z!BaseCase.double_click_with_offsetc                 C   s’   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rP| j |¡S | j	|d||d�}|dkrz|dkrzt
dƒ‚t| j	|d||dd�ƒS )	a3  Determines if a checkbox or a radio button element is checked.
        Returns True if the element is checked.
        Returns False if the element is not checked.
        If the element is not present on the page, raises an exception.
        If the element is not a checkbox or radio, raises an exception.r  rI  ZcheckboxÚradioz/Expecting a checkbox or a radio button element!ÚcheckedF)rð   rç   rÅ  )r³   r   rÿ   r   r  r  r´   rµ   Ú
is_checkedr  r¿   Úbool)r3   r-  rð   rç   Úkindr8   r8   r9   r"  í	  s     

ÿÿzBaseCase.is_checkedc                 C   s   | j |||d�S )zSame as is_checked()rI  )r"  r5  r8   r8   r9   Úis_selected
  s    zBaseCase.is_selectedc                 C   s.  |   ¡  |  ||¡\}}|  ¡ r0| j |¡ dS | j||d��s*| j||d�r^| j||d� nÌ| j||d�}|  	d|¡}t
tƒ� |  	d|¡ W d  ƒ n1 s¢0    Y  | j||d�rÊ| j||d� n(| j||d�}d| _| j|dd� d| _t
tƒ� |  	d||¡ W d  ƒ n1 �s 0    Y  dS )	z<If a checkbox or radio button is not checked, will check it.Nrï   ú"return arguments[0].style.opacity;ú#arguments[0].style.opacity="0.001";Trå   Fú*arguments[0].style.opacity="arguments[1]";)r³   r  r´   rµ   Úcheck_if_uncheckedr"  r£  r  rg  rÈ   r   r¿   r<  re   r   ©r3   r-  rð   r0  Zopacityr8   r8   r9   r)  
  s8    ÿ
ÿ"
ýzBaseCase.check_if_uncheckedc                 C   s   | j ||d� dS )zSame as check_if_unchecked()rï   N)r)  r¢  r8   r8   r9   Úselect_if_unselected+
  s    zBaseCase.select_if_unselectedc                 C   s.  |   ¡  |  ||¡\}}|  ¡ r0| j |¡ dS | j||d��r*| j||d�r^| j||d� nÌ| j||d�}|  	d|¡}t
tƒ� |  	d|¡ W d  ƒ n1 s¢0    Y  | j||d�rÊ| j||d� n(| j||d�}d| _| j|dd� d| _t
tƒ� |  	d||¡ W d  ƒ n1 �s 0    Y  dS )	z*If a checkbox is checked, will uncheck it.Nrï   r&  r'  Trå   Fr(  )r³   r  r´   rµ   Úuncheck_if_checkedr"  r£  r  rg  rÈ   r   r¿   r<  re   r   r*  r8   r8   r9   r,  /
  s8    ÿ
ÿ"
ýzBaseCase.uncheck_if_checkedc                 C   s   | j ||d� dS )zSame as uncheck_if_checked()rï   N)r,  r¢  r8   r8   r9   Úunselect_if_selectedR
  s    zBaseCase.unselect_if_selectedc                 C   sø   |   ¡  |  ||¡\}}| j||d�r*dS |  ¡ }| d¡}|D ]²}d}| d¡rlt|d ƒdkrl|d }nX| d¡r�t|d ƒdkr�|d }n4| d¡r@t|d ƒdkr@d	 |d ¡}d
| }nq@|  |¡ | j||d�rê|  	¡   dS |  	¡  q@dS )z`Returns True if the selector's element is located in an iframe.
        Otherwise returns False.rï   FÚiframeNr”   r   rÍ  Úclassre  ú[class="%s"]T)
r³   r  r   r»  ÚselectrÄ  r  ÚjoinÚswitch_to_frameÚswitch_to_default_content©r3   r-  rð   r¾  Ziframe_listr.  Ziframe_identifierZiframe_classr8   r8   r9   Úis_element_in_an_iframeV
  s,    





z BaseCase.is_element_in_an_iframec              	   C   sÜ  |   ¡  |  ¡ r*t d¡ | jr*t d¡ |  ||¡\}}| j||d�rLdS |  ¡ }| d¡}|D �]}d}| 	d¡r�t
|d ƒdkr�|d }nX| 	d¡r´t
|d ƒdkr´|d }n4| 	d¡rbt
|d ƒdkrbd	 |d ¡}d
| }nqbttƒ�X | j|dd� |  ¡ �rt d¡ | j||d��r:|W  d  ƒ   S W d  ƒ n1 �sP0    Y  |  ¡  |  ¡ rbt d¡ qbz*| j|dd� | j�rœ|  jd7  _|W S  t�yÖ   | j||d��rÆY dS td| ƒ‚Y n0 dS )a  Set driver control to the iframe containing element (assuming the
        element is in a single-nested iframe) and returns the iframe name.
        If element is not in an iframe, returns None, and nothing happens.
        May not work if multiple iframes are nested within each other.r›   rï   Nr.  r”   r   rÍ  r/  re  r0  r�   ré   r7  rd  z3Could not switch to iframe containing element {%s}!)rÔ   r½   rD   r¾   rÓ   r  r   r»  r1  rÄ  r  r2  r   r¿   r3  r4  rL   r5  r8   r8   r9   Úswitch_to_frame_of_elementq
  sT    









6ÿÿz#BaseCase.switch_to_frame_of_elementc           
      C   sø   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}|  ¡ r\| j |¡ d S | j	|||d� |  
||¡ | j||d� t d¡ t | j||¡}| jrô|  ¡ rô|  d¡dkrô|tjkrÊ|}|  d¡}|  ¡ }d|||g}	| j |	¡ |S )NrI  rï   rë   rB  rC  r    Úhover)r³   r   rÿ   r   r  r  r´   rµ   Úhover_elementr  r  rv  rD   r¾   r$   Úhover_on_elementr=   rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   )
r3   r-  rð   rç   rí   r/  r0  rÝ   rÞ   rß   r8   r8   r9   r8  ¡
  s6    
ÿ


zBaseCase.hoverc              	   C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}|}	|  ||¡\}}|  ¡ rr| j ||¡ dS | j	|||d�}
|  
||¡ | j||d� d}ttƒ� | jj}W d  ƒ n1 sÆ0    Y  t| jjƒ}| j�rP|  ¡ �rP|  d¡dk�rP|tjk�r|}|tjk�r|	}|  d¡}|  ¡ }||g}d|||g}| j |¡ d}d}z$| j�rl|
 ¡  nt | j|
¡ W n| t�yø   d	}|  |||¡}|tj k�r¼|  !|  "|¡¡ n8|tj#k�rÚ|  !|  $|¡¡ nd	| _%| j&||d� d| _%Y n0 |�rn6| j�r| j||d� n|�s8t | j||||||¡}t| jjƒ}||k�rv| j�sltj'�rv| jj|k�rv|  (¡  nD| j)d
k�rºttƒ� t *| jd¡ W d  ƒ n1 �s°0    Y  | j+�r| jj|k�rút, -| j¡�sðt, .| jt/j0j1¡ |  2¡  n| j2d	d� n| j3�r|  4¡  |S )zsWhen you want to hover over an element or dropdown menu,
        and then click an element that appears after that.NrI  rï   rB  rC  r    Úho_clFTrê   r¨  rü   )5r³   r   rÿ   r   r  r  r´   rµ   Úhover_and_clickr  r  rv  r   r¿   r=   rÀ   r  r  rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   Úmobile_emulatorr  r$   r9  rg  r  r¶   rÞ  r	  ré  re   r   r$  r%  r  r:  rÕ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r  r+  )r3   Úhover_selectorÚclick_selectorÚhover_byÚclick_byrç   r   rí   r/  Zoriginal_click_selectorÚdropdown_elementrÜ   r1  rÝ   rÞ   Zthe_selectorsrß   Úoutdated_driverr0  r3  r8   r8   r9   r<  ¾
  sº    
ÿÿÿ
&

ÿÿù	ÿýû
ú


.
zBaseCase.hover_and_clickc                 C   s   | j |||||dd� d S )NT)r>  r?  r@  rA  rç   r   )r<  )r3   r>  r?  r@  rA  rç   r8   r8   r9   Úhover_and_js_click.  s    úzBaseCase.hover_and_js_clickc                 C   s   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}|  ||¡}tj}|  ||¡\}}| j	|||d�}|  
||¡ | j||d� d}	ttƒ� | jj}	W d  ƒ n1 sº0    Y  t| jjƒ}
d}d}zt | j|¡ W nz t�yd   d}|  |||¡}|tjk�r*|  |  |¡¡ n6|tjk�rH|  |  |¡¡ nd| _|  ||¡ d| _Y n0 |�s‚tj| j||d|d�}t| jjƒ}||
k�r¾| j�s¶tj�r¾| jj|	k�r¾|  ¡  | j �r| jj|	k�rþt! "| j¡�sôt! #| jt$j%j&¡ |  '¡  n| j'dd� n| j(�r|  )¡  |S )	zzWhen you want to hover over an element or dropdown menu,
        and then double-click an element that appears after that.rI  rï   NFTrå   ©rA  rç   rü   )*r³   r   rÿ   r   r  r  r<  r   rq  r  r  rv  r   r¿   r=   rÀ   r  r  r$   r9  rg  r  r¶   rÞ  r	  ré  re   r   Zhover_element_and_double_clickrÇ   r$  r%  rÕ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r  r+  )r3   r>  r?  r@  rA  rç   rí   r/  rB  rÜ   r1  rC  r0  r3  r8   r8   r9   Úhover_and_double_click?  sŠ    

ÿÿÿ
&ÿÿûÿýû
ú

zBaseCase.hover_and_double_clickc           
   	   C   s,  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ||¡\}}|  ¡ rf| j ||¡ dS | j	|||d�}|  
||¡ | j|||d�}|  
||¡ | j||d� |  ||¡}|  ||¡}|sèt ¡ }	|  |	||dddd¡ nt ¡ }	|  |	d||f  ¡ | j�r|  ¡  n| j�r(|  ¡  |S )z6Drag-and-drop an element from one selector to another.NrI  rï   r   r�   z-$('%s').simulateDragDrop({dropTarget: '%s'});)r³   r   rÿ   r   r  r  r´   rµ   Zgui_drag_and_dropr  r  r  rv  r<  r#   Zget_js_drag_and_drop_scriptrÈ   Zget_drag_and_drop_scriptÚsafe_execute_scriptrÕ   rÚ   r  r+  )
r3   Zdrag_selectorZdrop_selectorZdrag_byZdrop_byrç   ZjqueryZdrag_elementZdrop_elementZdrag_and_drop_scriptr8   r8   r9   Údrag_and_drop“  sV    

ÿÿÿÿÿþþÿ
zBaseCase.drag_and_dropc           	      C   s´   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j||d�}| j||d�}|  |t	j
¡ t |¡}|  |¡}t |||¡}|  |¡ | jr¢|  ¡  n| jr°|  ¡  |S )z5Drag-and-drop an element to an {X,Y}-offset location.rï   ré   )r³   r   rÿ   r   r  r  r<  r  r  r   rq  r=  r>  r?  r#   Z$get_drag_and_drop_with_offset_scriptrÈ   rÕ   rÚ   r  r+  )	r3   r-  r  r  rð   rç   rA  r0  r{  r8   r8   r9   Údrag_and_drop_with_offsetË  s(    


ÿ

z"BaseCase.drag_and_drop_with_offsetc                 C   s¨   |   ¡  | jr6| js6| jdks6t|dƒr6|j ¡ dkr@| ¡  ndzH| d¡}| d¡}t	|ƒdkrt|dkrt| 
¡  n| ¡  t d¡ W n ty¢   | ¡  Y n0 d S )Nr   Úuc_clickrò   ró   rõ   rö   çú~j¼t“ˆ?)r³   rÓ   Úuc_cdp_eventsrL   rÍ   r  r  r  r  r  rJ  rD   r¾   r¿   )r3   r0  ró   rõ   r8   r8   r9   Z__element_clickä  s*    ÿþýüû



zBaseCase.__element_clickr]  c                 C   st  ddl m} |  ¡  |stj}| jr8|tjkr8|  |¡}|  ||¡\}}|  ¡  | j	|||d�}z| j
||dd�}W n tyŽ   |  ¡  Y n0 | j||d�rª|  ||¡ d}ttƒ� | jj}W d  ƒ n1 sÔ0    Y  t| jjƒ}	zZ|dk�r||ƒ |¡ n(|dk�r ||ƒ |¡ n||ƒ |¡ t d	¡ |  ¡  W �nR t�y–   t d
¡ |  ¡  | j	|||d�}z| j
||dd�}W n t�y¦   |  ¡  Y n0 |dk�rôz||ƒ |¡ W n, t�yð   d||f }
t d|
¡ Y n0 nŒ|dk�r@z||ƒ |¡ W n, t�y<   d||f }
t d|
¡ Y n0 n@z||ƒ |¡ W n, t�y~   d||f }
t d|
¡ Y n0 t d	¡ |  ¡  Y n0 t| jjƒ}||	k�rÔ| j�sÌtj�rÔ| jj|k�rÔ|  ¡  tj�ræ|  ¡  n,| jtjd� | jj|k�r|   ¡  |  !¡  | j"�r`| jj|k�rRt# $| j¡�sHt# %| jt&j'j(¡ |  )¡  n| j)dd� n| j*�rp|  +¡  dS )z¶Selects an HTML <select> option by specification.
        Option specifications are by "text", "index", or "value".
        Defaults to "text" if option_by is unspecified or unknown.r   )ÚSelectrI  rù   rï   NÚindexrS  rë   r4  z1Element {%s} has no selectable index option {%s}!ZNoSuchOptionExceptionz1Element {%s} has no selectable value option {%s}!z0Element {%s} has no selectable text option {%s}!ré   Trü   ),Zselenium.webdriver.support.uirM  r³   r   rÿ   r   r  r  rÔ   rg  r  r¿   r£  r  r   r=   rÀ   r  r  Zselect_by_indexZselect_by_valueZselect_by_visible_textrD   r¾   r$   rË  rÇ   r$  r%  r&  r'  r(  r)  r*  rÕ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r  r+  )r3   Údropdown_selectorÚoptionÚdropdown_byÚ	option_byrç   rM  r0  rÜ   r1  r¨   r3  r8   r8   r9   Z__select_optionú  sÒ    
ÿÿÿ
ÿ
&



ÿÿ

ÿÿÿ
ÿÿÿÿÿÿ

ÿýû
ú


zBaseCase.__select_optionc                 C   s^   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rF| j ||¡ dS | j|||d|d� dS )z›Selects an HTML <select> option by option text.
        @Params
        dropdown_selector - the <select> selector.
        option - the text of the option.Nr]  ©rQ  rR  rç   )	r³   r   rÿ   r   r  r´   rµ   Úselect_option_by_textÚ_BaseCase__select_option©r3   rO  rP  rQ  rç   r8   r8   r9   rT  w  s    
ûzBaseCase.select_option_by_textc                 C   s^   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rF| j ||¡ dS | j|||d|d� dS )z¤Selects an HTML <select> option by option index.
        @Params
        dropdown_selector - the <select> selector.
        option - the index number of the option.NrN  rS  )	r³   r   rÿ   r   r  r´   rµ   Úselect_option_by_indexrU  rV  r8   r8   r9   rW  ’  s    
ûzBaseCase.select_option_by_indexc                 C   s^   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rF| j ||¡ dS | j|||d|d� dS )z¦Selects an HTML <select> option by option value.
        @Params
        dropdown_selector - the <select> selector.
        option - the value property of the option.NrS  rS  )	r³   r   rÿ   r   r  r´   rµ   Úselect_option_by_valuerU  rV  r8   r8   r9   rX  ­  s    
ûzBaseCase.select_option_by_valuec           
         sè   |   ¡  |stj}| jr,|tjkr,|  |¡}|}g d¢}ˆ |vrLtd| ƒ‚|  ||¡\}}| j|||d�}|j 	¡ dkrŒtd|j 	¡  ƒ‚|dkr¢| j
||d�}|d }|  |¡}	ˆ s¼|	S ˆ d	krÒd
d„ |	D ƒS ‡ fdd„|	D ƒS dS )a}  Returns a list of select options as attribute text (configurable).
        @Params
        dropdown_selector - The selector of the "select" element.
        attribute - Choose from "text", "index", "value", or None (elements).
        by - The "by" of the "select" selector to use. Default: "css selector".
        timeout - Wait time for "select". If None: settings.SMALL_TIMEOUT.)r]  rN  rS  NzThe attribute must be in %srI  r1  zeElement tag_name for get_select_options(selector) must be a "select"! Actual tag_name found was: "%s"rå   rï   z optionr]  c                 S   s   g | ]
}|j ‘qS r8   )r]  ©Ú.0rà   r8   r8   r9   Ú
<listcomp>í  ó    z/BaseCase.get_select_options.<locals>.<listcomp>c                    s   g | ]}|  ˆ ¡‘qS r8   )r  rY  ©rµ  r8   r9   r[  ï  r\  N)rÔ   r   rÿ   r   r  r¿   r  Úwait_for_elementr  r  r<  r	  )
r3   rO  rµ  rð   rç   r-  Zallowed_attributesr0  Zoption_selectorZoption_elementsr8   r]  r9   Úget_select_optionsÈ  s4    
þÿ
zBaseCase.get_select_optionsc                 C   sÚ  |   ¡  g }| d¡}|D ]}| ¡  d¡s| |¡ qd |¡}|  |¡}d}| d¡}d}	|D ]6}
|
 d¡dgkrb|
 d¡rbd	}|
 d¡}	|  	|	¡}	qb|rÌ| 
d
¡dkrÌ| 
d¡dkrÌ| d
d|	 ¡}n,|sø| d¡}|D ]}| d¡rÞ| d¡}	qÞ|	�r| dd|	 ¡}|  |¡}| d¡}|D ]&}| d¡dk�r&| t|ƒd¡}�q&|  |¡}d}d}d}d}|j�r²tt|jƒƒdk�r²d	}t|jƒ}t |¡}|  |¡}| dd¡}|j�rPtt|jƒƒdk�rPd	}t|jƒ}| dd¡}| dd¡}| dd¡}| dd ¡}| d!d"¡}| d#d$¡}| d%d&¡}t |¡}|  |¡}| dd¡}t |¡}|  |¡}| dd¡}|�r€|  d'¡ d(}d)}ttƒ� | jd*dd+� W d  ƒ n1 �s¶0    Y  |�sÚ|  d,||f ¡ nd|�rú|�sú|  d,||f ¡ nD|�r6|�r6|  d,||f ¡ t d-¡ |  d,||f ¡ ntd.ƒ‚|D ]’}|j}| d/¡}|�r¼| d¡dk�r¼| d¡}g }|D ]}| ¡ }| |¡ �q~d |¡}t |¡}t | j|¡ n|�rBt | j|¡ n �qBdS )0z²Loads an HTML string into the web browser.
        If new_page==True, the page will switch to: "data:text/html,"
        If new_page==False, will load HTML into the current page.rN  ú//FÚlinkNÚrelÚ	canonicalró   Tz<head>r�   z<baser   z<head><base href="%s">Úbasez	base: "."z
base: "%s"r{  r  zapplication/jsonrd  é   z\ re  u   Ã‚Â z&#xA0;u   Ã‚Â¡z&#xA1;u   Ã‚Â©z&#xA9;u   Ã‚Â·z&#xB7;u   Ã‚Â¿z&#xBF;u   ÃƒÂ—z&#xD7;u   ÃƒÂ·z&#xF7;z4data:text/html,<head></head><body><div></div></body>z2document.getElementsByTagName("head")[0].innerHTMLz2document.getElementsByTagName("body")[0].innerHTMLr¨  ré   z	%s = "%s"r7  zLogic Error!r  )rÔ   rž  rÂ   rÆ   r�   r2  r»  r¼  rÌ   rÊ   rh  ri  rÁ   Úheadr  r=  r>  r?  r¨  r¶   r   r¿   rg  rÈ   rD   r¾   Ústringr#   Úadd_js_coder=   r×   )r3   Úhtml_stringÚnew_pageÚ	new_linesÚlinesÚliner¾  Z
found_baseÚlinksró   ra  Úbasesrd  Úscriptsr{  Z
found_headZ
found_bodyZ	html_headZ	html_bodyZ
inner_headZ
inner_bodyÚjs_codeZjs_srcZjs_code_linesr8   r8   r9   Úload_html_stringñ  s¼    




ÿþýÿ














.




zBaseCase.load_html_stringc                 C   s   | j ||d� dS )z=Same as load_html_string(), but "new_page" defaults to False.)rj  N)rr  )r3   ri  rj  r8   r8   r9   Úset_contentY  s    zBaseCase.set_contentc                 C   s´   |   ¡  |  |¡r |  |¡ dS t|ƒdk s6| d¡s>tdƒ‚tj d¡}d}||v r\|}ntj 	||¡}d}t|dƒ�}| 
¡  ¡ }W d  ƒ n1 sš0    Y  |  ||¡ dS )a  Loads a local html file into the browser from a relative file path.
        If new_page==True, the page will switch to: "data:text/html,"
        If new_page==False, will load HTML into the current page.
        Local images and other local src content WILL BE IGNORED.Né   ú.htmlúExpecting a ".html" file!Ú.Úr)r³   rÃ   r¶   r  rZ  r¿   ÚosÚpathÚabspathr2  ÚreadrÂ   rr  )r3   Ú	html_filerj  Úabs_pathÚ	file_pathri  Úfr8   r8   r9   Úload_html_file]  s    

*zBaseCase.load_html_filec                 C   s|   |   ¡  |  |¡r |  |¡ dS t|ƒdk s6| d¡s>tdƒ‚tj d¡}d}||v r\|}ntj 	||¡}|  d| ¡ dS )z‹Opens a local html file into the browser from a relative file path.
        The URL displayed in the web browser will start with "file://".Nrt  ru  rv  rw  zfile://)
r³   rÃ   r¶   r  rZ  r¿   ry  rz  r{  r2  )r3   r}  r~  r  r8   r8   r9   Úopen_html_files  s    

zBaseCase.open_html_filec                 C   sN  |   ¡  |  ¡ r| j |¡S |  ¡  |}| ¡ }| d¡}|r‚|d  ¡  d¡r‚d |dd… ¡d |d  ¡ t	dƒd…   ¡ }| j
 dd|i¡}d|d	 v r¬|d	 d S |d	 d
 dkrÀdS d|v rÜt|d	 d |ƒ‚nn|d	 d
 dk�rd|v�rd| ¡  }|  |¡S |d	 d
 dk�r$i S d|d	 v �rFt|d	 d |ƒ‚ndS dS )z2Run a JavaScript expression and return the result.rN  rû   zreturn r   NzRuntime.evaluateÚ
expressionrS  Úresultr  Z	undefinedZexceptionDetailsÚdescriptionÚobjectÚfunction)r³   r´   rµ   Úevaluater¼   rÂ   rž  rÆ   r2  r  r=   Úexecute_cdp_cmdr¿   rÈ   )r3   rƒ  Zoriginal_expressionZexp_listZ
evaluationr8   r8   r9   rˆ  „  s@    
ÿÿÿþ

zBaseCase.evaluatec                 O   s>   |   ¡  |  ¡ r| j |¡S |  ¡  | jj|g|¢R i |¤ŽS r.   )r³   r´   rµ   rˆ  r¼   r=   rÈ   ©r3   r{  r4   r5   r8   r8   r9   rÈ   ¬  s
    zBaseCase.execute_scriptc                 O   s*   |   ¡  |  ¡  | jj|g|¢R i |¤ŽS r.   )r³   r¼   r=   r‰  rŠ  r8   r8   r9   r‰  ³  s    zBaseCase.execute_cdp_cmdc                 C   s*   |   ¡  |  ¡  |stj}t | j||¡S r.   )r³   r¼   r   ÚEXTREME_TIMEOUTr#   Úexecute_async_scriptr=   )r3   r{  rç   r8   r8   r9   rŒ  ¸  s
    zBaseCase.execute_async_scriptc                 O   s>   |   ¡  |  ¡  t | j¡s$|  ¡  | jj|g|¢R i |¤ŽS )z¿When executing a script that contains a jQuery command,
        it's important that the jQuery library has been loaded first.
        This method will load jQuery if it wasn't already loaded.)r³   r¼   r#   rÖ   r=   Úactivate_jqueryrÈ   rŠ  r8   r8   r9   rG  ¿  s
    zBaseCase.safe_execute_scriptc                 C   s"   |   ¡  |  ¡  |  d||f ¡S )z3Return element at current window's x,y coordinates.z)return document.elementFromPoint(%s, %s);)r³   r¼   rÈ   )r3   r  r  r8   r8   r9   Úget_element_at_x_yÉ  s
    
ÿzBaseCase.get_element_at_x_yc                 C   s,  |   ¡ r| j |¡S | j||dd�}|j}|d }|d }d}d}d}	|  ¡ rŒ|  ¡  |  ¡ rftdƒ‚d}	| jd	dd
�}
|
jd }|
jd }|  ¡ }|d |d  }|  	d¡}t
 |d | |d  ¡}t
 || | |d  ¡}|  	d¡}t|| ƒ}|	�r|  ¡  | j||d��s|  ¡  ||||dœS )a  Very similar to element.rect, but the x, y coordinates are
        relative to the entire screen, rather than the browser window.
        This is specifically for PyAutoGUI actions on the full screen.
        (Note: There may be complications if iframes are involved.)r�   rI  ÚwidthÚheightr   Fz+Nested iframes breaks get_gui_element_rect!Tr.  ré   r  r  zreturn window.innerHeight;zreturn window.pageYOffset;rï   )r�  r�  r  r  )r´   rµ   Úget_gui_element_rectrg  ÚrectÚ_BaseCase__is_in_frameÚswitch_to_parent_framer¿   Úget_window_rectrÈ   ÚmathÚceilrO   r3  r   )r3   r-  rð   r0  Úelement_rectZe_widthZe_heightZi_xZi_yZiframe_switchr.  Zwindow_rectZ
w_bottom_yZviewport_heightr  r  Zy_scroll_offsetr8   r8   r9   r‘  Ñ  s:    



zBaseCase.get_gui_element_rectc                 C   sZ   |   ¡ r| j |¡S | j||d�}|d |d d  d }|d |d d  d }||fS )a  Returns the x, y coordinates of the element's center based
        on the entire GUI / screen, rather than on the browser window.
        This is specifically for PyAutoGUI actions on the full screen.
        (Note: There may be complications if iframes are involved.)rï   r  r�  g       @ç      à?r  r�  )r´   rµ   Úget_gui_element_centerr‘  )r3   r-  rð   r˜  r  r  r8   r8   r9   rš  ô  s    zBaseCase.get_gui_element_centerc                 C   s,   |   ¡  |  ¡ r| j ¡ S |  ¡  | j ¡ S r.   )r³   r´   rµ   Úget_screen_rectr¼   r=   r‹   r8   r8   r9   r›     s
    
zBaseCase.get_screen_rectc                 C   s,   |   ¡  |  ¡ r| j ¡ S |  ¡  | j ¡ S r.   )r³   r´   rµ   r•  r¼   r=   r‹   r8   r8   r9   r•    s
    
zBaseCase.get_window_rectc                 C   s,   |   ¡  |  ¡ r| j ¡ S |  ¡  | j ¡ S r.   )r³   r´   rµ   Úget_window_sizer¼   r=   r‹   r8   r8   r9   rœ    s
    
zBaseCase.get_window_sizec                 C   s,   |   ¡  |  ¡ r| j ¡ S |  ¡  | j ¡ S r.   )r³   r´   rµ   Úget_window_positionr¼   r=   r‹   r8   r8   r9   r�    s
    
zBaseCase.get_window_positionc                 C   sP   |   ¡  |  ¡ r&| j ||||¡ d S |  ¡  | j ||||¡ | jdd� d S ©NTrü   )r³   r´   rµ   Úset_window_rectr¼   r=   rÚ   ©r3   r  r  r�  r�  r8   r8   r9   rŸ    s    zBaseCase.set_window_rectc                 C   sf   |   ¡  |  ¡ r@| j ¡ }|d }|d }| j ||||¡ d S |  ¡  | j ||¡ | jdd� d S )Nr  r  Trü   )	r³   r´   rµ   r�  rŸ  r¼   r=   Úset_window_sizerÚ   )r3   r�  r�  Úpositionr  r  r8   r8   r9   r¡  %  s    
zBaseCase.set_window_sizec                 C   sf   |   ¡  |  ¡ r@| j ¡ }|d }|d }| j ||||¡ d S |  ¡  | j ||¡ | jdd� d S )Nr�  r�  Trü   )	r³   r´   rµ   rœ  rŸ  r¼   r=   Úset_window_positionrÚ   )r3   r  r  Úsizer�  r�  r8   r8   r9   r£  1  s    
zBaseCase.set_window_positionc                 C   s¤   |   ¡  |  ¡ r| j ¡  d S |  ¡  z| j ¡  W n^ ty’   ttƒ�4 |  	d¡}|  	d¡}|  
dd||¡ W d   ƒ n1 s„0    Y  Y n0 | jdd� d S )Nzreturn screen.availWidth;zreturn screen.availHeight;r   Trü   )r³   r´   rµ   Úmaximizer¼   r=   Úmaximize_windowr¿   r   rÈ   rŸ  rÚ   )r3   r�  r�  r8   r8   r9   r¦  =  s    



4zBaseCase.maximize_windowc                 C   s   |   ¡  d S r.   )r¦  r‹   r8   r8   r9   r¥  L  s    zBaseCase.maximizec                 C   s@   |   ¡  |  ¡ r| j ¡  d S |  ¡  | j ¡  | jdd� d S rž  )r³   r´   rµ   Úminimizer¼   r=   Úminimize_windowrÚ   r‹   r8   r8   r9   r¨  O  s    

zBaseCase.minimize_windowc                 C   s   |   ¡  d S r.   )r¨  r‹   r8   r8   r9   r§  X  s    zBaseCase.minimizec                 C   s^   |   ¡  |  ¡ r| j ¡  d S |  ¡  tj}tj}tj}tj	}|  
||||¡ | jdd� d S rž  )r³   r´   rµ   Úreset_window_sizer¼   r   ÚWINDOW_START_XÚWINDOW_START_YÚCHROME_START_WIDTHÚCHROME_START_HEIGHTrŸ  rÚ   r   r8   r8   r9   r©  [  s    
zBaseCase.reset_window_sizer.  c                 C   s   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rNt d¡ | jrNt d¡ t	|t
ƒr¶|  |¡r¶z4| j|dd� |  ¡ r”t d¡ | jr”t d¡ W qØ ty²   t d¡ Y qØ0 n"|  ¡ rØt d¡ | jrØt d¡ | jrì|  jd7  _| j�rŒ| j�rŒ|  ¡ �rŒ|  d¡}|dk�rŒ|  d¡}|  ¡ }d	d
||g}| j |¡ |  d¡}d| _| j||d� d| _|  ¡ }d|||g}| j |¡ dS |  ¡  |  ¡ �rºt d¡ | j�rºt d¡ tj| j|||d� |  ¡  |  ¡ �rüt d¡ | j�rüt d¡ dS )a  Wait for an iframe to appear, and switch to it. This should be
        usable as a drop-in replacement for driver.switch_to.frame().
        The iframe identifier can be a selector, an index, an id, a name,
        or a web element, but scrolling to the iframe first will only occur
        for visible iframes with a string selector.
        @Params
        frame - the frame element, name, id, index, or selector
        timeout - the time to wait for the alert in seconds
        invisible - if True, the iframe can be invisible rë   r�   ré   r›   r7  Úrecorder_activatedÚyesr    Úsk_oprd  TFÚsw_frNçìQ¸…ë¡?)Ú	invisibleg¸…ëQ¸Ž?)r³   r   rT  r   r  r½   rD   r¾   rÓ   r˜  rÁ   r£  rv  r¿   rL   rÇ   rw   rF  rG  rÈ   rÉ   rF   r�   rH   Úset_content_to_framerÔ   r$   r3  r=   )r3   Úframerç   r³  Úr_arÝ   rÞ   rß   r8   r8   r9   r3  h  sr    






ÿþý







ÿ

zBaseCase.switch_to_framec                 C   sŒ   |   ¡  | jrp| jrp|  ¡ rp|  d¡}|dkrp|  d¡}d| _|  ¡  d| _|  ¡ }dd||g}| j	 
|¡ dS | jj ¡  | jrˆd	| _dS )
a
  Brings driver control outside the current iframe.
        If the driver is currently set inside an iframe or nested iframes,
        then the driver control will exit from all entered iframes.
        If the driver is not currently set in an iframe, nothing happens.r®  r¯  r    TFÚsw_dcrd  Nr   )r³   rÇ   rw   rF  rG  rÈ   rH   Úset_content_to_defaultrÉ   rF   r�   r=   r§   Údefault_contentrÓ   rL   ©r3   r¶  rÝ   rÞ   rß   r8   r8   r9   r4  ¬  s(    ÿþý

z"BaseCase.switch_to_default_contentc                 C   s¨   |   ¡  | jrt| jrt|  ¡ rt|  d¡}|dkrt|  d¡}d| _| jdd� d| _|  ¡ }dd||g}| j	 
|¡ d	S | jj ¡  | jr¤|  jd
8  _| jdk r¤d| _d	S )a  Brings driver control outside the current iframe.
        If the driver is currently set inside an iframe or nested iframes,
        the driver control will be set to one level above the current frame.
        If the driver is not currently set in an iframe, nothing happens.r®  r¯  r    T©ÚnestedFÚsw_pfrd  Nr�   r   )r³   rÇ   rw   rF  rG  rÈ   rH   r¸  rÉ   rF   r�   r=   r§   Zparent_framerÓ   rL   rº  r8   r8   r9   r”  Å  s,    ÿþý


zBaseCase.switch_to_parent_framec                 c   sÄ   | j r$|  jd7  _| jdkr$d| _| j||d� | jrF|  jd7  _dV  | jrp|  jd8  _| jdk rpd| _|  ¡  | j rÀ|  jd8  _| jdk r¢d| _d| _| jdkrÀ| jrÀ|  ¡  d| _dS )a   Context Manager for switching into iframes.
        Usage example:
            with self.frame_switch("iframe"):
                # Perform actions here that should be done within the iframe.
            # The iframe is automatically exited after the "with" block ends.
        r�   é   Tré   Nr   F)rÇ   rI   rJ   r3  rÓ   rL   r”  r}  )r3   rµ  rç   r8   r8   r9   Úframe_switchà  s*    


zBaseCase.frame_switchc                 C   sô  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ }| jj}|  ¡ }|  	d¡ t
 | j||¡ |  ¡ }| jj ¡  |  ¡  d}|}|  |¡r’d}nd|vr°d| }|  |¡r°d}d}	d}
|rø|  	d| ¡}
|
røt|
ƒdkrød	|
v sød
|
v sød|
v rônd}
d}|
�rd}| j |||g¡ | j�rb| j�sb|  	d¡}	|  ¡ }dd||	g}| j |¡ tt|	ƒd ƒ}	|�r”|  	d¡ | jdd� |  |
¡ |  	d¡ n,|  |¡ |  	d¡�s¶|  	d¡ n
|  	d¡ | j�rð| j�sð|  ¡ }d|||	g}| j |¡ dS )aÌ  Replaces the page html with an iframe's html from that page.
        If the iframe contains an "src" field that includes a valid URL,
        then instead of replacing the current html, this method will then
        open up the "src" URL of the iframe in a new browser tab.
        To return to default content, use: self.set_content_to_default().
        This method also sets the state of the browser window so that the
        self.set_content_to_default() method can bring the user back to
        the original content displayed, which is similar to how the methods
        self.switch_to_frame(frame) and self.switch_to_default_content()
        work together to get the user into frames and out of all of them.údocument.cframe_swap = 0;FTre  ziframe[name="%s"]r   Nz(return document.querySelector('%s').src;r£   r¤   r¥   r    r°  rd  r�   zdocument.cframe_tab = 1;r¦   úreturn document.cframe_swap;zdocument.cframe_swap = 1;zdocument.cframe_swap += 1;Ús_c_f)r³   r   rÿ   r   r  r„  r=   r  r†  rÈ   r$   r3  r§   r¹  rÔ   r   r  rE   r�   rÇ   rH   rÉ   rF   rÁ   rO   rË   r¶   rs  )r3   rµ  rç   rÀ   Zc_tabZcurrent_page_sourceZiframe_htmlZframe_foundZo_framerÝ   rÛ   Z
cframe_tabrÞ   rß   r8   r8   r9   r´  þ  sl    



ÿ




zBaseCase.set_content_to_framec                 C   s–  |   ¡  |  d¡}|  d¡}d}| jrf| jsf|  d¡}|  ¡ }dd||g}| j |¡ tt|ƒd ƒ}|�s`t	| j
ƒdk�r*|rŒt|ƒdks |�r*t|ƒdk�r*| j
d }|d }|d }	|d }
| jj}||
ksè|
| jjv rè|  |
¡ |  ¡ }| j�r
| j�s
|  d¡}||k�r |  |	¡ n|  ¡  n"| j�rD| j�sD|  d¡}|  ¡  |  d	¡ g | _
�nd
}|�rÐt|ƒdk�rÐt	| j
ƒdk�rÐ|  d¡ |  ¡ }| j
 ¡ }|d }|d }	||k�rÊ|  |	¡ nd}nZ|�r&t|ƒdk�r&t	| j
ƒdk�r&| j
 ¡ }|d }
|
| jjv �r |  |
¡ nd}nd}|�rb| j�rJ| j�sJ|  d¡}|  ¡  |  d	¡ g | _
| j�r’| j�s’|  ¡ }d|||g}| j |¡ dS )ah  After using self.set_content_to_frame(), this reverts the page back.
        If self.set_content_to_frame() hasn't been called here, only refreshes.
        If "nested" is set to True when the content is set to a nested iframe,
        then the page control will only exit from the current iframe entered,
        instead of exiting out of all iframes entered.rÁ  zreturn document.cframe_tab;r   r    r°  rd  r�   r¾  rÀ  Fzdocument.cframe_swap -= 1;TÚs_c_dN)r³   rÈ   rÇ   rH   rÉ   rF   r�   rÁ   rO   r  rE   r=   r  r  r  r„  rs  r~  Úpop)r3   r¼  Zswap_cntZtab_starÝ   rÞ   rß   Zpast_contentZpast_urlZpast_sourceZpast_tabZcurrent_tabZurl_of_past_tabZjust_refreshrÀ   r8   r8   r9   r¸  F  s†    


ÿý
ýü
ü







$


$


zBaseCase.set_content_to_defaultc                 C   s   | j |d� dS )z&Same as self.set_content_to_default().r»  N©r¸  )r3   r¼  r8   r8   r9   Úset_content_to_default_contentœ  s    z'BaseCase.set_content_to_default_contentc                 C   s   | j dd� dS )zÚSame as self.set_content_to_parent_frame().
        Same as self.set_content_to_default(nested=True).
        Sets the page to the content outside the current nested iframe.
        Reverts self.set_content_to_frame().Tr»  NrÅ  r‹   r8   r8   r9   Úset_content_to_parent   s    zBaseCase.set_content_to_parentc                 C   s   | j dd� dS )zÔSame as self.set_content_to_parent().
        Same as self.set_content_to_default(nested=True).
        Sets the page to the content outside the current nested iframe.
        Reverts self.set_content_to_frame().Tr»  NrÅ  r‹   r8   r8   r9   Úset_content_to_parent_frame§  s    z$BaseCase.set_content_to_parent_framec                 K   sò   d}|   t|ƒ¡r|}d}|  ¡ r>| jjf ||dœ|¤Ž dS t| jddƒr~t| jddƒr~|  ¡  | jjf ||dœ|¤Ž dS |  ¡  |rÆz| jj	 
d¡ W qÒ tyÂ   | j d¡ |  ¡  Y qÒ0 n| j d¡ t d¡ | jd	krî|  ¡  dS )
z=Opens a new browser tab/window and switches to it by default.NT)rÛ   r§   r™   rš   Útabzwindow.open('');r©  rê   )rÃ   rÁ   r´   rµ   Úopen_new_tabr·   r=   r»   rÔ   r§   Z
new_windowr¿   rÈ   Úswitch_to_newest_windowrD   r¾   r  )r3   r§   r5   rÛ   r8   r8   r9   rË   ®  s2    ÿþ

zBaseCase.open_new_windowc                 C   sb   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rNt|tƒsN| j 	|¡ dS t
 | j||¡ dS )zÆSwitches control of the browser to the specified window.
        The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...
            Or it can be a list item from self.driver.window_handlesN)r³   r   rÿ   r   r  r´   r˜  rÁ   rµ   Úswitch_to_tabr$   r  r=   )r3   Úwindowrç   r8   r8   r9   r  Í  s    
zBaseCase.switch_to_windowc                 C   s   |   d¡ d S )Nr   ©r  r‹   r8   r8   r9   Úswitch_to_default_windowÛ  s    z!BaseCase.switch_to_default_windowc                 C   s   |   d¡ d S )Nrû   rÎ  r‹   r8   r8   r9   rË  Þ  s    z BaseCase.switch_to_newest_windowc9           H   <   K   s@	  |   ¡  | jdkr$| jdkr$tdƒ‚d}:d};| jdkrR| jsR| jsRtd|:|;f ƒ‚g d¢}<|9r€|9 ¡ D ]}=|=|<vrftd|= ƒ‚qf|d	u rŽ| j}|}>|d	u r | j}|d	u r®| j	}d
|9v rÂ|sÂ|9d
 }|d	u rÐ| j
}|d	u rÞ| j}|d	u rì| j}d}?|dkrüd}?|}@|@d	u �r| j}@|d	u �r | j}|	d	u �r0| j}	|
d	u �r@| j}
|}A|Ad	u �rT| j}A|d	u �rd| j}|d	u �rt| j}|d	u �r„| j}|d	u �r”| j}|d	u �r¤| j}|d	u �r´| j}|d	u �rÄ| j}|d	u �rÔ| j}|d	u �rä| j}|d	u �rô| j}d|9v �r|�s|9d }|d	u �r| j}|d	u �r,| j}|d	u �r<| j}|d	u �rL| j}|d	u �r\| j}|d	u �rl| j }|d	u �r|| j!}d|9v �r”|�s”|9d }| d	u �r¤| j"} d|9v �r¼| �s¼|9d } |!d	u �rÌ| j#}!|"d	u �rÜ| j$}"|#d	u �rì| j%}#|$d	u �rü| j&}$|%d	u �r| j'}%|&d	u �r| j(}&|'d	u �r,| j)}'|(d	u �r<| j*}(|)d	u �rL| j+})|*d	u �r\| j,}*|+d	u �rl| j-}+|,d	u �r|| j.},|-d	u �rŒ| j/}-|.d	u �rœ| j0}.|/d	u �r¬| j1}/|0d	u �r¼| j2}0|1d	u �rÌ| j3}1|2d	u �rÜ| j4}2d|9v �rô|2�sô|9d }2|3d	u �r| j5}3d|9v �r|3�s|9d }3|4d	u �r,| j6}4|  7¡ }B|d	u �rD| j}|d	u �rT| j}|5d	u �rd| j8}5d|9v �r||5�s||9d }5|6d	u �rŒ| j9}6|7d	u �rœ| j:}7|8d	u �r¬| j;}8|5�rÀ|A�sÀt<j=j>}At<j?j@}C|>|Cv�râtd||Cf ƒ‚tAjB|>|||?||||@||	|
|A|||||||||||||||||||| |!|"|#|$|%|&|'|(|)|*|+|,|-|.|/|0|1|2|3|4|B|5|6|7|8|>d�:}D| jC D|D¡ |>| jE|D< |�r’|D| _F|>| _| j�s | j�s | jG�rðtHjI}EtHjJ}F| jdk�r2| jdk�r2z| jF K|E|F¡ W n t�yê   Y n0 �nBtHjL}EtHjM}F|  N¡ �r<z| jO�r"|  P¡  |  Q¡  n W n t�y8   Y n0 nö| jdk�r¶zV| jO�rd|  P¡  |  Q¡  n8tRtƒ� | jF K|E|F¡ W d	  ƒ n1 �s’0    Y  W n t�y²   Y n0 n|| jdk�r2| jO�röz|  P¡  |  Q¡  W n t�yò   Y n0 n<tRtƒ�" | jF Sdd|E|F¡ W d	  ƒ n1 �s(0    Y  | jT�r’tU| jTƒdk�r’tV W| jT¡�rf|  X| jT¡ n,d| jT }GtV W|G¡�r’d| _Y|  X|G¡ d| _Y|�	r<tZ|Ddƒ�r¬|Dj[| _[tZ|Ddƒ�rÀ|Dj\| _\tZ|Ddƒ�rÔ|Dj]| _]tZ|Dd ƒ�rè|Dj^| _^tZ|Dd!ƒ�rü|Dj_| __tZ|Dd"ƒ�r|Dj`| _`tZ|Dd#ƒ�r$|Dja| _atZ|Dd$ƒ�r8|Djb| _btZ|Dd%ƒ�rL|Djc| _ctZ|Dd&ƒ�r`|Djd| _dtZ|Dd'ƒ�rt|Dje| _etZ|Dd(ƒ�rˆ|Djf| _ftZ|Dd)ƒ�rœ|Djg| _gtZ|Dd*ƒ�r°|Djh| _htZ|Dd+ƒ�rÄ|Dji| _itZ|Dd,ƒ�rØ|Djj| _jtZ|Dd-ƒ�rì|Djk| _ktZ|Dd.ƒ�	r |Djl| _ltZ|Dd/ƒ�	r|Djm| _mtZ|Dd0ƒ�	r(|Djn| _ntZ|Dd1ƒ�	r<|Djo| _o|DS )2aë  This method spins up an extra browser for tests that require
        more than one. The first browser is already provided by tests
        that import base_case.BaseCase from seleniumbase. If parameters
        aren't specified, the method uses the same as the default driver.
        @Params
        browser - the browser to use. (Ex: "chrome", "firefox")
        headless - the option to run webdriver in headless mode
        locale_code - the Language Locale Code for the web browser
        protocol - if using a Selenium Grid, set the host protocol here
        servername - if using a Selenium Grid, set the host address here
        port - if using a Selenium Grid, set the host port here
        proxy - if using a proxy server, specify the "host:port" combo here
        proxy_bypass_list - ";"-separated hosts to bypass (Eg. "*.foo.com")
        proxy_pac_url - designates the proxy PAC URL to use (Chromium-only)
        multi_proxy - allow multiple proxies with auth while multi-threaded
        switch_to - the option to switch to the new driver (default = True)
        cap_file - the file containing desired capabilities for the browser
        cap_string - the string with desired capabilities for the browser
        recorder_ext - the option to enable the SBase Recorder extension
        disable_cookies - the option to disable Cookies (May break things!)
        disable_js - the option to disable JavaScript (May break websites!)
        disable_csp - an option to disable Chrome's Content Security Policy
        enable_ws - the option to enable the Web Security feature (Chrome)
        enable_sync - the option to enable the Chrome Sync feature (Chrome)
        use_auto_ext - the option to enable Chrome's Automation Extension
        undetectable - the option to use an undetectable chromedriver
        uc_cdp_events - capture CDP events in "undetectable" mode (Chrome)
        uc_subprocess - use the undetectable chromedriver as a subprocess
        log_cdp_events - capture {"performance": "ALL", "browser": "ALL"})
        no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
        disable_gpu - the option to enable Chrome's "Disable GPU" feature
        headless1 - the option to use the older headless mode (Chromium)
        headless2 - the option to use the newer headless mode (Chromium)
        incognito - the option to enable Chrome's Incognito mode (Chrome)
        guest_mode - the option to enable Chrome's Guest mode (Chrome)
        dark_mode - the option to enable Chrome's Dark mode (Chrome)
        devtools - the option to open Chrome's DevTools on start (Chrome)
        remote_debug - the option to enable Chrome's Remote Debugger
        enable_3d_apis - the option to enable WebGL and 3D APIs (Chrome)
        swiftshader - the option to use Chrome's swiftshader (Chrome-only)
        ad_block_on - the option to block ads from loading (Chromium-only)
        host_resolver_rules - Configure host-resolver-rules (Chromium-only)
        block_images - the option to block images from loading (Chrome)
        do_not_track - indicate that websites should not track you (Chrome)
        chromium_arg - the option to add a Chromium arg to Chrome/Edge
        firefox_arg - the option to add a Firefox arg to Firefox runs
        firefox_pref - the option to add a Firefox pref:value set (Firefox)
        user_data_dir - Chrome's User Data Directory to use (Chrome-only)
        extension_zip - A Chrome Extension ZIP file to use (Chrome-only)
        extension_dir - A Chrome Extension folder to use (Chrome-only)
        disable_features - the option to disable features on Chrome/Edge
        binary_location - the path of the browser binary to use (Chromium)
        driver_version - the chromedriver or uc_driver version to force
        page_load_strategy - the option to change pageLoadStrategy (Chrome)
        use_wire - Use selenium-wire webdriver instead of the selenium one
        external_pdf - "plugins.always_open_pdf_externally": True. (Chrome)
        is_mobile - the option to use the mobile emulator (Chrome-only)
        d_width - the device width of the mobile emulator (Chrome-only)
        d_height - the device height of the mobile emulator (Chrome-only)
        d_p_r - the device pixel ratio of the mobile emulator (Chrome-only)
        ÚremoteÚ	localhosta  Cannot use "remote" browser driver on localhost! Did you mean to connect to a remote Grid server such as BrowserStack or Sauce Labs? If so, you must specify the "server" and "port" parameters on the command line! Example: --server=user:key@hub.browserstack.com --port=80z.https://browserstack.com/automate/capabilitiesz?https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/a"  Need to specify a desired capabilities file when using "--browser=remote". Add "--cap_file=FILE". File should be in the Python format used by: %s OR %s 
(See SeleniumBase/examples/capabilities/sample_cap_file_BS.py and SeleniumBase/examples/capabilities/sample_cap_file_SL.py for examples!))ÚdarkÚguestÚlocaleÚmobileÚplsÚucÚwirez Unexpected keyword argument '%s'NrÔ  FTr×  rÓ  rÒ  rÖ  rØ  rÕ  zABrowser: {%s} is not a valid browser option. Valid options = {%s}):Úbrowser_namer  Úlocale_codeÚuse_gridÚprotocolÚ
servernameÚportÚproxy_stringÚproxy_bypass_listÚproxy_pac_urlÚmulti_proxyÚ
user_agentÚcap_fileÚ
cap_stringÚrecorder_extÚdisable_cookiesÚ
disable_jsÚdisable_cspÚ	enable_wsÚenable_syncÚuse_auto_extrÓ   rL  Úuc_subprocessÚlog_cdp_eventsÚ
no_sandboxÚdisable_gpuÚ	headless1Ú	headless2Ú	incognitoÚ
guest_modeÚ	dark_modeÚdevtoolsÚremote_debugÚenable_3d_apisÚswiftshaderÚad_block_onÚhost_resolver_rulesÚblock_imagesÚdo_not_trackÚchromium_argÚfirefox_argÚfirefox_prefÚuser_data_dirÚextension_zipÚextension_dirÚdisable_featuresÚbinary_locationÚdriver_versionÚpage_load_strategyÚuse_wireÚexternal_pdfÚtest_idr=  Zdevice_widthZdevice_heightZdevice_pixel_ratior  ÚchromeÚedgerú   rê   é
   é.   r–  rœ   rµ   Úuc_openÚuc_open_with_tabÚuc_open_with_reconnectÚuc_open_with_cdp_modeÚuc_open_with_disconnectÚ	reconnectr»   ÚconnectrJ  Úuc_gui_press_keyÚuc_gui_press_keysÚuc_gui_writeÚuc_gui_click_x_yÚuc_gui_click_captchaÚuc_gui_click_cfÚuc_gui_click_rcÚuc_gui_handle_captchaÚuc_gui_handle_cfÚuc_gui_handle_rcÚuc_switch_to_frame)pr³   r  rÝ  r¿   rä  rå  ÚkeysÚ	TypeErrorr  rÚ  rÜ  rÞ  rß  rà  rá  râ  rã  ræ  rç  rè  ré  rê  rë  rì  rÓ   rL  rí  rî  rï  rð  rñ  rò  ró  rô  rõ  rö  r÷  rø  Ú_swiftshaderrú  rû  rü  rý  rþ  rÿ  r   r  r  r  r  r  r  r  r  r	  Ú_BaseCase__get_test_idr=  rk   rl   rm   r!   ÚMobileÚAGENTZValidBrowsersÚvalid_browsersr   Z
get_driverr~   r�   r   r=   Úxvfbr   ÚHEADLESS_START_WIDTHÚHEADLESS_START_HEIGHTr¡  r¬  r­  Úis_chromiumÚmaximize_optionr¦  rÔ   r   rŸ  r—  r  r%   rÄ   r¶   rd   rÍ   rµ   r  r  r  r  r  r  r»   r  rJ  r  r  r  r  r  r  r  r  r  r  r   )Hr3   r  r  rÚ  rÜ  rÝ  rÞ  Úproxyrà  rá  râ  Úagentr§   rä  rå  ræ  rç  rè  ré  rê  rë  rì  rÓ   rL  rí  rî  rï  rð  rñ  rò  ró  rô  rõ  rö  r÷  rø  rù  rú  rû  rü  rý  rþ  rÿ  r   r  r  r  r  r  r  r  r  r	  Ú	is_mobileÚd_widthÚd_heightÚd_p_rr5   Zbrowserstack_refZsauce_labs_refZ	shortcutsrs  rÙ  rÛ  rß  rã  r
  r'  Z
new_driverr�  r�  r™  r8   r8   r9   rÏ   á  sr   yÿ	ÿùÿ


















































ÿÿÆ<





2
2

ÿzBaseCase.get_new_driverc                 C   sJ   |   ¡  || _| j| jv r(| j| j | _|  ¡ r>| j | j¡ |  ¡  dS )zÃSwitches control of the browser to the specified driver.
        Also sets the self.driver variable to the specified driver.
        You may need this if using self.get_new_driver() in your code.N)r³   r=   r   r  r´   rµ   Ú_swap_driverÚbring_active_window_to_front©r3   r=   r8   r8   r9   Úswitch_to_driver®  s    zBaseCase.switch_to_driverc                 C   sL   |   ¡  | j| _| j| jv r*| j| j | _|  ¡ r@| j | j¡ |  ¡  dS )z/Sets self.driver to the default/initial driver.N)	r³   r}   r=   r   r  r´   rµ   r3  r4  r‹   r8   r8   r9   Úswitch_to_default_driverº  s    z!BaseCase.switch_to_default_driverc           
      C   sú   |   ¡ r| jj|||d� dS |  ¡  |rb|rb|  ||¡\}}t | j||¡rbt | j||||¡S | jrê|  	¡ }|rêt
|ƒdkrêd|v s˜d|v s˜d|v rê|  d¡dkrê|  d	¡}|  ¡ }|sÊd
|||g}n||g}	d|	||g}| j |¡ t | j||¡S )aŒ  Saves a screenshot of the current page.
        If no folder is specified, uses the folder where pytest was called.
        The screenshot will include the entire page unless a selector is given.
        If a provided selector is not found, then takes a full-page screenshot.
        If the folder provided doesn't exist, it will get created.
        The screenshot will be in PNG format: (*.png)©Úfolderr-  Nr   r£   r¤   r¥   rB  rC  r    Ús_scrÚss_tf)r´   rµ   Úsave_screenshotrÔ   r  r$   r   r=   rÇ   r„  r  rG  rÈ   rÉ   rF   r�   )
r3   r”   r9  r-  rð   rÛ   rÝ   rÞ   rß   Zname_folderr8   r8   r9   r<  Ä  s.    	ÿ
zBaseCase.save_screenshotc           
      C   sÎ  |   ¡ s|  ¡  tj | j|  ¡ ¡}|  |¡ |r:t|ƒ}|  j	d7  _	|rXt
|ƒdkrdd| j	 }nRd| j	 }t
|ƒdkrª|dd…  ¡ dkrª|dd… }t
|ƒdkrªd	}d
||f }|�r"|�r"|  ||¡\}}t | j||¡�r"|   ¡ �r| j||d�}| jj|||d�S t | j||||¡S | j�rž|  ¡ }|�ržt
|ƒdk�ržd|v �sdd|v �sdd|v �rž|  d¡dk�rž|  d¡}|  ¡ }dd||g}	| j |	¡ dt_|   ¡ �r¾| jj||d�S t | j||¡S )a  Saves a screenshot of the current page to the "latest_logs/" folder.
        Naming is automatic:
            If NO NAME provided: "_1_screenshot.png", "_2_screenshot.png", etc.
            If NAME IS provided, it becomes: "_1_name.png", "_2_name.png", etc.
        The screenshot will include the entire page unless a selector is given.
        If a provided selector is not found, then takes a full-page screenshot.
        (The last_page / failure screenshot is always "screenshot.png")
        The screenshot will be in PNG format.r�   r   z_%s_screenshot.pngú_%s_r–  éüÿÿÿNú.pngZ
screenshotz%s%s.pngrï   r8  r£   r¤   r¥   rB  rC  r    Úss_tlrd  T©r9  )r´   rÔ   ry  rz  r2  Úlog_pathr$  Ú$_BaseCase__create_log_path_as_neededrÁ   rS   r  r  r  r$   r   r=   r<  rµ   r<  rÇ   r„  rG  rÈ   rÉ   rF   r�   Ú	sb_configÚ	_has_logs)
r3   r”   r-  rð   Útest_logpathÚpre_namerÛ   rÝ   rÞ   rß   r8   r8   r9   Úsave_screenshot_to_logsæ  sN    

 
ÿÿ

z BaseCase.save_screenshot_to_logsc                 C   s   | j ||d�S )zSame as self.print_to_pdf()rA  )Úprint_to_pdf©r3   r”   r9  r8   r8   r9   Úsave_as_pdf  s    zBaseCase.save_as_pdfc                 C   sZ  |   ¡ s|  ¡  tj | j|  ¡ ¡}|  |¡ |r:t|ƒ}|  j	d7  _	|rXt
|ƒdkrdd| j	 }nRd| j	 }t
|ƒdkrª|dd…  ¡ dkrª|dd… }t
|ƒdkrªd	}d
||f }| j�r.|  ¡ }|�r.t
|ƒdk�r.d|v sôd|v sôd|v �r.|  d¡dk�r.|  d¡}|  ¡ }dd||g}| j |¡ dt_|   ¡ �rN| jj||d�S |  ||¡S )zÞSaves the page as a PDF to the "latest_logs/" folder.
        Naming is automatic:
            If NO NAME provided: "_1_PDF.pdf", "_2_PDF.pdf", etc.
            If NAME IS provided, then: "_1_name.pdf", "_2_name.pdf", etc.r�   r   z_%s_PDF.pdfr=  r–  r>  Nú.pdfZPDFz%s%s.pdfr£   r¤   r¥   rB  rC  r    Úpdftlrd  TrA  )r´   rÔ   ry  rz  r2  rB  r$  rC  rÁ   rT   r  r  rÇ   r„  rG  rÈ   rÉ   rF   r�   rD  rE  rµ   rI  ©r3   r”   rF  rG  rÛ   rÝ   rÞ   rß   r8   r8   r9   Úsave_as_pdf_to_logs  s8    

 

zBaseCase.save_as_pdf_to_logsc                 C   sD  |   ¡ s|  ¡  tj | j|  ¡ ¡}|  |¡ |r:t|ƒ}|  j	d7  _	|rXt
|ƒdkrdd| j	 }nRd| j	 }t
|ƒdkrª|dd…  ¡ dkrª|dd… }t
|ƒdkrªd	}d
||f }| j�r.|  ¡ }|�r.t
|ƒdk�r.d|v sôd|v sôd|v �r.|  d¡dk�r.|  d¡}|  ¡ }dd||g}| j |¡ dt_t | j||¡S )a/  Saves the page HTML to the "latest_logs/" folder.
        Naming is automatic:
            If NO NAME provided: "_1_source.html", "_2_source.html", etc.
            If NAME IS provided, then: "_1_name.html", "_2_name.html", etc.
        (The last_page / failure page_source is always "page_source.html")r�   r   z_%s_source.htmlr=  r–  r>  Nru  Úsourcez	%s%s.htmlr£   r¤   r¥   rB  rC  r    Úspstlrd  T)r´   rÔ   ry  rz  r2  rB  r$  rC  rÁ   rR   r  r  rÇ   r„  rG  rÈ   rÉ   rF   r�   rD  rE  r$   Úsave_page_sourcer=   rN  r8   r8   r9   Úsave_page_source_to_logsA  s4    

 
z!BaseCase.save_page_source_to_logsc                 C   s†   t j | j|  ¡ ¡}|  |¡ |r*t|ƒ}|r:t|ƒdkrT|  jd7  _d| j }nd|vrdd| }|| _	dt
_|}t |||¡ dS )a¼  Saves data to the "latest_logs/" data folder of the current test.
        If no file_name, file_name becomes: "data_1.txt", "data_2.txt", etc.
        Useful variables for getting the "latest_logs/" or test data folders:
            self.log_path OR self.log_abspath  (For the top-level folder)
            self.data_path OR self.data_abspath  (Individual test folders)
        If a file_name is given with no extension, adds ".txt" to the end.r   r�   údata_%s.txtrw  ú%s.txtTN)ry  rz  r2  rB  r$  rC  rÁ   r  rU   rV   rD  rE  r%   Ú_save_data_as©r3   r²   Ú	file_namerF  Údestination_folderr8   r8   r9   Úsave_data_to_logsc  s    
zBaseCase.save_data_to_logsc                 C   s®   t j | j|  ¡ ¡}|  |¡ |r*t|ƒ}|r:t|ƒdkrH| jrH| j}nD|rXt|ƒdkr|| j	dkrp|  j	d7  _	d| j	 }nd|vrŒd| }|| _dt
_|}t |||¡ dS )zÿSaves data to the "latest_logs/" folder of the current test.
        If no file_name, file_name becomes the last data file used in
            save_data_to_logs() or append_data_to_logs().
        If neither method was called before, creates "data_1.txt".r   r�   rT  rw  rU  TN)ry  rz  r2  rB  r$  rC  rÁ   r  rV   rU   rD  rE  r%   Ú_append_data_to_filerW  r8   r8   r9   Úappend_data_to_logsx  s     

zBaseCase.append_data_to_logsc                 C   s    |   ¡ s|  ¡  t | j||¡S )a#  Saves the page HTML to the current directory (or given subfolder).
        If the folder specified doesn't exist, it will get created.
        @Params
        name - The file name to save the current page's HTML to.
        folder - The folder to save the file to. (Default = current folder))r´   rÔ   r$   rR  r=   rJ  r8   r8   r9   rR  Ž  s    zBaseCase.save_page_sourceúcookies.txtc           	      C   sê   |   ¡  | j ¡ }t |¡}| d¡r.tdƒ‚d|v rD| d¡d }d|v rZ| d¡d }t|ƒdk rntdƒ‚| d¡s€|d }t	j
j}tj d¡}tj ||¡}tj |¡s¸t |¡ tj ||¡}t|d	d
d�}| |¡ | ¡  dS )z5Saves the page cookies to the "saved_cookies" folder.rÏ  úInvalid filename for Cookies!rû   ú\r�   ú"Filename for Cookies is too short!ú.txtrw  úw+úutf-8©ÚmodeÚencodingN)rÔ   r=   Úget_cookiesÚjsonÚdumpsrZ  r¿   rž  r  r!   ÚSavedCookiesÚSTORAGE_FOLDERry  rz  r{  r2  ÚexistsÚmakedirsr¶   Ú
writelinesÚclose)	r3   r”   ÚcookiesÚjson_cookiesr9  r~  r  Úcookies_file_pathZcookies_filer8   r8   r9   Úsave_cookies˜  s,    





zBaseCase.save_cookiesc                 C   sâ   |   |¡}|  ¡  |  ¡ }| d¡d }|D ]°}d|v rL|d |vrL||d< d|v rh|r`|dkrh|d= nh|du r†tt ¡ ƒd |d< nJt|ttfƒrž|dk ržn2t|ttfƒrÐ|dkrÐtt ¡ ƒt|d ƒ |d< | j 	|¡ q,d	S )
a_  
        Loads the page cookies from the "saved_cookies" folder.
        Usage for setting expiry:
        If expiry == 0 or False: Delete "expiry".
        If expiry is True: Set "expiry" to 24 hours in the future.
        If expiry == -1 (or < 0): Do not modify "expiry".
        If expiry > 0: Set "expiry" to expiry minutes in the future.
        rž   rû   ÚdomainÚexpiryr   Té€Q ç      N@N)
Úget_saved_cookiesrÔ   rÉ   rž  rO   rD   r˜  r  r=   Ú
add_cookie)r3   r”   ru  rp  rÞ   Útrim_originÚcookier8   r8   r9   Úload_cookies±  s"    	
zBaseCase.load_cookiesc                 C   s\   |   ¡ r| j ¡  dS |  ¡  | j ¡  | jrX|  d¡}|  ¡ }dd||g}| j	 
|¡ dS )zWDeletes all cookies in the web browser.
        Does NOT delete the saved cookies file.Nr    Úd_a_crd  )r´   rµ   Zclear_cookiesrÔ   r=   Údelete_all_cookiesrÇ   rÈ   rÉ   rF   r�   r•  r8   r8   r9   r~  Ì  s    


zBaseCase.delete_all_cookiesc                 C   s¢   |  d¡rtdƒ‚d|v r(| d¡d }t|ƒdk r<tdƒ‚|  d¡sN|d }tjj}tj 	d¡}tj 
||¡}tj 
||¡}tj |¡rž|  d¡ržt |¡ dS )	zsDeletes the cookies file from the "saved_cookies" folder.
        Does NOT delete the cookies from the web browser.rÏ  r^  rû   r�   r`  ra  rw  N)rZ  r¿   rž  r  r!   rj  rk  ry  rz  r{  r2  rl  Úremove)r3   r”   r9  r~  r  rr  r8   r8   r9   Údelete_saved_cookiesÚ  s    


zBaseCase.delete_saved_cookiesc                 C   sØ   |  d¡rtdƒ‚d|v r(| d¡d }d|v r>| d¡d }t|ƒdk rRtdƒ‚|  d¡sd|d }tjj}tj 	d¡}tj 
||¡}tj 
||¡}d	}t|d
ƒ�}| ¡  ¡ }W d	  ƒ n1 sÄ0    Y  t |¡S )z6Gets the page cookies from the "saved_cookies" folder.rÏ  r^  rû   r_  r�   r`  ra  rw  Nrx  )rZ  r¿   rž  r  r!   rj  rk  ry  rz  r{  r2  r¶   r|  rÂ   rh  Úloads)r3   r”   r9  r~  r  rr  rq  r€  r8   r8   r9   rx  í  s$    

*zBaseCase.get_saved_cookiesc                 C   s   |   ¡  |  ¡  | j |¡S r.   )r³   r¼   r=   Ú
get_cookie)r3   r”   r8   r8   r9   r‚    s    zBaseCase.get_cookiec                 C   s   |   ¡  |  ¡  | j ¡ S r.   )r³   r¼   r=   rg  r‹   r8   r8   r9   rg    s    zBaseCase.get_cookiesc                 C   s,   |   ¡  |  ¡ r| j ¡ S |  ¡  |  d¡S )Nzreturn document.cookie;)r³   r´   rµ   Úget_cookie_stringr¼   rÈ   r‹   r8   r8   r9   rƒ    s
    
zBaseCase.get_cookie_stringc                 C   sÚ   |   ¡  |  ¡  |}d|v rF|  ¡ }| d¡d }|d |vrF||d< d|v rb|rZ|dkrb|d= nh|du r€tt ¡ ƒd |d< nJt|ttfƒr˜|dk r˜n2t|ttfƒrÊ|dkrÊtt ¡ ƒt|d ƒ |d< | j 	|¡ d	S )
aE  Usage examples:
        self.add_cookie({'name': 'foo', 'value': 'bar'})
        self.add_cookie({'name': 'foo', 'value': 'bar', 'path': '/'})
        self.add_cookie({'name': 'foo', 'value': 'bar', 'secure': True})
        self.add_cookie({'name': 'foo', 'value': 'bar', 'sameSite': 'Strict'})
        Usage for setting expiry:
        If expiry == 0 or False: Delete "expiry".
        If expiry is True: Set "expiry" to 24 hours in the future.
        If expiry == -1 (or < 0): Do not modify "expiry".
        If expiry > 0: Set "expiry" to expiry minutes in the future.
        rt  rž   rû   ru  r   Trv  rw  N©
r³   r¼   rÉ   rž  rO   rD   r˜  r  r=   ry  )r3   Úcookie_dictru  r{  rÞ   rz  r8   r8   r9   ry    s"    zBaseCase.add_cookiec                 C   sà   |   ¡  |  ¡  |  ¡ }| d¡d }|D ]°}d|v rJ|d |vrJ||d< d|v rf|r^|dkrf|d= nh|du r„tt ¡ ƒd |d< nJt|ttfƒrœ|dk rœn2t|ttfƒrÎ|dkrÎtt ¡ ƒt|d ƒ |d< | j 	|¡ q*d	S )
a  
        Usage for setting expiry:
        If expiry == 0 or False: Delete "expiry".
        If expiry is True: Set "expiry" to 24 hours in the future.
        If expiry == -1 (or < 0): Do not modify "expiry".
        If expiry > 0: Set "expiry" to expiry minutes in the future.
        rž   rû   rt  ru  r   Trv  rw  Nr„  )r3   rp  ru  rÞ   rz  r{  r8   r8   r9   Úadd_cookies1  s"    zBaseCase.add_cookiesc                 C   s   t | dd ƒrd}|  |¡ d S )NÚesc_endaã  document.onkeydown = function(evt) {
                    evt = evt || window.event;
                    var isEscape = false;
                    if ("key" in evt) {
                        isEscape = (evt.key === "Escape" || evt.key === "Esc");
                    } else {
                        isEscape = (evt.keyCode === 27);
                    }
                    if (isEscape) {
                        document.sb_esc_end = 'yes';
                    }
                };)r·   rÈ   ©r3   r{  r8   r8   r9   Z__set_esc_skipK  s    ÿzBaseCase.__set_esc_skipc                 C   s&   t | dd ƒr"|  d¡dkr"|  ¡  d S )Nr‡  zreturn document.sb_esc_end;r¯  )r·   rÈ   Úskipr‹   r8   r8   r9   Z__skip_if_esc]  s    zBaseCase.__skip_if_escc                 C   s²   |   ¡  |  ¡  |  ¡  |s"tj}| jr<|tjkr<|  |¡}t | j	|¡ | j
tjd� | jrf|  ¡  |  ¡  |  ¡  | jdkr¦ttddƒr¦t d¡ | jr¦t d¡ |  ¡  dS )zhWaits for the "readyState" of the page to be "complete".
        Returns True when the method completes.ré   ÚnoneÚSKIP_JS_WAITSNr©  r²  T)r³   r¼   rþ   r   r‹  r   r  r#   rÔ   r=   r'  r(  Újs_checking_onÚassert_no_js_errorsr)  r*  r  r·   rD   r¾   rÓ   r,  ©r3   rç   r8   r8   r9   rÔ   b  s,    
ÿ
þ

z&BaseCase.wait_for_ready_state_completec                 K   sF   |   ¡  |stj}| jr,|tjkr,|  |¡}tj| j|fi |¤Ž dS )zkWaits for Angular components of the page to finish loading.
        Returns True when the method completes.T)r³   r   r(  r   r  r#   r'  r=   )r3   rç   r5   r8   r8   r9   r'  |  s    
zBaseCase.wait_for_angularjsc           	      C   sÜ   |   ¡  ttdd ƒs t |¡ n||dk rDt ¡  t |¡ t ¡  nXt ¡ d }||d  }tt|d ƒƒD ].}t ¡  t ¡ d }||kr� qœt d¡ ql| j	rØttdd ƒrØ|  
d¡}|  ¡ }d|||g}| j |¡ d S )	NÚ
time_limitrª   r:   é   r®   Úrecord_sleepr    r¾   )r³   r·   rD  rD   r¾   r&   rÐ   ÚrangerO   rÇ   rÈ   rÉ   rF   r�   )	r3   ÚsecondsÚstart_msÚstop_msr  Únow_msrÝ   rÞ   rß   r8   r8   r9   r¾   ‡  s(    


zBaseCase.sleepc                 C   s:   |   ¡  | jdkrtdƒ‚tj |¡}| jj|dd� dS )zrInstalls a Firefox add-on instantly at run-time.
        @Params
        xpi_file - A file archive in .xpi format.rú   z�install_addon(xpi_file) is for Firefox ONLY!
To load a Chrome extension, use the comamnd-line:
--extension_zip=CRX_FILE  OR  --extension_dir=DIRT)Ú	temporaryN)rÔ   r  r¿   ry  rz  r{  r=   Úinstall_addon)r3   Zxpi_fileZxpi_pathr8   r8   r9   r˜  ž  s    
ÿzBaseCase.install_addonc                 C   s    |   ¡  t | j¡ |   ¡  dS )z‹If "jQuery is not defined", use this method to activate it for use.
        This happens because jQuery is not always defined on web sites.N)rÔ   r#   r�  r=   r‹   r8   r8   r9   r�  ¬  s    zBaseCase.activate_jqueryc                 C   s:   d| _ | jr6|  d¡}|  ¡ }dd||g}| j |¡ d S )NTr    Úa_d_mrd  ©rÕ   rÇ   rÈ   rÉ   rF   r�   r•  r8   r8   r9   Úactivate_demo_mode³  s    
zBaseCase.activate_demo_modec                 C   s:   d| _ | jr6|  d¡}|  ¡ }dd||g}| j |¡ d S )NFr    Úd_d_mrd  rš  r•  r8   r8   r9   Údeactivate_demo_mode»  s    
zBaseCase.deactivate_demo_modec                 C   s   |   ¡  d}|  |¡ d S )Nzdocument.designMode = 'on';©rÔ   rÈ   rˆ  r8   r8   r9   Úactivate_design_modeÃ  s    zBaseCase.activate_design_modec                 C   s   |   ¡  d}|  |¡ d S )Nzdocument.designMode = 'off';rž  )r3   rÛ   r{  r8   r8   r9   Údeactivate_design_modeÊ  s    zBaseCase.deactivate_design_modec                 K   s(  t | jddƒr`|  ¡ rdS |  ¡ s,| j ¡  |  ¡ }| d¡sJ| j d¡ | jj|fi |¤Ž n | j	dd� | jj|fi |¤Ž | jj
| _
t| j
dƒr | j
j| _t| j
dƒr¶| j
j| _t| j
d	ƒrÌ| j
j| _t | jd
dƒ�rttƒ�( | j
j | j
j d¡¡ W d  ƒ n1 �s0    Y  d| _dS )z*Activate CDP Mode with the URL and kwargs.r™   N)Zaboutr²   r  r;   T)rÓ   Úsolve_captchaÚclick_captchaÚfind_element_by_textZ_is_using_authr4  )r·   r=   r´   Úis_connectedr  r„  rÆ   rÌ   r  rÏ   rµ   rÍ   r¡  r¢  r£  r   r¿   ÚloopZrun_until_completeÚpageÚwaitrÓ   )r3   rÛ   r5   rÀ   r8   r8   r9   rº   Ð  s,    






8zBaseCase.activate_cdp_modec           
      C   s  ddl m} |  ¡ s`tsTtjjtjj }tjjtjj	 }tj
j}|d | d | }td| ƒ‚|  ¡ }| d¡r†d}td| ƒ d	S | jr–| js–d	S |  ¡  ttƒ�V |  d
¡}|dksÄ|  |¡ d| _d}td| ƒ d}	| j|	ddd� W d	  ƒ n1 �s0    Y  d	S )z2Activate Recorder Mode on the newest tab / window.r   )Úrecorder_jsZSeleniumZBasezOThe %s Recorder is for Chromium only!
    (Supported browsers: Chrome and Edge)©údata:zabout:zchrome:zedge:zUThe URL in Recorder-Mode cannot start with: "data:", "about:", "chrome:", or "edge:"!rN  Nr®  r¯  Tz1Recorder Mode ACTIVE. [ESC]: Pause. [~`]: Resume.z4Recorder Mode ACTIVE.<br>[ESC]: Pause. [~`]: Resume.FÚerror)ÚpauseÚstyle)Z seleniumbase.js_code.recorder_jsr¨  r+  Úis_linuxÚcoloramaÚForeZBLUEÚBackZLIGHTCYAN_EXÚLIGHTGREEN_EXÚStyleÚ	RESET_ALLr¿   r„  rÆ   Úprintræ  rÓ   Úswitch_to_newest_tabr   rG  rÈ   rÇ   Úpost_message)
r3   r¨  Úc1Úc2ÚcrÚscrÛ   râ   Zrecorder_onZp_msgr8   r8   r9   Úactivate_recorderê  s<    ÿÿ
ÿ


zBaseCase.activate_recorderc                 C   s8   |   ¡ }|r4t|ƒdkr4d|v s0d|v s0d|v r4dS dS ©Nr   r£   r¤   r¥   TF©r„  r  rä   r8   r8   r9   Z__current_url_is_recordable  s
    z$BaseCase.__current_url_is_recordablec                 C   sú   | j du rdS |  ¡ }|röt|ƒdkröd|v s>d|v s>d|v rö|  ¡ }| j |¡ |  ¡ }tt|ƒƒD ]‚}|dkrf||d  d dkrf||d  d d	krf|| d d
krf||d  d }tt	|| d ƒd ƒ}dd||g}| |¡ qf| j
 |¡ dS )aó  (When using Recorder Mode, use this method if you plan on
            navigating to a different domain/origin in the same tab.)
        This method saves recorded actions from the active tab so that
        a complete recording can be exported as a SeleniumBase file at the
        end of the test. This is only needed in special cases because most
        actions that result in a new origin, (such as clicking on a link),
        should automatically open a new tab while Recorder Mode is enabled.Nr   r£   r¤   r¥   r¾  r±  r�   Úsk_for¢   r,   r½  rd  )r=   r„  r  rÉ   rb   r�   Ú-_BaseCase__get_recorded_actions_on_active_tabr’  rÁ   rO   rc   )r3   rÛ   rÞ   Útab_actionsÚnrÝ   Ú
new_actionr8   r8   r9   r�    s,    
ÿþýüzBaseCase.save_recorded_actionsc                 C   sJ   | j j}| d¡rg S | j |  ¡ ¡ |  d¡}|rBt |¡}|S g S d S )Nr©  Úrecorded_actions)	r=   rÀ   rÆ   rb   r�   rÉ   rG  rh  r�  )r3   rÛ   r@  r8   r8   r9   Z$__get_recorded_actions_on_active_tab1  s    


z-BaseCase.__get_recorded_actions_on_active_tabc           0      C   sˆ'  | j du rdS ddlm} g }g }g }i }| j jD ]Â}|  |¡ |  ¡ }tt|ƒƒD ]‚}|dkrT||d  d dkrT||d  d dkrT|| d dkrT||d  d }	tt	|| d	 ƒd ƒ}
d
d|	|
g}| 
|¡ qT|D ]}||vrÜ| 
|¡ qÜq2| jD ]$}|D ]}||v�r| 
|¡ �qqü| jD ]}||v�r(| 
|¡ �q(|D ]F}t	|d	 ƒt	| jƒk �rh�qHt|d	 ƒd t|d ƒ }|||< �qHt|ƒD ]}| 
|| ¡ �q˜tt|ƒƒD ]$}|| d dk�rºd|| d< �qºtt|ƒƒD ]V}|| d dk�s|| d dk�rì|dk�rì||d  d dk�rìd|| d< �qìtt|ƒƒD �]}|| d dk�rP|dk�rP||d  d dk�r²t	|| d	 ƒt	||d  d	 ƒ dk �s2||d  d dk�ròt	|| d	 ƒt	||d  d	 ƒ dk �s2||d  d dk�rPt	|| d	 ƒt	||d  d	 ƒ dk �rPd|| d< ||d  d dk�rPd||d  d< �qPtt|ƒƒD ]–}|dk�rt||d  d dk�rt|| d dk�sÎ|| d dk�sÎ|| d dk�rtt	|| d	 ƒt	||d  d	 ƒ dk �rtd||d  d< �qttt|ƒƒD ]Š}|| d dk�s@|| d dk�r|dk�r||d  d dk�r||d  d dk�r|| d ||d  d k�rd|| d< �qtt|ƒƒD �]<}|| d dk�sÚ|| d dk�r°|dk�r°||d  d dk�sR||d  d dk�sR||d  d dk�sR||d  d dk�sR||d  d dk�r°||d  d }||d  d }||d  d dk�sÊ||d  d dk�sÊ||d  d dk�sÊ||d  d dk�rÞ||d  d d }| d¡�rø|dd… }n| d¡�r|dd… }|| d }| d¡�r6|dd… }n| d¡�rN|dd… }||k�sà|| dd¡k�sà|| dd ¡k�sà| d!¡d  d"¡�sàt|ƒdk�r°| |¡�s¶d#|v �r°t	|| d	 ƒt	||d  d	 ƒ d$k �r°d%|| d< �q°tt|ƒƒD �]H}|| d dk�s&|| d dk�rü|dk�rü||d  d dk�s\||d  d dk�rü||d  d }| d¡�r†|dd… }n| d¡�rž|dd… }|| d }| d¡�rÄ|dd… }n| d¡�rÜ|dd… }| dd¡| dd¡k�rd||d  d< n<| d d¡|k�r,d||d  d< n| |¡�rüd%|| d< �qütt|ƒƒD ]î}|| d d&k�r²|dk�r²||d  d d&k�r²||d  d dk�r²d||d  d< nŽ|| d d&k�rT|dk�rT||d  d d&k�rT||d  d d'k�rT||d  d  d(¡�rT||d  d || d k�rTd||d  d< �qTtt|ƒƒD �]°}|| d dk�	sz|| d dk�	rP|dk�	rP||d  d dk�
s||d  d dk�
s||d  d dk�
s||d  d dk�
s||d  d dk�
s||d  d d&k�	rPt	|| d	 ƒt	||d  d	 ƒ d$k �	rP||d  d dk�
s ||d  d dk�
s ||d  d dk�
s ||d  d dk�
s ||d  d dk�
rÆ||d  d  d)¡�r d%|| d< n:||d  d d&k�	rP||d  d  d*¡�	rPd%|| d< �	qPtt|ƒƒD ]¨}|| d d+k�r|dk�r||d  d dk�r||d  d dk�r||d  d ||d  d k�rd||d  d< d||d  d< ||d  d || d< �qtt|ƒƒD ]6}|| d d+k�rÆ|| d dk�rÆd|| d< �qÆtt|ƒƒD ]d}|| d d,k�r
|dk�r
||d  d d-k�r
d||d  d< ||d  d d || d< �q
tt|ƒƒD ]D}|| d d&k�r||dk�r|||d  d d.k�r|d|| d< �q|tt|ƒƒD ]l}|| d dk�sö|| d dk�rÎ|dk�rÎ||d  d d'k�s,||d  d d.k�rÎd%|| d< �qÎtt|ƒƒD ]–}|| d dk�sp|| d dk�rH|dk�rH||d  d dk�rH||d  d d/k�rHt	|| d	 ƒt	||d  d	 ƒ d0k �rHd%|| d< �qHtt|ƒƒD ]Ø}|| d dk�s|| d dk�rì|dk�rì||d  d dk�sŒ||d  d dk�sŒ||d  d dk�sŒ||d  d dk�sŒ||d  d dk�rìt	|| d	 ƒt	||d  d	 ƒ d1k �rìd%|| d< �qìtt|ƒƒD ]Ú}|dk�rÒ|| d d%k�rÒ||d  d dk�rÒ|| d }||d  d }| d¡�r<|dd… }| d¡�rT|dd… }| d d¡}| d2d3¡}| d d¡}| d2d3¡}||k�rÒd|| d< d||d  d< �qÒtt|ƒƒD ]€}|| d d%k�rºd4|| d v �rºd5|| d v �rº|| d  d4¡|| d  d5¡k �rº|| d  d5¡d || d< �qºtt|ƒƒD �]}|| d dk�sr|| d dk�rH|dk�rH||d  d dk�rH||d  d d/k�rH||d	  d dk�s||d	  d d6k�s||d	  d d
k�s||d	  d d7k�s||d	  d d8k�rHt	|| d	 ƒt	||d	  d	 ƒ d9k �rHd|| d< �qHtt|ƒƒD ]Ø}|| d dk�s„|| d dk�r\|dk�r\||d  d dk�sü||d  d d6k�sü||d  d d
k�sü||d  d d7k�sü||d  d d8k�r\t	|| d	 ƒt	||d  d	 ƒ d9k �r\d|| d< �q\tt|ƒƒD ]´}|| d dk�sj|| d dk�rB|dk�rB||d  d d%k�s ||d  d dk�rB|| d ||d  d k�rBt	|| d	 ƒt	||d  d	 ƒ d0k �rBd|| d< �qBtt|ƒƒD ]ð}|| d d&k�r|dk�r||d  d dk�r||d  d d&k�r|| d  d*¡�r|| d ||d  d k�r|| d dd… ||d  d k�rt	|| d	 ƒt	||d  d	 ƒ dk �rd||d  d< d||d  d< �qtt|ƒƒD ]†}|| d d&k�r|dk�r||d  d dk�r|| d  d*¡�rt	|| d	 ƒt	||d  d	 ƒ d:k �rd||d  d< �qtt|ƒƒD ]Ü}|| d d&k�r–|dk�r–||d	  d d;k�r–||d  d dk�r–||d  d dk�r–|| d  d*¡�r–|| d dd… ||d	  d d k�r–t	|| d	 ƒt	||d	  d	 ƒ dk �r–d||d	  d< �q–tt|ƒƒD ]Æ}|| d d&k�r€|dk�r€||d  d d<k�r€||d  d dk�r€|| d  d*¡�r€|| d dd… ||d  d d k�r€t	|| d	 ƒt	||d  d	 ƒ d:k �r€d||d  d< �q€g }tt|ƒƒD ]t}|| d dk�s’|| d dk�s’|| d d%k�rX|| d }	|	 d¡�r¶|	dd… }	|	|v�rX| 
|	¡ �qX| jD ]}	| 
|	¡ �qÔtt|ƒƒD ]¢}|| d dk�rò|dk�rò||d  d d=k�rò||d  d |v �ròd||d  d< d>|| d< ||d  d d || d< ||d  d d || d< �qòtt|ƒƒD ]f}|| d d-k�r¢|| d |v �r¢d,|| d< || d d || d< || d d || d< �q¢tt|ƒƒD ]H}|| d d?k�r|dk�r||d  d d?k�rd||d  d< �qtt|ƒƒD ]d}|| d d@k�rlt t|| d d ƒ¡|| d d< t t|| d d ƒ¡|| d d< �qlg }| 
d¡ | 
d¡ | 
d¡ | 
d;¡ | 
dA¡ | 
d¡ | 
d¡ | 
d<¡ | 
dB¡ | 
dC¡ | 
dD¡ | 
dE¡ | 
dF¡ | 
dG¡ | 
dH¡ | 
dI¡ | 
dJ¡ | 
dK¡ | 
dL¡ | 
dM¡ | 
dN¡ | 
dO¡ | 
dP¡ | 
dQ¡ | 
dR¡ | 
dS¡ | 
dT¡ | 
dU¡ | 
dV¡ | 
dW¡ | 
d¡ | 
d6¡ | 
d
¡ | 
d8¡ | 
d7¡ | 
dX¡ | 
dY¡ | 
d?¡ | 
dZ¡ | 
d[¡ | 
d\¡ | 
d]¡ | 
d^¡ | 
d_¡ | 
d`¡ | 
d.¡ | 
da¡ | 
db¡ | 
dc¡ | 
dd¡ | 
de¡ | 
df¡ | 
dg¡ | 
dh¡ | 
di¡ | 
dj¡ | 
dk¡ | 
dl¡ | 
dm¡ tt|ƒƒD �]Ø}|| d |v �r0|| d }	|| d dk�sœ|| d dk�sœ|| d dk�sœ|| d dk�r¬|| d d }	|	 d¡�rÄ|	dd… }	|| d d;k�r|| d d || d< || d d || d< || d d<k�rH|| d d || d< || d d || d< || d dBk�rŠ|| d d || d< || d d || d< || d d.k�rÌ|| d d || d< || d d || d< || d dk�rò|	|v�rò| 
|	¡ |	|v�r0d|| d< �q0tt|ƒƒD ]Ž}|| d d&k�r|dk�r||d  d d;k�sz||d  d d<k�sz||d  d dBk�r|| d ||d  d k�rd|| d< �qtt|ƒƒD ]$}|| d dk�r´d|| d< �q´tt|ƒƒD ]T}|| d dAk�rædn|| d< || d d || d< || d d || d< �qæ| |¡}|  ¡ }| jj}| j}d}ttdodƒ�rü|dpk�s‚|dqk�rüddl}|  ¡ d  t!j"¡d }| dr¡d }t| dsdƒ�rÆ| j#}n| dt¡d }du}dv| dw¡d  }| dx¡d dy }t$| dzƒ�rptj%}| d{¡d }| d{¡d }| &d{¡dk�rJ| d{¡d| }nd}}| d~d¡ d€d¡}t' (d�d‚|¡}t| dƒdƒ� rˆtj)j*}| dd!¡ d„d!¡}t' (d…d|¡}| d!¡}d}|D ]"}||d  +¡ |dd…  7 }�qº|}tj,j*}| dd‚¡ d„d‚¡}| d†d‡¡}| dˆd‰¡}| dŠd‹¡}| dŒd�¡}| dŽd�¡}| d�d‘¡}t' (d…d|¡}| d’d‚¡ -¡ }| d!d‚¡ -¡ }| d“¡� sˆd“| }d”}g } |tj.v� rúd•}g tj.|< |  
d–¡ d—t/j0v � rÌ|  
d˜¡ n
|  
d™¡ |  
d¡ |  
d¡ |  
dš| ¡ n
tj.| } |�!s(|d! 1| ¡v�!r(|  
dš| ¡ |  
d›| ¡ t|ƒdk�!rŽd—t/j0v �!rZ|  
dœ¡ |D ],}d—t/j0v �!rz| d�dž¡}|  
dŸ| ¡ �!q^n
|  
d ¡ |  
d¡ | tj.|< | }!t2j3j4}"|" d¡�!rÐ|"dd… }"t!j5 6|"¡�"s$t7t8ƒ�, t! 9|"¡ t/j: ;d¡t!j" ¡ W d  ƒ n1 �"s0    Y  g } |  
d¡ d¢}#t!j5 1|"|#¡}$t!j5 6|$¡�"sŠt<|$d£d¤d¥�}%|% =d¦ 1| ¡¡ |% >¡  t/j: ;d§t!j" ¡ g } |  
d¨¡ |  
d©¡ |  
dª¡ |  
d«¡ |  
d¬¡ |  
d­¡ |  
d®¡ |  
d¯¡ |  
d°¡ |  
d±¡ |  
d²¡ |  
d³¡ |  
d´¡ |  
dµ¡ |  
d¶¡ |  
d·¡ |  
d¸¡ |  
d¹¡ |  
dº¡ |  
d»¡ |  
d¼¡ |  
d½¡ |  
d¾¡ |  
d¿¡ |  
dÀ¡ |  
dÁ¡ |  
dÂ¡ |  
dÃ¡ |  
dÄ¡ |  
dÅ¡ |  
dÆ¡ |  
dÇ¡ |  
dÈ¡ |  
dÉ¡ |  
dÊ¡ |  
dË¡ |  
dÌ¡ |  
dÍ¡ |  
d¡ dÎ}#t!j5 1|"|#¡}$t!j5 6|$¡�$slt<|$d£d¤d¥�}%|% =d¦ 1| ¡¡ |% >¡  t/j: ;dÏt!j" ¡ g } |  
dÐ¡ |  
dÑ¡ |  
dÒ¡ |  
d¡ |  
dÓ¡ |  
dÔ¡ |  
dÕ¡ |  
d¡ |  
dÖ¡ |  
d×¡ |  
dØ¡ |  
d¡ dÙ}#t!j5 1|"|#¡}$t!j5 6|$¡�%s@t<|$d£d¤d¥�}%|% =d¦ 1| ¡¡ |% >¡  t/j: ;dÚt!j" ¡ |!} | jj? dx¡d dy }&t$| dzƒ�%r tj%}| d{¡d  d¡d  dÛ¡d }&|& dÜ¡d dy }&t| dƒdƒ�%ràtj,j@ dxd‚¡}&|& d¡d  dÛ¡d dy }&|&}&n
|�%rê|}&t!j5 1|"|&¡}'t<|'d£d¤d¥�}%|% =d¦ 1| ¡¡ |% >¡  dÝ}(|�&s,dÞ}(t|(ƒt|'ƒ })t7t8ƒ�2 t! A¡ jB}*|*dßk�&rh|)|*k�&rh|*})W d  ƒ n1 �&s~0    Y  dà}+t| dádƒ�&rüd}+t/j: ;dât!j"|&f ¡ tCƒ  d!|'v�&rÔt! Ddã|' ¡ n(dt|'v�&rît! Ddä|' ¡ nt! Ddå|' ¡ dæ|) },d}-d}.d}/tE�'sRtFjGjHtFjIjJ }-tFjGjKtFjIjJ }.tFjLjM}/|( dç|.dç |/ ¡}(tCdè|+|(|-|'|/|,f ƒ t| dédƒ�'r„|  N|tF¡ dS )êz4Generates code after the SeleniumBase Recorder runs.Nr   )Úrecorder_helperr¾  r±  r�   r¿  r¢   r,   r½  rd  ú-r°  ÚbeginZ_skipZc_boxr  é   Újs_clrM  Újq_cli¸  Zch_clÚjs_caÚjq_caz/#/éýÿÿÿrÏ  rû   zwww.rœ   zhttp://re  za[href=z?searchid  Zf_urlrì  Zsubmirí  )rì  ÚbuttonrN  ZdbclkZcho_fÚchfilÚe_mfar¡   iÀ  iP  z://www.rž   r›  rœ  r·  rÃ  rÂ  ih  i„  Újs_tyÚjq_tyr;  Zh_clkÚsh_fcZcanvaÚs_valrn  rD  Úas_elÚas_epÚasenvÚacc_aÚdis_aÚhi_liÚas_ltÚas_tiÚas_tcÚa_urlÚa_u_cÚas_dfÚdo_fiÚas_atÚas_teÚastnvÚaetnvÚas_etÚasnetÚwf_elr8  r¾   rô  rù  r™  rœ  Úc_l_sÚc_s_sr}  rŽ  r’  r:  r;  r@  rM  rQ  Úda_elÚda_epÚda_teÚda_etÚdanetÚpr_daZset_vÚis_context_managerúbase_case.pyÚrunTestú, in Úcm_filenameú"ZSB_TestZ
test_line_ú, line rw  z_rec.pyÚ_using_sb_fixtureú::éþÿÿÿÚMyTestClassú[Ú__ú]z[\W]Ú_Ú	is_behavez & ú[^\w_ ]z + z plus z - z minus u    Ã— z times u    Ã· z divided by z = z equals z %% z	 percent z _ Ztest_FTú!from seleniumbase import BaseCaseú--ucz)BaseCase.main(__name__, __file__, "--uc")z!BaseCase.main(__name__, __file__)zclass %s(BaseCase):z    def %s(self):z         self.activate_cdp_mode()z
self.type(zself.press_keys(z        z        passz
Created recordings%sú__init__.pyrb  rc  rd  ú
z 
Created recordings%s__init__.pyz[pytest]z*addopts = --capture=no -p no:cacheproviderz4norecursedirs = .* build dist recordings temp assetszfilterwarnings =z     ignore::pytest.PytestWarningz5    ignore:.*U.*mode is deprecated:DeprecationWarningzjunit_family = legacyzpython_files =z    test_*.py z    *_test.py z    *_tests.pyz    *_suite.pyz    *_feature.pyz    *_test_rec.pyz    *_feature_rec.pyz1python_classes = Test* *Test* *Test *Tests *Suitezpython_functions = test_*z	markers =z    marker1: custom markerz    marker2: custom markerz    marker3: custom markerz$    marker_test_suite: custom markerz#    expected_failure: custom markerz    local: custom markerz    remote: custom markerz    offline: custom markerz    develop: custom markerz    qa: custom markerz    ci: custom markerz    e2e: custom markerz    ready: custom markerz    smoke: custom markerz    deploy: custom markerz    active: custom markerz    master: custom markerz    release: custom markerz    staging: custom markerz    production: custom markerz
pytest.iniz
Created recordings%spytest.iniz[flake8]zexclude=recordings,tempzignore=W503z[nosetests]znocapture=1zlogging-level=INFOú[behave]úshow_skipped=falseúshow_timings=falsez	setup.cfgz
Created recordings%ssetup.cfgr_  ú.pyú>>> RECORDING SAVED as: ú>>> RECORDING ADDED to: é   z

Ú	rec_printz
Created recordings%s%súsbase print %s -núsbase print "%s" -núsbase print '%s' -nÚ*ú>>>ú%s%s%s%s%s
%sÚ
rec_behave)Or=   Úseleniumbase.corerÅ  r  r  rÀ  r’  r  rÁ   rO   r�   rc   rF   rG   ÚsortedrZ  ri  rž  rÆ   r�  rb   r–  r—  r  Zgenerate_sbase_codeÚ_BaseCase__get_filenamer7   Ú__name__Ú_testMethodNamer·   rD  Ú	tracebackÚformat_stackry  Úseprõ  rÍ   Ú_test_idrh  r=  ÚsubÚbehave_featurer”   ÚupperÚbehave_scenarior  Ú_recorded_actionsr�   r‘   r2  r!   Ú
RecordingsÚSAVED_FOLDERrz  rl  r   r¿   rm  ÚstdoutÚwriter¶   rn  ro  Ú
__module__ÚfilenameÚget_terminal_sizeÚcolumnsrµ  Úsystemr®  r¯  r°  ÚREDr±  ÚLIGHTYELLOW_EXÚLIGHTRED_EXr³  r´  Ú*_BaseCase__process_recorded_behave_actions)0r3   rÅ  Zraw_actionsÚsrt_actionsZ
sb_actionsZaction_dictrÍ  rÁ  rÂ  rÞ   rÝ   rÃ  rß   rs  Zsel1Úurl1Úurl2Zurl0ZoriginsZext_actionsr(  Ú	classnameÚ
methodnameZcontext_filenamer  Ú
stack_baseÚ	test_baser
  Zclassname_partsZnew_classnameÚpartÚnew_filer²   Z
saved_dataÚrecordings_folderZextra_file_nameZextra_file_pathÚout_filerX  r  Úrec_messageÚstar_lenÚterminal_sizeÚspcÚstarsr¸  r¹  rº  r8   r8   r9   Z__process_recorded_actions=  s®   

ÿþýü



ÿÿþýÿþû"ÿú
ö"ÿõñ"ÿðÿþüûú	&÷ÿÿþýüûÿÿþüûúùøÿþýüÿþýü
ûúúÿÿù
ÿÿþüûÿþýüÿþýüûúÿÿþüûúùø	÷&õÿþýüûÿþýüûÿþÿþý ÿþýÿÿþüûÿÿþýü&ú	ÿÿþüûúùø&õÿþý
ÿþý"ü"ÿÿþýüúùø	÷
ö&óÿÿþüûúùø&õÿÿþüûù	&÷ÿþýüûú"ù	&÷ÿþýü&ú	ÿþýüûú&ù	&÷ÿþýüû&ú&øÿþý

ÿþýü $ÿþý&*


























































ÿþýü

ÿþüûúø


ÿþþ
 






ÿ




2



















































"

$

z#BaseCase.__process_recorded_actionsc                 C   sŒ  ddl m} | |¡}|  ¡ }d }d }t| dd ƒrDtjj}tjj}n\| j	j
}| j}t| dƒr tj}| d¡d }| d¡d }| d¡dkrœ| d¡d }nd	}d
}	g }
|tjvrÚd}	g tj|< |
 d| ¡ |
 d¡ n
tj| }
|
 d| ¡ t|ƒdk�r^d}dtjv �r"|
 d¡ |d7 }|D ]6}|dk�rD|
 d| ¡ n|
 d| ¡ |d7 }�q&|
 d¡ |
tj|< tjj}| d¡�r’|d d… }tj |¡�sÔttƒ� t |¡ W d   ƒ n1 �sÊ0    Y  tj |d¡}tj |¡�s$ttƒ� t |¡ W d   ƒ n1 �s0    Y  tj |d¡}tj |¡�stttƒ� t |¡ W d   ƒ n1 �sj0    Y  | d¡d }t| dd ƒ�r tjj  !dd¡}| d¡d  d¡d d }tj ||¡}t"|ddd�}| #d |
¡¡ | $¡  d}|	�sþd }t|ƒt|ƒ }ttƒ�2 t %¡ j&}|d!k�r:||k�r:|}W d   ƒ n1 �sP0    Y  d"}t| d#d ƒ�r¸d}t'ƒ  d$|v�r�t (d%| ¡ n(d&|v�rªt (d'| ¡ nt (d(| ¡ d)| }d}d}d}t)�s|j*j+|j,j- }|j*j.|j,j- }|j/j0}| !d*|d* | ¡}t'd+||||||f ƒ g }
|
 d¡ d,}tj ||¡}tj |¡�s‚t"|ddd�}| #d |
¡¡ | $¡  t'd-ƒ g }
|
 d.¡ |
 d/¡ |
 d0¡ |
 d¡ d1}tj ||¡}tj |¡�süt"|ddd�}| #d |
¡¡ | $¡  t'd2ƒ g }
|
 d3¡ |
 d4¡ |
 d5¡ |
 d6¡ |
 d7¡ |
 d8¡ |
 d9¡ |
 d:¡ |
 d;¡ |
 d<¡ |
 d=¡ |
 d¡ d>}tj ||¡}tj |¡�sÆt"|ddd�}| #d |
¡¡ | $¡  t'd?ƒ g }
|
 d¡ d,}tj ||¡}tj |¡�s"t"|ddd�}| #d |
¡¡ | $¡  t'd@ƒ g }
|
 dA¡ |
 d¡ dB}tj ||¡}tj |¡�sˆt"|ddd�}| #d |
¡¡ | $¡  t'dCƒ d S )DNr   )Úbehave_helperr   rø  rù  rû   r¾  rú  rû  FTzFeature: %srd  z  Scenario: %sr  z    Given Activate CDP Moder�   z
    Given z    And rÏ  ÚfeaturesZstepsrw  rÿ  r_  z_rec.featurerb  rc  rd  r  r
  r  r  rN  r  re  r  rö  r  r  r  r  r  r  z'Created recordings/features/__init__.pyr  r  r  z
behave.iniz&Created recordings/features/behave.inir  z)from seleniumbase.behave import behave_sbzAbehave_sb.set_base_class(BaseCase)  # Accepts a BaseCase subclassz<from seleniumbase.behave.behave_sb import before_all  # noqaz@from seleniumbase.behave.behave_sb import before_feature  # noqazAfrom seleniumbase.behave.behave_sb import before_scenario  # noqaz=from seleniumbase.behave.behave_sb import before_step  # noqaz<from seleniumbase.behave.behave_sb import after_step  # noqaz@from seleniumbase.behave.behave_sb import after_scenario  # noqaz?from seleniumbase.behave.behave_sb import after_feature  # noqaz;from seleniumbase.behave.behave_sb import after_all  # noqazenvironment.pyz*Created recordings/features/environment.pyz-Created recordings/features/steps/__init__.pyz-from seleniumbase.behave import steps  # noqazimported.pyz-Created recordings/features/steps/imported.py)1Zseleniumbase.behaver@  Zgenerate_gherkinr  r·   rD  r  r”   r!  r7   r  r  rÍ   r  rž  rh  Ú_behave_recorded_actionsr�   r  r�   r‘   r!   r#  r$  rZ  ry  rz  rl  r   r¿   rm  r2  r(  ri  r¶   rn  ro  r)  r*  rµ  r+  r®  r°  r,  r±  r-  r.  r³  r´  )r3   r0  r¯  r@  Zbehave_actionsr(  Zfeature_classZscenario_testr
  r8  r²   rh  rß   r9  Zfeatures_folderZsteps_folderrX  r  r:  r;  r<  r=  r>  r?  r¸  r¹  rº  r8   r8   r9   Z!__process_recorded_behave_actionsH  sJ   










*
*
*

$








ÿÿÿÿÿÿÿÿÿ



z*BaseCase.__process_recorded_behave_actionsc                 C   s`   |   ¡  |  ¡ r| j ¡  dS ttƒ�& |  ¡ s>|  | jj	¡ W d  ƒ n1 sR0    Y  dS )z}Brings the active browser window to the front (on top).
        Useful when multiple drivers are being used at the same time.N)
r³   r´   rµ   r4  r   r¿   r“  r  r=   r  r‹   r8   r8   r9   r4  ý  s    

z%BaseCase.bring_active_window_to_frontc                 C   sŒ   |   ¡  |  ||¡\}}| j||tjd�}z| j||d�}W n$ ty`   d}|  ||¡ Y dS 0 t 	|¡}|  
|¡}d| }|  |¡ dS )zøUpdates the Z-index of a page element to bring it into view.
        Useful when getting a WebDriverException, such as the one below:
            { Element is not clickable at point (#, #).
              Other element would receive the click: ... }rI  rï   z%arguments[0].style.zIndex = '999999';Nz5document.querySelector('%s').style.zIndex = '999999';)r³   r  r  r   rÿ   r<  r¿   rÈ   r=  r>  r?  )r3   r-  rð   r0  r{  r8   r8   r9   Úbring_to_front
  s$    ÿ

ÿÿzBaseCase.bring_to_frontr,   c                 C   sL   |   ¡  |stj}| j|||d� | js:| j||||d� | j||d� dS )z+Highlights the element, and then clicks it.rI  ©rð   rá  rè   rï   N)r³   r   rÿ   r  rÕ   Ú_BaseCase__highlightr  )r3   r-  rð   rá  rè   rç   r8   r8   r9   Úhighlight_click#  s    zBaseCase.highlight_clickc                 C   sN   |   ¡  |stj}| j|||d� | js:| j||||d� | j|||d� dS )z:Highlights the element and then types text into the field.rI  rD  rï   N©r³   r   rÿ   r  rÕ   rE  r`  ©r3   r-  r]  rð   rá  rè   rç   r8   r8   r9   Úhighlight_update_text/  s    
zBaseCase.highlight_update_textc                 C   sN   |   ¡  |stj}| j|||d� | js:| j||||d� | j|||d� dS )zqSame as self.highlight_update_text()
        As above, highlights the element and then types text into the field.rI  rD  rï   NrG  rH  r8   r8   r9   Úhighlight_typeA  s    zBaseCase.highlight_typer–  c                 C   s,   |   ¡  | j||d�r(| j||||d� dS )z1Highlights the element if the element is visible.rï   rD  N)r³   r£  rE  )r3   r-  rð   rá  rè   r8   r8   r9   Úhighlight_if_visibleT  s    zBaseCase.highlight_if_visiblec           	      C   s0  |   ¡  |stj}|rR| jdkrRttƒ� |  |¡ W d   ƒ n1 sH0    Y  | jr^| j}| jdkrld}t|ƒ}| j	s†| j
s†| jr˜tt |d ¡ƒ}d}z| d¡}W n. tyØ   |  ¡  t d¡ | d¡}Y n0 |�rd|v �r| d¡}| d	|¡d }|||… }|}|  |||¡ t d
¡ d S )Nrê   rî   r�   r™  rd  r­  rw  úbox-shadow: ú;ç¤p=
×£°?)r³   r   rÚ  r  r   r¿   rÙ  Ú
highlightsrO   r  rò  r(  r–  r—  r  rÔ   rD   r¾   r�  Ú$_BaseCase__highlight_element_with_js)	r3   r0  rá  rè   rà  r­  Ú	box_startÚbox_endÚoriginal_box_shadowr8   r8   r9   Z__highlight_element\  s8    
(



zBaseCase.__highlight_elementc                 C   s€  |   ¡  | j||dd�\}}| j||tjd�}|s8tj}|rÐzR| jdkr€t | j	|¡}t
|ƒtjjkrt|  ||¡ qŒ|  |¡ n|  ||¡ W n@ tyÎ   |  ¡  t d¡ | j||tjd�}|  |¡ Y n0 d}z| j||d�}W n tyü   d}Y n0 | j�r| j}| jdk�rd	}t|ƒ}| j�s<| j�s<| j�rNtt |d
 ¡ƒ}d}z| d¡}	W nB t�y¢   |  ¡  t d¡ | j|dtjd�}| d¡}	Y n0 |	�rÞd|	v �rÞ|	 d¡}
|	 d|
¡d	 }|	|
|… }|}|�rô|  |||¡ n~d|v�r,d|v�r,t  |¡}|  !|¡}|  "|||¡ nF|  #|¡}t  |¡}|  !|¡}z|  $|||¡ W n t�yp   Y n0 t d¡ dS )z}This method uses fancy JavaScript to highlight an element.
        (Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)F©Úxp_okrI  rê   rw  rï   Trî   r�   r™  rd  r­  rå   rL  rM  ú	:containsú:firstrN  N)%r³   r  r  r   rÿ   rÚ  r  r#   Úget_scroll_distance_to_elementr=   Úabsr!   ÚValuesÚSSMDr×  rÙ  r¿   rÔ   rD   r¾   r<  rO  rO   r  rò  r(  r–  r—  r  r�  rP  r=  r>  r?  Ú_BaseCase__highlight_with_jsrÛ  rÜ  )r3   r-  rð   rá  rè   r0  Úscroll_distanceÚuse_element_directlyrà  r­  rQ  rR  rS  r8   r8   r9   Z__highlight|  s„    ÿ
ÿ
ÿ

ÿ






zBaseCase.__highlightc           	      C   sØ   |   ¡  |  ¡ r4t |¡r<d|v r<| j |¡ dS n|  ¡  |  ¡  t|t	ƒrb| j
|||d� dS |sltj}| j|||d� | j||||d� | jrÔ|  ¡ rÔ|  d¡dkrÔ|  d¡}|  ¡ }d	|||g}| j |¡ dS )
a×  This method uses fancy JavaScript to highlight an element.
        @Params
        selector - the selector of the element to find (Accepts WebElement)
        by - the type of selector to search by (Default: CSS)
        loops - # of times to repeat the highlight animation
                (Default: 4. Each loop lasts for about 0.2s)
        scroll - the option to scroll to the element first (Default: True)
        timeout - the time to wait for the element to appear rø   N©rá  rè   rI  )r-  rð   rá  rè   rB  rC  r    rÚ  )r³   r´   r%   Úis_xpath_selectorrµ   Ú	highlightr¼   rþ   r˜  r   Ú_BaseCase__highlight_elementr   rÿ   r  rE  rÇ   rF  rG  rÈ   rÉ   rF   r�   )	r3   r-  rð   rá  rè   rç   rÝ   rÞ   rß   r8   r8   r9   ra  Ê  s*    


zBaseCase.highlightc           	   	   C   sŒ   |sd}t |ƒ}d}| j||d�}|D ]`}ttƒ�0 | ¡ rT| j|||d� |d7 }W d   ƒ n1 sh0    Y  |dkr&||kr& qˆq&d S )Nr   rï   r_  r�   )rO   r	  r   r¿   ry  rb  )	r3   r-  rð   rá  rè   r  rh  r  r0  r8   r8   r9   Úhighlight_elementsñ  s    
ÿ&zBaseCase.highlight_elementsr�   c              	   C   s¾   |   ¡  |  ¡  |dk rdS |  |¡}|  ||¡ | jsL| jsL|  |||¡ tt|ƒƒD ]`}z| 	t
j¡ W n0 tyœ   |  ¡  |  |¡}| 	t
j¡ Y n0 t d¡ | jrXt d¡ qXdS )z¸Simulates pressing the UP Arrow on the keyboard.
        By default, "html" will be used as the CSS Selector target.
        You can specify how many times in-a-row the action happens.r�   Nr©  r¯   )r³   r¼   rg  r  rÕ   r  r  r’  rO   rX  r   ZARROW_UPr¿   rÔ   r  rD   r¾   ©r3   r-  Útimesrð   r0  Úir8   r8   r9   Úpress_up_arrow  s$    


zBaseCase.press_up_arrowc              	   C   s¾   |   ¡  |  ¡  |dk rdS |  |¡}|  ||¡ | jsL| jsL|  |||¡ tt|ƒƒD ]`}z| 	t
j¡ W n0 tyœ   |  ¡  |  |¡}| 	t
j¡ Y n0 t d¡ | jrXt d¡ qXdS )zºSimulates pressing the DOWN Arrow on the keyboard.
        By default, "html" will be used as the CSS Selector target.
        You can specify how many times in-a-row the action happens.r�   Nr©  r¯   )r³   r¼   rg  r  rÕ   r  r  r’  rO   rX  r   Z
ARROW_DOWNr¿   rÔ   r  rD   r¾   rd  r8   r8   r9   Úpress_down_arrow  s$    


zBaseCase.press_down_arrowc              	   C   s¾   |   ¡  |  ¡  |dk rdS |  |¡}|  ||¡ | jsL| jsL|  |||¡ tt|ƒƒD ]`}z| 	t
j¡ W n0 tyœ   |  ¡  |  |¡}| 	t
j¡ Y n0 t d¡ | jrXt d¡ qXdS )zºSimulates pressing the LEFT Arrow on the keyboard.
        By default, "html" will be used as the CSS Selector target.
        You can specify how many times in-a-row the action happens.r�   Nr©  r¯   )r³   r¼   rg  r  rÕ   r  r  r’  rO   rX  r   Z
ARROW_LEFTr¿   rÔ   r  rD   r¾   rd  r8   r8   r9   Úpress_left_arrow6  s$    


zBaseCase.press_left_arrowc              	   C   s¾   |   ¡  |  ¡  |dk rdS |  |¡}|  ||¡ | jsL| jsL|  |||¡ tt|ƒƒD ]`}z| 	t
j¡ W n0 tyœ   |  ¡  |  |¡}| 	t
j¡ Y n0 t d¡ | jrXt d¡ qXdS )z»Simulates pressing the RIGHT Arrow on the keyboard.
        By default, "html" will be used as the CSS Selector target.
        You can specify how many times in-a-row the action happens.r�   Nr©  r¯   )r³   r¼   rg  r  rÕ   r  r  r’  rO   rX  r   ZARROW_RIGHTr¿   rÔ   r  rD   r¾   rd  r8   r8   r9   Úpress_right_arrowM  s$    


zBaseCase.press_right_arrowc              	   C   sÒ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rD| j |¡ dS | jsP| j	rd| j
|||d� dS | j|||d�}z|  |||¡ W nF ttfyÌ   |  ¡  t d¡ | j|||d�}|  |||¡ Y n0 dS )zFast scroll to destinationNrI  rw  )r³   r   rÿ   r   r  r´   rµ   Úscroll_into_viewrÕ   r  Úslow_scroll_tor  r  r  r  rÔ   rD   r¾   ©r3   r-  rð   rç   r0  r8   r8   r9   rv  d  s.    
ÿ
ÿzBaseCase.scroll_toc                 C   s   | j |||d� dS )zSame as self.scroll_to()rI  N)rv  r5  r8   r8   r9   Úscroll_to_element~  s    zBaseCase.scroll_to_elementc                 C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|}|  ||¡\}}|  ¡ rdd|vrd| j |¡ dS | j	|||d�}zR| j
dkr¸t | j|¡}t|ƒtjjkr¬|  ||¡ qÄ|  |¡ n|  ||¡ W n@ t�y   |  ¡  t d¡ | j	|||d�}|  |¡ Y n0 dS )z!Slow motion scroll to destinationú
:contains(NrI  rê   rw  )r³   r   rÿ   r   r  r  r´   rµ   rk  r  r  r#   rX  r=   rY  r!   rZ  r[  r×  rÙ  r¿   rÔ   rD   r¾   )r3   r-  rð   rç   rí   r/  r0  r]  r8   r8   r9   rl  ‚  s<    
ÿ
ÿ
ÿzBaseCase.slow_scroll_toc                 C   s   | j |||d� dS )zSame as self.slow_scroll_to()rI  N)rl  r5  r8   r8   r9   Úslow_scroll_to_element¥  s    zBaseCase.slow_scroll_to_elementc                 C   sd   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rD| j |¡ dS | j|||d�}|  	d|¡ dS )zÇUses the JS scrollIntoView() method to scroll to an element.
        Unlike other scroll methods, (which put elements upper-center),
        this method places elements at the very top of the screen.Nré   zarguments[0].scrollIntoView();)
r³   r   rÿ   r   r  r´   rµ   rk  r  rÈ   rm  r8   r8   r9   rk  «  s    
zBaseCase.scroll_into_viewc                 C   sb   |   ¡  |  ¡ r| j ¡  dS d}ttƒ�$ |  |¡ t d¡ W d  ƒ n1 sT0    Y  dS )zScroll to the top of the page.Nzwindow.scrollTo(0, 0);rK  )	r³   r´   rµ   Úscroll_to_topr   r¿   rÈ   rD   r¾   ©r3   Úscroll_scriptr8   r8   r9   rq  º  s    


zBaseCase.scroll_to_topc                 C   sb   |   ¡  |  ¡ r| j ¡  dS d}ttƒ�$ |  |¡ t d¡ W d  ƒ n1 sT0    Y  dS )z!Scroll to the bottom of the page.Nzwindow.scrollTo(0, 10000);rK  )	r³   r´   rµ   Úscroll_to_bottomr   r¿   rÈ   rD   r¾   rr  r8   r8   r9   rt  Å  s    


zBaseCase.scroll_to_bottomc                 C   sp   |   ¡  t|ƒ}|  ¡ r(| j |¡ dS d| }ttƒ�$ |  |¡ t 	d¡ W d  ƒ n1 sb0    Y  dS )z!Scroll to y position on the page.Núwindow.scrollTo(0, %s);rK  )
r³   rO   r´   rµ   Úscroll_to_yr   r¿   rÈ   rD   r¾   ©r3   r  rs  r8   r8   r9   rv  Ð  s    

zBaseCase.scroll_to_yc                 C   sp   |   ¡  t|ƒ}|  ¡ r(| j |¡ dS d| }ttƒ�$ |  |¡ t 	d¡ W d  ƒ n1 sb0    Y  dS )zScrolls page by y pixels.Núwindow.scrollBy(0, %s);rK  )
r³   rO   r´   rµ   Úscroll_by_yr   r¿   rÈ   rD   r¾   rw  r8   r8   r9   ry  Ü  s    

zBaseCase.scroll_by_yé   c                 C   s>   |   ¡ r| j |¡ dS |  ¡ d | d }|  d| ¡ dS )z'Scrolls up as a percentage of the page.Nr�  éd   zwindow.scrollBy(0, -%s);)r´   rµ   Ú	scroll_uprœ  rÈ   ©r3   Úamountr8   r8   r9   r|  è  s
    zBaseCase.scroll_upc                 C   s>   |   ¡ r| j |¡ dS |  ¡ d | d }|  d| ¡ dS )z)Scrolls down as a percentage of the page.Nr�  r{  rx  )r´   rµ   Úscroll_downrœ  rÈ   r}  r8   r8   r9   r  ð  s
    zBaseCase.scroll_downc                 C   s   | j |dd� dS )z‰Technically, self.click() automatically detects xpath selectors,
        so self.click_xpath() is just a longer name for the same action.r   rï   N)r  ©r3   r   r8   r8   r9   Úclick_xpathø  s    zBaseCase.click_xpathc                 C   s  |   ¡ r| jj||d� dS |  ¡  |r0|du r6tj}| jrP|tjkrP|  |¡}| j||dd�\}}|t	j
krŽd}t |¡ | j||d� dS | j|||d�}t | j||¡s¶|  ¡  d}| j||d��r&d}|  ||¡ |�r&| j�s&| j�s&t | j|¡}	|	�s&|  ¡  tj}tj| j|||d�}| j||d�}
t |
¡}
|  |
¡}
d	}d
d
d
|g}d}ttƒ� | jj}W d  ƒ n1 �s„0    Y  t| jjƒ}| j �r| j!�s|  "d¡}d}d
}d|
v�rÔ|  "d|
 ¡}|dk�rì|  "d|
 ¡}|  #¡ }||g}d|||g}|�rd|d	< | j||d��sx|  ¡  | j||d��rx|�rx|�sxt | j|¡}	|	�sxtj}tj| j|||d�}| j �r¢| j!�s¢|  "d¡|d< | j$ %|¡ |�s<d|
v�rúz| j&||d� W n0 t�yô   | jj}||k�rð|  '|¡ Y n0 �qhz|  '|¡ W �qh t�y8   |  ¡  t( )d¡ | jj}||k�rP| j||tjd�}||k�rØ|  |¡�rØ|  |¡�rØz|  *|¡ W nT t�yÔ   z|  '|¡ W n0 t�yÎ   | j||tj+d�}|  '|¡ Y n0 Y n0 n\||k�r4z|  '|¡ W nB t�y2   | jj}||k�r.| j||tj+d�}|  '|¡ Y n0 Y n0 n,d|
v�rV| j,||d� nd|
 }|  -|¡ t| jjƒ}||k�r¦| j �sœtj.�r¦| jj|k�r¦|  /¡  n"||d k�rÈ|d	k�rÈ|  0d¡ ttƒ� |  ¡  W d  ƒ n1 �sð0    Y  |  1¡  dS )zéClicks an element using JavaScript.
        Can be used to click hidden / invisible elements.
        If "all_matches" is False, only the first match is clicked.
        If "scroll" is False, won't scroll unless running in Demo Mode.ré   NTFrT  zçPure JavaScript doesn't support clicking by Link Text. You may want to use self.jquery_click() instead, which allows this with :contains(), assuming jQuery isn't blocked. For now, self.js_click() will use a regular WebDriver click.rï   rI  r   rd  r    r9  ú:return document.querySelector('%s').tagName.toLowerCase();rò   ú)return document.querySelector('%s').href;rÉ  rË  r,   rë   újQuery('%s').click();r�   rû   )2r´   rµ   r  rÔ   r   rÿ   r   r  r  r   r  r¸   rÎ   rg  r$   r"  r=   r£  r  rÕ   r  r#   rn  r<  r=  r>  r?  r   r¿   rÀ   r  r  rÇ   re   rÈ   rÉ   rF   r�   r#  Ú_BaseCase__js_click_elementrD   r¾   r  r(  Ú_BaseCase__js_click_allrG  r$  r%  r  rÚ   )r3   r-  rð   Úall_matchesrç   rè   râ   r0  Zscroll_doneræ  rA  rÝ   rß   rÜ   r1  r  ró   rÞ   Úhref_originrÀ   Úclick_scriptr3  r8   r8   r9   r   ý  s   

ÿ
ÿ
ÿ


(

ÿÿ
ÿ
ÿ



ÿÿþýÿ

ÿ

ÿýû
ú


ÿþ

(zBaseCase.js_clickc                 C   s†   |   ¡  | j||d�r&| j||d� n\|dkr‚ttƒ�  | j|||d� W d  ƒ n1 s\0    Y  | j||d�r‚| j||d� dS )a  If the page selector exists, js_click() the element.
        This method only clicks on the first matching element found.
        If a "timeout" is provided, waits that long for the element to
        be present before giving up and returning without a js_click().rï   r   rI  N)rÔ   r   r   r   r¿   rg  r5  r8   r8   r9   Újs_click_if_presentž  s    
.zBaseCase.js_click_if_presentc                 C   s†   |   ¡  | j||d�r&| j||d� n\|dkr‚ttƒ�  | j|||d� W d  ƒ n1 s\0    Y  | j||d�r‚| j||d� dS )a  If the page selector exists and is visible, js_click() the element.
        This method only clicks on the first matching element found.
        If a "timeout" is provided, waits that long for the element
        to appear before giving up and returning without a js_click().rï   r   rI  N)rÔ   r£  r   r   r¿   r  r5  r8   r8   r9   Újs_click_if_visible¬  s    
.zBaseCase.js_click_if_visiblec                 C   s   | j |dd|d� dS )ú7Clicks all matching elements using pure JS. (No jQuery)rå   T)rð   r‡  rç   N)r   r5  r8   r8   r9   Újs_click_allº  s    ÿzBaseCase.js_click_allc                 C   s8  |   ¡  |r|du rtj}| jr4|tjkr4|  |¡}|}| j||dd�\}}| j|||d� | j||d�rv|  ||¡ | j	||d�}|}|  
|¡}d| }| j�r"|  ¡ �r"|  d¡dk�r"|  d	¡}d
}d}	d|vrä|  d| ¡}|dkrú|  d| ¡}	|  ¡ }
|	|
g}d|||g}| j |¡ |  |¡ |  ¡  d
S )zyClicks an element using jQuery. (Different from using pure JS.)
        Can be used to click hidden / invisible elements.TFrT  rI  rï   újQuery('%s')[0].click();rB  rC  r    Nrd  r9  r‚  rò   rƒ  rÊ  )r³   r   rÿ   r   r  r  rg  r£  r  r<  rÛ  rÇ   rF  rG  rÈ   rÉ   rF   r�   rG  rÚ   ©r3   r-  rð   rç   rí   rA  r‰  rÝ   r  ró   rÞ   rˆ  rß   r8   r8   r9   r!  À  sN    

ÿþý
ÿÿÿ
zBaseCase.jquery_clickc                 C   s*  |   ¡  |r|du rtj}| jr4|tjkr4|  |¡}|}| j||dd�\}}| j|||d� | j||d�rv|  ||¡ | j	||d�}d| }| j
�r|  ¡ �r|  d¡dk�r|  d	¡}d
}d}	d|vrÖ|  d| ¡}|dkrì|  d| ¡}	|  ¡ }
|	|
g}d|||g}| j |¡ |  |¡ |  ¡  d
S )z*Clicks all matching elements using jQuery.TFrT  rI  rï   r„  rB  rC  r    Nrd  r9  r‚  rò   rƒ  rÌ  )r³   r   rÿ   r   r  r  rg  r£  r  r<  rÇ   rF  rG  rÈ   rÉ   rF   r�   rG  rÚ   r�  r8   r8   r9   Újquery_click_allé  sJ    
ÿþý
ÿÿÿ
zBaseCase.jquery_click_allc                 C   sâ   |   ¡  d}ttƒ�. | jddd� | j||dd�}W d  ƒ n1 sH0    Y  |  ||¡\}}| j||d�}d|v rŽ|rŽd	}|  ||¡ nPd|v r¸|s¸|  |¡}d
| }|  	|¡ n&t
 |¡}|  |¡}d| }|  |¡ dS )z=Hide the first element on the page that matches the selector.Nr¨  ç      ø?ré   r™  rI  rï   ro  zJconst e = arguments[0];e.style.display="none";e.style.visibility="hidden";újQuery('%s').hide();zZconst e = document.querySelector("%s");e.style.display="none";e.style.visibility="hidden";©r³   r   r¿   r  rg  r  r<  rÈ   rÛ  rG  r=  r>  r?  ©r3   r-  rð   r0  rA  r{  r8   r8   r9   Úhide_element  s0    
ÿ$ÿ


þÿzBaseCase.hide_elementc                 C   s¢   |   ¡  ttƒ� | jddd� W d  ƒ n1 s40    Y  |  ||¡\}}| j||d�}d|v rxd| }|  |¡ n&t |¡}|  	|¡}d| }|  
|¡ dS )	z6Hide all elements on the page that match the selector.r¨  r‘  ré   Nrï   ro  r’  a  var $elements = document.querySelectorAll('%s');
                var index = 0, length = $elements.length;
                for(; index < length; index++){
                $elements[index].style.display="none";
                $elements[index].style.visibility="hidden";}©r³   r   r¿   r  r  r<  rG  r=  r>  r?  rÈ   ©r3   r-  rð   rA  r{  r8   r8   r9   Úhide_elements.  s    
,

ûÿzBaseCase.hide_elementsc                 C   sâ   |   ¡  d}ttƒ�. | jddd� | j||dd�}W d  ƒ n1 sH0    Y  |  ||¡\}}| j||d�}d|v rŽ|rŽd	}|  ||¡ nPd|v r¸|s¸|  |¡}d
| }|  	|¡ n&t
 |¡}|  |¡}d| }|  |¡ dS )z=Show the first element on the page that matches the selector.Nr¨  r‘  ré   r�   rI  rï   ro  zGconst e = arguments[0];e.style.display="";e.style.visibility="visible";újQuery('%s').show(0);zWconst e = document.querySelector("%s");e.style.display="";e.style.visibility="visible";r“  r”  r8   r8   r9   Úshow_elementE  s,    
.ÿ


þÿzBaseCase.show_elementc                 C   s¢   |   ¡  ttƒ� | jddd� W d  ƒ n1 s40    Y  |  ||¡\}}| j||d�}d|v rxd| }|  |¡ n&t |¡}|  	|¡}d| }|  
|¡ dS )	z6Show all elements on the page that match the selector.r¨  r‘  ré   Nrï   ro  r™  a  var $elements = document.querySelectorAll('%s');
                var index = 0, length = $elements.length;
                for(; index < length; index++){
                $elements[index].style.display="";
                $elements[index].style.visibility="visible";}r–  r—  r8   r8   r9   Úshow_elementsb  s    
,

ûÿzBaseCase.show_elementsc                 C   sú   |   ¡  |  ¡ r | j |¡ dS d}ttƒ�. | jddd� | j||dd�}W d  ƒ n1 s`0    Y  |  ||¡\}}| j	||d�}d|v r¦|r¦d	}|  
||¡ nPd|v rÐ|sÐ|  |¡}d
| }|  |¡ n&t |¡}|  |¡}d| }|  
|¡ dS )z?Remove the first element on the page that matches the selector.Nr¨  r‘  ré   r™  rI  rï   ro  z6const e = arguments[0];e.parentElement.removeChild(e);újQuery('%s').remove();zFconst e = document.querySelector("%s");e.parentElement.removeChild(e);)r³   r´   rµ   Úremove_elementr   r¿   r  rg  r  r<  rÈ   rÛ  rG  r=  r>  r?  r”  r8   r8   r9   r�  y  s6    
ÿ$ÿ


þÿzBaseCase.remove_elementc                 C   sº   |   ¡  |  ¡ r | j |¡ dS ttƒ� | jddd� W d  ƒ n1 sL0    Y  |  ||¡\}}| j||d�}d|v r�d| }|  	|¡ n&t
 |¡}|  |¡}d| }|  |¡ dS )	z8Remove all elements on the page that match the selector.Nr¨  r‘  ré   rï   ro  rœ  úÆvar $elements = document.querySelectorAll('%s');
                var index = 0, length = $elements.length;
                for(; index < length; index++){
                $elements[index].remove();})r³   r´   rµ   Úremove_elementsr   r¿   r  r  r<  rG  r=  r>  r?  rÈ   r—  r8   r8   r9   rŸ  ›  s$    
,

üÿzBaseCase.remove_elementsc              	   C   sb   ddl m} |  ¡  |jD ]B}t |¡}|  |¡}d| }z|  |¡ W q tyZ   Y q0 qdS )z.Block ads that appear on the current web page.r   )Úad_block_listrž  N)	Úseleniumbase.configr   r³   ZAD_BLOCK_LISTr=  r>  r?  rÈ   r¿   )r3   r   rA  r{  r8   r8   r9   Úad_block´  s    


üÿzBaseCase.ad_blockc                 C   s  |   ¡  d}z| j|tjd� W n ty<   t d¡ Y n0 |  ¡ rPt d¡ z|  |¡ W n tyz   t d¡ Y n0 t	 
|¡}|  |¡}d| }ttƒ� |  |¡ W d  ƒ n1 sÀ0    Y  | j�r|  ¡ �r|  d¡d	k�r|  d
¡}|  ¡ }dd||g}| j |¡ dS )z=Display hidden file-chooser input fields on sites if present.úinput[type="file"]ré   rP  rë   r÷   aU  var $elements = document.querySelectorAll('%s');
            var index = 0, length = $elements.length;
            for(; index < length; index++){
            the_class = $elements[index].getAttribute('class');
            new_class = the_class.replaceAll('hidden', 'visible');
            $elements[index].setAttribute('class', new_class);}NrB  rC  r    rÓ  rd  )rÔ   rg  r   r(  r¿   rD   r¾   r½   r›  r=  r>  r?  r   rÈ   rÇ   rF  rG  rÉ   rF   r�   )r3   rA  r{  rÝ   rÞ   rß   r8   r8   r9   Úshow_file_choosersÈ  s8    ÿ



úÿ	
(
zBaseCase.show_file_choosersc                 C   s^   |   ¡  |  ¡  |  ¡ rZ| jj d¡rZttƒ� | j d¡ W d  ƒ n1 sP0    Y  dS )zÈThis prevents: "Leave Site? Changes you made may not be saved."
                          on Chromium browsers (Chrome or Edge).
        SB already sets "dom.disable_beforeunload" for Firefox options.r±   zwindow.onbeforeunload=null;N)	r³   r¼   r+  r=   rÀ   rÆ   r   r¿   rÈ   r‹   r8   r8   r9   Údisable_beforeunloadì  s    ÿþ
zBaseCase.disable_beforeunloadc                 C   s   |   ¡  t |¡S r.   )r³   r%   rÊ   rä   r8   r8   r9   rÊ   ù  s    zBaseCase.get_domain_urlc                 C   s   t  | j¡S r.   )r#   r  r=   r‹   r8   r8   r9   r  ý  s    zBaseCase.get_active_element_cssc                 C   sZ   ddl m} |sPttƒ�  | jdtjd� W d  ƒ n1 s>0    Y  |  ¡ }||dƒS )zÅBeautifulSoup is a toolkit for dissecting an HTML document
        and extracting what you need. It's great for screen-scraping!
        See: https://www.crummy.com/software/BeautifulSoup/bs4/doc/ r   )ÚBeautifulSoupr¨  ré   Nzhtml.parser)Zbs4r¦  r   r¿   r  r   r(  r†  )r3   rP  r¦  r8   r8   r9   r»     s    
ÿ$zBaseCase.get_beautiful_soupc                 C   s²   |   ¡  |  ¡ r*t d¡ | jr*t d¡ ttƒ�, | jddd� | jddd� W d  ƒ n1 sd0    Y  |  ¡ r�t d¡ | jr�t d¡ |  	|  
¡ ¡}|  ¡ }t ||¡S )	z¬Get all unique links in the html of the page source.
        Page links include those obtained from:
        "a"->"href", "img"->"src", "link"->"href", and "script"->"src".r°   r7  r¨  r‘  ré   Nr4  g°rh‘í|¿?)rÔ   r½   rD   r¾   rÓ   r   r¿   rg  r  r»  r†  r„  r%   Z_get_unique_links)r3   r¾  Úpage_urlr8   r8   r9   Úget_unique_links  s    


,

zBaseCase.get_unique_linksr�  c                 C   s*   | j r| j }|dk rd}tj||||d�S )aY  Get the status code of a link.
        If the timeout is set to less than 1, it becomes 1.
        If the timeout is exceeded by requests.head(), it will return a 404.
        If "verify" is False, will ignore certificate errors.
        For a list of available status codes, see:
        https://en.wikipedia.org/wiki/List_of_HTTP_status_codes r�   )Úallow_redirectsrç   Úverify)rQ   r%   Z_get_link_status_code)r3   ra  r©  rç   rª  r8   r8   r9   Úget_link_status_code"  s    üzBaseCase.get_link_status_codec                 C   s(   t |  |¡ƒ}d| }|  |d|¡ d S )NzError: "%s" returned a 404!Ú404)rÁ   r«  ÚassertNotEqual)r3   ra  Ústatus_codeZbad_link_strr8   r8   r9   Ú"assert_link_status_code_is_not_404:  s    z+BaseCase.assert_link_status_code_is_not_404c                 C   s>   t |  |¡ƒ}|dkr6t |  |¡ƒ}|dkr0|S d S nd S d S )Nr¬  )rÁ   r«  )r3   ra  r®  r8   r8   r9   Z__get_link_if_404_error?  s    z BaseCase.__get_link_if_404_errorc                 C   s¦  |   ¡ }g }|D ]F}d|vrd|vrd|vrd|vrd|vrd|vrd|vr| |¡ q|rˆt|ttfƒsrtdƒ‚|d	k r‚td
ƒ‚|| _g }|rÜd	dlm} |dƒ}| 	| j
|¡}	| ¡  | ¡  |	D ]}
|
rÆ| |
¡ qÆn"g }|D ]}|  
|¡rä| |¡ qäd| _t|ƒd	k�r^t|ƒ}d |¡}t|ƒdk�rB|  d| ¡ nt|ƒdk�r^|  d| ¡ | j�r¢d}| jdk�rŽd	dlm} | | j¡}d| }|  |d¡ dS )a‹  Assert no 404 errors from page links obtained from:
        "a"->"href", "img"->"src", "link"->"href", and "script"->"src".
        Timeout is on a per-link basis using the "requests" library.
        If timeout is None, uses the one set in get_link_status_code().
        (That timeout value is currently set to 5 seconds per link.)
        (A 404 error represents a broken link on a web page.)rª  ztel:zmailto:zjavascript:z://fonts.gstatic.comz://fonts.googleapis.comz://googleads.g.doubleclick.netú(Expecting a numeric value for "timeout"!r   ú*The "timeout" cannot be a negative number!)ÚPoolr  NrN  r�   zBroken link detected:
%szBroken links detected:
%szASSERT NO 404 ERRORSr<   ©ÚSDú	<b>%s</b>rb  )r¨  r�   r˜  rO   r  r¿   rQ   Zmultiprocessing.dummyr²  ÚmapÚ _BaseCase__get_link_if_404_errorro  r2  r  r  ÚfailrÕ   rs   Úseleniumbase.fixtures.wordsr´  Ztranslate_assert_no_404_errorsÚ(_BaseCase__highlight_with_assert_success)r3   Úmultithreadedrç   Z	all_linksrn  ra  Zbroken_linksZ
ThreadPoolÚpoolÚresultsr„  Zbad_links_strÚa_tr´  Úmessenger_postr8   r8   r9   Úassert_no_404_errorsK  sj    ÿþýüûúù	

zBaseCase.assert_no_404_errorsc                 C   s&   |   ¡ }|  |  ¡ ¡}t ||¡ dS )a'  Finds all unique links in the html of the page source
        and then prints out those links with their status codes.
        Format:  ["link"  ->  "status_code"]  (per line)
        Page links include those obtained from:
        "a"->"href", "img"->"src", "link"->"href", and "script"->"src".N)r„  r»  r†  r%   Z%_print_unique_links_with_status_codes)r3   r§  r¾  r8   r8   r9   Ú$print_unique_links_with_status_codes†  s    z-BaseCase.print_unique_links_with_status_codesc                 C   sd   |  dd¡}|  dd¡}|  dd¡}|  dd¡}|  d	d
¡}|  dd¡}|  d	d
¡}|  dd¡}|S )z;Fixing Chinese characters when converting from PDF to HTML.u   â¾�u   è¡Œu   â½…u   æ–¹u   â¼ˆu   äººu   â½°u   ç¤ºu   Ã¢Â¾Â�u   Ã¨Â¡ÂŒu   Ã¢Â½Â°u   Ã§Â¤Âºu   Ã¢Â½Â…u   Ã¦Â–Â¹)ri  ©r3   r]  r8   r8   r9   Z__fix_unicode_conversion�  s    z!BaseCase.__fix_unicode_conversionc                 C   s¬   t |tƒr|S t |ttfƒr$t|ƒS t |tƒr8tdƒ‚npt|ƒjdkrPtdƒ‚nXt |tƒrdtdƒ‚nDt |t	ƒrxtdƒ‚n0t |t
ƒrŒtdƒ‚nt |tƒr tdƒ‚nt|ƒS dS )	z¶Do type-checking on text. Then return it when valid.
        If the text is acceptable, return the text or str(text).
        If the text is not acceptable, raise a Python Exception.z%text must be a string! Boolean found!ÚNoneTypez&text must be a string! NoneType found!z"text must be a string! List found!z#text must be a string! Tuple found!z!text must be a string! Set found!z"text must be a string! Dict found!N)r˜  rÁ   rO   r  r#  r¿   r  r  ÚlistrA   ÚsetÚdictrÂ  r8   r8   r9   Z__get_type_checked_textœ  s"    











z BaseCase.__get_type_checked_textrc  c
              
   C   s\  ddl }
|
 ¡ �À |
jdtd� t tjj¡}|�€ t	t
ƒ� t tjj¡ W d  ƒ n1 s`0    Y  zddlm} W n( t
y¢   t d¡ ddlm} Y n0 W d  ƒ n1 s¸0    Y  W d  ƒ n1 sÖ0    Y  |sèd}|sðd}| ¡  d¡�st
d	| ƒ‚d}t |¡�rŠt ¡ }|�rB|  ¡ |k�rB|  |¡ | d
¡d }tj ||¡}tj |¡�sx|  |¡ n|�r°|  |¡ n&tj |¡�s¤t
d| ƒ‚tj |¡}d}t|t ƒ�rä|}g }|D ]}| !|d ¡ �qÌn.t|t"ƒ�r|d }|dk �rd}|g}nd}t# $d¡ %t#j&¡ ||d|||	|d�}|  '|¡}|�rT| (dd¡}| )¡ S )a\  Gets text from a PDF file.
        PDF can be either a URL or a file path on the local file system.
        @Params
        pdf - The URL or file path of the PDF file.
        page - The page number (or a list of page numbers) of the PDF.
                If a page number is provided, looks only at that page.
                    (1 is the first page, 2 is the second page, etc.)
                If no page number is provided, returns all PDF text.
        maxpages - Instead of providing a page number, you can provide
                   the number of pages to use from the beginning.
        password - If the PDF is password-protected, enter it here.
        codec - The compression format for character encoding.
                (The default codec used by this method is 'utf-8'.)
        wrap - Replaces ' 
' with ' ' so that individual sentences
               from a PDF don't get broken up into separate lines when
               getting converted into text format.
        nav - If PDF is a URL, navigates to the URL in the browser first.
              (Not needed because the PDF will be downloaded anyway.)
        override - If the PDF file to be downloaded already exists in the
                   downloaded_files/ folder, that PDF will be used
                   instead of downloading it again.
        caching - If resources should be cached via pdfminer.r   NÚignore)Úcategory)Úextract_textzpdfminer.sixrd  rL  z(%s is not a PDF file! (Expecting a .pdf)rÏ  rû   z#%s is not a valid URL or file path!r�   Zpdfminer)ÚpasswordZpage_numbersÚmaxpagesÚcachingÚcodecz 
re  )*ÚwarningsÚcatch_warningsÚsimplefilterÚUserWarningÚ	fastenersÚInterProcessLockr!   Ú
PipInstallÚFINDLOCKr   r¿   r&   Úmake_writableZpdfminer.high_levelrÉ  Úpip_installr  rZ  r%   rÄ   r   Úget_downloads_folderr„  r¶   rž  ry  rz  r2  rl  Údownload_filer{  r˜  rÄ  r�   rO   r¸   Ú	getLoggerÚsetLevelÚERRORÚ!_BaseCase__fix_unicode_conversionri  rÂ   )r3   Úpdfr¦  rË  rÊ  rÍ  ÚwrapÚnavÚoverriderÌ  rÎ  Úpip_find_lockrÉ  r  Zdownloads_folderrX  Zpage_searchÚpagesÚpdf_textr8   r8   r9   Úget_pdf_text³  sx    "
ÿ
,
N

ú
zBaseCase.get_pdf_textc                 C   st   |   |¡}|sd}| j||||||||	|
d�	}t|tƒrV||vrp|  d|||f ¡ n||vrp|  d||f ¡ dS )aŒ  Asserts text in a PDF file.
        PDF can be either a URL or a file path on the local file system.
        @Params
        pdf - The URL or file path of the PDF file.
        text - The expected text to verify in the PDF.
        page - The page number of the PDF to use (optional).
                If a page number is provided, looks only at that page.
                    (1 is the first page, 2 is the second page, etc.)
                If no page number is provided, looks at all the pages.
        maxpages - Instead of providing a page number, you can provide
                   the number of pages to use from the beginning.
        password - If the PDF is password-protected, enter it here.
        codec - The compression format for character encoding.
                (The default codec used by this method is 'utf-8'.)
        wrap - Replaces ' 
' with ' ' so that individual sentences
               from a PDF don't get broken up into separate lines when
               getting converted into text format.
        nav - If PDF is a URL, navigates to the URL in the browser first.
              (Not needed because the PDF will be downloaded anyway.)
        override - If the PDF file to be downloaded already exists in the
                   downloaded_files/ folder, that PDF will be used
                   instead of downloading it again.
        caching - If resources should be cached via pdfminer.rc  )r¦  rË  rÊ  rÍ  rß  rà  rá  rÌ  z4PDF [%s] is missing expected text [%s] on page [%s]!z'PDF [%s] is missing expected text [%s]!T)rÝ  rå  r˜  rO   r¸  )r3   rÞ  r]  r¦  rË  rÊ  rÍ  rß  rà  rá  rÌ  rä  r8   r8   r9   Úassert_pdf_text  s4    $
÷
ÿÿ
ÿzBaseCase.assert_pdf_textc                 C   sl   |  d¡r|dd… }t|ƒdk r*tdƒ‚tj |¡shttƒ� t |¡ W d  ƒ n1 s^0    Y  dS )z?Creates a folder of the given name if it doesn't already exist.rÏ  Nrû   r�   zMinimum folder name length = 1.)rZ  r  r¿   ry  rz  rl  r   rm  )r3   r9  r8   r8   r9   Úcreate_folderT  s    

zBaseCase.create_folderc                 C   sÔ  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}tj |¡}|  	¡ rZt
 d¡ | j|||d�}|  	¡ r|t
 d¡ | j||d�r²|  ||¡ | js°| js°|  |||¡ n^d}|  |¡�r|  |¡�s|  ¡  | j||d��r|  ||¡ | j�s| j�s|  |||¡ d}| j�rNttƒ� | jj}W d  ƒ n1 �sD0    Y  | j�r¢|  ¡ �r¢|  d¡dk�r¢|  d	¡}	|  ¡ }
||g}d
||
|	g}| j |¡ t|t t!fƒ�rºt"|ƒ}z@| j#dk�rîz| $|¡ W n t%�yê   Y n0 n
| $|¡ W nv t&t'f�yp   |  (¡  t
 d¡ | j|||d�}| j#dk�rbz| $|¡ W n t%�y^   Y n0 n
| $|¡ Y n0 | j�rÀ| jj|k�r²t) *| j¡�s¨t) +| jt,j-j.¡ |  /¡  n| j/dd� n| j�rÐ|  0¡  dS )a6  This method is used to choose a file to upload to a website.
        It works by populating a file-chooser "input" field of type="file".
        A relative file_path will get converted into an absolute file_path.

        Example usage:
            self.choose_file('input[type="file"]', "my_dir/my_file.txt") r7  rI  r°   rï   r£  NrB  rC  r    rÏ  rê   r÷   Trü   )1r³   r   rT  r   r  r  ry  rz  r{  r½   rD   r¾   rg  r£  r  rÕ   r  r  r   r¤  r   r¿   r=   rÀ   rÇ   rF  rG  rÈ   rÉ   rF   r�   r˜  rO   r  rÁ   r  rX  r   r  r  rÔ   r#   rÖ   r×   r!   rØ   rÙ   rÚ   r+  )r3   r-  r  rð   rç   r~  r0  Zchoose_file_selectorrÜ   rÝ   rÞ   Zsele_file_pathrß   r8   r8   r9   Úchoose_file^  s„    	

ÿ

(

ÿ
zBaseCase.choose_filerd  c                 C   sŽ  |   |¡}|j}t| d¡d ƒdk r.tdƒ‚| d¡s@|d }d}|r„| tj¡r`|dd… }t|ƒdkr„|  |¡ tj	 
||¡}|sŒ|}t|dƒ�}| |¡ W d  ƒ n1 s¶0    Y  t|tƒ�rŠt|ƒdk�rŠt tjj¡}	|	�ò ttƒ� t tjj¡ W d  ƒ n1 �s0    Y  zdd	lm}
m} W n” t�yÎ   t d
¡ zdd	lm}
m} W n` t�yÈ } zFtjdk�r²d|jv �r²tdd 
dd„ tjD ƒ¡ ƒ‚n‚ W Y d}~n
d}~0 0 Y n0 W d  ƒ n1 �sæ0    Y  | d¡}t|ƒ}d}|D ]}t|ƒ|k�r
t|ƒ}�q
|
 |¡}| |¡}|jddt |d ƒd d| d fdd� |j!d|ddd� |j"|dddd� dS )zËTake a screenshot of an element and save it as an image file.
        If no folder is specified, will save it to the current folder.
        If overlay_text is provided, will add that to the saved image.rw  r   r�   z$Error: file_name length must be > 0.r?  Nrû   Úwb)ÚImageÚ	ImageDrawZPillow)r,   re  zsymbol not foundz*PIL / Pillow is not supported on Python %sc                 s   s   | ]}t |ƒV  qd S r.   )rÁ   )rZ  Úsr8   r8   r9   Ú	<genexpr>Ú  r\  z6BaseCase.save_element_as_image_file.<locals>.<genexpr>rN  g¤p=
×£ @r  é   r¾  )éì   rï  é   )Úfill)r–  r¾  )é   é&   é°   é   )rñ  Z	font_sizeZPNGr{  T)ZqualityÚoptimize)#r  Úscreenshot_as_pngr  rž  r¿   rZ  ry  r  rç  rz  r2  r¶   r&  r˜  rÁ   rÒ  rÓ  r!   rÔ  rÕ  r   r&   rÖ  ZPILrê  rë  r×  r�   rC   r¨   ZDrawZ	rectanglerO   r]  Úsave)r3   r-  rX  r9  Zoverlay_textr0  Zelement_pngZimage_file_pathr•   râ  rê  rë  rà   Z	text_rowsZlen_text_rowsÚ	max_widthZtext_rowÚimageZdrawr8   r8   r9   Úsave_element_as_image_file®  sx    


(ÿ
.
ÿþÿÿ>


þüz#BaseCase.save_element_as_image_filec           
   	   C   sü   t  tjj¡}|�h ttƒ� t tjj¡ W d  ƒ n1 s@0    Y  |sVtj	j
}tj |¡slt |¡ W d  ƒ n1 s€0    Y  |  ¡ }d|i}tj|||d� | jrø|  ¡ rø|  d¡dkrø|  d¡}|  ¡ }||g}d|||g}	| j |	¡ dS )zÅDownloads the file from the url to the destination folder.
        If no destination folder is specified, the default one is used.
        (The default folder for downloads is "./downloaded_files")Nú
user-agent©ÚheadersrB  rC  r    rá  )rÒ  rÓ  r!   ÚMultiBrowserÚDOWNLOAD_FILE_LOCKr   r¿   r&   rÖ  ÚFilesÚDOWNLOADS_FOLDERry  rz  rl  rm  rŒ  r%   Ú_download_file_torÇ   rF  rG  rÈ   rÉ   rF   r�   )
r3   Úfile_urlrY  Údownload_file_lockr.  rþ  rÝ   rÞ   Zurl_destrß   r8   r8   r9   rÙ  ò  s0    ÿ
ÿ"(ÿ
zBaseCase.download_filec              	   C   s°   t  tjj¡}|�h ttƒ� t tjj¡ W d  ƒ n1 s@0    Y  |sVtj	j
}tj |¡slt |¡ W d  ƒ n1 s€0    Y  |  ¡ }d|i}tj||||d� dS )zvSimilar to self.download_file(), except that you get to rename the
        file being downloaded to whatever you want.Nrü  rý  )rÒ  rÓ  r!   rÿ  r   r   r¿   r&   rÖ  r  r  ry  rz  rl  rm  rŒ  r%   r  )r3   r  Znew_file_namerY  r  r.  rþ  r8   r8   r9   Úsave_file_as  s"    ÿ
ÿ"(ÿzBaseCase.save_file_asc                 C   s   |st jj}t |||¡ dS )zðSaves the data specified to the file specified.
        If no destination folder is specified, the default one is used.
        (The default folder = "./downloaded_files")
        Use "." as the destination folder for the current directory.N)r!   r  r  r%   rV  ©r3   r²   rX  rY  r8   r8   r9   Úsave_data_as$  s    zBaseCase.save_data_asc                 C   s   |st jj}t |||¡ dS )zæAppends the data specified to the file specified.
        If no destination folder is specified, the default one is used.
        (The default folder = "./downloaded_files")
        Use "." as the folder for the current directory.N)r!   r  r  r%   r[  r  r8   r8   r9   Úappend_data_to_file-  s    zBaseCase.append_data_to_filec                 C   s   |st jj}t ||¡S )a4  Gets the data from the file specified.
        If no folder is specified, the default one is used.
        The default folder = "./downloaded_files"
        For the "latest_logs/" test data folders, use:
            self.data_path OR self.data_abspath
        Use "." as the folder for the current directory.)r!   r  r  r%   Z_get_file_data)r3   rX  r9  r8   r8   r9   Úget_file_data6  s    zBaseCase.get_file_datac           
   	   C   s¸  ddl }ddlm} | ¡  d¡s.td| ƒ‚t tj	j
¡}|  ¡ rÊ|�n ttƒ� t tj	j
¡ W d  ƒ n1 sv0    Y  |rštj |¡sšt |¡ | j ||¡ W d  ƒ n1 s¼0    Y  dS |  ¡  |ƒ }| j |¡}|�º ttƒ� t tj	j
¡ W d  ƒ n1 �s0    Y  |�r@tj |¡�s@t |¡ |}|�rXtj ||¡}t|dƒ� }	|	 | |¡¡ W d  ƒ n1 �sŠ0    Y  W d  ƒ n1 �sª0    Y  dS )a@  Saves the current page as a PDF.
        If no folder is specified, uses the folder where pytest was called.
        If the folder provided doesn't exist, it will get created.
        @Params
        name - The name to give the PDF file. Must end in ".pdf".
        folder - The directory where you want to save the PDF.r   N)ÚPrintOptionsrL  z"PDF name {%s} must end in ".pdf"!)ré  )Úbase64Z,selenium.webdriver.common.print_page_optionsr  r  rZ  r¿   rÒ  rÓ  r!   rÿ  r   r´   r   r&   rÖ  ry  rz  rl  rm  rµ   rI  rÔ   r=   Z
print_pager2  r¶   r&  Ú	b64decode)
r3   r”   r9  r  r  r  Zprint_optionsZ
pdf_base64r(  r€  r8   r8   r9   rI  A  s@    ÿ
ÿ"
,
ÿ$
zBaseCase.print_to_pdfc                 C   s   |   ¡  t ¡ S )aX  Returns the path of the SeleniumBase "downloaded_files/" folder.
        Calling self.download_file(file_url) will put that file in here.
        With the exception of Safari, IE, and Chromium Guest Mode,
            any clicks that download files will also use this folder
            rather than using the browser's default "downloads/" path.)r³   r   rØ  r‹   r8   r8   r9   rØ  j  s    zBaseCase.get_downloads_folderc                 C   s  |   ¡  |  ¡ r2| jr2| js2tj tj d¡d¡S | jdksF| jdkr\tj tj d¡d¡S d| j	j
v ržt|  ¡  d¡d ƒdk rž| jržtj tj d¡d¡S d| j	j
v rðt|  ¡  d¡d ƒd	krðt|  ¡  d¡d ƒd
krð| jrðtj d¡S t ¡ S tj tj d¡d¡S )a  Returns the path that is used when a click initiates a download.
        SeleniumBase overrides the system path to be "downloaded_files/"
        The path can't be changed on Safari, IE, or Chromium Guest Mode.
        The same problem occurs when using an out-of-date chromedriver.ú~Z	downloadsrê   rî   r  rw  r   éI   én   ép   )r³   r+  rô  r  ry  rz  r2  Ú
expanduserr  r=   ÚcapabilitiesrO   Úget_chromedriver_versionrž  r{  r   rØ  r‹   r8   r8   r9   Úget_browser_downloads_folders  s.    
ÿþý
ÿþýüz%BaseCase.get_browser_downloads_folderc                    sN   |   ¡ }|r|  ¡ }tj |¡s$g S ˆ r@‡ fdd„t |¡D ƒS t |¡S dS )z«Returns a list of files in the [Downloads Folder].
        Depending on settings, that dir may have other files.
        If regex is provided, uses that to filter results.c                    s   g | ]}t  ˆ |¡r|‘qS r8   ©r=  Úmatch©rZ  Úfn©Úregexr8   r9   r[  š  r\  z1BaseCase.get_downloaded_files.<locals>.<listcomp>N)rØ  r  ry  rz  rl  Úlistdir)r3   r  r  Údfr8   r  r9   Úget_downloaded_files�  s    zBaseCase.get_downloaded_filesc                 C   s4   |   ¡  |rtj |  ¡ |¡S tj |  ¡ |¡S dS )z0Returns the full OS path of the downloaded file.N)r³   ry  rz  r2  r  rØ  ©r3   r•   r  r8   r8   r9   Úget_path_of_downloaded_filež  s    z$BaseCase.get_path_of_downloaded_filec              	   C   sÀ   | j |||d� | j||d�}t tjj¡}|�| ttƒ� t	 
tjj¡ W d  ƒ n1 s^0    Y  t|dƒ�}| ¡  ¡ }W d  ƒ n1 s”0    Y  W d  ƒ n1 s²0    Y  |S )z6Returns the contents of the downloaded file specified.©rç   r  ©r  Nrx  )Úassert_downloaded_filer   rÒ  rÓ  r!   rÿ  ZFILE_IO_LOCKr   r¿   r&   rÖ  r¶   r|  rÂ   )r3   r•   rç   r  ZfpathZfile_io_lockr€  r²   r8   r8   r9   Úget_data_from_downloaded_file¦  s    ÿ
,Hz&BaseCase.get_data_from_downloaded_filec                 C   s   t j | j||d�¡S )aÍ  Returns True if the file exists in the pre-set [Downloads Folder].
        For browser click-initiated downloads, SeleniumBase will override
            the system [Downloads Folder] to be "./downloaded_files/",
            but that path can't be overridden when using Safari, IE,
            or Chromium Guest Mode, which keeps the default system path.
        self.download_file(file_url) will always use "./downloaded_files/".
        @Params
        file - The filename of the downloaded file.
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).r"  )ry  rz  rl  r   r  r8   r8   r9   Úis_downloaded_file_present´  s    ÿz#BaseCase.is_downloaded_file_presentc                    s8   |   ¡ }|r|  ¡ }‡ fdd„t |¡D ƒ}t|ƒdkS )a»  Returns True if the filename regex exists in the [Downloads Folder].
        Uses Python regex via the "re" library for string-matching on the name.
        @Params
        regex - The filename regex of the downloaded file.
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).c                    s   g | ]}t  ˆ |¡r|‘qS r8   r  r  r  r8   r9   r[  Ï  r\  z=BaseCase.is_downloaded_file_regex_present.<locals>.<listcomp>r�   )rØ  r  ry  r  r  )r3   r  r  r  Úmatchesr8   r  r9   Ú is_downloaded_file_regex_presentÄ  s
    z)BaseCase.is_downloaded_file_regex_presentc                 C   sR   | j ||d�rN| j||d�}ttƒ� t |¡ W d  ƒ n1 sD0    Y  dS )aÞ  Deletes the file from the [Downloads Folder] if the file exists.
        For browser click-initiated downloads, SeleniumBase will override
            the system [Downloads Folder] to be "./downloaded_files/",
            but that path can't be overridden when using Safari, IE,
            or Chromium Guest Mode, which keeps the default system path.
        self.download_file(file_url) will always use "./downloaded_files/".
        @Params
        file - The filename to be deleted from the [Downloads Folder].
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).r"  N©r%  r   r   r¿   ry  r  ©r3   r•   r  r  r8   r8   r9   Ú!delete_downloaded_file_if_presentÒ  s    
z*BaseCase.delete_downloaded_file_if_presentc                 C   sR   | j ||d�rN| j||d�}ttƒ� t |¡ W d  ƒ n1 sD0    Y  dS )a  Same as self.delete_downloaded_file_if_present()
        Deletes the file from the [Downloads Folder] if the file exists.
        For browser click-initiated downloads, SeleniumBase will override
            the system [Downloads Folder] to be "./downloaded_files/",
            but that path can't be overridden when using Safari, IE,
            or Chromium Guest Mode, which keeps the default system path.
        self.download_file(file_url) will always use "./downloaded_files/".
        @Params
        file - The filename to be deleted from the [Downloads Folder].
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).r"  Nr(  r)  r8   r8   r9   Údelete_downloaded_fileã  s    
zBaseCase.delete_downloaded_filec              	   C   sÎ  |   ¡  |  ¡ }|r|  ¡ }|s&tj}| jr@|tjkr@|  |¡}t ¡ d }||d  }|  ||¡}d}t	t
|ƒƒD ]n}	t ¡  z*|  tj |¡d||f ¡ d}W  qäW qt tyà   t ¡ d }
|
|krÒY  qät d¡ Y qt0 qt|�s&tj |¡�s&d}|dk�r
d}d||||f }t d	|¡ | j�rr|  ¡ �rr|  d
¡dk�rr|  d¡}|  ¡ }d|||g}| j |¡ | j�rÊd| }ttƒ�. t | j ¡ t !| j || j"¡ W d  ƒ n1 �sÀ0    Y  dS )a  Asserts that the file exists in SeleniumBase's [Downloads Folder].
        For browser click-initiated downloads, SeleniumBase will override
            the system [Downloads Folder] to be "./downloaded_files/",
            but that path can't be overridden when using Safari, IE,
            or Chromium Guest Mode, which keeps the default system path.
        self.download_file(file_url) will always use "./downloaded_files/".
        @Params
        file - The filename of the downloaded file.
        timeout - The time (seconds) to wait for the download to complete.
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).r:   Fz5File [%s] was not found in the downloads folder [%s]!Tr�   rì  rd  zjFile {%s} was not found in the downloads folder {%s} after %s second%s! (Or the download didn't complete!)ÚNoSuchFileExceptionrB  rC  r    rà  z#<b>ASSERT DOWNLOADED FILE</b>: [%s]N)#r³   rØ  r  r   rT  r   r  rD   r   r’  rO   r&   rÐ   Ú
assertTruery  rz  rl  r¿   r¾   r$   rË  rÇ   rF  rG  rÈ   rÉ   rF   r�   rÕ   r   r#   r�  r=   Úpost_messenger_success_messageÚmessage_duration)r3   r•   rç   r  r  r”  r•  Zdownloaded_file_pathÚfoundr  r–  Úpluralrâ   rÝ   rÞ   rß   r¿  r8   r8   r9   r#  õ  sd    

ÿþ


þÿ


ÿzBaseCase.assert_downloaded_filec              	      s€  |   ¡  |stj}| jr,|tjkr,|  |¡}t ¡ d }||d  }d}|  ¡ }|r\|  ¡ }tt	|ƒƒD ]†}t
 ¡  zB‡ fdd„t |¡D ƒ}	|  t|	ƒdkdˆ |f ¡ d}W  qðW qh tyì   t ¡ d }
|
|krÞY  qðt d¡ Y qh0 qh|�s$d}|dk�rd	}d
ˆ |||f }t d|¡ | j�r|dˆ  }ttƒ�. t | j¡ t | j|| j¡ W d  ƒ n1 �sr0    Y  dS )a  Assert the filename regex exists in SeleniumBase's Downloads Folder.
        Uses Python regex via the "re" library for string-matching on the name.
        @Params
        regex - The filename regex of the downloaded file.
        timeout - The time (seconds) to wait for the download to complete.
        browser - If True, uses the path set by click-initiated downloads.
                  If False, uses the self.download_file(file_url) path.
                  Those paths are usually the same. (browser-dependent).r:   Fc                    s   g | ]}t  ˆ |¡r|‘qS r8   r  r  r  r8   r9   r[  L  r\  z9BaseCase.assert_downloaded_file_regex.<locals>.<listcomp>r�   z6Regex [%s] was not found in the downloads folder [%s]!Trì  rd  zkRegex {%s} was not found in the downloads folder {%s} after %s second%s! (Or the download didn't complete!)r,  z)<b>ASSERT DOWNLOADED FILE REGEX</b>: [%s]N)r³   r   rT  r   r  rD   rØ  r  r’  rO   r&   rÐ   ry  r  r-  r  r¿   r¾   r$   rË  rÕ   r   r#   r�  r=   r.  r/  )r3   r  rç   r  r”  r•  r0  r  r  r&  r–  r1  râ   r¿  r8   r  r9   Úassert_downloaded_file_regex5  sZ    	

ÿþ


þÿÿ

ÿz%BaseCase.assert_downloaded_file_regexc                 C   sF   | j |||d� | ¡ }| j||d�}||vrBd||f }t|ƒ‚dS )z<Assert that the expected data exists in the downloaded file.r!  r"  z2Expected data [%s] is not in downloaded file [%s]!T)r#  rÂ   r$  r¿   )r3   r²   r•   rç   r  ÚexpectedÚactualrâ   r8   r8   r9   Úassert_data_in_downloaded_filem  s    ÿÿz'BaseCase.assert_data_in_downloaded_filec                 C   s   | j ||d� dS )z[Asserts that the expression is True.
        Raises an exception if the statement if False.©r¨   N)r-  ©r3   Úexprr¨   r8   r8   r9   Úassert_true|  s    zBaseCase.assert_truec                 C   s   | j ||d� dS )z[Asserts that the expression is False.
        Raises an exception if the statement if True.r6  N)ZassertFalser7  r8   r8   r9   Úassert_false�  s    zBaseCase.assert_falsec                 C   s   | j |||d� dS )z_Asserts that the two values are equal.
        Raises an exception if the values are not equal.r6  N)ÚassertEqual©r3   ÚfirstÚsecondr¨   r8   r8   r9   Úassert_equal†  s    zBaseCase.assert_equalc                 C   s   | j |||d� dS )z_Asserts that the two values are not equal.
        Raises an exception if the values are equal.r6  N)r­  r<  r8   r8   r9   Úassert_not_equal‹  s    zBaseCase.assert_not_equalc                 C   s   | j |||d� dS )z|Asserts that the first string is in the second string.
        Raises an exception if the first string is not in the second.r6  N)ÚassertInr<  r8   r8   r9   Ú	assert_in�  s    zBaseCase.assert_inc                 C   s   | j |||d� dS )zƒAsserts that the first string is not in the second string.
        Raises an exception if the first string is in the second string.r6  N)ZassertNotInr<  r8   r8   r9   Úassert_not_in•  s    zBaseCase.assert_not_inc                 O   s   | j |i |¤ŽS )a=  Asserts that the following block of code raises an exception.
        Raises an exception if the block of code has no exception.
        Usage Example =>
            # Verify that the expected exception is raised.
            with self.assert_raises(Exception):
                raise Exception("Expected Exception!") )ZassertRaisesr2   r8   r8   r9   Úassert_raisesš  s    zBaseCase.assert_raisesc                 C   sŒ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rX| j |||¡ dS |  	|¡rt| j
||||d�S tj| j|||||d�S )zúRaises an exception if the element attribute/value is not found.
        If the value is not specified, the attribute only needs to exist.
        Returns the element that contains the attribute if successful.
        Default timeout = LARGE_TIMEOUT.N)rS  rç   ©rS  rð   rç   )r³   r   rT  r   r  r  r´   rµ   Úassert_element_attributer  Ú,_BaseCase__wait_for_shadow_attribute_presentr$   Úwait_for_attributer=   ©r3   r-  rµ  rS  rð   rç   r8   r8   r9   rH  £  s*    

ÿúzBaseCase.wait_for_attributec                 C   sn  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rX| j |||¡ dS | j	|||||d� | j
�r|  |¡�s| j||d��rd}d}| jdkrÆddlm} | | j¡}| | j¡}|sâd	|||| ¡ |f }	nd
||||| ¡ |f }	|  |	||¡ | j�rj|  ¡ �rj|  d¡dk�rj|  d¡}
|  ¡ }| dd¡}|||g}d|||
g}| j |¡ dS )zÏRaises an exception if the element attribute/value is not found.
        If the value is not specified, the attribute only needs to exist.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.NrE  rï   zASSERT ATTRIBUTEÚinr<   r   r³  z<b>%s</b>: [%s] %s %s: %sz<b>%s</b>: [%s="%s"] %s %s: %srB  rC  r    r_  z\\râ  T)r³   r   rÿ   r   r  r  r´   rµ   rF  rH  rÕ   r  r£  rs   r¹  r´  Ztranslate_assert_attributeÚtranslate_inr   rº  rÇ   rF  rG  rÈ   rÉ   ri  rF   r�   )r3   r-  rµ  rS  rð   rç   Za_aÚi_nr´  r¿  rÝ   rÞ   Zsel_att_valrß   r8   r8   r9   Úassert_attributeÀ  sd    

ÿÿþý
ûú

zBaseCase.assert_attributec                 C   sŒ  |   ¡ r| j |¡ dS |  ¡  | ¡ }|  ¡  ¡ }d}| jsìz|  |||||f ¡ W n’ tyê   |  ¡  t	 
d¡ |  ¡  ¡ }z|  |||||f ¡ W nF tyä   |  ¡  t	 
d¡ |  ¡  ¡ }|  |||||f ¡ Y n0 Y n0 | j�r<| j�s<d}| jdk�r$ddlm} | | j¡}d||f }|  |d	¡ | j�rˆ|  ¡ �rˆ|  d
¡dk�rˆ|  d¡}|  ¡ }	d||	|g}
| j |
¡ dS )a\  Asserts that the web page title matches the expected title.
        When a web page initially loads, the title starts as the URL,
            but then the title switches over to the actual page title.
        In Recorder Mode, this assertion is skipped because the Recorder
            changes the page title to the selector of the hovered element.Nz>Expected page title [%s] does not match the actual title [%s]!r¾  zASSERT TITLEr<   r   r³  ú<b>%s</b>: {%s}rb  rB  rC  r    rÜ  T)r´   rµ   Úassert_titlerÔ   rÂ   r‹  rÇ   r;  r¿   rD   r¾   rÕ   rs   r¹  r´  Ztranslate_assert_titlerº  rF  rG  rÈ   rÉ   rF   r�   )r3   r‰  r3  r4  r«  r¾  r´  r¿  rÝ   rÞ   rß   r8   r8   r9   rO  ú  sP    ÿ
ÿ
ÿ
zBaseCase.assert_titlec                 C   sŒ  |   ¡ r| j |¡ dS |  ¡  | ¡ }|  ¡  ¡ }d}| jsìz|  |||||f ¡ W n’ tyê   |  ¡  t	 
d¡ |  ¡  ¡ }z|  |||||f ¡ W nF tyä   |  ¡  t	 
d¡ |  ¡  ¡ }|  |||||f ¡ Y n0 Y n0 | j�r<| j�s<d}| jdk�r$ddlm} | | j¡}d||f }|  |d	¡ | j�rˆ|  ¡ �rˆ|  d
¡dk�rˆ|  d¡}|  ¡ }	d||	|g}
| j |
¡ dS )a`  Asserts that the title substring appears in the web page title.
        When a web page initially loads, the title starts as the URL,
            but then the title switches over to the actual page title.
        In Recorder Mode, this assertion is skipped because the Recorder
            changes the page title to the selector of the hovered element.NzLExpected title substring [%s] does not appear in the actual page title [%s]!r¾  zASSERT TITLE CONTAINSr<   r   r³  rN  rb  rB  rC  r    rÝ  T)r´   rµ   Úassert_title_containsrÔ   rÂ   r‹  rÇ   rA  r¿   rD   r¾   rÕ   rs   r¹  r´  Ztranslate_assert_title_containsrº  rF  rG  rÈ   rÉ   rF   r�   )r3   Ú	substringr3  r4  r«  r¾  r´  r¿  rÝ   rÞ   rß   r8   r8   r9   rP  +   sP    ÿ
ÿ
ÿ
zBaseCase.assert_title_containsc                 C   s†  |   ¡ r| j |¡ dS |  ¡  | ¡ }|  ¡  ¡ }d}z|  |||||f ¡ W n’ tyä   |  ¡  t 	d¡ |  ¡  ¡ }z|  |||||f ¡ W nF tyÞ   |  ¡  t 	d¡ |  ¡  ¡ }|  |||||f ¡ Y n0 Y n0 | j
�r6| j�s6d}| jdk�rddlm} | | j¡}d||f }|  |d	¡ | j�r‚|  ¡ �r‚|  d
¡dk�r‚|  d¡}|  ¡ }	d||	|g}
| j |
¡ dS )z7Asserts that the web page URL matches the expected URL.Nz5Expected URL [%s] does not match the actual URL [%s]!r¾  z
ASSERT URLr<   r   r³  rN  rb  rB  rC  r    rÞ  T)r´   rµ   Ú
assert_urlrÔ   rÂ   r„  r;  r¿   rD   r¾   rÕ   rÇ   rs   r¹  r´  Ztranslate_assert_urlrº  rF  rG  rÈ   rÉ   rF   r�   )r3   rÛ   r3  r4  r«  Úa_ur´  r¿  rÝ   rÞ   rß   r8   r8   r9   rR  ]   sD    

"
zBaseCase.assert_urlc                 C   s†  |   ¡ r| j |¡ dS |  ¡  | ¡ }|  ¡  ¡ }d}z|  |||||f ¡ W n’ tyä   |  ¡  t 	d¡ |  ¡  ¡ }z|  |||||f ¡ W nF tyÞ   |  ¡  t 	d¡ |  ¡  ¡ }|  |||||f ¡ Y n0 Y n0 | j
�r6| j�s6d}| jdk�rddlm} | | j¡}d||f }|  |d	¡ | j�r‚|  ¡ �r‚|  d
¡dk�r‚|  d¡}|  ¡ }	d||	|g}
| j |
¡ dS )z7Asserts that the URL substring appears in the full URL.NzAExpected URL substring [%s] does not appear in the full URL [%s]!r¾  zASSERT URL CONTAINSr<   r   r³  rN  rb  rB  rC  r    rß  T)r´   rµ   Úassert_url_containsrÔ   rÂ   r„  rA  r¿   rD   r¾   rÕ   rÇ   rs   r¹  r´  Ztranslate_assert_url_containsrº  rF  rG  rÈ   rÉ   rF   r�   )r3   rQ  r3  r4  r«  rS  r´  r¿  rÝ   rÞ   rß   r8   r8   r9   rT  ƒ   sF    ÿ

"
zBaseCase.assert_url_containsc              	   C   sè  |   ¡  |r0t|ttfƒs0t|ƒ dd¡ d¡}t d¡ z| j	 
d¡}W n ttfyb   Y dS 0 d}d}g }|D ]€}|d	 d
krt||d vrt||d vrt|s¬| |¡ qtd}|d }|D ](}	t|	ƒ}	t|	ƒdkr¼|	|v r¼d} qæq¼|st| |¡ qtt|ƒdk�r–tt|ƒƒD �]L}
d}d}d}|||
 d v �r¾||
 d  |¡d }d||
 d v �rld|i||
< �q\d||
 d v �rŽd|i||
< �q\d||
 d v �r°d|i||
< �q\d||
 d v �rÐd|i||
< nìd||
 d v �rðd|i||
< nÌd||
 d v �rd|i||
< n¬d||
 d v �r0d|i||
< nŒd ||
 d v �rPd!|i||
< nld"||
 d v �rpd#|i||
< nLd$||
 d v �r�d%|i||
< n,d&||
 d v �r°d'|i||
< nd(|i||
< nž|||
 d v �r||
 d  |¡d }||
 d  |¡d) }d*| |i||
< nN|||
 d v �r||
 d  |¡d }||
 d  |¡d) }d+| |i||
< �qt|ƒ}| d,d-¡ d.d/¡}|  ¡ }|  d0||f ¡ | j�rä|  ¡ �räd1}| jd2k�rÐdd3lm} | | j¡}d4| }|  |d5¡ dS )6a
  Asserts current URL has no "SEVERE"-level JavaScript errors.
        Works ONLY on Chromium browsers (Chrome or Edge).
        Does NOT work on Firefox, IE, Safari, or some other browsers:
            * See https://github.com/SeleniumHQ/selenium/issues/1161
        Based on the following Stack Overflow solution:
            * https://stackoverflow.com/a/41150512/7058266
        @Params
        exclude -->
            A list of substrings or a single comma-separated string of
            substrings for filtering out error URLs that contain them.
            URLs that contain any excluded substring will get excluded
            from the final errors list that's used with the assertion.
        Examples:
            self.assert_no_js_errors()
            self.assert_no_js_errors(exclude=["/api.", "/analytics."])
            self.assert_no_js_errors(exclude="//api.go,/analytics.go")
            self.assert_no_js_errors(exclude=["Uncaught SyntaxError"])
            self.assert_no_js_errors(exclude=["TypeError", "SyntaxE"]) re  rd  ú,r¯   r  Nú*//cdnjs.cloudflare.com/ajax/libs/messengerz+//cdnjs.cloudflare.com/ajax/libs/underscoreÚlevelZSEVERErâ   Fr   Tz - Failed to load resourcez Uncaught SyntaxError: z Uncaught TypeError: zstatus of 400zError 400 (Bad Request)zstatus of 401zError 401 (Unauthorized)zstatus of 402zError 402 (Payment Required)zstatus of 403zError 403 (Forbidden)zstatus of 404zError 404 (Not Found)zstatus of 405zError 405 (Method Not Allowed)zstatus of 406zError 406 (Not Acceptable)zstatus of 407zError 407 (Proxy Auth Required)zstatus of 408zError 408 (Request Timeout)zstatus of 409zError 409 (Conflict)zstatus of 410zError 410 (Gone)zFailed to load resourcer�   zUncaught SyntaxError (%s)zUncaught TypeError (%s)z[{z[
{z}, {z},
{z#JavaScript errors found on %s => %szASSERT NO JS ERRORSr<   r³  rµ  rb  )r³   r˜  rÄ  rA   rÁ   ri  rž  rD   r¾   r=   Úget_logÚ
ValueErrorr   r�   r  r’  r„  r¸  rÕ   r+  rs   r¹  r´  Ztranslate_assert_no_js_errorsrº  )r3   ÚexcludeÚbrowser_logsÚmessenger_libraryZunderscore_libraryrƒ  Úentryr0  râ   rQ  rÂ  Zf_t_l_rZu_c_s_eZu_c_t_erÛ   r«  Zer_strrÀ   r¾  r´  r¿  r8   r8   r9   r�  ¬   s¦    

ÿ
þ
ÿþ
ÿ
zBaseCase.assert_no_js_errorsc                 C   s"   |   ¡  t d¡ t | j¡ d S )Nrë   )rÔ   rD   r¾   r#   Zactivate_html_inspectorr=   r‹   r8   r8   r9   Z__activate_html_inspector!  s    
z"BaseCase.__activate_html_inspectorc              	   C   s˜  |   ¡  |  ¡  d}z|  |¡ W n& tyH   d}td| ƒ | Y S 0 t d¡ g }z| j d¡}W n* t	t
fy’   d}td| ƒ | Y S 0 d}|  ¡ }d| }|g}d	}|D ]ª}	|	d
 }
d|
v rØ|
 d¡d }
|
 dd¡}
|
 dd¡}
|
 d¡�r|
 d¡dk�r|
 d¡d }
d|
v �r&q¶t�s6d|
 }
nd|
 }
||
vr¶|
|vr¶| |
¡ |d7 }q¶|d	k�rx| d¡ n
| d¡ d |¡}t|ƒ |S )zËInspects the Page HTML with HTML-Inspector.
        (https://github.com/philipwalton/html-inspector)
        (https://cdnjs.com/libraries/html-inspector)
        Prints the results and also returns them.zHTMLInspector.inspect();z7(Unable to load HTML-Inspector JS! Inspection Skipped!)rN  r¯   r  z4(Unable to Inspect HTML! -> Only works on Chromium!)rV  z
* HTML Inspection Results: %sr   râ   z0:6053 z0:6053r�   z\u003Cú<z and should not be usedrd  z "rö  r¾  zbut not found in any stylesheetu   âš ï¸�  z!-> z'* (See the Console output for details!)z* (No issues detected!))Ú"_BaseCase__activate_html_inspectorrÔ   rÈ   r¿   rµ  rD   r¾   r=   rX  rY  r   r„  rž  ri  rÆ   rh  Ú
is_windowsr�   r2  )r3   r{  r¨   r[  r\  rÛ   Úheaderr½  Ú	row_countr]  râ   r8   r8   r9   Úinspect_html!  sZ    









zBaseCase.inspect_htmlc                 C   s
   t  |¡S )z&Return True if the url is a valid url.)r%   rÄ   rä   r8   r8   r9   rÄ   T!  s    zBaseCase.is_valid_urlc                 C   s*   z| j jj W dS  ty$   Y dS 0 d S )NTF)r=   r§   Úalertr¿   r‹   r8   r8   r9   Úis_alert_presentX!  s
    
zBaseCase.is_alert_presentc                 C   s   |   ¡ r| j d¡S |  d¡S )z)Return True if connected to the Internet.znavigator.onLine;zreturn navigator.onLine;)r´   rµ   rˆ  rÈ   r‹   r8   r8   r9   Ú	is_online_!  s    zBaseCase.is_onlinec                 C   s   t | jdƒr| j ¡ S dS dS )a  
        Return True if WebDriver is connected to the browser.
        Note that the stealthy CDP-Driver isn't a WebDriver.
        In CDP Mode, the CDP-Driver controls the web browser.
        The CDP-Driver can be connected while WebDriver isn't.
        r¤  TN)rÍ   r=   r¤  r‹   r8   r8   r9   r¤  e!  s    
zBaseCase.is_connectedc                 C   s8   |   ¡  |  ¡ rdS d}d| jjv s0d| jjv r4d}|S )z-Return True if the browser is Chrome or Edge.TFr  Úmsedge)r³   r´   r=   r  )r3   Zchromiumr8   r8   r9   r+  q!  s    
ÿ
þzBaseCase.is_chromiumc                 C   s<   d}d| j jv rd}|s8| j jd }d||f }t|ƒ‚d S )NFr  TÚbrowserNamezèError: "%s" should only be called by tests running with "--browser=chrome" / "--chrome"! You should add an "if" statement to your code before calling this method if using browsers that are Not Chrome! The browser detected was: "%s".)r=   r  r   )r3   Úmethodr  rÙ  râ   r8   r8   r9   Z__fail_if_not_using_chrome~!  s    üÿz#BaseCase.__fail_if_not_using_chromec                 C   s,   |   ¡ s(| jjd }d||f }t|ƒ‚d S )Nrh  zîError: "%s" should only be called by tests running with a Chromium browser! (Chrome or Edge) You should add an "if" statement to your code before calling this method if using browsers that are Not Chromium! The browser detected was: "%s".)r+  r=   r  r   )r3   ri  rÙ  râ   r8   r8   r9   Z__fail_if_not_using_chromium�!  s    üÿz%BaseCase.__fail_if_not_using_chromiumc                 C   s4   |   ¡  |  d¡ d| jjv r,| jjd }nd}|S )Nzget_chrome_version()ÚbrowserVersionú(Unknown Version))r³   Ú#_BaseCase__fail_if_not_using_chromer=   r  )r3   Úchrome_versionr8   r8   r9   Úget_chrome_version™!  s    
zBaseCase.get_chrome_versionc                 C   s   |   ¡  |  d¡ |  ¡ S )Núget_chromium_version())r³   Ú%_BaseCase__fail_if_not_using_chromiumÚ$_BaseCase__get_major_browser_versionr‹   r8   r8   r9   Úget_chromium_version¢!  s    
zBaseCase.get_chromium_versionc                 C   s8   |   ¡  |  d¡ | jjd }|d }| d¡d }|S )Nzget_chromedriver_version()r  ÚchromedriverVersionre  r   )r³   rl  r=   r  rž  )r3   Úchrome_dictÚchromedriver_versionr8   r8   r9   r  §!  s    
z!BaseCase.get_chromedriver_versionc                 C   sx   |   ¡  |  d¡ d }d| jjv rF| jjd }|d }| d¡d }n.d| jjv rt| jjd }|d }| d¡d }|S )Nro  r  rs  re  r   rg  ÚmsedgedriverVersion)r³   rp  r=   r  rž  )r3   r  rt  Z	edge_dictr8   r8   r9   Úget_chromium_driver_version¯!  s    
z$BaseCase.get_chromium_driver_versionc                 C   s
   t  |¡S )z»Same as get_totp_code() and get_google_auth_password().
        Returns a time-based one-time password based on the Google
        Authenticator algorithm for multi-factor authentication.)r&   Úget_mfa_code©r3   Útotp_keyr8   r8   r9   rx  ½!  s    zBaseCase.get_mfa_codec                 C   sÖ   |   ¡  |stj}|  ¡ r>|  |¡}| jj||d |d� dS | j|||d� | jr²|  	¡ r²|  
d¡dkrª| j||d�}|  d¡}||g}|  ¡ }	d	||	|g}
| j |
¡ |  ¡  |  |¡}| j||d ||d� dS )
a[  Enters into the field a Multi-Factor Authentication TOTP Code.
        If the "totp_key" is not specified, this method defaults
        to using the one provided in [seleniumbase/config/settings.py].
        The TOTP code is generated by the Google Authenticator Algorithm.
        This method will automatically press ENTER after typing the code.rN  ré   NrI  rB  rC  rï   r    rÐ  )r³   r   rÿ   r´   rx  rµ   r  r  rÇ   rF  rG  r<  rÈ   rÉ   rF   r�   r�  r`  )r3   r-  rz  rð   rç   Zmfa_coderA  rÝ   Zsel_keyrÞ   rß   r8   r8   r9   Úenter_mfa_codeÃ!  s&    


zBaseCase.enter_mfa_codec                 C   s
   t  |¡S r.   )r"   Úconvert_css_to_xpath)r3   Úcssr8   r8   r9   r|  à!  s    zBaseCase.convert_css_to_xpathc                 C   s
   t  |¡S r.   )r(   Úconvert_xpath_to_cssr€  r8   r8   r9   r~  ã!  s    zBaseCase.convert_xpath_to_cssc                 C   s   t  ||¡S )a  This method converts a selector to a CSS_SELECTOR.
        jQuery commands require a CSS_SELECTOR for finding elements.
        This method should only be used for jQuery/JavaScript actions.
        Pure JavaScript doesn't support using a:contains("LINK_TEXT").)r#   r<  r¢  r8   r8   r9   r<  æ!  s    z BaseCase.convert_to_css_selectorc                 C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}| j||dd�\}}|  ¡ rZ| j ||¡ dS |  	¡  | j
|||d� |}| j||d�}|  ||¡ |rÂ| jsÂ| jsÂ| j|||d� |  ¡ rÂt d¡ |sä| jsä| jsä|  ¡ rät d¡ |  |¡}t |¡}|  |¡}|}	t |¡}|  |¡}d}
d|v�r:d	| }|  |¡}
| j�r°|  ¡ �r°|  d
¡dk�r°|  d¡}|  ¡ }|	|g}|
dk�r˜d|v�r˜d|||g}nd|||g}| j |¡ d|v�rÒd||f }|  |¡ n$| j
|||d�}d| }|  ||¡ | d¡�r0| j
|||d�}| t j!¡ tj"�rà|  	¡  n°|
dk�r‚d|v�r‚t#t$ƒ�" d| }|  |¡ W d  ƒ n1 �sv0    Y  n^|
dk�ràd|v �ràt#t$ƒ�0 | j
||dd�}d}|  ||¡ W d  ƒ n1 �sÖ0    Y  |  %¡  | j�s| j�s|  ¡ �rt d¡ dS )z3This method uses JavaScript to update a text field.FrT  NrI  rï   r›   r  r9  z9return document.querySelector('%s').getAttribute('type');rB  rC  r    r’  rÔ  rÑ  z(document.querySelector('%s').value='%s';zarguments[0].value='%s';rN  z_m_elm = document.querySelector('%s');m_evt = new Event('mousemove');m_elm.dispatchEvent(m_evt);r�   zOm_elm = arguments[0];m_evt = new Event('mousemove');m_elm.dispatchEvent(m_evt);)&r³   r   rT  r   r  r  r´   rµ   r\  rÔ   rg  r<  r  rÕ   r  rv  r½   rD   r¾   rY  r=  r>  r?  rÈ   rÇ   rF  rG  rÉ   rF   r�   rZ  rX  r   r[  rÒ   r   r¿   rÚ   )r3   r-  r]  rð   rç   rè   rí   rA  rS  Zpre_escape_css_selectorZthe_typeZget_type_scriptrÝ   rÞ   rr  rß   r{  r0  Zmouse_move_scriptr8   r8   r9   r\  í!  s     








ÿÿ


þÿÿ

þÿ,
ÿÿ,
zBaseCase.set_valuec                 C   s²   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  |¡}| j||||d� | d¡s®t	t
ƒ�4 tj| j||dd�}| dtj ¡ W d  ƒ n1 s¤0    Y  dS )zöJavaScript + send_keys are used to update a text field.
        Performs self.set_value() and triggers event listeners.
        If text ends in "
", set_value() presses RETURN after.
        Works faster than send_keys() alone due to the JS call.rI  rN  r®   ré   re  N)r³   r   rT  r   r  r  rY  r\  rZ  r   r¿   r$   rg  r=   rX  r   rW  ©r3   r-  r]  rð   rç   r0  r8   r8   r9   Újs_update_textJ"  s    




ÿzBaseCase.js_update_textc                 C   sR   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j||||d� dS )a  Same as self.js_update_text()
        JavaScript + send_keys are used to update a text field.
        Performs self.set_value() and triggers event listeners.
        If text ends in "
", set_value() presses RETURN after.
        Works faster than send_keys() alone due to the JS call.rI  N)r³   r   rT  r   r  r  r€  rm  r8   r8   r9   Újs_type^"  s    
zBaseCase.js_typec                 C   s¨   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rV| j ||¡ dS |  	¡  t
 | j|||¡}|j ¡ dv r’| j||||d� n| j||||d� dS )a[  Same as self.js_update_text()
        JavaScript + send_keys are used to update a text field.
        Performs self.set_value() and triggers event listeners.
        If text ends in "
", set_value() presses RETURN after.
        Works faster than send_keys() alone due to the JS call.
        If not an input or textarea, sets textContent instead.Nrë  rI  )r³   r   rT  r   r  r  r´   rµ   r\  rÔ   r$   rg  r=   r  r  r€  Úset_text_contentr  r8   r8   r9   Úset_textl"  s     

ÿzBaseCase.set_textc                 C   sJ  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}d}|  ¡ rZ| jj||d�}n|  	¡  t
 | j|||¡}|j ¡ dv r˜| j||||d� dS |}| j||d�}|rÖ|  ||¡ | jsÖ| jsÖ| j|||d� |  |¡}t |¡}	|  |	¡}	t |¡}|  |¡}d|v�r*d||	f }
|  |
¡ nd|	 }
|  |
|¡ |  ¡  dS )	z„This method uses JavaScript to set an element's textContent.
        If the element is an input or textarea, sets the value instead.Nré   rë  rI  rï   r9  z.document.querySelector('%s').textContent='%s';zarguments[0].textContent='%s';)r³   r   rT  r   r  r  r´   rµ   r1  rÔ   r$   rg  r=   r  r  r€  r<  r  rÕ   r  rv  rY  r=  r>  r?  rÈ   rÚ   )r3   r-  r]  rð   rç   rè   r0  rí   rA  rS  r{  r8   r8   r9   r‚  …"  sH    

ÿ





þzBaseCase.set_text_contentc                 C   s–  |   ¡  |}|}|stj}| jr4|tjkr4|  |¡}| j||dd�\}}| j|||d�}|  ||¡ | j||d� | j	||d�}|}|  
|¡}|  |¡}t |¡}|  |¡}d||f }	| j�r|  ¡ �r|  d¡dk�r|  d¡}
|  ¡ }||g}d	|||
g}| j |¡ |  |	¡ | d
¡�r@| j||dd�}| tj¡ nJttƒ�0 | j||dd�}| dtj ¡ W d  ƒ n1 �s€0    Y  |  ¡  dS )a  This method uses jQuery to update a text field.
        If the text string ends with the newline character,
        Selenium finishes the call, which simulates pressing
        {Enter/Return} after the text is entered.
        This method also triggers event listeners.FrT  rI  rï   zjQuery('%s').val('%s');rB  rC  r    rÒ  rN  r®   re  N)r³   r   rT  r   r  r  r  r  rv  r<  rÛ  r?  r=  r>  rÇ   rF  rG  rÈ   rÉ   rF   r�   rG  rZ  rg  rX  r   r[  r   r¿   rW  rÚ   )r3   r-  r]  rð   rç   rí   r/  r0  rA  Zupdate_text_scriptrÝ   rÞ   rr  rß   r8   r8   r9   Újquery_update_text±"  sN    
ÿ





ÿ
ÿ0zBaseCase.jquery_update_textc                 C   sR   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}| j||||d� dS )zÎSame as self.jquery_update_text()
        JQuery is used to update a text field.
        Performs jQuery(selector).val(text); and triggers event listeners.
        If text ends in "
", presses RETURN after.rI  N)r³   r   rT  r   r  r  r„  rm  r8   r8   r9   Újquery_typeâ"  s    
zBaseCase.jquery_typec           	      C   sâ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡  | j|||d� |}| j||d�}|  	||¡ | j
sŽ| jsŽ| j|||d� t |¡}|  |¡}d|vr¾d| }|  |¡}n | j||dd�}d}|  ||¡}|S )zyThis method uses JavaScript to get the value of an input field.
        (Works on both input fields and textarea fields.)rI  rï   r9  z*return document.querySelector('%s').value;r�   zreturn arguments[0].value;)r³   r   rT  r   r  r  rÔ   rg  r<  r  rÕ   r  rv  r=  r>  r?  rÈ   )	r3   r-  rð   rç   rí   rA  r{  rS  r0  r8   r8   r9   Ú	get_valueï"  s0    


ÿzBaseCase.get_valuec                 C   s|   |   ¡  |r6zt|ƒt_W q< ty2   d t_Y q<0 nd t_tjrftjdkrfttjd ƒt_tj| _nd | _d t_d t_d S )Nr   r:   )r³   r  rD  r�  r¿   rO   Ztime_limit_ms)r3   r�  r8   r8   r9   Úset_time_limit#  s    
zBaseCase.set_time_limitc                 C   s�   |   ¡  t|ttfƒstdƒ‚|dk r.tdƒ‚t|ƒ}d}d}||k rZt d| ¡ |}n||krtt d| ¡ |}d| _dt_	|t
_|t
_d	S )
aû  This method changes the default timeout values of test methods
        for the duration of the current test.
        Effected timeouts: (used by methods that wait for elements)
            * settings.SMALL_TIMEOUT - (default value: 6 seconds)
            * settings.LARGE_TIMEOUT - (default value: 10 seconds)
        The minimum allowable default timeout is: 0.5 seconds.
        The maximum allowable default timeout is: 60.0 seconds.
        (Test methods can still override timeouts outside that range.)r°  r   r±  r™  rw  zMinimum default timeout = %szMaximum default timeout = %sTN)r³   r˜  rO   r  r¿   r¸   r¹   rg   rD  Ú_is_timeout_changedr   rÿ   rT  )r3   rç   Zmin_timeoutZmax_timeoutr8   r8   r9   Úset_default_timeout#  s$    	zBaseCase.set_default_timeoutc                 C   s2   | j r.tjr.tjr.tjt_tjt_dt_d| _ dS )zƒReset default timeout values to the original from settings.py
        This method reverts the changes made by set_default_timeout()FN)rg   rD  Ú_SMALL_TIMEOUTÚ_LARGE_TIMEOUTr   rÿ   rT  rˆ  r‹   r8   r8   r9   Úreset_default_timeout:#  s    zBaseCase.reset_default_timeoutúfail() called!c                    s   t ƒ  |¡ dS )z)Fail immediately, with the given message.N)r/   r¸  ©r3   r¨   r6   r8   r9   r¸  D#  s    zBaseCase.failc                 C   sÚ   |   ¡  | jrX|  ¡ }t| dƒr&tj}|tj ¡ v rHtj| dkrHd| _d| _	dtj|< t
| ddƒrx| jrr|| _n|| _t| dƒsŠ|  ¡ }tj | j|¡}|  |¡ | j}|s²d}t | || j||¡ d| _|  |¡ dS )zMark the test as Skipped.rø  ÚPassedTÚSkippedÚwith_db_reportingNzNo skip reason given)r³   Ú	dashboardÚ_BaseCase__get_test_id_2rÍ   rD  r  Ú_resultsr!  rY   rX   r·   Ú	is_pytestra   Z_nose_skip_reasonr$  ry  rz  r2  rB  rC  r  r   Zlog_skipped_test_datar=   r€   ZskipTest)r3   Úreasonr
  rF  r  r8   r8   r9   r‰  H#  s8    
ÿþ


ÿzBaseCase.skipc                 C   s   |   d¡ dS )a   Starts recording console logs. Logs are saved to: "console.logs".
        To get those logs later, call "self.get_recorded_console_logs()".
        If navigating to a new page, then the current recorded logs will be
        lost, and you'll have to call start_recording_console_logs() again.
        # Link1: https://stackoverflow.com/a/19846113/7058266
        # Link2: https://stackoverflow.com/a/74196986/7058266 a  
            console.stdlog = console.log.bind(console);
            console.logs = [];
            console.log = function(){
                console.logs.push(Array.from(arguments));
                console.stdlog.apply(console, arguments);
            }
            N©rÈ   r‹   r8   r8   r9   Ústart_recording_console_logso#  s    ÿz%BaseCase.start_recording_console_logsc                 C   s   |   d| ¡ dS )zlLog a string to the Web Browser's Console.
        Example:
        self.console_log_string("Hello World!") zconsole.log(`%s`);Nr—  ©r3   rg  r8   r8   r9   Úconsole_log_string�#  s    zBaseCase.console_log_stringc                 C   s   |   d| ¡ dS )z”Log output of JavaScript to the Web Browser's Console.
        Example:
        self.console_log_script('document.querySelector("h2").textContent') zconsole.log(%s);Nr—  rˆ  r8   r8   r9   Úconsole_log_script‡#  s    zBaseCase.console_log_scriptc                 C   s:   g }t tƒ� |  d¡}W d  ƒ n1 s,0    Y  |S )zAGet console logs recorded after "start_recording_console_logs()".zreturn console.logs;N)r   r¿   rÈ   )r3   Úlogsr8   r8   r9   Úget_recorded_console_logs�#  s    
(z"BaseCase.get_recorded_console_logsc                 C   s8   |   ¡ }|r4t|ƒdkr4d|v s0d|v s0d|v r4dS dS r½  r¾  rä   r8   r8   r9   Z__is_valid_storage_url˜#  s
    zBaseCase.__is_valid_storage_urlc                 C   sH   |   ¡  |  ¡ stdƒ‚|  ¡ r2| j ||¡ d S |  d ||¡¡ d S )Nú$Local Storage is not available here!z(window.localStorage.setItem('{}', '{}');)r³   Ú_BaseCase__is_valid_storage_urlr   r´   rµ   Úset_local_storage_itemrÈ   Úformat©r3   rs  rS  r8   r8   r9   r   Ÿ#  s    
ÿzBaseCase.set_local_storage_itemc                 C   s<   |   ¡  |  ¡ stdƒ‚|  ¡ r,| j |¡S |  d |¡¡S )Nrž  z)return window.localStorage.getItem('{}');)r³   rŸ  r   r´   rµ   Úget_local_storage_itemrÈ   r¡  ©r3   rs  r8   r8   r9   r£  ª#  s    ÿzBaseCase.get_local_storage_itemc                 C   s,   |   ¡  |  ¡ stdƒ‚|  d |¡¡ d S )Nrž  z%window.localStorage.removeItem('{}');©r³   rŸ  r   rÈ   r¡  r¤  r8   r8   r9   Úremove_local_storage_item´#  s    ÿz"BaseCase.remove_local_storage_itemc                 C   sR   |   ¡  |  ¡ sd S |  d¡ | jrN|  d¡}|  ¡ }dd||g}| j |¡ d S )Nzwindow.localStorage.clear();r    ré  rd  )r³   rŸ  rÈ   rÇ   rÉ   rF   r�   r•  r8   r8   r9   Úclear_local_storage¼#  s    

zBaseCase.clear_local_storagec                 C   s"   |   ¡  |  ¡ stdƒ‚|  d¡S )Nrž  zpvar ls = window.localStorage, keys = []; for (var i = 0; i < ls.length; ++i)   keys[i] = ls.key(i); return keys;©r³   rŸ  r   rÈ   r‹   r8   r8   r9   Úget_local_storage_keysÇ#  s    ÿzBaseCase.get_local_storage_keysc                 C   s"   |   ¡  |  ¡ stdƒ‚|  d¡S )Nrž  z†var ls = window.localStorage, items = {}; for (var i = 0, k; i < ls.length; ++i)   items[k = ls.key(i)] = ls.getItem(k); return items;r¨  r‹   r8   r8   r9   Úget_local_storage_itemsÒ#  s    ÿz BaseCase.get_local_storage_itemsc                 C   sH   |   ¡  |  ¡ stdƒ‚|  ¡ r2| j ||¡ d S |  d ||¡¡ d S )Nú&Session Storage is not available here!z*window.sessionStorage.setItem('{}', '{}');)r³   rŸ  r   r´   rµ   Úset_session_storage_itemrÈ   r¡  r¢  r8   r8   r9   r¬  ß#  s    
ÿz!BaseCase.set_session_storage_itemc                 C   s<   |   ¡  |  ¡ stdƒ‚|  ¡ r,| j |¡S |  d |¡¡S )Nr«  z+return window.sessionStorage.getItem('{}');)r³   rŸ  r   r´   rµ   rG  rÈ   r¡  r¤  r8   r8   r9   rG  ê#  s    ÿz!BaseCase.get_session_storage_itemc                 C   s,   |   ¡  |  ¡ stdƒ‚|  d |¡¡ d S )Nr«  z'window.sessionStorage.removeItem('{}');r¥  r¤  r8   r8   r9   Úremove_session_storage_itemô#  s    ÿz$BaseCase.remove_session_storage_itemc                 C   s€   |   ¡  |  ¡ sd S | js&|  d¡ nVg d¢}|  ¡ }|D ]}||vr:|  |¡ q:|  d¡}|  ¡ }dd||g}| j |¡ d S )Nzwindow.sessionStorage.clear();)rÇ   rÄ  Zrecorder_titlerB  r®  r    rê  rd  )	r³   rŸ  rÇ   rÈ   Úget_session_storage_keysr­  rÉ   rF   r�   )r3   Zrecorder_keysr!  rs  rÝ   rÞ   rß   r8   r8   r9   Úclear_session_storageü#  s    
zBaseCase.clear_session_storagec                 C   s"   |   ¡  |  ¡ stdƒ‚|  d¡S )Nr«  zrvar ls = window.sessionStorage, keys = []; for (var i = 0; i < ls.length; ++i)   keys[i] = ls.key(i); return keys;r¨  r‹   r8   r8   r9   r®  $  s    ÿz!BaseCase.get_session_storage_keysc                 C   s"   |   ¡  |  ¡ stdƒ‚|  d¡S )Nr«  zˆvar ls = window.sessionStorage, items = {}; for (var i = 0, k; i < ls.length; ++i)   items[k = ls.key(i)] = ls.getItem(k); return items;r¨  r‹   r8   r8   r9   Úget_session_storage_items$  s    ÿz"BaseCase.get_session_storage_itemsc                 C   sp   |si | j _dS d}d}| d¡r,d}d}n| d¡r>d}d}| d¡d	 }d
||f d
||f ddœ| j _dS )a/  Set a proxy server for selenium-wire mode ("--wire")
        NOTE: This method ONLY works while using "--wire" mode!
        Examples:
            self.set_wire_proxy("SERVER:PORT")
            self.set_wire_proxy("socks5://SERVER:PORT")
            self.set_wire_proxy("USERNAME:PASSWORD@SERVER:PORT") Nr±   rŸ   z	socks4://Zsocks4z	socks5://Zsocks5r`  rû   z%s://%szlocalhost,127.0.0.1)r±   rŸ   Úno_proxy)r=   r-  rÆ   rž  )r3   rg  Zthe_httpZ	the_httpsr8   r8   r9   Úset_wire_proxy-$  s     



ýzBaseCase.set_wire_proxyc                 C   s   |   |¡ dS ©zSame as self.open()N©r¶   rä   r8   r8   r9   Úopen_urlJ$  s    zBaseCase.open_urlc                 C   s   |   |¡ dS r³  r´  rä   r8   r8   r9   ÚvisitN$  s    zBaseCase.visitc                 C   s   |   |¡ dS r³  r´  rä   r8   r8   r9   Ú	visit_urlR$  s    zBaseCase.visit_urlc                 C   s   |   |¡ dS r³  r´  rä   r8   r8   r9   ÚgotoV$  s    zBaseCase.gotoc                 C   s   |   |¡ dS r³  r´  rä   r8   r8   r9   Úgo_toZ$  s    zBaseCase.go_toc                 C   s   |   ¡  dS ©zSame as self.refresh_page()Nr  r‹   r8   r8   r9   r|  ^$  s    zBaseCase.reloadc                 C   s   |   ¡  dS rº  r  r‹   r8   r8   r9   Úreload_pageb$  s    zBaseCase.reload_pagec                 K   s   | j f d|i|¤Ž dS )zSame as self.open_new_window()r§   N)rË   )r3   r§   r5   r8   r8   r9   rÊ  f$  s    zBaseCase.open_new_tabc                 C   s   | j ||d� dS )zïSame as self.switch_to_window()
        Switches control of the browser to the specified window.
        The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...
            Or it can be a list item from self.driver.window_handles )rÍ  rç   NrÎ  )r3   rÉ  rç   r8   r8   r9   rÌ  j$  s    zBaseCase.switch_to_tabc                 C   s   |   ¡  dS )z'Same as self.switch_to_default_window()N)rÏ  r‹   r8   r8   r9   Úswitch_to_default_tabq$  s    zBaseCase.switch_to_default_tabc                 C   s   |   ¡  dS )z&Same as self.switch_to_newest_window()N)rË  r‹   r8   r8   r9   r¶  u$  s    zBaseCase.switch_to_newest_tabc                 C   s   | j ||d� dS )zSame as self.save_page_source()rA  N)rR  rJ  r8   r8   r9   Úsave_as_htmly$  s    zBaseCase.save_as_htmlc                 C   s   | j |||||d� dS ©zSame as self.update_text()rk  N©r`  rl  r8   r8   r9   rì  }$  s    zBaseCase.inputc                 C   s   | j |||||d� dS r¾  r¿  rl  r8   r8   r9   rñ  ƒ$  s    zBaseCase.fillc                 C   s   | j |||||d� dS r¾  r¿  rl  r8   r8   r9   r&  ‰$  s    zBaseCase.writec                 C   s   | j ||d� dS )zSame as self.click_link_text()ré   N)r  ©r3   r¸  rç   r8   r8   r9   rÕ  �$  s    zBaseCase.click_linkc                 C   s   | j ||d� dS )z&Same as self.click_partial_link_text()ré   N)r  ©r3   rº  rç   r8   r8   r9   Úclick_partial_link“$  s    zBaseCase.click_partial_linkc                 C   s   | j |||d� dS )zSame as self.context_click()rI  N)rE  r5  r8   r8   r9   Úright_click—$  s    zBaseCase.right_clickc                 C   s   | j |||d�S ©zSame as self.hover()rI  ©r8  r5  r8   r8   r9   r9  ›$  s    zBaseCase.hover_elementc                 C   s   | j |||d�S rÄ  rÅ  r5  r8   r8   r9   r:  Ÿ$  s    zBaseCase.hover_on_elementc                 C   s   | j |||d�S rÄ  rÅ  r5  r8   r8   r9   Úhover_over_element£$  s    zBaseCase.hover_over_elementc                 C   sŒ   |   ¡  |  ¡  |stj}| jr4|tjkr4|  |¡}|}|  ||¡\}}|  ¡ r`| jj	||d�S |  
|¡rv|  ||¡S tj| j||||d�S )zSame as self.wait_for_element()ré   rì   )r³   rþ   r   rT  r   r  r  r´   rµ   r1  r  Ú_BaseCase__get_shadow_elementr$   r  r=   ©r3   r-  rð   rç   rí   r8   r8   r9   r  §$  s&    

ûz!BaseCase.wait_for_element_visiblec                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ rX| jj||d�S |  	|¡rn|  
||¡S tj| j||||d�S )z=Waits for the element to be clickable, but does NOT click it.ré   rì   )r³   r   rT  r   r  r  r´   rµ   r1  r  Ú*_BaseCase__wait_for_shadow_element_visibler$   r  r=   rÈ  r8   r8   r9   r  ¿$  s$    

ûz#BaseCase.wait_for_element_clickablec                 C   sr   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ r\| jj||d� dS t	j| j
||||d�S )a,  Same as self.wait_for_element_absent()
        Waits for an element to no longer appear in the HTML of a page.
        A hidden element still counts as appearing in the page HTML.
        If waiting for elements to be hidden instead of nonexistent,
        use wait_for_element_not_visible() instead.ré   Trì   ©r³   r   rT  r   r  r  r´   rµ   Úwait_for_element_absentr$   r=   rÈ  r8   r8   r9   Úwait_for_element_not_present×$  s"    
ûz%BaseCase.wait_for_element_not_presentc                 O   sŒ  |   ¡  g }d}|D ]ˆ}|dkr*|d }q|dkr4q|dksD|dkr�|| }t|tƒrb| |¡ qœt|tƒrœ|}|D ]}t|tƒrt| |¡ qtqtd| ƒ‚q|s¨tj}| jrÂ|tjkrÂ|  	|¡}|D ]B}t|tƒrô|D ]}t|tƒrØ| |¡ qØqÆt|tƒrÆ| |¡ qÆ|�stdƒ‚|}	g }
|D ]4}d}t
 |¡�r<d	}|  ||¡\}}|
 |¡ �q$|
}|  ¡ �rx| jj||d
�S tj| j|||	d�S )a.  Waits for at least one of the elements to be visible.
        Returns the first element that is found.
        The input is a list of elements. (Should be CSS selectors or XPath)
        Optional kwargs include: "timeout" (used by all selectors).
        Raises an exception if no elements are visible by the timeout.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.wait_for_any_of_elements_visible("h1", "h2", "h3")
            OR
            self.wait_for_any_of_elements_visible(["h1", "h2", "h3"]) Nrç   rð   r-  Ú	selectorsúUnknown kwarg: "%s"!úThe selectors list was empty!rå   r   ré   ©rç   Úoriginal_selectors)r³   r˜  rÁ   r�   rÄ  r¿   r   rT  r   r  r%   r`  r  r´   rµ   Ú wait_for_any_of_elements_visibler$   r=   ©r3   r4   r5   rÍ  rç   Úkwargr-  rJ  r—   rÑ  Zupdated_selectorsrð   r8   r8   r9   rÒ  ñ$  sd    








ÿüz)BaseCase.wait_for_any_of_elements_visiblec                 O   sŒ  |   ¡  g }d}|D ]ˆ}|dkr*|d }q|dkr4q|dksD|dkr�|| }t|tƒrb| |¡ qœt|tƒrœ|}|D ]}t|tƒrt| |¡ qtqtd| ƒ‚q|s¨tj}| jrÂ|tjkrÂ|  	|¡}|D ]B}t|tƒrô|D ]}t|tƒrØ| |¡ qØqÆt|tƒrÆ| |¡ qÆ|�stdƒ‚|}	g }
|D ]4}d}t
 |¡�r<d	}|  ||¡\}}|
 |¡ �q$|
}|  ¡ �rx| jj||d
�S tj| j|||	d�S )aq  Waits for at least one of the elements to be present.
        Visibility not required, but element must be in the DOM.
        Returns the first element that is found.
        The input is a list of elements. (Should be CSS selectors or XPath)
        Optional kwargs include: "timeout" (used by all selectors).
        Raises an exception if no elements are present by the timeout.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.wait_for_any_of_elements_present("style", "script")
            OR
            self.wait_for_any_of_elements_present(["style", "script"]) Nrç   rð   r-  rÍ  rÎ  rÏ  rå   r   ré   rÐ  )r³   r˜  rÁ   r�   rÄ  r¿   r   rT  r   r  r%   r`  r  r´   rµ   Ú wait_for_any_of_elements_presentr$   r=   rÓ  r8   r8   r9   rÕ  0%  sd    








ÿüz)BaseCase.wait_for_any_of_elements_presentc                 O   s&   d|vrt j|d< | j|i |¤Ž dS )aÄ  Similar to wait_for_any_of_elements_visible(), but returns nothing.
        As above, raises an exception if none of the set elements are visible.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.assert_any_of_elements_visible("h1", "h2", "h3")
            OR
            self.assert_any_of_elements_visible(["h1", "h2", "h3"]) rç   T)r   rÿ   rÒ  r2   r8   r8   r9   Úassert_any_of_elements_visiblep%  s    	
z'BaseCase.assert_any_of_elements_visiblec                 O   s&   d|vrt j|d< | j|i |¤Ž dS )a  Similar to wait_for_any_of_elements_present(), but returns nothing.
        As above, raises an exception if none of the given elements are found.
        Visibility is not required, but element must exist in the DOM.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.assert_any_of_elements_present("h1", "h2", "h3")
            OR
            self.assert_any_of_elements_present(["h1", "h2", "h3"]) rç   T)r   rÿ   rÕ  r2   r8   r8   r9   Úassert_any_of_elements_present~%  s    

z'BaseCase.assert_any_of_elements_presentc                 C   s   | j |||d�S )N)rð   r  )r	  )r3   r-  rð   r  r8   r8   r9   r  �%  s    zBaseCase.select_allc                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d� dS )zSame as self.assert_link_text()ré   N)r³   r   rÿ   r   r  Úassert_link_textrÀ  r8   r8   r9   Úassert_link�%  s    
zBaseCase.assert_linkc                 C   s@   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|||d� dS )aÂ  Same as self.assert_element_absent()
        Raises an exception if the element stays present.
        A hidden element counts as a present element, which fails this assert.
        If you want to assert that elements are hidden instead of nonexistent,
        use assert_element_not_visible() instead.
        (Note that hidden elements are still present in the HTML of the page.)
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rI  T)r³   r   rÿ   r   r  rË  r5  r8   r8   r9   Úassert_element_not_present™%  s    

z#BaseCase.assert_element_not_presentc                 C   s   | j |d�S ©zSame as self.get_mfa_code())rz  ©rx  ry  r8   r8   r9   Úget_google_auth_password«%  s    z!BaseCase.get_google_auth_passwordc                 C   s   | j |d�S rÛ  rÜ  ry  r8   r8   r9   Úget_google_auth_code¯%  s    zBaseCase.get_google_auth_codec                 C   s   | j |d�S rÛ  rÜ  ry  r8   r8   r9   Úget_totp_code³%  s    zBaseCase.get_totp_codec                 C   s   | j ||||d�S )zSame as self.enter_mfa_code())r-  rz  rð   rç   )r{  )r3   r-  rz  rð   rç   r8   r8   r9   Úenter_totp_code·%  s    ÿzBaseCase.enter_totp_codec                 C   s   |   ¡  dS )z!Same as self.delete_all_cookies()N)r~  r‹   r8   r8   r9   Úclear_all_cookies¿%  s    zBaseCase.clear_all_cookiesc                 C   s   |   ¡  dS )z"Same as self.clear_local_storage()N)r§  r‹   r8   r8   r9   Údelete_local_storageÃ%  s    zBaseCase.delete_local_storagec                 C   s   |   ¡  dS )zSame as clear_session_storage()N)r¯  r‹   r8   r8   r9   Údelete_session_storageÇ%  s    zBaseCase.delete_session_storagec                 C   s   | j |d� dS )z#Same as self.assert_no_404_errors())r»  N)rÀ  )r3   r»  r8   r8   r9   Úassert_no_broken_linksË%  s    zBaseCase.assert_no_broken_linksc                 C   s   |   |¡ dS )z?Same as self.sleep() - Some JS frameworks use this method name.N)r¾   )r3   r“  r8   r8   r9   r§  Ï%  s    zBaseCase.waitc                 C   s   |   ¡  dS )zSame as self.ad_block()N)r¢  r‹   r8   r8   r9   Ú	block_adsÓ%  s    zBaseCase.block_adsc                 C   sP   t  | j¡ d}ttƒ� | jj}W d  ƒ n1 s60    Y  |sLtdƒ‚dS )z‹This method raises an exception if the active window is closed.
        (This provides a much cleaner exception message in this situation.)Nz!Active window was already closed!)r$   Ú_reconnect_if_disconnectedr=   r   r¿   r  r	   )r3   Zactive_windowr8   r8   r9   r¼   ×%  s    
&zBaseCase._check_browserc                 C   sd   t tddƒrXt|tƒsFttƒ� t|ƒ}W d  ƒ n1 s<0    Y  tj |d ¡ nt	|ƒ dS )aÜ  Same as Python's print(), but also prints during multithreaded runs.
        Normally, Python's print() command won't print for multithreaded tests.
        Here's an example of running tests using multithreading: "pytest -n=4".
        Here's how to print directly from sys without using a print() command:
        To force a print during multithreaded tests, use: "sys.stderr.write()".
        To print without the new-line character end, use: "sys.stdout.write()".
        Ú_multithreadedNrN  )
r·   rD  r˜  rÁ   r   r¿   r�   Ústderrr&  rµ  rŽ  r8   r8   r9   Ú_printá%  s    

&zBaseCase._printc                 C   s"   |   ¡  |  ¡  t | j|¡ d S r.   )r³   r¼   r#   Úadd_css_linkr=   )r3   Zcss_linkr8   r8   r9   rê  ó%  s    zBaseCase.add_css_linkc                 C   s"   |   ¡  |  ¡  t | j|¡ d S r.   )r³   r¼   r#   r×   r=   ©r3   Zjs_linkr8   r8   r9   r×   ø%  s    zBaseCase.add_js_linkc                 C   s"   |   ¡  |  ¡  t | j|¡ d S r.   )r³   r¼   r#   Úadd_css_styler=   )r3   Z	css_styler8   r8   r9   rì  ý%  s    zBaseCase.add_css_stylec                 C   s"   |   ¡  |  ¡  t | j|¡ d S r.   )r³   r¼   r#   Úadd_js_code_from_linkr=   rë  r8   r8   r9   rí  &  s    zBaseCase.add_js_code_from_linkc                 C   s"   |   ¡  |  ¡  t | j|¡ d S r.   )r³   r¼   r#   rh  r=   )r3   rq  r8   r8   r9   rh  &  s    zBaseCase.add_js_codec                 C   s&   |   ¡  |  ¡  tj| j||d� d S )N)Ú
http_equivÚcontent)r³   r¼   r#   Úadd_meta_tagr=   )r3   rî  rï  r8   r8   r9   rð  &  s
    ÿzBaseCase.add_meta_tagc                 C   s8   |   ¡  |  ¡ s|  ¡  t | j¡ |  ¡ s4|  ¡  d S r.   )r³   r´   r¼   r#   Úactivate_messengerr=   rÔ   r‹   r8   r8   r9   rñ  &  s    zBaseCase.activate_messengerÚdefaultc                 C   sR   |   ¡  |  ¡ s|  ¡  |s d}|s(d}|s2d}nt|ƒ}tj| j|||d� dS )a  Sets a theme for posting messages.
        Themes: ["flat", "future", "block", "air", "ice"]
        Locations: ["top_left", "top_center", "top_right",
                    "bottom_left", "bottom_center", "bottom_right"]
        max_messages: The limit of concurrent messages to display.rò  )ÚthemeÚlocationÚmax_messagesN)r³   r´   r¼   rÁ   r#   Úset_messenger_themer=   )r3   ró  rô  rõ  r8   r8   r9   rö  &  s     üzBaseCase.set_messenger_themer¹   c                 C   sÀ   |   ¡  |  ¡ s|  ¡  |dvr$d}|s<| js6tj}n| j}| jsN| jsN| jr^t	|ƒdkr^d}zt
j| j|||d� W n& tyœ   td| ¡ |f ƒ Y n0 |r¼t	|ƒd }t t	|ƒ¡ dS )a¨  Post a message on the screen with Messenger.
        Arguments:
            message: The message to display.
            duration: The time until the message vanishes. (Default: 2.55s)
            pause: If True, the program waits until the message completes.
            style: "info", "success", or "error".

        You can also post messages by using =>
            self.execute_script('Messenger().post("My Message")') )r¹   ræ  r«  r¹   ç      è?©r­  z * %s message: %sro  N)r³   r´   r¼   r/  r   ÚDEFAULT_MESSAGE_DURATIONr  rò  r(  r  r#   r·  r=   r¿   rµ  r   rD   r¾   )r3   râ   Údurationr¬  r­  r8   r8   r9   r·  7&  s2    
ÿÿÿ
þzBaseCase.post_messagec                 C   s   |   ¡  | j|||d� dS )a  Post a message on the screen and highlight an element.
        Arguments:
            message: The message to display.
            selector: The selector of the Element to highlight.
            by: The type of selector to search by. (Default: "css selector")rï   N)r³   rº  )r3   râ   r-  rð   r8   r8   r9   Úpost_message_and_highlightX&  s    z#BaseCase.post_message_and_highlightc                 C   s¤   |   ¡  |  ¡  |s(| js"tj}n| j}| js:| js:| jrJt|ƒdkrJd}zt	j
| j||dd� W n ty€   td| ƒ Y n0 |r t|ƒd }t t|ƒ¡ dS )a  Post a success message on the screen with Messenger.
        Arguments:
            message: The success message to display.
            duration: The time until the message vanishes. (Default: 2.55s)
            pause: If True, the program waits until the message completes.r÷  ræ  rø  z * SUCCESS message: %sro  N©r³   r¼   r/  r   rù  r  rò  r(  r  r#   r·  r=   r¿   rµ  rD   r¾   ©r3   râ   rú  r¬  r8   r8   r9   Úpost_success_messagea&  s0    ÿÿÿ
þ
ÿ
zBaseCase.post_success_messagec                 C   s¤   |   ¡  |  ¡  |s(| js"tj}n| j}| js:| js:| jrJt|ƒdkrJd}zt	j
| j||dd� W n ty€   td| ƒ Y n0 |r t|ƒd }t t|ƒ¡ dS )a  Post an error message on the screen with Messenger.
        Arguments:
            message: The error message to display.
            duration: The time until the message vanishes. (Default: 2.55s)
            pause: If True, the program waits until the message completes.r÷  r«  rø  z * ERROR message: %sro  Nrü  rý  r8   r8   r9   Úpost_error_message}&  s0    ÿÿÿ
þ
ÿ
zBaseCase.post_error_messagec                 C   sž   |   ¡  t |¡std| ƒ‚|rTt |¡s8td| ƒ‚|  |¡ t d¡ |  ¡  d| }|  d| ¡ | j	ddd� t d	¡ |rš|  	|¡ t d	¡ d
S )aU  This method opens the start_page, creates a referral link there,
        and clicks on that link, which goes to the destination_page.
        If a selector is given, clicks that on the destination_page,
        which can prevent an artificial rise in website bounce-rate.
        (This generates real traffic for testing analytics software.)z4Exception: destination_page {%s} is not a valid URL!zhException: start_page {%s} is not a valid URL! (Use an empty string or None to start from current page.)r°   z–<body><a class='analytics referral test' href='%s' style='font-family: Arial,sans-serif; font-size: 30px; color: #18a2cd'>Magic Link Button</a></body>zdocument.body.outerHTML = "%s"za.analytics.referral.testr¾  ré   ro  N)
r³   r%   rÄ   r¿   r¶   rD   r¾   rÔ   rÈ   r  )r3   r—  Údestination_pager-  Zreferral_linkr8   r8   r9   Úgenerate_referral›&  s:    
ÿÿ
þÿ

üÿÿ

zBaseCase.generate_referralc                 C   s4   |   ¡  t|ƒD ]}| j|||d� t d¡ qdS )zÄSimilar to generate_referral(), but can do multiple loops.
        If a selector is given, clicks that on the destination_page,
        which can prevent an artificial rise in website bounce-rate.©r-  rë   N)r³   r’  r  rD   r¾   )r3   r—  r   rá  r-  r¥  r8   r8   r9   Úgenerate_trafficÂ&  s    ÿzBaseCase.generate_trafficc                 C   sl   |   ¡  t|ttfƒstdƒ‚t|ƒdk r2tdƒ‚|D ]}t |¡s6td| ƒ‚q6|D ]}|  d|¡ qVdS )aV  Use this method to chain the action of creating button links on
        one website page that will take you to the next page.
        (When you want to create a referral to a website for traffic
        generation without increasing the bounce rate, you'll want to visit
        at least one additional page on that site with a button click.)z:Exception: Expecting a list of website pages for chaining!r¾  z<Exception: At least two website pages required for chaining!z0Exception: Website page {%s} is not a valid URL!N)	r³   r˜  rÄ  rA   r¿   r  r%   rÄ   r  )r3   rã  r¦  r8   r8   r9   Úgenerate_referral_chainÏ&  s     ÿÿ
ÿz BaseCase.generate_referral_chainc                 C   s.   |   ¡  t|ƒD ]}|  |¡ t d¡ qdS )z=Similar to generate_referral_chain(), but for multiple loops.rë   N)r³   r’  r  rD   r¾   )r3   rã  rá  r¥  r8   r8   r9   Úgenerate_traffic_chainæ&  s    
zBaseCase.generate_traffic_chainc                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ rX| jj||d�S |  	|¡rn|  
||¡S tj| j||||d�S )zvWaits for an element to appear in the HTML of a page.
        The element does not need be visible (it may be hidden).ré   rì   )r³   r   rT  r   r  r  r´   rµ   r1  r  Ú*_BaseCase__wait_for_shadow_element_presentr$   rg  r=   rÈ  r8   r8   r9   rg  ï&  s$    

ûz!BaseCase.wait_for_element_presentc                 C   sÔ   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ rX| jj||d�S | j	r¬|  
¡ r¬|  d¡dkr¬|tjkr‚|}|  d¡}|  ¡ }d|||g}| j |¡ |  |¡rÂ|  ||¡S t | j|||¡S )zpWaits for an element to appear in the HTML of a page.
        The element must be visible (it cannot be hidden).ré   rB  rC  r    rè  )r³   r   rT  r   r  r  r´   rµ   r1  rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   r  rÇ  r$   r  r=   )r3   r-  rð   rç   rí   rÝ   rÞ   rß   r8   r8   r9   r^  '  s,    




ÿzBaseCase.wait_for_elementc                 C   s   | j |||d�S ©zzSame as wait_for_element_present() - returns the element.
        The element does not need be visible (it may be hidden).rI  ©rg  r5  r8   r8   r9   rã   !'  s    zBaseCase.get_elementc                 C   s   | j |||d�S r  r  r5  r8   r8   r9   Úlocator&'  s    zBaseCase.locatorc                 C   s   | j |||d�S r  r  r5  r8   r8   r9   Úwait_for_selector+'  s    zBaseCase.wait_for_selectorc                 C   sb   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d�}|  ¡ rR| jj||d�S t	 
| j||¡S )z·Waits for an element to appear in the HTML of a page.
        The element does not need be visible (it may be hidden).
        This method uses document.querySelector() over Selenium.rï   ré   )r³   r   rT  r   r  r<  r´   rµ   r1  r#   Zwait_for_css_query_selectorr=   )r3   r-  rð   rç   rA  r8   r8   r9   Úwait_for_query_selector0'  s    
ÿz BaseCase.wait_for_query_selectorc                 C   sØ   |   ¡  |stj}| jr,|tjkr,|  |¡}t|tƒrJ| j|||d� dS |  ¡ rf| j	j
||d� dS |  |¡r~|  |¡ dS | j|||d� | jrÔ|  ¡ rÔ|  d¡dkrÔ|  d¡}|  ¡ }d|||g}| j |¡ dS )zÿSimilar to wait_for_element_present(), but returns nothing.
        Waits for an element to appear in the HTML of a page.
        The element does not need be visible (it may be hidden).
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rI  Tré   rB  rC  r    rÖ  )r³   r   rÿ   r   r  r˜  rÄ  Úassert_elements_presentr´   rµ   Úassert_element_presentr  Ú(_BaseCase__assert_shadow_element_presentrg  rÇ   rF  rG  rÈ   rÉ   rF   r�   ©r3   r-  rð   rç   rÝ   rÞ   rß   r8   r8   r9   r  B'  s,    




zBaseCase.assert_element_presentc           
      O   sX  |   ¡  g }d}tj}|D ]�}|dkr0|d }q|dkrB|d }q|dksR|dkrž|d }t|tƒrp| |¡ qªt|tƒrª|}|D ]}t|tƒr‚| |¡ q‚qtd| ƒ‚q|s¶tj	}| j
rÐ|tj	krÐ|  |¡}|D ]D}	t|	tƒ�r|	D ]}t|tƒrè| |¡ qèqÔt|	tƒrÔ| |	¡ qÔ|D ]4}|  |¡�r<|  |¡ �q| j|||d� �q�qdS )	a'  Similar to self.assert_element_present(),
            but can assert that multiple elements are present in the HTML.
        The input is a list of elements.
        Optional kwargs include "by" and "timeout" (used by all selectors).
        Raises an exception if any of the elements are not visible.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.assert_elements_present("head", "style", "script", "body")
            OR
            self.assert_elements_present(["head", "body", "h1", "h2"]) Nrç   rð   r-  rÍ  rÎ  rI  T)r³   r   rq  r˜  rÁ   r�   rÄ  r¿   r   rÿ   r   r  r  Ú(_BaseCase__assert_shadow_element_visiblerg  )
r3   r4   r5   rÍ  rç   rð   rÔ  r-  rJ  r—   r8   r8   r9   r  `'  sJ    








z BaseCase.assert_elements_presentc                 C   s   | j |||d�S )z8Same as wait_for_element_visible() - returns the elementrI  )r  r5  r8   r8   r9   rÔ  ’'  s    zBaseCase.find_elementc                 C   s¶  |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ r¨| jr”| j||dd�\}}d}| jdkrtddl	m
} | | j¡}d|| ¡ |f }|  |||¡ | jj||d� d	S t|tƒrÆ| j|||d
� d	S |  |¡rÞ|  |¡ d	S | j|||d
� |}| j�rV| j||dd�\}}d}| jdk�r6ddl	m
} | | j¡}d|| ¡ |f }|  |||¡ | j�r²|  ¡ �r²|  d¡dk�r²|tjk�rˆ|}|  d¡}|  ¡ }	d||	|g}
| j |
¡ d	S )z¿Similar to wait_for_element_visible(), but returns nothing.
        As above, raises an exception if nothing can be found.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.FrT  ÚASSERTr<   r   r³  ú<b>%s %s</b>: %sré   TrI  rB  rC  r    rÕ  )r³   r   rÿ   r   r  r´   rÕ   r  rs   r¹  r´  Útranslate_assertr   rº  rµ   Úassert_elementr˜  rÄ  Úassert_elementsr  r  r  rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   )r3   r-  rð   rç   r¾  r´  r¿  rí   rÝ   rÞ   rß   r8   r8   r9   r  –'  sb    
ÿ


ÿÿ


ÿ

zBaseCase.assert_elementc                 C   s@   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|||d� dS )z\Same as self.assert_element()
        As above, raises an exception if nothing can be found.rI  T)r³   r   rÿ   r   r  r  r5  r8   r8   r9   Úassert_element_visibleÎ'  s    
zBaseCase.assert_element_visiblec                 O   s¸  |   ¡  g }d}tj}|D ]�}|dkr0|d }q|dkrB|d }q|dksR|dkrž|d }t|tƒrp| |¡ qªt|tƒrª|}|D ]}t|tƒr‚| |¡ q‚qtd| ƒ‚q|s¶tj	}| j
rÐ|tj	krÐ|  |¡}|D ]D}	t|	tƒ�r|	D ]}t|tƒrè| |¡ qèqÔt|	tƒrÔ| |	¡ qÔ|D ]”}|  |¡�r<|  |¡ �q| j|||d� | j�r|  ||¡\}}d}
| jd	k�rŒd
dlm} | | j¡}
d|
| ¡ |f }|  |||¡ �q�qdS )aË  Similar to self.assert_element(), but can assert multiple elements.
        The input is a list of elements.
        Optional kwargs include "by" and "timeout" (used by all selectors).
        Raises an exception if any of the elements are not visible.
        Allows flexible inputs (Eg. Multiple args or a list of args)
        Examples:
            self.assert_elements("h1", "h2", "h3")
            OR
            self.assert_elements(["h1", "h2", "h3"]) Nrç   rð   r-  rÍ  rÎ  rI  r  r<   r   r³  r  T)r³   r   rq  r˜  rÁ   r�   rÄ  r¿   r   rÿ   r   r  r  r  r  rÕ   r  rs   r¹  r´  r  r   rº  )r3   r4   r5   rÍ  rç   rð   rÔ  r-  rJ  r—   r¾  r´  r¿  r8   r8   r9   r  Û'  sb    










ÿÿzBaseCase.assert_elementsc                 O   s   | j |i |¤ŽS )zZSame as self.assert_elements()
        Raises an exception if any element cannot be found.)r  r2   r8   r8   r9   Úassert_elements_visible(  s    z BaseCase.assert_elements_visiblec                 C   sŒ   |   ¡  |stj}| jr,|tjkr,|  |¡}|  |¡}|  ||¡\}}|  ¡ r`| jj	|||d�S |  
|¡rx|  |||¡S t | j||||¡S ©Nré   )r³   r   rT  r   r  rY  r  r´   rµ   Úwait_for_textr  Ú'_BaseCase__wait_for_shadow_text_visibler$   Úwait_for_text_visibler=   ©r3   r]  r-  rð   rç   r8   r8   r9   r   (  s    


ÿzBaseCase.wait_for_text_visiblec                 C   sh   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  |¡rT|  |||¡S t 	| j
||||¡S r.   )r³   r   rT  r   r  r  r  Ú-_BaseCase__wait_for_exact_shadow_text_visibler$   Úwait_for_exact_text_visibler=   r  r8   r8   r9   r  2(  s    

ÿÿz$BaseCase.wait_for_exact_text_visiblec                 C   sf   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  |¡rR|  ||¡S tj	| j
|||d�S )a  Searches for any text in the element of the given selector.
        Returns the element if it has visible text within the timeout.
        Raises an exception if the element has no text within the timeout.
        Whitespace-only text is considered empty text.rI  )r³   r   rT  r   r  r  r  Ú1_BaseCase__wait_for_non_empty_shadow_text_visibler$   Úwait_for_non_empty_text_visibler=   r5  r8   r8   r9   r   C(  s    

ÿ
ÿz(BaseCase.wait_for_non_empty_text_visiblec                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d�S )z.The shorter version of wait_for_text_visible()rI  ©r³   r   rT  r   r  r  r  r8   r8   r9   r  X(  s    
ÿzBaseCase.wait_for_textc                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d�S )z4The shorter version of wait_for_exact_text_visible()rI  ©r³   r   rT  r   r  r  r  r8   r8   r9   Úwait_for_exact_texte(  s    
ÿzBaseCase.wait_for_exact_textc                 C   s<   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|||d�S )z8The shorter version of wait_for_non_empty_text_visible()rI  ©r³   r   rT  r   r  r   r5  r8   r8   r9   Úwait_for_non_empty_textr(  s    
ÿz BaseCase.wait_for_non_empty_textc                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d�S )z5Same as wait_for_text_visible() - returns the elementrI  r!  r  r8   r8   r9   Ú	find_text(  s    
ÿzBaseCase.find_textc                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d�S )z;Same as wait_for_exact_text_visible() - returns the elementrI  r"  r  r8   r8   r9   Úfind_exact_textŒ(  s    
ÿzBaseCase.find_exact_textc                 C   s<   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|||d�S )z?Same as wait_for_non_empty_text_visible() - returns the elementrI  r$  r5  r8   r8   r9   Úfind_non_empty_text™(  s    
ÿzBaseCase.find_non_empty_textc                 C   s>   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d�S )zSame as assert_text()rI  )r³   r   rÿ   r   r  Úassert_textr  r8   r8   r9   Úassert_text_visible¦(  s    
zBaseCase.assert_text_visiblec                 C   sŽ  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}t|ttfƒrÒ|}|D ]v}| j	||||d� | j
rVd}d}	| jdkr¨ddlm}
 |
 | j¡}|
 | j¡}	d|||	| ¡ |f }|  |||¡ qV�nT|  ¡ �rV| j
�r@d}d}	| jdk�rddlm}
 |
 | j¡}|
 | j¡}	d|||	| ¡ |f }|  |||¡ | jj|||d� d	S |  |¡�r’t| d
ƒ�r€|  ¡ �s€|  ¡  |  |||¡ d	S t| d
ƒ�r°|  ¡ �s°|  ¡  | j	||||d� | j
�r&d}d}	| jdk�rddlm}
 |
 | j¡}|
 | j¡}	d|||	| ¡ |f }|  |||¡ | j�rŠ|  ¡ �rŠ|  d¡dk�rŠ|tjk�rX|}|  d¡}|   ¡ }||g}d|||g}| j! "|¡ d	S )a6  Similar to wait_for_text_visible()
        Raises an exception if the element or the text is not found.
        The text only needs to be a subset within the complete text.
        The text can be a string or a list/tuple of text substrings.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rI  úASSERT TEXTrJ  r<   r   r³  ú<b>%s</b>: {%s} %s %s: %sré   Tr  rB  rC  r    rã  )#r³   r   rÿ   r   r  r  r˜  rÄ  rA   r  rÕ   rs   r¹  r´  Útranslate_assert_textrK  r   rº  r´   rµ   r)  r  rÍ   r¤  r  Ú%_BaseCase__assert_shadow_text_visiblerÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   )r3   r]  r-  rð   rç   rí   Z	text_listÚ_textr¾  rL  r´  r¿  rÝ   rÞ   Útext_selectorrß   r8   r8   r9   r)  ±(  s’    
ÿ
ÿÿ

ÿÿÿÿ
zBaseCase.assert_textc                 C   sT  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ r^| jj|||d� dS |  	|¡rz|  
|||¡ dS | j||||d� | jrìd}d}| jdkrÈddlm} | | j¡}| | j¡}d	|||| ¡ |f }	|  |	||¡ | j�rP|  ¡ �rP|  d
¡dk�rP|tjk�r|}|  d¡}
|  ¡ }||g}d|||
g}| j |¡ dS )a=  Similar to assert_text(), but the text must be exact,
        rather than exist as a subset of the full text.
        (Extra whitespace at the beginning or the end doesn't count.)
        Raises an exception if the element or the text is not found.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.ré   TrI  úASSERT EXACT TEXTrJ  r<   r   r³  r,  rB  rC  r    ræ  )r³   r   rÿ   r   r  r  r´   rµ   Úassert_exact_textr  Ú+_BaseCase__assert_exact_shadow_text_visibler  rÕ   rs   r¹  r´  Útranslate_assert_exact_textrK  r   rº  rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   )r3   r]  r-  rð   rç   rí   r¾  rL  r´  r¿  rÝ   rÞ   r0  rß   r8   r8   r9   r2  )  sJ    

ÿ
ÿ
zBaseCase.assert_exact_textc                 C   s&  |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  |¡rZ|  ||¡ dS | j|||d� | j	rÈd}d}| j
dkr¦ddlm} | | j
¡}| | j
¡}d||| ¡ |f }|  |||¡ | j�r"|  ¡ �r"|  d	¡d
k�r"|tjkrø|}|  d¡}	|  ¡ }
d||
|	g}| j |¡ dS )z¹Assert that the element has any non-empty text visible.
        Raises an exception if the element has no text within the timeout.
        Whitespace-only text is considered empty text.TrI  úASSERT NON-EMPTY TEXTrJ  r<   r   r³  ú<b>%s</b> %s %s: %srB  rC  r    rç  )r³   r   rÿ   r   r  r  r  Ú/_BaseCase__assert_non_empty_shadow_text_visibler   rÕ   rs   r¹  r´  Útranslate_assert_non_empty_textrK  r   rº  rÇ   rF  rG  r   rH  rÈ   rÉ   rF   r�   )r3   r-  rð   rç   rí   r¾  rL  r´  r¿  rÝ   rÞ   rß   r8   r8   r9   Úassert_non_empty_text6)  s>    


ÿ

zBaseCase.assert_non_empty_textc           	   	   C   sÌ   |   ¡  |stj}t ¡ d }||d  }tt|d ƒƒD ]b}t ¡  z|  |¡s^t	d| ƒ‚W  d S  t	yš   t ¡ d }||krŒY  qžt 
d¡ Y q:0 q:d}|dkr®d}d|||f }t d	|¡ d S )
Nr:   r�  rÃ  r®   rì  r�   rd  z/Link text {%s} was not found after %s second%s!rÊ  )r³   r   rÿ   rD   r’  rO   r&   rÐ   rÁ  r¿   r¾   r$   rË  ©	r3   r¸  rç   r”  r•  r  r–  r1  râ   r8   r8   r9   rÖ  _)  s6    
ÿýz#BaseCase.wait_for_link_text_presentc           	   	   C   sÌ   |   ¡  |stj}t ¡ d }||d  }tt|d ƒƒD ]b}t ¡  z|  |¡s^t	d| ƒ‚W  d S  t	yš   t ¡ d }||krŒY  qžt 
d¡ Y q:0 q:d}|dkr®d}d|||f }t d	|¡ d S )
Nr:   r�  rÉ  r®   rì  r�   rd  z7Partial Link text {%s} was not found after %s second%s!rÊ  )r³   r   rÿ   rD   r’  rO   r&   rÐ   rÂ  r¿   r¾   r$   rË  r:  r8   r8   r9   rç  |)  s4    
ÿÿÿz+BaseCase.wait_for_partial_link_text_presentc                 C   sT   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rD| jj|dd�S | j|d|d�S )Nrò   )r]  r  r¶  rI  )	r³   r   rT  r   r  r´   rµ   r£  r  rÀ  r8   r8   r9   rØ  ˜)  s    
ÿz#BaseCase.wait_for_link_text_visiblec                 C   s:   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d�S )z3The shorter version of wait_for_link_text_visible()ré   ©r³   r   rT  r   r  rØ  rÀ  r8   r8   r9   Úwait_for_link_text¤)  s    
zBaseCase.wait_for_link_textc                 C   s:   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d�S )z:Same as wait_for_link_text_visible() - returns the elementré   r;  rÀ  r8   r8   r9   Úfind_link_text­)  s    
zBaseCase.find_link_textc           	      C   sè   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rH| jj||d� dS | j||d� | j	ržd}| j
dkr‚ddlm} | | j
¡}d||f }| j||dd	� | jrä|  ¡ rä|  d
¡dkrä|  d¡}|  ¡ }d|||g}| j |¡ dS )zÁSimilar to wait_for_link_text_visible(), but returns nothing.
        As above, raises an exception if nothing can be found.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.ré   NzASSERT LINK TEXTr<   r   r³  rN  r¶  rï   rB  rC  r    rÛ  T)r³   r   rÿ   r   r  r´   rµ   rÔ  rØ  rÕ   rs   r¹  r´  Útranslate_assert_link_textrº  rÇ   rF  rG  rÈ   rÉ   rF   r�   )	r3   r¸  rç   r¾  r´  r¿  rÝ   rÞ   rß   r8   r8   r9   rØ  ¶)  s2    

ÿ
zBaseCase.assert_link_textc                 C   s<   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|d|d�S )Nr¹  rI  )r³   r   rT  r   r  r  rÁ  r8   r8   r9   rè  Õ)  s    
ÿz#BaseCase.wait_for_partial_link_textc                 C   s:   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d�S )z;Same as wait_for_partial_link_text() - returns the element.ré   )r³   r   rT  r   r  rè  rÁ  r8   r8   r9   Úfind_partial_link_textß)  s    
ÿzBaseCase.find_partial_link_textc                 C   s†   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||d� | jr‚d}| jdkrfddlm	} | 
| j¡}d||f }| j||dd� d	S )
zÁSimilar to wait_for_partial_link_text(), but returns nothing.
        As above, raises an exception if nothing can be found.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.ré   zASSERT PARTIAL LINK TEXTr<   r   r³  rN  r¹  rï   T)r³   r   rÿ   r   r  rè  rÕ   rs   r¹  r´  r>  rº  )r3   rº  rç   r¾  r´  r¿  r8   r8   r9   Úassert_partial_link_textê)  s     

ÿz!BaseCase.assert_partial_link_textc                 C   sr   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ r\| jj||d� dS t	j| j
||||d�S )a  Waits for an element to no longer appear in the HTML of a page.
        A hidden element counts as a present element, which fails this assert.
        If waiting for elements to be hidden instead of nonexistent,
        use wait_for_element_not_visible() instead.ré   Trì   rÊ  rÈ  r8   r8   r9   rË  *  s"    
ûz BaseCase.wait_for_element_absentc                 C   s\   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rH| jj||d� dS | j|||d� dS )aÌ  Similar to wait_for_element_absent()
        As above, raises an exception if the element stays present.
        A hidden element counts as a present element, which fails this assert.
        If you want to assert that elements are hidden instead of nonexistent,
        use assert_element_not_visible() instead.
        (Note that hidden elements are still present in the HTML of the page.)
        Returns True if successful. Default timeout = SMALL_TIMEOUT.ré   TrI  )	r³   r   rÿ   r   r  r´   rµ   Úassert_element_absentrË  r5  r8   r8   r9   rA  *  s    
zBaseCase.assert_element_absentc                 C   sr   |   ¡  |stj}| jr,|tjkr,|  |¡}|}|  ||¡\}}|  ¡ r\| jj||d� dS t	j| j
||||d�S )z¤Waits for an element to no longer be visible on a page.
        The element can be non-existent in the HTML or hidden on the page
        to qualify as not visible.ré   Trì   )r³   r   rT  r   r  r  r´   rµ   Úwait_for_element_not_visibler$   r=   rÈ  r8   r8   r9   rB  0*  s"    
ûz%BaseCase.wait_for_element_not_visiblec                 C   s¢   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ¡ rH| jj||d� dS | j|||d� | j	rž|  
¡ rž|  d¡dkrž|  d¡}|  ¡ }d|||g}| j |¡ dS )z²Similar to wait_for_element_not_visible()
        As above, raises an exception if the element stays visible.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.ré   TrI  rB  rC  r    r×  )r³   r   rÿ   r   r  r´   rµ   Úassert_element_not_visiblerB  rÇ   rF  rG  rÈ   rÉ   rF   r�   r  r8   r8   r9   rC  H*  s     

z#BaseCase.assert_element_not_visiblec                 C   sj   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}|  ¡ rV| jj|||d�S t	 | j
||||¡S )N)r-  rç   )r³   r   rT  r   r  r  r´   rµ   Úwait_for_text_not_visibler$   r=   r  r8   r8   r9   rD  a*  s    
ÿÿz"BaseCase.wait_for_text_not_visiblec                 C   sP   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}t | j||||¡S r.   )	r³   r   rT  r   r  r  r$   Úwait_for_exact_text_not_visibler=   r  r8   r8   r9   rE  r*  s    
ÿz(BaseCase.wait_for_exact_text_not_visiblec           	      C   s�   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d� | jrŒ|  ¡ rŒ|  d¡dkrŒ|  	d¡}|  
¡ }||g}d|||g}| j |¡ dS )z³Similar to wait_for_text_not_visible()
        Raises an exception if the text is still visible after timeout.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rI  rB  rC  r    rä  T)r³   r   rÿ   r   r  rD  rÇ   rF  rG  rÈ   rÉ   rF   r�   ©	r3   r]  r-  rð   rç   rÝ   rÞ   r0  rß   r8   r8   r9   Úassert_text_not_visible*  s    

z BaseCase.assert_text_not_visiblec           	      C   s�   |   ¡  |stj}| jr,|tjkr,|  |¡}| j||||d� | jrŒ|  ¡ rŒ|  d¡dkrŒ|  	d¡}|  
¡ }||g}d|||g}| j |¡ dS )z¿Similar to wait_for_exact_text_not_visible()
        Raises an exception if the exact text is still visible after timeout.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rI  rB  rC  r    rå  T)r³   r   rÿ   r   r  rE  rÇ   rF  rG  rÈ   rÉ   rF   r�   rF  r8   r8   r9   Úassert_exact_text_not_visible”*  s     
ÿ
z&BaseCase.assert_exact_text_not_visiblec                 C   sR   |   ¡  |stj}| jr,|tjkr,|  |¡}|  ||¡\}}t | j|||||¡S r.   )	r³   r   rT  r   r  r  r$   Úwait_for_attribute_not_presentr=   rI  r8   r8   r9   rI  ­*  s    
ÿz'BaseCase.wait_for_attribute_not_presentc                 C   s@   |   ¡  |stj}| jr,|tjkr,|  |¡}| j|||||d�S )z½Similar to wait_for_attribute_not_present()
        Raises an exception if the attribute is still present after timeout.
        Returns True if successful. Default timeout = SMALL_TIMEOUT.rE  )r³   r   rÿ   r   r  rI  rI  r8   r8   r9   Úassert_attribute_not_presentº*  s    

ÿz%BaseCase.assert_attribute_not_presentc                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡}| jr€|  	¡ r€|  
d¡dkr€|  d¡}|  ¡ }dd||g}| j |¡ |S )NrB  rC  r    rØ  rd  )r³   r   rT  r   r  r$   Úwait_for_and_accept_alertr=   rÇ   rF  rG  rÈ   rÉ   rF   r�   ©r3   rç   rd  rÝ   rÞ   rß   r8   r8   r9   rK  Ë*  s    

z"BaseCase.wait_for_and_accept_alertc                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡}| jr€|  	¡ r€|  
d¡dkr€|  d¡}|  ¡ }dd||g}| j |¡ |S )NrB  rC  r    rÙ  rd  )r³   r   rT  r   r  r$   Úwait_for_and_dismiss_alertr=   rÇ   rF  rG  rÈ   rÉ   rF   r�   rL  r8   r8   r9   rM  Ú*  s    

z#BaseCase.wait_for_and_dismiss_alertc                 C   s:   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡S r.   )r³   r   rT  r   r  r$   Úwait_for_and_switch_to_alertr=   rŽ  r8   r8   r9   rN  é*  s    
z%BaseCase.wait_for_and_switch_to_alertc                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡}| jr€|  	¡ r€|  
d¡dkr€|  d¡}|  ¡ }dd||g}| j |¡ |S )z<Same as wait_for_and_accept_alert(), but smaller default T_OrB  rC  r    rØ  rd  )r³   r   rÿ   r   r  r$   rK  r=   rÇ   rF  rG  rÈ   rÉ   rF   r�   rL  r8   r8   r9   Úaccept_alertó*  s    

zBaseCase.accept_alertc                 C   s„   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡}| jr€|  	¡ r€|  
d¡dkr€|  d¡}|  ¡ }dd||g}| j |¡ |S )z=Same as wait_for_and_dismiss_alert(), but smaller default T_OrB  rC  r    rÙ  rd  )r³   r   rÿ   r   r  r$   rM  r=   rÇ   rF  rG  rÈ   rÉ   rF   r�   rL  r8   r8   r9   Údismiss_alert+  s    

zBaseCase.dismiss_alertc                 C   s:   |   ¡  |stj}| jr,|tjkr,|  |¡}t | j|¡S )z?Same as wait_for_and_switch_to_alert(), but smaller default T_O)r³   r   rÿ   r   r  r$   rN  r=   rŽ  r8   r8   r9   Úswitch_to_alert+  s    
zBaseCase.switch_to_alertc                 C   sj  |   ¡  |s| j}t|ƒjdkr*tdƒ‚n€t|dƒr\t|dƒr\t|dƒr\t|dƒr\t|dƒsftdƒ‚nD| jr€|| jkr€td	ƒ‚n*|| jks¢|| jv rªt	| jƒd
krªtdƒ‚z"t
rÂ| jdksÂ|jjrÊ| ¡  W n" tyÞ   Y n tyî   Y n0 || jv �r| j |¡ || jv �r| j|= || jk�r0|  ¡  z|  ¡  W n( t�yd   | jd | _|  ¡  Y n0 dS )aº  Quits the driver only if it's not the default/initial driver.
        If a driver is given, quits that, otherwise quits the active driver.
        Raises an Exception if quitting the default/initial driver.
        Should only be called if a test has already called get_new_driver().
        Afterwards, self.driver points to the default/initial driver
        if self.driver was the one being quit.
        ----
        If a test never calls get_new_driver(), this method isn't needed.
        SeleniumBase automatically quits browsers after tests have ended.
        Even if tests do call get_new_driver(), you don't need to use this
        method unless you want to quit extra browsers before a test ends.
        ----
        Terminology and important details:
        * Active driver: The one self.driver is set to. Used within methods.
        * Default/initial driver: The one that is spun up when tests start.
        Initially, the active driver and the default driver are the same.
        The active driver can change when one of these methods is called:
        > self.get_new_driver()
        > self.switch_to_default_driver()
        > self.switch_to_driver()
        > self.quit_extra_driver() rÃ  z+The driver to quit was a NoneType variable!rÌ   r”   Úquitr  r  z+The driver to quit does not match a Driver!z¨Cannot quit the initial driver in --reuse-session mode!
This is done automatically after all tests have ended.
Use this method only if get_new_driver() has been called.r�   z•Cannot quit the default/initial driver!
This is done automatically at the end of each test.
Use this method only if get_new_driver() has been called.rî   rû   N)r³   r=   r  r  r¿   rÍ   Ú_reuse_sessionr}   r~   r  r`  r  ÚserviceÚprocessrR  ÚAttributeErrorr  r   r7  r¼   r5  r8   r8   r9   Úquit_extra_driver+  sh    
ÿþýüû
ÿÿþþÿÿþýzBaseCase.quit_extra_driverc              
   O   sp  d}z| j |i |¤Ž W �nB t�y\ } �z&t|ƒ}d}| d¡}d}d}d}	d}
|D ]î}|rŠ|
sp||d 7 }|d }|dkrˆd}d}
qX| d¡r®d	}	d	}d}||d 7 }qX| d
¡rØd	}d}|	sÒ||d 7 }nd	}
qX| d¡rød	}d}||d 7 }qX| d¡�r||d 7 }qX| d¡�r,||d 7 }qX| ¡  d¡rX||d 7 }qXW Y d}~n
d}~0 0 |�rlt|ƒ‚dS )z1Minified assert_equal() using only the list diff.Nz
AssertionError:
rN  r,   Fr�   r   zFirst differingTz
First listÚF)ú+rÆ  ú?r  )r;  r¿   rÁ   rž  rÆ   rÂ   r   )r3   r4   r5   Zminified_exceptionrà   Zstr_erl  Z	countdownZcountdown_onZfirst_differingZ
skip_linesrm  r8   r8   r9   Z__assert_eqj+  sT    



$zBaseCase.__assert_eqc                 C   s"   t rtsdtjv sd S |  ¡  d S ©Nú--pdb)Úpython3_11_or_newerÚpy311_patch2r�   r‘   Ú'_BaseCase__process_visual_baseline_logsr‹   r8   r8   r9   Ú_process_visual_baseline_logs˜+  s    ÿÿþz&BaseCase._process_visual_baseline_logsc                 C   sL  t j | j|  ¡ ¡}| jD ]Þ}|d }|d }|d }|d }|d }|d }t j ||¡}	t j ||¡}
t j ||¡}t j ||¡}t| jƒdkrœ|
}	|}t j |¡rÊt j |	¡sÊ|  |¡ t	 
||	¡ t j |¡rt j |¡s|  |¡ t	 
||¡ qt| jƒdk�rdS t ¡ }t j |tjj¡}t|dd	d
�}| |¡ | ¡  dS )z…Save copies of baseline PNGs in "./latest_logs" during failures.
        Also create a side_by_side.html file for visual comparisons.r   r�   r¾  r,   r–  r�  Nrb  rc  rd  )ry  rz  r2  rB  r$  rZ   r  rl  rC  ÚshutilÚcopyr    Úget_sbs_htmlr!   Z
SideBySideZ	HTML_FILEr¶   rn  ro  )r3   rF  Úbaseline_copy_tupleÚbaseline_pathÚbaseline_copy_nameÚb_c_alt_nameÚlatest_png_pathÚlatest_copy_nameÚl_c_alt_nameÚbaseline_copy_pathZb_c_alt_pathÚlatest_copy_pathZl_c_alt_pathÚthe_htmlr  r:  r8   r8   r9   Z__process_visual_baseline_logs +  sD    

ÿ
þ

ÿ
þ

z'BaseCase.__process_visual_baseline_logsc           4   
   C   s  |   ¡  ttƒ�  | jdtjd� W d  ƒ n1 s60    Y  |  ¡ rRt d¡ |dkr^d}|dkrjd}|d	krvd
}|dkr‚d}|dkrª|dkrª|d
krª|dkrªtdƒ‚| j	r¾d}t
 |¡ |  ¡  d¡d }|ràt|ƒdk räd}t|ƒ}t ¡  tjj}tj |||¡}	tj |	d¡}
d}tj |	|¡}d}tj |	|¡}tj |	d¡}tj |	d¡}tj |	d¡}d}|�sz| j�r~d}tj |	¡�s´d}zt |	¡ W n t�y²   Y n0 tj |
¡�sÆd}tj |¡�sØd}tj |¡�sêd}tj |¡�süd}tj |¡�sd}|  ¡ }|  ¡ }|j ¡ }dd„ |D ƒ}t  t !|¡¡}dd„ |D ƒ}t  t !|¡¡}dd„ |D ƒ}t  t !|¡¡}|�r*| j"||	dd� t#|
dd d!�}| $|¡ | %¡  t#|dd d!�}| $t !|¡¡ | %¡  t#|dd d!�}| $t !|¡¡ | %¡  t#|dd d!�}| $t !|¡¡ | %¡  tj |	|¡}d"| }d}d#| }d$}||||||f}| j& '|¡ d} |�s
| j"||	dd� t#|
d%ƒ}!|! (¡  )¡ }"|! %¡  t#|d%ƒ}!t  |! (¡ ¡}#|! %¡  t#|d%ƒ}!t  |! (¡ ¡}$|! %¡  t#|d%ƒ}!t  |! (¡ ¡}%|! %¡  d&}&d'}'d(}(d)})|  *|¡}*|  *|"¡}+d*t+j,_-|dk�rN|�rN|  .|+|*|&¡ |dk�r||�sn|  /|%||)¡ n|  .|%||)¡ |d
k�rª|�sœ|  /|$||(¡ n|  .|$||(¡ |dk�rØ|�sÊ|  /|#||'¡ n|  .|#||'¡ |dk�rzì|�rø|  .|*|+|&¡ z(|�s|  /|#||'¡ n|  .|#||'¡ W n. t�yN }, zt0|,ƒ W Y d},~,n
d},~,0 0 z(|�sh|  /|$||(¡ n|  .|$||(¡ W n. t�y¦ }, zt0|,ƒ W Y d},~,n
d},~,0 0 |�s¾|  /|%||)¡ n|  .|%||)¡ W n2 t�y  }, zt0|,ƒ d} W Y d},~,n
d},~,0 0 dt+j,_-| j&d= | �rtj | j1|  2¡ ¡}-tj |¡�rHtj |¡�sLdS d| _3tj |-¡�sj|  4|-¡ tj |-|¡}.tj |-|¡}/tj |.¡�sºtj |/¡�sºt5 6||.¡ t5 6||/¡ t 7||¡}0d+ d,d„ |D ƒ¡}1d-|1 }2tj |-|2¡}3t#|3dd d!�}| $|0¡ | %¡  dS ).a
  ***  Automated Visual Testing with SeleniumBase  ***

        The first time a test calls self.check_window() for a unique "name"
        parameter provided, it will set a visual baseline, meaning that it
        creates a folder, saves the URL to a file, saves the current window
        screenshot to a file, and creates the following three files
        with the listed data saved:
        tags_level1.txt  ->  HTML tags from the window
        tags_level2.txt  ->  HTML tags + attributes from the window
        tags_level3.txt  ->  HTML tags + attributes/values from the window

        Baseline folders are named based on the test name and the name
        parameter passed to self.check_window(). The same test can store
        multiple baseline folders.

        If the baseline is being set/reset, the "level" doesn't matter.

        After the first run of self.check_window(), it will compare the
        HTML tags of the latest window to the one from the initial run.
        Here's how the level system works:
        * level=0 ->
            DRY RUN ONLY - Will perform comparisons to the baseline (and
                           print out any differences that are found) but
                           won't fail the test even if differences exist.
        * level=1 ->
            HTML tags are compared to tags_level1.txt
        * level=2 ->
            HTML tags are compared to tags_level1.txt and
            HTML tags/attributes are compared to tags_level2.txt
        * level=3 ->
            HTML tags are compared to tags_level1.txt and
            HTML tags + attributes are compared to tags_level2.txt and
            HTML tags + attributes/values are compared to tags_level3.txt
        As shown, Level-3 is the most strict, Level-1 is the least strict.
        If the comparisons from the latest window to the existing baseline
        don't match, the current test will fail, except for Level-0 tests.

        You can reset the visual baseline on the command line by using:
            --visual_baseline
        As long as "--visual_baseline" is used on the command line while
        running tests, the self.check_window() method cannot fail because
        it will rebuild the visual baseline rather than comparing the html
        tags of the latest run to the existing baseline. If there are any
        expected layout changes to a website that you're testing, you'll
        need to reset the baseline to prevent unnecessary failures.

        self.check_window() will fail with "Page Domain Mismatch Failure"
        if the page domain doesn't match the domain of the baseline,
        unless "check_domain" is set to False when calling check_window().

        If you want to use self.check_window() to compare a web page to
        a later version of itself from within the same test run, you can
        add the parameter "baseline=True" to the first time you call
        self.check_window() in a test to use that as the baseline. This
        only makes sense if you're calling self.check_window() more than
        once with the same name parameter in the same test.

        If "full_diff" is set to False, the error output will only
        include the first differing element in the list comparison.
        Set "full_diff" to True if you want to see the full output.

        Automated Visual Testing with self.check_window() is not very
        effective for websites that have dynamic content that changes
        the layout and structure of web pages. For those, you're much
        better off using regular SeleniumBase functional testing.

        Example usage:
            self.check_window(name="testing", level=0)
            self.check_window(name="xkcd_home", level=1)
            self.check_window(name="github_page", level=2)
            self.check_window(name="wikipedia_page", level=3) r¨  ré   Nr°   Ú0r   Ú1r�   Ú2r¾  Ú3r,   z/Parameter "level" must be set to 0, 1, 2, or 3!zmWARNING: Using check_window() from Demo Mode may lead to unexpected results caused by Demo Mode HTML changes.rù  rû   rò  zpage_url.txtzbaseline.pngz
latest.pngztags_level_1.txtztags_level_2.txtztags_level_3.txtFTc                 S   s   g | ]}|j g‘qS r8   ©r”   ©rZ  Útagr8   r8   r9   r[  W,  r\  z)BaseCase.check_window.<locals>.<listcomp>c                 S   s    g | ]}|j t|j ¡ ƒg‘qS r8   )r”   r  Úattrsr!  rs  r8   r8   r9   r[  Y,  r\  c                 S   s    g | ]}|j t|j ¡ ƒg‘qS r8   )r”   r  ru  Úitemsrs  r8   r8   r9   r[  [,  r\  r  rb  rc  rd  zbaseline_%s.pngzbaseline_diff_%s.pngzbaseline_diff.pngrx  zÃ
*
Page Domain Mismatch Failure: Current Page Domain doesn't match the Page Domain of the Baseline! Can't compare two completely different sites! Run with --visual_baseline to reset the baseline!zV
*
*** Exception: <Level 1> Visual Diff Failure:
* HTML tags don't match the baseline!ze
*
*** Exception: <Level 2> Visual Diff Failure:
* HTML tag attribute names don't match the baseline!zf
*
*** Exception: <Level 3> Visual Diff Failure:
* HTML tag attribute values don't match the baseline!i   rd  c                 S   s   g | ]}|  ¡ r|nd ‘qS )rÿ  )Úisalnum)rZ  r  r8   r8   r9   r[  ó,  r\  zside_by_side_%s.html)8rÔ   r   r¿   r  r   r(  r½   rD   r¾   rÕ   r¸   r¹   Ú_BaseCase__get_display_idrž  r  rÁ   r    Zvisual_baseline_folder_setupr!   ZVisualBaselinerk  ry  rz  r2  Úvisual_baselinerl  rm  r„  r»  r¨  r¼  rh  r�  ri  r<  r¶   rn  ro  rZ   r�   r|  rÂ   rÊ   ÚunittestÚTestCaseZmaxDiffr;  Ú_BaseCase__assert_eqrµ  rB  r$  rW   rC  ra  rb  rc  )4r3   r”   rW  ÚbaselineÚcheck_domainÚ	full_diffrâ   r
  Zbaseline_dirZvisual_baseline_pathZpage_url_fileZbaseline_pngZbaseline_png_pathZ
latest_pngrh  Zlevel_1_fileZlevel_2_fileZlevel_3_fileZset_baseliner§  r¾  Z	html_tagsZlevel_1Zlevel_2Zlevel_3r:  re  rf  rg  ri  rj  rd  Zis_level_0_failurer€  Zpage_url_dataZlevel_1_dataZlevel_2_dataZlevel_3_dataZdomain_failZlevel_1_failureZlevel_2_failureZlevel_3_failureZpage_domainZpage_data_domainrà   rF  rk  rl  rm  Zalpha_n_d_nameZside_by_side_namer  r8   r8   r9   Úcheck_windowÆ+  sˆ   O
ÿ$
 ÿ

ÿ
þÿ



ÿÿÿÿ





ÿÿÿÿÿÿÿ
ÿ
þ

ÿ
þÿ
zBaseCase.check_windowc                 C   sR   |   ¡  z.t| jƒ}|dkr d}tt || ¡ƒ}|W S  tyL   | Y S 0 dS )z#When using --timeout_multiplier=#.#r™  N)r³   r  r   rO   r–  r—  r¿   )r3   rç   r   r8   r8   r9   Z__get_new_timeoutü,  s    
zBaseCase.__get_new_timeoutc                 C   s2   t  | j¡}|r*| js&| jj| _d| _dS dS dS )z?If the driver is disconnected, use a CDP method when available.TFN)r&   Zis_cdp_swap_neededr=   rµ   rÓ   )r3   Zcdp_swap_neededr8   r8   r9   Z__is_cdp_swap_needed-  s    
zBaseCase.__is_cdp_swap_neededc                 C   s   t | dƒrd S d}t|ƒ‚d S )Nr  a”  
 It looks like you are trying to call a SeleniumBase method
 from outside the scope of your test class's `self` object,
 which is initialized by calling BaseCase's setUp() method.
 The `self` object is where all test variables are defined.
 If you created a custom setUp() method (that overrided the
 the default one), make sure to call super().setUp() in it.
 When using page objects, be sure to pass the `self` object
 from your test class into your page object methods so that
 they can call BaseCase class methods with all the required
 variables, which are initialized during the setUp() method
 that runs automatically before all tests called by pytest.)rÍ   r   )r3   râ   r8   r8   r9   Z__check_scope-  s
    
ÿzBaseCase.__check_scopec                 C   s`   t  ¡ d }t|dƒr|j}n>t|dƒr0|j}n,t|dƒrTt|jƒdkrT|jd }nt  ¡ }|S )zÁThis method extracts the message from an exception if there
        was an exception that occurred during the test, assuming
        that the exception was in a try/except block and not thrown.r�   r¨   râ   r4   r   )r�   Úexc_inforÍ   r¨   râ   r  r4   )r3   Zexception_infoÚexc_messager8   r8   r9   Z__get_exception_message--  s    

z BaseCase.__get_exception_messagec                 C   sL   |   ¡  | jj}|  ¡ }| j}| j d|||f ¡ |rH| jd| d� dS )z>Add a deferred_assert failure to a list for future processing.zDEFERRED ASSERT #%s: (%s) %s
zdeferred_#%srr  N)r³   r=   rÀ   Ú _BaseCase__get_exception_messageri   rj   r�   rH  )r3   ÚfsrÀ   râ   rh  r8   r8   r9   Z__add_deferred_assert_failure<-  s    ÿz&BaseCase.__add_deferred_assert_failurec           	      C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  jd7  _ttƒ�. |  ¡ }|| j	kr\d}n|| _	W d  ƒ n1 sv0    Y  | j
rÆ|  ¡ rÆ|  d¡dkrÆ|  d¡}|  ¡ }d|||g}| j |¡ z| j|||d� W d	S  t� yþ   | j|d
� Y dS 0 dS )aÏ  A non-terminating assertion for an element visible on the page.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   ç333333ã?NrB  rC  r    rë  rI  T©r„  F)r³   r   r(  r   r  ri   r   r¿   r„  r[   rÇ   rF  rG  rÈ   rÉ   rF   r�   r  Ú&_BaseCase__add_deferred_assert_failure©	r3   r-  rð   rç   r„  rÛ   rÝ   rÞ   rß   r8   r8   r9   Údeferred_assert_elementJ-  s.    



$
z BaseCase.deferred_assert_elementc           	      C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  jd7  _ttƒ�. |  ¡ }|| j	kr\d}n|| _	W d  ƒ n1 sv0    Y  | j
rÆ|  ¡ rÆ|  d¡dkrÆ|  d¡}|  ¡ }d|||g}| j |¡ z| j|||d� W d	S  t� yþ   | j|d
� Y dS 0 dS )aÔ  A non-terminating assertion for an element present in the page html.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   r…  NrB  rC  r    rì  rI  Tr†  F)r³   r   r(  r   r  ri   r   r¿   r„  r[   rÇ   rF  rG  rÈ   rÉ   rF   r�   rg  r‡  rˆ  r8   r8   r9   Údeferred_assert_element_presentm-  s.    



$
z(BaseCase.deferred_assert_element_presentc                 C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  jd7  _ttƒ�. |  ¡ }|| j	kr\d}n|| _	W d  ƒ n1 sv0    Y  | j
rÎ|  ¡ rÎ|  d¡dkrÎ|  d¡}|  ¡ }||g}	d|	||g}
| j |
¡ z| j||||d� W d	S  t�y   | j|d
� Y dS 0 dS )aÏ  A non-terminating assertion for text from an element on a page.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   r…  NrB  rC  r    rí  rI  Tr†  F)r³   r   r(  r   r  ri   r   r¿   r„  r[   rÇ   rF  rG  rÈ   rÉ   rF   r�   r  r‡  ©r3   r]  r-  rð   rç   r„  rÛ   rÝ   rÞ   r0  rß   r8   r8   r9   Údeferred_assert_text�-  s0    



$
zBaseCase.deferred_assert_textc                 C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  jd7  _ttƒ�. |  ¡ }|| j	kr\d}n|| _	W d  ƒ n1 sv0    Y  | j
rÎ|  ¡ rÎ|  d¡dkrÎ|  d¡}|  ¡ }||g}	d|	||g}
| j |
¡ z| j||||d� W d	S  t�y   | j|d
� Y dS 0 dS )aË  A non-terminating assertion for exact text from an element.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   r…  NrB  rC  r    rî  rI  Tr†  F)r³   r   r(  r   r  ri   r   r¿   r„  r[   rÇ   rF  rG  rÈ   rÉ   rF   r�   r  r‡  r‹  r8   r8   r9   Údeferred_assert_exact_text´-  s4    



$
ÿz#BaseCase.deferred_assert_exact_textc           	      C   s  |   ¡  |stj}| jr,|tjkr,|  |¡}|  jd7  _ttƒ�. |  ¡ }|| j	kr\d}n|| _	W d  ƒ n1 sv0    Y  | j
rÆ|  ¡ rÆ|  d¡dkrÆ|  d¡}|  ¡ }d|||g}| j |¡ z| j|||d� W d	S  t� yþ   | j|d
� Y dS 0 dS )aÇ  A non-terminating assertion for non-empty element text.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   r…  NrB  rC  r    rï  rI  Tr†  F)r³   r   r(  r   r  ri   r   r¿   r„  r[   rÇ   rF  rG  rÈ   rÉ   rF   r�   r   r‡  rˆ  r8   r8   r9   Údeferred_assert_non_empty_textÚ-  s2    


$
ÿz'BaseCase.deferred_assert_non_empty_textc                 C   sV   |   ¡  |  jd7  _z| j|||||d� W dS  tyP   | j|d� Y dS 0 dS )aÊ  A non-terminating assertion for the check_window() method.
        Failures will be saved until the process_deferred_asserts()
        method is called from inside a test, likely at the end of it.
        If "fs" is set to True, a failure screenshot is saved to the
        "latest_logs/" folder for that assertion failure. Otherwise,
        only the last page screenshot is taken for all failures when
        calling the process_deferred_asserts() method.r�   )r”   rW  r}  r~  r  Tr†  FN)r³   ri   r€  r¿   r‡  ©r3   r”   rW  r}  r~  r  r„  r8   r8   r9   Údeferred_check_window.  s    ûzBaseCase.deferred_check_windowc                 C   s–   | j r0|  d¡}|  ¡ }dd||g}| j |¡ | jr’d}|d7 }|d|  ¡  7 }| j}g | _|D ]}|d| 7 }qb|r‚t|ƒ nt| 	dd¡ƒ‚d	S )
a•  To be used with any test that uses deferred_asserts, which are
        non-terminating verifications that only raise exceptions
        after this method is called.
        This is useful for pages with multiple elements to be checked when
        you want to find as many bugs as possible in a single test run
        before having all the exceptions get raised simultaneously.
        Might be more useful if this method is called after processing all
        the deferred asserts on a single html page so that the failure
        screenshot matches the location of the deferred asserts.
        If "print_only" is set to True, the exception won't get raised.r    rð  rd  z$
***** DEFERRED ASSERTION FAILURES:
z
TEST: %s

z%s
z\nrN  N)
rÇ   rÈ   rÉ   rF   r�   rj   rÍ  rµ  r¿   ri  )r3   Ú
print_onlyrÝ   rÞ   rß   Zexception_outputZall_failing_checksÚtbr8   r8   r9   Úprocess_deferred_asserts".  s     

z!BaseCase.process_deferred_assertsc                 C   s   | j ||||d�S )z&Same as self.deferred_assert_element()©r-  rð   rç   r„  )r‰  ©r3   r-  rð   rç   r„  r8   r8   r9   Údelayed_assert_elementC.  s    ÿzBaseCase.delayed_assert_elementc                 C   s   | j ||||d�S )z.Same as self.deferred_assert_element_present()r”  )rŠ  r•  r8   r8   r9   Údelayed_assert_element_presentK.  s    ÿz'BaseCase.delayed_assert_element_presentc                 C   s   | j |||||d�S )z#Same as self.deferred_assert_text()©r]  r-  rð   rç   r„  )rŒ  ©r3   r]  r-  rð   rç   r„  r8   r8   r9   Údelayed_assert_textS.  s    
ÿzBaseCase.delayed_assert_textc                 C   s   | j |||||d�S )z)Same as self.deferred_assert_exact_text()r˜  )r�  r™  r8   r8   r9   Údelayed_assert_exact_text[.  s    
ÿz"BaseCase.delayed_assert_exact_textc                 C   s   | j ||||d�S )z-Same as self.deferred_assert_non_empty_text()r”  )rŽ  r•  r8   r8   r9   Údelayed_assert_non_empty_textc.  s    ÿz&BaseCase.delayed_assert_non_empty_textc                 C   s   | j ||||||d�S )z$Same as self.deferred_check_window())r”   rW  r}  r~  r  r„  )r�  r�  r8   r8   r9   Údelayed_check_windowo.  s    
úzBaseCase.delayed_check_windowc                 C   s   | j |d� dS )z'Same as self.process_deferred_asserts()©r‘  N)r“  )r3   r‘  r8   r8   r9   Úprocess_delayed_asserts‚.  s    z BaseCase.process_delayed_assertsc                 C   sŠ  |sd}|r|dkrd}g d¢}|  ¡ }||vr@td||f ƒ‚|rL|dkrPd}g d¢}|  ¡ }||vrxtd||f ƒ‚d}|dkrŽtjj}nÄ|d	kr tjj}n²|d
kr²tjj}n |dkrÄtjj}nŽ|dkrÖtjj}n||dkrètjj	}nj|dkrútjj
}nX|dk�rtjj}nD|dk�r"tjj}n0|dk�r6tjj}n|dk�rJtjj}ntjj}dtjj|f }g | j|< | j|  |¡ || j|< dS )a·  Creates a Reveal-JS presentation that you can add slides to.
        @Params
        name - If creating multiple presentations at the same time,
               use this to specify the name of the current presentation.
        theme - Set a theme with a unique style for the presentation.
                Valid themes: "serif" (default), "sky", "white", "black",
                              "simple", "league", "moon", "night",
                              "beige", "blood", and "solarized".
        transition - Set a transition between slides.
                     Valid transitions: "none" (default), "slide", "fade",
                                        "zoom", "convex", and "concave".rò  Úserif)r   ÚwhiteÚblackÚbeigeÚsimpleÚskyÚleagueÚmoonÚnightÚbloodÚ	solarizedz&Theme {%s} not found! Valid themes: %srŠ  ©rŠ  ÚslideÚfadeZzoomZconvexZconcaveú0Transition {%s} not found! Valid transitions: %sNr¥  r¡  r¢  r¤  r¦  r§  r¨  r£  r©  rª  a	  <html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html">
<meta name="viewport" content="shrink-to-fit=no">
<link rel="stylesheet" href="%s">
<link rel="stylesheet" href="%s">
<style>
pre{background-color:#fbe8d4;border-radius:8px;}
div[flex_div]{height:68vh;margin:0;align-items:center;justify-content:center;}
img[rounded]{border-radius:16px;max-width:64%%;}
</style>
</head>

<body>
<!-- Generated by SeleniumBase - https://seleniumbase.io -->
<div class="reveal">
<div class="slides">
)r  r¿   r!   ÚRevealZSERIF_MIN_CSSZSKY_MIN_CSSZWHITE_MIN_CSSZBLACK_MIN_CSSZSIMPLE_MIN_CSSZLEAGUE_MIN_CSSZMOON_MIN_CSSZNIGHT_MIN_CSSZBEIGE_MIN_CSSZBLOOD_MIN_CSSZSOLARIZED_MIN_CSSZMIN_CSSrt   r�   ru   )r3   r”   ró  Ú
transitionÚvalid_themesÚvalid_transitionsZreveal_theme_cssZnew_presentationr8   r8   r9   Úcreate_presentationˆ.  sj    ÿÿÿÿ















îÿ
zBaseCase.create_presentationc	                 C   s"  |sd}|| j vr| j|d� |s&d}|s.d}|s6d}|sF| j| }n|dkrRd}g d¢}	| ¡ }||	vrztd||	f ƒ‚d}
| d¡rŒd}
d	||
|f }|rª|d
| 7 }|rÂ|d7 }|d| 7 }|rÒ|d| 7 }d}
| d¡räd}
|rø|d|
|f 7 }|d| 7 }|d7 }d|v�r2d|v�r2| j |  |¡ nìd}tdƒD ]È}d| |v �rôd| |v �rôd}|}| d| d¡}| d| d¡}tdƒD ]R}||k�r �qŽd| |v�r¾|dk�r¾ �qâ| d| d¡}| d| d¡}�qŽ| j |  |¡ n|dk�r> �q�q>|�s| j |  |¡ dS )aÌ  Allows the user to add slides to a presentation.
        @Params
        content - The HTML content to display on the presentation slide.
        image - Attach an image (from a URL link) to the slide.
        code - Attach code of any programming language to the slide.
               Language-detection will be used to add syntax formatting.
        iframe - Attach an iframe (from a URL link) to the slide.
        content2 - HTML content to display after adding an image or code.
        notes - Additional notes to include with the slide.
                ONLY SEEN if show_notes is set for the presentation.
        transition - Set a transition between slides. (overrides previous)
                     Valid transitions: "none" (default), "slide", "fade",
                                        "zoom", "convex", and "concave".
        name - If creating multiple presentations at the same time,
               use this to select the presentation to add slides to.rò  rr  rd  rŠ  r«  r®  r^  rN  z#
<section data-transition="%s">%s%sz-
<div flex_div><img rounded src="%s" /></div>z
<div></div>z#
<pre class="prettyprint">
%s</pre>z_
<div></div>
<iframe src="%s" style="width:92%%;height:550px;" title="iframe content"></iframe>z%s%sz 
<aside class="notes">%s</aside>z
</section>
z<mk-0>z<mk-1>Fé    z<mk-%s>z</mk-%s>Tz<mark>z</mark>r¾  N)	rt   r³  ru   r  r¿   rÆ   r�   r’  ri  )r3   rï  rú  Úcoder.  Zcontent2Únotesr°  r”   r²  Úadd_linerb  ZreplacementsÚnumZnew_htmlZnum2r8   r8   r9   Ú	add_slideð.  sŠ    
ÿÿ
ýþÿ



zBaseCase.add_slidec                 C   sÄ  |sd}|sd}|| j vr&td| ƒ‚| d¡s8tdƒ‚|s@d}|dkrX| jrXt| jƒ}t|ttfƒsntdƒ‚|dk r~tdƒ‚t|ƒd	 }d
}|r–d}d}| j | D ]}||7 }q¤|dtjj	tj
j||f 7 }dtjjtjjtjjtjjf }	| |	¡dk�rd}
| |	|
¡}| |
|	d¡}tjj}| d¡�r<|dd… }tj |¡�s~ttƒ� t |¡ W d  ƒ n1 �st0    Y  tj ||¡}t|ddd�}| |¡ | ¡  | j�rÀtd| ƒ |S )ao  Saves a Reveal-JS Presentation to a file for later use.
        @Params
        name - If creating multiple presentations at the same time,
               use this to select the one you wish to use.
        filename - The name of the HTML file that you wish to
                   save the presentation to. (filename must end in ".html")
        show_notes - When set to True, the Notes feature becomes enabled,
                     which allows presenters to see notes next to slides.
        interval - The delay time between autoplaying slides. (in seconds)
                   If set to 0 (default), autoplay is disabled.rò  úmy_presentation.htmlú!Presentation {%s} does not exist!ru  ú&Presentation file must end in ".html"!r   ú)Expecting a numeric value for "interval"!ú+The "interval" cannot be a negative number!r:   ÚfalseÚtruerd  zÊ
</div>
</div>
<script src="%s"></script>
<script src="%s"></script>
<script>Reveal.initialize({showNotes: %s, slideNumber: true, progress: true, hash: false, autoSlide: %s,});</script>
</body>
</html>
ú©
            <script src="%s"></script>
            <script src="%s"></script>
            <script src="%s"></script>
            <script src="%s"></script>
            r�   z&<!-- HighCharts Libraries Imported -->rÏ  Nrû   rb  rc  rd  z
>>> [%s] was saved!
) rt   r¿   rZ  Úintervalr  r˜  rO   r!   r¯  rÙ   Z
PrettifyJSZRUN_PRETTIFY_JSÚ
HighChartsÚHC_JSÚEXPORTING_JSÚEXPORT_DATA_JSÚACCESSIBILITY_JSrh  ri  ÚPresentationsr$  ry  rz  rl  r   rm  r2  r¶   rn  ro  rv   rµ  )r3   r”   r(  Ú
show_notesrÂ  Zinterval_msZshow_notes_strrm  r¬  Ú
chart_libsZchart_libs_commentZsaved_presentations_folderr  r:  r8   r8   r9   Úsave_presentation[/  sp    



üöÿüû
*
zBaseCase.save_presentationc                 C   sN  | j s| js| jrdS |sd}|s&d}|| jvr<td| ƒ‚| d¡sNtdƒ‚|sVd}|dkrn| jrnt| jƒ}t|t	tfƒs„tdƒ‚|dk r”td	ƒ‚d
}| j|  
|¡ | j||||d�}| j|  ¡  |  |¡ tjj}ttƒ�V t| jjƒdk�r*||  ¡ v �r*t d¡ |  d¡�r�q*t d¡ qäW d  ƒ n1 �s@0    Y  dS )aj  Begin a Reveal-JS Presentation in the web browser.
        @Params
        name - If creating multiple presentations at the same time,
               use this to select the one you wish to use.
        filename - The name of the HTML file that you wish to
                   save the presentation to. (filename must end in ".html")
        show_notes - When set to True, the Notes feature becomes enabled,
                     which allows presenters to see notes next to slides.
        interval - The delay time between autoplaying slides. (in seconds)
                   If set to 0 (default), autoplay is disabled.Nrò  rº  r»  ru  r¼  r   r½  r¾  zS
<section data-transition="none">
<p class="End_Presentation_Now"> </p>
</section>
)r”   r(  rÉ  rÂ  rë   z&section.present p.End_Presentation_Now)r  rò  r(  rt   r¿   rZ  rÂ  r  r˜  rO   r�   rË  rÄ  r‚  r!   rÈ  r$  r   r  r=   r  r„  rD   r¾   r£  )r3   r”   r(  rÉ  rÂ  Z	end_slider  Zpresentation_folderr8   r8   r9   Úbegin_presentation±/  sR    


ÿü

ÿ
þ
ÿzBaseCase.begin_presentationc	           
      C   s4   |sd}|sd}d}	| j ||||	|||||d�	 dS )aÌ  Creates a JavaScript pie chart using "HighCharts".
        @Params
        chart_name - If creating multiple charts,
                     use this to select which one.
        title - The title displayed for the chart.
        subtitle - The subtitle displayed for the chart.
        data_name - The series name. Useful for multi-series charts.
                    If no data_name, will default to using "Series 1".
        unit - The description label given to the chart's y-axis values.
        libs - The option to include Chart libraries (JS and CSS files).
               Should be set to True (default) for the first time creating
               a chart on a web page. If creating multiple charts on the
               same web page, you won't need to re-import the libraries
               when creating additional charts.
        labels - If True, displays labels on the chart for data points.
        legend - If True, displays the data point legend on the chart.rò  rd  Úpie©	Ú
chart_namer‰  Úsubtitler­  Ú	data_nameÚunitÚlibsÚlabelsÚlegendN©Ú_BaseCase__create_highchart©
r3   rÏ  r‰  rÐ  rÑ  rÒ  rÓ  rÔ  rÕ  r­  r8   r8   r9   Úcreate_pie_chartì/  s     ÷zBaseCase.create_pie_chartc	           
      C   s4   |sd}|sd}d}	| j ||||	|||||d�	 dS )aÌ  Creates a JavaScript bar chart using "HighCharts".
        @Params
        chart_name - If creating multiple charts,
                     use this to select which one.
        title - The title displayed for the chart.
        subtitle - The subtitle displayed for the chart.
        data_name - The series name. Useful for multi-series charts.
                    If no data_name, will default to using "Series 1".
        unit - The description label given to the chart's y-axis values.
        libs - The option to include Chart libraries (JS and CSS files).
               Should be set to True (default) for the first time creating
               a chart on a web page. If creating multiple charts on the
               same web page, you won't need to re-import the libraries
               when creating additional charts.
        labels - If True, displays labels on the chart for data points.
        legend - If True, displays the data point legend on the chart.rò  rd  ÚbarrÎ  NrÖ  rØ  r8   r8   r9   Úcreate_bar_chart0  s     ÷zBaseCase.create_bar_chartc	           
      C   s4   |sd}|sd}d}	| j ||||	|||||d�	 dS )aÏ  Creates a JavaScript column chart using "HighCharts".
        @Params
        chart_name - If creating multiple charts,
                     use this to select which one.
        title - The title displayed for the chart.
        subtitle - The subtitle displayed for the chart.
        data_name - The series name. Useful for multi-series charts.
                    If no data_name, will default to using "Series 1".
        unit - The description label given to the chart's y-axis values.
        libs - The option to include Chart libraries (JS and CSS files).
               Should be set to True (default) for the first time creating
               a chart on a web page. If creating multiple charts on the
               same web page, you won't need to re-import the libraries
               when creating additional charts.
        labels - If True, displays labels on the chart for data points.
        legend - If True, displays the data point legend on the chart.rò  rd  ÚcolumnrÎ  NrÖ  rØ  r8   r8   r9   Úcreate_column_chartD0  s     ÷zBaseCase.create_column_chartc
                 C   s6   |sd}|sd}d}
| j ||||
||||||	d�
 dS )a  Creates a JavaScript line chart using "HighCharts".
        @Params
        chart_name - If creating multiple charts,
                     use this to select which one.
        title - The title displayed for the chart.
        subtitle - The subtitle displayed for the chart.
        data_name - The series name. Useful for multi-series charts.
                    If no data_name, will default to using "Series 1".
        unit - The description label given to the chart's y-axis values.
        zero - If True, the y-axis always starts at 0. (Default: False).
        libs - The option to include Chart libraries (JS and CSS files).
               Should be set to True (default) for the first time creating
               a chart on a web page. If creating multiple charts on the
               same web page, you won't need to re-import the libraries
               when creating additional charts.
        labels - If True, displays labels on the chart for data points.
        legend - If True, displays the data point legend on the chart.rò  rd  rm  ©
rÏ  r‰  rÐ  r­  rÑ  rÒ  ÚzerorÓ  rÔ  rÕ  NrÖ  ©r3   rÏ  r‰  rÐ  rÑ  rÒ  rß  rÓ  rÔ  rÕ  r­  r8   r8   r9   Úcreate_line_chartp0  s"    özBaseCase.create_line_chartc
                 C   s6   |sd}|sd}d}
| j ||||
||||||	d�
 dS )a  Creates a JavaScript area chart using "HighCharts".
        @Params
        chart_name - If creating multiple charts,
                     use this to select which one.
        title - The title displayed for the chart.
        subtitle - The subtitle displayed for the chart.
        data_name - The series name. Useful for multi-series charts.
                    If no data_name, will default to using "Series 1".
        unit - The description label given to the chart's y-axis values.
        zero - If True, the y-axis always starts at 0. (Default: False).
        libs - The option to include Chart libraries (JS and CSS files).
               Should be set to True (default) for the first time creating
               a chart on a web page. If creating multiple charts on the
               same web page, you won't need to re-import the libraries
               when creating additional charts.
        labels - If True, displays labels on the chart for data points.
        legend - If True, displays the data point legend on the chart.rò  rd  ZarearÞ  NrÖ  rà  r8   r8   r9   Úcreate_area_chartŸ0  s"    özBaseCase.create_area_chartc                 C   s¤  |sd}|sd}|sd}|s d}|s(d}|s0d}|	r:d}	nd}	|
rHd}
nd}
|  dd	¡}|  dd	¡}|  dd	¡}|  jd
7  _dtjjtjjtjjtjjf }|s¦d}d}|s²d}d}d| j|f }d}|rÐd}d| j|||||f }d}|dkröd}d| }d|	|
f }|dk�r d|	|
f }|| | }d}|dk�r>d}d||f }|| | | | }t 	|¡}g | j
|< g | j|< | j
|  |¡ d| j|< d
| j|< dS )z:Creates a JavaScript chart using the "HighCharts" library.rò  rd  rÍ  zSeries 1rZ  rÀ  r¿  ú'ú\'r�   rÁ  aØ  
            <style>
            .highcharts-figure, .highcharts-data-table table {
                min-width: 320px;
                max-width: 660px;
                margin: 1em auto;
            }
            .highcharts-data-table table {
                font-family: Verdana, sans-serif;
                border-collapse: collapse;
                border: 1px solid #EBEBEB;
                margin: 10px auto;
                text-align: center;
                width: 100%;
                max-width: 500px;
            }
            .highcharts-data-table caption {
                padding: 1em 0;
                font-size: 1.2em;
                color: #555;
            }
            .highcharts-data-table th {
                font-weight: 600;
                padding: 0.5em;
            }
            .highcharts-data-table td, .highcharts-data-table th,
            .highcharts-data-table caption {
                padding: 0.5em;
            }
            .highcharts-data-table thead tr,
            .highcharts-data-table tr:nth-child(even) {
                background: #f8f8f8;
            }
            .highcharts-data-table tr:hover {
                background: #f1f7ff;
            }
            </style>
            zÂ
            <figure class="highcharts-figure">
                <div id="chartcontainer_num_%s"></div>
                <p class="highcharts-description">%s</p>
            </figure>
            zmin: 0,a¾  
            <script>
            // Build the chart
            Highcharts.chart('chartcontainer_num_%s', {
            credits: {
                enabled: false
            },
            title: {
                text: '%s'
            },
            subtitle: {
                text: '%s'
            },
            xAxis: { },
            yAxis: {
                %s
                title: {
                    text: '%s',
                    style: {
                        fontSize: '14px'
                    }
                },
                labels: {
                    useHTML: true,
                    style: {
                        fontSize: '14px'
                    }
                }
            },
            chart: {
                renderTo: 'statusChart',
                plotBackgroundColor: null,
                plotBorderWidth: null,
                plotShadow: false,
                type: '%s'
            },
            z4<b>{point.y}</b><br /><b>{point.percentage:.1f}%</b>z<b>{point.y}</b>a÷  
            tooltip: {
                enabled: true,
                useHTML: true,
                style: {
                    padding: '6px',
                    fontSize: '14px'
                },
                backgroundColor: {
                    linearGradient: {
                        x1: 0,
                        y1: 0,
                        x2: 0,
                        y2: 1
                    },
                    stops: [
                        [0, 'rgba(255, 255, 255, 0.78)'],
                        [0.5, 'rgba(235, 235, 235, 0.76)'],
                        [1, 'rgba(244, 252, 255, 0.74)']
                    ]
                },
                hideDelay: 40,
                pointFormat: '%s'
            },
            a9  
            accessibility: {
                point: {
                    valueSuffix: '%%'
                }
            },
            plotOptions: {
                series: {
                    states: {
                        inactive: {
                            opacity: 0.85
                        }
                    }
                },
                pie: {
                    size: "95%%",
                    allowPointSelect: true,
                    animation: false,
                    cursor: 'pointer',
                    dataLabels: {
                        enabled: %s,
                        formatter: function() {
                          if (this.y > 0) {
                            return this.point.name + ': ' + this.point.y
                          }
                        }
                    },
                    states: {
                        hover: {
                            enabled: true
                        }
                    },
                    showInLegend: %s
                }
            },
            a‡  
                allowPointSelect: true,
                cursor: 'pointer',
                legend: {
                    layout: 'vertical',
                    align: 'right',
                    verticalAlign: 'middle'
                },
                states: {
                    hover: {
                        enabled: true
                    }
                },
                plotOptions: {
                    series: {
                        dataLabels: {
                            enabled: %s
                        },
                        showInLegend: %s,
                        animation: false,
                        shadow: false,
                        lineWidth: 3,
                        fillOpacity: 0.5,
                        marker: {
                            enabled: true
                        }
                    }
                },
                zn
            series: [{
            name: '%s',
            colorByPoint: %s,
            data: [
            TN)ri  r‚   r!   rÃ  rÄ  rÅ  rÆ  rÇ  ÚtextwrapÚdedentr�   rƒ   r�   r…   r†   )r3   rÏ  r‰  rÐ  r­  rÑ  rÒ  rß  rÓ  rÔ  rÕ  rÊ  Z	chart_cssZchart_descriptionZchart_figureZmin_zeroZchart_init_1Zpoint_formatZchart_init_2Zchart_init_3Z
chart_initZcolor_by_pointÚseriesZ	new_chartr8   r8   r9   Z__create_highchartÎ0  s®    üû&þû	%úÜ.ÿçÿ$þÝ'
þä 
þû	



zBaseCase.__create_highchartc                 C   sR   |sd}| j |  d7  < |s,d| j |  }d| }| j|  |¡ d| j|< dS )a   Add a new data series to an existing chart.
        This allows charts to have multiple data sets.
        @Params
        data_name - Set the series name. Useful for multi-series charts.
        chart_name - If creating multiple charts,
                     use this to select which one.rò  r�   z	Series %sz…
            ]
            },
            {
            name: '%s',
            colorByPoint: false,
            data: [
            FN)r†   r�   r�   r…   )r3   rÑ  rÏ  rç  r8   r8   r9   Úadd_series_to_chartâ1  s    øÿzBaseCase.add_series_to_chartc                 C   s¶   |sd}|| j vr| j|d� |s&d}t|ttfƒs<tdƒ‚|sFd}n| dd¡}| dd¡}|rrd|||f }nd	||f }t |¡}| j |  	|¡ | j
| r²| j|  	|¡ d
S )a­  Add a data point to a SeleniumBase-generated chart.
        @Params
        label - The label name for the data point.
        value - The numeric value of the data point.
        color - The HTML color of the data point.
                Can be an RGB color. Eg: "#55ACDC".
                Can also be a named color. Eg: "Teal".
        chart_name - If creating multiple charts,
                     use this to select which one.rò  )rÏ  r   z&Expecting a numeric value for "value"!rd  rã  rä  z…
                {
                name: '%s',
                y: %s,
                color: '%s'
                },
                zi
                {
                name: '%s',
                y: %s,
                },
                N)r�   rÙ  r˜  rO   r  r¿   ri  rå  ræ  r�   r…   rƒ   )r3   ÚlabelrS  ÚcolorrÏ  Z
data_pointr8   r8   r9   Úadd_data_pointü1  s8    

ýúþû	

zBaseCase.add_data_pointc                 C   sŠ  |sd}|sd}|| j vr&td| ƒ‚| d¡s8tdƒ‚d}|d7 }|d7 }| j | D ]}||7 }qV|d	7 }d
}|d7 }|d7 }|d7 }|d7 }|d7 }|d7 }|d7 }| j| D ]}|d| 7 }q²|d7 }| d|¡}|sætjj}n|}| d¡�r|dd… }tj	 
|¡�sDttƒ� t |¡ W d  ƒ n1 �s:0    Y  tj	 ||¡}	t|	ddd�}
|
 |¡ |
 ¡  | j�r†td|	 ƒ |	S )aÐ  Saves a SeleniumBase-generated chart to a file for later use.
        @Params
        chart_name - If creating multiple charts at the same time,
                     use this to select the one you wish to use.
        filename - The name of the HTML file that you wish to
                   save the chart to. (filename must end in ".html")
        folder - The name of the folder where you wish to
                 save the HTML file. (Default: "./saved_charts/")rò  úmy_chart.htmlúChart {%s} does not exist!ru  úChart file must end in ".html"!z<meta charset="utf-8">
z5<meta http-equiv="Content-Type" content="text/html">
z2<meta name="viewport" content="shrink-to-fit=no">
úT
            ]
                }]
            });
            </script>
            ú	xAxis: {
ú    labels: {
ú        useHTML: true,
ú        style: {
ú            fontSize: '14px',
ú        },
ú    },
úcategories: [ú'%s',ú], crosshair: false},úxAxis: { },rÏ  Nrû   rb  rc  rd  z
>>> [%s] was saved!)r�   r¿   rZ  rƒ   ri  r!   ÚChartsr$  ry  rz  rl  r   rm  r2  r¶   rn  ro  rv   rµ  )r3   rÏ  r(  r9  rm  Úchart_data_pointÚaxisré  Zsaved_charts_folderr  r:  r8   r8   r9   Ú
save_chart/2  sR    	




*
zBaseCase.save_chartc           
      C   sÊ  | j s| js| jrd}|sd}|s&d}|s.d}|dkrF| jrFt| jƒ}t|ttfƒs\tdƒ‚|dk rltdƒ‚|| jvr‚td| ƒ‚| 	d¡s”td	ƒ‚| j
||d
�}|  |¡ tjj}|dk�rttƒ�@ tdƒ t| jjƒdkrø||  ¡ v røt d¡ qÐW d  ƒ n1 �s0    Y  n¬ttƒ�’ t ¡ d }||d  }tt|d ƒƒD ]X}t ¡ d }	|	|k�rl �q¦t| jjƒdk�r„ �q¦||  ¡ v�r˜ �q¦t d¡ �qLW d  ƒ n1 �s¼0    Y  dS )aå  Displays a SeleniumBase-generated chart in the browser window.
        @Params
        chart_name - If creating multiple charts at the same time,
                     use this to select the one you wish to use.
        filename - The name of the HTML file that you wish to
                   save the chart to. (filename must end in ".html")
        interval - The delay time for auto-advancing charts. (in seconds)
                   If set to 0 (default), auto-advancing is disabled.r�   rò  rì  r   r½  r¾  rí  ru  rî  )rÏ  r(  z-
*** Close the browser window to continue ***rë   Nr:   r  r¯   )r  rò  r(  rÂ  r  r˜  rO   r¿   r�   rZ  rþ  r‚  r!   rû  r$  r   rµ  r  r=   r  r„  rD   r¾   r’  )
r3   rÏ  r(  rÂ  r  Zchart_folderr”  r•  r  r–  r8   r8   r9   Údisplay_charth2  sP    	






ÿ.

zBaseCase.display_chartc                 C   sÒ   |sd}|| j vrtd| ƒ‚d}| j | D ]}||7 }q,|d7 }d}|d7 }|d7 }|d7 }|d	7 }|d
7 }|d7 }|d7 }| j| D ]}|d| 7 }qˆ|d7 }| d|¡}|  jd7  _| dd| j ¡}|S )zÊExtracts the HTML from a SeleniumBase-generated chart.
        @Params
        chart_name - If creating multiple charts at the same time,
                     use this to select the one you wish to use.rò  rí  rd  rï  rð  rñ  rò  ró  rô  rõ  rö  r÷  rø  rù  rú  r�   Zchartcontainer_num_zchartcontainer_%s_)r�   r¿   rƒ   ri  r„   )r3   rÏ  rm  rü  rý  ré  r8   r8   r9   Úextract_chartœ2  s2    


ÿzBaseCase.extract_chartc                 C   sŒ  |sd}|�r~|  ¡ dkr(|  |¡ �qˆ|  ¡ dkrB|  |¡ �qˆ|  ¡ dkr\|  |¡ �qˆ|  ¡ dkrv|  |¡ �qˆ|  ¡ dkrŽ|  |¡ nî|  ¡ dkr¦|  |¡ nÖ|  ¡ dkrÂ| j|d	d
� nº|  ¡ d	krÞ| j|d	d
� nž|  ¡ dkrú| j|d	d
� n‚|  ¡ dk�r| j|dd
� nd|  ¡ dk�r6| j|dd
� nF|  ¡ dk�rT| j|dd
� n(|  ¡ dk�rr| j|dd
� n
|  |¡ n
|  |¡ dS )a  Creates a guided tour for any website.
        The default theme is the IntroJS Library.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        theme - Sets the default theme for the website tour. Available themes:
                "Bootstrap", "DriverJS", "Hopscotch", "IntroJS", "Shepherd".
                The "Shepherd" library includes variations: "light"/"arrows",
                "dark", "default", "square", and "square-dark".rò  Ú	bootstrapZ	hopscotchZintroÚintrojsr=   ZdriverjsZshepherdÚlight)ró  ÚarrowsrÒ  Úsquareúsquare-darkN)r  Úcreate_bootstrap_tourÚcreate_hopscotch_tourÚcreate_introjs_tourÚcreate_driverjs_tourÚcreate_shepherd_tour)r3   r”   ró  r8   r8   r9   Úcreate_tourÂ2  s>    
zBaseCase.create_tourc                 C   s    d}|rr|  ¡ dkrd}nX|  ¡ dkr,d}nF|  ¡ dkr>d}n4|  ¡ dkrPd}n"|  ¡ dkrbd	}n|  ¡ d
krrd}|szd}d| }g | j|< | j|  |¡ dS )a~  Creates a Shepherd JS website tour.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        theme - Sets the default theme for the tour.
                Choose from "light"/"arrows", "dark", "default", "square",
                and "square-dark". ("light" is used if None is selected.)úshepherd-theme-arrowsrò  úshepherd-theme-defaultrÒ  úshepherd-theme-darkr  r  r  úshepherd-theme-squarer  úshepherd-theme-square-darka½  
            // Shepherd Tour
            var tour = new Shepherd.Tour({
                defaults: {
                    classes: '%s',
                    scrollTo: true
                }
            });
            var allButtons = {
                skip: {
                    text: "Skip",
                    action: tour.cancel,
                    classes: 'shepherd-button-secondary tour-button-left'
                },
                back: {
                    text: "Back",
                    action: tour.back,
                    classes: 'shepherd-button-secondary'
                },
                next: {
                    text: "Next",
                    action: tour.next,
                    classes: 'shepherd-button-primary tour-button-right'
                },
            };
            var firstStepButtons = [allButtons.skip, allButtons.next];
            var midTourButtons = [allButtons.back, allButtons.next];
            N)r  r‡   r�   )r3   r”   ró  Úshepherd_themeÚnew_tourr8   r8   r9   r  î2  s,    äÿ
zBaseCase.create_shepherd_tourc                 C   s*   |sd}d}g | j |< | j |  |¡ dS )z¸Creates a Bootstrap tour for a website.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.rò  aŽ  
            // Bootstrap Tour
            var tour = new Tour({
            container: 'body',
            animation: true,
            keyboard: true,
            orphan: true,
            smartPlacement: true,
            autoscroll: true,
            backdrop: true,
            backdropContainer: 'body',
            backdropPadding: 3,
            });
            tour.addSteps([
            N©r‡   r�   ©r3   r”   r  r8   r8   r9   r  (3  s
    
zBaseCase.create_bootstrap_tourc                 C   s*   |sd}d}g | j |< | j |  |¡ dS )z·Creates a DriverJS tour for a website.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.rò  aÚ  
            // DriverJS Tour
            var tour = new Driver({
                opacity: 0.24,  // Background opacity (0: no popover / overlay)
                padding: 6,    // Distance of element from around the edges
                allowClose: false, // Whether clicking on overlay should close
                overlayClickNext: false, // Move to next step on overlay click
                doneBtnText: 'Done', // Text that appears on the Done button
                closeBtnText: 'Close', // Text appearing on the Close button
                nextBtnText: 'Next', // Text that appears on the Next button
                prevBtnText: 'Previous', // Text appearing on Previous button
                showButtons: true, // This shows control buttons in the footer
                keyboardControl: true, // (escape to close, arrow keys to move)
                animate: true,   // Animate while changing highlighted element
            });
            tour.defineSteps([
            Nr  r  r8   r8   r9   r
  A3  s
    
zBaseCase.create_driverjs_tourc                 C   s*   |sd}d}g | j |< | j |  |¡ dS )z¸Creates a Hopscotch tour for a website.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.rò  z{
            // Hopscotch Tour
            var tour = {
            id: "hopscotch_tour",
            steps: [
            Nr  r  r8   r8   r9   r  \3  s
    
zBaseCase.create_hopscotch_tourc                 C   sR   t tdƒstjjt_t tdƒs(tjjt_|s0d}d}g | j|< | j|  	|¡ dS )z·Creates an IntroJS tour for a website.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.Úintrojs_theme_colorÚintrojs_hover_colorrò  z£
            // IntroJS Tour
            function startIntro(){
            var intro = introJs();
            intro.setOptions({
            steps: [
            N)
rÍ   rD  r!   Ú	TourColorÚtheme_colorr  Úhover_colorr  r‡   r�   r  r8   r8   r9   r	  n3  s    




zBaseCase.create_introjs_tourc                 C   sˆ   t tdƒstjjt_t tdƒs(tjjt_|rLt 	d|¡}|sDt
dƒ‚|t_n
tjjt_|rzt 	d|¡}|srt
dƒ‚|t_n
tjjt_dS )a…  Use this method to set the theme colors for IntroJS tours.
        Args must be hex color values that start with a "#" sign.
        If a color isn't specified, the color will reset to the default.
        The border color of buttons is set to the hover color.
        @Params
        theme_color - The color of buttons.
        hover_color - The color of buttons after hovering over them.r  r  z^#(?:[0-9a-fA-F]{3}){1,2}$z1Expecting a hex value color that starts with "#"!N)rÍ   rD  r!   r  r  r  r  r  r=  Úsearchr¿   )r3   r  r  r  r8   r8   r9   Úset_introjs_colorsƒ3  s(    



ÿ
ÿzBaseCase.set_introjs_colorsc           	      C   s‚  |sd}t  |¡r$t  |¡}d| }t  |¡r<|  |tj¡}|  |¡}|sNd}|| jvrf| j	|dd� |snd}|  |¡}|rˆ|  |¡}nd}|r˜|dvrÀ| j| d }d	|vr¼d
|vr¼d}nd}d| j| d v rê| j
||||||d� n”d
| j| d v �r| j|||||d� njd	| j| d v �r>| j|||||d� n@d| j| d v �rh| j|||||d� n| j||||||d� dS )aq  Allows the user to add tour steps for a website.
        @Params
        message - The message to display.
        selector - The CSS Selector of the Element to attach to.
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        title - Additional header text that appears above the message.
        theme - (Shepherd Tours ONLY) The styling of the tour step.
                Choose from "light"/"arrows", "dark", "default", "square",
                and "square-dark". ("arrows" is used if None is selected.)
        alignment - Choose from "top", "bottom", "left", and "right".
                    ("top" is default, except for Hopscotch and DriverJS).
        duration - (Bootstrap Tours ONLY) The amount of time, in seconds,
                   before automatically advancing to the next tour step.rb  z[name="%s"]rò  r  )r”   ró  rd  )ÚtopÚbottomÚleftÚrightr   Ú	HopscotchÚDriverJSr  r  Ú	Bootstrap)r-  r”   r‰  Ú	alignmentrú  )r-  r”   r‰  r$  ÚIntroJS)r-  r”   r‰  ró  r$  N)r%   Zis_name_selectorZget_name_from_selectorr`  r<  r   rH  r?  r‡   r  Ú"_BaseCase__add_bootstrap_tour_stepÚ!_BaseCase__add_driverjs_tour_stepÚ"_BaseCase__add_hopscotch_tour_stepÚ _BaseCase__add_introjs_tour_stepÚ!_BaseCase__add_shepherd_tour_step)	r3   râ   r-  r”   r‰  ró  r$  rú  Zt_namer8   r8   r9   Úadd_tour_step¢3  s€    





úûûûúzBaseCase.add_tour_stepc                 C   sÌ   |dkrd}nf|dkrd}nX|dkr*d}nJ|dkr8d}n<|dkrFd	}n.|d
krTd}n t  d| j| d ¡ d¡}|}|}	|dkrˆ|	d7 }	d}
t| j| ƒdkr¢d}
d|||	||||
f }| j|  |¡ dS )aÉ  Allows the user to add tour steps for a website.
        @Params
        message - The message to display.
        selector - The CSS Selector of the Element to attach to.
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        title - Additional header text that appears above the message.
        theme - (Shepherd Tours ONLY) The styling of the tour step.
                Choose from "light"/"arrows", "dark", "default", "square",
                and "square-dark". ("arrows" is used if None is selected.)
        alignment - Choose from "top", "bottom", "left", and "right".
                    ("top" is the default alignment).rò  r  rÒ  r  r  r  r  r  r  r  r  z#[\S\s]+classes: '([\S\s]+)',[\S\s]+r   r�   rb  z shepherd-orphanZfirstStepButtonsZmidTourButtonsa  tour.addStep('%s', {
                    title: '%s',
                    classes: '%s',
                    text: '%s',
                    attachTo: {element: '%s', on: '%s'},
                    buttons: %s,
                    advanceOn: '.docs-link click'
                });N)r=  r  r‡   Úgroupr  r�   )r3   râ   r-  r”   r‰  ró  r$  r  Zshepherd_base_themeZshepherd_classesÚbuttonsÚstepr8   r8   r9   Z__add_shepherd_tour_step4  sH    þýùùz!BaseCase.__add_shepherd_tour_stepc           
      C   sr   |dkr|   |¡}d| }nd}|s*d}ntt|ƒd ƒ}d}|dkrJd}d||||||f }	| j|  |	¡ d	S )
a‚  Allows the user to add tour steps for a website.
        @Params
        message - The message to display.
        selector - The CSS Selector of the Element to attach to.
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        title - Additional header text that appears above the message.
        alignment - Choose from "top", "bottom", "left", and "right".
                    ("top" is the default alignment).
        duration - (Bootstrap Tours ONLY) The amount of time, in seconds,
                   before automatically advancing to the next tour step.rb  úelement: '%s',rd  rn  r:   zbackdrop: true,zbackdrop: false,a  {
                %s
                title: '%s',
                content: '%s',
                orphan: true,
                autoscroll: true,
                %s
                placement: '%s',
                smartPlacement: true,
                duration: %s,
                },N)rÛ  rÁ   r  r‡   r�   )
r3   râ   r-  r”   r‰  r$  rú  Úelement_rowZbdr.  r8   r8   r9   Z__add_bootstrap_tour_stepC4  s(    

úöz"BaseCase.__add_bootstrap_tour_stepc                 C   s�   d| d }d}|s"d| }d}nd| }d| }d}|rJ|dksJ|dkrZd}d	}dd
 }d| }	d| }
d|	|||
|f }| j |  |¡ dS )áï  Allows the user to add tour steps for a website.
        @Params
        message - The message to display.
        selector - The CSS Selector of the Element to attach to.
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        title - Additional header text that appears above the message.
        alignment - Choose from "top", "bottom", "left", and "right".
                    ("top" is the default alignment).z"<font size="3" color="#33477B"><b>z</b></font>rd  ztitle: '%s',zposition: '%s',zanimate: true,rb  r¨  zanimate: false,z
mid-centerr/  zdescription: '%s',zÔ{
                %s
                %s
                popover: {
                  className: 'popover-class',
                  %s
                  %s
                  %s
                }
                },Nr  )r3   râ   r-  r”   r‰  r$  Z	title_rowZ	align_rowZani_rowr0  Zdesc_rowr.  r8   r8   r9   Z__add_driverjs_tour_stepw4  s0    
ÿ
û÷z!BaseCase.__add_driverjs_tour_stepc                 C   sH   d}|r|dkrd}d}d}nd}d|||||f }| j |  |¡ dS )aò  Allows the user to add tour steps for a website.
        @Params
        message - The message to display.
        selector - The CSS Selector of the Element to attach to.
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        title - Additional header text that appears above the message.
        alignment - Choose from "top", "bottom", "left", and "right".
                    ("bottom" is the default alignment).Nrb  rf  r  zarrowOffset: '200',rd  zð{
                target: '%s',
                title: '%s',
                content: '%s',
                %s
                showPrevButton: 'true',
                scrollDuration: '550',
                placement: '%s'},
                r  )r3   râ   r-  r”   r‰  r$  Zarrow_offset_rowr.  r8   r8   r9   Z__add_hopscotch_tour_step¦4  s    	ûøz"BaseCase.__add_hopscotch_tour_stepc                 C   sX   |dkrd| }nd}|r*d| d | }d| d }d|||f }| j |  |¡ d	S )
r1  rb  r/  rd  z<center><b>z</b></center><hr>z<font size="3" color="#33477B">z</font>z9{%s
            intro: '%s',
            position: '%s'},Nr  )r3   râ   r-  r”   r‰  r$  r0  r.  r8   r8   r9   Z__add_introjs_tour_stepÊ4  s    
ýþz BaseCase.__add_introjs_tour_stepc                 C   sP  ddl m} | js| js| jr"dS |  ¡  |s2d}|dkrJ| jrJt| jƒ}|sRd}|| jvrht	d| ƒ‚d| j| d v rš|j
| j| j| j| j||d� n²d| j| d v rÌ|j| j| j| j| j||d� n€d	| j| d v rþ|j| j| j| j| j||d� nNd
| j| d v �r2|j| j| j| j| j||d� n|j| j| j| j||d� dS )aM  Plays a tour on the current website.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        interval - The delay time between autoplaying tour steps. (Seconds)
                   If set to 0 (default), the tour is fully manual control.r   ©Útour_helperNrò  zTour {%s} does not exist!r#  ©r”   rÂ  r"  r!  r%  )r  r3  r  rò  r(  rÔ   rÂ  r  r‡   r¿   Zplay_bootstrap_tourr=   r  r/  Zplay_driverjs_tourZplay_hopscotch_tourZplay_introjs_tourZplay_shepherd_tour)r3   r”   rÂ  r3  r8   r8   r9   Ú	play_touræ4  sn    

úúúú	ûzBaseCase.play_tourc                 C   s   | j ||d� dS )zSame as self.play_tour()r4  N)r5  )r3   r”   rÂ  r8   r8   r9   Ú
start_tour'5  s    zBaseCase.start_tourú
my_tour.jsc                 C   s0   ddl m} |s|  ¡ }|j| j|||d� dS )aÝ  Exports a tour as a JS file.
        You can call self.export_tour() anywhere where you would
        normally use self.play_tour() to play a website tour.
        It will include necessary resources as well, such as jQuery.
        You'll be able to copy the tour directly into the Console of
        any web browser to play the tour outside of SeleniumBase runs.
        @Params
        name - If creating multiple tours at the same time,
               use this to select the tour you wish to add steps to.
        filename - The name of the JavaScript file that you wish to
                   save the tour to.
        url - The URL where the tour starts. If not specified, the URL
              of the current page will be used.r   r2  )r”   r(  rÛ   N)r  r3  r„  Úexport_tourr‡   )r3   r”   r(  rÛ   r3  r8   r8   r9   r8  +5  s    
ÿzBaseCase.export_tourc                 C   s(   |   ¡  |  ¡  t | j¡ |  ¡  dS )z9See https://craftpip.github.io/jquery-confirm/ for usage.N)r³   r¼   r#   Úactivate_jquery_confirmr=   rÔ   r‹   r8   r8   r9   r9  C5  s    z BaseCase.activate_jquery_confirmc                 C   s”  | j s$tjj| _tjj| _tjj| _g d¢}| 	¡ |vrLt
d| 	¡ |f ƒ‚| 	¡ tj_|r�g d¢}| 	¡ |vr„t
d| 	¡ |f ƒ‚| 	¡ tj_|�r�t|ttfƒr¬t|ƒ}| ¡ rðt|ƒdkrÊt
dƒ‚n&t|ƒdkrät|ƒd }nt|ƒd	 }| d¡�s| d	¡�st
d
ƒ‚d}| d¡�r,|dd… }| d	¡�rD|dd… }zt|ƒ}W n  t
�yp   t
d| ƒ‚Y n0 |dk�rˆt
d| ƒ‚|tj_dS )a   Sets the default jquery-confirm theme and width (optional).
        Available themes: "bootstrap", "modern", "material", "supervan",
                          "light", "dark", and "seamless".
        Available colors: (This sets the BORDER color, NOT the button color.)
            "blue", "default", "green", "red", "purple", "orange", "dark".
        Width can be set using percent or pixels. Eg: "36.0%", "450px".)r  ZmodernÚmaterialZsupervanr  rÒ  Zseamlessz6%s is not a valid jquery-confirm theme! Select from %s©Úbluerò  ÚgreenÚredÚpurpleZorangerÒ  z=%s is not a valid jquery-confirm border color! Select from %sr   z'Width must be set to a positive number!r{  r€  Úpxz8jqc width must end with %% for percent or px for pixels!Nrû   rú  z%s is not a numeric value!z%s is not a positive number!)rn   r!   ÚJqueryConfirmÚDEFAULT_THEMEro   ÚDEFAULT_COLORrp   ÚDEFAULT_WIDTHrq   r  r¿   r˜  rO   r  rÁ   Ú	isnumericrZ  )r3   ró  rê  r�  r±  Úvalid_colorsrS  r8   r8   r9   Úset_jqc_themeJ5  s\    


	
ÿÿ	
ÿÿ
ÿ
zBaseCase.set_jqc_themec                 C   s.   | j r*| jtj_| jtj_| jtj_d| _ dS )z2Resets the jqc theme settings to factory defaults.FN)	rn   ro   r!   rA  rB  rp   rC  rq   rD  r‹   r8   r8   r9   Úreset_jqc_theme�5  s
    


zBaseCase.reset_jqc_themec                 C   sä  ddl m} |r"t|tƒs"tdƒ‚t|ttfƒs8tdƒ‚t|ƒdk rLtdƒ‚g }|D ]z}t|ttfƒr‚t|ƒdkr‚| |d ¡ qTt|ttfƒr¼t|ƒdkr¼| |d t|d ƒ 	¡ f¡ qT| t|ƒdf¡ qT|}|rø|D ]}t|ttfƒsÜtdƒ‚qÜ| j
�s| j�s| j�r|d	 d S | | j|||¡ t d
¡ d}ttƒ� |  |¡ W d  ƒ n1 �sf0    Y  d}	|	�r¤t d¡ |  d¡}
t|
ƒdk�rt�q¤�qtt d¡ d}z|  d¡}W n t�yÞ   |  d¡}Y n0 |S )a4  
        Pop up a jquery-confirm box and return the text of the button clicked.
        If running in headless mode, the last button text is returned.
        @Params
        message: The message to display in the jquery-confirm dialog.
        buttons: A list of tuples for text and color.
            Example: [("Yes!", "green"), ("No!", "red")]
            Available colors: blue, green, red, orange, purple, default, dark.
            A simple text string also works: "My Button". (Uses default color.)
        options: A list of tuples for options to set.
            Example: [("theme", "bootstrap"), ("width", "450px")]
            Available theme options: bootstrap, modern, material, supervan,
                                     light, dark, and seamless.
            Available colors: (For the BORDER color, NOT the button color.)
                "blue", "default", "green", "red", "purple", "orange", "dark".
            Example option for changing the border color: ("color", "default")
            Width can be set using percent or pixels. Eg: "36.0%", "450px".r   ©Ú
jqc_helperú&Expecting a string for arg: "message"!ú,Expecting a list or tuple for arg: "button"!r�   ú,List "buttons" requires at least one button!rd  ú%"options" should be a list of tuples!rû   r7  z0document.querySelector('.jconfirm-box').focus();NTrë   ú!return jconfirm.instances.length;rn  r¯   úreturn $jqc_status;úreturn jconfirm.lastButtonText;)r  rJ  r˜  rÁ   r¿   rÄ  rA   r  r�   r  r  rò  r(  Zjquery_confirm_button_dialogr=   rD   r¾   r   rÈ   )r3   râ   r-  ÚoptionsrJ  Únew_buttonsrÎ  rP  ÚjfÚwaiting_for_responseÚjqc_openÚstatusr8   r8   r9   Úget_jqc_button_input˜5  sR     

ÿ

*


zBaseCase.get_jqc_button_inputc                 C   sà  ddl m} |r"t|tƒs"tdƒ‚|rÔt|ttfƒrRt|ƒdkrRt|d ƒdf}qØt|ttfƒrÆt|ƒdkrÆg d¢}t|d ƒ ¡ }t|d ƒ ¡ |vr¨td||f ƒ‚t|d ƒt|d ƒ ¡ f}qØt|ƒdf}nd}|rü|D ]}t|ttfƒsàtd	ƒ‚qà| j	�s| j
�s| j�rdS | | j|||¡ t d
¡ d}ttƒ� |  |¡ W d  ƒ n1 �sb0    Y  d}	|	�r t d¡ |  d¡}
t|
ƒdk�rp�q �qpt d¡ d}z|  d¡}W n t�yÚ   |  d¡}Y n0 |S )ab  
        Pop up a jquery-confirm box and return the text submitted by the input.
        If running in headless mode, the text returned is "" by default.
        @Params
        message: The message to display in the jquery-confirm dialog.
        button: A 2-item list or tuple for text and color. Or just the text.
            Example: ["Submit", "blue"] -> (default button if not specified)
            Available colors: blue, green, red, orange, purple, default, dark.
            A simple text string also works: "My Button". (Uses default color.)
        options: A list of tuples for options to set.
            Example: [("theme", "bootstrap"), ("width", "450px")]
            Available theme options: bootstrap, modern, material, supervan,
                                     light, dark, and seamless.
            Available colors: (For the BORDER color, NOT the button color.)
                "blue", "default", "green", "red", "purple", "orange", "dark".
            Example option for changing the border color: ("color", "default")
            Width can be set using percent or pixels. Eg: "36.0%", "450px".r   rI  rK  r�   rd  r;  z<%s is an invalid jquery-confirm button color!
Select from %s)ZSubmitr<  rN  r7  ú@document.querySelector('.jconfirm-box input.jqc_input').focus();NTrë   rO  rn  r¯   úreturn $jqc_input;úreturn jconfirm.lastInputText;)r  rJ  r˜  rÁ   r¿   rÄ  rA   r  r  r  rò  r(  Zjquery_confirm_text_dialogr=   rD   r¾   r   rÈ   )r3   râ   rÎ  rR  rJ  rF  Zdetected_colorrP  rT  rU  rV  rW  r8   r8   r9   Úget_jqc_text_inputÖ5  sX    	ÿÿ

ÿ

*


zBaseCase.get_jqc_text_inputc                 C   s  ddl m} |r"t|tƒs"tdƒ‚t|ttfƒs8tdƒ‚t|ƒdk rLtdƒ‚g }|D ]z}t|ttfƒr‚t|ƒdkr‚| |d ¡ qTt|ttfƒr¼t|ƒdkr¼| |d t|d ƒ 	¡ f¡ qT| t|ƒdf¡ qT|}|rø|D ]}t|ttfƒsÜtdƒ‚qÜ| j
�s| j�s| j�r d|d	 d fS | | j|||¡ t d
¡ d}ttƒ� |  |¡ W d  ƒ n1 �sj0    Y  d}	|	�r¨t d¡ |  d¡}
t|
ƒdk�rx�q¨�qxt d¡ d}d}z|  d¡}|  d¡}W n( t�yú   |  d¡}|  d¡}Y n0 ||fS )a;  
        Pop up a jquery-confirm box and return the input/button texts as tuple.
        If running in headless mode, returns the ("", buttons[-1][0]) tuple.
        @Params
        message: The message to display in the jquery-confirm dialog.
        buttons: A list of tuples for text and color.
            Example: [("Yes!", "green"), ("No!", "red")]
            Available colors: blue, green, red, orange, purple, default, dark.
            A simple text string also works: "My Button". (Uses default color.)
        options: A list of tuples for options to set.
            Example: [("theme", "bootstrap"), ("width", "450px")]
            Available theme options: bootstrap, modern, material, supervan,
                                     light, dark, and seamless.
            Available colors: (For the BORDER color, NOT the button color.)
                "blue", "default", "green", "red", "purple", "orange", "dark".
            Example option for changing the border color: ("color", "default")
            Width can be set using percent or pixels. Eg: "36.0%", "450px".r   rI  rK  rL  r�   rM  rd  rN  rû   r7  rY  NTrë   rO  rn  r¯   rZ  rP  r[  rQ  )r  rJ  r˜  rÁ   r¿   rÄ  rA   r  r�   r  r  rò  r(  Zjquery_confirm_full_dialogr=   rD   r¾   r   rÈ   )r3   râ   r-  rR  rJ  rS  rÎ  rP  rT  rU  rV  Ztext_statusZbutton_statusr8   r8   r9   Úget_jqc_form_inputs6  s\     

ÿ

*




ÿ
zBaseCase.get_jqc_form_inputsc                 C   s
   t  |¡S r.   )r#   Zare_quotes_escapedr™  r8   r8   r9   Z__are_quotes_escapedd6  s    zBaseCase.__are_quotes_escapedc                 C   s
   t  |¡S r.   )r#   Zescape_quotes_if_neededr™  r8   r8   r9   Z__escape_quotes_if_neededg6  s    z"BaseCase.__escape_quotes_if_neededc                 C   s   t  | j¡S r.   )r#   Zis_in_framer=   r‹   r8   r8   r9   Z__is_in_framej6  s    zBaseCase.__is_in_framec                 C   sP  |   ||¡\}}| j||d�}t |¡}|  |¡}| j||d�}|  ¡ }d| }t| ddƒrd|  ¡  z|  	|¡ W nØ t
�yJ } z¾|r–| j||d�r¢||  ¡ kr°W Y d}~dS |  ¡  d|jv �r$tj| j||dd� t | j||¡�s$tt
ƒ�  | j||dd� W d  ƒ n1 �s0    Y  d	| }|  	|¡ W Y d}~n
d}~0 0 dS )
ú5Clicks an element using pure JS. Does not use jQuery.rï   a˜  var simulateClick = function (elem) {
                   var evt = new MouseEvent('click', {
                       bubbles: true,
                       cancelable: true,
                       view: window
                   });
                   var canceled = !elem.dispatchEvent(evt);
               };
               var someLink = document.querySelector('%s');
               simulateClick(someLink);rÇ   NzCannot read properties of nullr�  ré   rù   z%document.querySelector('%s').click();)r  r<  r=  r>  r?  r£  r„  r·   r�  rÈ   r¿   rÔ   r¨   r$   rg  r=   r"  r   r  )r3   r-  rð   rA  Ú
is_visiblerÀ   r{  rà   r8   r8   r9   Z
__js_clicko6  sN    


öÿÿÿ
þ
ÿÿ
ÿ&ÿÿzBaseCase.__js_clickc                 C   s†   |  ¡ }|  ¡ }d}t| ddƒr(|  ¡  z|  ||¡ W nH ty€   |rR|  ¡ r^||  ¡ krdY dS |  ¡  d}|  ||¡ Y n0 dS )r^  aˆ  var simulateClick = function (elem) {
                   var evt = new MouseEvent('click', {
                       bubbles: true,
                       cancelable: true,
                       view: window
                   });
                   var canceled = !elem.dispatchEvent(evt);
               };
               var someLink = arguments[0];
               simulateClick(someLink);rÇ   Nrñ   )ry  r„  r·   r�  rÈ   r¿   rÔ   )r3   r0  r_  rÀ   r{  r8   r8   r9   Z__js_click_element¤6  s&    ÿÿÿ
þzBaseCase.__js_click_elementc                 C   sH   |   ||¡\}}| j||d�}t |¡}|  |¡}d| }|  |¡ dS )rŒ  rï   a  var simulateClick = function (elem) {
                   var evt = new MouseEvent('click', {
                       bubbles: true,
                       cancelable: true,
                       view: window
                   });
                   var canceled = !elem.dispatchEvent(evt);
               };
               var $elements = document.querySelectorAll('%s');
               var index = 0, length = $elements.length;
               for(; index < length; index++){
               simulateClick($elements[index]);}N)r  r<  r=  r>  r?  rÈ   r—  r8   r8   r9   Z__js_click_allÆ6  s    

ôÿzBaseCase.__js_click_allc
                 C   s¨  |   ¡ r"| jj|||||	d� d S |  ¡  |  ¡ r<t d¡ |sFtj}| j	r`|tjkr`|  
|¡}|  ||¡\}}t | j|||¡}
| jrš| j||dd� n4| jr¼|	r°|  |
¡ qÎ|  d¡ n|	rÎ|  |
||¡ |  ¡  |  ¡ rèt d¡ | jrú|d u rúd}|�r–| j||d�}t |¡}|  |¡}|}|}|�rj|
j}|d	 d
 }|d d
 }||�pXd }||�pfd }|d }|d }d|||||f }|  |¡ zH|
jd }|tjj | }|dk �rÀd}d| }|  |¡ t d¡ W n t�yü   t d¡ Y n0 |  ¡ �rt d¡ z”|�sl|
j}|d	 d
 }|d d
 }| t  t!|ƒ¡�pNd }| t  t!|ƒ¡�phd }t"| jƒ}| #|
||¡ |�s˜| $¡  %¡  n| &¡  %¡  W nÚ t'�yÆ   d}t|ƒ‚Y n¼ t(�y€   |  )¡ �sà‚ | jj*d }| +d¡d }| jj*d }|d }| +d¡d }| +d¡d }t,|ƒdk�rHt,|ƒdk�rH‚ d| }t,|ƒt,|ƒk �rzd|||f }t|ƒ‚n‚ Y n0 | j�r”|  -¡  n| j�r¤|  .¡  d S )N)r  rè   rP  r�   )rð   rá  r®   rQ  Trï   r�  r¾  r�  r   r,   zºvar canvas = document.querySelector('%s');var ctx = canvas.getContext('2d');ctx.fillStyle = '#F8F808';ctx.fillRect(%s, %s, 7, 7);ctx.fillStyle = '#F80808';ctx.fillRect(%s+1, %s+1, 5, 5);r  ru  rw  rë   z_Target coordinates for click are out-of-bounds!
The offset must stay inside the target element!rj  rw  r  rs  re  éL   z seleniumbase get chromedriver %szõYou need to upgrade to a newer
version of chromedriver to perform canvas actions!
Reason: github.com/SeleniumHQ/selenium/issues/7000
Your version of chromedriver is: %s
And your version of Chrome is: %s
You can fix this issue by running:
>>> %s
)/r´   rµ   r  rÔ   r½   rD   r¾   r   rÿ   r   r  r  r$   r  r=   rÕ   rE  r  rÙ  r  r<  r=  r>  r?  r’  rÈ   rô  r!   ÚScrollÚY_OFFSETr¿   r–  r—  r  r   Zmove_to_element_with_offsetr  r;  r:  r   r   r+  r  rž  rO   rÚ   r+  )r3   r-  r  r  rð   r  r  rç   r  rè   r0  Zm_xZm_yr˜  Zleft_offsetZ
top_offsetr@  Úpyr{  Zelement_locationrs  Zaction_chainsrâ   rm  Zmajor_chrome_versionrt  ru  Zmajor_chromedriver_versionZ
install_sbr8   r8   r9   Z__click_with_offsetÝ6  sÎ    
ÿ


ÿ


ûÿ






ÿ

ÿ
þÿúÿ	

zBaseCase.__click_with_offsetc           	      C   sþ   |   ||¡\}}| j||tjd�}t | j|¡}d}z@|rrt|ƒtj	j
krrttt|ƒtj	j
 ƒd ƒ}|dkrrd}W n tyŠ   d}Y n0 d| }dt|ƒd  }| j||d�}|  |¡}d	|tjj|f }t | j¡ræ|  |¡ n
|  |¡ t |¡ d S )
NrI  r   g      )@i¶  i&  g      ä?r:   rï   zkjQuery([document.documentElement, document.body]).animate({scrollTop: jQuery('%s').offset().top - %s}, %s);)r  rg  r   rÿ   r#   rX  r=   rY  r!   rZ  r[  rO   r  r¿   r<  rÛ  ra  rb  rÖ   rÈ   rÙ  rD   r¾   )	r3   r-  rð   r0  ÚdistZtime_offsetZscroll_time_msZ
sleep_timers  r8   r8   r9   Z__jquery_slow_scroll_tob7  s6    ÿÿ

þÿ
z BaseCase.__jquery_slow_scroll_toc                 C   sd   |   ||¡\}}| j||tjd� | j||d�}|  |¡}d| }t| ddƒrV|  ¡  |  |¡ dS )z=Clicks an element using jQuery. Different from using pure JS.rI  rï   rŽ  rÇ   N)	r  rg  r   rÿ   r<  rÛ  r·   r�  rG  )r3   r-  rð   r‰  r8   r8   r9   Z__jquery_click�7  s    ÿ
zBaseCase.__jquery_clickc                 C   s   | j jd d }| d¡d S )NZcapsrj  rw  r   )r=   Ú__dict__rž  )r3   Úversionr8   r8   r9   Z__get_major_browser_versionŽ7  s    z$BaseCase.__get_major_browser_versionc                 C   sX   |   |d|¡}|sd S | d¡r*d| }n*| d¡rP| jj}|  |¡}|| }n|}|S ©Nró   r`  r£   rÏ  )rÇ  rÆ   r=   rÀ   rÊ   ©r3   r¸  rÅ  ró   ra  rÛ   Z
domain_urlr8   r8   r9   Z__get_href_from_link_text’7  s    




z"BaseCase.__get_href_from_link_textc                 C   sb  |   ¡ }g }| d¡D ]}| |¡ q| d¡d  d¡d }|D �]}|j d¡}||v rB|| ¡ v rBd}z"|d D ]}	|d	7 }||	7 }qvW n ty¤   Y qBY n0 |j| }|  |¡}
|
D ]œ}| 	¡ r¾t
tƒ�v zt | j|¡ W n6 t�y   |  |  |¡¡ Y W d
  ƒ   dS 0 tj| j||ddd� W d
  ƒ   dS 1 �sP0    Y  q¾qBdS )z:When a link may be hidden under a dropdown menu, use this.ú	li[class]rü  r�   ú=r   rN  rd  r/  rw  NTr¶  rw  rE  F)r»  r1  r�   rž  r]  Údecoder¿   r”   r  ry  r   r$   r9  r=   r¶   rÞ  Úhover_element_and_click©r3   r¸  rä  r¾  Zdrop_down_listÚitemZcsstypeZitem_text_listZdropdown_cssZ	css_classZmatching_dropdownsZdropdownr8   r8   r9   Z__click_dropdown_link_text 7  sN    




þÿû*z#BaseCase.__click_dropdown_link_textc                 C   sX   |   |d|¡}|sd S | d¡r*d| }n*| d¡rP| jj}|  |¡}|| }n|}|S rg  )rÌ  rÆ   r=   rÀ   rÊ   rh  r8   r8   r9   Z!__get_href_from_partial_link_textÍ7  s    ÿ




z*BaseCase.__get_href_from_partial_link_textc                 C   sb  |   ¡ }g }| d¡D ]}| |¡ q| d¡d  d¡d }|D �]}|j d¡}||v rB|| ¡ v rBd}z"|d D ]}	|d	7 }||	7 }qvW n ty¤   Y qBY n0 |j| }|  |¡}
|
D ]œ}| 	¡ r¾t
tƒ�v zt | j|¡ W n6 t�y   |  |  |¡¡ Y W d
  ƒ   dS 0 tj| j||ddd� W d
  ƒ   dS 1 �sP0    Y  q¾qBdS )z=When a partial link may be hidden under a dropdown, use this.ri  rü  r�   rj  r   rN  rd  r/  rw  NTr¶  rw  rE  F)r»  r1  r�   rž  r]  rk  r¿   r”   r  ry  r   r$   r9  r=   r¶   ré  rl  rm  r8   r8   r9   Z"__click_dropdown_partial_link_textÝ7  sP    




ÿÿÿû*z+BaseCase.__click_dropdown_partial_link_textc                 C   s   t j|||d�S )zÿUse autodetection to return the correct selector with "by" updated.
        If "xp_ok" is False, don't call convert_css_to_xpath(), which is
        used to make the ":contains()" selector valid outside of JS calls.
        Returns a (selector, by) tuple.rT  )r%   Zrecalculate_selector)r3   r-  rð   rU  r8   r8   r9   Z__recalculate_selector8  s    zBaseCase.__recalculate_selectorc                 C   s
   t  |¡S r.   )r%   Zlooks_like_a_page_urlrä   r8   r8   r9   Z__looks_like_a_page_url8  s    z BaseCase.__looks_like_a_page_urlc                 C   s
   t  |¡S r.   )r%   Z!make_css_match_first_element_only©r3   r-  r8   r8   r9   Z#__make_css_match_first_element_only8  s    z,BaseCase.__make_css_match_first_element_onlyc                 C   sv   | j j}z$|  d¡ |  ¡ dkr*|  |¡ W nD typ   ttƒ� |  |¡ W d   ƒ n1 sb0    Y  Y n0 d S )Nrû   r;   )r=   r  r  r„  r¿   r   )r3   r2  r8   r8   r9   Z&__switch_to_newest_window_if_not_blank8  s    

z/BaseCase.__switch_to_newest_window_if_not_blankc                 C   s"   | j dkrttdd ƒrdS dS d S )NrŠ  r‹  TF)r  r·   r   r‹   r8   r8   r9   Z__needs_minimum_wait#8  s    ÿ
þzBaseCase.__needs_minimum_waitc                 C   sN   | j r<tj}| jrt| jƒ}|s,t |¡ qJt |d ¡ n| jrJ|  ¡  d S )Ng333333@)	rÕ   r   ÚDEFAULT_DEMO_MODE_TIMEOUTÚ
demo_sleepr  rD   r¾   r  r+  )r3   rý   Ú	wait_timer8   r8   r9   Z__demo_mode_pause_if_active,8  s    
z$BaseCase.__demo_mode_pause_if_activec                 C   s*   | j r&tj}| jrt| jƒ}t |¡ d S r.   )r  r   rp  rq  r  rD   r¾   )r3   rr  r8   r8   r9   Z__slow_mode_pause_if_active88  s
    
z$BaseCase.__slow_mode_pause_if_activec                 C   s   | j r| j||d� d S )Nrï   )rÕ   rl  r¢  r8   r8   r9   Z__demo_mode_scroll_if_active?8  s    z%BaseCase.__demo_mode_scroll_if_activec              	   C   sö   |   ¡  | jr| j||d� nÔ| jròt d¡ |  ||¡\}}| j||tj	d�}zR| j
dkr”t | j|¡}t|ƒtjjkrˆ|  ||¡ q |  |¡ n|  ||¡ W nD ttfyæ   |  ¡  t d¡ | j||tj	d�}|  |¡ Y n0 t d¡ d S )Nrï   r°   rI  rê   rw  )rþ   rÕ   rE  r  rD   r¾   r  r  r   rÿ   r  r#   rX  r=   rY  r!   rZ  r[  r×  rÙ  r  r  rÔ   )r3   r-  rð   r0  r]  r8   r8   r9   Z__demo_mode_highlight_if_activeC8  s4    
ÿ
ÿ
ÿz(BaseCase.__demo_mode_highlight_if_activec                 C   sD   t  | j|¡}|s4|r4|  ¡  tj| j||tjd�}| jdd� d S )Nré   Trü   )	r#   rn  r=   rÔ   r$   r  r   rÿ   rÚ   )r3   r0  r-  rð   ræ  r8   r8   r9   Z__scroll_to_elementc8  s    ÿzBaseCase.__scroll_to_elementc                 C   s8   zt  | j|¡ W n  ty2   t  | j|¡ Y n0 d S r.   )r#   rp  r=   r¿   rn  )r3   r0  r8   r8   r9   Z__slow_scroll_to_elementl8  s    z!BaseCase.__slow_scroll_to_elementc                 C   s&   |   ¡ s|  ¡  t | j|||¡ d S r.   )r´   rÔ   r#   Zhighlight_with_jsr=   ©r3   r-  rá  rà  r8   r8   r9   Z__highlight_with_jss8  s    zBaseCase.__highlight_with_jsc                 C   s   |   ¡  t | j|||¡ d S r.   )rÔ   r#   Zhighlight_element_with_jsr=   )r3   r0  rá  rà  r8   r8   r9   Z__highlight_element_with_jsx8  s    z$BaseCase.__highlight_element_with_jsc                 C   s&   |   ¡ s|  ¡  t | j|||¡ d S r.   )r´   rÔ   r#   Zhighlight_with_jqueryr=   rs  r8   r8   r9   Z__highlight_with_jquery|8  s    z BaseCase.__highlight_with_jqueryc                 C   sJ   | j }|stj}| js"| js"| jr2t|ƒdkr2d}t | j	||||¡ d S ©Nr÷  )
r/  r   rù  r  rò  r(  r  r#   Zhighlight_with_js_2r=   ©r3   râ   r-  rà  rú  r8   r8   r9   Z__highlight_with_js_2�8  s    ÿÿÿ
þÿzBaseCase.__highlight_with_js_2c                 C   sJ   | j }|stj}| js"| js"| jr2t|ƒdkr2d}t | j	||||¡ d S rt  )
r/  r   rù  r  rò  r(  r  r#   Zhighlight_element_with_js_2r=   )r3   râ   r0  rà  rú  r8   r8   r9   Z__highlight_element_with_js_2Ž8  s    ÿÿÿ
þÿz&BaseCase.__highlight_element_with_js_2c                 C   sJ   | j }|stj}| js"| js"| jr2t|ƒdkr2d}t | j	||||¡ d S rt  )
r/  r   rù  r  rò  r(  r  r#   Zhighlight_with_jquery_2r=   ru  r8   r8   r9   Z__highlight_with_jquery_2›8  s    ÿÿÿ
þÿz"BaseCase.__highlight_with_jquery_2c                 C   s  | j ||dd�\}}| j||tjd�}zR| jdkrjt | j|¡}t|ƒt	j
jkr^|  ||¡ qv|  |¡ n|  ||¡ W n@ ty¸   |  ¡  t d¡ | j||tjd�}|  |¡ Y n0 d}z| j||d�}W n tyæ   d}Y n0 d}z| d	¡}W nB t�y<   |  ¡  t d¡ | j|d
tjd�}| d	¡}Y n0 |�rxd|v �rx| d¡}	| d|	¡d }
||	|
… }|}|�rŽ|  |||¡ n~d|v�rÆd|v�rÆt |¡}|  |¡}|  |||¡ nF|  |¡}t |¡}|  |¡}z|  |||¡ W n t�y
   Y n0 t d¡ d S )NFrT  rI  rê   rw  rï   Trd  r­  rå   rL  rM  r�   rV  rW  rN  )r  r  r   rÿ   r  r#   rX  r=   rY  r!   rZ  r[  r×  rÙ  r¿   rÔ   rD   r¾   r<  r  r�  Ú&_BaseCase__highlight_element_with_js_2r=  r>  r?  Ú_BaseCase__highlight_with_js_2rÛ  Ú"_BaseCase__highlight_with_jquery_2)r3   râ   r-  rð   r0  r]  r^  rà  r­  rQ  rR  rS  r8   r8   r9   Z__highlight_with_assert_success¨8  sn    ÿ
ÿ
ÿ

ÿ






z(BaseCase.__highlight_with_assert_successc                 C   s¤   ddl m} tj}tj}ttƒ�p |d||fd�| _| j ¡  d| _	| j
sX| jt_dt_	| jr‚ttdƒr‚ttjtƒr‚tj | j¡ W d   ƒ n1 s–0    Y  d S )Nr   ©ÚDisplay)Úvisibler¤  TÚ_vd_list)Úsbvirtualdisplayrz  r   r)  r*  r   r¿   rˆ   ÚstartÚheadless_activerÓ   rD  Ú_virtual_displayrS  rÍ   r˜  r|  rÄ  r�   )r3   rz  r�  r�  r8   r8   r9   Z#__activate_standard_virtual_displayé8  s    
ÿ
z,BaseCase.__activate_standard_virtual_displayc           
   
   C   s–  | j �rŠ| j�sŠ| j�sŠddlm} dd l}z¶| js:d| _| jsFd| _|d| j| jfddd�| _dt	j
v r~td	| j| jf ƒ | j ¡  | jt_d
tj ¡ vr°tdƒ |  ¡  n0d| _| jràttdƒràttjtƒràtj | j¡ W n` t�yB } zFt|dƒ�rtdt|jƒ ƒ nt|ƒ tdƒ |  ¡  W Y d }~d S d }~0 0 d}zzdd l}ttƒ�P tj j!}t" #|¡}t" #|j$¡}||k �rœ~t"j%ddd� dd l}W d   ƒ n1 �s²0    Y  d}W n> t�y    d}	td|	 ƒ t"j%ddd� dd l}d}Y n0 |�r’t|dƒ�r’z$|j& tjd
 ¡|j'_(|j'j(t_)W nN t�y† } z4t|dƒ�rjtdt|jƒ ƒ nt|ƒ W Y d }~n
d }~0 0 n|  ¡  d S )Nr   ry  iV  é   Tr(  )r{  r¤  ÚbackendZ	use_xauthz--debug-displayz*Starting VDisplay from base_case: (%s, %s)ZDISPLAYzQ
  X11 display failed! Is Xvfb installed? 
  Try this: `sudo apt install -y xvfb`r|  r¨   rN  FÚ	pyautoguiZLatest)rf  z=PyAutoGUI is required for UC Mode on Linux! Installing now...Ú_pyautogui_x11)*rÓ   r  rò  r}  rz  ZXlib.displayr‰   rŠ   rˆ   r�   r‘   rµ  r~  rD  r€  ry  Úenvironr!  Ú,_BaseCase__activate_standard_virtual_displayr  rS  rÍ   r˜  r|  rÄ  r�   r¿   rÁ   r¨   rƒ  r   r!   Z	PyAutoGUIZVERr&   Zmake_version_tupler   r×  Údisplayr„  Ú_displayZ_pyautogui_x11_display)
r3   rz  ZXlibrà   Zpyautogui_is_installedrƒ  Zuse_pyautogui_verZu_pvÚpvrâ   r8   r8   r9   Z__activate_virtual_displayú8  s’    
ü

ÿÿ
ÿ
ÿ


(ÿ
ÿþÿÿ z#BaseCase.__activate_virtual_displayc              	   C   sÊ   t rÆ| jr| jrÆt tjj¡}z(|� W d  ƒ n1 s:0    Y  W n tyb   |  	¡  Y dS 0 |�N t
tƒ� t tjj¡ W d  ƒ n1 s–0    Y  |  	¡  W d  ƒ n1 s¼0    Y  dS )zªThis is only needed on Linux.
        The "--xvfb" arg is still useful, as it prevents headless mode,
        which is the default mode on Linux unless using another arg.N)r®  Úheadedr(  rÒ  rÓ  r!   rÔ  rÕ  r¿   Ú#_BaseCase__activate_virtual_displayr   r&   rÖ  )r3   râ  r8   r8   r9   Z$__activate_virtual_display_as_neededN9  s    ÿ"
,z-BaseCase.__activate_virtual_display_as_neededc                 C   sJ   | j rF| js|  ¡ sF|  ¡ }|| jksFt | jdtj	¡r@|  
¡  || _dS )z®This is an internal method for handling ad-blocking.
        Use "pytest --ad-block" to enable this during tests.
        When not Chromium or in headless mode, use the hack.r.  N)rú  r  r+  r„  r\   r$   r   r=   r   rq  r¢  ©r3   rÀ   r8   r8   r9   Z__ad_block_as_neededb9  s    

ÿzBaseCase.__ad_block_as_neededc                 C   sb   t | ddƒr|  ¡  | jr^z
| j}W n ty@   d}d| _Y n0 || jkr^d| _d| _|| _dS )z@Disables beforeunload as needed. Also resets frame_switch state.Ú_disable_beforeunloadNr   F)r·   r¥  rÇ   r„  r¿   rK   rI   rJ   rŒ  r8   r8   r9   Z __disable_beforeunload_as_neededp9  s    

z)BaseCase.__disable_beforeunload_as_neededz#You should use re.escape() instead.c                 C   s
   t  |¡S r.   )r#   Z
_jq_format)r3   rµ  r8   r8   r9   Ú	jq_format�9  s    zBaseCase.jq_formatc                 C   s*  |   ¡  |d u rtj}n|dkr$d}| jr>|tjkr>|  |¡}|  |¡ d|vrXtdƒ‚| d¡}|  |d ¡}|d }d}|dd … D �]š}d }	|  	¡ s¦| j
dk�rz
|j}	W nN tyþ   |dkrÐt d¡ z
|j}	W n tyø   td	| ƒ‚Y n0 Y n0 n<z|  d
|¡}	W n* t�y<   t d¡ |  d
|¡}	Y n0 |dk�r\|	�s\td	| ƒ‚n.|	�sŠt d¡ |  d
|¡}	|	�sŠtd	| ƒ‚|d7 }||7 }�z(|  	¡ �s´| j
dk�r°t|  ¡ ƒdk�r°|dk�râ|	jtj|d�}nÌd}
tt|ƒd ƒD ]v}zJ|	jtj|d�}d}||d k�r6|�r6| ¡ �s6tdƒ‚d}
W  �qnW n$ t�yh   t d¡ Y �qöY n0 �qö|
�sÂ|	jtj|d�}d}||d k�rÂ|�rÂ| ¡ �sÂtdƒ‚ntj|	|d|d�}W qˆ t�y"   d}d}|�rð|�rðd}d}d}|dk�rd}d||||f }t ||¡ Y qˆ0 qˆ|S )Nr   r¯   ú	::shadow z<A Shadow DOM selector must contain at least one "::shadow "!Fr�   rú   r¾  z Element {%s} has no shadow root!zreturn arguments[0].shadowRoot;é`   r±  r–  Trû   z Shadow Root element not visible!r®   rå   rI  znot presentr   znot visibleÚElementNotVisibleExceptionrì  rd  z1Shadow DOM Element {%s} was %s after %s second%s!)rÔ   r   rÿ   r   r  Ú0_BaseCase__fail_if_invalid_shadow_selector_usager¿   rž  rã   r+  r  Úshadow_rootrD   r¾   rÈ   rO   rq  rÔ  r   rq  r’  ry  r$   rg  rË  )r3   r-  rç   Úmust_be_visiblerÍ  r0  Zselector_chainZ
is_presentZselector_partr“  r0  rf  r«  Zthe_exceptionr1  r¨   r8   r8   r9   Z__get_shadow_elementŠ9  sð    

ÿ



ÿÿ
ÿ
ÿ
ÿÿÿÿþ
ÿÿ
ÿþ
ÿ
ÿ
ÿþýÿü


ÿÿzBaseCase.__get_shadow_elementc                 C   s   |  ¡  d¡rd}t|ƒ‚d S )Nz::shadowzsA Shadow DOM selector cannot end on a shadow root element! End the selector with an element inside the shadow root!)rÂ   rZ  r¿   )r3   r-  r¨   r8   r8   r9   Z'__fail_if_invalid_shadow_selector_usage:  s    ÿz0BaseCase.__fail_if_invalid_shadow_selector_usagec                 C   s   |   |¡ d|v rdS dS )Nr�  TF)r’  ro  r8   r8   r9   Z__is_shadow_selector:  s    
zBaseCase.__is_shadow_selectorc                 C   s   | j ||dd�}| ¡  d S ©NT©rç   r”  )rÇ  r  ©r3   r-  rç   r0  r8   r8   r9   Z__shadow_click:  s    ÿzBaseCase.__shadow_clickc                 C   s¶   | j ||dd�}|rXttƒ�, | ¡  tjd }| |¡ W d   ƒ n1 sN0    Y  |  |¡}| d¡s†| |¡ t	j
r²|  ¡  n,| |d d… ¡ | tj¡ t	j
r²|  ¡  d S )NTr–  rM  rN  rû   )rÇ  r   r¿   rV  r   rW  rX  rY  rZ  r   rÒ   rÔ   r[  )r3   r-  r]  rç   ra  r0  r_  r8   r8   r9   Z__shadow_type:  s"    ÿ

(



zBaseCase.__shadow_typec                 C   sX   | j ||dd�}ttƒ�, | ¡  tjd }| |¡ W d   ƒ n1 sJ0    Y  d S )NTr–  rM  )rÇ  r   r¿   rV  r   rW  rX  )r3   r-  rç   r0  r_  r8   r8   r9   Z__shadow_clear.:  s    ÿ

zBaseCase.__shadow_clearc                 C   s.   | j ||dd�}|j}| jdkr*| d¡}|S )NTr–  rê   rî  )rÇ  r]  r  r  )r3   r-  rç   r0  rò  r8   r8   r9   Z__get_shadow_text7:  s    ÿ

zBaseCase.__get_shadow_textc                 C   s   | j ||d�}| |¡S r  )rÇ  r  )r3   r-  rµ  rç   r0  r8   r8   r9   Z__get_shadow_attribute@:  s    zBaseCase.__get_shadow_attributec           
   	   C   sò   t |ƒ}t ¡ d }|tjd  }tttjd ƒƒD ]~}zB| j|dd� ¡ }| ¡ }||vrtd||f }t 	d|¡ W  dS  t
y°   t ¡ d }	|	|kr¢Y  q´t d¡ Y q40 q4| j|dd� ¡ }| ¡ }||vrîd||f }t 	d	|¡ dS )
Nr:   r  r�   ré   z3Expected text {%s} in element {%s} was not visible!r‘  Tr¯   ÚTextNotVisibleException©rÁ   rD   r   rÿ   r’  rO   rð  rÂ   r$   rË  r¿   r¾   ©
r3   r]  r-  rç   r”  r•  r  Úactual_textr¨   r–  r8   r8   r9   Z__wait_for_shadow_text_visibleD:  s@    ÿ
ÿÿÿþz'BaseCase.__wait_for_shadow_text_visiblec           
   	   C   sò   t |ƒ}t ¡ d }|tjd  }tttjd ƒƒD ]~}zB| j|dd� ¡ }| ¡ }||krtd||f }t 	d|¡ W  dS  t
y°   t ¡ d }	|	|kr¢Y  q´t d¡ Y q40 q4| j|dd� ¡ }| ¡ }||krîd	||f }t 	d|¡ dS )
Nr:   r  r�   ré   z5Expected exact text {%s} in element {%s} not visible!r˜  Tr¯   z9Expected exact text {%s} in element {%s} was not visible!r™  rš  r8   r8   r9   Z$__wait_for_exact_shadow_text_visiblef:  s@    ÿ
ÿÿÿÿÿz-BaseCase.__wait_for_exact_shadow_text_visiblec           	   	   C   sâ   t   ¡ d }|tjd  }tttjd ƒƒD ]z}z>| j|dd�}| ¡ }t|ƒdkrhd| }t 	d|¡ W  dS  t
y¤   t   ¡ d }||kr–Y  q¨t  d	¡ Y q,0 q,| j|dd�}| ¡ }t|ƒdkrÞd| }t 	d|¡ dS )
Nr:   r  r�   ré   r   z!Element {%s} has no visible text!r˜  Tr¯   )rD   r   rÿ   r’  rO   rð  rÂ   r  r$   rË  r¿   r¾   )	r3   r-  rç   r”  r•  r  r›  r¨   r–  r8   r8   r9   Z(__wait_for_non_empty_shadow_text_visibleˆ:  s.    ÿz1BaseCase.__wait_for_non_empty_shadow_text_visiblec           	      C   s°   |   |||¡ | jr¬d}d}tj}| jdkrPddlm} | | j¡}| | j¡}d|||| 	¡ |f }t
tƒ�. t | j¡ t | j|| j¡ W d   ƒ n1 s¢0    Y  d S )Nr+  rJ  r<   r   r³  r,  )r  rÕ   r   rq  rs   r¹  r´  r-  rK  r   r   r¿   r#   r�  r=   r.  r/  ©	r3   r]  r-  rç   r¾  rL  rð   r´  r¿  r8   r8   r9   Z__assert_shadow_text_visible¡:  s"    
ÿ

ÿz%BaseCase.__assert_shadow_text_visiblec           	      C   s°   |   |||¡ | jr¬d}d}tj}| jdkrPddlm} | | j¡}| | j¡}d|||| 	¡ |f }t
tƒ�. t | j¡ t | j|| j¡ W d   ƒ n1 s¢0    Y  d S )Nr1  rJ  r<   r   r³  r,  )r  rÕ   r   rq  rs   r¹  r´  r4  rK  r   r   r¿   r#   r�  r=   r.  r/  rœ  r8   r8   r9   Z"__assert_exact_shadow_text_visibleµ:  s"    
ÿ

ÿz+BaseCase.__assert_exact_shadow_text_visiblec           	      C   s®   |   |||¡ | jrªd}d}tj}| jdkrPddlm} | | j¡}| | j¡}d||| 	¡ |f }t
tƒ�. t | j¡ t | j|| j¡ W d   ƒ n1 s 0    Y  d S )Nr5  rJ  r<   r   r³  r6  )r  rÕ   r   rq  rs   r¹  r´  r8  rK  r   r   r¿   r#   r�  r=   r.  r/  )	r3   r-  rç   rÂ   r¾  rL  rð   r´  r¿  r8   r8   r9   Z&__assert_non_empty_shadow_text_visibleÉ:  s"    
ÿ

ÿz/BaseCase.__assert_non_empty_shadow_text_visiblec                 C   s2   z| j |dd�}|d uW S  ty,   Y dS 0 d S ©Nr¯   ré   F)rÇ  r¿   ©r3   r-  r0  r8   r8   r9   Z__is_shadow_element_presentÝ:  s
    
z$BaseCase.__is_shadow_element_presentc                 C   s2   z| j |dd�}| ¡ W S  ty,   Y dS 0 d S r�  )rÇ  ry  r¿   rž  r8   r8   r9   Z__is_shadow_element_visibleä:  s
    
z$BaseCase.__is_shadow_element_visiblec                 C   sD   z*| j |dd�}| ¡ r&| ¡ r&W dS W dS  ty>   Y dS 0 d S )Nr¯   ré   TF)rÇ  ry  Ú
is_enabledr¿   rž  r8   r8   r9   Z__is_shadow_element_clickableë:  s    z&BaseCase.__is_shadow_element_clickablec                 C   s2   z| j |dd�}| ¡ W S  ty,   Y dS 0 d S r�  )rÇ  rŸ  r¿   rž  r8   r8   r9   Z__is_shadow_element_enabledô:  s
    
z$BaseCase.__is_shadow_element_enabledc                 C   sf   t |ƒ}zD| j|dd�}| jdkr:| ¡ o6|| d¡v W S | ¡ oJ||jv W S  ty`   Y dS 0 d S ©Nr¯   ré   rê   rî  F)rÁ   rÇ  r  ry  r  r]  r¿   ©r3   r]  r-  r0  r8   r8   r9   Z__is_shadow_text_visibleû:  s    
þz!BaseCase.__is_shadow_text_visiblec                 C   sn   t |ƒ}zL| j|dd�}| jdkr:| ¡ o6|| d¡v W S | ¡ oR| ¡ |j ¡ kW S  tyh   Y dS 0 d S r   )rÁ   rÇ  r  ry  r  rÂ   r]  r¿   r¡  r8   r8   r9   Z__is_shadow_exact_text_visible;  s    
þþz'BaseCase.__is_shadow_exact_text_visiblec                 C   sn   zT| j |dd�}| jdkr:| ¡ o6t| d¡ ¡ dkƒW S | ¡ oRt|j ¡ ƒdkW S  tyh   Y dS 0 d S )Nr¯   ré   rê   rî  r   F)rÇ  r  ry  r  r  rÂ   r]  r¿   rž  r8   r8   r9   Z"__is_shadow_non_empty_text_visible;  s    
þz+BaseCase.__is_shadow_non_empty_text_visiblec                 C   sh   zN| j |dd�}| |¡}|d u r(W dS |d urF||kr>W dS W dS nW dS W n tyb   Y dS 0 d S )Nr¯   ré   FT)rÇ  r  r¿   )r3   r-  rµ  rS  r0  Zfound_valuer8   r8   r9   Z__is_shadow_attribute_present$;  s    

z&BaseCase.__is_shadow_attribute_presentc                 C   s   | j ||d�}|S r  ©rÇ  r—  r8   r8   r9   Z!__wait_for_shadow_element_present4;  s    z*BaseCase.__wait_for_shadow_element_presentc                 C   s   | j ||dd�}|S r•  r¢  r—  r8   r8   r9   Z!__wait_for_shadow_element_visible8;  s    ÿz*BaseCase.__wait_for_shadow_element_visiblec           	      C   sŠ   | j ||d�}| |¡}d}|dkr(d}|d u rZ|d ur<|S d||||f }t d|¡ n,||krf|S d||||||f }t d|¡ d S )Nré   rì  r�   rd  zJExpected attribute {%s} of element {%s} was not present after %s second%s!ZNoSuchAttributeExceptionzqExpected value {%s} for attribute {%s} of element {%s} was not present after %s second%s! (Actual value was {%s}))rÇ  r  r$   rË  )	r3   r-  rµ  rS  rç   r0  Zactual_valuer1  râ   r8   r8   r9   Z#__wait_for_shadow_attribute_present>;  s<    

þÿÿúýÿÿz,BaseCase.__wait_for_shadow_attribute_presentc                 C   s˜   |   |¡ | jr”d}tj}| jdkr<ddlm} | | j¡}d|| ¡ |f }t	t
ƒ�. t | j¡ t | j|| j¡ W d   ƒ n1 sŠ0    Y  d S )Nr  r<   r   r³  r  )rÇ  rÕ   r   rq  rs   r¹  r´  r  r   r   r¿   r#   r�  r=   r.  r/  )r3   r-  r¾  rð   r´  r¿  r8   r8   r9   Z__assert_shadow_element_presenti;  s    



ÿz(BaseCase.__assert_shadow_element_presentc                 C   s´   |   |¡}| ¡ s&d| }t d|¡ | jr°d}tj}| jdkrXddlm	} | 
| j¡}d|| ¡ |f }ttƒ�. t | j¡ t | j|| j¡ W d   ƒ n1 s¦0    Y  d S )Nz(Shadow DOM Element {%s} was not visible!r   r  r<   r   r³  r  )rÇ  ry  r$   rË  rÕ   r   rq  rs   r¹  r´  r  r   r   r¿   r#   r�  r=   r.  r/  )r3   r-  r0  r¨   r¾  rð   r´  r¿  r8   r8   r9   Z__assert_shadow_element_visibley;  s     



ÿz(BaseCase.__assert_shadow_element_visiblec              :   C   s  t | dƒs| jrdS d| _d| _d| _tjj| _|| _zt	j| _W n t
yZ   d| _Y n0 | j�rª|  ¡ }|| _d| _t | dƒršt	j| _t t	dƒršdt	_t	j| _t	j| _t	j| _t	j| _t	j| _t	j| _t	j}|�rbt|tƒ�rbt|ƒdk�rbddl}d}| d¡�r| d¡�sd}n8z| |¡}t|tƒ�s6d}W n t
�yP   d}Y n0 |�rtt
d	ƒ‚nt|tƒ�rpni }|t	_t	j| _t	j| _t	j | _ t	j!| _!t	j"| _"t	j#| _$t	j#t	_$t	j%| _%| j%| _&t	j'| _'t	j(| _(t	j)| _)| j)�rèd| _(t	j*| _*d| _+dt	_+t	j,| _,t	j-| _-t	j.| _.t	j/| _/t	j0| _0t	j1| _1t	j| _t	j2| _2t	j3| _3t	j4| _4t	j5| _5t	j6| _6t	j7| _7t	j8| _8t	j9| _9t	j:| _:t	j;| _;t	j<| _<t	j=| _=t	j>| _>t	j?| _?t	j@| _@t	jA| _At	jB| _Bt	jC| _Ct	jD| _Dt	jE| _Et	jF| _Ft	jG| _Gt	jH| _Ht	jI| _It	jJ| _Jt	jK| _Kt	jL| _Lt	jM| _Mt	jN| _Nt	jO| _Ot	jP| _Pt	jQ| _Qt	jQ| _Rt	jS| _St	jT| _Tt	jU| _U| jS�rr| jQ�srd| _Qd| _Rn:| jT�r�| jQ�s�d| _Qd| _Rn| jU�r¬| jQ�s¬d| _Qd| _Rt	jV| _Vt	jW| _Wt	jX| _Xt	jY| _Yt	jZ| _Z| jY�sâd| _Zt	j[| _[t	j\| _\t	j]| _]t	j^| _^t	j_| __t	j`| _`t	ja| _at	jb| _bt	jc| _ct	jd| _dt	je| _et	jf| _ft	jg| _gt	jh| _ht	ji| _jt	jk| _lt	jm| _mt	jn| _nt	jo| _p| jn�rš| jh�rštq rtjsjt¡| _ut	jv| _vt	jw| _xt	jy| _yt	jz| _zt	j{| _{t	j|| _|t	j}| _}t	j~| _~t	j| _t	j€| _€t	j�| _�t	j‚| _ƒt	j„| _„t	j…| _…t	j†| _†t	j‡| _ˆt	j‰| _Št	j‹| _‹t	jŒ| _Œt	j�| _�d| _Ž| j��rNd| _Žd| _�| j9d
k�rfd| _�| j6�rÒddl�}ddl‘}ddl’m“} ddl”m•}	m–}
m—} t| ˜¡ ƒ| _™d| _šd| _›d| _œd| _�|| jEƒ| _�|	ƒ }tžtŸ Ÿ¡ d ƒ|_›|j›| _›| j™|_ | ¡¡ |_¢| j� £|¡ |
ƒ }t| ˜¡ ƒ| _š| jš|_ | j™|_™| j'�rD| j|_nd|_||_¤| ¥| ¡}| ¦d¡d |_&| ¦d¡d |_§tj¨j©|_ªd| _«| j� ¬|¡ tžtŸ Ÿ¡ d ƒ| _œn(t­| ddƒ�rÂ|  ®¡  nt­| ddƒ�rÒn t | dƒ�sæt
dƒ‚t t	dƒ�sdt	_¯t°j±t	_²t°j³t	_´t	j¯�r0t	j²�r0t	j´�r0t	j²t°_±t	j´t°_³t | dƒ�sBd| _xt t	dƒ�sZi t	_µi t	_¶t t°dƒ�sldt°_·| jD�rŒddl¸m¹} | º| jD¡ t»j¼ ½| j¡| _¾t»j¼ ¿| j|  ¡ ¡| _Àt»j¼ ½| jÀ¡| _Á|  ¡ }t»j¼ ¿| j|¡}|t	_Â| jÃt	_Ã| jÄt	_Ä| jÅt	_Æ| jÇt	_Çdt	_Èdt	_Édt	_Êdt	_Ë| jA�r¨| jA}| Ìdd¡}| ¦d¡}d}t|ƒdk�rVt
|ƒ‚z4tž|d ƒ| _Ítž|d ƒ| _ÎtÏ|d ƒ| _Ðd| _@W n t
�y¦   t
|ƒ‚Y n0 | j„}|�	rB| Ñd¡dk�rÔd | }t
|ƒ‚| Ìdd¡}d}d}z(tž| ¦d¡d ƒ}tž| ¦d¡d ƒ}W n$ t
�	y4   d!| }t
|ƒ‚Y n0 |t°_Ò|t°_Ó| j…}|�	rè| Ñd¡dk�	rnd"| }t
|ƒ‚| Ìdd¡}d}d}z(tž| ¦d¡d ƒ}tž| ¦d¡d ƒ}W n$ t
�	yÎ   d#| }t
|ƒ‚Y n0 |t°_Ô|t°_Õ|t°_Ö|t°_×| j.�
r¦| j.}| Ìdd¡}| ¦d¡dd… }d$}t|ƒdk�
r.t
|ƒ‚zZtž|d ƒ| _Øtž|d ƒ| _Ù| jØd%k �
r^d%| _Ø| jØt	_Ø| jÙd&k �
rxd&| _Ù| jÙt	_Ùd| _-W n t
�
y¤   t
|ƒ‚Y n0 | j@�
rÀ| j?�
sÀtjÚjÛ| _?| jd'v �
ræ| jQ�
ræd(| j }t
|ƒ‚t­| ddƒ�
sü|  Ü¡  | jn�r²| jh�r�| ju�j tÝt
ƒ� tÞ ßtjsjt¡ W d  ƒ n1 �sB0    Y  | jp�sndt	_od| _p| jàddd)� W d  ƒ n1 �s„0    Y  n"| jp�s²dt	_od| _p| jàddd)� | jQ�rÌtžtŸ Ÿ¡ d ƒ| _ád}| jj�rìt t	d*ƒ�sêdt	_ât	jâ�rìtÝt
ƒ�à t	jâ| _ãt	jâ| _ät	jâg| _å|  æ¡ }|du�r,d}t| jäjçƒdk�rrt| jäjçƒdk�rh|  èd+¡ | jä é¡  �q>|  èd¡ | jl�rÌ| j}d,k�r�|  ê¡  n<|  ë¡  tÝt
ƒ� | jä ì¡  W d  ƒ n1 �sÂ0    Y  W d  ƒ n1 �sâ0    Y  | jj�rìt	jâ�rì|�rìd}| jR�r tžtŸ Ÿ¡ d ƒ| _á| j1�r”t| j1ƒd-k�r”tí î| j1¡�rdd}d| _ï|  ð| j1¡ d| _ïn0d.| j1 }tí î|¡�r”d}d| _ñ|  ð|¡ d| _ñ| jR�sª| jl�r†|�s†|  æ¡ d/k�r†d| _ï|  ðd/¡ d| _ï| jR�r†tžtŸ Ÿ¡ d ƒ| _á�nš| jò| j| j(| j/| j8| j9| j:| j;| j<| j=| j>| j?d| jB| jC| jR| jV| jW| jX| jZ| j[| j\| j]| j^| j_| j`| ja| jb| j)| j*| jc| jd| je| jf| jg| jv| jx| jH| jI| jJ| jK| jL| jM| jN| jy| jz| j{| j|| j}| j~| j| j€| j�| j@| jÍ| jÎ| jÐd0�8| _äz | jäjójôdk�rô| jä õd¡ W nJ t
�y@   tÝt
ƒ� | jä õd¡ W d  ƒ n1 �s20    Y  Y n0 | jä| _ã| jj�rZ| jät	_ât| jåƒdk�r†| jå ö| jä¡ | j| j÷| jä< | jd'v �r˜d| _@|  ø| j$¡ tÝt
ƒ�8 t t°d1ƒ�rÊ| jä ùt°jú¡ n| jä ùd2¡ W d  ƒ n1 �sì0    Y  tžtŸ Ÿ¡ d ƒt	_ût	jû| _üdS )3zÉThis method runs before every test begins.
        Be careful if a subclass of BaseCase overrides setUp().
        If so, add the following line to the subclass setUp() method:
        super().setUp() rø  NTFÚ_sb_pdb_driverr   Ú{Ú}z^
Expecting a Python dictionary for "variables"!
Eg. --variables="{'KEY1':'VALUE', 'KEY2':123}"rÑ  )ÚApplicationManager)ÚExecutionQueryPayloadÚTestcaseDataPayloadÚTestcaseManagerr:   zN/Arw  r�   r   Zis_nosetestr  a\  SeleniumBase plugins DID NOT load!
Either "seleniumbase" is not installed on your system,
or you called "setUp()" directly without initialization!
*** To install SeleniumBase in Develop Mode from a clone:
    >>> "pip install -e ."     (Run in DIR with setup.py)
*** To install the latest SeleniumBase version from PyPI:
    >>> "pip install -U seleniumbase"    (Run in any DIR)
NOTE: "setUp()" can ONLY be called after vars are set.
    If using "pytest", then "pytest_plugin.py" sets them.
    The SeleniumBase "SB()" Manager can also set them.
See SeleniumBase/help_docs/syntax_formats.md for details!rˆ  r#  r"  r$  )Úsettings_parserre  rd  rU  z¿Invalid input for Mobile Emulator device metrics!
Expecting a comma-separated string with integer values
for Width/Height, and an int or float for Pixel-Ratio.
Example: --metrics="412,732,3" r,   r¾  zF

  window_position expects an "x,y" string!
  (Your input was: "%s")
zL

  Expecting integer values for "x,y"!
  (window_position input was: "%s")
zJ

  window_size expects a "width,height" string!
  (Your input was: "%s")
zQ

  Expecting integer values for "width,height"!
  (window_size input was: "%s")
z°Invalid input for xvfb_metrics!
Expecting a comma-separated string
with integer values for Width/Height.
Eg. --xvfb-metrics="1920,1080".
(Minimum: 1024,768) (Default: 1366,768)i   r�  )rú   rî   rê   zLRecorder Mode ONLY supports Chrome and Edge!
(Your browser choice was: "%s"))ÚinitÚshared_driverrû   Zchsr–  rœ   r;   )8r  r  rÚ  rÜ  rÝ  rÞ  r-  rà  rá  râ  r.  r§   rä  rå  ræ  rç  rè  ré  rê  rë  rì  rÓ   rL  rí  rî  rï  rð  rñ  rò  ró  rô  rõ  rö  r÷  rø  rù  rú  rû  rü  rý  rþ  rÿ  r   r  r  r  r  r  r  r  r  r	  r/  r0  r1  r2  ÚPAGE_LOAD_TIMEOUTéx   )ýrÍ   rM   rN   r•  r!   ÚLogsÚLATESTrB  Úmasterqa_moderD  r¿   r$  r
  r   r  r£  r  Úaccountr²   Zvar1Zvar2Zvar3Ú	variablesr˜  rÁ   r  ÚastrÆ   rZ  Úliteral_evalrÆ  r  rÕ   rq  rO  Z_time_limitr�  r>   r?   Úwith_seleniumr  rñ  rò  r  rŠ  r(  Zxvfb_metricsrÚ  rÂ  r—  Úwith_testing_baseÚwith_basic_test_infoÚwith_screen_shotsÚwith_page_sourcer‘  Úwith_s3_loggingrÜ  rÝ  rÞ  rß  rà  rá  râ  rã  r=  Zdevice_metricsrä  rå  Zsettings_fileÚdatabase_envr/  rŒ  rú  rû  rü  rý  rþ  rÿ  r   Zverify_delayr‡  rÇ   ræ  r  r  r‘  rç  rè  ré  Z
disable_wsrê  rë  rì  rÓ   rL  rí  rî  rï  rð  ró  rô  rõ  rö  r÷  rç  Úreuse_sessionrS  ZcrumbsZ_crumbsr�  r’  Z_dashboard_initializedZ_dash_initializedrÒ  rÓ  Ú	DashboardÚLOCKFILEÚ	dash_lockrø  rù  r#  r  r  r  r  r  r  r  r  r	  Zfinal_debugr|   Úwindow_positionÚwindow_sizer,  r<  Úsave_screenshot_after_testZno_screenshotÚno_screenshot_after_testry  r   Zpytest_html_reportÚ	report_onrÛ  ÚgetpassÚuuidZ%seleniumbase.core.application_managerr¦  Ú"seleniumbase.core.testcase_managerr§  r¨  r©  Úuuid4Úexecution_guidÚtestcase_guidÚexecution_start_timeÚcase_start_timeÚtestcase_managerrO   rD   ÚguidÚgetuserÚusernameZinsert_execution_dataZtest_addressZgenerate_application_stringrž  Ú
start_timeÚStateZUNTESTEDÚstatera   Zinsert_testcase_datar·   r1   rˆ  r   rÿ   rŠ  rT  r‹  r"  rB  r$  r  rª  Zset_settingsry  rz  r{  Zlog_abspathr2  Ú	data_pathZdata_abspathZ_test_logpathÚ_process_dashboard_entryÚ_add_pytest_html_extrar`  Z_process_v_baseline_logsÚ_log_fail_datarz   Ú_last_page_screenshot_pngZ_sbase_detectedZ_only_unittestri  rk   rl   r  rm   rh  rª  r«  r¬  r­  r)  r*  r‰   rŠ   r%  r&  Ú-_BaseCase__activate_virtual_display_as_neededr   r&   rÖ  Ú_BaseCase__process_dashboardrG   r¬  r}   r=   r~   r„  r  r  ro  rã  rÔ   r~  r%   rÄ   rf   r¶   rd   rÏ   rÑ   Zimplicit_waitZimplicitly_waitr�   r   r‡  Zset_page_load_timeoutr­  Zstart_time_msrP   )r3   r±  r
  r³  r´  Z	bad_inputrÆ  rÇ  r¦  r§  r¨  r©  Zexec_payloadÚdata_payloadZapplicationrª  rF  Zmetrics_stringZmetrics_listZexception_stringrÁ  râ   Zwin_xZwin_yrÂ  r�  r�  Zhas_urlrÛ   Zgood_start_pager™  r8   r8   r9   ÚsetUpŽ;  sÂ   


 ÿþ

ÿÿ

ÿ

ÿ
ÿ
ÿÿþÿÿÿÿÿÿ

ÿÿ
ÿ$0






J


È:
2
,zBaseCase.setUpc                 C   sH  t jj}t jj}t| ddƒrFddlm} | ¡ }|| _|| _	|t
_dS d}| j�s<| j	�s<ttƒ�Æ ztj| jddddd	�}W n( ty¦   tj| jddddd	�}Y n0 z&ttd
dƒrÄ| j ¡ | _n|j| _W nJ t�y   ttƒ� | j ¡ | _W d  ƒ n1 �s
0    Y  Y n0 W d  ƒ n1 �s00    Y  | j�s®|| _|| _	|�r<z|j| _	W nJ t�yª   ttƒ� | j ¡ | _	W d  ƒ n1 �sœ0    Y  Y n0 nŽddl}z| | j¡| _	W nr t�y:   |�r6z|j| _	W nJ t�y4   ttƒ� | j ¡ | _	W d  ƒ n1 �s&0    Y  Y n0 Y n0 | j	t
_dS )z‰self.__last_page_screenshot is only for pytest html report logs.
        self.__last_page_screenshot_png is for all screenshot log files.rÄ  Nr   )Úencoded_imagesr¨  rå   r¯   T)rç   Zignore_test_time_limitZSCREENSHOT_WITH_BACKGROUND)r!   ÚWarningsÚSCREENSHOT_SKIPPEDÚSCREENSHOT_UNDEFINEDr·   r  rÞ  Zget_no_screenshot_pngr]   r^   rD  rÙ  r   r¿   r$   r  r=   rg  r   Zget_screenshot_as_base64Zscreenshot_as_base64r÷  Zget_screenshot_as_pngr  r  )r3   rà  rá  rÞ  ZNO_SCREENSHOTr0  r  r8   r8   r9   Z__set_last_page_screenshotá=  s„    ÿþ
û
ûÿÿ
ÿJÿ
ÿ,
ÿÿ
ÿ0z#BaseCase.__set_last_page_screenshotc                 C   s6   | j s2zt | j¡| _ W n ty0   d | _ Y n0 d S r.   )r_   r   Zget_last_pager=   r¿   r‹   r8   r8   r9   Z__set_last_page_url3>  s
    zBaseCase.__set_last_page_urlc                 C   sH   | j sDzt | j| jj¡| _ W n ty:   tjj| _ Y n0 | j t	_
d S r.   )r`   r   Zget_html_source_with_base_hrefr=   rˆ  r¿   r!   rß  ZPAGE_SOURCE_UNDEFINEDrD  Z_last_page_sourcer‹   r8   r8   r9   Z__set_last_page_source:>  s    
ÿÿÿ
zBaseCase.__set_last_page_sourcec                 C   sx   d }t | dƒrNt| jdd ƒrNz| jjd d d }W qp tyJ   d}Y qp0 n"z
tj}W n tyn   d}Y n0 t|ƒS )NÚ_outcomerƒ  rû   r�   z(Unknown Exception))rÍ   r·   râ  rƒ  r¿   r�   Ú
last_valuerÁ   )r3   r‚  r8   r8   r9   Z__get_exception_infoH>  s    ÿþ

zBaseCase.__get_exception_infoc                 C   s  ddl m} |ƒ }tt ¡ d ƒ| j |_| j|_| j|_||_	|r²dd l
}| ¡ }d|v rrd| d¡d  |_qöd|v rŒ| d¡d |_qöd|v r¦| d¡d |_qö|  ¡ |_nD|  ¡ }| jrö|tj ¡ v rötj| dkrö| jrðd	| j |_nd
|_| j |¡ d S )Nr   )r¨  r:   z	Message: rû   zException: zError: r�  zSkipped:   zSkipped:   (no reason given))rÈ  r¨  rO   rD   rÍ  ÚruntimerË  rÏ  rÊ  rÔ  r  Ú
format_excrž  râ   Ú_BaseCase__get_exception_infor“  r•  rD  r”  r!  ra   rÎ  Zupdate_testcase_data)r3   rÔ  Úerrr¨  rÜ  r  Z	tb_stringr
  r8   r8   r9   Z__insert_test_resultY>  s8    ÿÿþýzBaseCase.__insert_test_resultc                 C   s"   t rtsdtjv sd S |  ¡  d S r[  )r]  r^  r�   r‘   Ú _BaseCase__add_pytest_html_extrar‹   r8   r8   r9   r×  {>  s    ÿÿþzBaseCase._add_pytest_html_extrac                 C   sô   | j sðttƒ�Ò | jrÒ| js4|  ¡  |  ¡  |  ¡  | jrÒi }d|d< d|d< d|d< | j	|d< d |d< d |d< i }d	|d< d
|d< d
|d< | j|d< d|d< d|d< d| _ | jt
jjkrÒ| j |¡ | j |¡ W d   ƒ n1 sæ0    Y  d S )NÚURLr”   rÛ   r¡  Zformat_typerï  Z	mime_typeÚ	extensionZ
Screenshotrú  z	image/pngZpngT)rh   r   r¿   r¶  r]   Ú#_BaseCase__set_last_page_screenshotÚ_BaseCase__set_last_page_urlÚ_BaseCase__set_last_page_sourcerÅ  r_   r!   rß  rá  ry   r�   )r3   Z	extra_urlZextra_imager8   r8   r9   Z__add_pytest_html_extraƒ>  s8    


ÿz BaseCase.__add_pytest_html_extrac                 C   sD   d}t | dd ƒr@dtjv r@|  ¡ r@t| jƒdkr@| j| jkr@d}|S )NFrø  r\  r�   T)r·   r�   r‘   Ú_BaseCase__has_exceptionr  r~   r=   r}   )r3   Údelay_driver_quitr8   r8   r9   Z__delay_driver_quit¡>  s    
ÿþýü
û	zBaseCase.__delay_driver_quitc              	   C   s0  | j rŽtjrŽt| jƒdkrh| jd tjkrTtj| jv rD| j tj¡ | j dtj¡ | jd | _|  ¡  t| jƒdkrˆ| jdd … | _ng | _|  	¡ }| j 
¡  | jD ]l}zBtrÖ| jdksÖ| jdksÖt|dƒrê|jjrê|sä| ¡  n|t_W q¦ tyþ   Y q¦ t�y   Y q¦0 q¦|�s,d | _d | _g | _d S )Nr   r�   rî   rÑ  rT  )rS  rD  r¬  r  r~   r  Úinsertr}   r7  Ú_BaseCase__delay_driver_quitÚreverser`  r  rÝ  rÍ   rT  rU  rR  r£  rV  r¿   r=   )r3   rï  r=   r8   r8   r9   Z__quit_all_drivers¯>  sH    

ÿþýûú	

zBaseCase.__quit_all_driversc                 C   sº   d}t tdƒrtjd urd}n„t| dd ƒr@| jr:| jr:dS dS nbt | dƒr’t | jdƒr’tr„| jjr�| jjd r�| jjd d r�d}q¢| jjr¢d}nt 	¡ d d u}| j
r¶t | d	ƒr¶d}|S )
NFÚlast_tracebackTrñ  râ  rƒ  rû   r�   rø  )rÍ   r�   ró  r·   r·  Z_has_failurerâ  r]  rƒ  r�  rX   )r3   Úhas_exceptionr8   r8   r9   Z__has_exceptionØ>  s,    ÿ
þýzBaseCase.__has_exceptionc           
      C   s  t | ddƒrttjj}| dd¡ dd¡}tjj}d|v rJ| d¡d  ¡ }t 	d	d
|¡}| dd¡}d||f }|S t | ddƒ�rRt
| dƒr”| j| _| jr | jS | jj d¡d d }| j}d}|dksÒ|dk�rRddl}| ¡ d  tj¡d }| d¡d }	t | ddƒ�r| j}n|	 d¡d }d|	 d¡d  }| d¡d | }|| _|S d| jj| jj| jf }| j�rŽtt| jƒƒdk�rŽ| j}nt | ddƒ�r¢tj}| dd¡ dd¡}| dd¡ dd¡}| dd¡}t|ƒdk�rè|S |dd… d  |d!d…  S dS )"z8The id used in various places such as the test log path.r   NrÏ  rw  r_  ú -- @ú # r   r  rd  re  rÿ  z%s.%srñ  Ú_manager_saved_idrû   r	  rò  ró  rô  rõ  rö  z.line_r÷  ú%s.%s.%srt  rø  ú.py::rù  éß   éi   Z__TRUNCATED__i—ÿÿÿ)r·   rD  r!  r(  ri  r”   rž  Úrstripr=  r  rÍ   r÷  rr   r7   r'  r  r  r  ry  r  rõ  r  rx   r  rÁ   Z_latest_display_id)
r3   rX  Úscenario_namer
  r(  r4  Z
context_idr  r5  r6  r8   r8   r9   Z__get_test_idò>  sX    
ýzBaseCase.__get_test_idc                 C   sº   dt jv r<t jd }d|v r.| d¡d d S | d¡d S t| ddƒrP|  ¡ S d| jj d	¡d
 | jj| jf }| j	r¶t
t| j	ƒƒdkr¶| j	}| d	¡dkr¶d	 | d	¡dd… ¡}|S )z*The id for SeleniumBase Dashboard entries.ÚPYTEST_CURRENT_TESTú] r   rþ  re  r   Nrø  rw  rû   rt  r�   )ry  r…  rž  r·   r$  r7   r'  r  r  rx   r  rÁ   rh  r2  )r3   Ú	full_namer
  r8   r8   r9   Z__get_test_id_2'?  s"    

ýzBaseCase.__get_test_id_2c                 C   sZ  dt jv r<t jd }d|v r.| d¡d d S | d¡d S t| ddƒrŠtjj}tj}tjj}d|v rx| d	¡d  	¡ }d
|||f }|S d| j
j dd¡| j
j| jf }| j�rVtt| jƒƒdk�rV| j}t| dƒ�r| d¡dk�rV| d¡}|d d |d  d |d  }|}n>t| dƒ�rV| d¡dk�rV| d¡}|d d |d  }|}|S )z?The id for running a test from pytest. (Displayed on Dashboard)rþ  rÿ  r   rþ  re  r   Nrõ  rö  z%s:%s => %sz%s.py::%s::%srw  rÏ  rt  Z_using_sb_fixture_classr¾  rÍ  rù  rú  rù  rû   Z_using_sb_fixture_no_classr�   )ry  r…  rž  r·   rD  r!  r(  Zbehave_line_numr”   rü  r7   r'  ri  r  r  rx   r  rÁ   rÍ   rh  )r3   r   rX  Úline_numrý  r
  ÚpartsÚfullr8   r8   r9   Z__get_display_id<?  s>    

ý
 
zBaseCase.__get_display_idc                 C   s„   d}dt jv r<t jd  d¡d }| d¡d  d¡d }nDt| ddƒrjtjj}| d¡d  d	¡d }n| jj d
¡d d }|S )z9The filename of the current SeleniumBase test. (NOT Path)Nrþ  re  r   rù  rÏ  rû   r   r_  rw  r	  )	ry  r…  rž  r·   rD  r!  r(  r7   r'  )r3   r(  r
  r8   r8   r9   Z__get_filename_?  s    
zBaseCase.__get_filenamec                 C   s2   t j |¡s.zt  |¡ W n ty,   Y n0 d S r.   )ry  rz  rl  rm  r¿   )r3   rF  r8   r8   r9   Z__create_log_path_as_neededl?  s
    z$BaseCase.__create_log_path_as_neededc              	   C   s�   | j r€t tjj¡| _| j�R ttƒ� t	 
tjj¡ W d   ƒ n1 sJ0    Y  |  ||¡ W d   ƒ qŒ1 st0    Y  n|  ||¡ d S r.   )rç  rÒ  rÓ  r!   r¾  r¿  rÀ  r   r¿   r&   rÖ  rÛ  )r3   rô  r«  r8   r8   r9   rÖ  s?  s    ÿ
,,z!BaseCase._process_dashboard_entryc           A   	   C   sR  | j rdtjv r|rdt_n| j r6ttddƒr6|s6dS | jrútj}tj	 
d¡}tjj}tj	 ||¡}|sútj	 |¡rút|dƒ�}| ¡  ¡ }W d  ƒ n1 s 0    Y  t |¡\}	}
}}}|\}}}}|	t_|
t_|t_|t_|t_|t_|t_|t_ttjƒdk�rÔtjD ]¼}|tj ¡ v �rtj| dk�rRt jd	7  _t jd	8  _nxtj| d
k�r€t jd	7  _t jd	8  _nJtj| dk�r®t jd	7  _t jd	8  _nt jd	7  _t jd	8  _�qg t_| j}|   ¡ }|  !¡ }d}d}t"| dƒ�r| j#�rtj$}|�s¾t%t& &¡ d ƒ| j' }t(|ƒd }d )|¡}|tj|< |�s~| j*�s~| j+dk�s~| j,dk�s~| j-�s~| j#�r”tj	 ||¡tj|< n
dtj|< |tj ¡ v�r¼|  .¡ tj|< tj| |k�rÐdS t"| dƒ�rŒ|tj ¡ v�rŒ| /d¡d	k�r2d | 0d¡d	d… ¡}|tj ¡ v �rŒtj 1|¡ nZ| /d¡d	k�rŒtj| }| 2dd¡}| 2dd¡}| 2dd¡}|tj ¡ v �rŒtj 1|¡ |tj ¡ v �r tj| dk�r | j3�rÖt jd	8  _t jd	7  _d| _3dtj|< t jd	7  _t jd	8  _�q¾| j�rN|| ¡ v �rN|| dk�rNdtj|< t jd	7  _t jd	8  _�q¾|�r|tj ¡ v�rŒd
tj|< t jd	7  _t jd	8  _nztj| d
k�sütj| dk�rÔd
tj|< t jd	7  _t jd	8  _n&d
tj|< t jd	7  _t jd	8  _n
d
tj|< n´|tj ¡ v �rZtj| d
k�rZtj	 ||¡tj|< t jd	8  _t jd	7  _n<|tj ¡ v �r–tj| dk�r–t jd	8  _t jd	7  _dtj|< t jd	7  _t jd	8  _n tj}tj}tj}tj}| j4tjj5d� | j6d|dd� | j6d|dd� | j6d|dd� | j6d
|dd� dtjj7 }d}|dk�rJtjj8}nhtj9�r²|  :¡ t_;| j�r²tj	 
d¡}t <tj;¡}tjj=}tj	 ||¡}t|dd d!�}| >|¡ | ?¡  tj @¡ } d"| ||f }!d#}"g }#g }$g }%g }&g }'|tj ¡ v �rþtj 1|¡ tj ¡ D �]}(tj|( })tj|( }*tj|( }+tj|( },|) A¡ }-tj|( d
k�r„tj|( �sntj	 ||¡tj|(< |# B|-|)|+|*|,g¡ n¢tj|( dk�rª|$ B|-|)|+|*|,g¡ n|tj|( dk�rÖ|,�rÖ|% B|-|)|+|*|,g¡ nPtj|( dk�r|,�s|& B|-|)|+|*|,g¡ n$tj|( dk�r|' B|-|)|+|*|,g¡ �q|#D ]6}.d$|.d |.d	 |.d% |.d& ||.d' f }.|"|.7 }"�q.|$D ]b}.|.d' �sšd(|.d |.d	 |.d% |.d& f }.n(d)|.d |.d	 |.d% |.d& ||.d' f }.|"|.7 }"�qj|%D ]6}.d*|.d |.d	 |.d% |.d& ||.d' f }.|"|.7 }"�qÒ|&D ].}.d+|.d |.d	 |.d% |.d& f }.|"|.7 }"�	q|'D ].}.d,|.d |.d	 |.d% |.d& f }.|"|.7 }"�	qB|"d-7 }"d.}/tC D¡ \}0}1}2d/|1|2f }3|/d0|3  }/d1}4|4d27 }4|dk�
r8d3}4|dk�	rú|dk�	rð|dk�	ræ|4d47 }4n|4d57 }4n|4d67 }4n>tjEjFd7 }5d8}6|d	k�
r&|4d9|5|6f 7 }4n|4d:||5|6f 7 }4|4d;7 }4|/|4 }/d<}7|/|7 }/d=tjjG }8|dk�
rxtj9�
rx|4t_H|/|8 }/d>|! |  :¡  |" |/ }9tj	 
d¡}tj	 |d?¡}:t|:dd d!�};|; >|9¡ |; ?¡  |9t_I| j�rN||||f}tj}<tj}=tj}>tj}?t <|<|=|>|?|f¡}tjj}tj	 ||¡}t|dd d!�}@|@ >|¡ |@ ?¡  dS )@z!SeleniumBase Dashboard Processingr\  TÚ_pdb_failureNrw  rx  r   r�  r�   ZFailedr�  z=seleniumbase/plugins/pytest_plugin.py::BaseClass::base_methodz#pytest_plugin.BaseClass.base_methodrø  r:   z{:.2f}rù  rù  re  rÿ  F)r‰  z#84d474)rê  ZUntestedz#eaeaeaz#efd8b4z#f17476z1<link rel="stylesheet" charset="utf-8" href="%s">rd  rb  rc  rd  z”<head><meta charset="utf-8"><meta name="viewport" content="shrink-to-fit=no"><link rel="shortcut icon" href="%s">%s<title>Dashboard</title>%s</head>aC  <div></div><table border="1px solid #e6e6e6;" width="100%;" padding: 5px; font-size="12px;" text-align="left;" id="results-table"><thead id="results-table-head"><tr style="background-color: #F7F7FD;"><th col="result">Result</th><th col="name">Test</th><th col="duration">Duration</th><th col="links">Links</th></tr></thead>zÃ<tbody class="%s results-table-row"><tr style="background-color: #FFF8F8;"><td class="col-result">%s</td><td>%s</td><td>%s</td><td><a href="%s">Logs</a> / <a href="%s/">Data</a></td></tr></tbody>r¾  r,   r–  z–<tbody class="%s results-table-row"><tr style="background-color: #FEFEF9;"><td class="col-result">%s</td><td>%s</td><td>%s</td><td>-</td></tr></tbody>zÃ<tbody class="%s results-table-row"><tr style="background-color: #FEFEF9;"><td class="col-result">%s</td><td>%s</td><td>%s</td><td><a href="%s">Logs</a> / <a href="%s/">Data</a></td></tr></tbody>zÃ<tbody class="%s results-table-row"><tr style="background-color: #F8FFF8;"><td class="col-result">%s</td><td>%s</td><td>%s</td><td><a href="%s">Logs</a> / <a href="%s/">Data</a></td></tr></tbody>z–<tbody class="%s results-table-row"><tr style="background-color: #F8FFF8;"><td class="col-result">%s</td><td>%s</td><td>%s</td><td>-</td></tr></tbody>zs<tbody class="%s results-table-row"><tr><td class="col-result">%s</td><td>%s</td><td>%s</td><td>-</td></tr></tbody>z</table>z<br /><b>Last updated:</b> z%s at %sú%sz.<p></p><div><b>Status:</b> Awaiting results...z (Refresh the page for updates)z-<p></p><div><b>Status:</b> Test Run Complete:z# <b>Success!</b> (All tests passed)z# <b>Success!</b> (No failing tests)z All tests were skipped!rÏ  zSee latest logs for detailsz7 <b>1 test failed!</b> --- (<b><a href="%s">%s</a></b>)z9 <b>%s tests failed!</b> --- (<b><a href="%s">%s</a></b>)z</div><p></p>za<p><div>Generated by: <b><a href="https://seleniumbase.io/">SeleniumBase</a></b></div></p><p></p>z1<script type="text/javascript" src="%s"></script>z<html lang="en">zdashboard.html)Jr•  r�   r‘   rD  r  r·   rç  r”  ry  rz  r{  r!   r¾  Z	DASH_JSONr2  rl  r¶   r|  rÂ   rh  r�  Ú_display_idZ	_durationZ_d_t_log_pathZitem_count_passedZitem_count_failedZitem_count_skippedZitem_count_untestedr  Z_extra_dash_entriesr!  rB  r$  r“  rÍ   rX   r  rO   rD   rP   r  r¡  rÃ  rS   rU   rW   rx  rh  rž  rÄ  ri  rY   rÙ  ZTITLErë  Z	STYLE_CSSZMETA_REFRESH_HTMLZ_using_html_reportr   Z_saved_dashboard_pieri  ZDASH_PIErn  ro  Zget_dash_pie_1r  r�   r   Zget_master_timer¯  r°  ZLIVE_JSZ_dash_final_summaryZ
_dash_html)Ar3   rô  r«  Zexisting_resr~  Zdash_json_locZdash_jsonpathr€  Z	dash_jsonZ	dash_dataZd_idZdash_rtZtlpZd_statsZ
num_passedZ
num_failedZnum_skippedZnum_untestedr
  Zlog_dirZft_idZdudZdud2Zduration_msrú  Zalt_test_idr­  Zauto_refresh_htmlZdash_pieZdash_pie_locZpie_pathZpie_fileZDASH_PIE_PNG_1rf  Z
table_htmlZ
the_failedZthe_skippedZthe_passed_hlZthe_passed_nlZthe_untestedrs  Zt_resZt_durZt_d_idZt_l_pathZres_lowÚrowZadd_moreÚ	timestampZthe_dateZthe_timeZlast_updatedrW  Zlatest_logs_dirZlog_msgZgen_byZrefresh_linerm  r  r:  r”  r  Z_rtZ_tlpZdash_json_filer8   r8   r9   Z__process_dashboard?  s`   ÿþýÿ
þý*


ÿþýüûú
ÿþ
ÿ
ÿ
þ
ý



ÿþÿ
ÿþ
ÿÿ




úÿ
ÿ




"ûÿ
üÿ	"ûÿ"ûÿýÿþÿ







þÿþÿÿÿÿÿþýüÿ

zBaseCase.__process_dashboardc                 C   s   ddl }| tjj¡ dS )zAActivate Post Mortem Debug Mode for failing tests that use Behaver   N)ÚpdbÚpost_mortemrD  Úbehave_stepÚexc_traceback©r3   r	  r8   r8   r9   Z(__activate_behave_post_mortem_debug_modeä@  s    z1BaseCase.__activate_behave_post_mortem_debug_modec                 C   s   ddl }| ¡  dS )zAActivate Post Mortem Debug Mode for failing tests that use SB Mgrr   N)r	  r
  r  r8   r8   r9   Z(__activate_sb_mgr_post_mortem_debug_modeë@  s    z1BaseCase.__activate_sb_mgr_post_mortem_debug_modec                 C   s   ddl }| ¡  dS )z!Activate Final Trace / Debug Moder   N)r	  Z	set_tracer  r8   r8   r9   Z!__activate_debug_mode_in_teardownò@  s    z*BaseCase.__activate_debug_mode_in_teardownc                 C   s   |   ¡ S )aÆ  (This method should ONLY be used in custom tearDown() methods.)
        This method returns True if the test failed or raised an exception.
        This is useful for performing additional steps in your tearDown()
        method (based on whether or not the test passed or failed).
        Example use cases:
            * Performing cleanup steps if a test didn't complete.
            * Sending test data and/or results to a dashboard service.
        )rî  r‹   r8   r8   r9   rô  ù@  s    	zBaseCase.has_exceptionc                 C   sŽ   z|   ¡  W n ty    Y dS 0 t| ddƒr6|  ¡  |  ¡ sV| jsVtrLtsVdtj	v rŠ|  
¡  |  ¡  |  ¡  |  ¡ s|| jrŠ| jrŠ|  ¡  dS )aŽ  (Should ONLY be used at the start of custom tearDown() methods.)
        This method takes a screenshot of the active page for FAILING tests
        (or when using "--screenshot" / "--save-screenshot" / "--ss").
        That way your tearDown() method can navigate away from the last
        page where the test failed, and still get the correct screenshot
        before performing tearDown() steps on other pages. If this method
        is not included in your custom tearDown() method, a screenshot
        will still be taken after calling "super().tearDown()" there.
        This method also saves recorded actions when using Recorder Mode.
        NrÇ   r\  )r³   r¿   r·   r�  rî  rÃ  r]  r^  r�   r‘   rë  rì  rí  r•  rè  r‹   r8   r8   r9   Úsave_teardown_screenshotA  s,    ÿþýýüz!BaseCase.save_teardown_screenshotc                 C   sJ   t rtsdtjv sd S |  ¡ }tj | j|¡}t	 
| || j| j| j¡ d S r[  )r]  r^  r�   r‘   r$  ry  rz  r2  rB  r   Úlog_test_failure_datar=   r  r_   )r3   r
  rF  r8   r8   r9   rØ  #A  s     ÿÿþûzBaseCase._log_fail_datac                 C   sR   d }t | dƒr$t | jdƒr$| jj}nt tdƒr4tjS dS d|v rJ|d }nd}|S )Nr=   r  Ú_browser_versionrk  rj  )rÍ   r=   r  rD  r  )r3   Zdriver_capabilitiesZbrowser_versionr8   r8   r9   Ú_get_browser_version3A  s    


zBaseCase._get_browser_versionc                 C   sÞ   t | jdƒs t tdƒrtjS d S | j}d|jv rP|jd }d|d  d¡d fS d|jv rz|jd }d	|d
  d¡d fS |jd  ¡ dkršd|jd fS |jd  ¡ dkr¸d|  ¡ fS |jd  ¡ dkrÖd|  ¡ fS d S d S )Nr  Ú_driver_name_versionr  Zchromedriverrs  re  r   rg  Zmsedgedriverrv  rh  rú   Zgeckodriverzmoz:geckodriverVersionrê   Zsafaridriverzinternet explorerZiedriver)rÍ   r=   rD  r  r  rž  r  r  )r3   r=   Zcap_dictr8   r8   r9   Ú_get_driver_name_and_versionAA  s*    


ÿ

ÿ
ÿz%BaseCase._get_driver_name_and_versionc                 C   s   t | jjƒS r.   )r  r=   r  r‹   r8   r8   r9   Ú_get_num_handles]A  s    zBaseCase._get_num_handlesc                 C   s   dS )NaÍ  document.onkeydown = function(evt) {
                evt = evt || window.event;
                var isEscape = false;
                if ("key" in evt) {
                    isEscape = (evt.key === "Escape" || evt.key === "Esc");
                    last_key = evt.key;
                } else {
                    isEscape = (evt.keyCode === 27);
                    last_key = evt.keyCode;
                    if (last_key === 16) {
                        last_key = "Shift";
                    }
                }
                if (isEscape && document.sb_last_key === "Shift") {
                    document.sb_esc_end = "yes";
                }
                document.sb_last_key = last_key;
            };r8   r‹   r8   r8   r9   Ú_get_rec_shift_esc_script`A  s    ÿz"BaseCase._get_rec_shift_esc_scriptc                 C   sD   t |ddƒ}|dur |||ƒ n ddl}| dtd¡ | |¡ dS )ú5This method should NOT be called directly from tests.ÚaddSkipNr   z5TestResult has no addSkip method! Skips not reported!r¾  )r·   rÎ  ÚwarnÚRuntimeWarningÚ
addSuccess)r3   r„  Z	test_caser–  r  rÎ  r8   r8   r9   Ú_addSkipvA  s    þzBaseCase._addSkipc                 C   s
   |ƒ  dS )r  Nr8   )r3   ri  r8   r8   r9   Ú_callTestMethodƒA  s    zBaseCase._callTestMethodc              	      sä  t stƒ j|d�S |du rJ|  ¡ }t|ddƒ}t|ddƒ}|durN|ƒ  nd}| | ¡ �zht| | jƒ}t| jddƒs‚t|ddƒrÈt| jddƒpšt|ddƒ}|  || |¡ |W | 	| ¡ |durÆ|ƒ  S t| d	dƒpÞt|d	dƒ}t
 |¡}�z || _| | ¡� |  ¡  W d  ƒ n1 �s0    Y  |j�rª||_|j| d
d�� |  |¡ W d  ƒ n1 �sf0    Y  d|_| | ¡� |  ¡  W d  ƒ n1 �s 0    Y  |  ¡  |jD ]\}}	|  |||	¡ �q¸|jD ]@\}}
|
du�rØt|
d | jƒ�r
| ||
¡ n| ||
¡ �qØ|j�rV|�rL|j�r@|  ||j¡ n
|  |¡ n
| | ¡ |W |j ¡  d|_d| _W | 	| ¡ |du�rŒ|ƒ  S |j ¡  d|_d| _0 W | 	| ¡ |du�rà|ƒ  n| 	| ¡ |du�rÞ|ƒ  0 dS )z{Overwrite the unittest run() method for Python 3.11 or newer.
        This method should NOT be called directly from tests.)r„  NÚstartTestRunÚstopTestRunZ__unittest_skip__FZ__unittest_skip_why__rd  Z__unittest_expecting_failure__T)ZisTestr   )r]  r/   ÚrunZdefaultTestResultr·   Z	startTestr  r7   r  ZstopTestr'   Z_Outcomerâ  ZtestPartExecutorZ
_callSetUpræ  Úexpecting_failurer  Z_callTearDownZ
doCleanupsZskippedrƒ  Ú
issubclassZfailureExceptionZ
addFailureZaddErrorZexpectedFailureZ_addExpectedFailureZ_addUnexpectedSuccessr  rV  )r3   r„  r  r  Z
testMethodZskip_whyr   ÚoutcomeÚtestr–  r�  r6   r8   r9   r  ‡A  sš    
ÿ
þ
þ*
Ô
þ
(*(
ÿ

ü

ø   þ



þ

zBaseCase.runc               
   C   sÒ	  t | dƒs| jrdS t| ddƒrŒt | j¡ z|  ¡  W nR tyŠ } z:tdƒ t |dƒrntdt	|j
ƒ ƒ nt|ƒ W Y d}~n
d}~0 0 d| _d| _z| j}|rª| j}W n¾ t�yj   t	| jjd	 ƒ d
¡d  d¡d	 }t	| jjd	 ƒ d
¡d }|d }t	| jƒ d
¡d  d¡d	 }t	| jƒ d
¡d d }|}|}	|dk�rR|}|}	d||	f }
t|
ƒ‚Y n0 t | j¡ |  ¡  |  ¡ }|t_|  ¡ t_|  ¡ t_| j�rÖtj�rÖtj�rÖtjt_tjt_dt_d| _d}| j �r6tdƒ |�s*z|  !¡  W n* t�y& } z|}W Y d}~n
d}~0 0 n| j!dd� | j�rf|  "¡ }|�r¾|�rf|  #¡  dt_dt_$| j%�rØ|�sØ| j&�rØt'j( )| j*|¡}|  +|¡ | j,�s¶|  -¡  |  .¡  |  /¡  t0 1|| j| j,¡ |  #¡  dt_$n6t2�rät3�sðdt4j5v �r|�s|  -¡  |  .¡  |  /¡  | j%�r |�r t'j( )| j*|¡}|  +|¡ | j6�s¬| j7�s¬| j8�s¬| j,�sn|  -¡  |  .¡  |  /¡  t0 1|| j| j,¡ t0 9| || j| j:| j;¡ t0 <|| j| j=¡ nt| j6�ræ| j,�sÔ|  -¡  |  .¡  |  /¡  t0 1|| j| j,¡ | j7�rt0 9| || j| j:| j;¡ | j8�r t0 <|| j| j=¡ | j>�r¦| j?�rœ| j@�R tAtƒ� tB CtDjEjF¡ W d  ƒ n1 �sf0    Y  |  G|¡ W d  ƒ n1 �s�0    Y  n
|  G|¡ | jH�r¶|  I¡  |  J¡  | jK�rN|�rÞ|  LtDjMjNd¡ nJ|  O¡ }|tjP Q¡ v �rtjP| dk�r|  LtDjMjRd¡ n|  LtDjMjSd¡ tTtU U¡ d ƒ| jV }| jW X| jY|¡ | jZ�rÖ|�rÖd	dl[}d	dl\m]} |ƒ }t	| ^¡ j_ƒ}t'j( )| j*|¡}g }t' `|¡D ]B}d||| |¡d f }| a|dt'j( )||¡ ¡ | b|¡ �q¢| c|¡ | d||| je| jf¡}td| ƒ tg hd| ¡ | jK�rÖd	dlimj}mk} || jlƒ| _W|ƒ }| jm|_n||_o| jW p|¡ �npt| ddƒ�rtjqjrjsdk�rÎd}dt_d}tt�rÄtujvjwtujxjy }tujzj{}| |d|d | ¡}t|ƒ n>d }tt�rtujvj}tujxj~ }tujzj{}| |d!|d" | ¡}t|ƒ | j>�r|  G|¡ |�r´|  "¡ }t'j( )| j*|¡}|  +|¡ t0 9| || j| j:| j;¡ t| j€ƒd	k�r| j,�sŽ|  -¡  |  .¡  |  /¡  t0 1|| j| j,¡ t0 <|| j| j=¡ n\| j&�r|  "¡ }t'j( )| j*|¡}|  +|¡ | j,�sþ|  -¡  |  .¡  |  /¡  t0 1|| j| j,¡ | j��rJ| j,| _‚z|  ƒ¡ | _„W n t�yH   d#| _„Y n0 t| ddƒ�rŽ|�rŽttd$dƒ�rŽt td%ƒ�rŽt tj…d&ƒ�rŽ|  †¡  | jH�r |  I¡  n.ttd'dƒ�r¸|  ‡¡  nttd(dƒ�rÎ|  I¡  |  J¡  t| d)dƒ�	r<| jˆ�	s<z(t | j‰d*ƒ�	r| j‰ Š¡  d| _‰d| _‹W n& tŒ�	y(   Y n t�	y:   Y n0 ttd+dƒ�	r¨t tj�d*ƒ�	r¨ttd,dƒ�	s¨ztj� Š¡  dt_�dt_‹W n& tŒ�	y”   Y n t�	y¦   Y n0 | jŽ�	rÄdt_�|�	rÄ|  �¡  |�	rÎ|‚dS )-zÓThis method runs after every test completes.
        Be careful if a subclass of BaseCase overrides setUp().
        If so, add the following line to the subclass's tearDown() method:
        super().tearDown() rø  NrÇ   z'
 (Recorder) Code-generation exception:r¨   rN  TFr   rw  rû   rã  rú  r	  r)   ab  You're overriding SeleniumBase's BaseCase setUp() method with your own setUp() method, which breaks SeleniumBase. You can fix this by going to your %s class located in %s, and adding the following line AT THE BEGINNING of your setUp() method:
super().setUp()

Also make sure the following line is AT THE END of your tearDown() method:
super().tearDown()
z¨
When using self.deferred_assert_*() methods in your tests, remember to call self.process_deferred_asserts() afterwards. Now calling in tearDown()...
Failures Detected:rž  r\  r�  r:   )ÚS3LoggingBucketz%s/%s/%sr  z 
*** Log files uploaded: ***
%s
)r¨  r©  r   Úfailedu4      â�Œ Scenario Failed!  (Skipping remaining steps:)u   â�Œz><u      âœ… Scenario Passed!u   âœ…z<>z(Error: Unknown URL)Z
pdb_optionr  r  Z_do_sb_post_mortemZ_do_sb_final_tracerˆ   Ústopr€  r½  )‘rÍ   rN   r·   r$   ræ  r=   Ú#_BaseCase__process_recorded_actionsr¿   rµ  rÁ   r¨   rM   r•  r¶  r7   Ú	__bases__rž  r+  rî  rD  Z_has_exceptionr  r  r  r  rg   rŠ  r‹  r   rÿ   rT  rˆ  rj   r“  r$  rè  rE  r·  rÃ  ry  rz  r2  rB  rC  r^   rë  rì  rí  r   Zlog_screenshotr]  r^  r�   r‘   r¹  r¸  rº  r  r  r_   Zlog_page_sourcer`   r’  rç  rÀ  r   r&   rÖ  r!   r¾  r¿  rÛ  r|   Ú*_BaseCase__activate_debug_mode_in_teardownÚ_BaseCase__quit_all_driversr‘  Ú_BaseCase__insert_test_resultrÓ  ZFAILEDr“  r”  r!  ZSKIPPEDZPASSEDrO   rD   rÌ  rÎ  Zupdate_execution_datarÊ  r»  rÇ  Zseleniumbase.core.s3_managerr$  rÉ  Úhexr  Zupload_filer�   Zsave_uploaded_file_namesZupload_index_filerÕ  rZ  r¸   r¹   rÈ  r¨  r©  r¼  rË  rÏ  ZlogURLZupdate_testcase_log_urlr!  rW  r”   r`  r¯  r°  r,  r±  r.  r³  r´  ri  ZGREENr²  r  r~   rÅ  rz   r„  r{   r  Ú1_BaseCase__activate_behave_post_mortem_debug_modeÚ1_BaseCase__activate_sb_mgr_post_mortem_debug_moderS  rˆ   r&  r  rV  r€  rZ   Z_visual_baseline_copiesr_  ) r3   rà   r•  r¶  Zsub_class_nameZsub_file_nameÚ
class_namerX  Zclass_name_usedZfile_name_usedrâ   rô  Zdeferred_exceptionr
  rF  rä  rÇ  r$  Z	s3_bucketrÏ  rz  Zuploaded_filesZlogfileZlogfile_nameZ
index_filer¨  r©  rÜ  r¨   r¸  rº  r¹  r8   r8   r9   ÚtearDownÎA  sl   

"ÿ
øÿ

ÿÿþý
ýþþýû
ÿþýýû
ÿýûý
ÿ$,
ÿÿÿÿýÿ
ÿÿ


ûý
ÿ

ÿÿ
þ




ÿ
þ
ý

zBaseCase.tearDownc                 C   s   t  ¡  d S r.   ©r   Z"end_reused_class_session_as_neededr‹   r8   r8   r9   Ú
setUpClass.C  s    zBaseCase.setUpClassc                 C   s   t  ¡  d S r.   r1  r‹   r8   r8   r9   ÚtearDownClass4C  s    zBaseCase.tearDownClass)rå   Nr   T)rå   N)rå   N)rå   N)rå   Nr   )rå   NF)rå   N)rå   NF)rå   N)rå   N)rå   )rå   N)rå   N)rå   )rå   )rå   )rå   )r¨  rå   )r¨  rå   )r¨  rå   )Nrå   )T)T)T)N)N)r¨  rå   N)rå   NT)rå   NF)rå   )rå   )rå   N)rå   )rå   N)rå   N)r¨  rå   N)rå   N)rå   N)rå   r   )rå   r   )rå   r   NT)rå   NT)rå   r   T)rå   NNNT)rå   NNNT)rå   N)rå   N)rå   )rå   )rå   )rå   )rå   )rå   )rå   N)rå   rå   NF)rå   rå   N)rå   rå   N)rå   rå   NF)rå   N)rå   r]  N)rå   N)rå   N)rå   N)r]  rå   N)T)F)T)N)rå   )rå   )r.  NF)N)N)F)F)T)N)8NNNNNNNNNNNTNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN)NNrå   )NNrå   )N)N)N)N)N)N)r]  )r]  F)r]  )r]  )F)F)N)N)N)N)rå   )rå   r,   TN)rå   r,   TN)rå   r,   TN)rå   r–  T)NT)rå   NT)rå   NTN)rå   NTr   )r¨  r�   rå   )r¨  r�   rå   )r¨  r�   rå   )r¨  r�   rå   )rå   N)rå   N)rå   N)rå   N)rå   N)rz  )rz  )rå   FNT)rå   r   )rå   r   )rå   N)rå   N)rå   N)rå   )rå   )rå   )rå   )rå   )rå   )N)Fr�  F)TN)NNNrc  FFFT)NNNrc  TFFT)rå   N)Nrd  )N)N)N)N)N)N)NF)F)NF)F)F)F)F)NF)NF)NF)N)N)N)N)N)N)Nrå   N)Nrå   N)N)Nrå   N)rå   NT)rå   N)rå   N)rå   N)rå   NF)rå   N)rå   N)rå   N)r�  )rd  )T)N)N)rå   NF)rå   NF)rå   NF)N)N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   r   )N)rå   N)N)N)N)Nrå   N)T)NN)rò  rò  rò  )NTr¹   )rå   )NT)NT)N)r�   N)r�   )rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)N)N)N)N)N)N)N)N)N)rå   N)rå   N)rå   N)rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)r¨  rå   N)Nrå   N)Nrå   N)N)N)N)N)N)N)N)rò  r   FTF)F)rå   NF)rå   NF)r¨  rå   NF)r¨  rå   NF)r¨  rå   NF)rò  r   FTFF)F)rå   NF)rå   NF)r¨  rå   NF)r¨  rå   NF)r¨  rå   NF)rò  r   FTFF)F)Nrò  rò  )NNNNNNNN)NNFr   )NNFr   )NNNNNTTT)NNNNNTTT)NNNNNTTT)	NNNNNFTTT)	NNNNNFTTT)
NNNNNNFTTT)NN)NN)NNN)NNr   )N)NN)NN)N)N)N)N)NN)NNNNNN)NNNNN)NNNNN)NNNN)NNNN)NNNN)Nr   )Nr   )Nr7  N)NN)N)NN)N)rå   )rå   )rå   FNNNT)rå   )rå   )T)T)T)F)Nrå   )rå   )NF)T)N)NN)F)F)F)N(G  r  r'  Ú__qualname__Ú__doc__r0   r1   Úclassmethodr˜   r¶   rÌ   r  r6  r:  rE  rL  r`  rj  r  rX  rp  rt  rV  rx  r~  r}  r„  rÉ   r‡  r†  r‹  rŠ  rŒ  r�  r�  r“  rš  rŸ  r   r£  r"  r§  rª  r­  r°  r²  r  r
  rÁ  rÂ  rÇ  rÈ  rÌ  r  r  rï  r  rø  rú  rû  rü  rý  rÿ  r  rñ  r  r  r  r	  r  r  r  r  rf  r  r  r"  r%  r)  r+  r,  r-  r6  r7  r8  r<  rD  rF  rH  rI  r  rU  rT  rW  rX  r_  rr  rs  r�  r‚  rˆ  rÈ   r‰  rŒ  rG  rŽ  r‘  rš  r›  r•  rœ  r�  rŸ  r¡  r£  r¦  r¥  r¨  r§  r©  r3  r4  r”  r   r¿  r´  r¸  rÆ  rÇ  rÈ  rË   r  rÏ  rË  rÏ   r6  r7  r<  rH  rK  rO  rS  rZ  r\  rR  rs  r|  r~  r€  rx  r‚  rg  rƒ  ry  r†  r,  rþ   rÔ   r'  r¾   r˜  r�  r›  r�  rŸ  r   rº   r¼  rF  r�  rÀ  r'  r/  r4  rC  rF  rI  rJ  rK  rb  rE  ra  rc  rg  rh  ri  rj  rv  rn  rl  rp  rk  rq  rt  rv  ry  r|  r  r�  r   rŠ  r‹  r�  r!  r�  r•  r˜  rš  r›  r�  rŸ  r¢  r¤  r¥  rÊ   r  r»  r¨  r«  r¯  r·  rÀ  rÁ  rÝ  rY  rå  ræ  rç  rè  rû  rÙ  r  r  r	  r
  rI  rØ  r  r  r   r$  r%  r'  r*  r+  r#  r2  r5  r9  r:  r?  r@  rB  rC  rD  rH  rM  rO  rP  rR  rT  r�  r_  rc  rÄ   re  rf  r¤  r+  rl  rp  rn  rr  r  rw  rx  r{  r|  r~  r<  r\  r€  r�  rƒ  r‚  r„  r…  r†  r‡  r‰  rŒ  r¸  r‰  r˜  rš  r›  r�  rŸ  r   r£  r¦  r§  r©  rª  r¬  rG  r­  r¯  r®  r°  r²  rµ  r¶  r·  r¸  r¹  r|  r»  rÊ  rÌ  r¼  r¶  r½  rì  rñ  r&  rÕ  rÂ  rÃ  r9  r:  rÆ  r  r  rÌ  rÒ  rÕ  rÖ  r×  r  rÙ  rÚ  rÝ  rÞ  rß  rà  rá  râ  rã  rä  r§  rå  r¼   ré  rê  r×   rì  rí  rh  rð  rñ  rö  r·  rû  rþ  rÿ  r  r  r  r  rg  r^  rã   r	  r
  r  r  r  rÔ  r  r  r  r  r  r  r   r  r#  r%  r&  r'  r(  r*  r)  r2  r9  rÖ  rç  rØ  r<  r=  rØ  rè  r?  r@  rË  rA  rB  rC  rD  rE  rG  rH  rI  rJ  rK  rM  rN  rO  rP  rQ  rW  r|  r`  r_  r€  r  r´   r³   rƒ  r‡  r‰  rŠ  rŒ  r�  rŽ  r�  r“  r–  r—  rš  r›  rœ  r�  rŸ  r³  r¹  rË  rÌ  rÙ  rÛ  rÝ  rá  râ  r×  rè  rë  rþ  rÿ  r   r  r  r  r
  r  r	  r  r+  r*  r&  r'  r(  r)  r5  r6  r8  r9  rG  rH  rX  r\  r]  Z_BaseCase__are_quotes_escapedr?  r“  r#  r…  r†  r  r×  r  rq  rÞ  rß  ré  rê  r  rÃ   rÛ  r%  r½   rÚ   r+  Z%_BaseCase__demo_mode_scroll_if_activer  r  rÙ  r\  rP  rÜ  rw  rv  rx  rº  r†  r‹  rÚ  r)  r*  r   Ú
deprecatedrŽ  rÇ  r’  r  r  rU  ru  rð  ró  r  r  r  r.  r3  r7  r¡  r¤  r¥  r¦  r«  r®  r¯  r³  r  rÉ  rG  r  r  rÝ  rë  rì  rí  ræ  r+  r×  rè  rñ  r*  rî  r$  r“  rx  r  rC  rÖ  rÛ  r-  r.  r)  rô  r  rØ  r  r  r  r  r  r  r  r0  r2  r3  Ú__classcell__r8   r8   r6   r9   r)   j   sP  O
  %ÿ
  PZÿ
ÿ
 Qÿ
2.(


ÿ
ÿ
 p-  ú
8  ù
*%	ÿ
ÿ
"ÿ
ÿ
*ÿ
aÿ
@ÿ
2    ÷
"    ÷
##0!   ù
t  ú
  ú
X   ù
9ÿ
  ú
  û
 û
 û
  û
)h(
#		DHV                                                       Ç   Pÿ#ÿ4#"
#       6ÿ   ù   ùÿ!ÿQ   ú*   ú$ÿ   ú ")&"$  û;
       öf       õ?ÿQÿD		)	@9ÿ
ÿÿ:12&)l7	ÿÿ]ÿ-ÿ1
'

ÿÿÿÿÿÿ?@
ÿÿ
		ÿ!	(ÿ
ÿÿÿ29ÿ>ÿÿÿÿÿÿÿÿÿÿÿWÿ0ÿ)		
ÿÿÿÿÿÿÿÿÿ
L.(    ú  8ÿ$ÿ$ÿ%ÿ(   û+     ù"ÿ	ÿ	ÿ	ÿ
   û     ùÿj       ÷lÿWÿ=       ÷.       ÷.       ÷.        ö1        ö1         õ  394&,:"     øe    ùB    ù5ÿ0ÿ%ÿAF>IE5"     ö -.
	 	ÿAT	ÿ|		""	ÿ+    WR")5#  gG  b)Wr5  r¯  rÒ  rh  r¸   r–  ry  r=  ra  r�   rå  rD   rz  r+   Ú
contextlibr   r   Zselenium.common.exceptionsr   rÝ  r   r  r   r   r   r	   r
   r  r   r   Z'selenium.webdriver.common.action_chainsr   Zselenium.webdriver.common.byr   Zselenium.webdriver.common.keysr   Z+selenium.webdriver.remote.remote_connectionr   Z$selenium.webdriver.remote.webelementr   Zseleniumbaser   rD  Zseleniumbase.__version__r   Zseleniumbase.commonr   Zseleniumbase.common.exceptionsr   r   r   r   r   r   r¡  r   r  r   r   r   r   r    Zseleniumbase.fixturesr!   r"   r#   r$   r%   r&   r'   r(   Ú__all__rÚ  rÛ  rÜ  ÚCRITICALÚdisable_warningsÚWARNINGr®  r`  r]  rC   Z
PatchPy311ÚPATCHr^  r{  r)   r8   r8   r8   r9   Ú<module>   st  ",                                                                                                                                       W