Files
stealthii/tests/test_stealth_detection.py
T
retoorandClaude Sonnet 5 86c3a95cb8 Add PUT/PATCH/DELETE/HEAD, full aiohttp/httpx param parity, screenshots,
async-with tab claiming, and full documentation

- get/post/put/patch/delete/head now accept the same request shape as
  aiohttp/httpx: data/json/files/cookies/auth/allow_redirects/
  follow_redirects/max_redirects, plus the existing session= for named
  cookie-persisting contexts.
- screenshot(url, path=None) captures a PNG, saved to disk or returned
  as base64.
- `async with stealth as page` claims a tab directly, task-safe for
  concurrent use on one shared instance (keyed off asyncio.current_task,
  not instance state).
- Strip all docstrings/comments from the source (author line excepted),
  per house style.
- README.md rewritten as the complete documentation: rationale, JA3/JA4
  comparison, dependencies, construction/laziness/lifetime, every method
  with examples, named sessions, configuration, error handling, testing.
- STEALTH_PATCHES.md: a literal, patch-by-patch account of every launch
  argument and JS patch applied, with rationale and verification method.
- 20 new tests: full HTTP-method coverage, cookies, auth, multipart,
  download, render, screenshot, named-session isolation, retry/error
  paths, and guaranteed page/context cleanup under exception.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116i7dYLNZTXNR7Lqf439bV
2026-09-09 13:56:28 +02:00

55 lines
1.5 KiB
Python

# retoor <retoor@molodetz.nl>
import pytest
from stealthii import Stealthii
@pytest.mark.online
@pytest.mark.asyncio
async def test_sannysoft_detection_suite_is_clean():
s = Stealthii()
try:
async with s.page() as pg:
await pg.goto('https://bot.sannysoft.com/', wait_until='networkidle', timeout=20000)
rows = await pg.evaluate(
"""() => Array.from(document.querySelectorAll('table tr')).map(tr =>
Array.from(tr.querySelectorAll('td')).map(td => td.innerText.trim()).join(' | ')
)"""
)
finally:
await s.shutdown()
failures = [r for r in rows if 'FAIL' in r or 'failed' in r]
assert not failures, f'stealth detection regressions: {failures}'
@pytest.mark.online
@pytest.mark.asyncio
async def test_async_with_instance_claims_isolated_concurrent_tabs():
import asyncio
s = Stealthii()
async def worker():
async with s as pg:
await pg.goto('https://example.com')
return await pg.title()
try:
titles = await asyncio.gather(*[worker() for _ in range(3)])
finally:
await s.shutdown()
assert titles == ['Example Domain'] * 3
@pytest.mark.online
@pytest.mark.asyncio
async def test_fast_path_uses_real_chromium_fingerprint():
s = Stealthii()
try:
info = await s.fingerprint_info()
finally:
await s.shutdown()
assert info['hash']
assert info['mode'] == 'ja4'