@@ -334,5 +334,102 @@ describe('Elements', () => {
334334 expect ( mockElements . update ) . toHaveBeenCalledWith ( { bar : 'bar' } ) ;
335335 expect ( mockStripe . elements ) . toHaveBeenCalledTimes ( 2 ) ;
336336 } ) ;
337+
338+ test ( 'creates only one elements instance when updated while resolving Stripe promise' , async ( ) => {
339+ let updateResolver : any = ( ) => { } ;
340+ const updateResult = new Promise < void > ( ( resolve ) => {
341+ updateResolver = resolve ;
342+ } ) ;
343+
344+ let stripePromiseResolve : any = ( ) => { } ;
345+ const stripePromise = new Promise < any > ( ( resolve ) => {
346+ stripePromiseResolve = resolve ;
347+ } ) ;
348+
349+ // Only resolve stripe once the options have been updated
350+ updateResult . then ( ( ) => {
351+ stripePromiseResolve ( mockStripePromise ) ;
352+ } ) ;
353+
354+ const TestComponent = ( ) => {
355+ const [ _ , forceRerender ] = React . useState ( 0 ) ;
356+
357+ React . useEffect ( ( ) => {
358+ setTimeout ( ( ) => {
359+ forceRerender ( ( val ) => val + 1 ) ;
360+ setTimeout ( ( ) => {
361+ updateResolver ( ) ;
362+ } ) ;
363+ } ) ;
364+ } , [ ] ) ;
365+
366+ return (
367+ < Elements
368+ stripe = { stripePromise }
369+ options = { { appearance : { theme : 'flat' } } }
370+ />
371+ ) ;
372+ } ;
373+
374+ render ( < TestComponent /> ) ;
375+
376+ await act ( async ( ) => await updateResult ) ;
377+
378+ await act ( async ( ) => await stripePromise ) ;
379+
380+ expect ( mockStripe . elements ) . toHaveBeenCalledWith ( {
381+ appearance : { theme : 'flat' } ,
382+ } ) ;
383+ expect ( mockStripe . elements ) . toHaveBeenCalledTimes ( 1 ) ;
384+ } ) ;
385+
386+ test ( 'creates only one elements instance when updated while resolving Stripe promise in StrictMode' , async ( ) => {
387+ let updateResolver : any = ( ) => { } ;
388+ const updateResult = new Promise < void > ( ( resolve ) => {
389+ updateResolver = resolve ;
390+ } ) ;
391+
392+ let stripePromiseResolve : any = ( ) => { } ;
393+ const stripePromise = new Promise < any > ( ( resolve ) => {
394+ stripePromiseResolve = resolve ;
395+ } ) ;
396+
397+ // Only resolve stripe once the options have been updated
398+ updateResult . then ( ( ) => {
399+ stripePromiseResolve ( mockStripePromise ) ;
400+ } ) ;
401+
402+ const TestComponent = ( ) => {
403+ const [ _ , forceRerender ] = React . useState ( 0 ) ;
404+
405+ React . useEffect ( ( ) => {
406+ setTimeout ( ( ) => {
407+ forceRerender ( ( val ) => val + 1 ) ;
408+ setTimeout ( ( ) => {
409+ updateResolver ( ) ;
410+ } ) ;
411+ } ) ;
412+ } , [ ] ) ;
413+
414+ return (
415+ < StrictMode >
416+ < Elements
417+ stripe = { stripePromise }
418+ options = { { appearance : { theme : 'flat' } } }
419+ />
420+ </ StrictMode >
421+ ) ;
422+ } ;
423+
424+ render ( < TestComponent /> ) ;
425+
426+ await act ( async ( ) => await updateResult ) ;
427+ await act ( async ( ) => await stripePromise ) ;
428+
429+ expect ( mockStripe . elements ) . toHaveBeenCalledWith ( {
430+ appearance : { theme : 'flat' } ,
431+ } ) ;
432+ expect ( mockStripe . elements ) . toHaveBeenCalledTimes ( 1 ) ;
433+ } ) ;
337434 } ) ;
338435} ) ;
0 commit comments