@@ -47,6 +47,7 @@ import { proposalManager } from "@exactly/plugin/deploy.json";
4747import database , { cards , credentials , transactions } from "../../database" ;
4848import app from "../../hooks/panda" ;
4949import keeper from "../../utils/keeper" ;
50+ import * as onesignal from "../../utils/onesignal" ;
5051import * as panda from "../../utils/panda" ;
5152import publicClient from "../../utils/publicClient" ;
5253import * as sardine from "../../utils/sardine" ;
@@ -601,6 +602,44 @@ describe("card operations", () => {
601602 expect ( response . status ) . toBe ( 200 ) ;
602603 } ) ;
603604
605+ it ( "sends locale-aware card purchase notification" , async ( ) => {
606+ const sendPushNotificationSpy = vi
607+ . spyOn ( onesignal , "sendPushNotification" )
608+ . mockImplementation ( ( ) => Promise . resolve ( undefined as never ) ) ;
609+ // @ts -expect-error mock implementation
610+ vi . spyOn ( keeper , "exaSend" ) . mockImplementation ( async ( ...args ) => {
611+ await args [ 2 ] ?. onHash ?.( zeroHash as Hash ) ;
612+ } ) ;
613+ const localAmount = 123_456 ;
614+ const cardId = "locale-notify" ;
615+ await database . insert ( cards ) . values ( [ { id : cardId , credentialId : "cred" , lastFour : "9999" , mode : 0 } ] ) ;
616+
617+ const response = await appClient . index . $post ( {
618+ ...authorization ,
619+ json : {
620+ ...authorization . json ,
621+ action : "created" ,
622+ body : {
623+ ...authorization . json . body ,
624+ id : cardId ,
625+ spend : { ...authorization . json . body . spend , cardId, localAmount, localCurrency : "ars" } ,
626+ } ,
627+ } ,
628+ } ) ;
629+
630+ expect ( response . status ) . toBe ( 200 ) ;
631+ await vi . waitFor ( ( ) => expect ( sendPushNotificationSpy ) . toHaveBeenCalled ( ) ) ;
632+ const call = sendPushNotificationSpy . mock . calls [ 0 ] ?. [ 0 ] ;
633+ expect ( call ?. headings ) . toStrictEqual ( { en : "Card purchase" , es : "Compra con tarjeta" } ) ; // cspell:ignore Compra tarjeta
634+ const enAmount = ( localAmount / 100 ) . toLocaleString ( "en-US" , { style : "currency" , currency : "ars" } ) ;
635+ const esAmount = ( localAmount / 100 ) . toLocaleString ( "es-AR" , { style : "currency" , currency : "ars" } ) ;
636+ expect ( enAmount ) . not . toBe ( esAmount ) ;
637+ expect ( call ?. contents ) . toStrictEqual ( {
638+ en : `${ enAmount } at 99999. Paid with USDC` ,
639+ es : `${ esAmount } en 99999. Pagado con USDC` , // cspell:ignore Pagado
640+ } ) ;
641+ } ) ;
642+
604643 it ( "fails with transaction timeout" , async ( ) => {
605644 const error = new Error ( "timeout" ) ;
606645 const track = vi . spyOn ( segment , "track" ) . mockReturnValue ( ) ;
@@ -896,6 +935,7 @@ describe("card operations", () => {
896935 afterEach ( ( ) => vi . restoreAllMocks ( ) ) ;
897936
898937 it ( "handles reversal" , async ( ) => {
938+ const sendPushNotification = vi . spyOn ( onesignal , "sendPushNotification" ) ;
899939 const amount = 2073 ;
900940 const cardId = "card" ;
901941 await keeper . exaSend (
@@ -954,6 +994,14 @@ describe("card operations", () => {
954994
955995 expect ( deposit ?. args . assets ) . toBe ( BigInt ( amount * 1e4 ) ) ;
956996 expect ( response . status ) . toBe ( 200 ) ;
997+ expect ( sendPushNotification ) . toHaveBeenCalledWith ( {
998+ userId : account ,
999+ headings : { en : "Refund processed" , es : "Reembolso procesado" } , // cspell:ignore Reembolso procesado
1000+ contents : {
1001+ en : "20.73 USDC from 99999 have been refunded to your account" ,
1002+ es : "20,73 USDC de 99999 fueron reembolsados a tu cuenta" , // cspell:ignore reembolsados cuenta fueron
1003+ } ,
1004+ } ) ;
9571005 } ) ;
9581006
9591007 it ( "returns ok on reversal replay" , async ( ) => {
0 commit comments