diff --git a/app/src/components/flagship/CalibrationMatches.tsx b/app/src/components/flagship/CalibrationMatches.tsx index acb1ffe43..124a026f9 100644 --- a/app/src/components/flagship/CalibrationMatches.tsx +++ b/app/src/components/flagship/CalibrationMatches.tsx @@ -211,7 +211,7 @@ export function CalibrationMatchSection({ return card(Calibration checks are temporarily unavailable.); } if (matches === undefined) { - return card(Checking calibration targets…); + return card(); } if (matches.matches.length === 0) { const where = matches.geography === 'US' ? 'nationally' : `in ${matches.geography}`; diff --git a/app/src/components/flagship/ReportAdjustPanel.tsx b/app/src/components/flagship/ReportAdjustPanel.tsx index cccdfb0e2..7fa1ac21f 100644 --- a/app/src/components/flagship/ReportAdjustPanel.tsx +++ b/app/src/components/flagship/ReportAdjustPanel.tsx @@ -35,6 +35,11 @@ interface ReportAdjustPanelProps { year?: string; /** What the report is compared with, so a recompute is too; current law when unset. */ baseline?: RunReportBaseline; + /** + * The report's baseline policy could not be loaded. A recompute would + * compare with current law instead, so it is off. + */ + baselineUnknown?: boolean; } /** True when the reform's parameter set is exactly the given provisions. */ @@ -66,6 +71,7 @@ export default function ReportAdjustPanel({ region, year, baseline, + baselineUnknown = false, }: ReportAdjustPanelProps) { const runReport = useRunFlagshipReport(); const nav = useAppNavigate(); @@ -351,7 +357,15 @@ export default function ReportAdjustPanel({ {reconcileError || runReport.error} )} - diff --git a/app/src/components/flagship/ValidationDisplay.tsx b/app/src/components/flagship/ValidationDisplay.tsx index e05549c32..5c11ba7d5 100644 --- a/app/src/components/flagship/ValidationDisplay.tsx +++ b/app/src/components/flagship/ValidationDisplay.tsx @@ -1,6 +1,7 @@ import type { CSSProperties, ReactNode } from 'react'; import { IconExternalLink } from '@tabler/icons-react'; -import { Badge, Spinner, Stack, Text } from '@/components/ui'; +import { SkeletonLine, SkeletonRegion } from '@/components/flagship/states'; +import { Badge, Stack, Text } from '@/components/ui'; import { colors, spacing, typography } from '@/designTokens'; /** @@ -158,13 +159,20 @@ export function NotComparable({ children }: { children: ReactNode }) { ); } -/** A card's check is still loading; the line, not the spinner, is what gets announced. */ -export function ValidationLoading({ children }: { children: ReactNode }) { +/** + * A card's check is still loading: placeholder lines where its rows will + * be, as the rest of app v3 waits, named for what is coming. + */ +export function ValidationLoading({ label }: { label: string }) { return ( - - + + + + + ); } diff --git a/app/src/components/flagship/ValidationPanel.tsx b/app/src/components/flagship/ValidationPanel.tsx index 8db215dce..2866d1771 100644 --- a/app/src/components/flagship/ValidationPanel.tsx +++ b/app/src/components/flagship/ValidationPanel.tsx @@ -336,7 +336,7 @@ export function BaselineComparisons({ } else if (entries.length > 0) { content = ; } else if (trackRecord === undefined || scorecardRows === undefined) { - content = Loading baseline comparisons…; + content = ; } else if (trackRecord === null) { content = Baseline comparisons are temporarily unavailable.; } else if (trackRecord.reachedCount > 0) { diff --git a/app/src/components/flagship/reform/BaselinePicker.tsx b/app/src/components/flagship/reform/BaselinePicker.tsx index ac00b331b..5fc77f69d 100644 --- a/app/src/components/flagship/reform/BaselinePicker.tsx +++ b/app/src/components/flagship/reform/BaselinePicker.tsx @@ -175,10 +175,17 @@ export default function BaselinePicker({ value, onChange, reforms }: BaselinePic /> - + {reforms.length > 0 && ( Current law - New value + + New value + Effective @@ -84,11 +86,13 @@ function DraftTableSkeleton({ rows }: { rows: number }) { - +
+ +
- + ))}
window.location.reload() : undefined} + retryLabel="Reload" + actions={ + <> + + + + } > -
- - - -
-

- This report's saved details can't be read -

-

- {newer - ? 'A newer version of PolicyEngine saved them. Reload to update.' - : 'They are damaged in this browser.'} -

-
-
- -
- {newer && } - - -
-
- + ); } diff --git a/app/src/components/flagship/report/ReportValidation.tsx b/app/src/components/flagship/report/ReportValidation.tsx index 9015c3472..3d5417096 100644 --- a/app/src/components/flagship/report/ReportValidation.tsx +++ b/app/src/components/flagship/report/ReportValidation.tsx @@ -69,7 +69,7 @@ function ExternalEstimates({ if (!estimates && reforms.length === 0) { fallback = scorecard === undefined ? ( - Loading external estimates… + ) : scorecard === null ? ( External estimates are temporarily unavailable. ) : ( diff --git a/app/src/components/flagship/report/ReportView.tsx b/app/src/components/flagship/report/ReportView.tsx index efe974e11..6c9f72a98 100644 --- a/app/src/components/flagship/report/ReportView.tsx +++ b/app/src/components/flagship/report/ReportView.tsx @@ -84,6 +84,11 @@ export interface ReportViewProps { provisionsLoading?: boolean; /** What the results are compared with, by name; current law when unset. */ customBaselineLabel?: string | null; + /** + * The baseline policy could not be loaded: the adjust panel cannot + * recompute against it. + */ + baselineUnknown?: boolean; /** What the adjust panel's runs compare with; current law when unset. */ baseline?: RunReportBaseline; year: string; @@ -133,6 +138,7 @@ export default function ReportView({ priorLawBaseline = false, provisionsLoading = false, customBaselineLabel, + baselineUnknown = false, baseline, year, region, @@ -429,6 +435,7 @@ export default function ReportView({ region={region} year={year} baseline={baseline} + baselineUnknown={baselineUnknown} />
diff --git a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx index d715c8741..07a1297e2 100644 --- a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx +++ b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx @@ -1,9 +1,9 @@ import { useState } from 'react'; -import { IconAlertTriangle } from '@tabler/icons-react'; import HouseholdForm from '@/components/flagship/report/household/HouseholdForm'; import HouseholdImpactResult from '@/components/flagship/report/household/HouseholdImpactResult'; import RunProgress from '@/components/flagship/report/RunProgress'; -import { Button, Stack, Text } from '@/components/ui'; +import { ErrorState } from '@/components/flagship/states'; +import { Stack, Text } from '@/components/ui'; import { colors, spacing, typography } from '@/designTokens'; import { useFlagshipHousehold } from '@/hooks/useFlagshipHousehold'; import { @@ -81,46 +81,17 @@ export default function HouseholdImpactSection({ {running && } {failed && ( -
- - - - This household could not be calculated. - - {run.error?.message && ( - - {run.error.message} - - )} - - -
+ {run.error.message}
+ ) + } + onRetry={run.refetch} + /> )} {result && requested && ( diff --git a/app/src/hooks/useFlagshipReport.ts b/app/src/hooks/useFlagshipReport.ts index febbb7c73..9254e883c 100644 --- a/app/src/hooks/useFlagshipReport.ts +++ b/app/src/hooks/useFlagshipReport.ts @@ -37,6 +37,11 @@ export interface FlagshipReportData { error: Error | null; /** The report id resolves to no report (a bad or deleted link). */ notFound: boolean; + /** + * The policies that failed to load, with nothing to show. A missing + * baseline policy leaves what the report compares with unknown. + */ + failedPolicyIds: string[]; /** Asks again for whatever failed; settles when the answers are in. */ retry: () => Promise; } @@ -92,6 +97,10 @@ export function useFlagshipReport(id: string): FlagshipReportData { structuralSharing: false, }); const policies = policyResults.queries.map((q) => q.data).filter((p): p is Policy => !!p); + const failedPolicyIds = policyIds.filter((_, index) => { + const query = policyResults.queries[index]; + return !!query?.error && !query.data; + }); if (!direct) { return { @@ -102,6 +111,7 @@ export function useFlagshipReport(id: string): FlagshipReportData { // A legacy link that resolves to nothing reads as unresolvable. error: null, notFound: false, + failedPolicyIds: [], retry: async () => undefined, }; } @@ -120,6 +130,7 @@ export function useFlagshipReport(id: string): FlagshipReportData { isLoading: reportLoading || simulationResults.isLoading || policyResults.isLoading, error, notFound: !!unloadedReportError && isNotFoundError(unloadedReportError), + failedPolicyIds, retry: () => Promise.all([ reportError ? refetchReport() : null, diff --git a/app/src/libs/flagship/reportBaseline.ts b/app/src/libs/flagship/reportBaseline.ts index 8650a10b8..fdef9fd7a 100644 --- a/app/src/libs/flagship/reportBaseline.ts +++ b/app/src/libs/flagship/reportBaseline.ts @@ -23,6 +23,28 @@ export function reportBaselineLabel( : null; } +/** What a report compares with when its baseline policy could not be loaded. */ +export const UNKNOWN_BASELINE_LABEL = 'a baseline policy that could not be loaded'; + +/** + * Whether what the report compares with is unknown: no record of the + * run's baseline (a shared link), and a baseline policy, not current + * law, that failed to load. Read as current law, the report would claim + * a comparison that it cannot show. + */ +export function reportBaselineUnknown( + meta: Pick | null | undefined, + baselinePolicyId: string | undefined, + { currentLawId, failedPolicyIds }: { currentLawId: number; failedPolicyIds: string[] } +): boolean { + return ( + !meta?.baseline && + !!baselinePolicyId && + baselinePolicyId !== String(currentLawId) && + failedPolicyIds.includes(baselinePolicyId) + ); +} + /** * What a new run from this report compares with: the same baseline * policy when it is not current law, so an adjusted report keeps its diff --git a/app/src/pages/flagship/Report.page.tsx b/app/src/pages/flagship/Report.page.tsx index c3d826b69..024c281a0 100644 --- a/app/src/pages/flagship/Report.page.tsx +++ b/app/src/pages/flagship/Report.page.tsx @@ -22,13 +22,33 @@ import { useReportValidationSnapshot } from '@/hooks/useReportValidationSnapshot import { useStartCalculationOnLoad } from '@/hooks/useStartCalculationOnLoad'; import { useUnreadableReportMeta } from '@/hooks/useUnreadableReportMeta'; import { clearDraftAfterRun, loadProvisionsIntoDraft } from '@/libs/draftReform'; -import { reportBaselineLabel, reportRunBaseline } from '@/libs/flagship/reportBaseline'; +import { + reportBaselineLabel, + reportBaselineUnknown, + reportRunBaseline, + UNKNOWN_BASELINE_LABEL, +} from '@/libs/flagship/reportBaseline'; import { provenanceFromPolicy } from '@/libs/flagship/reportProvenance'; import { readReportMeta } from '@/libs/flagship/runReport'; import { RootState } from '@/store'; import type { CalcStartConfig } from '@/types/calculation'; import { allSimulationsLoaded } from '@/utils/reportSimulations'; +/** A failed load at the top of the overview, in a dashed box. */ +function LeadError({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ); +} + interface FlagshipReportPageProps { /** Passed by the Next.js route bridge; react-router falls back to params. */ userReportId?: string; @@ -51,12 +71,14 @@ export default function FlagshipReportPage({ userReportId: propId }: FlagshipRep isLoading, error: loadError, notFound, + failedPolicyIds, retry, } = useFlagshipReport(userReportId); // A local association id from another browser resolves to nothing. const unresolvable = !isLoading && !report && !!userReportId && !isApiReportId(userReportId); const parameters = useSelector((state: RootState) => state.metadata.parameters); const economyRegions = useSelector((state: RootState) => state.metadata.economyOptions.region); + const currentLawId = useSelector((state: RootState) => state.metadata.currentLawId); // Provenance: the local stash from the run, else rebuilt from the reform // policy so a shared link validates like the original. const reformPolicy = policies.find((policy) => policy.id === simulations?.[1]?.policyId); @@ -120,9 +142,18 @@ export default function FlagshipReportPage({ userReportId: propId }: FlagshipRep const reformPolicyId = simulations?.[1]?.policyId; const baselinePolicyId = simulations?.[0]?.policyId; const baselinePolicy = policies.find((policy) => policy.id === baselinePolicyId); - const customBaselineLabel = reportBaselineLabel(meta, baselinePolicy); - // Adjusted, the report keeps what it was compared with. - const runBaseline = reportRunBaseline(meta, baselinePolicyId, customBaselineLabel); + // A baseline policy that failed to load is unknown, not current law. + const baselineUnknown = reportBaselineUnknown(meta, baselinePolicyId, { + currentLawId, + failedPolicyIds, + }); + const customBaselineLabel = baselineUnknown + ? UNKNOWN_BASELINE_LABEL + : reportBaselineLabel(meta, baselinePolicy); + // Adjusted, the report keeps what it was compared with; an unknown one gives it nothing to keep. + const runBaseline = baselineUnknown + ? undefined + : reportRunBaseline(meta, baselinePolicyId, customBaselineLabel); const region = simulations?.[0]?.populationId; // A report on part of the country names it: "California". const regionLabel = @@ -269,19 +300,26 @@ export default function FlagshipReportPage({ userReportId: propId }: FlagshipRep budgetWindow={meta?.budgetWindow} provisions={meta?.provisions ?? []} overviewLead={ - !meta && metadata.status === 'error' ? ( -
- -
- ) : undefined + <> + {!meta && metadata.status === 'error' && ( + + + + )} + {baselineUnknown && ( + + + + )} + } customBaselineLabel={customBaselineLabel} + baselineUnknown={baselineUnknown} baseline={runBaseline} year={report?.year ?? ''} region={region} diff --git a/app/src/tests/unit/components/flagship/CalibrationMatches.test.tsx b/app/src/tests/unit/components/flagship/CalibrationMatches.test.tsx index 8dcca7f11..2af77e229 100644 --- a/app/src/tests/unit/components/flagship/CalibrationMatches.test.tsx +++ b/app/src/tests/unit/components/flagship/CalibrationMatches.test.tsx @@ -24,7 +24,9 @@ describe('CalibrationMatchSection', () => { test('given matches are loading then the loading state renders', () => { render(); - expect(screen.getByRole('status')).toHaveTextContent('Checking calibration targets…'); + expect( + screen.getByRole('status', { name: 'Checking calibration targets' }) + ).toBeInTheDocument(); }); test('given reached variables but none calibrated then the gap is stated, not hidden', () => { diff --git a/app/src/tests/unit/components/flagship/ReportAdjustPanel.test.tsx b/app/src/tests/unit/components/flagship/ReportAdjustPanel.test.tsx index 5ea7d326b..4cb0571a6 100644 --- a/app/src/tests/unit/components/flagship/ReportAdjustPanel.test.tsx +++ b/app/src/tests/unit/components/flagship/ReportAdjustPanel.test.tsx @@ -63,7 +63,13 @@ async function renderPanel({ region, year, baseline, -}: { region?: string; year?: string; baseline?: RunReportBaseline } = {}) { + baselineUnknown, +}: { + region?: string; + year?: string; + baseline?: RunReportBaseline; + baselineUnknown?: boolean; +} = {}) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); const result = render( @@ -74,6 +80,7 @@ async function renderPanel({ region={region} year={year} baseline={baseline} + baselineUnknown={baselineUnknown} /> ); @@ -365,6 +372,20 @@ describe('ReportAdjustPanel', () => { expect(screen.getByLabelText(/new value for maximum credit per child/i)).toBeInTheDocument(); }); + test('given the baseline policy could not be loaded then recompute is off and says why', async () => { + const user = userEvent.setup(); + await renderPanel({ baselineUnknown: true }); + + await user.click(screen.getByRole('button', { name: /remove maximum allotment/i })); + + expect(screen.getByRole('button', { name: /recompute/i })).toBeDisabled(); + expect( + screen.getByText( + 'The baseline policy could not be loaded, so a recompute cannot compare with it.' + ) + ).toBeInTheDocument(); + }); + test('given collapse then the panel shrinks to the adjust tab and reopens', async () => { const user = userEvent.setup(); await renderPanel(); diff --git a/app/src/tests/unit/components/flagship/ValidationPanel.test.tsx b/app/src/tests/unit/components/flagship/ValidationPanel.test.tsx index d593c1618..046a9eff2 100644 --- a/app/src/tests/unit/components/flagship/ValidationPanel.test.tsx +++ b/app/src/tests/unit/components/flagship/ValidationPanel.test.tsx @@ -110,7 +110,9 @@ describe('BaselineComparisons', () => { test('given matches are loading then the loading state renders', () => { render(); - expect(screen.getByText(/loading baseline comparisons/i)).toBeInTheDocument(); + expect( + screen.getByRole('status', { name: 'Loading baseline comparisons' }) + ).toBeInTheDocument(); }); test('given the reform reaches nothing then a plain line says no comparison covers it', () => { diff --git a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx index c61218901..6a67627b4 100644 --- a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx +++ b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx @@ -236,7 +236,7 @@ describe('HouseholdImpactSection', () => { await user.click(screen.getByRole('button', { name: 'Calculate' })); const alert = await screen.findByRole('alert'); - expect(alert).toHaveTextContent('This household could not be calculated.'); + expect(alert).toHaveTextContent('This household could not be calculated'); expect(alert).toHaveTextContent('Household calculation failed'); await user.click(within(alert).getByRole('button', { name: 'Try again' })); diff --git a/app/src/tests/unit/components/flagship/report/ReportDetailsError.test.tsx b/app/src/tests/unit/components/flagship/report/ReportDetailsError.test.tsx index cfabeed0b..a99ab4ec8 100644 --- a/app/src/tests/unit/components/flagship/report/ReportDetailsError.test.tsx +++ b/app/src/tests/unit/components/flagship/report/ReportDetailsError.test.tsx @@ -15,7 +15,7 @@ describe('ReportDetailsError', () => { render(); expect( - screen.getByRole('heading', { name: "This report's saved details can't be read" }) + screen.getByRole('heading', { name: "Could not read this report's saved details" }) ).toBeInTheDocument(); expect(screen.getByText('They are damaged in this browser.')).toBeInTheDocument(); expect(screen.getByText('provisions must be an array')).toBeInTheDocument(); diff --git a/app/src/tests/unit/components/flagship/report/ReportValidation.test.tsx b/app/src/tests/unit/components/flagship/report/ReportValidation.test.tsx index 0269d3603..586cd20ea 100644 --- a/app/src/tests/unit/components/flagship/report/ReportValidation.test.tsx +++ b/app/src/tests/unit/components/flagship/report/ReportValidation.test.tsx @@ -128,9 +128,9 @@ describe('ReportValidation', () => { mockUseScorecardComparisons.mockReturnValue(undefined); renderValidation(); - expect(within(card('External estimates')).getByRole('status')).toHaveTextContent( - 'Loading external estimates…' - ); + expect( + within(card('External estimates')).getByRole('status', { name: 'Loading external estimates' }) + ).toBeInTheDocument(); }); test('given the scorecard is unavailable then the estimates card says so, not that none exists', () => { diff --git a/app/src/tests/unit/hooks/useFlagshipReport.test.tsx b/app/src/tests/unit/hooks/useFlagshipReport.test.tsx index 34a051c79..200b272c2 100644 --- a/app/src/tests/unit/hooks/useFlagshipReport.test.tsx +++ b/app/src/tests/unit/hooks/useFlagshipReport.test.tsx @@ -165,6 +165,8 @@ describe('useFlagshipReport', () => { await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.simulations).toHaveLength(2); expect(result.current.error).toBeNull(); + // Each failed policy is named, so a missing baseline reads as unknown. + await waitFor(() => expect(result.current.failedPolicyIds).toEqual(['2', '98557'])); }); test('given a failed simulation then retry asks for it again and the error clears', async () => { diff --git a/app/src/tests/unit/libs/flagship/reportBaseline.test.ts b/app/src/tests/unit/libs/flagship/reportBaseline.test.ts index 7af80d3a2..ddbf80d1b 100644 --- a/app/src/tests/unit/libs/flagship/reportBaseline.test.ts +++ b/app/src/tests/unit/libs/flagship/reportBaseline.test.ts @@ -3,6 +3,7 @@ import { baselineProvisions, customBaseline, reportBaselineLabel, + reportBaselineUnknown, reportRunBaseline, } from '@/libs/flagship/reportBaseline'; @@ -39,6 +40,37 @@ describe('reportBaselineLabel', () => { }); }); +describe('reportBaselineUnknown', () => { + const CURRENT_LAW_ID = 2; + + test('given a shared link whose baseline policy failed then the baseline is unknown', () => { + expect( + reportBaselineUnknown(null, '88', { currentLawId: CURRENT_LAW_ID, failedPolicyIds: ['88'] }) + ).toBe(true); + }); + + test('given the baseline policy loaded then the baseline is known', () => { + expect( + reportBaselineUnknown(null, '88', { currentLawId: CURRENT_LAW_ID, failedPolicyIds: ['99'] }) + ).toBe(false); + }); + + test('given current law failed to load then it is still current law', () => { + expect( + reportBaselineUnknown(null, '2', { currentLawId: CURRENT_LAW_ID, failedPolicyIds: ['2'] }) + ).toBe(false); + }); + + test('given the run recorded its baseline then a failed policy leaves it known', () => { + expect( + reportBaselineUnknown(PLAN_B_META, '88', { + currentLawId: CURRENT_LAW_ID, + failedPolicyIds: ['88'], + }) + ).toBe(false); + }); +}); + describe('reportRunBaseline', () => { test('given a report compared with a saved reform then a re-run reuses its baseline policy', () => { expect(reportRunBaseline(PLAN_B_META, '88', 'Plan B')).toEqual({ diff --git a/app/src/tests/unit/pages/flagship/Report.test.tsx b/app/src/tests/unit/pages/flagship/Report.test.tsx index 5c5401d20..90625cbf2 100644 --- a/app/src/tests/unit/pages/flagship/Report.test.tsx +++ b/app/src/tests/unit/pages/flagship/Report.test.tsx @@ -10,6 +10,9 @@ import { createMockSocietyWideOutput } from '@/tests/fixtures/pages/reportOutput const mockCalcStatus = vi.fn(); // The report's policies; a baseline policy with parameters is a custom baseline. const mockPolicies = vi.hoisted(() => ({ current: [] as unknown[] })); +// The policies that failed to load, by id. +const mockFailedPolicyIds = vi.hoisted(() => ({ current: [] as string[] })); +const mockRetry = vi.fn(); const META: FlagshipReportMeta = { title: 'Test Reform', @@ -38,6 +41,8 @@ vi.mock('@/hooks/useFlagshipReport', () => ({ ], policies: mockPolicies.current, isLoading: false, + failedPolicyIds: mockFailedPolicyIds.current, + retry: mockRetry, }), })); @@ -91,6 +96,8 @@ describe('FlagshipReportPage', () => { mockCalcStatus.mockReset(); mockMeta = META; mockPolicies.current = []; + mockFailedPolicyIds.current = []; + mockRetry.mockReset(); mockStartCalculationOnLoad.mockReset(); }); @@ -218,6 +225,32 @@ describe('FlagshipReportPage', () => { }); }); + test('given the baseline policy failed to load then the report does not read as current law', async () => { + const user = userEvent.setup(); + vi.stubGlobal( + 'fetch', + vi.fn(async () => Response.json({ built: null, rows: [], unmappedCount: 0 })) + ); + mockFailedPolicyIds.current = ['2']; + mockCalcStatus.mockReturnValue({ + status: 'complete', + isComplete: true, + isError: false, + result: createMockSocietyWideOutput(), + }); + + renderPage(); + + expect( + screen.getByText('Compared with a baseline policy that could not be loaded') + ).toBeInTheDocument(); + await user.click(screen.getByRole('button', { name: 'Try again' })); + expect(mockRetry).toHaveBeenCalledTimes(1); + + await user.click(screen.getByRole('tab', { name: 'Validation' })); + expect(within(screen.getByRole('tabpanel')).getAllByText('Not comparable')).toHaveLength(2); + }); + test('given a failed run then Build gets the reform back with the same comparison', async () => { clearDraftReform(); mockMeta = PLAN_B_META; diff --git a/app/src/tests/unit/pages/flagship/ReportLoadStates.test.tsx b/app/src/tests/unit/pages/flagship/ReportLoadStates.test.tsx index 3b315ab2c..995848aee 100644 --- a/app/src/tests/unit/pages/flagship/ReportLoadStates.test.tsx +++ b/app/src/tests/unit/pages/flagship/ReportLoadStates.test.tsx @@ -65,6 +65,7 @@ function reportData(overrides: Partial = {}): FlagshipReport isLoading: false, error: null, notFound: false, + failedPolicyIds: [], retry: mockRetry, ...overrides, }; diff --git a/app/src/tests/unit/pages/flagship/ReportUnreadableMeta.test.tsx b/app/src/tests/unit/pages/flagship/ReportUnreadableMeta.test.tsx index de78cfa57..74f2b0a85 100644 --- a/app/src/tests/unit/pages/flagship/ReportUnreadableMeta.test.tsx +++ b/app/src/tests/unit/pages/flagship/ReportUnreadableMeta.test.tsx @@ -12,7 +12,7 @@ import { // schema, from real localStorage (Report.test.tsx stubs the read). const REPORT_ID = 'r1'; -const UNREADABLE_HEADING = "This report's saved details can't be read"; +const UNREADABLE_HEADING = "Could not read this report's saved details"; const WAITING_TEXT = 'Calculating the nationwide results'; vi.mock('@/hooks/useFlagshipReport', () => ({ @@ -25,6 +25,7 @@ vi.mock('@/hooks/useFlagshipReport', () => ({ ], policies: [], isLoading: false, + failedPolicyIds: [], }), }));