@@ -6,7 +6,6 @@ import { flushPromiseQueue } from "DevTools/flushPromiseQueue"
66import { setupTestWrapperTL } from "DevTools/setupTestWrapperTL"
77import type { Order2ExpressCheckoutUI_Test_Query } from "__generated__/Order2ExpressCheckoutUI_Test_Query.graphql"
88import { useEffect } from "react"
9- import React from "react"
109import { graphql } from "react-relay"
1110import { useTracking } from "react-tracking"
1211import { Order2ExpressCheckoutUI } from "../Order2ExpressCheckoutUI"
@@ -644,45 +643,19 @@ describe("ExpressCheckoutUI", () => {
644643 } )
645644 } )
646645
647- it ( "displays error when there is an error" , async ( ) => {
648- const mockErrorRef = { current : "test_error_code" }
649- jest . spyOn ( React , "useRef" ) . mockReturnValue ( mockErrorRef )
646+ it ( "does not track cancel event when there is an existing error" , async ( ) => {
647+ // Set up a pre-existing error in context (e.g. from a failed payment)
648+ mockMessages . EXPRESS_CHECKOUT = {
649+ error : { title : "An error occurred" , message : "Something went wrong" } as any ,
650+ }
651+ mockCheckoutContext . messages = { ...mockMessages }
650652
651- const { mockResolveLastOperation } = renderWithRelay ( {
652- Order : ( ) => ( { ...orderData } ) ,
653- } )
653+ renderWithRelay ( { Order : ( ) => ( { ...orderData } ) } )
654654
655655 fireEvent . click ( screen . getByTestId ( "express-checkout-cancel" ) )
656656
657- // Resolve the mutations
658- await mockResolveLastOperation ( {
659- unsetOrderPaymentMethodPayload : ( ) => ( {
660- orderOrError : {
661- __typename : "OrderMutationSuccess" ,
662- order : orderData ,
663- } ,
664- } ) ,
665- } )
666-
667- await mockResolveLastOperation ( {
668- unsetOrderFulfillmentOptionPayload : ( ) => ( {
669- orderOrError : {
670- __typename : "OrderMutationSuccess" ,
671- order : orderData ,
672- } ,
673- } ) ,
674- } )
675-
676- await flushPromiseQueue ( )
677-
678- // Verify error was set for the express checkout section
679- expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith (
680- expect . objectContaining ( {
681- section : "EXPRESS_CHECKOUT" ,
682- error : expect . objectContaining ( {
683- title : "An error occurred" ,
684- } ) ,
685- } ) ,
657+ expect ( trackEvent ) . not . toHaveBeenCalledWith (
658+ expect . objectContaining ( { action : "clickedCancelExpressCheckout" } ) ,
686659 )
687660 } )
688661 } )
@@ -729,89 +702,157 @@ describe("ExpressCheckoutUI", () => {
729702 expect ( window . location . reload ) . not . toHaveBeenCalled ( )
730703 } )
731704
732- describe ( "Error message handling by error code" , ( ) => {
733- it ( "shows payment failed message for backend processing errors" , async ( ) => {
734- const mockErrorRef = { current : "create_credit_card_failed" }
735- jest . spyOn ( React , "useRef" ) . mockReturnValue ( mockErrorRef )
705+ describe ( "Error handling" , ( ) => {
706+ describe ( "handleSubmitError" , ( ) => {
707+ it ( "sets a 'not available' error when insufficient inventory" , async ( ) => {
708+ const stripeModule = jest . requireMock ( "@stripe/react-stripe-js" )
709+ stripeModule . useElements . mockReturnValueOnce ( {
710+ submit : jest . fn ( async ( ) => ( {
711+ error : {
712+ code : "insufficient_inventory" ,
713+ message : "Artwork unavailable" ,
714+ } ,
715+ } ) ) ,
716+ update : mockElementsUpdate ,
717+ } )
736718
737- const { mockResolveLastOperation } = renderWithRelay ( {
738- Order : ( ) => ( { ...orderData } ) ,
739- } )
719+ renderWithRelay ( { Order : ( ) => ( { ...orderData } ) } )
740720
741- fireEvent . click ( screen . getByTestId ( "express-checkout-cancel" ) )
721+ fireEvent . click ( screen . getByTestId ( "express-checkout-confirm" ) )
722+ await flushPromiseQueue ( )
742723
743- // Resolve the mutations
744- await mockResolveLastOperation ( {
745- unsetOrderPaymentMethodPayload : ( ) => ( {
746- orderOrError : {
747- __typename : "OrderMutationSuccess " ,
748- order : orderData ,
724+ expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith ( {
725+ section : "EXPRESS_CHECKOUT" ,
726+ error : {
727+ title : "Not available" ,
728+ message : "Sorry, the work is no longer available. " ,
729+ code : "insufficient_inventory" ,
749730 } ,
750- } ) ,
731+ } )
751732 } )
752733
753- await mockResolveLastOperation ( {
754- unsetOrderFulfillmentOptionPayload : ( ) => ( {
755- orderOrError : {
756- __typename : "OrderMutationSuccess" ,
757- order : orderData ,
734+ it ( "sets a payment processing error when charge authorization fails" , async ( ) => {
735+ const stripeModule = jest . requireMock ( "@stripe/react-stripe-js" )
736+ stripeModule . useElements . mockReturnValueOnce ( {
737+ submit : jest . fn ( async ( ) => ( {
738+ error : {
739+ code : "charge_authorization_failed" ,
740+ message : "Your card was declined" ,
741+ } ,
742+ } ) ) ,
743+ update : mockElementsUpdate ,
744+ } )
745+
746+ renderWithRelay ( { Order : ( ) => ( { ...orderData } ) } )
747+
748+ fireEvent . click ( screen . getByTestId ( "express-checkout-confirm" ) )
749+ await flushPromiseQueue ( )
750+
751+ expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith ( {
752+ section : "EXPRESS_CHECKOUT" ,
753+ error : {
754+ title : "An error occurred while processing your payment" ,
755+ message : "Your card was declined" ,
756+ code : "charge_authorization_failed" ,
758757 } ,
759- } ) ,
758+ } )
760759 } )
761760
762- await flushPromiseQueue ( )
761+ it ( "sets a generic error for unhandled submit error codes" , async ( ) => {
762+ const stripeModule = jest . requireMock ( "@stripe/react-stripe-js" )
763+ stripeModule . useElements . mockReturnValueOnce ( {
764+ submit : jest . fn ( async ( ) => ( {
765+ error : {
766+ code : "unexpected_error" ,
767+ message : "Something went wrong" ,
768+ } ,
769+ } ) ) ,
770+ update : mockElementsUpdate ,
771+ } )
763772
764- // Verify error was set for the express checkout section with payment failed message
765- expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith (
766- expect . objectContaining ( {
773+ renderWithRelay ( { Order : ( ) => ( { ...orderData } ) } )
774+
775+ fireEvent . click ( screen . getByTestId ( "express-checkout-confirm" ) )
776+ await flushPromiseQueue ( )
777+
778+ expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith ( {
767779 section : "EXPRESS_CHECKOUT" ,
768780 error : expect . objectContaining ( {
769- title : "Payment failed" ,
781+ title : "An error occurred" ,
782+ code : "unexpected_error" ,
770783 } ) ,
771- } ) ,
772- )
784+ } )
785+ } )
773786 } )
774787
775- it ( "shows fallback message for unhandled errors " , async ( ) => {
776- const mockErrorRef = { current : "unknown_error" }
777- jest . spyOn ( React , "useRef" ) . mockReturnValue ( mockErrorRef )
788+ it ( "sets an error and calls reject when handleShippingAddressChange fails " , async ( ) => {
789+ const mockReject = jest . fn ( )
790+ const mockResolve = jest . fn ( )
778791
779- const { mockResolveLastOperation } = renderWithRelay ( {
792+ const { mockRejectLastOperation } = renderWithRelay ( {
780793 Order : ( ) => ( { ...orderData } ) ,
781794 } )
782795
783- fireEvent . click ( screen . getByTestId ( "express-checkout-cancel" ) )
796+ const elementProps = mockExpressCheckoutElement . mock . calls [ 0 ] [ 0 ]
784797
785- // Resolve the mutations
786- await mockResolveLastOperation ( {
787- unsetOrderPaymentMethodPayload : ( ) => ( {
788- orderOrError : {
789- __typename : "OrderMutationSuccess" ,
790- order : orderData ,
791- } ,
792- } ) ,
798+ elementProps . onShippingAddressChange ( {
799+ address : {
800+ city : "New York" ,
801+ state : "NY" ,
802+ country : "US" ,
803+ postal_code : "10013" ,
804+ } ,
805+ name : "Buyer Name" ,
806+ resolve : mockResolve ,
807+ reject : mockReject ,
793808 } )
794809
795- await mockResolveLastOperation ( {
796- unsetOrderFulfillmentOptionPayload : ( ) => ( {
797- orderOrError : {
798- __typename : "OrderMutationSuccess" ,
799- order : orderData ,
800- } ,
810+ await flushPromiseQueue ( )
811+
812+ mockRejectLastOperation ( new Error ( "Network error" ) )
813+
814+ await flushPromiseQueue ( )
815+
816+ expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith ( {
817+ section : "EXPRESS_CHECKOUT" ,
818+ error : expect . objectContaining ( {
819+ title : "An error occurred" ,
820+ code : "shipping_address_update_error" ,
801821 } ) ,
802822 } )
823+ expect ( mockReject ) . toHaveBeenCalled ( )
824+ } )
825+
826+ it ( "sets an error and calls reject when handleShippingRateChange fails" , async ( ) => {
827+ const mockReject = jest . fn ( )
828+ const mockResolve = jest . fn ( )
829+
830+ const { mockRejectLastOperation } = renderWithRelay ( {
831+ Order : ( ) => ( { ...orderData } ) ,
832+ } )
833+
834+ const elementProps = mockExpressCheckoutElement . mock . calls [ 0 ] [ 0 ]
835+
836+ elementProps . onShippingRateChange ( {
837+ shippingRate : { id : "DOMESTIC_FLAT" , amount : 4200 } ,
838+ resolve : mockResolve ,
839+ reject : mockReject ,
840+ } )
803841
804842 await flushPromiseQueue ( )
805843
806- // Verify error was set for the express checkout section with fallback message
807- expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith (
808- expect . objectContaining ( {
809- section : "EXPRESS_CHECKOUT" ,
810- error : expect . objectContaining ( {
811- title : "An error occurred" ,
812- } ) ,
844+ mockRejectLastOperation ( new Error ( "Network error" ) )
845+
846+ await flushPromiseQueue ( )
847+
848+ expect ( mockSetSectionErrorMessage ) . toHaveBeenCalledWith ( {
849+ section : "EXPRESS_CHECKOUT" ,
850+ error : expect . objectContaining ( {
851+ title : "An error occurred" ,
852+ code : "shipping_rate_update_error" ,
813853 } ) ,
814- )
854+ } )
855+ expect ( mockReject ) . toHaveBeenCalled ( )
815856 } )
816857 } )
817858} )
0 commit comments