commit 46f1625647080af02dd7bea664321a3ce9563f39
Author: Jens Kristoffersson <jens.kristoffersson.se@gmail.com>
AuthorDate: Fri Sep 4 13:50:00 2026 +0200
Commit: Jens Kristoffersson <jens.kristoffersson.se@gmail.com>
CommitDate: Fri Sep 4 13:50:00 2026 +0200
skip_browser: ignorera inaktiverade steg + logga vad som kraver webblasaren
- ett inaktiverat webblasarsteg (enabled:false) tvingar inte langre igang Chromium
- korloggen sager nu "Startar webblasare (kravs av steg: click 'knappen')" sa det
gar att se varfor den oppnades
---
rpa/flow_engine.py | 34 +++++++++++++++++++++++++++++++++-
tests/test_skip_browser.py | 17 +++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/rpa/flow_engine.py b/rpa/flow_engine.py
index df020ba..602454b 100644
--- a/rpa/flow_engine.py
+++ b/rpa/flow_engine.py
@@ -170,7 +170,10 @@ def _condition_needs_browser(cond: dict) -> bool:
def _step_needs_browser(step: dict) -> bool:
- """True om steget (eller något nästlat steg / if-villkor) kräver Playwright."""
+ """True om steget (eller något nästlat steg / if-villkor) kräver Playwright.
+ Inaktiverade steg räknas inte - de hoppas över vid körning."""
+ if step.get("enabled") is False:
+ return False
t = step.get("type")
if t in _DESKTOP_STEPS or (t in _NO_BROWSER_STEPS and t not in ("loop", "if")):
return False
@@ -190,6 +193,31 @@ def _flow_needs_browser(steps: list) -> bool:
return any(_step_needs_browser(s) for s in steps)
+def _first_browser_step(steps: list) -> str | None:
+ """Beskrivning av det första steget som gör att webbläsaren måste startas -
+ för att kunna säga det i körloggen. Ignorerar inaktiverade steg? Nej, motorn
+ startar webbläsaren oavsett enabled (enkelhet)."""
+ for step in steps:
+ if not _step_needs_browser(step):
+ continue
+ t = step.get("type")
+ if t == "loop":
+ inner = _first_browser_step(step.get("steps", []))
+ return f"loop -> {inner}" if inner else t
+ if t == "if":
+ for br in step.get("branches", []):
+ if _condition_needs_browser(br.get("condition", {})):
+ return f"if ({br['condition'].get('kind')})"
+ inner = _first_browser_step(br.get("steps", []))
+ if inner:
+ return f"if -> {inner}"
+ inner = _first_browser_step(step.get("else") or [])
+ return f"if/else -> {inner}" if inner else t
+ label = step.get("label")
+ return f"{t}" + (f" '{label}'" if label else "")
+ return None
+
+
_BAD_FILENAME_CHARS = re.compile(r'[<>:"/\\|?*\x00-\x1f]')
@@ -1119,6 +1147,10 @@ def run_flow(
)
return
+ reason = _first_browser_step(steps)
+ if reason:
+ log(f"Startar webbläsare (krävs av steg: {reason}).")
+
with sync_playwright() as p:
context = launch_context(p, settings)
if trace_path is not None:
diff --git a/tests/test_skip_browser.py b/tests/test_skip_browser.py
index 4ce1b4c..c124cb0 100644
--- a/tests/test_skip_browser.py
+++ b/tests/test_skip_browser.py
@@ -42,6 +42,23 @@ def test_if_with_element_condition_needs_browser():
assert flow_engine._flow_needs_browser(steps) is True
+def test_disabled_browser_step_does_not_force_browser():
+ steps = [
+ {"type": "desktop_launch", "path": "notepad.exe"},
+ {"type": "click", "by": "text", "value": "X", "enabled": False},
+ ]
+ assert flow_engine._flow_needs_browser(steps) is False
+
+
+def test_first_browser_step_names_the_trigger():
+ steps = [
+ {"type": "desktop_launch", "path": "x"},
+ {"type": "click", "by": "text", "value": "Y", "label": "knappen"},
+ ]
+ assert flow_engine._first_browser_step(steps) == "click 'knappen'"
+ assert flow_engine._first_browser_step([{"type": "set_var", "var": "a", "text": "1"}]) is None
+
+
# --- integration: webbläsaren startas inte -------------------------------
def test_run_flow_skips_browser_for_var_only(tmp_path, monkeypatch):