diff --git a/client/components/CandidateTests/CandidateTestPlanRun/CandidateTestPlanRun.css b/client/components/CandidateTests/CandidateTestPlanRun/CandidateTestPlanRun.css
index af31f7b01..2af3c9c0d 100644
--- a/client/components/CandidateTests/CandidateTestPlanRun/CandidateTestPlanRun.css
+++ b/client/components/CandidateTests/CandidateTestPlanRun/CandidateTestPlanRun.css
@@ -157,3 +157,12 @@
position: relative;
top: -5px;
}
+
+.incomplete-test-plan-information-text {
+ margin-top: 5%;
+}
+
+.status-bar {
+ display: flex;
+ align-items: center;
+}
diff --git a/client/components/CandidateTests/CandidateTestPlanRun/index.jsx b/client/components/CandidateTests/CandidateTestPlanRun/index.jsx
index b6c3357d5..726fd33d8 100644
--- a/client/components/CandidateTests/CandidateTestPlanRun/index.jsx
+++ b/client/components/CandidateTests/CandidateTestPlanRun/index.jsx
@@ -29,6 +29,7 @@ import ThankYouModal from '../CandidateModals/ThankYouModal';
import getMetrics from '../../Reports/getMetrics';
import FeedbackListItem from '../FeedbackListItem';
import DisclosureComponent from '../../common/DisclosureComponent';
+import StatusBar from '../../TestRun/StatusBar';
// https://codesandbox.io/s/react-hookresize-observer-example-ft88x
function useSize(target) {
@@ -165,6 +166,21 @@ const CandidateTestPlanRun = () => {
setThankYouModalShowing(true);
};
+ const handleIncompleteTestPlans = () => {
+ const runnableTests = testPlanReport.runnableTests;
+ const finalizedTests = testPlanReport.finalizedTestResults;
+ const finalizedTestIds = finalizedTests.map(x => x.test.id);
+
+ const hasIncompleteTests =
+ runnableTests.length != finalizedTests.length;
+
+ const viewedCompleteTests = viewedTests.filter(viewedTest =>
+ finalizedTestIds.includes(viewedTest)
+ );
+
+ return { hasIncompleteTests, viewedCompleteTests };
+ };
+
useEffect(() => {
if (data) {
if (
@@ -345,6 +361,9 @@ const CandidateTestPlanRun = () => {
}
};
+ const { hasIncompleteTests, viewedCompleteTests } =
+ handleIncompleteTestPlans();
+
const heading = (
@@ -369,6 +388,10 @@ const CandidateTestPlanRun = () => {
)}
+ {hasIncompleteTests &&
+ (
+
+ )}
);
@@ -492,21 +515,34 @@ const CandidateTestPlanRun = () => {
testPlanReport.finalizedTestResults[
currentTestIndex
];
- const { testsPassedCount } = getMetrics({ testResult });
- return (
- <>
-
- Test Result:{' '}
- {testsPassedCount ? 'PASS' : 'FAIL'}
-
-
- >
- );
+
+ if (testResult) {
+ const { testsPassedCount } = getMetrics({
+ testResult
+ });
+ return (
+ <>
+
+ Test Result:{' '}
+ {testsPassedCount ? 'PASS' : 'FAIL'}
+
+
+ >
+ );
+ } else {
+ return (
+ <>
+
+ Test Result: INCOMPLETE
+
+ >
+ );
+ }
})
]}
stacked
@@ -542,7 +578,7 @@ const CandidateTestPlanRun = () => {
currentTestIndex={currentTestIndex}
toggleShowClick={toggleTestNavigator}
handleTestClick={handleTestClick}
- viewedTests={viewedTests}
+ viewedTests={viewedCompleteTests}
/>
{
true
);
}}
- disabled={!isLastTest}
+ disabled={
+ !isLastTest ||
+ hasIncompleteTests
+ }
>
Finish
diff --git a/client/components/TestQueueRow/TestQueueRow.css b/client/components/TestQueueRow/TestQueueRow.css
index 4035df1db..9d86b243e 100644
--- a/client/components/TestQueueRow/TestQueueRow.css
+++ b/client/components/TestQueueRow/TestQueueRow.css
@@ -107,6 +107,14 @@ button.more-actions:active {
width: initial;
}
+.next-report-status-information-text {
+ font-size: small;
+ text-align: center;
+ display: block;
+ margin: 5%;
+ color:gray;
+}
+
/* tr.test-queue-run-row td:first-child {
padding: 0.75rem;
} */
diff --git a/client/components/TestQueueRow/index.jsx b/client/components/TestQueueRow/index.jsx
index 94367c80e..4216c5f28 100644
--- a/client/components/TestQueueRow/index.jsx
+++ b/client/components/TestQueueRow/index.jsx
@@ -427,12 +427,20 @@ const TestQueueRow = ({
};
const evaluateNewReportStatus = () => {
- const { status, conflictsLength } = testPlanReport;
+ const { status, conflictsLength, runnableTestsLength, draftTestPlanRuns } =
+ testPlanReport;
+
const conflictsCount = conflictsLength;
+ const draftTestPlansTestResultsLengths = draftTestPlanRuns.map(x => x.testResultsLength);
+
+ const hasIncompleteTests = draftTestPlansTestResultsLengths.filter(x => x != runnableTestsLength).length > 0
// If there are no conflicts OR the test has been marked as "final",
// and admin can mark a test run as "draft"
let newStatus;
+ let newStatusCanContinue;
+ let newStatusInformationText;
+
if (
(status !== 'IN_REVIEW' &&
conflictsCount === 0 &&
@@ -450,11 +458,24 @@ const TestQueueRow = ({
) {
newStatus = 'CANDIDATE';
}
- return newStatus;
+
+ if (newStatus === 'CANDIDATE' && hasIncompleteTests) {
+ newStatusCanContinue = false;
+ newStatusInformationText =
+ 'Incomplete test plans cannot transition to the candidate report status.';
+ } else {
+ newStatusCanContinue = true;
+ }
+
+ return { newStatus, newStatusCanContinue, newStatusInformationText };
};
const { status, results } = evaluateStatusAndResults();
- const nextReportStatus = evaluateNewReportStatus();
+ const {
+ newStatus: nextReportStatus,
+ newStatusCanContinue: nextReportStatusCanContinue,
+ newStatusInformationText: nextReportStatusInformationText
+ } = evaluateNewReportStatus();
const getRowId = tester =>
[
@@ -533,25 +554,37 @@ const TestQueueRow = ({
{status}
{isSignedIn && isTester && (
- {isAdmin && !isLoading && nextReportStatus && (
- <>
-
- >
+ {isAdmin &&
+ !isLoading &&
+ nextReportStatus &&
+ nextReportStatusCanContinue && (
+ <>
+
+ >
+ )}
+
+ {nextReportStatusInformationText && (
+
+ {nextReportStatusInformationText}
+
)}
{results}
diff --git a/client/components/TestRun/StatusBar/index.jsx b/client/components/TestRun/StatusBar/index.jsx
index 011c7aa2e..2c5f21d32 100644
--- a/client/components/TestRun/StatusBar/index.jsx
+++ b/client/components/TestRun/StatusBar/index.jsx
@@ -6,6 +6,8 @@ import nextId from 'react-id-generator';
const StatusBar = ({
hasConflicts = false,
+ hasIncompleteTestRuns = false,
+ isCandidateTestRun = false,
handleReviewConflictsButtonClick = () => {}
}) => {
const [statuses, setStatuses] = useState([]);
@@ -34,6 +36,17 @@ const StatusBar = ({
});
}
+ if(hasIncompleteTestRuns && isCandidateTestRun) {
+ const variant = 'warning';
+ const icon = 'alert';
+ const message = 'This Candidate Test Plan has incomplete test results and cannot be finished. Please move this Test Plan back to Draft and complete recording all test results.';
+ statuses.push({
+ icon,
+ message,
+ variant
+ });
+ }
+
setStatuses(statuses);
}, []);
@@ -59,6 +72,8 @@ const StatusBar = ({
StatusBar.propTypes = {
issues: PropTypes.array,
hasConflicts: PropTypes.bool,
+ hasIncompleteTestRuns: PropTypes.bool,
+ isCandidateTestRun: PropTypes.bool,
handleReviewConflictsButtonClick: PropTypes.func
};