Skip to content

Commit c63bd7a

Browse files
authored
Merge pull request #4137 from seleniumbase/cdp-mode-patch-81
CDP Mode: Patch 81
2 parents 5aaeb39 + 80f491b commit c63bd7a

File tree

12 files changed

+220
-13
lines changed

12 files changed

+220
-13
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import mycdp
2+
from seleniumbase import sb_cdp
3+
4+
sb = sb_cdp.Chrome()
5+
tab = sb.get_active_tab()
6+
loop = sb.get_event_loop()
7+
loop.run_until_complete(
8+
tab.send(
9+
mycdp.emulation.set_device_metrics_override(
10+
width=411, height=731, device_scale_factor=3, mobile=True
11+
)
12+
)
13+
)
14+
url = "https://gitlab.com/users/sign_in"
15+
sb.open(url)
16+
sb.sleep(2)
17+
sb.solve_captcha()
18+
# (The rest is for testing and demo purposes)
19+
sb.assert_text("Username", '[for="user_login"]', timeout=3)
20+
sb.assert_element('label[for="user_login"]')
21+
sb.highlight('button:contains("Sign in")')
22+
sb.highlight('h1:contains("GitLab")')
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import asyncio
2+
import mycdp
3+
import time
4+
from seleniumbase import cdp_driver
5+
from seleniumbase import decorators
6+
7+
8+
async def main():
9+
url = "https://gitlab.com/users/sign_in"
10+
driver = await cdp_driver.start_async()
11+
await driver.main_tab.send(
12+
mycdp.emulation.set_device_metrics_override(
13+
width=411, height=731, device_scale_factor=3, mobile=True
14+
)
15+
)
16+
page = await driver.get(url, lang="en")
17+
time.sleep(3)
18+
try:
19+
element = await page.select('[style*="grid"] div div', timeout=1)
20+
await element.mouse_click_with_offset_async(32, 28)
21+
except Exception:
22+
pass # Maybe CAPTCHA was already bypassed
23+
element = await page.select('label[for="user_login"]')
24+
await element.flash_async(duration=1.5, color="44EE44")
25+
time.sleep(1)
26+
element = await page.select('[data-testid="sign-in-button"]')
27+
await element.flash_async(duration=2, color="44EE44")
28+
time.sleep(2)
29+
30+
if __name__ == "__main__":
31+
# Call an async function with awaited methods
32+
loop = asyncio.new_event_loop()
33+
with decorators.print_runtime("raw_mobile_async.py"):
34+
loop.run_until_complete(main())
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import mycdp
2+
from seleniumbase import SB
3+
4+
with SB(uc=True, test=True) as sb:
5+
url = "https://gitlab.com/users/sign_in"
6+
sb.activate_cdp_mode()
7+
tab = sb.cdp.get_active_tab()
8+
loop = sb.cdp.get_event_loop()
9+
loop.run_until_complete(
10+
tab.send(
11+
mycdp.emulation.set_device_metrics_override(
12+
width=411, height=731, device_scale_factor=3, mobile=True
13+
)
14+
)
15+
)
16+
sb.open(url)
17+
sb.sleep(2)
18+
sb.solve_captcha()
19+
# (The rest is for testing and demo purposes)
20+
sb.assert_text("Username", '[for="user_login"]', timeout=3)
21+
sb.assert_element('label[for="user_login"]')
22+
sb.highlight('button:contains("Sign in")')
23+
sb.highlight('h1:contains("GitLab")')
24+
sb.post_message("SeleniumBase wasn't detected", duration=4)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import mycdp
2+
from seleniumbase import SB
3+
4+
with SB(uc=True, test=True) as sb:
5+
url = "https://www.roblox.com/"
6+
agent = (
7+
"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 "
8+
"(KHTML, like Gecko) Mobile Safari/537.36"
9+
)
10+
sb.activate_cdp_mode(agent=agent)
11+
tab = sb.cdp.get_active_tab()
12+
loop = sb.cdp.get_event_loop()
13+
loop.run_until_complete(
14+
tab.send(
15+
mycdp.emulation.set_device_metrics_override(
16+
width=411, height=731, device_scale_factor=3, mobile=True
17+
)
18+
)
19+
)
20+
sb.open(url)
21+
sb.assert_element("#download-the-app-container")
22+
sb.assert_text("Roblox for Android")
23+
sb.highlight('span:contains("Roblox for Android")', loops=8)
24+
sb.highlight('span:contains("Continue in App")', loops=8)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Test Stop & Shop search. Non-US IPs might be blocked."""
2+
from seleniumbase import SB
3+
4+
with SB(uc=True, test=True, guest=True, ad_block=True) as sb:
5+
url = "https://stopandshop.com/"
6+
sb.activate_cdp_mode(url)
7+
sb.sleep(2.6)
8+
if not sb.is_element_present("#brand-logo_link"):
9+
sb.refresh()
10+
sb.sleep(2.6)
11+
sb.wait_for_element("#brand-logo_link", timeout=3)
12+
query = "Fresh Turkey"
13+
required_text = "Turkey"
14+
search_box = 'input[type="search"]'
15+
sb.wait_for_element(search_box)
16+
sb.sleep(1.2)
17+
sb.press_keys(search_box, query)
18+
sb.sleep(1.2)
19+
sb.click("button.search-btn")
20+
sb.sleep(3.2)
21+
print('*** Stop & Shop Search for "%s":' % query)
22+
print(' (Results must contain "%s".)' % required_text)
23+
print(' (Results cannot contain "Out of Stock")')
24+
unique_item_text = []
25+
item_selector = "div.product-tile_content"
26+
items = sb.find_elements(item_selector)
27+
for item in items:
28+
sb.sleep(0.06)
29+
if "Out of Stock" not in item.text:
30+
if required_text in item.text:
31+
item.flash(color="44CC88")
32+
sb.sleep(0.025)
33+
if item.text not in unique_item_text:
34+
unique_item_text.append(item.text)
35+
print("* " + item.text)

mkdocs_build/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Minimum Python version: 3.10 (for generating docs only)
33

44
regex>=2025.11.3
5-
pymdown-extensions>=10.17.1
5+
pymdown-extensions>=10.17.2
66
pipdeptree>=2.30.0
77
python-dateutil>=2.8.2
88
Markdown==3.10

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.44.18"
2+
__version__ = "4.44.19"

seleniumbase/core/browser_launcher.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,6 +1486,10 @@ def _uc_gui_click_captcha(
14861486
'[data-callback="onCaptchaSuccess"]'
14871487
):
14881488
frame = '[data-callback="onCaptchaSuccess"]'
1489+
elif driver.is_element_present(
1490+
"div:not([class]) > div:not([class])"
1491+
):
1492+
frame = "div:not([class]) > div:not([class])"
14891493
else:
14901494
return
14911495
if (
@@ -1829,6 +1833,10 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
18291833
frame = ".cf-turnstile-wrapper"
18301834
elif driver.is_element_present('[class="cf-turnstile"]'):
18311835
frame = '[class="cf-turnstile"]'
1836+
elif driver.is_element_present(
1837+
"div:not([class]) > div:not([class])"
1838+
):
1839+
frame = "div:not([class]) > div:not([class])"
18321840
else:
18331841
return
18341842
else:
@@ -3048,6 +3056,11 @@ def get_driver(
30483056
if _special_binary_exists(binary_location, "atlas"):
30493057
driver_dir = DRIVER_DIR_ATLAS
30503058
sb_config._cdp_browser = "atlas"
3059+
if undetectable and mobile_emulator:
3060+
# For stealthy mobile mode, see the CDP Mode examples
3061+
# to learn how to properly configure it.
3062+
user_agent = None # Undo the override
3063+
mobile_emulator = False # Instead, set from CDP Mode
30513064
if (
30523065
hasattr(sb_config, "settings")
30533066
and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)

seleniumbase/core/sb_cdp.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,10 @@ def __click_captcha(self, use_cdp=False):
20302030
'[data-callback="onCaptchaSuccess"]'
20312031
):
20322032
selector = '[data-callback="onCaptchaSuccess"]'
2033+
elif self.is_element_present(
2034+
"div:not([class]) > div:not([class])"
2035+
):
2036+
selector = "div:not([class]) > div:not([class])"
20332037
else:
20342038
return
20352039
if not selector:

seleniumbase/fixtures/base_case.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10136,6 +10136,21 @@ def assert_element(self, selector, by="css selector", timeout=None):
1013610136
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
1013710137
timeout = self.__get_new_timeout(timeout)
1013810138
if self.__is_cdp_swap_needed():
10139+
if self.demo_mode:
10140+
selector, by = self.__recalculate_selector(
10141+
selector, by, xp_ok=False
10142+
)
10143+
a_t = "ASSERT"
10144+
if self._language != "English":
10145+
from seleniumbase.fixtures.words import SD
10146+
10147+
a_t = SD.translate_assert(self._language)
10148+
messenger_post = "<b>%s %s</b>: %s" % (
10149+
a_t, by.upper(), selector
10150+
)
10151+
self.__highlight_with_assert_success(
10152+
messenger_post, selector, by
10153+
)
1013910154
self.cdp.assert_element(selector, timeout=timeout)
1014010155
return True
1014110156
if isinstance(selector, list):
@@ -10430,6 +10445,20 @@ def assert_text(
1043010445
messenger_post, selector, by
1043110446
)
1043210447
elif self.__is_cdp_swap_needed():
10448+
if self.demo_mode:
10449+
a_t = "ASSERT TEXT"
10450+
i_n = "in"
10451+
if self._language != "English":
10452+
from seleniumbase.fixtures.words import SD
10453+
10454+
a_t = SD.translate_assert_text(self._language)
10455+
i_n = SD.translate_in(self._language)
10456+
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
10457+
a_t, text, i_n, by.upper(), selector
10458+
)
10459+
self.__highlight_with_assert_success(
10460+
messenger_post, selector, by
10461+
)
1043310462
self.cdp.assert_text(text, selector, timeout=timeout)
1043410463
return True
1043510464
elif self.__is_shadow_selector(selector):

0 commit comments

Comments
 (0)