From eb154a7e35c11407eb05816ab0146c0a89c0ad7a Mon Sep 17 00:00:00 2001 From: Christian Weiss Date: Fri, 29 May 2026 16:13:08 -0400 Subject: [PATCH 1/2] Return event handler result from wrapper (#681) --- .../createElementComponent.test.tsx | 63 ++++++++++++++++++- src/utils/useAttachEvent.ts | 5 +- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/components/createElementComponent.test.tsx b/src/components/createElementComponent.test.tsx index da02a9d5..b4afca79 100644 --- a/src/components/createElementComponent.test.tsx +++ b/src/components/createElementComponent.test.tsx @@ -4,8 +4,10 @@ import {render, act, waitFor} from '@testing-library/react'; import * as ElementsModule from './Elements'; import * as CheckoutContextModule from '../checkout/components/CheckoutContext'; import {CheckoutElementsProvider} from '../checkout/components/CheckoutElementsProvider'; +import {CheckoutFormProvider} from '../checkout/components/CheckoutFormProvider'; import createElementComponent from './createElementComponent'; import * as mocks from '../../test/mocks'; +import makeDeferred from '../../test/makeDeferred'; import { CardElementComponent, PaymentElementComponent, @@ -21,7 +23,7 @@ import { } from '../types'; const {Elements} = ElementsModule; -const {useCheckout} = CheckoutContextModule; +const {useCheckout, useCheckoutForm} = CheckoutContextModule; describe('createElementComponent', () => { let mockStripe: any; @@ -517,6 +519,65 @@ describe('createElementComponent', () => { expect(mockHandler).not.toHaveBeenCalled(); }); + it('returns the Payment Form Element`s async confirm handler result', async () => { + const validation = makeDeferred(); + const mockActions = mocks.mockCheckoutActions(); + mockActions.confirm.mockResolvedValue({type: 'success'}); + mockCheckoutSdk.loadActions.mockResolvedValue({ + type: 'success', + actions: mockActions, + }); + mockStripe.initCheckoutFormSdk.mockReturnValue(mockCheckoutSdk); + + const CheckoutFormWithAsyncConfirm = () => { + const checkoutState = useCheckoutForm(); + const onConfirm = async (event: any) => { + if (checkoutState.type !== 'success') { + return undefined; + } + + await validation.promise; + return checkoutState.checkout.confirm({formConfirmEvent: event}); + }; + + return ; + }; + + render( + + + + ); + + await waitFor(() => + expect(mockCheckoutSdk.on).toHaveBeenCalledWith( + 'change', + expect.any(Function) + ) + ); + + const confirmHandler = simulateOn.mock.calls.find( + ([event]: any[]) => event === 'confirm' + )?.[1]; + expect(confirmHandler).toEqual(expect.any(Function)); + + const confirmEventMock = Symbol('confirm'); + const handlerResult = confirmHandler(confirmEventMock); + + expect(handlerResult).toHaveProperty('then', expect.any(Function)); + expect(mockActions.confirm).not.toHaveBeenCalled(); + + await validation.resolve(undefined); + await handlerResult; + + expect(mockActions.confirm).toHaveBeenCalledWith({ + formConfirmEvent: confirmEventMock, + }); + }); + it('propagates the Payment Form Element`s cancel event to the current onCancel prop', () => { const mockHandler = jest.fn(); const mockHandler2 = jest.fn(); diff --git a/src/utils/useAttachEvent.ts b/src/utils/useAttachEvent.ts index fbc4ca06..68726b37 100644 --- a/src/utils/useAttachEvent.ts +++ b/src/utils/useAttachEvent.ts @@ -20,10 +20,11 @@ export const useAttachEvent = ( return () => {}; } - const decoratedCb = (...args: A): void => { + const decoratedCb = (...args: A) => { if (cbRef.current) { - cbRef.current(...args); + return cbRef.current(...args); } + return undefined; }; (element as any).on(event, decoratedCb); From ff4f3630bdba54d796ee04e851a681e41d02be89 Mon Sep 17 00:00:00 2001 From: Tian Ji Liu Date: Fri, 29 May 2026 16:21:39 -0400 Subject: [PATCH 2/2] v6.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1617a9f6..200e5f84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stripe/react-stripe-js", - "version": "6.4.0", + "version": "6.5.0", "description": "React components for Stripe.js and Stripe Elements", "main": "dist/react-stripe.js", "module": "dist/react-stripe.esm.mjs",