}})
- {%- set effective_fetcher = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%}
+ {%- set _fb = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%}
+ {# The watch may store a browser-config id - resolve it to the underlying engine so the status icon (built-in or plugin) matches by engine name. #}
+ {%- set _bc = datastore.browser_config_store.get(_fb) -%}
+ {%- set effective_fetcher = _bc.base_fetcher if _bc else _fb -%}
{%- if effective_fetcher and ("html_webdriver" in effective_fetcher or "html_" in effective_fetcher or "extra_browser_" in effective_fetcher) -%}
{{ effective_fetcher|fetcher_status_icons }}
{%- endif -%}
diff --git a/changedetectionio/content_fetchers/puppeteer.py b/changedetectionio/content_fetchers/puppeteer.py
index b163332a..41775ce1 100644
--- a/changedetectionio/content_fetchers/puppeteer.py
+++ b/changedetectionio/content_fetchers/puppeteer.py
@@ -181,7 +181,7 @@ class fetcher(Fetcher):
proxy = None
# Capability flags
- supports_browser_steps = True
+ supports_browser_steps = True # @note Not really, it actually starts a playwright session.
supports_screenshots = True
supports_xpath_element_data = True
supports_request_blocking = True
diff --git a/changedetectionio/pluggy_interface.py b/changedetectionio/pluggy_interface.py
index 6b5a036d..d9f18468 100644
--- a/changedetectionio/pluggy_interface.py
+++ b/changedetectionio/pluggy_interface.py
@@ -456,10 +456,14 @@ def get_fetcher_capabilities(watch, datastore):
'supports_xpath_element_data': bool
}
"""
- # Resolve the watch's fetch_backend (which may be a browser-config id, engine name or
- # 'system') to the concrete engine name via the shared browser-config helper.
- from changedetectionio.model.browser_config import base_fetcher_for
- fetcher_name = base_fetcher_for(watch.get('fetch_backend', 'system'), datastore)
+ # Resolve the EFFECTIVE browser to a concrete engine name, mirroring resolve_content_fetcher:
+ # a group override wins over the watch's own fetch_backend. Then map that (browser-config id,
+ # engine name or 'system') to the engine so capability checks (Visual Selector etc.) reflect
+ # what will actually fetch the page.
+ from changedetectionio.model.browser_config import base_fetcher_for, resolve_browser_config_override
+ override = resolve_browser_config_override(watch, datastore)
+ selected = override['config_id'] if override else watch.get('fetch_backend', 'system')
+ fetcher_name = base_fetcher_for(selected, datastore)
# Get the fetcher class
from changedetectionio import content_fetchers
diff --git a/changedetectionio/tests/test_browser_config.py b/changedetectionio/tests/test_browser_config.py
index d9aa8ca0..e3d9e71a 100644
--- a/changedetectionio/tests/test_browser_config.py
+++ b/changedetectionio/tests/test_browser_config.py
@@ -92,6 +92,10 @@ def test_watch_browser_picker_and_resolution(client, live_server, measure_memory
follow_redirects=True)
assert datastore.data['watching'][uuid]['fetch_backend'] == cid
+ # Watchlist renders fine for a watch whose fetch_backend is a browser-config id - the
+ # status icon resolves to the underlying base engine (html_webdriver) as before.
+ assert client.get(url_for("watchlist.index")).status_code == 200
+
# Resolver maps the browser id -> engine + FetcherConfig
_cls, backend_name, _url, browser_config = resolve_content_fetcher(datastore.data['watching'][uuid], datastore)
assert backend_name == 'html_webdriver'
@@ -251,6 +255,13 @@ def test_group_browser_config_override(client, live_server, measure_memory_usage
assert browser_config.locale == 'fr-FR'
assert browser_config.viewport_width == 375
+ # Capabilities (used to gate the Visual Selector tab) must reflect the OVERRIDING browser's
+ # engine, not the watch's own fetch_backend - the user browser is html_webdriver here.
+ from changedetectionio.pluggy_interface import get_fetcher_capabilities
+ caps = get_fetcher_capabilities(datastore.data['watching'][uuid], datastore)
+ assert caps['supports_screenshots'] is True
+ assert caps['supports_xpath_element_data'] is True
+
def test_group_override_with_builtin_browser(client, live_server, measure_memory_usage, datastore_path):
"""A group can also override with a built-in engine (e.g. html_webdriver), not just a user browser."""