mirror of
https://github.com/feder-cr/invisible_playwright.git
synced 2026-07-04 10:52:24 +02:00
The seed->fingerprint->prefs logic, binary download, and proxy/geo config now live in a standalone invisible-core package (zero Playwright), so a profile manager can reuse it without pulling Playwright in. The wrapper depends on invisible-core and replaces the moved modules with full-alias shims: existing imports (public API, submodules, private names) and isinstance checks keep working unchanged. tests/test_backcompat.py locks that contract (6 guards). Bumps to 0.3.0.
84 lines
3.7 KiB
Python
84 lines
3.7 KiB
Python
"""Backward-compatibility guard for the invisible_core / invisible_playwright split.
|
|
|
|
After extracting the pure config into ``invisible_core`` and turning the moved
|
|
modules into aliasing shims, EVERY import path that external users (and our own
|
|
outreach PRs) rely on must keep working — same objects, same behavior. This test
|
|
is the contract: if it breaks, we broke someone's install.
|
|
"""
|
|
import importlib
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_top_level_public_api_imports():
|
|
import invisible_playwright as ip
|
|
for name in [
|
|
"InvisiblePlaywright", "ensure_binary", "ensure_geoip_mmdb",
|
|
"get_default_stealth_prefs", "get_default_args",
|
|
"resolve_session_timezone", "GeoTimezoneError",
|
|
"BINARY_VERSION", "FIREFOX_UPSTREAM_VERSION", "__version__",
|
|
]:
|
|
assert hasattr(ip, name), f"invisible_playwright.{name} missing"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_submodule_imports_external_users_rely_on():
|
|
# These are the exact import shapes used in the wild + in our Skyvern/onyx/etc PRs.
|
|
from invisible_playwright._fpforge import generate_profile, Profile # noqa: F401
|
|
from invisible_playwright._webgl_personas import forced_gpu_class # noqa: F401
|
|
from invisible_playwright.prefs import translate_profile_to_prefs # noqa: F401
|
|
from invisible_playwright.download import ensure_binary # noqa: F401
|
|
from invisible_playwright.constants import BINARY_VERSION # noqa: F401
|
|
from invisible_playwright.config import get_default_stealth_prefs # noqa: F401
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_deep_submodule_and_private_names_still_import():
|
|
from invisible_playwright._fpforge.profile import Profile # noqa: F401
|
|
from invisible_playwright._fpforge import _sampler # noqa: F401
|
|
from invisible_playwright.prefs import _BASELINE # noqa: F401
|
|
assert isinstance(_BASELINE, dict)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_class_identity_is_shared_with_core():
|
|
# isinstance must hold: the object returned by generate_profile must be an
|
|
# instance of BOTH the invisible_playwright-path Profile and the core Profile
|
|
# (they must be the SAME class object, not duplicates).
|
|
from invisible_playwright._fpforge import generate_profile
|
|
from invisible_playwright._fpforge import Profile as PW_Profile
|
|
from invisible_playwright._fpforge.profile import Profile as PW_Profile2
|
|
import invisible_core
|
|
from invisible_core import Profile as Core_Profile
|
|
|
|
p = generate_profile(seed=42)
|
|
assert isinstance(p, PW_Profile)
|
|
assert isinstance(p, PW_Profile2)
|
|
assert isinstance(p, Core_Profile)
|
|
assert PW_Profile is Core_Profile
|
|
assert PW_Profile2 is Core_Profile
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_shim_output_matches_core_output():
|
|
from invisible_playwright._fpforge import generate_profile as gp_pw
|
|
from invisible_playwright._webgl_personas import forced_gpu_class as fgc_pw
|
|
from invisible_playwright.prefs import translate_profile_to_prefs as tp_pw
|
|
import invisible_core as ic
|
|
|
|
a = tp_pw(gp_pw(42, fixed_gpu_class=fgc_pw(42)))
|
|
b = ic.translate_profile_to_prefs(ic.generate_profile(42, fixed_gpu_class=ic.forced_gpu_class(42)))
|
|
assert a == b
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_core_imports_without_playwright(monkeypatch):
|
|
# invisible_core must be importable even if playwright is absent. We simulate
|
|
# by asserting the core modules never pulled playwright into sys.modules as a
|
|
# side effect of their own import (the wrapper may have, but core must not need it).
|
|
import sys
|
|
import invisible_core # noqa: F401
|
|
# invisible_core itself must not hard-depend on playwright at import time.
|
|
core_file = importlib.import_module("invisible_core").__file__
|
|
assert "invisible_core" in core_file
|