11import { afterEach , describe , expect , it , vi } from "vitest" ;
22import { backfillEvents } from "../src/backfill" ;
3- import { getBlockWithTxHashes } from "../src/block-cache" ;
3+ import { StarknetBlockCache , getBlockWithTxHashes } from "../src/block-cache" ;
44import { compareEventCursor , eventCursorKey } from "../src/cursor" ;
55import { getEvents } from "../src/http" ;
66import { normalizeEvent , normalizeFelt } from "../src/normalize" ;
@@ -37,7 +37,7 @@ describe("cursor comparison", () => {
3737 ) . toBeGreaterThan ( 0 ) ;
3838 expect (
3939 compareEventCursor ( cursor ( 2 , "0x2" , 1 , 0 ) , cursor ( 2 , "0x1" , 1 , 0 ) ) ,
40- ) . toBeGreaterThan ( 0 ) ;
40+ ) . toBe ( 0 ) ;
4141 } ) ;
4242
4343 it ( "keeps the cursor identity keyed by transaction hash and event index" , ( ) => {
@@ -47,6 +47,46 @@ describe("cursor comparison", () => {
4747 } ) ;
4848} ) ;
4949
50+ describe ( "block cache" , ( ) => {
51+ it ( "caches blocks by number and hash and invalidates from a reorg start" , async ( ) => {
52+ const requests : unknown [ ] = [ ] ;
53+ mockRpcFetch ( ( request ) => {
54+ requests . push ( request ) ;
55+ return {
56+ block_hash : "0xabc" ,
57+ block_number : 10 ,
58+ timestamp : 100 ,
59+ transactions : [ ] ,
60+ } ;
61+ } ) ;
62+
63+ const cache = new StarknetBlockCache ( { url : RPC_URL } ) ;
64+
65+ await expect (
66+ cache . getBlockWithTxHashes ( { block_number : 10 } ) ,
67+ ) . resolves . toMatchObject ( {
68+ block_number : 10 ,
69+ } ) ;
70+ await expect (
71+ cache . getBlockWithTxHashes ( { block_number : 10 } ) ,
72+ ) . resolves . toMatchObject ( {
73+ block_number : 10 ,
74+ } ) ;
75+ expect ( requests ) . toHaveLength ( 1 ) ;
76+ expect (
77+ cache . getCachedMetadata ( { block_hash : normalizeFelt ( "0xabc" ) } ) ,
78+ ) . toMatchObject ( {
79+ blockNumber : 10 ,
80+ timestamp : 100 ,
81+ } ) ;
82+
83+ cache . invalidateFrom ( 10 ) ;
84+
85+ await cache . getBlockWithTxHashes ( { block_number : 10 } ) ;
86+ expect ( requests ) . toHaveLength ( 2 ) ;
87+ } ) ;
88+ } ) ;
89+
5090describe ( "event normalization" , ( ) => {
5191 it ( "requires transaction_index and includes it in the cursor" , ( ) => {
5292 expect ( normalizeEvent ( rawEvent ( { transactionIndex : 7 } ) ) . cursor ) . toEqual ( {
@@ -453,6 +493,38 @@ describe("WebSocket subscriptions", () => {
453493 await expect ( next ) . rejects . toBeInstanceOf ( TooManyBlocksBackError ) ;
454494 expect ( socket . sent ) . toHaveLength ( 1 ) ;
455495 } ) ;
496+
497+ it ( "rejects subscription-only block tags before sending" , async ( ) => {
498+ const sockets : MockWebSocket [ ] = [ ] ;
499+ const iterator = connectSubscribeEvents ( {
500+ url : WS_URL ,
501+ blockId : "pending" ,
502+ webSocketFactory : mockWebSocketFactory ( sockets ) ,
503+ } as never ) ;
504+
505+ const next = iterator . next ( ) ;
506+ const socket = await waitForSocket ( sockets , 0 ) ;
507+ socket . open ( ) ;
508+
509+ await expect ( next ) . rejects . toThrow ( / b l o c k I d t a g / ) ;
510+ expect ( socket . sent ) . toHaveLength ( 0 ) ;
511+ } ) ;
512+
513+ it ( "rejects unsupported subscription finality statuses before sending" , async ( ) => {
514+ const sockets : MockWebSocket [ ] = [ ] ;
515+ const iterator = connectSubscribeEvents ( {
516+ url : WS_URL ,
517+ finalityStatus : "ACCEPTED_ON_L1" ,
518+ webSocketFactory : mockWebSocketFactory ( sockets ) ,
519+ } as never ) ;
520+
521+ const next = iterator . next ( ) ;
522+ const socket = await waitForSocket ( sockets , 0 ) ;
523+ socket . open ( ) ;
524+
525+ await expect ( next ) . rejects . toThrow ( / f i n a l i t y S t a t u s / ) ;
526+ expect ( socket . sent ) . toHaveLength ( 0 ) ;
527+ } ) ;
456528} ) ;
457529
458530describe ( "combined stream" , ( ) => {
0 commit comments