Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion crawl4ai/browser_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,25 @@ def __init__(
host (str): Host for debugging the browser. Default: "localhost".
debugging_port (int): Port for debugging the browser. Default: 9222.
cdp_url (str or None): CDP URL to connect to the browser. Default: None.
browser_config (BrowserConfig): Configuration object containing all browser settings. Default: None.
browser_config (BrowserConfig): Configuration object carrying the same settings. When
given it is used as-is and the individual arguments
above are ignored; when omitted one is built from
them. Default: None.
"""
if browser_config is None:
# Every attribute below is read off `browser_config`, so without this the
# documented all-arguments form raised
# `AttributeError: 'NoneType' object has no attribute 'browser_type'`, and the
# arguments themselves reached nothing.
browser_config = BrowserConfig(
browser_type=browser_type,
headless=headless,
user_data_dir=user_data_dir,
host=host,
debugging_port=debugging_port,
cdp_url=cdp_url,
)

self.browser_type = browser_config.browser_type
self.user_data_dir = browser_config.user_data_dir
self.headless = browser_config.headless
Expand Down
66 changes: 66 additions & 0 deletions tests/unit/test_managed_browser_arguments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""`ManagedBrowser` reads every setting off `browser_config`.

Without one, that raised `AttributeError: 'NoneType' object has no attribute
'browser_type'` for the documented all-arguments form, which is how
`BrowserProfiler.launch_builtin_browser` constructs it — so `crwl browser start`
and `crwl browser restart` could not start a browser at all.
"""

import pytest

from crawl4ai.async_configs import BrowserConfig
from crawl4ai.browser_manager import ManagedBrowser


def test_defaults_construct_without_a_config():
browser = ManagedBrowser()

assert browser.browser_type == "chromium"
assert browser.debugging_port == 9222
assert browser.host == "localhost"


def test_launch_builtin_browser_argument_shape_constructs():
"""The exact call `BrowserProfiler.launch_builtin_browser` makes."""
browser = ManagedBrowser(
browser_type="chromium",
user_data_dir="/tmp/crawl4ai-builtin",
headless=True,
logger=None,
debugging_port=9333,
)

assert browser.user_data_dir == "/tmp/crawl4ai-builtin"
assert browser.debugging_port == 9333


@pytest.mark.parametrize(
("kwargs", "attribute", "expected"),
[
({"browser_type": "firefox"}, "browser_type", "firefox"),
({"user_data_dir": "/tmp/profile"}, "user_data_dir", "/tmp/profile"),
({"headless": False}, "headless", False),
({"host": "0.0.0.0"}, "host", "0.0.0.0"),
({"debugging_port": 9333}, "debugging_port", 9333),
({"cdp_url": "http://localhost:9444"}, "cdp_url", "http://localhost:9444"),
],
)
def test_each_argument_reaches_the_instance(kwargs, attribute, expected):
assert getattr(ManagedBrowser(**kwargs), attribute) == expected


def test_a_supplied_config_still_wins():
"""Existing callers pass both; the config is the source of truth and stays so."""
config = BrowserConfig(browser_type="chromium", debugging_port=9222, headless=True)

browser = ManagedBrowser(
browser_type="firefox",
debugging_port=9333,
headless=False,
browser_config=config,
)

assert browser.browser_type == "chromium"
assert browser.debugging_port == 9222
assert browser.headless is True
assert browser.browser_config is config