mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8e09656aa | ||
|
|
724d49f65b | ||
|
|
ed79560e5f | ||
|
|
829e4b881f |
@@ -0,0 +1,34 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
python:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install -e ".[dev]" pytest pytest-asyncio
|
||||||
|
- name: Run tests
|
||||||
|
run: pytest tests/ -v -m "not slow"
|
||||||
|
|
||||||
|
javascript:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Install and build
|
||||||
|
run: cd js && npm install && npm run build
|
||||||
|
- name: Typecheck
|
||||||
|
run: cd js && npm run typecheck
|
||||||
|
- name: Run tests
|
||||||
|
run: cd js && npm test
|
||||||
@@ -6,6 +6,14 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.3.10] — 2026-03-07
|
||||||
|
|
||||||
|
- **[binary]** Upgrade Linux build to 145.0.7632.159.2
|
||||||
|
- **[binary]** Fix detection regression caused by unnecessary browser flag (fixes #16)
|
||||||
|
- **[binary]** Fix fingerprint consistency in offline audio rendering
|
||||||
|
- **[wrapper]** Add `cloakserve` CDP server mode for Docker — exposes Chrome DevTools Protocol on `0.0.0.0:9222` for external tool integration
|
||||||
|
- **[wrapper]** Add wrapper regression tests: page.goto timing with stealth init (#9), add_init_script compatibility with proxy auth (#27)
|
||||||
|
|
||||||
## [0.3.9] — 2026-03-05
|
## [0.3.9] — 2026-03-05
|
||||||
|
|
||||||
- **[binary]** Upgrade Chromium base to 145.0.7632.159 (Linux x64). macOS and Windows remain on 145.0.7632.109.2
|
- **[binary]** Upgrade Chromium base to 145.0.7632.159 (Linux x64). macOS and Windows remain on 145.0.7632.109.2
|
||||||
|
|||||||
+5
-2
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libglib2.0-0 libgtk-3-0 libpangocairo-1.0-0 libcairo-gobject2 \
|
libglib2.0-0 libgtk-3-0 libpangocairo-1.0-0 libcairo-gobject2 \
|
||||||
libgdk-pixbuf-2.0-0 libxss1 libxtst6 fonts-liberation \
|
libgdk-pixbuf-2.0-0 libxss1 libxtst6 fonts-liberation \
|
||||||
xvfb xdotool \
|
xvfb xdotool \
|
||||||
curl ca-certificates \
|
curl ca-certificates socat \
|
||||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||||
&& apt-get install -y --no-install-recommends nodejs \
|
&& apt-get install -y --no-install-recommends nodejs \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
@@ -36,7 +36,10 @@ RUN python -c "from cloakbrowser import ensure_binary; ensure_binary()" \
|
|||||||
|
|
||||||
# CLI shortcuts
|
# CLI shortcuts
|
||||||
COPY bin/cloaktest /usr/local/bin/cloaktest
|
COPY bin/cloaktest /usr/local/bin/cloaktest
|
||||||
RUN chmod +x /usr/local/bin/cloaktest
|
COPY bin/cloakserve /usr/local/bin/cloakserve
|
||||||
|
RUN chmod +x /usr/local/bin/cloaktest /usr/local/bin/cloakserve
|
||||||
|
|
||||||
|
EXPOSE 9222
|
||||||
|
|
||||||
# Xvfb entrypoint for headed mode support
|
# Xvfb entrypoint for headed mode support
|
||||||
COPY bin/docker-entrypoint.sh /entrypoint.sh
|
COPY bin/docker-entrypoint.sh /entrypoint.sh
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/last-commit/cloakhq/cloakbrowser" alt="Last Commit"></a>
|
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/last-commit/cloakhq/cloakbrowser" alt="Last Commit"></a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/stars/cloakhq/cloakbrowser" alt="Stars"></a>
|
<a href="https://github.com/CloakHQ/CloakBrowser"><img src="https://img.shields.io/github/stars/cloakhq/cloakbrowser" alt="Stars"></a>
|
||||||
<a href="https://pepy.tech/projects/cloakbrowser"><img src="https://img.shields.io/pepy/dt/cloakbrowser?label=pypi&logo=pypi&logoColor=white" alt="PyPI Downloads"></a>
|
<a href="https://pypi.org/project/cloakbrowser/"><img src="https://img.shields.io/pepy/dt/cloakbrowser?label=pypi&logo=pypi&logoColor=white" alt="PyPI Downloads"></a>
|
||||||
<a href="https://www.npmjs.com/package/cloakbrowser"><img src="https://img.shields.io/npm/dt/cloakbrowser?label=npm&logo=npm&logoColor=white" alt="npm Downloads"></a>
|
<a href="https://www.npmjs.com/package/cloakbrowser"><img src="https://img.shields.io/npm/dt/cloakbrowser?label=npm&logo=npm&logoColor=white" alt="npm Downloads"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ page.goto("https://example.com")
|
|||||||
|
|
||||||
> ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop.
|
> ⭐ **Star** to show support — **[Watch releases](https://github.com/CloakHQ/CloakBrowser/subscription)** to get notified when new builds drop.
|
||||||
|
|
||||||
## Latest: v0.3.8 (Chromium 145.0.7632.159)
|
## Latest: v0.3.10 (Chromium 145.0.7632.159.2)
|
||||||
|
|
||||||
- **All 4 platforms** — Linux x64, macOS arm64, macOS x64, and Windows x64 all on Chromium 145
|
- **All 4 platforms** — Linux x64, macOS arm64, macOS x64, and Windows x64 all on Chromium 145
|
||||||
- **26 fingerprint patches** — 10 new patches since v142 (screen, device memory, audio, WebGL, auto-spoof, and more)
|
- **26 fingerprint patches** — 10 new patches since v142 (screen, device memory, audio, WebGL, auto-spoof, and more)
|
||||||
@@ -307,7 +307,7 @@ from cloakbrowser import binary_info, clear_cache, ensure_binary
|
|||||||
|
|
||||||
# Check binary installation status
|
# Check binary installation status
|
||||||
print(binary_info())
|
print(binary_info())
|
||||||
# {'version': '145.0.7632.159', 'platform': 'linux-x64', 'installed': True, ...}
|
# {'version': '145.0.7632.159.2', 'platform': 'linux-x64', 'installed': True, ...}
|
||||||
|
|
||||||
# Force re-download
|
# Force re-download
|
||||||
clear_cache()
|
clear_cache()
|
||||||
@@ -506,13 +506,18 @@ The wrapper auto-downloads the correct binary for your platform.
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
Pre-built image on Docker Hub — no install, no setup:
|
Pre-built image on Docker Hub — no install, no setup.
|
||||||
|
|
||||||
|
### Quick test
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run the stealth test suite
|
|
||||||
docker run --rm cloakhq/cloakbrowser cloaktest
|
docker run --rm cloakhq/cloakbrowser cloaktest
|
||||||
|
```
|
||||||
|
|
||||||
# Run your own script
|
### Run a script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Inline script
|
||||||
docker run --rm cloakhq/cloakbrowser python -c "
|
docker run --rm cloakhq/cloakbrowser python -c "
|
||||||
from cloakbrowser import launch
|
from cloakbrowser import launch
|
||||||
browser = launch()
|
browser = launch()
|
||||||
@@ -522,6 +527,9 @@ print(page.title())
|
|||||||
browser.close()
|
browser.close()
|
||||||
"
|
"
|
||||||
|
|
||||||
|
# Mount your own script
|
||||||
|
docker run --rm -v ./my_script.py:/app/my_script.py cloakhq/cloakbrowser python my_script.py
|
||||||
|
|
||||||
# With a proxy
|
# With a proxy
|
||||||
docker run --rm cloakhq/cloakbrowser python -c "
|
docker run --rm cloakhq/cloakbrowser python -c "
|
||||||
from cloakbrowser import launch
|
from cloakbrowser import launch
|
||||||
@@ -533,7 +541,86 @@ browser.close()
|
|||||||
"
|
"
|
||||||
```
|
```
|
||||||
|
|
||||||
To extend with your own script:
|
### CDP server mode
|
||||||
|
|
||||||
|
Start a persistent stealth browser and connect to it remotely via Chrome DevTools Protocol:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name cloak -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser cloakserve
|
||||||
|
```
|
||||||
|
|
||||||
|
Then connect from your host machine:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
pw = sync_playwright().start()
|
||||||
|
browser = pw.chromium.connect_over_cdp("http://localhost:9222")
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto("https://example.com")
|
||||||
|
print(page.title())
|
||||||
|
browser.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass extra flags to the browser:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# With proxy
|
||||||
|
docker run -d --name cloak -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
|
||||||
|
cloakserve --proxy-server=http://proxy:8080
|
||||||
|
|
||||||
|
# Headed mode (renders to Xvfb inside container)
|
||||||
|
docker run -d --name cloak -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser \
|
||||||
|
cloakserve --headless=false
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop the server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stop cloak && docker rm cloak
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Security:** CDP gives full control over the browser (execute JS, read pages, access files).
|
||||||
|
> The examples bind to `127.0.0.1` so only your machine can connect. Never expose port 9222
|
||||||
|
> to the public internet without additional authentication.
|
||||||
|
|
||||||
|
### Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
cloakbrowser:
|
||||||
|
image: cloakhq/cloakbrowser
|
||||||
|
command: cloakserve
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9222:9222"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9222/json/version"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
```
|
||||||
|
|
||||||
|
Run multiple instances with different fingerprint seeds on different ports — each gets unique canvas noise, client rects, and other browser signals. Pass `--fingerprint=<seed>` in the command (e.g., `cloakserve --fingerprint=12345`).
|
||||||
|
|
||||||
|
**Persistent profiles** — mount a volume to keep cookies and sessions across container restarts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -v ./my-profile:/profile cloakhq/cloakbrowser python -c "
|
||||||
|
from cloakbrowser import launch_persistent_context
|
||||||
|
ctx = launch_persistent_context('/profile')
|
||||||
|
page = ctx.new_page()
|
||||||
|
page.goto('https://example.com')
|
||||||
|
ctx.close()
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
Run again with the same volume — cookies, localStorage, and cache are restored automatically.
|
||||||
|
|
||||||
|
**Resource usage:** ~190MB RAM idle, ~280MB with 3 tabs. ~30MB per additional tab.
|
||||||
|
|
||||||
|
### Extend with your own image
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM cloakhq/cloakbrowser
|
FROM cloakhq/cloakbrowser
|
||||||
@@ -630,7 +717,7 @@ export CLOAKBROWSER_BINARY_PATH=/path/to/your/chrome
|
|||||||
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/`. Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
|
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/`. Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
|
||||||
```bash
|
```bash
|
||||||
# Linux
|
# Linux
|
||||||
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.159/chrome
|
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.159.2/chrome
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
|
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
|
||||||
|
|||||||
Executable
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Launch stealth Chromium as a CDP server for remote connections.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
cloakserve # headless on port 9222
|
||||||
|
cloakserve --headless=false # headed (uses Xvfb in Docker)
|
||||||
|
cloakserve --proxy-server=host:port # with proxy
|
||||||
|
|
||||||
|
Connect from host:
|
||||||
|
playwright.chromium.connect_over_cdp("http://localhost:9222")
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from cloakbrowser.config import get_default_stealth_args
|
||||||
|
from cloakbrowser.download import ensure_binary
|
||||||
|
|
||||||
|
EXPOSE_PORT = 9222 # External, 0.0.0.0 (user connects here)
|
||||||
|
CHROME_PORT = 9223 # Internal, 127.0.0.1 (Chrome binds here)
|
||||||
|
|
||||||
|
binary = ensure_binary()
|
||||||
|
|
||||||
|
chrome_args = [
|
||||||
|
binary,
|
||||||
|
f"--remote-debugging-port={CHROME_PORT}",
|
||||||
|
# "--remote-debugging-address=0.0.0.0", # TODO: enable after binary patch 032
|
||||||
|
# Sane defaults for running Chrome directly (outside Playwright)
|
||||||
|
"--no-first-run",
|
||||||
|
"--no-default-browser-check",
|
||||||
|
"--disable-dev-shm-usage",
|
||||||
|
"--disable-extensions",
|
||||||
|
"--disable-popup-blocking",
|
||||||
|
"--disable-background-networking",
|
||||||
|
"--metrics-recording-only",
|
||||||
|
] + get_default_stealth_args() + sys.argv[1:]
|
||||||
|
|
||||||
|
# Launch Chrome
|
||||||
|
chrome = subprocess.Popen(chrome_args)
|
||||||
|
|
||||||
|
# Wait for Chrome to start listening
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# Forward 0.0.0.0:9222 -> 127.0.0.1:9223
|
||||||
|
# Chrome hardcodes 127.0.0.1 for security; socat exposes it to Docker network.
|
||||||
|
# TODO: Remove socat after patching binary to support --remote-debugging-address
|
||||||
|
socat = subprocess.Popen([
|
||||||
|
"socat",
|
||||||
|
f"TCP-LISTEN:{EXPOSE_PORT},fork,reuseaddr,bind=0.0.0.0",
|
||||||
|
f"TCP:127.0.0.1:{CHROME_PORT}",
|
||||||
|
])
|
||||||
|
|
||||||
|
print(f"CloakBrowser CDP server ready on port {EXPOSE_PORT}", flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup(sig, frame):
|
||||||
|
chrome.terminate()
|
||||||
|
socat.terminate()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, cleanup)
|
||||||
|
signal.signal(signal.SIGINT, cleanup)
|
||||||
|
|
||||||
|
# Wait for Chrome to exit, then clean up socat
|
||||||
|
chrome.wait()
|
||||||
|
socat.terminate()
|
||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.3.9"
|
__version__ = "0.3.10"
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ from ._version import __version__
|
|||||||
# CHROMIUM_VERSION is the latest across all platforms (for display/reference).
|
# CHROMIUM_VERSION is the latest across all platforms (for display/reference).
|
||||||
# Use get_chromium_version() for the current platform's actual version.
|
# Use get_chromium_version() for the current platform's actual version.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
CHROMIUM_VERSION = "145.0.7632.159"
|
CHROMIUM_VERSION = "145.0.7632.159.2"
|
||||||
|
|
||||||
PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = {
|
PLATFORM_CHROMIUM_VERSIONS: dict[str, str] = {
|
||||||
"linux-x64": "145.0.7632.159",
|
"linux-x64": "145.0.7632.159.2",
|
||||||
"darwin-arm64": "145.0.7632.109.2",
|
"darwin-arm64": "145.0.7632.109.2",
|
||||||
"darwin-x64": "145.0.7632.109.2",
|
"darwin-x64": "145.0.7632.109.2",
|
||||||
"windows-x64": "145.0.7632.109.2",
|
"windows-x64": "145.0.7632.109.2",
|
||||||
|
|||||||
+1
-1
@@ -247,7 +247,7 @@ Other tips for maximizing reCAPTCHA scores:
|
|||||||
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/`. Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
|
When auto-update downloads a newer binary, the previous version stays in `~/.cloakbrowser/`. Point `CLOAKBROWSER_BINARY_PATH` to the older cached binary:
|
||||||
```bash
|
```bash
|
||||||
# Linux
|
# Linux
|
||||||
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.159/chrome
|
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.159.2/chrome
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
|
export CLOAKBROWSER_BINARY_PATH=~/.cloakbrowser/chromium-145.0.7632.109.2/Chromium.app/Contents/MacOS/Chromium
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cloakbrowser",
|
"name": "cloakbrowser",
|
||||||
"version": "0.3.9",
|
"version": "0.3.10",
|
||||||
"description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.",
|
"description": "Stealth Chromium that passes every bot detection test. Drop-in Playwright/Puppeteer replacement with source-level fingerprint patches.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
+2
-2
@@ -27,10 +27,10 @@ export { WRAPPER_VERSION };
|
|||||||
// CHROMIUM_VERSION is the latest across all platforms (for display/reference).
|
// CHROMIUM_VERSION is the latest across all platforms (for display/reference).
|
||||||
// Use getChromiumVersion() for the current platform's actual version.
|
// Use getChromiumVersion() for the current platform's actual version.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
export const CHROMIUM_VERSION = "145.0.7632.159";
|
export const CHROMIUM_VERSION = "145.0.7632.159.2";
|
||||||
|
|
||||||
export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = {
|
export const PLATFORM_CHROMIUM_VERSIONS: Record<string, string> = {
|
||||||
"linux-x64": "145.0.7632.159",
|
"linux-x64": "145.0.7632.159.2",
|
||||||
"darwin-arm64": "145.0.7632.109.2",
|
"darwin-arm64": "145.0.7632.109.2",
|
||||||
"darwin-x64": "145.0.7632.109.2",
|
"darwin-x64": "145.0.7632.109.2",
|
||||||
"windows-x64": "145.0.7632.109.2",
|
"windows-x64": "145.0.7632.109.2",
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ describe("config", () => {
|
|||||||
expect(args.some((a) => a.includes("hardware-concurrency"))).toBe(false);
|
expect(args.some((a) => a.includes("hardware-concurrency"))).toBe(false);
|
||||||
} else {
|
} else {
|
||||||
expect(args).toContain("--fingerprint-platform=windows");
|
expect(args).toContain("--fingerprint-platform=windows");
|
||||||
expect(args).toContain("--fingerprint-hardware-concurrency=8");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should have a random fingerprint seed
|
// Should have a random fingerprint seed
|
||||||
|
|||||||
@@ -217,3 +217,70 @@ class TestBotDetectionSites:
|
|||||||
score = results["score"]
|
score = results["score"]
|
||||||
assert score is not None, "Could not extract reCAPTCHA score"
|
assert score is not None, "Could not extract reCAPTCHA score"
|
||||||
assert score >= 0.7, f"reCAPTCHA score too low: {score}"
|
assert score >= 0.7, f"reCAPTCHA score too low: {score}"
|
||||||
|
|
||||||
|
|
||||||
|
class TestIssueRegressions:
|
||||||
|
"""Regression tests for specific GitHub issues.
|
||||||
|
|
||||||
|
Uses the shared browser fixture to avoid "Sync API inside asyncio loop"
|
||||||
|
errors when pytest-asyncio is active.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@pytest.mark.slow
|
||||||
|
def test_immediate_goto_works(self, browser):
|
||||||
|
"""Issue #9: page.goto() immediately after launch must not fail.
|
||||||
|
|
||||||
|
User reported reCAPTCHA fails if goto is called too quickly after
|
||||||
|
launch. This test verifies that immediate navigation works without
|
||||||
|
needing an artificial delay.
|
||||||
|
"""
|
||||||
|
page = browser.new_page()
|
||||||
|
# No delay — goto immediately
|
||||||
|
page.goto("https://example.com", timeout=30000)
|
||||||
|
title = page.title()
|
||||||
|
page.close()
|
||||||
|
assert "Example Domain" in title, f"Immediate goto failed, title={title}"
|
||||||
|
|
||||||
|
@pytest.mark.slow
|
||||||
|
def test_add_init_script_without_proxy(self, browser):
|
||||||
|
"""Issue #27: add_init_script must work (baseline without proxy).
|
||||||
|
|
||||||
|
The bug is proxy + add_init_script, but we first verify init_script
|
||||||
|
alone works so we have a baseline.
|
||||||
|
"""
|
||||||
|
page = browser.new_page()
|
||||||
|
page.add_init_script("window.__cloaktest = 42;")
|
||||||
|
page.goto("https://example.com", timeout=30000)
|
||||||
|
val = page.evaluate("window.__cloaktest")
|
||||||
|
page.close()
|
||||||
|
assert val == 42, f"add_init_script failed, got {val}"
|
||||||
|
|
||||||
|
@pytest.mark.slow
|
||||||
|
def test_add_init_script_with_proxy(self, browser):
|
||||||
|
"""Issue #27: add_init_script + proxy must not cause ERR_TUNNEL_CONNECTION_FAILED.
|
||||||
|
|
||||||
|
Patchright bug: add_init_script breaks proxy auth. This test guards
|
||||||
|
against regression if/when the upstream fix lands. Uses context-level
|
||||||
|
proxy to avoid launching a separate browser (event loop conflict).
|
||||||
|
"""
|
||||||
|
proxy = os.environ.get("CLOAKBROWSER_TEST_PROXY")
|
||||||
|
if not proxy:
|
||||||
|
pytest.skip("CLOAKBROWSER_TEST_PROXY not set")
|
||||||
|
|
||||||
|
ctx = browser.new_context(proxy={"server": proxy})
|
||||||
|
page = ctx.new_page()
|
||||||
|
page.add_init_script("window.__cloaktest = 99;")
|
||||||
|
try:
|
||||||
|
page.goto("https://httpbin.org/ip", timeout=30000)
|
||||||
|
body = page.evaluate("document.body.innerText")
|
||||||
|
val = page.evaluate("window.__cloaktest")
|
||||||
|
assert val == 99, f"init_script value wrong: {val}"
|
||||||
|
assert "origin" in body, f"Page didn't load through proxy: {body[:100]}"
|
||||||
|
except Exception as e:
|
||||||
|
err = str(e)
|
||||||
|
if "ERR_TUNNEL_CONNECTION_FAILED" in err:
|
||||||
|
pytest.xfail("Known patchright bug: add_init_script + proxy auth (issue #27)")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
page.close()
|
||||||
|
ctx.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user