from os import terminal_size from rich.console import Console from rich.tree import Tree from browser_cli.models import Tab from browser_cli.commands import rendering from browser_cli.commands.rendering import common def test_shorten_uses_ellipsis(): assert rendering.shorten("abcdef", 4) == "abc…" assert rendering.shorten("abc", 4) == "abc" def test_terminal_width_prefers_shell_width_when_rich_is_redirected(monkeypatch): monkeypatch.setattr(common.shutil, "get_terminal_size", lambda fallback: terminal_size((140, 20))) assert rendering.terminal_width(Console(width=80)) == 140 def test_browser_label_style_distinguishes_browser_families(): assert rendering.browser_label_style("Firefox") == "orange1" assert rendering.browser_label_style("Chrome") == "cyan" assert rendering.browser_label_style(None) == "bold cyan" def test_scoped_browser_label_strips_repeated_remote_prefix(): assert rendering.scoped_browser_label("browser-host.example:work", "browser-host.example", grouped=True) == "work" assert rendering.scoped_browser_label("work", "browser-host.example", grouped=True) == "work" assert rendering.scoped_browser_label("browser-host.example:work", "browser-host.example", grouped=False) == "browser-host.example:work" def test_tab_tree_label_is_reusable_no_wrap_text(): tab = type("Tab", (), {"id": 1, "title": "abcdef", "active": True, "url": "https://example.com"})() label = rendering.tab_tree_label(tab, title_limit=4, show_urls=True, url_limit=12) assert label.no_wrap is True assert label.overflow == "ellipsis" assert "abc…" in label.plain assert "https://exa…" in label.plain def test_print_tree_uses_detected_width(monkeypatch): widths = [] class CapturingConsole(Console): def __init__(self, *args, **kwargs): widths.append(kwargs.get("width")) super().__init__(*args, **kwargs) monkeypatch.setattr(common, "Console", CapturingConsole) monkeypatch.setattr(common, "terminal_width", lambda console=None: 132) rendering.print_tree(Tree("Root")) assert widths == [132] def test_build_tabs_tree_groups_by_browser_window_and_group(): tabs = [ Tab(id=1, window_id=5, active=False, muted=False, title="Before", url="https://example.com/before", group_id=None, index=0, browser="work"), Tab(id=2, window_id=5, active=False, muted=False, title="Inside", url="https://example.com/inside", group_id=9, index=1, browser="work"), ] groups = [{"id": 9, "windowId": 5, "browser": "work", "title": "Research", "color": "blue", "tabCount": 1, "collapsed": True}] tree = rendering.build_tabs_tree(tabs, groups, console=Console(width=120), show_urls=True) text = "\n".join(str(line) for line in tree.__rich_console__(Console(width=120), Console(width=120).options)) assert "work" in text assert "Window 5" in text assert "Research" in text assert "collapsed" in text assert "Inside" in text def test_build_tabs_tree_groups_remote_browsers_by_scope(): tabs = [ Tab(id=1, window_id=5, active=False, muted=False, title="Remote A", url="https://example.com/a", index=0, browser="main", browser_group="browser-host.example"), Tab(id=2, window_id=6, active=False, muted=False, title="Remote B", url="https://example.com/b", index=0, browser="work", browser_group="browser-host.example"), Tab(id=3, window_id=7, active=False, muted=False, title="Local", url="https://example.com/local", index=0, browser="local"), ] tree = rendering.build_tabs_tree(tabs, [], console=Console(width=120)) text = "\n".join(str(line) for line in tree.__rich_console__(Console(width=120), Console(width=120).options)) assert "browser-host.example" in text assert "main" in text assert "work" in text assert "browser-host.example:main" not in text assert "browser-host.example:work" not in text assert "Local" in text def test_build_windows_tree_keeps_multi_browser_windows_separate(): tabs = [ Tab(id=1, window_id=5, active=False, muted=False, title="Work Tab", url="https://example.com/work", index=0, browser="work"), Tab(id=2, window_id=5, active=False, muted=False, title="Personal Tab", url="https://example.com/personal", index=0, browser="personal"), ] windows = [ {"id": 5, "alias": "main", "browser": "work", "tabCount": 1, "state": "normal"}, {"id": 5, "alias": "main", "browser": "personal", "tabCount": 1, "state": "normal"}, ] tree = rendering.build_windows_tree(windows, tabs, console=Console(width=120)) text = "\n".join(str(line) for line in tree.__rich_console__(Console(width=120), Console(width=120).options)) assert "work: Window 5" in text assert "personal: Window 5" in text assert "Work Tab" in text assert "Personal Tab" in text