diff --git a/src/Immediate.Jobs.Dashboard/DashboardClient/tests/components.test.ts b/src/Immediate.Jobs.Dashboard/DashboardClient/tests/components.test.ts index 28ae62fc..c2563532 100644 --- a/src/Immediate.Jobs.Dashboard/DashboardClient/tests/components.test.ts +++ b/src/Immediate.Jobs.Dashboard/DashboardClient/tests/components.test.ts @@ -9,8 +9,8 @@ import { getJobExecutions, getJobExecutionTelemetryLinks } from '@/api'; import BatchTable from '@/components/BatchTable.vue'; import HistoryChart from '@/components/HistoryChart.vue'; import JobDetail from '@/components/JobDetail.vue'; +import JobStateSummary from '@/components/JobStateSummary.vue'; import JobTable from '@/components/JobTable.vue'; -import MetricCard from '@/components/MetricCard.vue'; import ServerCard from '@/components/ServerCard.vue'; import WorkflowGraph from '@/components/WorkflowGraph.vue'; import type { BatchGraph, JobServerSnapshot } from '@/contracts'; @@ -34,13 +34,24 @@ describe('dashboard components', () => { getJobExecutionTelemetryLinksMock.mockReset().mockResolvedValue([]); }); - it('renders multi-word metric labels as readable text', () => { - const wrapper = mount(MetricCard, { - props: { label: 'AwaitingContinuation', value: 3 }, + it('groups job state counts by lifecycle stage and links to filtered jobs', async () => { + const router = createRouter({ history: createMemoryHistory(), routes }); + const wrapper = mount(JobStateSummary, { + props: { counts: { Pending: 2, Active: 1, AwaitingContinuation: 3, Succeeded: 5, Failed: 1 } }, + global: { plugins: [router] }, }); - - expect(wrapper.get('.metric-label').text()).toBe('Awaiting continuation'); - expect(dashboardStyles).not.toMatch(/\.metric-label\s*\{[^}]*text-transform:\s*uppercase/s); + await router.isReady(); + + const groups = wrapper.findAll('.state-group'); + expect(groups.map(group => group.get('.eyebrow').text())).toEqual(['Queue', 'Waiting', 'Finished']); + expect(groups.map(group => group.get('header strong').text())).toEqual(['3', '3', '6']); + + const awaiting = wrapper.get('.state-row[data-state="awaitingcontinuation"]'); + expect(awaiting.get('.state-row-label').text()).toBe('Awaiting continuation'); + expect(awaiting.attributes('href')).toBe('/invocations?state=AwaitingContinuation'); + expect(awaiting.classes()).not.toContain('empty'); + expect(wrapper.get('.state-row[data-state="skipped"]').classes()).toContain('empty'); + expect(dashboardStyles).not.toMatch(/\.state-row-label\s*\{[^}]*text-transform:\s*uppercase/s); }); it('renders job rows, retained executions, and complete payload/context details', async () => { From 88451544b3a4e32fcf91eb7dae8cb1053495f7df Mon Sep 17 00:00:00 2001 From: Duke <40759437+dukesteen@users.noreply.github.com> Date: Wed, 30 Sep 2026 17:25:31 +0200 Subject: [PATCH 2/2] Open job details from the overview's recent jobs table --- .../DashboardClient/src/views/OverviewView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Immediate.Jobs.Dashboard/DashboardClient/src/views/OverviewView.vue b/src/Immediate.Jobs.Dashboard/DashboardClient/src/views/OverviewView.vue index 47aa3e30..8f738e93 100644 --- a/src/Immediate.Jobs.Dashboard/DashboardClient/src/views/OverviewView.vue +++ b/src/Immediate.Jobs.Dashboard/DashboardClient/src/views/OverviewView.vue @@ -38,7 +38,7 @@ watch(snapshot, (value) => { }, { immediate: true }); function openJob(job: JobRecord): void { - void router.push({ name: 'jobs', params: { jobHandle: job.jobHandle } }); + void router.push({ name: 'job-detail', params: { jobHandle: job.jobHandle } }); } function openBatch(batchHandle: string): void {