Implement role-based account journeys with database and browser acceptance suites
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 20s
Account journey acceptance / journeys (push) Failing after 0s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
This commit is contained in:
tegwick 2026-09-13 12:20:02 +02:00
parent 75750c0036
commit 1127f852dd
24 changed files with 1554 additions and 148 deletions

View file

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Run mapped acceptance tests; report external gaps separately from test results."""
import argparse
import json
from pathlib import Path
import sys
import unittest
ROOT=Path(__file__).resolve().parents[1]
sys.path[:0]=[str(ROOT/'src'),str(ROOT/'tests')]
parser=argparse.ArgumentParser()
parser.add_argument('--role',choices=['user','tenant_admin','platform_admin'])
parser.add_argument('--report',type=Path)
parser.add_argument('--require-complete',action='store_true',help='Fail while any journey has an implementation or external acceptance gap')
args=parser.parse_args()
rows=json.loads((ROOT/'tests/journey-coverage.json').read_text())['journeys']
expected={f'U{i:02}' for i in range(1,14)}|{f'T{i:02}' for i in range(1,9)}|{f'P{i:02}' for i in range(1,9)}
if len(rows)!=29 or {r['id'] for r in rows}!=expected:
raise SystemExit('Journey coverage must contain each of the 29 journey IDs exactly once')
rows=[r for r in rows if not args.role or r['role']==args.role]
for row in rows:
if not row['tests'] or row['implementation'] not in {'implemented','partial','external-blocked'}:
raise SystemExit('Invalid coverage entry: '+row['id'])
if row['implementation']!='implemented' and not row['remaining']:
raise SystemExit('Unexplained journey gap: '+row['id'])
selectors=sorted({name for row in rows for name in row['tests']})
suite=unittest.TestSuite(unittest.defaultTestLoader.loadTestsFromName(name) for name in selectors)
result=unittest.TextTestRunner(verbosity=2).run(suite)
failed={test.id() for test,_ in result.failures+result.errors}
skipped={test.id() for test,_ in result.skipped}
report={'tests_run':result.testsRun,'test_success':result.wasSuccessful(),'skipped':len(skipped),
'journeys':[dict(row,automated_result='failed' if failed.intersection(row['tests']) else 'skipped' if skipped.intersection(row['tests']) else 'passed') for row in rows],
'complete':result.wasSuccessful() and not skipped and all(r['implementation']=='implemented' for r in rows)}
if args.report:
args.report.parent.mkdir(parents=True,exist_ok=True)
args.report.write_text(json.dumps(report,indent=2)+'\n')
print(json.dumps({'tests_run':report['tests_run'],'test_success':report['test_success'],'complete':report['complete'],
'unresolved_journeys':[r['id'] for r in rows if r['implementation']!='implemented']}))
raise SystemExit(0 if result.wasSuccessful() and not skipped and (not args.require_complete or report['complete']) else 1)