Skip to content

Commit 476588f

Browse files
author
Luis Sanchez
committed
fix(payment): CHECKOUT-2926 Send Square payment data
1 parent 4265e37 commit 476588f

File tree

3 files changed

+86
-22
lines changed

3 files changed

+86
-22
lines changed

src/payment/create-payment-strategy-registry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export default function createPaymentStrategyRegistry(
154154
new SquarePaymentStrategy(
155155
store,
156156
orderActionCreator,
157+
paymentActionCreator,
157158
new SquareScriptLoader(scriptLoader)
158159
)
159160
);

src/payment/strategies/square/square-payment-strategy.spec.ts

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
/// <reference path="./square-form.d.ts" />
2-
32
import { createClient as createPaymentClient } from '@bigcommerce/bigpay-client';
43
import { createAction, Action } from '@bigcommerce/data-store';
54
import { createScriptLoader } from '@bigcommerce/script-loader';
65
import { Observable } from 'rxjs';
76

7+
import { PaymentActionCreator, PaymentRequestSender } from '../..';
88
import { createCheckoutClient, createCheckoutStore, CheckoutClient, CheckoutStore } from '../../../checkout';
9+
import { MissingDataError, TimeoutError } from '../../../common/error/errors';
910
import { OrderActionCreator } from '../../../order';
1011
import { SUBMIT_ORDER_REQUESTED } from '../../../order/order-action-types';
1112
import { getSquare } from '../../../payment/payment-methods.mock';
13+
import { SUBMIT_PAYMENT_REQUESTED } from '../../payment-action-types';
1214
import PaymentMethod from '../../payment-method';
1315

1416
import SquarePaymentStrategy from './square-payment-strategy';
1517
import SquareScriptLoader from './square-script-loader';
1618

19+
1720
describe('SquarePaymentStrategy', () => {
1821
let client: CheckoutClient;
1922
let scriptLoader: SquareScriptLoader;
2023
let store: CheckoutStore;
2124
let strategy: SquarePaymentStrategy;
2225
let orderActionCreator: OrderActionCreator;
26+
let paymentActionCreator: PaymentActionCreator;
2327
let paymentMethod: PaymentMethod;
2428
let callbacks: Square.FormCallbacks;
2529
let submitOrderAction: Observable<Action>;
30+
let submitPaymentAction: Observable<Action>;
2631

2732
const formFactory = options => {
2833
callbacks = options.callbacks;
@@ -39,13 +44,21 @@ describe('SquarePaymentStrategy', () => {
3944
store = createCheckoutStore();
4045
paymentMethod = getSquare();
4146
orderActionCreator = new OrderActionCreator(createCheckoutClient());
47+
paymentActionCreator = new PaymentActionCreator(
48+
new PaymentRequestSender(createPaymentClient()),
49+
orderActionCreator
50+
);
4251
scriptLoader = new SquareScriptLoader(createScriptLoader());
43-
strategy = new SquarePaymentStrategy(store, orderActionCreator, scriptLoader);
44-
submitOrderAction = Observable.of(createAction(SUBMIT_ORDER_REQUESTED);
52+
strategy = new SquarePaymentStrategy(store, orderActionCreator, paymentActionCreator, scriptLoader);
53+
submitOrderAction = Observable.of(createAction(SUBMIT_ORDER_REQUESTED));
54+
submitPaymentAction = Observable.of(createAction(SUBMIT_PAYMENT_REQUESTED));
4555

4656
jest.spyOn(orderActionCreator, 'submitOrder')
4757
.mockReturnValue(submitOrderAction);
4858

59+
jest.spyOn(paymentActionCreator, 'submitPayment')
60+
.mockReturnValue(submitPaymentAction);
61+
4962
jest.spyOn(store, 'dispatch');
5063
jest.spyOn(store, 'getState')
5164
.mockReturnValue({
@@ -119,9 +132,15 @@ describe('SquarePaymentStrategy', () => {
119132
});
120133

121134
describe('#execute()', () => {
135+
const payload = {
136+
payment: {
137+
name: 'foo',
138+
},
139+
};
140+
122141
describe('when form has not been initialized', () => {
123142
it('rejects the promise', () => {
124-
strategy.execute()
143+
strategy.execute(payload)
125144
.catch(e => expect(e.type).toEqual('not_initialized'));
126145

127146
expect(squareForm.requestCardNonce).toHaveBeenCalledTimes(0);
@@ -140,47 +159,64 @@ describe('SquarePaymentStrategy', () => {
140159
await strategy.initialize(initOptions);
141160
});
142161

162+
it('fails if payment name is not passed', () => {
163+
try {
164+
strategy.execute({});
165+
} catch (error) {
166+
expect(error).toBeInstanceOf(MissingDataError);
167+
expect(squareForm.requestCardNonce).toHaveBeenCalledTimes(0);
168+
}
169+
});
170+
143171
it('requests the nonce', () => {
144-
strategy.execute({});
172+
strategy.execute(payload);
145173
expect(squareForm.requestCardNonce).toHaveBeenCalledTimes(1);
146174
});
147175

148-
it('cancels the first request', async () => {
149-
strategy.execute({})
150-
.catch(e => expect(e.type).toEqual('timeout'));
176+
it('cancels the first request when a newer is made', async () => {
177+
strategy.execute(payload).catch(e => expect(e).toBeInstanceOf(TimeoutError));
151178

152179
setTimeout(() => {
153180
callbacks.cardNonceResponseReceived(null, 'nonce');
154181
}, 0);
155182

156-
await strategy.execute({});
183+
await strategy.execute(payload);
157184
});
158185

159186
describe('when the nonce is received', () => {
160187
let promise;
161188

162189
beforeEach(() => {
163-
promise = strategy.execute({ payment: '', x: 'y' }, { b: 'f' });
190+
promise = strategy.execute({ payment: { name: 'square' }, useStoreCredit: true, x: 'y' }, { b: 'f' });
164191
callbacks.cardNonceResponseReceived(null, 'nonce');
165192
});
166193

167194
it('places the order with the right arguments', () => {
168-
expect(orderActionCreator.submitOrder).toHaveBeenCalledWith({ x: 'y' }, true, { b: 'f' });
195+
expect(orderActionCreator.submitOrder).toHaveBeenCalledWith({ x: 'y', useStoreCredit: true }, true, { b: 'f' });
169196
expect(store.dispatch).toHaveBeenCalledWith(submitOrderAction);
170197
});
171198

172-
it('resolves to what is returned by submitOrder', async () => {
199+
it('resolves to what is returned by submitPayment', async () => {
173200
const value = await promise;
174201

175202
expect(value).toEqual(store.getState());
176203
});
204+
205+
it('submits the payment with the right arguments', () => {
206+
expect(paymentActionCreator.submitPayment).toHaveBeenCalledWith({
207+
name: 'square',
208+
paymentData: {
209+
nonce: 'nonce',
210+
},
211+
});
212+
});
177213
});
178214

179215
describe('when a failure happens receiving the nonce', () => {
180216
let promise;
181217

182218
beforeEach(() => {
183-
promise = strategy.execute({});
219+
promise = strategy.execute(payload);
184220
callbacks.cardNonceResponseReceived({}, 'nonce');
185221
});
186222

@@ -189,6 +225,10 @@ describe('SquarePaymentStrategy', () => {
189225
expect(store.dispatch).not.toHaveBeenCalledWith(submitOrderAction);
190226
});
191227

228+
it('does not submit payment', () => {
229+
expect(paymentActionCreator.submitPayment).toHaveBeenCalledTimes(0);
230+
});
231+
192232
it('rejects the promise', async () => {
193233
await promise.catch(error => expect(error).toBeTruthy());
194234
});

src/payment/strategies/square/square-payment-strategy.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
/// <reference path="./square-form.d.ts" />
2-
import { omit } from 'lodash';
3-
42
import { CheckoutSelectors, CheckoutStore } from '../../../checkout';
5-
import { InvalidArgumentError, NotInitializedError, StandardError, TimeoutError, UnsupportedBrowserError } from '../../../common/error/errors';
3+
import {
4+
InvalidArgumentError,
5+
MissingDataError,
6+
NotInitializedError,
7+
StandardError,
8+
TimeoutError,
9+
UnsupportedBrowserError,
10+
} from '../../../common/error/errors';
611
import { OrderActionCreator, OrderRequestBody } from '../../../order';
12+
import { TokenizedCreditCard } from '../../payment';
13+
import PaymentActionCreator from '../../payment-action-creator';
714
import PaymentMethod from '../../payment-method';
815
import PaymentStrategy from '../payment-strategy';
916

@@ -16,6 +23,7 @@ export default class SquarePaymentStrategy extends PaymentStrategy {
1623
constructor(
1724
store: CheckoutStore,
1825
private _orderActionCreator: OrderActionCreator,
26+
private _paymentActionCreator: PaymentActionCreator,
1927
private _scriptLoader: SquareScriptLoader
2028
) {
2129
super(store);
@@ -35,7 +43,15 @@ export default class SquarePaymentStrategy extends PaymentStrategy {
3543
}
3644

3745
execute(payload: OrderRequestBody, options?: any): Promise<CheckoutSelectors> {
38-
return new Promise((resolve, reject) => {
46+
const { payment, ...order } = payload;
47+
48+
if (!payment || !payment.name) {
49+
throw new MissingDataError('Unable to submit payment because "payload.payment.name" argument is not provided.');
50+
}
51+
52+
const paymentName = payment.name;
53+
54+
return new Promise<TokenizedCreditCard>((resolve, reject) => {
3955
if (!this._paymentForm) {
4056
throw new NotInitializedError('Unable to submit payment because the choosen payment method has not been initialized.');
4157
}
@@ -45,12 +61,19 @@ export default class SquarePaymentStrategy extends PaymentStrategy {
4561
}
4662

4763
this._deferredRequestNonce = { resolve, reject };
48-
4964
this._paymentForm.requestCardNonce();
5065
})
51-
.then(paymentData => this._store.dispatch(
52-
this._orderActionCreator.submitOrder(omit(payload, 'payment'), true, options)
53-
));
66+
.then(paymentData => {
67+
const paymentPayload = {
68+
name: paymentName,
69+
paymentData,
70+
};
71+
72+
return this._store.dispatch(this._orderActionCreator.submitOrder(order, true, options))
73+
.then(() =>
74+
this._store.dispatch(this._paymentActionCreator.submitPayment(paymentPayload))
75+
);
76+
});
5477
}
5578

5679
private _getFormOptions(options: InitializeOptions, deferred: DeferredPromise): Square.FormOptions {
@@ -102,7 +125,7 @@ export default class SquarePaymentStrategy extends PaymentStrategy {
102125
}
103126

104127
export interface DeferredPromise {
105-
resolve(resolution?: any): void;
128+
resolve(resolution?: TokenizedCreditCard): void;
106129
reject(reason?: any): void;
107130
}
108131

0 commit comments

Comments
 (0)