mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
feat: make patchright optional, default to stock playwright
This commit is contained in:
@@ -6,6 +6,10 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.3.9] — 2026-03-05
|
||||||
|
|
||||||
|
- **[wrapper]** Default Playwright backend switched from `patchright` to stock `playwright`. Patchright broke proxy auth and `add_init_script` (#27) and is redundant since the binary handles stealth at C++ level. Opt in with `launch(backend="patchright")` or `CLOAKBROWSER_BACKEND=patchright` env var. Install: `pip install cloakbrowser[patchright]`
|
||||||
|
|
||||||
## [0.3.7] — 2026-03-05
|
## [0.3.7] — 2026-03-05
|
||||||
|
|
||||||
- **[wrapper]** Unify timezone parameter: rename `timezone_id` to `timezone` in `launch_context()`, `launch_persistent_context()`, and `launch_persistent_context_async()` (Python). Old `timezone_id` still works with a deprecation warning. JS: deprecate `timezoneId` on `LaunchContextOptions` — use `timezone` (inherited from `LaunchOptions`)
|
- **[wrapper]** Unify timezone parameter: rename `timezone_id` to `timezone` in `launch_context()`, `launch_persistent_context()`, and `launch_persistent_context_async()` (Python). Old `timezone_id` still works with a deprecation warning. JS: deprecate `timezoneId` on `LaunchContextOptions` — use `timezone` (inherited from `LaunchOptions`)
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ See the full [CHANGELOG.md](CHANGELOG.md) for details.
|
|||||||
|
|
||||||
- **Config-level patches break** — `playwright-stealth`, `undetected-chromedriver`, and `puppeteer-extra` inject JavaScript or tweak flags. Every Chrome update breaks them. Antibot systems detect the patches themselves.
|
- **Config-level patches break** — `playwright-stealth`, `undetected-chromedriver`, and `puppeteer-extra` inject JavaScript or tweak flags. Every Chrome update breaks them. Antibot systems detect the patches themselves.
|
||||||
- **CloakBrowser patches Chromium source code** — fingerprints are modified at the C++ level, compiled into the binary. Detection sites see a real browser because it *is* a real browser.
|
- **CloakBrowser patches Chromium source code** — fingerprints are modified at the C++ level, compiled into the binary. Detection sites see a real browser because it *is* a real browser.
|
||||||
- **Two layers of stealth** — C++ patches handle fingerprints (GPU, screen, UA, hardware reporting), while the Patchright driver defers Playwright's binding registration and randomizes internal world names. Most stealth tools only do one or the other.
|
- **Source-level stealth** — C++ patches handle fingerprints (GPU, screen, UA, hardware reporting) at the binary level. No JavaScript injection, no config-level hacks. Most stealth tools only patch at the surface.
|
||||||
- **Same behavior everywhere** — works identically local, in Docker, and on VPS. No environment-specific patches or config needed.
|
- **Same behavior everywhere** — works identically local, in Docker, and on VPS. No environment-specific patches or config needed.
|
||||||
- **Works with any browser automation framework** — tested and passing stealth checks with Playwright, Puppeteer, Selenium, undetected-chromedriver, browser-use, Crawl4AI, and agent-browser. Just point any Chromium-based framework at the binary path.
|
- **Works with any browser automation framework** — tested and passing stealth checks with Playwright, Puppeteer, Selenium, undetected-chromedriver, browser-use, Crawl4AI, and agent-browser. Just point any Chromium-based framework at the binary path.
|
||||||
|
|
||||||
@@ -648,7 +648,7 @@ xattr -cr ~/.cloakbrowser/chromium-*/Chromium.app
|
|||||||
**"playwright install" vs CloakBrowser binary**
|
**"playwright install" vs CloakBrowser binary**
|
||||||
You do NOT need `playwright install chromium`. CloakBrowser downloads its own binary. You only need Playwright's system deps:
|
You do NOT need `playwright install chromium`. CloakBrowser downloads its own binary. You only need Playwright's system deps:
|
||||||
```bash
|
```bash
|
||||||
patchright install-deps chromium
|
playwright install-deps chromium
|
||||||
```
|
```
|
||||||
|
|
||||||
**macOS: Blocked on some sites that pass on Linux**
|
**macOS: Blocked on some sites that pass on Linux**
|
||||||
@@ -699,6 +699,7 @@ await new Promise(r => setTimeout(r, 3000));
|
|||||||
```
|
```
|
||||||
|
|
||||||
Other tips for maximizing reCAPTCHA scores:
|
Other tips for maximizing reCAPTCHA scores:
|
||||||
|
- **Try the Patchright backend** — suppresses CDP automation signals that reCAPTCHA Enterprise detects. Install with `pip install cloakbrowser[patchright]`, then use `launch(backend="patchright")` or set `CLOAKBROWSER_BACKEND=patchright` globally. Note: Patchright breaks proxy auth and `add_init_script` — only use it when you need the extra CDP stealth
|
||||||
- **Use Playwright, not Puppeteer** — Puppeteer sends more CDP protocol traffic that reCAPTCHA detects ([details](#puppeteer))
|
- **Use Playwright, not Puppeteer** — Puppeteer sends more CDP protocol traffic that reCAPTCHA detects ([details](#puppeteer))
|
||||||
- **Use residential proxies** — datacenter IPs are flagged by IP reputation, not browser fingerprint
|
- **Use residential proxies** — datacenter IPs are flagged by IP reputation, not browser fingerprint
|
||||||
- **Spend 15+ seconds on the page** before triggering reCAPTCHA — short visits score lower
|
- **Spend 15+ seconds on the page** before triggering reCAPTCHA — short visits score lower
|
||||||
|
|||||||
+59
-6
@@ -57,6 +57,7 @@ def launch(
|
|||||||
timezone: str | None = None,
|
timezone: str | None = None,
|
||||||
locale: str | None = None,
|
locale: str | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
|
backend: str | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Launch stealth Chromium browser. Returns a Playwright Browser object.
|
"""Launch stealth Chromium browser. Returns a Playwright Browser object.
|
||||||
@@ -76,6 +77,10 @@ def launch(
|
|||||||
Requires ``pip install cloakbrowser[geoip]``. Downloads ~70 MB
|
Requires ``pip install cloakbrowser[geoip]``. Downloads ~70 MB
|
||||||
GeoLite2-City database on first use. Explicit timezone/locale
|
GeoLite2-City database on first use. Explicit timezone/locale
|
||||||
always override geoip results.
|
always override geoip results.
|
||||||
|
backend: Playwright backend — 'playwright' (default) or 'patchright'.
|
||||||
|
Patchright suppresses CDP signals (helps reCAPTCHA v3 Enterprise)
|
||||||
|
but breaks proxy auth and add_init_script.
|
||||||
|
Override globally with CLOAKBROWSER_BACKEND env var.
|
||||||
**kwargs: Passed directly to playwright.chromium.launch().
|
**kwargs: Passed directly to playwright.chromium.launch().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -89,7 +94,7 @@ def launch(
|
|||||||
>>> print(page.title())
|
>>> print(page.title())
|
||||||
>>> browser.close()
|
>>> browser.close()
|
||||||
"""
|
"""
|
||||||
from patchright.sync_api import sync_playwright
|
sync_playwright = _import_sync_playwright(_resolve_backend(backend))
|
||||||
|
|
||||||
binary_path = ensure_binary()
|
binary_path = ensure_binary()
|
||||||
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
||||||
@@ -127,6 +132,7 @@ async def launch_async(
|
|||||||
timezone: str | None = None,
|
timezone: str | None = None,
|
||||||
locale: str | None = None,
|
locale: str | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
|
backend: str | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Async version of launch(). Returns a Playwright Browser object.
|
"""Async version of launch(). Returns a Playwright Browser object.
|
||||||
@@ -139,6 +145,7 @@ async def launch_async(
|
|||||||
timezone: IANA timezone (e.g. 'America/New_York'). Sets --fingerprint-timezone binary flag.
|
timezone: IANA timezone (e.g. 'America/New_York'). Sets --fingerprint-timezone binary flag.
|
||||||
locale: BCP 47 locale (e.g. 'en-US'). Sets --lang binary flag.
|
locale: BCP 47 locale (e.g. 'en-US'). Sets --lang binary flag.
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
|
backend: Playwright backend — 'playwright' (default) or 'patchright'.
|
||||||
**kwargs: Passed directly to playwright.chromium.launch().
|
**kwargs: Passed directly to playwright.chromium.launch().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -157,7 +164,7 @@ async def launch_async(
|
|||||||
>>>
|
>>>
|
||||||
>>> asyncio.run(main())
|
>>> asyncio.run(main())
|
||||||
"""
|
"""
|
||||||
from patchright.async_api import async_playwright
|
async_playwright = _import_async_playwright(_resolve_backend(backend))
|
||||||
|
|
||||||
binary_path = ensure_binary()
|
binary_path = ensure_binary()
|
||||||
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
timezone, locale = _maybe_resolve_geoip(geoip, proxy, timezone, locale)
|
||||||
@@ -199,6 +206,7 @@ def launch_persistent_context(
|
|||||||
timezone: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
|
backend: str | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Launch stealth browser with a persistent profile and return a BrowserContext.
|
"""Launch stealth browser with a persistent profile and return a BrowserContext.
|
||||||
@@ -223,6 +231,7 @@ def launch_persistent_context(
|
|||||||
Default: None (uses Chromium default, which is 'light').
|
Default: None (uses Chromium default, which is 'light').
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
Requires ``pip install cloakbrowser[geoip]``.
|
Requires ``pip install cloakbrowser[geoip]``.
|
||||||
|
backend: Playwright backend — 'playwright' (default) or 'patchright'.
|
||||||
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -236,7 +245,7 @@ def launch_persistent_context(
|
|||||||
>>> page.goto("https://protected-site.com")
|
>>> page.goto("https://protected-site.com")
|
||||||
>>> ctx.close() # Profile is saved; re-use path next run to restore state.
|
>>> ctx.close() # Profile is saved; re-use path next run to restore state.
|
||||||
"""
|
"""
|
||||||
from patchright.sync_api import sync_playwright
|
sync_playwright = _import_sync_playwright(_resolve_backend(backend))
|
||||||
|
|
||||||
timezone = _migrate_timezone_id(timezone, kwargs)
|
timezone = _migrate_timezone_id(timezone, kwargs)
|
||||||
|
|
||||||
@@ -297,6 +306,7 @@ async def launch_persistent_context_async(
|
|||||||
timezone: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
|
backend: str | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Async version of launch_persistent_context().
|
"""Async version of launch_persistent_context().
|
||||||
@@ -318,6 +328,7 @@ async def launch_persistent_context_async(
|
|||||||
timezone: IANA timezone (e.g. 'America/New_York').
|
timezone: IANA timezone (e.g. 'America/New_York').
|
||||||
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
|
backend: Playwright backend — 'playwright' (default) or 'patchright'.
|
||||||
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
**kwargs: Passed directly to playwright.chromium.launch_persistent_context().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -336,7 +347,7 @@ async def launch_persistent_context_async(
|
|||||||
>>>
|
>>>
|
||||||
>>> asyncio.run(main())
|
>>> asyncio.run(main())
|
||||||
"""
|
"""
|
||||||
from patchright.async_api import async_playwright
|
async_playwright = _import_async_playwright(_resolve_backend(backend))
|
||||||
|
|
||||||
timezone = _migrate_timezone_id(timezone, kwargs)
|
timezone = _migrate_timezone_id(timezone, kwargs)
|
||||||
|
|
||||||
@@ -396,6 +407,7 @@ def launch_context(
|
|||||||
timezone: str | None = None,
|
timezone: str | None = None,
|
||||||
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
color_scheme: Literal["light", "dark", "no-preference"] | None = None,
|
||||||
geoip: bool = False,
|
geoip: bool = False,
|
||||||
|
backend: str | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Launch stealth browser and return a BrowserContext with common options pre-set.
|
"""Launch stealth browser and return a BrowserContext with common options pre-set.
|
||||||
@@ -414,8 +426,8 @@ def launch_context(
|
|||||||
timezone: IANA timezone (e.g. 'America/New_York').
|
timezone: IANA timezone (e.g. 'America/New_York').
|
||||||
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
color_scheme: Color scheme preference — 'light', 'dark', or 'no-preference'.
|
||||||
Default: None (uses Chromium default, which is 'light').
|
Default: None (uses Chromium default, which is 'light').
|
||||||
Note: 'no-preference' doesn't work in Patchright (falls back to 'light').
|
|
||||||
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
geoip: Auto-detect timezone/locale from proxy IP (default False).
|
||||||
|
backend: Playwright backend — 'playwright' (default) or 'patchright'.
|
||||||
**kwargs: Passed to browser.new_context().
|
**kwargs: Passed to browser.new_context().
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -430,7 +442,7 @@ def launch_context(
|
|||||||
# context and interferes with Playwright's timezone_id on new contexts.
|
# context and interferes with Playwright's timezone_id on new contexts.
|
||||||
# Timezone is set via browser.new_context(timezone_id=...) below instead.
|
# Timezone is set via browser.new_context(timezone_id=...) below instead.
|
||||||
browser = launch(headless=headless, proxy=proxy, args=args, stealth_args=stealth_args,
|
browser = launch(headless=headless, proxy=proxy, args=args, stealth_args=stealth_args,
|
||||||
timezone=None, locale=locale)
|
timezone=None, locale=locale, backend=backend)
|
||||||
|
|
||||||
context_kwargs: dict[str, Any] = {}
|
context_kwargs: dict[str, Any] = {}
|
||||||
if user_agent:
|
if user_agent:
|
||||||
@@ -462,6 +474,47 @@ def launch_context(
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Backend resolution
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_backend(backend: str | None) -> str:
|
||||||
|
"""Resolve backend: param > env var > default ('playwright')."""
|
||||||
|
b = backend or os.environ.get("CLOAKBROWSER_BACKEND", "playwright")
|
||||||
|
if b not in ("playwright", "patchright"):
|
||||||
|
raise ValueError(f"Unknown backend '{b}'. Use 'playwright' or 'patchright'.")
|
||||||
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
def _import_sync_playwright(backend: str):
|
||||||
|
"""Import sync_playwright from the resolved backend."""
|
||||||
|
if backend == "patchright":
|
||||||
|
try:
|
||||||
|
from patchright.sync_api import sync_playwright
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
raise ModuleNotFoundError(
|
||||||
|
"patchright is not installed. Install it with: pip install cloakbrowser[patchright]"
|
||||||
|
) from None
|
||||||
|
return sync_playwright
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
return sync_playwright
|
||||||
|
|
||||||
|
|
||||||
|
def _import_async_playwright(backend: str):
|
||||||
|
"""Import async_playwright from the resolved backend."""
|
||||||
|
if backend == "patchright":
|
||||||
|
try:
|
||||||
|
from patchright.async_api import async_playwright
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
raise ModuleNotFoundError(
|
||||||
|
"patchright is not installed. Install it with: pip install cloakbrowser[patchright]"
|
||||||
|
) from None
|
||||||
|
return async_playwright
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
return async_playwright
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Internal helpers
|
# Internal helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
+2
-1
@@ -49,12 +49,13 @@ classifiers = [
|
|||||||
"Topic :: Software Development :: Testing",
|
"Topic :: Software Development :: Testing",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"patchright>=1.40",
|
"playwright>=1.40",
|
||||||
"httpx>=0.24",
|
"httpx>=0.24",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
geoip = ["geoip2>=4.0"]
|
geoip = ["geoip2>=4.0"]
|
||||||
|
patchright = ["patchright>=1.40"]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://github.com/CloakHQ/CloakBrowser"
|
Homepage = "https://github.com/CloakHQ/CloakBrowser"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
"""Shared test fixtures."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _clean_backend_env(monkeypatch):
|
||||||
|
"""Ensure CLOAKBROWSER_BACKEND doesn't leak into tests from the host environment."""
|
||||||
|
monkeypatch.delenv("CLOAKBROWSER_BACKEND", raising=False)
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
"""Unit tests for backend resolution (_resolve_backend)."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from cloakbrowser.browser import _resolve_backend
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_default():
|
||||||
|
"""No param, no env var → 'playwright'."""
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
assert _resolve_backend(None) == "playwright"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_explicit_playwright():
|
||||||
|
assert _resolve_backend("playwright") == "playwright"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_explicit_patchright():
|
||||||
|
assert _resolve_backend("patchright") == "patchright"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_env_var():
|
||||||
|
"""CLOAKBROWSER_BACKEND env var used when no param."""
|
||||||
|
with patch.dict(os.environ, {"CLOAKBROWSER_BACKEND": "patchright"}):
|
||||||
|
assert _resolve_backend(None) == "patchright"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_param_beats_env():
|
||||||
|
"""Explicit param overrides env var."""
|
||||||
|
with patch.dict(os.environ, {"CLOAKBROWSER_BACKEND": "patchright"}):
|
||||||
|
assert _resolve_backend("playwright") == "playwright"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_invalid_raises():
|
||||||
|
with pytest.raises(ValueError, match="Unknown backend 'bogus'"):
|
||||||
|
_resolve_backend("bogus")
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_backend_invalid_env_raises():
|
||||||
|
with patch.dict(os.environ, {"CLOAKBROWSER_BACKEND": "bogus"}):
|
||||||
|
with pytest.raises(ValueError, match="Unknown backend 'bogus'"):
|
||||||
|
_resolve_backend(None)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"""Unit tests for launch_persistent_context() and launch_persistent_context_async().
|
"""Unit tests for launch_persistent_context() and launch_persistent_context_async().
|
||||||
|
|
||||||
All tests mock patchright to avoid needing a binary.
|
All tests mock playwright to avoid needing a binary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
@@ -32,7 +32,7 @@ def test_persistent_context_args_built(_mock_geoip, _mock_bin):
|
|||||||
"""Stealth args + extra args combined correctly."""
|
"""Stealth args + extra args combined correctly."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", args=["--disable-gpu"])
|
launch_persistent_context("/tmp/profile", args=["--disable-gpu"])
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ def test_persistent_context_default_viewport(_mock_geoip, _mock_bin):
|
|||||||
"""DEFAULT_VIEWPORT applied when no viewport given."""
|
"""DEFAULT_VIEWPORT applied when no viewport given."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile")
|
launch_persistent_context("/tmp/profile")
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ def test_persistent_context_custom_viewport(_mock_geoip, _mock_bin):
|
|||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
custom = {"width": 1280, "height": 720}
|
custom = {"width": 1280, "height": 720}
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", viewport=custom)
|
launch_persistent_context("/tmp/profile", viewport=custom)
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ def test_persistent_context_user_agent(_mock_geoip, _mock_bin):
|
|||||||
"""user_agent forwarded to launch_persistent_context()."""
|
"""user_agent forwarded to launch_persistent_context()."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", user_agent="Custom/1.0")
|
launch_persistent_context("/tmp/profile", user_agent="Custom/1.0")
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ def test_persistent_context_locale_and_timezone(_mock_bin):
|
|||||||
"""Both timezone and locale flow to context kwargs and binary args."""
|
"""Both timezone and locale flow to context kwargs and binary args."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", timezone="Asia/Tokyo", locale="ja-JP")
|
launch_persistent_context("/tmp/profile", timezone="Asia/Tokyo", locale="ja-JP")
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ def test_persistent_context_color_scheme(_mock_geoip, _mock_bin):
|
|||||||
"""color_scheme forwarded correctly."""
|
"""color_scheme forwarded correctly."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", color_scheme="dark")
|
launch_persistent_context("/tmp/profile", color_scheme="dark")
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ def test_persistent_context_geoip(_mock_bin, _mock_geoip):
|
|||||||
"""geoip fills missing tz/locale."""
|
"""geoip fills missing tz/locale."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", proxy="http://proxy:8080", geoip=True)
|
launch_persistent_context("/tmp/profile", proxy="http://proxy:8080", geoip=True)
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ def test_persistent_context_timezone_id_deprecation(_mock_bin):
|
|||||||
"""Old timezone_id kwarg migrated with warning."""
|
"""Old timezone_id kwarg migrated with warning."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
warnings.simplefilter("always")
|
warnings.simplefilter("always")
|
||||||
@@ -156,7 +156,7 @@ def test_persistent_context_close_stops_pw(_mock_geoip, _mock_bin):
|
|||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
original_close = context.close
|
original_close = context.close
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
ctx = launch_persistent_context("/tmp/profile")
|
ctx = launch_persistent_context("/tmp/profile")
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ def test_persistent_context_proxy_string(_mock_geoip, _mock_bin):
|
|||||||
"""Proxy string parsed and passed."""
|
"""Proxy string parsed and passed."""
|
||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", proxy="http://user:pass@proxy:8080")
|
launch_persistent_context("/tmp/profile", proxy="http://user:pass@proxy:8080")
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ def test_persistent_context_proxy_dict(_mock_geoip, _mock_bin):
|
|||||||
pw_cm, pw, context = _make_mock_pw_and_context()
|
pw_cm, pw, context = _make_mock_pw_and_context()
|
||||||
proxy_dict = {"server": "http://proxy:8080", "bypass": ".google.com"}
|
proxy_dict = {"server": "http://proxy:8080", "bypass": ".google.com"}
|
||||||
|
|
||||||
with patch("patchright.sync_api.sync_playwright", return_value=pw_cm):
|
with patch("playwright.sync_api.sync_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context
|
from cloakbrowser.browser import launch_persistent_context
|
||||||
launch_persistent_context("/tmp/profile", proxy=proxy_dict)
|
launch_persistent_context("/tmp/profile", proxy=proxy_dict)
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ async def test_persistent_context_async_args_built(_mock_geoip, _mock_bin):
|
|||||||
"""Async launch builds args correctly."""
|
"""Async launch builds args correctly."""
|
||||||
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.async_api.async_playwright", return_value=pw_cm):
|
with patch("playwright.async_api.async_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context_async
|
from cloakbrowser.browser import launch_persistent_context_async
|
||||||
await launch_persistent_context_async("/tmp/profile", args=["--disable-gpu"])
|
await launch_persistent_context_async("/tmp/profile", args=["--disable-gpu"])
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ async def test_persistent_context_async_close_stops_pw(_mock_geoip, _mock_bin):
|
|||||||
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
||||||
original_close = context.close
|
original_close = context.close
|
||||||
|
|
||||||
with patch("patchright.async_api.async_playwright", return_value=pw_cm):
|
with patch("playwright.async_api.async_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context_async
|
from cloakbrowser.browser import launch_persistent_context_async
|
||||||
ctx = await launch_persistent_context_async("/tmp/profile")
|
ctx = await launch_persistent_context_async("/tmp/profile")
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ async def test_persistent_context_async_timezone_id_deprecation(_mock_bin):
|
|||||||
"""Deprecated timezone_id kwarg migrated with warning in async path."""
|
"""Deprecated timezone_id kwarg migrated with warning in async path."""
|
||||||
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
pw_cm, pw, context = _make_mock_async_pw_and_context()
|
||||||
|
|
||||||
with patch("patchright.async_api.async_playwright", return_value=pw_cm):
|
with patch("playwright.async_api.async_playwright", return_value=pw_cm):
|
||||||
from cloakbrowser.browser import launch_persistent_context_async
|
from cloakbrowser.browser import launch_persistent_context_async
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
warnings.simplefilter("always")
|
warnings.simplefilter("always")
|
||||||
|
|||||||
Reference in New Issue
Block a user