"""Test that plugins can inject HTML into base.html via get_html_head_extras hookimpl.""" import pytest from flask import url_for, Response from changedetectionio.pluggy_interface import hookimpl, plugin_manager _MY_JS = "console.log('my_module_content loaded');" _MY_CSS = ".my-module-example { color: red; }" class _HeadExtrasPlugin: """Test plugin that injects tags pointing at its own Flask routes.""" @hookimpl def get_html_head_extras(self): css_url = url_for('test_plugin_my_module_content_css') js_url = url_for('test_plugin_my_module_content_js') return ( f'\n' f'' ) @pytest.fixture(scope='module') def plugin_routes(live_server): """Register plugin asset routes once per module (Flask routes can't be added twice).""" app = live_server.app @app.route('/test-plugin/my_module_content/css') def test_plugin_my_module_content_css(): return Response(_MY_CSS, mimetype='text/css', headers={'Cache-Control': 'max-age=3600'}) @app.route('/test-plugin/my_module_content/js') def test_plugin_my_module_content_js(): return Response(_MY_JS, mimetype='application/javascript', headers={'Cache-Control': 'max-age=3600'}) @pytest.fixture def head_extras_plugin(plugin_routes): """Register the hookimpl for one test then unregister it — function-scoped for clean isolation.""" plugin = _HeadExtrasPlugin() plugin_manager.register(plugin, name="test_head_extras") yield plugin plugin_manager.unregister(name="test_head_extras") def test_plugin_html_injected_into_head(client, live_server, measure_memory_usage, datastore_path, head_extras_plugin): """get_html_head_extras output must appear inside in the rendered page.""" res = client.get(url_for("watchlist.index"), follow_redirects=True) assert res.status_code == 200 assert b'id="test-head-extra-css"' in res.data, "Plugin tag missing from rendered page" assert b'id="test-head-extra-js"' in res.data, "Plugin