diff --git a/tests/test_cancel_stream_owner_guard.py b/tests/test_cancel_stream_owner_guard.py index 6b85b66f4..e149dd420 100644 --- a/tests/test_cancel_stream_owner_guard.py +++ b/tests/test_cancel_stream_owner_guard.py @@ -329,7 +329,16 @@ def _run_cancel_stream_scenarios() -> dict: f"--- stderr ---\n{completed.stderr}" ) try: - return json.loads(completed.stdout) + # The function under test legitimately emits diagnostic lines on stdout + # (e.g. cancelStream's '[stream] cancel requested' provenance log, added + # for #5345). Those fire DURING runAll(); the result JSON is written by + # `console.log(JSON.stringify(r))` only after runAll() resolves, so it is + # always the LAST non-empty stdout line. Parse that rather than assuming + # stdout is pure JSON. + lines = [ln for ln in completed.stdout.splitlines() if ln.strip()] + if not lines: + raise json.JSONDecodeError("empty stdout", completed.stdout or "", 0) + return json.loads(lines[-1]) except json.JSONDecodeError as e: raise AssertionError( f"node subprocess returned non-JSON output:\n" diff --git a/tests/test_sprint36.py b/tests/test_sprint36.py index 97b5d6fe3..89bc6f9f0 100644 --- a/tests/test_sprint36.py +++ b/tests/test_sprint36.py @@ -46,8 +46,11 @@ class TestCancelStreamCleanup: def _get_cancel_block(self): """Extract the cancelStream function body from boot.js.""" src = read("static/boot.js") - idx = src.find("async function cancelStream()") - assert idx != -1, "cancelStream not found in boot.js" + # Signature-tolerant: cancelStream now takes a `reason` param (#5345), so + # match the declaration regardless of its parameter list. + m = re.search(r"async function cancelStream\s*\(", src) + assert m is not None, "cancelStream not found in boot.js" + idx = m.start() # Find the closing brace — scan for the matching } depth = 0 end = idx @@ -122,8 +125,13 @@ class TestCancelStreamErrorPath: The status is cleared by setStatus('') unconditionally. """ src = read("static/boot.js") - idx = src.find("async function cancelStream()") - block = src[idx:idx + 400] + # Signature-tolerant match (cancelStream now takes a `reason` param, #5345). + m = re.search(r"async function cancelStream\s*\(", src) + assert m is not None, "cancelStream not found in boot.js" + idx = m.start() + # Widen the window: the provenance log + comments added for #5345 sit + # before the try/catch, so 400 chars no longer reaches the catch block. + block = src[idx:idx + 1200] # The old pattern was setStatus inside catch; new pattern has it outside # Look for the catch block specifically catch_idx = block.find("}catch(")