@@ -1253,16 +1253,74 @@ describe("Feed", () => {
12531253 event : "new-message" as const ,
12541254 metadata : { total_count : 2 , unread_count : 2 , unseen_count : 2 } ,
12551255 data : {
1256- client_ref_id : {
1256+ [ feed . referenceId ] : {
12571257 metadata : { total_count : 2 , unread_count : 2 , unseen_count : 2 } ,
12581258 } ,
12591259 } ,
12601260 } ;
12611261
12621262 await feed . handleSocketEvent ( newMessagePayload ) ;
12631263
1264- // Should trigger a fetch to get the latest data
1265- expect ( mockApiClient . makeRequest ) . toHaveBeenCalled ( ) ;
1264+ // Should trigger a fetch to get the latest data with exclude: "meta"
1265+ expect ( mockApiClient . makeRequest ) . toHaveBeenCalledWith ( {
1266+ method : "GET" ,
1267+ url : "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef" ,
1268+ params : {
1269+ archived : "exclude" ,
1270+ mode : "compact" ,
1271+ exclude : "meta" ,
1272+ } ,
1273+ } ) ;
1274+ } finally {
1275+ cleanup ( ) ;
1276+ }
1277+ } ) ;
1278+
1279+ test ( "handles new message socket events without metadata in payload" , async ( ) => {
1280+ const { knock, mockApiClient, cleanup } = getTestSetup ( ) ;
1281+
1282+ try {
1283+ const mockSocketManager = {
1284+ join : vi . fn ( ) . mockReturnValue ( vi . fn ( ) ) ,
1285+ leave : vi . fn ( ) ,
1286+ } ;
1287+
1288+ // Mock the store response for the feed fetch
1289+ mockApiClient . makeRequest . mockResolvedValue ( {
1290+ statusCode : "ok" ,
1291+ body : {
1292+ entries : [ ] ,
1293+ page_info : { before : null , after : null } ,
1294+ meta : { total_count : 1 , unread_count : 1 , unseen_count : 1 } ,
1295+ } ,
1296+ } ) ;
1297+
1298+ const feed = new Feed (
1299+ knock ,
1300+ "01234567-89ab-cdef-0123-456789abcdef" ,
1301+ { } ,
1302+ mockSocketManager as unknown as FeedSocketManager ,
1303+ ) ;
1304+
1305+ // Payload lacking metadata for this client's referenceId.
1306+ // This should never happen in practice, but we should handle it gracefully.
1307+ const newMessagePayload = {
1308+ event : "new-message" as const ,
1309+ metadata : { total_count : 2 , unread_count : 2 , unseen_count : 2 } ,
1310+ data : { } ,
1311+ } ;
1312+
1313+ await feed . handleSocketEvent ( newMessagePayload ) ;
1314+
1315+ // Should trigger a fetch WITHOUT exclude: "meta" to get badge counts from API
1316+ expect ( mockApiClient . makeRequest ) . toHaveBeenCalledWith ( {
1317+ method : "GET" ,
1318+ url : "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef" ,
1319+ params : {
1320+ archived : "exclude" ,
1321+ mode : "compact" ,
1322+ } ,
1323+ } ) ;
12661324 } finally {
12671325 cleanup ( ) ;
12681326 }
@@ -1677,4 +1735,83 @@ describe("Feed", () => {
16771735 }
16781736 } ) ;
16791737 } ) ;
1738+
1739+ describe ( "Exclude Option" , ( ) => {
1740+ test ( "converts exclude array to comma-separated string in query params" , async ( ) => {
1741+ const { knock, mockApiClient, cleanup } = getTestSetup ( ) ;
1742+
1743+ try {
1744+ const mockFeedResponse = {
1745+ entries : [ ] ,
1746+ meta : { total_count : 0 , unread_count : 0 , unseen_count : 0 } ,
1747+ page_info : { before : null , after : null , page_size : 50 } ,
1748+ } ;
1749+
1750+ mockApiClient . makeRequest . mockResolvedValue ( {
1751+ statusCode : "ok" ,
1752+ body : mockFeedResponse ,
1753+ } ) ;
1754+
1755+ const feed = new Feed (
1756+ knock ,
1757+ "01234567-89ab-cdef-0123-456789abcdef" ,
1758+ { } ,
1759+ undefined ,
1760+ ) ;
1761+
1762+ await feed . fetch ( {
1763+ exclude : [ "entries.archived_at" , "meta.total_count" ] ,
1764+ } ) ;
1765+
1766+ expect ( mockApiClient . makeRequest ) . toHaveBeenCalledWith ( {
1767+ method : "GET" ,
1768+ url : "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef" ,
1769+ params : {
1770+ archived : "exclude" ,
1771+ mode : "compact" ,
1772+ exclude : "entries.archived_at,meta.total_count" ,
1773+ } ,
1774+ } ) ;
1775+ } finally {
1776+ cleanup ( ) ;
1777+ }
1778+ } ) ;
1779+
1780+ test ( "ignores empty exclude array" , async ( ) => {
1781+ const { knock, mockApiClient, cleanup } = getTestSetup ( ) ;
1782+
1783+ try {
1784+ const mockFeedResponse = {
1785+ entries : [ ] ,
1786+ meta : { total_count : 0 , unread_count : 0 , unseen_count : 0 } ,
1787+ page_info : { before : null , after : null , page_size : 50 } ,
1788+ } ;
1789+
1790+ mockApiClient . makeRequest . mockResolvedValue ( {
1791+ statusCode : "ok" ,
1792+ body : mockFeedResponse ,
1793+ } ) ;
1794+
1795+ const feed = new Feed (
1796+ knock ,
1797+ "01234567-89ab-cdef-0123-456789abcdef" ,
1798+ { } ,
1799+ undefined ,
1800+ ) ;
1801+
1802+ await feed . fetch ( { exclude : [ ] } ) ;
1803+
1804+ expect ( mockApiClient . makeRequest ) . toHaveBeenCalledWith ( {
1805+ method : "GET" ,
1806+ url : "/v1/users/user_123/feeds/01234567-89ab-cdef-0123-456789abcdef" ,
1807+ params : {
1808+ archived : "exclude" ,
1809+ mode : "compact" ,
1810+ } ,
1811+ } ) ;
1812+ } finally {
1813+ cleanup ( ) ;
1814+ }
1815+ } ) ;
1816+ } ) ;
16801817} ) ;
0 commit comments