@@ -23,9 +23,17 @@ const dsoEntry = nameServiceEntries.find(e => e.name.startsWith('dso'))!;
2323
2424const walletUrl = window . splice_config . services . validator . url ;
2525
26- function featureSupportHandler ( tokenStandardSupported : boolean ) {
26+ function featureSupportHandler (
27+ tokenStandardSupported : boolean ,
28+ transferPreapprovalDescriptionSupported : boolean
29+ ) {
2730 return rest . get ( `${ walletUrl } /v0/feature-support` , async ( _ , res , ctx ) => {
28- return res ( ctx . json ( { token_standard : tokenStandardSupported } ) ) ;
31+ return res (
32+ ctx . json ( {
33+ token_standard : tokenStandardSupported ,
34+ transfer_preapproval_description : transferPreapprovalDescriptionSupported ,
35+ } )
36+ ) ;
2937 } ) ;
3038}
3139
@@ -100,7 +108,7 @@ describe('Wallet user can', () => {
100108 } ) ;
101109
102110 test ( 'not see dso in list of transfer-offer receivers' , async ( ) => {
103- server . use ( featureSupportHandler ( true ) ) ;
111+ server . use ( featureSupportHandler ( true , true ) ) ;
104112 const user = userEvent . setup ( ) ;
105113 render (
106114 < WalletConfigProvider >
@@ -133,7 +141,7 @@ describe('Wallet user can', () => {
133141 transferTests ( false ) ;
134142
135143 test ( 'fall back to non-token standard transfers when the token standard is not supported' , async ( ) => {
136- server . use ( featureSupportHandler ( false ) ) ;
144+ server . use ( featureSupportHandler ( false , true ) ) ;
137145
138146 const user = userEvent . setup ( ) ;
139147 render (
@@ -192,6 +200,121 @@ describe('Wallet user can', () => {
192200 // The withdraw has a dummy conversion rate of 0 so no amulet conversion rate is displayed
193201 expect ( await screen . findAllByText ( '@' ) ) . toHaveLength ( 3 ) ;
194202 } ) ;
203+
204+ test ( 'transfer preapproval (without token standard) does not show nor send description if not supported' , async ( ) => {
205+ // token standard as not supported
206+ server . use ( featureSupportHandler ( false , false ) ) ;
207+ const user = userEvent . setup ( ) ;
208+ render (
209+ < WalletConfigProvider >
210+ < App />
211+ </ WalletConfigProvider >
212+ ) ;
213+ expect ( await screen . findByText ( 'Transfer' ) ) . toBeDefined ( ) ;
214+
215+ const transferOffersLink = screen . getByRole ( 'link' , { name : 'Transfer' } ) ;
216+ await user . click ( transferOffersLink ) ;
217+ expect ( screen . getByRole ( 'heading' , { name : 'Transfers' } ) ) . toBeDefined ( ) ;
218+
219+ const receiverInput = screen
220+ . getAllByRole ( 'combobox' )
221+ . find ( e => e . id === 'create-offer-receiver' ) ! ;
222+ fireEvent . change ( receiverInput , { target : { value : 'bob::preapproval' } } ) ;
223+ await vi . waitFor ( ( ) => expect ( screen . getByRole ( 'button' , { name : 'Send' } ) ) . toBeEnabled ( ) ) ;
224+
225+ // there should be no description input
226+ expect ( screen . queryByRole ( 'textbox' , { name : 'description' } ) ) . not . toBeInTheDocument ( ) ;
227+
228+ await user . click ( screen . getByRole ( 'button' , { name : 'Send' } ) ) ;
229+
230+ await assertCorrectMockIsCalled (
231+ true ,
232+ {
233+ amount : '1.0' ,
234+ receiver_party_id : 'bob::preapproval' ,
235+ // description omitted: it is not sent
236+ } ,
237+ true
238+ ) ;
239+ } ) ;
240+
241+ test ( 'transfer offers have description field when unsupported for preapprovals' , async ( ) => {
242+ // transfer preapprovals do not support description, but that's inconsequential to regular transfer offers
243+ server . use ( featureSupportHandler ( false , false ) ) ;
244+ const user = userEvent . setup ( ) ;
245+ render (
246+ < WalletConfigProvider >
247+ < App />
248+ </ WalletConfigProvider >
249+ ) ;
250+ expect ( await screen . findByText ( 'Transfer' ) ) . toBeDefined ( ) ;
251+
252+ const transferOffersLink = screen . getByRole ( 'link' , { name : 'Transfer' } ) ;
253+ await user . click ( transferOffersLink ) ;
254+ expect ( screen . getByRole ( 'heading' , { name : 'Transfers' } ) ) . toBeDefined ( ) ;
255+
256+ const receiverInput = screen
257+ . getAllByRole ( 'combobox' )
258+ . find ( e => e . id === 'create-offer-receiver' ) ! ;
259+ fireEvent . change ( receiverInput , { target : { value : 'bob::preapproval' } } ) ;
260+ await vi . waitFor ( ( ) => expect ( screen . getByRole ( 'button' , { name : 'Send' } ) ) . toBeEnabled ( ) ) ;
261+
262+ await user . click ( screen . getByRole ( 'checkbox' ) ) ;
263+
264+ const description = 'Works' ;
265+ const descriptionInput = screen . getByRole ( 'textbox' , { name : 'description' } ) ;
266+ await user . type ( descriptionInput , description ) ;
267+
268+ await user . click ( screen . getByRole ( 'button' , { name : 'Send' } ) ) ;
269+
270+ await assertCorrectMockIsCalled (
271+ true ,
272+ {
273+ amount : '1.0' ,
274+ receiver_party_id : 'bob::preapproval' ,
275+ description,
276+ } ,
277+ false
278+ ) ;
279+ } ) ;
280+
281+ test ( 'transfer offers have description field when party has no preapproval and transfer preapprovals do not support descriptions' , async ( ) => {
282+ // transfer preapprovals do not support description, but that's inconsequential to regular transfer offers
283+ server . use ( featureSupportHandler ( false , false ) ) ;
284+ const user = userEvent . setup ( ) ;
285+ render (
286+ < WalletConfigProvider >
287+ < App />
288+ </ WalletConfigProvider >
289+ ) ;
290+ expect ( await screen . findByText ( 'Transfer' ) ) . toBeDefined ( ) ;
291+
292+ const transferOffersLink = screen . getByRole ( 'link' , { name : 'Transfer' } ) ;
293+ await user . click ( transferOffersLink ) ;
294+ expect ( screen . getByRole ( 'heading' , { name : 'Transfers' } ) ) . toBeDefined ( ) ;
295+
296+ const receiverInput = screen
297+ . getAllByRole ( 'combobox' )
298+ . find ( e => e . id === 'create-offer-receiver' ) ! ;
299+ fireEvent . change ( receiverInput , { target : { value : 'bob::nopreapproval' } } ) ;
300+ await vi . waitFor ( ( ) => expect ( screen . getByRole ( 'button' , { name : 'Send' } ) ) . toBeEnabled ( ) ) ;
301+
302+ const description = 'Works' ;
303+ const descriptionInput = screen . getByRole ( 'textbox' , { name : 'description' } ) ;
304+ await user . type ( descriptionInput , description ) ;
305+
306+ await user . click ( screen . getByRole ( 'button' , { name : 'Send' } ) ) ;
307+
308+ await assertCorrectMockIsCalled (
309+ true ,
310+ {
311+ amount : '1.0' ,
312+ receiver_party_id : 'bob::nopreapproval' ,
313+ description,
314+ } ,
315+ false
316+ ) ;
317+ } ) ;
195318} , 7500 ) ;
196319
197320function transferTests ( disableTokenStandard : boolean ) {
@@ -203,7 +326,7 @@ function transferTests(disableTokenStandard: boolean) {
203326 }
204327
205328 test ( 'transfer offer is used when receiver has no transfer preapproval' , async ( ) => {
206- server . use ( featureSupportHandler ( true ) ) ;
329+ server . use ( featureSupportHandler ( true , true ) ) ;
207330 const user = userEvent . setup ( ) ;
208331 render (
209332 < WalletConfigProvider >
@@ -236,7 +359,7 @@ function transferTests(disableTokenStandard: boolean) {
236359 } ) ;
237360
238361 test ( 'transfer preapproval is used when receiver has a transfer preapproval' , async ( ) => {
239- server . use ( featureSupportHandler ( true ) ) ;
362+ server . use ( featureSupportHandler ( true , true ) ) ;
240363 const user = userEvent . setup ( ) ;
241364 render (
242365 < WalletConfigProvider >
@@ -270,7 +393,7 @@ function transferTests(disableTokenStandard: boolean) {
270393 } ) ;
271394
272395 test ( 'transfer offer is used when receiver has a transfer preapproval but checkbox is unchecked' , async ( ) => {
273- server . use ( featureSupportHandler ( true ) ) ;
396+ server . use ( featureSupportHandler ( true , true ) ) ;
274397 const user = userEvent . setup ( ) ;
275398 render (
276399 < WalletConfigProvider >
@@ -304,7 +427,7 @@ function transferTests(disableTokenStandard: boolean) {
304427 } ) ;
305428
306429 test ( 'deduplication id is passed' , async ( ) => {
307- server . use ( featureSupportHandler ( true ) ) ;
430+ server . use ( featureSupportHandler ( true , true ) ) ;
308431 const user = userEvent . setup ( ) ;
309432 render (
310433 < WalletConfigProvider >
@@ -370,7 +493,7 @@ function transferTests(disableTokenStandard: boolean) {
370493
371494async function assertCorrectMockIsCalled (
372495 usesRegularTransferOffer : boolean ,
373- expected : { amount : string ; receiver_party_id : string ; description : string } ,
496+ expected : { amount : string ; receiver_party_id : string ; description ? : string } ,
374497 isPreapproval : boolean
375498) {
376499 if ( ! usesRegularTransferOffer ) {
@@ -383,6 +506,12 @@ async function assertCorrectMockIsCalled(
383506 expect ( requestMocks . transferPreapprovalSend ) . toHaveBeenCalledWith (
384507 expect . objectContaining ( expected )
385508 ) ;
509+ // unfortunately 'objectContaining' does not work for `description: undefined`:
510+ // the mock omits the field and the expected has it as undefined.
511+ // Omitting `description` from `expected` doesn't work because then it's not checked at all.
512+ expect ( requestMocks . transferPreapprovalSend . mock . lastCall ! [ 0 ] . description ) . equals (
513+ expected . description
514+ ) ;
386515 expect ( requestMocks . createTransferOffer ) . not . toHaveBeenCalled ( ) ;
387516 expect ( requestMocks . createTransferViaTokenStandard ) . not . toHaveBeenCalled ( ) ;
388517 } else {
0 commit comments