From 1f51a81752ad91037e8fd48c53dbb3ad09a9a2be Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Tue, 25 Aug 2026 14:25:08 +1000 Subject: [PATCH] PM-5368: show cancelled Marathon Match test status in the work app What was broken In the work app submissions table, a Marathon Match submission whose scorer was stopped because the member submitted a newer solution showed an empty Test Status cell with no explanation, matching the PM-5368 screenshots. Copilots and managers could not tell a superseded run apart from one that had never started. Root cause normalizeTestStatus in the work app challenge utils only recognized FAILED, IN PROGRESS and SUCCESS, so the CANCELLED status now recorded by marathon-match-api-v6 was normalized away and the status icon renderer had no branch for it. The placeholder aggregate score written for a terminal run without a score was also only suppressed for IN PROGRESS runs. What was changed - normalizeTestStatus and the display status union accept CANCELLED, and a cancelled run is ordered as terminal when choosing the current summation. - SubmissionsTable renders a neutral cancelled status icon so the run does not read as a failure. - Score display suppression now covers any status that produced no score, so a cancelled run shows the empty score placeholder instead of the placeholder aggregate score. Any added/updated tests - src/apps/work/src/lib/utils/challenge.utils.spec.ts: new case covering that getSubmissionTestProgress surfaces a cancelled provisional run. - src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.spec.tsx: new case covering that a superseded run renders the cancelled status icon and no aggregate score. --- .../SubmissionsTable.module.scss | 4 ++ .../SubmissionsTable.spec.tsx | 42 ++++++++++++++++++- .../SubmissionsTable/SubmissionsTable.tsx | 38 +++++++++++++---- .../work/src/lib/models/Submission.model.ts | 2 +- .../src/lib/utils/challenge.utils.spec.ts | 20 +++++++++ .../work/src/lib/utils/challenge.utils.ts | 16 +++++-- 6 files changed, 109 insertions(+), 13 deletions(-) diff --git a/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.module.scss b/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.module.scss index b0e8634cf..bd8bb596f 100644 --- a/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.module.scss +++ b/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.module.scss @@ -150,6 +150,10 @@ color: #ea1900; } +.testStatusCancelled { + color: #767676; +} + .level-1 { color: #555 !important; } diff --git a/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.spec.tsx b/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.spec.tsx index ce0827d80..7327b0179 100644 --- a/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.spec.tsx +++ b/src/apps/work/src/lib/components/SubmissionsTable/SubmissionsTable.spec.tsx @@ -5,6 +5,7 @@ import { SubmissionsTable } from './SubmissionsTable' jest.mock('~/libs/ui', () => ({ IconOutline: { + BanIcon: (): JSX.Element => , ClockIcon: (): JSX.Element => , XCircleIcon: (): JSX.Element => , }, @@ -55,7 +56,7 @@ jest.mock('../../utils', () => ({ metadata?: { testProcess?: 'example' | 'provisional' | 'system' testProgress?: number - testStatus?: 'FAILED' | 'IN PROGRESS' | 'SUCCESS' + testStatus?: 'CANCELLED' | 'FAILED' | 'IN PROGRESS' | 'SUCCESS' testType?: 'example' | 'provisional' | 'system' } }> @@ -337,6 +338,45 @@ describe('SubmissionsTable', () => { .toBeTruthy() }) + it('renders a cancelled test status without a score for a superseded marathon run', () => { + render( + , + ) + + expect(screen.getByRole('img', { name: 'Test status: CANCELLED' })) + .toBeTruthy() + expect(screen.queryByText('-1.00')) + .toBeNull() + }) + it('renders marathon scores from provisional and system summations only', () => { render( +