Skip to content

Commit 447e448

Browse files
committed
fix: robots.txt- und Drossel-Einstellung speichern und beim Oeffnen anzeigen
1 parent 71d896d commit 447e448

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

src/console_error_scanner/app.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,15 +1347,21 @@ def action_show_settings(self) -> None:
13471347
"language": self._settings.language,
13481348
"accept_consent": self._settings.accept_consent,
13491349
"trigger_lazy_load": self._settings.trigger_lazy_load,
1350+
"respect_robots": self._settings.respect_robots,
13501351
"concurrency": self._settings.concurrency,
1352+
"rate_limit_enabled": self._settings.rate_limit_enabled,
1353+
"rate_per_minute": self._settings.rate_per_minute,
13511354
"timeout": self._settings.timeout,
13521355
"console_level": self._settings.console_level,
13531356
"show_preview": self._settings.show_preview,
13541357
"no_headless": self._settings.no_headless,
1358+
"size_warn_mb": self._settings.size_warn_mb,
1359+
"score_error_weight": self._settings.score_error_weight,
13551360
"user_agent": self._settings.user_agent,
13561361
"cookies": self._settings.cookies,
13571362
"whitelist_path": self._settings.whitelist_path,
13581363
"proxy_url": self._settings.proxy_url,
1364+
"jira_format": self._settings.jira_format,
13591365
}
13601366
self.push_screen(
13611367
ScannerSettingsScreen(current, lang=current_language()),
@@ -1377,7 +1383,9 @@ def _on_settings_closed(self, result: dict[str, object] | None) -> None:
13771383
"language": self._settings.language,
13781384
"accept_consent": self._settings.accept_consent,
13791385
"trigger_lazy_load": self._settings.trigger_lazy_load,
1386+
"respect_robots": self._settings.respect_robots,
13801387
"concurrency": self._settings.concurrency,
1388+
"rate_limit_enabled": self._settings.rate_limit_enabled,
13811389
"timeout": self._settings.timeout,
13821390
"console_level": self._settings.console_level,
13831391
"show_preview": self._settings.show_preview,
@@ -1393,7 +1401,10 @@ def _on_settings_closed(self, result: dict[str, object] | None) -> None:
13931401
self._settings.language = str(result.get("language", self._settings.language))
13941402
self._settings.accept_consent = bool(result.get("accept_consent", self._settings.accept_consent))
13951403
self._settings.trigger_lazy_load = bool(result.get("trigger_lazy_load", self._settings.trigger_lazy_load))
1404+
self._settings.respect_robots = bool(result.get("respect_robots", self._settings.respect_robots))
13961405
self._settings.concurrency = int(result.get("concurrency", self._settings.concurrency)) # type: ignore[arg-type]
1406+
self._settings.rate_limit_enabled = bool(result.get("rate_limit_enabled", self._settings.rate_limit_enabled))
1407+
self._settings.rate_per_minute = int(result.get("rate_per_minute", self._settings.rate_per_minute)) # type: ignore[arg-type]
13971408
self._settings.timeout = int(result.get("timeout", self._settings.timeout)) # type: ignore[arg-type]
13981409
self._settings.console_level = str(result.get("console_level", self._settings.console_level))
13991410
self._settings.show_preview = bool(result.get("show_preview", self._settings.show_preview))
@@ -1406,11 +1417,13 @@ def _on_settings_closed(self, result: dict[str, object] | None) -> None:
14061417
str(result.get("score_error_weight", self._settings.score_error_weight))
14071418
)
14081419
self._settings.proxy_url = str(result.get("proxy_url", self._settings.proxy_url))
1420+
self._settings.jira_format = str(result.get("jira_format", self._settings.jira_format))
14091421
self._settings.save()
14101422

14111423
# Runtime-Werte fuer den naechsten Scan aktualisieren
14121424
self.accept_consent = self._settings.accept_consent
14131425
self.trigger_lazy_load = self._settings.trigger_lazy_load
1426+
self.respect_robots = self._settings.respect_robots
14141427
self.concurrency = self._settings.concurrency
14151428
self.rate_per_minute = self._settings.rate_per_minute if self._settings.rate_limit_enabled else 0
14161429
self.timeout = self._settings.timeout
@@ -1437,7 +1450,9 @@ def _on_settings_closed(self, result: dict[str, object] | None) -> None:
14371450
("language", t("binding.settings") + " (Lang)"),
14381451
("accept_consent", t("settings.consent_label")),
14391452
("trigger_lazy_load", t("settings.scroll_label")),
1453+
("respect_robots", t("settings.robots_label")),
14401454
("concurrency", t("settings.concurrency_label")),
1455+
("rate_limit_enabled", t("settings.rate_label")),
14411456
("timeout", t("settings.timeout_label")),
14421457
("console_level", t("settings.console_level_label")),
14431458
("show_preview", t("settings.preview_label")),

tests/test_settings_roundtrip.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Regression: Scanner-Einstellungen ueberleben Speichern + erneutes Oeffnen.
2+
3+
Deckt den Bug ab, bei dem 'robots.txt beachten' und 'Aufrufe drosseln' nach dem
4+
Speichern wieder angehakt waren: die App reichte diese Felder weder in den Dialog
5+
hinein (action_show_settings) noch aus dem Ergebnis zurueck in die persistierten
6+
Einstellungen (_on_settings_closed). Der reine to_dict()-Roundtrip in
7+
test_safe_defaults deckte das NICHT ab, weil er das App-Mapping ueberspringt.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
import asyncio
13+
from pathlib import Path
14+
15+
from textual.widgets import Checkbox
16+
17+
from console_error_scanner import app as app_module
18+
from console_error_scanner.app import ConsoleErrorScannerApp
19+
from console_error_scanner.i18n import load_locale
20+
from console_error_scanner.models import settings as settings_module
21+
from console_error_scanner.models.settings import Settings
22+
23+
24+
def _isolate(tmp_path: Path, monkeypatch: object) -> Path:
25+
"""Verlegt die settings.json in tmp_path und ueberspringt den Disclaimer."""
26+
settings_file = tmp_path / "settings.json"
27+
monkeypatch.setattr(settings_module, "SETTINGS_DIR", tmp_path) # type: ignore[attr-defined]
28+
monkeypatch.setattr(settings_module, "SETTINGS_FILE", settings_file) # type: ignore[attr-defined]
29+
monkeypatch.setattr(Settings, "SETTINGS_DIR", tmp_path) # type: ignore[attr-defined]
30+
monkeypatch.setattr(Settings, "SETTINGS_FILE", settings_file) # type: ignore[attr-defined]
31+
monkeypatch.setattr(app_module, "SETTINGS_FILE", settings_file) # type: ignore[attr-defined]
32+
monkeypatch.setattr(ConsoleErrorScannerApp, "_ask_disclaimer", lambda self: None) # type: ignore[attr-defined]
33+
load_locale("de")
34+
return settings_file
35+
36+
37+
def test_robots_and_rate_survive_save_and_reopen(tmp_path: Path, monkeypatch: object) -> None:
38+
_isolate(tmp_path, monkeypatch)
39+
40+
async def drive() -> None:
41+
app = ConsoleErrorScannerApp()
42+
async with app.run_test() as pilot:
43+
app.action_show_settings()
44+
await pilot.pause()
45+
app.screen.query_one("#set-robots", Checkbox).value = False
46+
app.screen.query_one("#set-rate-on", Checkbox).value = False
47+
await pilot.pause()
48+
await pilot.press("ctrl+s")
49+
await pilot.pause()
50+
51+
# Erneut oeffnen: der Dialog muss den gespeicherten Zustand zeigen
52+
# (deckt das fehlende Feld im current-Dict ab).
53+
app.action_show_settings()
54+
await pilot.pause()
55+
assert app.screen.query_one("#set-robots", Checkbox).value is False
56+
assert app.screen.query_one("#set-rate-on", Checkbox).value is False
57+
58+
asyncio.run(drive())
59+
60+
# Und auf der Platte gelandet (deckt das fehlende Mapping in
61+
# _on_settings_closed ab).
62+
reloaded = Settings.load()
63+
assert reloaded.respect_robots is False
64+
assert reloaded.rate_limit_enabled is False

0 commit comments

Comments
 (0)