0 votes
19 views
ago by (30.6k points)
We want regression tests that run a process end to end without a browser: start an instance, complete the human tasks with data, and assert the final state and variables. What is a clean way to do that against a test Process Server?

1 Answer

0 votes
ago by (30.6k points)

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}&params={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&params={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

Related questions

723 questions

807 answers

98 comments

4.8k users

Join BPM Community Discord Channel

Welcome to BPM Tips Q&A, Community wiki/forum where you can ask questions and receive answers from other IBM BPM experts and members of the community. Users with 2000 points will automatically be promoted to expert level.
Created by Dosvak LLC
Our Youtube Channel
...