From 0d63fe81f52d70efe13d97f65b83bb9fd340981c Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Tue, 20 Oct 2026 11:05:20 -0300 Subject: [PATCH 1/2] chore: never show link payment option in sponsor checkout --- .../components/__tests__/payment-view.test.js | 20 ++++++++++++++++++- .../components/payment-view.js | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/payment-view.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/payment-view.test.js index 2eca4219f..bc34e2028 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/payment-view.test.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/payment-view.test.js @@ -15,6 +15,7 @@ import React from "react"; import { act, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import flushPromises from "flush-promises"; +import StripePayment from "openstack-uicore-foundation/lib/components/mui/stripe-payment"; import { renderWithRedux } from "../../../../../../../utils/test-utils"; import PaymentView from "../payment-view"; import { payWithInvoice } from "../../../../../../../actions/sponsor-cart-actions"; @@ -52,7 +53,7 @@ jest.mock( "openstack-uicore-foundation/lib/components/mui/stripe-payment", () => ({ __esModule: true, - default: () =>
+ default: jest.fn(() =>
) }) ); @@ -159,3 +160,20 @@ describe("PaymentView - Pay with invoice instead", () => { expect(history.push).not.toHaveBeenCalled(); }); }); + +describe("PaymentView - Stripe payment form", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("hides Link so the admin's own saved card is never offered", () => { + renderPaymentView(); + + expect(StripePayment).toHaveBeenCalledWith( + expect.objectContaining({ + paymentOptions: { wallets: { link: "never" } } + }), + expect.anything() + ); + }); +}); diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/payment-view.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/payment-view.js index 25593aa82..78905068b 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/payment-view.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/payment-view.js @@ -146,6 +146,8 @@ const PaymentView = ({ showBilling redirectUrl={redirectUrl} stripeFormTitle={false} + // the admin pays for the sponsor, so never offer the admin's own saved Link card + paymentOptions={{ wallets: { link: "never" } }} updatePaymentIntent={updatePaymentIntent} onPaymentSuccess={handlePaymentSuccess} onPaymentError={handlePaymentError} From c42961adf7a5e015953bf75f165fe8a62bba4ecd Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Tue, 20 Oct 2026 11:09:00 -0300 Subject: [PATCH 2/2] fix: bug on reprice --- .../__tests__/sponsor-cart-actions.test.js | 43 +++++++++++++++++-- src/actions/sponsor-cart-actions.js | 2 +- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/actions/__tests__/sponsor-cart-actions.test.js b/src/actions/__tests__/sponsor-cart-actions.test.js index 4962e359d..a066607a7 100644 --- a/src/actions/__tests__/sponsor-cart-actions.test.js +++ b/src/actions/__tests__/sponsor-cart-actions.test.js @@ -16,16 +16,18 @@ import thunk from "redux-thunk"; import flushPromises from "flush-promises"; import { getRequest, - postRequest + postRequest, + putRequest } from "openstack-uicore-foundation/lib/utils/actions"; -import { payWithInvoice } from "../sponsor-cart-actions"; +import { payWithInvoice, updatePaymentIntent } from "../sponsor-cart-actions"; import * as methods from "../../utils/methods"; jest.mock("openstack-uicore-foundation/lib/utils/actions", () => ({ __esModule: true, ...jest.requireActual("openstack-uicore-foundation/lib/utils/actions"), getRequest: jest.fn(), - postRequest: jest.fn() + postRequest: jest.fn(), + putRequest: jest.fn() })); describe("payWithInvoice", () => { @@ -81,3 +83,38 @@ describe("payWithInvoice", () => { expect(cartUrl).toContain("/sponsors/456/carts/current"); }); }); + +describe("updatePaymentIntent", () => { + const mockStore = configureStore([thunk]); + + beforeEach(() => { + jest.clearAllMocks(); + window.PURCHASES_API_URL = "https://purchases.example.com"; + jest.spyOn(methods, "getAccessTokenSafely").mockResolvedValue("TOKEN"); + }); + + afterEach(() => { + jest.restoreAllMocks(); + delete window.PURCHASES_API_URL; + }); + + it("resolves when the reprice fails, so a payment method change never leaks an unhandled rejection", async () => { + putRequest.mockImplementation( + () => () => () => Promise.reject(new Error("412")) + ); + const store = mockStore({ + currentSummitState: { currentSummit: { id: 1 } }, + currentSponsorState: { entity: { id: 123 } }, + sponsorPageCartListState: { cart: { id: 55 }, paymentIntent: { id: 230 } } + }); + + await expect( + store.dispatch(updatePaymentIntent("us_bank_account")) + ).resolves.toBeUndefined(); + const [, , url, payload] = putRequest.mock.calls[0]; + expect(url).toBe( + "https://purchases.example.com/api/v1/summits/1/sponsors/123/payments/230/reprice" + ); + expect(payload).toEqual({ payment_method: "us_bank_account", cart_id: 55 }); + }); +}); diff --git a/src/actions/sponsor-cart-actions.js b/src/actions/sponsor-cart-actions.js index a3482bb6d..5d49fdd12 100644 --- a/src/actions/sponsor-cart-actions.js +++ b/src/actions/sponsor-cart-actions.js @@ -643,7 +643,7 @@ export const updatePaymentIntent = `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsor.id}/payments/${paymentIntent?.id}/reprice`, payload, snackbarErrorHandler - )(params)(dispatch); + )(params)(dispatch).catch(() => {}); // error already shown by snackbarErrorHandler }; export const confirmPayment = () => async (dispatch, getState) => {