foxygit / RPA-Remisser Log in
commits tags

/tests/test_new_steps.py · 5.96 KB

raw
"""lookup / merge_json / read_url / prompt – nya steg i rpa/flow_engine.py."""

import json

import pytest

from rpa import flow_engine
from rpa.flow_engine import FlowError, _execute_step


def run_step(step, vars_, *, page=None):
    _execute_step(step, step["type"], page, lambda _m: None, vars_, None, None, {"session": None})
    return vars_


# --- lookup -------------------------------------------------------------

TABLE = {"MEDS Gastro|IBD": {"team": "MAGMOT", "orsak": "IBD"}, "X|Y": "platt"}


def test_lookup_from_var_ci_and_dict_result():
    v = run_step(
        {"type": "lookup", "from_var": "cfg", "key": "{g}|{s}", "var": "row", "ci": True},
        {"cfg": TABLE, "g": "meds gastro", "s": "ibd"},
    )
    assert v["row"] == {"team": "MAGMOT", "orsak": "IBD"}
    # dict-resultat -> {row.field} funkar i efterföljande steg
    run_step({"type": "set_var", "var": "t", "text": "{row.team}"}, v)
    assert v["t"] == "MAGMOT"


def test_lookup_case_sensitive_miss():
    with pytest.raises(FlowError, match="ingen rad"):
        run_step({"type": "lookup", "from_var": "cfg", "key": "x|y", "var": "r", "ci": "false"}, {"cfg": TABLE})


def test_lookup_on_missing_empty_and_default():
    v = run_step({"type": "lookup", "from_var": "cfg", "key": "nope", "var": "r", "on_missing": "empty"}, {"cfg": TABLE})
    assert v["r"] == ""
    v = run_step({"type": "lookup", "from_var": "cfg", "key": "nope", "var": "r", "on_missing": "MED"}, {"cfg": TABLE})
    assert v["r"] == "MED"


def test_lookup_from_file(tmp_path, monkeypatch):
    monkeypatch.setattr(flow_engine.config, "EXPORT_DIR", tmp_path)
    (tmp_path / "m.json").write_text(json.dumps(TABLE), encoding="utf-8")
    v = run_step({"type": "lookup", "file": "m.json", "key": "X|Y", "var": "r"}, {})
    assert v["r"] == "platt"


def test_lookup_requires_key_and_var():
    with pytest.raises(FlowError):
        run_step({"type": "lookup", "from_var": "cfg", "var": "r"}, {"cfg": TABLE})


def test_lookup_dotted_from_var_walks_nested_dict():
    cfg = {"elvis": {"translationTable": TABLE}}
    v = run_step(
        {"type": "lookup", "from_var": "cfg.elvis.translationTable", "key": "X|Y", "var": "r"},
        {"cfg": cfg},
    )
    assert v["r"] == "platt"


# --- stop ------------------------------------------------------------

def test_stop_raises_interpolated_message():
    with pytest.raises(FlowError, match="Gruppen 'MEDS Obesitas' hanteras inte"):
        run_step({"type": "stop", "message": "Gruppen '{g}' hanteras inte"}, {"g": "MEDS Obesitas"})


# --- read_url pattern ------------------------------------------------

def test_read_url_pattern_extracts_id():
    page = type("P", (), {"url": "https://salma.vgregion.se/incident/1269212?x=1"})()
    v = run_step({"type": "read_url", "var": "nr", "pattern": r"/incident/(?P<value>\d+)"}, {}, page=page)
    assert v["nr"] == "1269212"
    v = run_step({"type": "read_url", "var": "nr2", "pattern": r"\d{5,8}"}, {}, page=page)
    assert v["nr2"] == "1269212"


# --- merge_json --------------------------------------------------------

def test_merge_json_creates_and_updates(tmp_path, monkeypatch):
    monkeypatch.setattr(flow_engine.config, "EXPORT_DIR", tmp_path)
    run_step({"type": "merge_json", "file": "reg.json", "key": "A", "value": "1"}, {})
    run_step({"type": "merge_json", "file": "reg.json", "key": "{k}", "value": "{val}"}, {"k": "B", "val": "2"})
    data = json.loads((tmp_path / "reg.json").read_text(encoding="utf-8"))
    assert data == {"A": "1", "B": "2"}


def test_merge_json_rejects_path(monkeypatch, tmp_path):
    monkeypatch.setattr(flow_engine.config, "EXPORT_DIR", tmp_path)
    with pytest.raises(FlowError, match="Ogiltigt filnamn"):
        run_step({"type": "merge_json", "file": "../evil.json", "key": "a", "value": "b"}, {})


# --- read_url --------------------------------------------------------

def test_read_url():
    page = type("P", (), {"url": "https://salma.vgregion.se/incident/12345"})()
    v = run_step({"type": "read_url", "var": "u"}, {}, page=page)
    assert v["u"].endswith("/12345")


# --- prompt (subprocess mockad) --------------------------------------

def _fake_proc(stdout):
    return type("R", (), {"stdout": stdout, "stderr": "", "returncode": 0})()


def test_prompt_confirm_ok(monkeypatch):
    monkeypatch.setattr(flow_engine.subprocess, "run", lambda *a, **k: _fake_proc('{"ok": true}'))
    run_step({"type": "prompt", "mode": "confirm", "message": "Fortsätt?"}, {})  # ingen exception


def test_prompt_confirm_cancel_aborts(monkeypatch):
    monkeypatch.setattr(flow_engine.subprocess, "run", lambda *a, **k: _fake_proc('{"ok": false}'))
    with pytest.raises(FlowError, match="Avbrutet av användaren"):
        run_step({"type": "prompt", "mode": "confirm", "message": "x"}, {})


def test_prompt_input_sets_var(monkeypatch):
    monkeypatch.setattr(flow_engine.subprocess, "run", lambda *a, **k: _fake_proc('{"ok": true, "value": "99999-999"}'))
    v = run_step({"type": "prompt", "mode": "input", "message": "Nummer?", "var": "nr"}, {})
    assert v["nr"] == "99999-999"


def test_prompt_fields_writes_back_edited_values(monkeypatch):
    seen = {}

    def fake_run(*a, **k):
        seen["input"] = json.loads(k["input"])
        return _fake_proc('{"ok": true, "values": {"pnr": "19850101-1234", "datum": "20260115"}}')

    monkeypatch.setattr(flow_engine.subprocess, "run", fake_run)
    v = run_step(
        {"type": "prompt", "mode": "fields", "message": "Kontrollera", "fields": "pnr, datum"},
        {"pnr": "1985010I-1234", "datum": "20260115"},
    )
    assert seen["input"]["fields"] == ["pnr", "datum"]
    assert v["pnr"] == "19850101-1234"  # användaren rättade OCR-felet


def test_prompt_interpolates_message(monkeypatch):
    seen = {}
    monkeypatch.setattr(flow_engine.subprocess, "run",
                        lambda *a, **k: (seen.update(json.loads(k["input"])), _fake_proc('{"ok": true}'))[1])
    run_step({"type": "prompt", "mode": "confirm", "message": "Spara {namn}?"}, {"namn": "Anna"})
    assert seen["message"] == "Spara Anna?"