1- import { describe , it , expect , beforeAll , afterAll , beforeEach } from "bun:test" ;
1+ import { describe , it , expect , beforeAll , afterAll , beforeEach , mock } from "bun:test" ;
22import { Miniflare } from "miniflare" ;
33import type { D1Database } from "@cloudflare/workers-types" ;
44import { initDb } from "@gonative-cc/lib/test-helpers/init_db" ;
55import { processSanctionedAddress } from "./sanction" ;
66
7+ const MOCK_NDJSON = [
8+ JSON . stringify ( {
9+ properties : {
10+ cryptoWallets : [ { properties : { currency : [ "XBT" ] , publicKey : [ "1BTC_TEST_ADDR" ] } } ] ,
11+ } ,
12+ } ) ,
13+ JSON . stringify ( {
14+ properties : {
15+ cryptoWallets : [ { properties : { currency : [ "SUI" ] , publicKey : [ "0xSUI_TEST_ADDR" ] } } ] ,
16+ } ,
17+ } ) ,
18+ JSON . stringify ( {
19+ properties : {
20+ cryptoWallets : [ { properties : { currency : [ "ETH" ] , publicKey : [ "0xETH_IGNORED" ] } } ] ,
21+ } ,
22+ } ) ,
23+ ] . join ( "\n" ) ;
24+
725let mf : Miniflare ;
826let db : D1Database ;
927let env : Env ;
@@ -24,51 +42,91 @@ afterAll(async () => {
2442beforeEach ( async ( ) => {
2543 db = await mf . getD1Database ( "DB" ) ;
2644 await initDb ( db ) ;
27- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28- env = ( await mf . getBindings ( ) ) as any ;
45+ env = await mf . getBindings ( ) ;
46+
47+ global . fetch = mock ( async ( ) => {
48+ return {
49+ ok : true ,
50+ status : 200 ,
51+ body : {
52+ getReader : ( ) => {
53+ let sent = false ;
54+ return {
55+ read : async ( ) => {
56+ if ( ! sent ) {
57+ sent = true ;
58+ return { done : false , value : Buffer . from ( MOCK_NDJSON ) } ;
59+ }
60+ return { done : true , value : undefined } ;
61+ } ,
62+ } ;
63+ } ,
64+ } ,
65+ } as unknown as Response ;
66+ } ) as unknown as typeof fetch ;
2967} ) ;
3068
3169describe ( "processSanctionedAddress" , ( ) => {
32- it ( "should fetch and store sanctioned addresses" , async ( ) => {
70+ it ( "should fetch, parse, and store sanctioned addresses from stream " , async ( ) => {
3371 await processSanctionedAddress ( env ) ;
3472
3573 const { results } = await db . prepare ( "SELECT * FROM sanctioned_addresses" ) . all ( ) ;
36- expect ( results . length ) . toBeGreaterThan ( 0 ) ;
74+ expect ( results . length ) . toBe ( 2 ) ;
3775 } ) ;
3876
39- it ( "should store BTC and SUI addresses separately " , async ( ) => {
77+ it ( "should map currencies correctly (XBT->BTC, SUI->SUI) " , async ( ) => {
4078 await processSanctionedAddress ( env ) ;
4179
42- const btcAddresses = await db
80+ const btcRecord = await db
4381 . prepare ( "SELECT * FROM sanctioned_addresses WHERE address_type = 'BTC'" )
44- . all ( ) ;
45- const suiAddresses = await db
46- . prepare ( "SELECT * FROM sanctioned_addresses WHERE address_type = 'SUI'" )
47- . all ( ) ;
82+ . first ( ) ;
83+ expect ( btcRecord ) . not . toBeNull ( ) ;
84+ expect ( btcRecord ?. wallet_address ) . toBe ( "1BTC_TEST_ADDR" ) ;
4885
49- expect ( btcAddresses . results . length ) . toBeGreaterThanOrEqual ( 0 ) ;
50- expect ( suiAddresses . results . length ) . toBeGreaterThanOrEqual ( 0 ) ;
86+ const suiRecord = await db
87+ . prepare ( "SELECT * FROM sanctioned_addresses WHERE address_type = 'SUI'" )
88+ . first ( ) ;
89+ expect ( suiRecord ) . not . toBeNull ( ) ;
90+ expect ( suiRecord ?. wallet_address ) . toBe ( "0xSUI_TEST_ADDR" ) ;
5191 } ) ;
5292
53- it ( "should replace existing addresses on subsequent runs " , async ( ) => {
93+ it ( "should strictly replace existing database records " , async ( ) => {
5494 await db
5595 . prepare (
5696 "INSERT INTO sanctioned_addresses (wallet_address, address_type) VALUES (?, ?)" ,
5797 )
58- . bind ( "test_address " , "BTC" )
98+ . bind ( "old_stale_address " , "BTC" )
5999 . run ( ) ;
60100
61- const before = await db . prepare ( "SELECT * FROM sanctioned_addresses" ) . all ( ) ;
62- expect ( before . results . length ) . toEqual ( 1 ) ;
63-
64101 await processSanctionedAddress ( env ) ;
65102
66- const after = await db . prepare ( "SELECT * FROM sanctioned_addresses" ) . all ( ) ;
67- expect ( after . results . length ) . toBeGreaterThan ( 0 ) ;
68-
69- const testAddr = await db
70- . prepare ( "SELECT * FROM sanctioned_addresses WHERE wallet_address = 'test_address'" )
103+ const staleCheck = await db
104+ . prepare (
105+ "SELECT * FROM sanctioned_addresses WHERE wallet_address = 'old_stale_address'" ,
106+ )
71107 . first ( ) ;
72- expect ( testAddr ) . toBeNull ( ) ;
108+ expect ( staleCheck ) . toBeNull ( ) ;
109+
110+ const newCheck = await db . prepare ( "SELECT * FROM sanctioned_addresses" ) . all ( ) ;
111+ expect ( newCheck . results . length ) . toBe ( 2 ) ;
112+ } ) ;
113+
114+ it ( "should handle empty or malformed API responses gracefully" , async ( ) => {
115+ global . fetch = mock (
116+ async ( ) =>
117+ ( {
118+ ok : true ,
119+ body : {
120+ getReader : ( ) => ( {
121+ read : async ( ) => ( { done : true , value : undefined } ) ,
122+ } ) ,
123+ } ,
124+ } ) as unknown as Response ,
125+ ) as unknown as typeof fetch ;
126+
127+ await processSanctionedAddress ( env ) ;
128+
129+ const { results } = await db . prepare ( "SELECT * FROM sanctioned_addresses" ) . all ( ) ;
130+ expect ( results . length ) . toBe ( 0 ) ;
73131 } ) ;
74132} ) ;
0 commit comments