feat(tabs): reuse an open tab instead of duplicating a page
Testing / remote-protocol-compat (0.15.0) (push) Successful in 42s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 47s
Testing / test (push) Successful in 50s

- Add browser_cli/url_match.py with a canonical URL key for tab matching
- Canonicalize scheme, host, default ports, www., trailing slash, query order
- Support reuse modes none, exact, similar and origin via normalize_mode()
- Pick the closest match when several tabs qualify, preferring identical URLs
- Skip the reload when the reused tab already shows the requested page
- Expose nav.reusable_tab() so callers can look up a tab without side effects
- Accept reuse/reuse_domain/reuse_title in tabs.open(), not just nav.open()
- Add --reuse-exact to nav open and nav open-wait; --reuse is now fuzzy
- Default MCP tabs_open to reuse="similar" and return a reused flag
- Tell MCP agents in the server instructions to reuse before opening
- Document the reuse modes in README for MCP, CLI and Python API
- Cover url_match, SDK reuse paths and MCP reuse behaviour with new tests
- Bump package and extension version to 0.16.9
- Refresh uv.lock for the updated dependency set
This commit is contained in:
2026-10-19 10:47:56 +02:00
parent 6c0f77e416
commit 7cb034dfc2
12 changed files with 600 additions and 203 deletions
+44 -5
View File
@@ -34,21 +34,60 @@ def test_session_export_cli_prints_json():
assert result.exit_code == 0
assert '"name": "work"' in result.output
def test_nav_open_reuse_navigates_existing_tab_instead_of_opening_new():
calls = []
def _reuse_sender(calls, tab_url="https://example.com"):
tab = {"id": 7, "windowId": 1, "active": False, "muted": False, "title": "Example", "url": tab_url}
def sender(command, args=None, **kwargs):
calls.append((command, args))
if command == "tabs.list":
return [{"id": 7, "windowId": 1, "active": False, "muted": False, "title": "Example", "url": "https://example.com"}]
return [tab]
if command in {"tabs.status", "navigate.open"}:
return dict(tab)
return {}
return sender
BrowserCLI(browser="testing", _command_sender=sender).nav.open("https://example.com", reuse=True)
def test_nav_open_reuse_navigates_existing_tab_instead_of_opening_new():
calls = []
BrowserCLI(browser="testing", _command_sender=_reuse_sender(calls, "https://example.com/app?a=1")).nav.open(
"https://example.com/app?a=2", reuse=True
)
assert calls == [
("tabs.list", {}),
("navigate.to", {"tabId": 7, "url": "https://example.com"}),
("navigate.to", {"tabId": 7, "url": "https://example.com/app?a=2"}),
]
def test_nav_open_reuse_matches_nearly_identical_urls():
calls = []
BrowserCLI(browser="testing", _command_sender=_reuse_sender(calls, "https://example.com/app?a=1&b=2")).nav.open(
"https://www.example.com/app/?b=2&a=1#top", reuse=True
)
assert calls == [("tabs.list", {})] # same page already open → no reload, no new tab
def test_nav_open_reuse_exact_opens_a_new_tab_for_a_different_url():
calls = []
BrowserCLI(browser="testing", _command_sender=_reuse_sender(calls)).nav.open(
"https://example.com/", reuse="exact"
)
assert [command for command, _ in calls] == ["tabs.list", "navigate.open"]
def test_tabs_open_reuse_returns_the_existing_tab():
calls = []
tab = BrowserCLI(browser="testing", _command_sender=_reuse_sender(calls)).tabs.open(
"https://example.com/deep/page", reuse="origin"
)
assert tab.id == 7
assert [command for command, _ in calls] == ["tabs.list", "navigate.to", "tabs.status"]
def test_tabs_open_without_reuse_always_creates_a_tab():
calls = []
BrowserCLI(browser="testing", _command_sender=_reuse_sender(calls)).tabs.open("https://example.com")
assert [command for command, _ in calls] == ["navigate.open"]
def _tree_sender(tabs, groups):
def sender(command, args=None, **kwargs):
if command == "tabs.list":