mirror of
https://github.com/feder-cr/invisible_playwright.git
synced 2026-06-07 08:35:12 +02:00
feat: public config helpers for third-party integrations (#25)
Adds invisible_playwright.config module with: - get_default_stealth_prefs(seed, *, pin, locale, timezone, extra_prefs, humanize, virtual_display) -> dict - get_default_args() -> list Both also re-exported at the package root alongside the existing InvisiblePlaywright. ensure_binary is also re-exported there for parity with the cloakbrowser.download.ensure_binary integration pattern that downstream projects (Skyvern PR #5340, crawlee-python PR #1794, agno PR #8129) already expect. These helpers let third-party fetchers (changedetection.io plugins, Crawlee BrowserPool subclasses, agno toolkits) drive playwright.firefox.launch(executable_path=..., firefox_user_prefs=...) themselves without depending on the InvisiblePlaywright context manager owning the lifecycle. Same seed semantics, same humanize toggle, same extra_prefs overlay as the existing wrapper. Tests: tests/unit/test_config_public.py adds 14 unit tests covering deterministic seed, locale/timezone/pin/extra_prefs/humanize variations, and round-trip via the public namespace. Full unit suite (392 tests) stays green. Backwards compatible: InvisiblePlaywright surface is unchanged. BINARY_VERSION stays at firefox-7. Python-only release.
This commit is contained in:
parent
929da150bc
commit
ee0fe57ced
6 changed files with 267 additions and 3 deletions
125
tests/unit/test_config_public.py
Normal file
125
tests/unit/test_config_public.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
"""Unit tests for the public ``config`` helpers."""
|
||||
|
||||
import pytest
|
||||
|
||||
from invisible_playwright import (
|
||||
ensure_binary,
|
||||
get_default_args,
|
||||
get_default_stealth_prefs,
|
||||
)
|
||||
from invisible_playwright.config import get_default_stealth_prefs as _direct
|
||||
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
def test_get_default_args_is_empty_list():
|
||||
"""Currently no baseline CLI args, but must return a list (mutable, fresh each call)."""
|
||||
args = get_default_args()
|
||||
assert args == []
|
||||
assert isinstance(args, list)
|
||||
args.append("--foo")
|
||||
# next call must return a fresh empty list, not the mutated one
|
||||
assert get_default_args() == []
|
||||
|
||||
|
||||
def test_get_default_stealth_prefs_random_seed_returns_dict():
|
||||
"""No seed -> fresh random fingerprint, dict has expected stealth keys."""
|
||||
prefs = get_default_stealth_prefs()
|
||||
assert isinstance(prefs, dict)
|
||||
assert len(prefs) > 0
|
||||
# humanize toggle is always set explicitly
|
||||
assert "invisible_playwright.humanize" in prefs
|
||||
assert prefs["invisible_playwright.humanize"] is True
|
||||
|
||||
|
||||
def test_get_default_stealth_prefs_seed_is_deterministic():
|
||||
"""Same seed -> byte-identical prefs across calls."""
|
||||
a = get_default_stealth_prefs(seed=42)
|
||||
b = get_default_stealth_prefs(seed=42)
|
||||
assert a == b
|
||||
|
||||
|
||||
def test_get_default_stealth_prefs_different_seeds_differ():
|
||||
"""Different seeds -> different prefs."""
|
||||
a = get_default_stealth_prefs(seed=1)
|
||||
b = get_default_stealth_prefs(seed=2)
|
||||
assert a != b
|
||||
|
||||
|
||||
def test_humanize_false_disables_prefs():
|
||||
"""humanize=False removes the maxTime knob and flips the toggle to False."""
|
||||
prefs = get_default_stealth_prefs(seed=42, humanize=False)
|
||||
assert prefs["invisible_playwright.humanize"] is False
|
||||
assert "invisible_playwright.humanize.maxTime" not in prefs
|
||||
|
||||
|
||||
def test_humanize_default_sets_max_time_1_5():
|
||||
"""humanize=True -> default maxTime is 1.5s, stored as string."""
|
||||
prefs = get_default_stealth_prefs(seed=42, humanize=True)
|
||||
assert prefs["invisible_playwright.humanize"] is True
|
||||
assert prefs["invisible_playwright.humanize.maxTime"] == "1.5"
|
||||
|
||||
|
||||
def test_humanize_float_overrides_max_time():
|
||||
"""Float for humanize is the explicit cap in seconds."""
|
||||
prefs = get_default_stealth_prefs(seed=42, humanize=3.0)
|
||||
assert prefs["invisible_playwright.humanize"] is True
|
||||
assert prefs["invisible_playwright.humanize.maxTime"] == "3.0"
|
||||
|
||||
|
||||
def test_extra_prefs_overlay_takes_precedence():
|
||||
"""extra_prefs overlay LAST overrides any baseline value."""
|
||||
prefs = get_default_stealth_prefs(
|
||||
seed=42, extra_prefs={"some.custom.pref": 999}
|
||||
)
|
||||
assert prefs["some.custom.pref"] == 999
|
||||
|
||||
|
||||
def test_extra_prefs_can_override_baseline():
|
||||
"""A key in extra_prefs that also exists in baseline gets overridden."""
|
||||
baseline = get_default_stealth_prefs(seed=42)
|
||||
a_baseline_key = next(iter(baseline.keys()))
|
||||
overridden = get_default_stealth_prefs(
|
||||
seed=42, extra_prefs={a_baseline_key: "OVERRIDDEN_SENTINEL"}
|
||||
)
|
||||
assert overridden[a_baseline_key] == "OVERRIDDEN_SENTINEL"
|
||||
|
||||
|
||||
def test_locale_argument_changes_prefs():
|
||||
"""Different locales produce different prefs (Accept-Language affected)."""
|
||||
en = get_default_stealth_prefs(seed=42, locale="en-US")
|
||||
it = get_default_stealth_prefs(seed=42, locale="it-IT")
|
||||
assert en != it
|
||||
|
||||
|
||||
def test_timezone_argument_changes_prefs():
|
||||
"""Different timezones produce different prefs."""
|
||||
ny = get_default_stealth_prefs(seed=42, timezone="America/New_York")
|
||||
rome = get_default_stealth_prefs(seed=42, timezone="Europe/Rome")
|
||||
assert ny != rome
|
||||
|
||||
|
||||
def test_pin_argument_forces_specific_fields():
|
||||
"""Pin forces a specific field while the rest stays seed-derived."""
|
||||
plain = get_default_stealth_prefs(seed=42)
|
||||
pinned = get_default_stealth_prefs(
|
||||
seed=42, pin={"hardware.concurrency": 999}
|
||||
)
|
||||
# something in the dict must differ vs the plain seed=42 build
|
||||
assert plain != pinned
|
||||
|
||||
|
||||
def test_public_import_matches_direct_import():
|
||||
"""Top-level re-export and direct module import return identical output."""
|
||||
a = get_default_stealth_prefs(seed=42)
|
||||
b = _direct(seed=42)
|
||||
assert a == b
|
||||
|
||||
|
||||
def test_ensure_binary_is_callable_via_public_namespace():
|
||||
"""ensure_binary is re-exported and stays callable from the package root."""
|
||||
# We don't invoke it (would trigger a network download in CI) — just
|
||||
# verify the public attribute is the same callable as the underlying.
|
||||
from invisible_playwright.download import ensure_binary as _direct_eb
|
||||
assert ensure_binary is _direct_eb
|
||||
Loading…
Add table
Add a link
Reference in a new issue