Everything a user does through the portal has a REST call; a test is a sequence of them. A compact Python harness (pytest) that works on 8.5.7 / BAW / CP4BA:
# bawtest.py - helpers (requests); on CP4BA use headers={"Authorization": "ZenApiKey ..."} instead of auth=
import requests, json, time
class Baw:
def __init__(s, base, auth): s.base, s.auth = base, auth; s.s = requests.Session(); s.s.verify = False
def token(s):
r = s.s.post(s.base + "/rest/bpm/wle/v1/system/login", json={"refresh_groups": False, "requested_lifetime": 7200}, auth=s.auth); s.tok = r.json().get("csrf_token", ""); return s.tok
def call(s, method, path, **kw):
h = kw.pop("headers", {}); h["BPMCSRFToken"] = s.tok
r = s.s.request(method, s.base + "/rest/bpm/wle/v1" + path, auth=s.auth, headers=h, **kw); r.raise_for_status(); return r.json()["data"]
def start(s, bpd_id, snapshot_id, params): return s.call("POST", f"/process?action=start&bpdId={bpd_id}&snapshotId={snapshot_id}¶ms={json.dumps(params)}&parts=header")
def instance(s, piid): return s.call("GET", f"/process/{piid}?parts=header,data,executionTree")
def tasks(s, piid): return [t for t in s.call("GET", f"/process/{piid}?parts=executionTree")["executionTree"]["root"].get("children", []) for t in [t] if t.get("createdTaskIDs")]
def open_tasks(s, piid): return s.call("PUT", f"/search/query?organization=byTask&run=true&filterByCurrentUser=false&size=50&condition=instanceId%7C{piid.split('.')[-1]}&condition=taskStatus%7CReceived")["data"]
def finish(s, task_id, output): return s.call("PUT", f"/task/{task_id}?action=finish¶ms={json.dumps(output)}&parts=none")
def wait(s, piid, state, timeout=60):
for _ in range(timeout): st = s.instance(piid)["state"];
return st
# test_order.py
def test_small_order_is_auto_approved(baw):
inst = baw.start(BPD, SNAP, {"order": {"number": "T-1", "total": 500}})
piid = inst["piid"]; time.sleep(3)
data = baw.instance(piid)
assert data["state"] == "STATE_FINISHED"; assert data["data"]["variables"]["order"]["status"] == "APPROVED"
def test_large_order_needs_approval(baw):
piid = baw.start(BPD, SNAP, {"order": {"number": "T-2", "total": 50000}})["piid"]; time.sleep(3)
tasks = baw.open_tasks(piid); assert len(tasks) == 1 and tasks[0]["taskSubject"].startswith("Approve")
baw.finish(tasks[0]["taskId"], {"decision": "REJECTED", "comment": "test"}); time.sleep(3)
assert baw.instance(piid)["data"]["variables"]["order"]["status"] == "REJECTED" Practices: a dedicated test user in every team of the app (the harness claims / completes as that user, or as an administrator with action=finish which bypasses claiming); deterministic test data (stub external systems with WireMock and point the Server definitions at it in the test environment); clean up instances after the run (Operations REST delete by a test tag in the instance name); run the suite in the pipeline after every snapshot install (question on CI). Coach UI tests are separate (Playwright against the task URLs) and fewer - the process logic is best tested at the REST level.
References