mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-31 10:47:16 +08:00
feat(browser): migrate to CloakBrowser for browser emulation and streamline dependency management
- Replace Playwright-based browser emulation with CloakBrowser as default - Update config to support CloakBrowser options and humanization presets - Refactor browser helper to use CloakBrowser context and remove cf_clearance dependency - Update Dockerfile, entrypoint, and update scripts to install CloakBrowser runtime - Ensure CloakBrowser kernel is pre-installed during local setup and dependency updates - Add tests for CloakBrowser integration and legacy compatibility
This commit is contained in:
95
tests/test_browser_helper.py
Normal file
95
tests/test_browser_helper.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from app.helper.browser import PlaywrightHelper
|
||||
|
||||
|
||||
class _FakePage:
|
||||
def __init__(self) -> None:
|
||||
self.headers = None
|
||||
self.loaded_url = None
|
||||
self.closed = False
|
||||
|
||||
def set_extra_http_headers(self, headers: dict[str, str]) -> None:
|
||||
self.headers = headers
|
||||
|
||||
def goto(self, url: str) -> None:
|
||||
self.loaded_url = url
|
||||
|
||||
def wait_for_load_state(self, _state: str, timeout: int) -> None:
|
||||
self.timeout = timeout
|
||||
|
||||
def content(self) -> str:
|
||||
return "<html>ok</html>"
|
||||
|
||||
def close(self) -> None:
|
||||
self.closed = True
|
||||
|
||||
|
||||
class _FakeContext:
|
||||
def __init__(self, page: _FakePage) -> None:
|
||||
self.page = page
|
||||
self.closed = False
|
||||
|
||||
def new_page(self) -> _FakePage:
|
||||
return self.page
|
||||
|
||||
def close(self) -> None:
|
||||
self.closed = True
|
||||
|
||||
|
||||
class BrowserHelperTests(unittest.TestCase):
|
||||
def _assert_get_page_source_uses_cloakbrowser(self, emulation: str) -> None:
|
||||
page = _FakePage()
|
||||
context = _FakeContext(page)
|
||||
|
||||
with patch("app.helper.browser.settings.BROWSER_EMULATION", emulation), \
|
||||
patch.object(
|
||||
PlaywrightHelper,
|
||||
"_PlaywrightHelper__launch_cloakbrowser_context",
|
||||
return_value=context,
|
||||
) as launch_context:
|
||||
source = PlaywrightHelper().get_page_source(
|
||||
url="https://example.com",
|
||||
cookies="uid=1",
|
||||
ua="UA",
|
||||
timeout=3,
|
||||
)
|
||||
|
||||
self.assertEqual(source, "<html>ok</html>")
|
||||
launch_context.assert_called_once_with(
|
||||
headless=False,
|
||||
user_agent="UA",
|
||||
proxies=None,
|
||||
)
|
||||
self.assertEqual(page.headers, {"cookie": "uid=1"})
|
||||
self.assertEqual(page.loaded_url, "https://example.com")
|
||||
self.assertTrue(page.closed)
|
||||
self.assertTrue(context.closed)
|
||||
|
||||
def test_default_emulation_uses_cloakbrowser_context(self):
|
||||
self._assert_get_page_source_uses_cloakbrowser("cloakbrowser")
|
||||
|
||||
def test_legacy_playwright_emulation_uses_cloakbrowser_context(self):
|
||||
self._assert_get_page_source_uses_cloakbrowser("Playwright")
|
||||
|
||||
def test_legacy_browser_type_constructor_is_accepted(self):
|
||||
page = _FakePage()
|
||||
context = _FakeContext(page)
|
||||
|
||||
with patch.object(
|
||||
PlaywrightHelper,
|
||||
"_PlaywrightHelper__launch_cloakbrowser_context",
|
||||
return_value=context,
|
||||
):
|
||||
source = PlaywrightHelper(browser_type="firefox").get_page_source(
|
||||
url="https://example.com"
|
||||
)
|
||||
|
||||
self.assertEqual(source, "<html>ok</html>")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import tempfile
|
||||
import unittest
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
@@ -58,6 +59,35 @@ class LocalSetupConfigDirTests(unittest.TestCase):
|
||||
self.assertIsNone(result)
|
||||
prompt_mock.assert_not_called()
|
||||
|
||||
def test_install_deps_installs_browser_runtime(self):
|
||||
module = load_local_setup_module()
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
venv_dir = (Path(temp_dir) / "venv").resolve()
|
||||
venv_python = venv_dir / "bin" / "python"
|
||||
venv_pip = venv_dir / "bin" / "pip"
|
||||
|
||||
with patch.object(module, "ensure_supported_python"), \
|
||||
patch.object(
|
||||
module,
|
||||
"configure_venv_pip_compat",
|
||||
return_value=venv_pip,
|
||||
), \
|
||||
patch.object(module, "run") as run_mock, \
|
||||
patch.object(module, "install_browser_runtime") as install_browser:
|
||||
result = module.install_deps(
|
||||
python_bin="python3",
|
||||
venv_dir=venv_dir,
|
||||
recreate=False,
|
||||
)
|
||||
|
||||
self.assertEqual(result, venv_python)
|
||||
run_mock.assert_any_call(["python3", "-m", "venv", str(venv_dir)])
|
||||
run_mock.assert_any_call(
|
||||
[str(venv_pip), "install", "-r", str(module.ROOT / "requirements.txt")]
|
||||
)
|
||||
install_browser.assert_called_once_with(venv_python)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user