Skip to content

Commit cffc8be

Browse files
lord2800Jonathan Delefortrie
authored andcommitted
fix(checkout-button): PAYMENTS-3071 Use the specified endpoint for paypal payment creation
1 parent 55fd8e2 commit cffc8be

File tree

5 files changed

+88
-13
lines changed

5 files changed

+88
-13
lines changed

src/checkout-buttons/create-checkout-button-initializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default function createCheckoutButtonInitializer(
4343
return new CheckoutButtonInitializer(
4444
store,
4545
new CheckoutButtonStrategyActionCreator(
46-
createCheckoutButtonRegistry(store, requestSender, formPoster),
46+
createCheckoutButtonRegistry(store, requestSender, formPoster, host),
4747
new PaymentMethodActionCreator(new PaymentMethodRequestSender(requestSender))
4848
)
4949
);

src/checkout-buttons/create-checkout-button-registry.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import { PaypalButtonStrategy } from './strategies/paypal';
1919
export default function createCheckoutButtonRegistry(
2020
store: CheckoutStore,
2121
requestSender: RequestSender,
22-
formPoster: FormPoster
22+
formPoster: FormPoster,
23+
host?: string
2324
): Registry<CheckoutButtonStrategy, CheckoutButtonMethodType> {
2425
const registry = new Registry<CheckoutButtonStrategy, CheckoutButtonMethodType>();
2526
const scriptLoader = getScriptLoader();
@@ -87,8 +88,10 @@ export default function createCheckoutButtonRegistry(
8788
registry.register(CheckoutButtonMethodType.PAYPALEXPRESS, () =>
8889
new PaypalButtonStrategy(
8990
store,
91+
checkoutActionCreator,
9092
new PaypalScriptLoader(scriptLoader),
91-
formPoster
93+
formPoster,
94+
host
9295
)
9396
);
9497

src/checkout-buttons/strategies/paypal/paypal-button-strategy.spec.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import { createAction } from '@bigcommerce/data-store';
12
import { createFormPoster, FormPoster } from '@bigcommerce/form-poster';
3+
import { createRequestSender } from '@bigcommerce/request-sender';
24
import { getScriptLoader } from '@bigcommerce/script-loader';
35
import { EventEmitter } from 'events';
46
import { merge } from 'lodash';
7+
import { from } from 'rxjs';
58

6-
import { createCheckoutStore, CheckoutStore } from '../../../checkout';
7-
import { getCheckoutStoreState } from '../../../checkout/checkouts.mock';
9+
import { createCheckoutStore, CheckoutActionCreator, CheckoutActionType, CheckoutRequestSender, CheckoutStore } from '../../../checkout';
10+
import { getCheckout, getCheckoutStoreState } from '../../../checkout/checkouts.mock';
811
import { MissingDataError } from '../../../common/error/errors';
12+
import { ConfigActionCreator, ConfigRequestSender } from '../../../config';
913
import { getPaypalExpress } from '../../../payment/payment-methods.mock';
1014
import { PaypalActions, PaypalButtonOptions, PaypalScriptLoader, PaypalSDK } from '../../../payment/strategies/paypal';
1115
import { getPaypalMock } from '../../../payment/strategies/paypal/paypal.mock';
@@ -16,6 +20,8 @@ import { PaypalButtonInitializeOptions } from './paypal-button-options';
1620
import PaypalButtonStrategy from './paypal-button-strategy';
1721

1822
describe('PaypalButtonStrategy', () => {
23+
let actionsMock: PaypalActions;
24+
let checkoutActionCreator: CheckoutActionCreator;
1925
let eventEmitter: EventEmitter;
2026
let formPoster: FormPoster;
2127
let options: CheckoutButtonInitializeOptions;
@@ -24,10 +30,13 @@ describe('PaypalButtonStrategy', () => {
2430
let paypalScriptLoader: PaypalScriptLoader;
2531
let store: CheckoutStore;
2632
let strategy: PaypalButtonStrategy;
27-
let actionsMock: PaypalActions;
2833

2934
beforeEach(() => {
3035
store = createCheckoutStore(getCheckoutStoreState());
36+
checkoutActionCreator = new CheckoutActionCreator(
37+
new CheckoutRequestSender(createRequestSender()),
38+
new ConfigActionCreator(new ConfigRequestSender(createRequestSender()))
39+
);
3140
formPoster = createFormPoster();
3241
paypalScriptLoader = new PaypalScriptLoader(getScriptLoader());
3342

@@ -63,7 +72,11 @@ describe('PaypalButtonStrategy', () => {
6372
jest.spyOn(paypal.Button, 'render')
6473
.mockImplementation((options: PaypalButtonOptions) => {
6574
eventEmitter.on('payment', () => {
66-
options.payment().catch(() => {});
75+
options.payment({
76+
payerId: 'PAYER_ID',
77+
paymentID: 'PAYMENT_ID',
78+
payerID: 'PAYER_ID',
79+
}, actionsMock).catch(() => {});
6780
});
6881

6982
eventEmitter.on('authorize', () => {
@@ -75,6 +88,12 @@ describe('PaypalButtonStrategy', () => {
7588
});
7689
});
7790

91+
jest.spyOn(checkoutActionCreator, 'loadDefaultCheckout')
92+
.mockReturnValue(() => from([
93+
createAction(CheckoutActionType.LoadCheckoutRequested),
94+
createAction(CheckoutActionType.LoadCheckoutSucceeded, getCheckout()),
95+
]));
96+
7897
jest.spyOn(paypalScriptLoader, 'loadPaypal')
7998
.mockReturnValue(Promise.resolve(paypal));
8099

@@ -83,6 +102,7 @@ describe('PaypalButtonStrategy', () => {
83102

84103
strategy = new PaypalButtonStrategy(
85104
store,
105+
checkoutActionCreator,
86106
paypalScriptLoader,
87107
formPoster
88108
);
@@ -93,6 +113,7 @@ describe('PaypalButtonStrategy', () => {
93113
store = createCheckoutStore();
94114
strategy = new PaypalButtonStrategy(
95115
store,
116+
checkoutActionCreator,
96117
paypalScriptLoader,
97118
formPoster
98119
);
@@ -193,6 +214,7 @@ describe('PaypalButtonStrategy', () => {
193214

194215
strategy = new PaypalButtonStrategy(
195216
store,
217+
checkoutActionCreator,
196218
paypalScriptLoader,
197219
formPoster
198220
);
@@ -251,4 +273,42 @@ describe('PaypalButtonStrategy', () => {
251273
}, 'checkout-button');
252274
});
253275
});
276+
277+
it('sends create payment requests to the relative url by default', async () => {
278+
await strategy.initialize(options);
279+
280+
eventEmitter.emit('payment');
281+
282+
await new Promise(resolve => process.nextTick(resolve));
283+
284+
const expectedBody = { cartId: 'b20deef40f9699e48671bbc3fef6ca44dc80e3c7', merchantId: 'h3hxn44tdd8wxkzd' };
285+
286+
expect(actionsMock.request.post)
287+
.toHaveBeenCalledWith('/api/storefront/payment/paypalexpress', expectedBody, expect.any(Object));
288+
});
289+
290+
describe('with a supplied host', () => {
291+
beforeEach(() => {
292+
strategy = new PaypalButtonStrategy(
293+
store,
294+
checkoutActionCreator,
295+
paypalScriptLoader,
296+
formPoster,
297+
'https://example.com'
298+
);
299+
});
300+
301+
it('sends create payment requests to the supplied host', async () => {
302+
await strategy.initialize(options);
303+
304+
eventEmitter.emit('payment');
305+
306+
await new Promise(resolve => process.nextTick(resolve));
307+
308+
const expectedBody = { cartId: 'b20deef40f9699e48671bbc3fef6ca44dc80e3c7', merchantId: 'h3hxn44tdd8wxkzd' };
309+
310+
expect(actionsMock.request.post)
311+
.toHaveBeenCalledWith('https://example.com/api/storefront/payment/paypalexpress', expectedBody, expect.any(Object));
312+
});
313+
});
254314
});

src/checkout-buttons/strategies/paypal/paypal-button-strategy.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import { FormPoster } from '@bigcommerce/form-poster';
22
import { pick } from 'lodash';
33

4-
import { CheckoutStore } from '../../../checkout';
4+
import { CheckoutActionCreator, CheckoutStore } from '../../../checkout';
55
import { InvalidArgumentError, MissingDataError, MissingDataErrorType, NotInitializedError, NotInitializedErrorType, StandardError } from '../../../common/error/errors';
6+
import { INTERNAL_USE_ONLY } from '../../../common/http-request';
67
import { PaymentMethod } from '../../../payment';
7-
import { PaypalScriptLoader } from '../../../payment/strategies/paypal';
88
import { PaypalActions, PaypalAuthorizeData, PaypalClientToken } from '../../../payment/strategies/paypal';
9+
import { PaypalScriptLoader } from '../../../payment/strategies/paypal';
910
import { CheckoutButtonInitializeOptions } from '../../checkout-button-options';
10-
1111
import CheckoutButtonStrategy from '../checkout-button-strategy';
1212

1313
export default class PaypalButtonStrategy implements CheckoutButtonStrategy {
1414
private _paymentMethod?: PaymentMethod;
1515

1616
constructor(
1717
private _store: CheckoutStore,
18+
private _checkoutActionCreator: CheckoutActionCreator,
1819
private _paypalScriptLoader: PaypalScriptLoader,
19-
private _formPoster: FormPoster
20+
private _formPoster: FormPoster,
21+
private _host: string = ''
2022
) {}
2123

2224
initialize(options: CheckoutButtonInitializeOptions): Promise<void> {
@@ -76,7 +78,17 @@ export default class PaypalButtonStrategy implements CheckoutButtonStrategy {
7678
throw new NotInitializedError(NotInitializedErrorType.CheckoutButtonNotInitialized);
7779
}
7880

79-
return actions.request.post('/api/storefront/paypal-payment/', { merchantId })
81+
return this._store.dispatch(this._checkoutActionCreator.loadDefaultCheckout())
82+
.then(state => {
83+
const cart = state.cart.getCart();
84+
const cartId = cart ? cart.id : '';
85+
86+
return actions.request.post(`${this._host}/api/storefront/payment/paypalexpress`, { merchantId, cartId }, {
87+
headers: {
88+
'X-API-INTERNAL': INTERNAL_USE_ONLY,
89+
},
90+
});
91+
})
8092
.then(res => res.id)
8193
.catch(error => {
8294
if (onError) {

src/payment/strategies/paypal/paypal-sdk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export interface PaypalPaymentActions {
5353
}
5454

5555
export interface PaypalRequestActions {
56-
post(url: string, payload?: object): Promise<{ id: string }>;
56+
post(url: string, payload?: object, options?: object): Promise<{ id: string }>;
5757
}
5858

5959
export interface PaypalTransaction {

0 commit comments

Comments
 (0)