From 45cfbc5c499cdd2344380238ceea9393c4dc7316 Mon Sep 17 00:00:00 2001 From: morgan-se Date: Wed, 12 Nov 2025 21:18:31 +1300 Subject: [PATCH] Moved collection results to runner title bar so they are move visible. (#3808) Added breakdown of test results within collection. Added filtering based on passing/failing requests and tests by click on results text. Co-authored-by: Morgan English Co-authored-by: Sid --- .../src/components/RunnerResults/index.jsx | 72 +++++++++++++++++-- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/packages/bruno-app/src/components/RunnerResults/index.jsx b/packages/bruno-app/src/components/RunnerResults/index.jsx index 7956eb1ad..31b6d97f2 100644 --- a/packages/bruno-app/src/components/RunnerResults/index.jsx +++ b/packages/bruno-app/src/components/RunnerResults/index.jsx @@ -46,6 +46,24 @@ export default function RunnerResults({ collection }) { const dispatch = useDispatch(); const [selectedItem, setSelectedItem] = useState(null); const [delay, setDelay] = useState(null); + const [activeFilter, setActiveFilter] = useState('all'); + + + const getActiveFilterPredicate = () => { + switch (activeFilter) { + case 'passing_requests': + return (item) => item.status !== 'error' && item.testStatus === 'pass' && item.assertionStatus === 'pass'; + case 'failing_requests': + return (item) => (item.status !== 'error' && item.testStatus === 'fail') || item.assertionStatus === 'fail'; + case 'passing_tests': + return (item) => item.testResults?.some((result) => result.status === 'pass'); + case 'failing_tests': + return (item) => item.testResults?.some((result) => result.status === 'fail' || result.status === 'error'); + default: + return () => true + } + } + const [selectedRequestItems, setSelectedRequestItems] = useState([]); const [configureMode, setConfigureMode] = useState(false); @@ -192,6 +210,44 @@ export default function RunnerResults({ collection }) { }, [tagsEnabled]); const totalRequestsInCollection = getTotalRequestCountInCollection(collectionCopy); + + const displayCollectionResults = () => { + let passedRequests = 0; + let failedRequests = 0; + let totalTestsInCollection = 0; + let passedTests = 0; + let failedTests = 0; + items.forEach(item => { + const isPassedRequest = item.status !== 'error' && item.testStatus === 'pass' && item.assertionStatus === 'pass'; + const isFailedRequest = (item.status !== 'error' && item.testStatus === 'fail') || item.assertionStatus === 'fail'; + + if (isPassedRequest) passedRequests++; + if (isFailedRequest) failedRequests++; + + const testResults = Array.isArray(item?.testResults) ? item.testResults : []; + totalTestsInCollection += testResults.length; + testResults.forEach(result => { + if (result.status === 'pass') passedTests++; + if (result.status === 'fail' || result.status === 'error') failedTests++; + }); + }); + + return ( +
+
+ setActiveFilter('all')} className={`cursor-pointer ${activeFilter === 'all' ? 'underline font-semibold' : ''} hover:font-semibold`}>Total Requests: {items.length}, + setActiveFilter('passing_requests')} className={`cursor-pointer ${activeFilter === 'passing_requests' ? 'underline font-semibold' : ''} hover:font-semibold`}>Passed: {passedRequests}, + setActiveFilter('failing_requests') } className={`cursor-pointer ${activeFilter === 'failing_requests' ? 'underline font-semibold' : ''} hover:font-semibold`}>Failed: {failedRequests} +
+
+ setActiveFilter('all')} className={`cursor-pointer ${activeFilter === 'all' ? 'underline font-semibold' : ''} hover:font-semibold`}>Total Tests: {totalTestsInCollection}, + setActiveFilter('passing_tests')} className={`cursor-pointer ${activeFilter === 'passing_tests' ? 'underline font-semibold' : ''} hover:font-semibold`}>Passed: {passedTests}, + setActiveFilter('failing_tests')} className={`cursor-pointer ${activeFilter === 'failing_tests' ? 'underline font-semibold' : ''} hover:font-semibold`}>Failed: {failedTests} +
+
+ ) + } + const passedRequests = items.filter(allTestsPassed); const failedRequests = items.filter(anyTestFailed); @@ -290,6 +346,7 @@ export default function RunnerResults({ collection }) { Runner + {displayCollectionResults()} {runnerInfo.status !== 'ended' && runnerInfo.cancelTokenUid && (