Skip to content

Commit 253b259

Browse files
test: cover holdings without price snapshot
1 parent 5a795cf commit 253b259

3 files changed

Lines changed: 39 additions & 6 deletions

File tree

src/modules/wallets/__tests__/wallet-holdings.integration.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,36 @@ describe('GET /wallets/:address/holdings', () => {
104104
});
105105
});
106106

107+
it('returns a holding with zero value when its creator has no price snapshot', async () => {
108+
const holding = makeHolding({
109+
creator_id: 'new-creator',
110+
creator_handle: 'new-creator-handle',
111+
key_count: '5',
112+
current_price: null,
113+
total_value: '0',
114+
});
115+
jest
116+
.spyOn(walletHoldingsService, 'fetchWalletHoldings')
117+
.mockResolvedValue([[holding], 1]);
118+
119+
const req = makeReq({ address: VALID_ADDRESS });
120+
const res = makeRes();
121+
const next = makeNext();
122+
await httpGetWalletHoldings(req, res, next);
123+
124+
expect(next).not.toHaveBeenCalled();
125+
expect(res.status).toHaveBeenCalledWith(200);
126+
const body = res.json.mock.calls[0][0];
127+
expect(body.data.items).toContainEqual(
128+
expect.objectContaining({
129+
creator_id: 'new-creator',
130+
key_count: '5',
131+
current_price: null,
132+
total_value: '0',
133+
})
134+
);
135+
});
136+
107137
it('returns 200 with empty items for a wallet with no holdings', async () => {
108138
jest
109139
.spyOn(walletHoldingsService, 'fetchWalletHoldings')

src/modules/wallets/wallet-holdings-price-snapshot.integration.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Integration test: wallet holdings total value recalculated after price snapshot update (#470)
22
//
33
// Covers: total_value and current_price reflect the current price snapshot,
4-
// both update correctly when the snapshot price changes, null when no snapshot exists,
4+
// both update correctly when the snapshot price changes, zero value when no snapshot exists,
55
// and multi-holding aggregation is correct.
66
// Uses Jest mocks — no database required.
77

@@ -83,13 +83,14 @@ describe('Holdings total_value recalculated after price snapshot update', () =>
8383
expect(updatedItems[0].total_value).not.toBe(initialTotalValue);
8484
});
8585

86-
it('current_price and total_value are null when no snapshot exists for the creator', async () => {
86+
it('returns zero total_value when no snapshot exists for the creator while preserving quantity', async () => {
8787
mockPrisma.creatorPriceSnapshot.findMany.mockResolvedValue([]);
8888

8989
const [items] = await fetchWalletHoldings(WALLET_ADDRESS);
9090

9191
expect(items[0].current_price).toBeNull();
92-
expect(items[0].total_value).toBeNull();
92+
expect(items[0].total_value).toBe('0');
93+
expect(items[0].key_count).toBe('5');
9394
});
9495

9596
it('total_value is computed per-holding when wallet has multiple holdings', async () => {

src/modules/wallets/wallet-holdings.service.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ export async function fetchWalletHoldings(
7474
const rawPrice = priceMap.get(row.creatorId) ?? null;
7575
const currentPrice = rawPrice !== null ? rawPrice.toString() : null;
7676
const totalValue =
77-
rawPrice !== null && row.balance !== null
78-
? (Number(row.balance) * Number(rawPrice)).toString()
79-
: null;
77+
rawPrice === null
78+
? '0'
79+
: row.balance !== null
80+
? (Number(row.balance) * Number(rawPrice)).toString()
81+
: null;
8082
return {
8183
creator_id: row.creatorId,
8284
creator_handle: handleMap.get(row.creatorId) ?? null,

0 commit comments

Comments
 (0)