@@ -82,15 +82,89 @@ jobs:
8282 timeout_minutes : ' 35'
8383
8484 - name : Check Test Status
85- if : inputs.skip_tests != true # Temporarily disable tests in CI pipeline
85+ if : always() && inputs.skip_tests != true # Temporarily disable tests in CI pipeline
86+ shell : bash
8687 run : |
87- if [ "${{ steps.run-tests.outputs.test_status }}" != "success" ]; then
88- echo "❌ Tests failed with status: ${{ steps.run-tests.outputs.test_status }}"
88+ test_status="${{ steps.run-tests.outputs.test_status }}"
89+ test_status="${test_status:-failed}"
90+
91+ if [ "$test_status" != "success" ]; then
92+ echo "❌ Tests failed with status: $test_status"
8993 echo "📊 Test Results:"
9094 echo " - Total Tests: ${{ steps.run-tests.outputs.test_count }}"
9195 echo " - Failed Tests: ${{ steps.run-tests.outputs.failed_count }}"
9296 echo " - Passed Tests: ${{ steps.run-tests.outputs.passed_count }}"
9397 echo " - Skipped Tests: ${{ steps.run-tests.outputs.skipped_count }}"
98+ echo ""
99+ echo "🔎 Failed test cases:"
100+
101+ python3 <<'PY'
102+ import os
103+ import xml.etree.ElementTree as ET
104+ from pathlib import Path
105+
106+ report_files = sorted(Path(".").glob("**/TEST-*.xml"))
107+ failures = []
108+
109+ for report_file in report_files:
110+ try:
111+ root = ET.parse(report_file).getroot()
112+ except ET.ParseError as exc:
113+ print(f"::warning file={report_file}::Unable to parse test report: {exc}")
114+ continue
115+
116+ for case in root.findall(".//testcase"):
117+ failed_nodes = [node for tag in ("failure", "error") for node in case.findall(tag)]
118+ if not failed_nodes:
119+ continue
120+
121+ classname = (
122+ case.attrib.get("classname")
123+ or case.attrib.get("className")
124+ or root.attrib.get("name")
125+ or report_file.stem.removeprefix("TEST-")
126+ )
127+ name = case.attrib.get("name", "<unknown>")
128+ duration = case.attrib.get("time")
129+
130+ for node in failed_nodes:
131+ raw_message = (node.attrib.get("message") or node.text or "").strip()
132+ message = raw_message.splitlines()[0] if raw_message else "No details provided"
133+ failures.append((str(report_file), classname, name, node.tag, message, duration))
134+
135+ if not failures:
136+ print(" - No per-test failure details were found in TEST-*.xml reports.")
137+ else:
138+ for report_file, classname, name, failure_type, message, duration in failures[:50]:
139+ duration_suffix = f" ({duration}s)" if duration else ""
140+ print(f" - {classname}#{name}{duration_suffix}: {message}")
141+
142+ escaped_message = (
143+ f"{failure_type}: {message}"
144+ .replace("%", "%25")
145+ .replace("\r", "%0D")
146+ .replace("\n", "%0A")
147+ )
148+ print(f"::error file={report_file},title={classname}#{name}::{escaped_message}")
149+
150+ remaining = len(failures) - 50
151+ if remaining > 0:
152+ print(f" - ... and {remaining} more failing test case(s)")
153+
154+ summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
155+ if summary_path:
156+ with open(summary_path, "a", encoding="utf-8") as summary:
157+ summary.write("### ❌ Failed test cases\n\n")
158+ for _, classname, name, failure_type, message, duration in failures[:20]:
159+ duration_suffix = f" ({duration}s)" if duration else ""
160+ summary.write(
161+ f"- `{classname}#{name}`{duration_suffix} - **{failure_type}**: {message}\n"
162+ )
163+ if len(failures) > 20:
164+ summary.write(f"- ... and {len(failures) - 20} more failing test case(s)\n")
165+ summary.write("\n")
166+ PY
167+
94168 exit 1
95169 else
96170 echo "✅ All tests passed successfully"
0 commit comments