Skip to content

Commit 9d58dca

Browse files
committedMar 26, 2024
feat(payment): PI-1537 Refactor the existing bluesnapv2 payment strategy in Checkout-js
1 parent beda770 commit 9d58dca

File tree

7 files changed

+96
-61
lines changed

7 files changed

+96
-61
lines changed
 

‎.github/CODEOWNERS

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package-lock.json @bigcommerce/team-checkout @bigcommerce/team-integrations @big
2121
/packages/core/payment/paymentMethod/AffirmPaymentMethod.tsx @bigcommerce/team-integrations
2222
/packages/core/payment/paymentMethod/AmazonPaymentMethod.tsx @bigcommerce/team-integrations
2323
/packages/core/payment/paymentMethod/BarclayCardPaymentMethod.tsx @bigcommerce/team-integrations
24-
/packages/core/payment/paymentMethod/BlueSnapV2PaymentMethod.tsx @bigcommerce/team-integrations
2524
/packages/core/payment/paymentMethod/BoltClientPaymentMethod.tsx @bigcommerce/team-integrations
2625
/packages/core/payment/paymentMethod/BoltCustomForm.tsx @bigcommerce/team-integrations
2726
/packages/core/payment/paymentMethod/BoltCustomFormValues.ts @bigcommerce/team-integrations

‎packages/bluesnap-direct-integration/.eslintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
{
1111
"files": ["*.mock.ts"],
1212
"rules": {
13-
"@typescript-eslint/naming-convention": "off"
13+
"@typescript-eslint/naming-convention": "off",
14+
"@typescript-eslint/no-unsafe-assignment" : "off"
1415
}
1516
}
1617
]

‎packages/core/src/app/payment/paymentMethod/BlueSnapV2PaymentMethod.spec.tsx ‎packages/bluesnap-direct-integration/src/BlueSnapV2PaymentMethod.test.tsx

+61-44
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,73 @@ import {
22
CheckoutSelectors,
33
CheckoutService,
44
createCheckoutService,
5+
createLanguageService,
6+
PaymentInitializeOptions,
57
} from '@bigcommerce/checkout-sdk';
8+
import { act } from '@testing-library/react';
69
import { mount, ReactWrapper } from 'enzyme';
710
import { Formik } from 'formik';
811
import { noop } from 'lodash';
912
import React, { FunctionComponent } from 'react';
10-
import { act } from 'react-dom/test-utils';
1113

12-
import { createLocaleContext, LocaleContext, LocaleContextType } from '@bigcommerce/checkout/locale';
13-
import { CheckoutProvider } from '@bigcommerce/checkout/payment-integration-api';
14-
15-
import { getCart } from '../../cart/carts.mock';
16-
import { getStoreConfig } from '../../config/config.mock';
17-
import { getCustomer } from '../../customer/customers.mock';
18-
import { Modal, ModalProps } from '../../ui/modal';
19-
import { getPaymentMethod } from '../payment-methods.mock';
20-
import PaymentContext, { PaymentContextProps } from '../PaymentContext';
21-
22-
import BlueSnapV2PaymentMethod, { BlueSnapV2PaymentMethodProps } from './BlueSnapV2PaymentMethod';
23-
import HostedPaymentMethod from './HostedPaymentMethod';
24-
import PaymentMethodId from './PaymentMethodId';
14+
import {
15+
createLocaleContext,
16+
LocaleContext,
17+
LocaleContextType,
18+
} from '@bigcommerce/checkout/locale';
19+
import {
20+
CheckoutProvider,
21+
PaymentFormContext,
22+
PaymentFormService,
23+
PaymentMethodId,
24+
PaymentMethodProps,
25+
} from '@bigcommerce/checkout/payment-integration-api';
26+
import {
27+
getCart,
28+
getCustomer,
29+
getPaymentFormServiceMock,
30+
getPaymentMethod,
31+
getStoreConfig,
32+
} from '@bigcommerce/checkout/test-mocks';
33+
import { Modal } from '@bigcommerce/checkout/ui';
34+
import HostedPaymentMethodComponent from 'packages/hosted-payment-integration/src/HostedPaymentComponent';
35+
import { ModalProps } from 'packages/ui/src/modal';
36+
37+
import BlueSnapV2PaymentMethod from './BlueSnapV2PaymentMethod';
2538

2639
describe('when using BlueSnapV2 payment', () => {
27-
let defaultProps: BlueSnapV2PaymentMethodProps;
40+
let defaultProps: PaymentMethodProps;
2841
let checkoutService: CheckoutService;
2942
let checkoutState: CheckoutSelectors;
3043
let localeContext: LocaleContextType;
31-
let paymentContext: PaymentContextProps;
3244
let BlueSnapV2PaymentMethodTest: FunctionComponent;
45+
let paymentForm: PaymentFormService;
46+
let initializePayment: jest.SpyInstance<
47+
Promise<CheckoutSelectors>,
48+
[options: PaymentInitializeOptions]
49+
>;
3350

3451
beforeEach(() => {
52+
checkoutService = createCheckoutService();
53+
checkoutState = checkoutService.getState();
54+
localeContext = createLocaleContext(getStoreConfig());
55+
paymentForm = getPaymentFormServiceMock();
56+
initializePayment = jest
57+
.spyOn(checkoutService, 'initializePayment')
58+
.mockResolvedValue(checkoutState);
3559
defaultProps = {
36-
initializePayment: jest.fn(),
37-
deinitializePayment: jest.fn(),
60+
checkoutService,
61+
checkoutState,
62+
paymentForm: getPaymentFormServiceMock(),
63+
language: createLanguageService(),
64+
onUnhandledError: jest.fn(),
3865
method: {
3966
...getPaymentMethod(),
4067
id: 'mastercard',
4168
gateway: PaymentMethodId.BlueSnapV2,
4269
},
4370
};
44-
45-
checkoutService = createCheckoutService();
46-
checkoutState = checkoutService.getState();
47-
localeContext = createLocaleContext(getStoreConfig());
48-
49-
paymentContext = {
50-
disableSubmit: jest.fn(),
51-
setSubmit: jest.fn(),
52-
setValidationSchema: jest.fn(),
53-
hidePaymentSubmitButton: jest.fn(),
54-
};
71+
jest.spyOn(checkoutService, 'initializePayment').mockResolvedValue(checkoutState);
5572

5673
jest.spyOn(checkoutState.data, 'getCart').mockReturnValue(getCart());
5774

@@ -61,27 +78,27 @@ describe('when using BlueSnapV2 payment', () => {
6178

6279
BlueSnapV2PaymentMethodTest = (props) => (
6380
<CheckoutProvider checkoutService={checkoutService}>
64-
<PaymentContext.Provider value={paymentContext}>
81+
<PaymentFormContext.Provider value={{ paymentForm }}>
6582
<LocaleContext.Provider value={localeContext}>
6683
<Formik initialValues={{}} onSubmit={noop}>
6784
<BlueSnapV2PaymentMethod {...defaultProps} {...props} />
6885
</Formik>
6986
</LocaleContext.Provider>
70-
</PaymentContext.Provider>
87+
</PaymentFormContext.Provider>
7188
</CheckoutProvider>
7289
);
7390
});
7491

7592
it('renders as hosted payment method', () => {
7693
const container = mount(<BlueSnapV2PaymentMethodTest />);
7794

78-
expect(container.find(HostedPaymentMethod)).toHaveLength(1);
95+
expect(container.find(HostedPaymentMethodComponent)).toHaveLength(1);
7996
});
8097

8198
it('initializes method with required config', () => {
8299
mount(<BlueSnapV2PaymentMethodTest />);
83100

84-
expect(defaultProps.initializePayment).toHaveBeenCalledWith(
101+
expect(defaultProps.checkoutService.initializePayment).toHaveBeenCalledWith(
85102
expect.objectContaining({
86103
methodId: 'mastercard',
87104
gatewayId: 'bluesnapv2',
@@ -99,10 +116,10 @@ describe('when using BlueSnapV2 payment', () => {
99116

100117
it('renders modal that hosts bluesnap payment page', async () => {
101118
const component = mount(<BlueSnapV2PaymentMethodTest />);
102-
const initializeOptions = (defaultProps.initializePayment as jest.Mock).mock.calls[0][0];
119+
const initializeOptions = initializePayment.mock.calls[0][0];
103120

104121
act(() => {
105-
initializeOptions.bluesnapv2.onLoad(document.createElement('iframe'), jest.fn());
122+
initializeOptions.bluesnapv2?.onLoad(document.createElement('iframe'), jest.fn());
106123
});
107124

108125
await new Promise((resolve) => process.nextTick(resolve));
@@ -116,10 +133,10 @@ describe('when using BlueSnapV2 payment', () => {
116133

117134
it('renders modal and appends bluesnap payment page', async () => {
118135
const component = mount(<BlueSnapV2PaymentMethodTest />);
119-
const initializeOptions = (defaultProps.initializePayment as jest.Mock).mock.calls[0][0];
136+
const initializeOptions = initializePayment.mock.calls[0][0];
120137
const iframe = document.createElement('iframe');
121138

122-
act(() => initializeOptions.bluesnapv2.onLoad(iframe, jest.fn()));
139+
act(() => initializeOptions.bluesnapv2?.onLoad(iframe, jest.fn()));
123140

124141
await new Promise((resolve) => process.nextTick(resolve));
125142

@@ -136,10 +153,10 @@ describe('when using BlueSnapV2 payment', () => {
136153

137154
it('renders modal but does not append bluesnap payment page because is empty', async () => {
138155
const component = mount(<BlueSnapV2PaymentMethodTest />);
139-
const initializeOptions = (defaultProps.initializePayment as jest.Mock).mock.calls[0][0];
140-
156+
const initializeOptions = initializePayment.mock.calls[0][0];
157+
141158
act(() => {
142-
initializeOptions.bluesnapv2.onLoad(undefined, jest.fn());
159+
initializeOptions.bluesnapv2?.onLoad(undefined, jest.fn());
143160
});
144161

145162
await new Promise((resolve) => process.nextTick(resolve));
@@ -158,10 +175,10 @@ describe('when using BlueSnapV2 payment', () => {
158175
it('cancels payment flow if user chooses to close modal', async () => {
159176
const cancelBlueSnapV2Payment = jest.fn();
160177
const component = mount(<BlueSnapV2PaymentMethodTest />);
161-
const initializeOptions = (defaultProps.initializePayment as jest.Mock).mock.calls[0][0];
178+
const initializeOptions = initializePayment.mock.calls[0][0];
162179

163180
act(() => {
164-
initializeOptions.bluesnapv2.onLoad(
181+
initializeOptions.bluesnapv2?.onLoad(
165182
document.createElement('iframe'),
166183
cancelBlueSnapV2Payment,
167184
);
@@ -176,9 +193,9 @@ describe('when using BlueSnapV2 payment', () => {
176193
const modal: ReactWrapper<ModalProps> = component.find(Modal);
177194

178195
act(() => {
179-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
196+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument, @typescript-eslint/consistent-type-assertions
180197
modal.prop('onRequestClose')!(new MouseEvent('click') as any);
181-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
198+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-argument, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
182199
modal.prop('onRequestClose')!(new MouseEvent('click') as any);
183200
});
184201

‎packages/core/src/app/payment/paymentMethod/BlueSnapV2PaymentMethod.tsx ‎packages/bluesnap-direct-integration/src/BlueSnapV2PaymentMethod.tsx

+31-10
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ import React, {
88
useState,
99
} from 'react';
1010

11-
import { LoadingOverlay } from '../../ui/loading';
12-
import { Modal } from '../../ui/modal';
13-
14-
import HostedPaymentMethod, { HostedPaymentMethodProps } from './HostedPaymentMethod';
11+
import {
12+
HostedPaymentComponent,
13+
HostedPaymentMethodProps,
14+
} from '@bigcommerce/checkout/hosted-payment-integration';
15+
import {
16+
PaymentMethodProps,
17+
PaymentMethodResolveId,
18+
toResolvableComponent,
19+
} from '@bigcommerce/checkout/payment-integration-api';
20+
import { LoadingOverlay, Modal } from '@bigcommerce/checkout/ui';
1521

1622
export type BlueSnapV2PaymentMethodProps = HostedPaymentMethodProps;
1723

@@ -20,8 +26,11 @@ interface BlueSnapV2PaymentMethodRef {
2026
cancelBlueSnapV2Payment?(): void;
2127
}
2228

23-
const BlueSnapV2PaymentMethod: FunctionComponent<BlueSnapV2PaymentMethodProps> = ({
24-
initializePayment,
29+
const BlueSnapV2PaymentMethod: FunctionComponent<PaymentMethodProps> = ({
30+
checkoutService,
31+
checkoutState,
32+
method,
33+
paymentForm,
2534
...rest
2635
}) => {
2736
const [isLoadingIframe, setisLoadingIframe] = useState<boolean>(false);
@@ -41,7 +50,8 @@ const BlueSnapV2PaymentMethod: FunctionComponent<BlueSnapV2PaymentMethodProps> =
4150

4251
const initializeBlueSnapV2Payment = useCallback(
4352
(options: PaymentInitializeOptions) => {
44-
return initializePayment({
53+
54+
return checkoutService.initializePayment({
4555
...options,
4656
bluesnapv2: {
4757
onLoad(content: HTMLIFrameElement, cancel: () => void) {
@@ -57,7 +67,7 @@ const BlueSnapV2PaymentMethod: FunctionComponent<BlueSnapV2PaymentMethodProps> =
5767
},
5868
});
5969
},
60-
[initializePayment],
70+
[checkoutService],
6171
);
6272

6373
const appendPaymentPageContent = useCallback(() => {
@@ -71,7 +81,15 @@ const BlueSnapV2PaymentMethod: FunctionComponent<BlueSnapV2PaymentMethodProps> =
7181

7282
return (
7383
<>
74-
<HostedPaymentMethod {...rest} initializePayment={initializeBlueSnapV2Payment} />
84+
<HostedPaymentComponent
85+
{...rest}
86+
checkoutService={checkoutService}
87+
checkoutState={checkoutState}
88+
deinitializePayment={checkoutService.deinitializePayment}
89+
initializePayment={initializeBlueSnapV2Payment}
90+
method={method}
91+
paymentForm={paymentForm}
92+
/>
7593
<Modal
7694
additionalModalClassName="modal--bluesnap"
7795
isOpen={!!paymentPageContent}
@@ -87,4 +105,7 @@ const BlueSnapV2PaymentMethod: FunctionComponent<BlueSnapV2PaymentMethodProps> =
87105
);
88106
};
89107

90-
export default BlueSnapV2PaymentMethod;
108+
export default toResolvableComponent<PaymentMethodProps, PaymentMethodResolveId>(
109+
BlueSnapV2PaymentMethod,
110+
[{ gateway: 'bluesnapv2' }],
111+
);

‎packages/bluesnap-direct-integration/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { default as BlueSnapDirectEcpPaymentMethod } from './BlueSnapDirectEcpPa
22
export { default as BlueSnapDirectAlternativePaymentMethod } from './BlueSnapDirectAlternativePaymentMethod';
33
export { default as BlueSnapDirectSepaPaymentMethod } from './BlueSnapDirectSepaPaymentMethod';
44
export { default as BlueSnapDirectIdealPaymentMethod } from './BlueSnapDirectIdealPaymentMethod';
5+
export { default as BlueSnapV2PaymentMethod } from './BlueSnapV2PaymentMethod';

‎packages/core/src/app/payment/Payment.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ class Payment extends Component<
331331
selectedMethod.type === PaymentMethodProviderType.Hosted ||
332332
selectedMethod.type === PaymentMethodProviderType.PPSDK ||
333333
selectedMethod.gateway === PaymentMethodId.BlueSnapDirect ||
334+
selectedMethod.gateway === PaymentMethodId.BlueSnapV2 ||
334335
selectedMethod.id === PaymentMethodId.AmazonPay ||
335336
selectedMethod.id === PaymentMethodId.CBAMPGS ||
336337
selectedMethod.id === PaymentMethodId.Checkoutcom ||

‎packages/core/src/app/payment/paymentMethod/PaymentMethod.tsx

-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { withCheckout } from '../../checkout';
1414

1515
import AmazonPayV2PaymentMethod from './AmazonPayV2PaymentMethod';
1616
import BarclaycardPaymentMethod from './BarclaycardPaymentMethod';
17-
import BlueSnapV2PaymentMethod from './BlueSnapV2PaymentMethod';
1817
import BoltPaymentMethod from './BoltPaymentMethod';
1918
import BraintreeCreditCardPaymentMethod from './BraintreeCreditCardPaymentMethod';
2019
import CCAvenueMarsPaymentMethod from './CCAvenueMarsPaymentMethod';
@@ -95,10 +94,6 @@ const PaymentMethodComponent: FunctionComponent<
9594
return <AmazonPayV2PaymentMethod {...props} />;
9695
}
9796

98-
if (method.gateway === PaymentMethodId.BlueSnapV2) {
99-
return <BlueSnapV2PaymentMethod {...props} />;
100-
}
101-
10297
if (method.id === PaymentMethodId.DigitalRiver) {
10398
return <DigitalRiverPaymentMethod {...props} />;
10499
}

0 commit comments

Comments
 (0)
Please sign in to comment.