diff --git a/src/components/treasuryOverviewPage/Stream.ts b/src/components/treasuryOverviewPage/Stream.ts
index 807dbfa1..6cd5b071 100644
--- a/src/components/treasuryOverviewPage/Stream.ts
+++ b/src/components/treasuryOverviewPage/Stream.ts
@@ -5,7 +5,7 @@ export interface Stream {
id: string;
recipient: string;
rate: string;
- accruedAmount?: string | number;
+ accruedAmount: number;
status: StreamStatus;
- startDate?: string;
+ startDate: string;
}
diff --git a/src/components/treasuryOverviewPage/StreamRow.tsx b/src/components/treasuryOverviewPage/StreamRow.tsx
index 01e52612..dc347fd1 100644
--- a/src/components/treasuryOverviewPage/StreamRow.tsx
+++ b/src/components/treasuryOverviewPage/StreamRow.tsx
@@ -330,11 +330,9 @@ export default function StreamRow({
{stream.rate}
- {typeof stream.accruedAmount === "number" && (
-
- {formatAccruedAmount(stream.accruedAmount)}
-
- )}
+
+ {formatAccruedAmount(stream.accruedAmount)}
+
|
diff --git a/src/components/treasuryOverviewPage/__tests__/StreamRow.test.tsx b/src/components/treasuryOverviewPage/__tests__/StreamRow.test.tsx
index b96ee0cf..580838b4 100644
--- a/src/components/treasuryOverviewPage/__tests__/StreamRow.test.tsx
+++ b/src/components/treasuryOverviewPage/__tests__/StreamRow.test.tsx
@@ -11,6 +11,7 @@ const stream: Stream = {
rate: "2,500 USDC/mo",
accruedAmount: 1234.56,
status: "Active",
+ startDate: "2026-01-01",
};
function renderRow(rowStream: Stream = stream) {
@@ -206,5 +207,110 @@ describe("StreamRow", () => {
// Menu should close after selection
expect(screen.queryByRole("menu")).not.toBeInTheDocument();
});
+
+ describe("Regression tests for issue #1459", () => {
+ it("renders accrued amount for streams with zero accrued amount", () => {
+ renderRow({
+ ...stream,
+ id: "STR-ZERO",
+ accruedAmount: 0,
+ });
+
+ expect(screen.getByText("0 USDC accrued")).toBeInTheDocument();
+ });
+
+ it("renders status for completed streams", () => {
+ renderRow({
+ ...stream,
+ id: "STR-COMP",
+ status: "Completed",
+ });
+
+ expect(screen.getByRole("status", { name: "Completed status" })).toHaveTextContent("COMPLETED");
+ });
+
+ it("renders status for paused streams", () => {
+ renderRow({
+ ...stream,
+ id: "STR-PAUSED",
+ status: "Paused",
+ });
+
+ expect(screen.getByRole("status", { name: "Paused status" })).toHaveTextContent("PAUSED");
+ });
+
+ it("renders status for active streams", () => {
+ renderRow({
+ ...stream,
+ id: "STR-ACTIVE",
+ status: "Active",
+ });
+
+ expect(screen.getByRole("status", { name: "Active status" })).toHaveTextContent("ACTIVE");
+ });
+
+ it("renders accrued amount for streams with large values", () => {
+ renderRow({
+ ...stream,
+ id: "STR-LARGE",
+ accruedAmount: 999999999.99,
+ });
+
+ expect(screen.getByText("999,999,999.99 USDC accrued")).toBeInTheDocument();
+ });
+
+ it("renders all required fields without defensive checks", () => {
+ renderRow({
+ id: "STR-ALL-FIELDS",
+ name: "Test Stream",
+ recipient: "GTEST123456789ABCDEF",
+ rate: "1,000 USDC/mo",
+ accruedAmount: 5000,
+ status: "Active",
+ startDate: "2026-01-01",
+ });
+
+ expect(screen.getByText("Test Stream")).toBeInTheDocument();
+ expect(screen.getByText("GTEST1...CDEF")).toBeInTheDocument();
+ expect(screen.getByText("1,000 USDC/mo")).toBeInTheDocument();
+ expect(screen.getByText("5,000 USDC accrued")).toBeInTheDocument();
+ expect(screen.getByRole("status", { name: "Active status" })).toHaveTextContent("ACTIVE");
+ });
+
+ it("consistently renders status matching normalized streamRecords data", () => {
+ // Test all three valid statuses from streamRecords StreamStatus type
+ const statuses: Array<"Active" | "Paused" | "Completed"> = ["Active", "Paused", "Completed"];
+
+ statuses.forEach((status) => {
+ const { unmount } = render(
+
+
+
+ );
+
+ expect(screen.getByRole("status", { name: `${status} status` })).toHaveTextContent(status.toUpperCase());
+ unmount();
+ });
+ });
+
+ it("renders accrued amount as number consistently with streamRecords normalization", () => {
+ // streamRecords.readNumber() returns 0 for invalid values, so we test that
+ // the UI renders the numeric value without type checking
+ renderRow({
+ ...stream,
+ id: "STR-NUMERIC",
+ accruedAmount: 0,
+ });
+
+ expect(screen.getByText(/0.*USDC accrued/)).toBeInTheDocument();
+ });
+ });
});
diff --git a/src/components/treasuryOverviewPage/__tests__/malformedRecordDefensive.test.tsx b/src/components/treasuryOverviewPage/__tests__/malformedRecordDefensive.test.tsx
index 341d6540..d2577c29 100644
--- a/src/components/treasuryOverviewPage/__tests__/malformedRecordDefensive.test.tsx
+++ b/src/components/treasuryOverviewPage/__tests__/malformedRecordDefensive.test.tsx
@@ -52,13 +52,15 @@ describe("StreamRow with records missing optional fields", () => {
},
);
- it("omits the accrued line when the optional accruedAmount is absent", () => {
- const stream = toLegacyStream(makeStreamRecord());
- delete stream.accruedAmount;
+ it("renders the accrued line even when source data is missing (normalization provides fallback)", () => {
+ // With the new design, accruedAmount is always required and the normalization
+ // layer provides a fallback of 0 when source data is missing
+ const record = normalizeStreamRecord({ id: "STR-NO-AMOUNT" });
+ const stream = toLegacyStream(record);
renderRow(stream);
expect(screen.getByText(stream.name)).toBeInTheDocument();
- expect(screen.queryByText(/accrued/)).not.toBeInTheDocument();
+ expect(screen.getByText(/accrued/)).toBeInTheDocument();
});
it("renders the accrued line when accruedAmount is present", () => {
diff --git a/src/components/treasuryOverviewPage/__tests__/useTreasuryOverviewData.test.ts b/src/components/treasuryOverviewPage/__tests__/useTreasuryOverviewData.test.ts
index 6a8b8428..9b1b897e 100644
--- a/src/components/treasuryOverviewPage/__tests__/useTreasuryOverviewData.test.ts
+++ b/src/components/treasuryOverviewPage/__tests__/useTreasuryOverviewData.test.ts
@@ -110,6 +110,7 @@ describe("useTreasuryOverviewData", () => {
rate: "1,200 XLM/mo",
accruedAmount: 500,
status: "Active",
+ startDate: "",
});
});
diff --git a/src/components/treasuryOverviewPage/useTreasuryOverviewData.ts b/src/components/treasuryOverviewPage/useTreasuryOverviewData.ts
index a3c4a48c..1607fbb5 100644
--- a/src/components/treasuryOverviewPage/useTreasuryOverviewData.ts
+++ b/src/components/treasuryOverviewPage/useTreasuryOverviewData.ts
@@ -51,7 +51,7 @@ export function toLegacyStream(record: StreamRecord): Stream {
rate: formatMonthlyRate(record),
accruedAmount: record.streamedAmount,
status: record.status,
- startDate: record.startDate,
+ startDate: record.startDate || "",
};
}
|