@paypal/checkout-components 5.0.316 → 5.0.317
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/button.js +1 -1
- package/dist/test/button.js +1 -1
- package/package.json +1 -1
- package/src/hosted-buttons/index.js +30 -30
- package/src/hosted-buttons/index.test.js +127 -86
- package/src/hosted-buttons/types.js +72 -27
- package/src/hosted-buttons/utils.js +160 -41
- package/src/hosted-buttons/utils.test.js +249 -33
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { request, memoize } from "@krakenjs/belter/src";
|
|
4
4
|
import {
|
|
5
|
+
getLogger,
|
|
5
6
|
buildDPoPHeaders,
|
|
6
7
|
getSDKHost,
|
|
7
8
|
getClientID,
|
|
8
9
|
getMerchantID as getSDKMerchantID,
|
|
9
10
|
} from "@paypal/sdk-client/src";
|
|
10
11
|
import { FUNDING } from "@paypal/sdk-constants/src";
|
|
12
|
+
import { SUPPORTED_FUNDING_SOURCES } from "@paypal/funding-components/src";
|
|
13
|
+
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
14
|
+
|
|
15
|
+
import { getButtonsComponent, type ButtonsComponent } from "../zoid/buttons";
|
|
11
16
|
|
|
12
17
|
import type {
|
|
13
18
|
ButtonVariables,
|
|
@@ -19,9 +24,15 @@ import type {
|
|
|
19
24
|
RenderForm,
|
|
20
25
|
GetFlexDirectionArgs,
|
|
21
26
|
GetFlexDirection,
|
|
22
|
-
BuildButtonContainerArgs,
|
|
23
27
|
Color,
|
|
24
28
|
FundingSources,
|
|
29
|
+
ApplyButtonStylesProps,
|
|
30
|
+
HostedButtonPreferences,
|
|
31
|
+
NcpResponsePreferences,
|
|
32
|
+
ButtonPreferences,
|
|
33
|
+
GetButtonsProps,
|
|
34
|
+
RenderStandaloneButtonProps,
|
|
35
|
+
RenderDefaultButtonProps,
|
|
25
36
|
} from "./types";
|
|
26
37
|
|
|
27
38
|
const entryPoint = "SDK";
|
|
@@ -41,6 +52,7 @@ export const getMerchantID = (): string | void => {
|
|
|
41
52
|
// https://developer.paypal.com/docs/multiparty/checkout/multiseller-payments/
|
|
42
53
|
const merchantIds = getSDKMerchantID();
|
|
43
54
|
if (merchantIds.length > 1) {
|
|
55
|
+
getLogger().error("ncps_multiple_merchant_ids", { merchantIds });
|
|
44
56
|
throw new Error("Multiple merchant-ids are not supported.");
|
|
45
57
|
}
|
|
46
58
|
return merchantIds[0];
|
|
@@ -77,6 +89,41 @@ export const createAccessToken: CreateAccessToken = memoize<CreateAccessToken>(
|
|
|
77
89
|
}
|
|
78
90
|
);
|
|
79
91
|
|
|
92
|
+
export const getButtonPreferences = ({
|
|
93
|
+
button_preferences: buttonPreferences,
|
|
94
|
+
eligible_funding_methods: eligibleFundingMethods,
|
|
95
|
+
}: NcpResponsePreferences): HostedButtonPreferences => {
|
|
96
|
+
if (!buttonPreferences?.length || !eligibleFundingMethods?.length) {
|
|
97
|
+
const preferences = {
|
|
98
|
+
buttonPreferences,
|
|
99
|
+
eligibleFundingMethods,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
getLogger().error("ncps_missing_preferences", { preferences });
|
|
103
|
+
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Expected preferences to be populated, received: ${JSON.stringify({
|
|
106
|
+
preferences,
|
|
107
|
+
})}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
// Remove any buttons that are not included in eligibleFundingMethods.
|
|
113
|
+
// If the funding method is "default", we want to keep it in the preferences, and decide which
|
|
114
|
+
// button should be rendered in its place in renderStandaloneButton()
|
|
115
|
+
buttonPreferences: buttonPreferences.filter(
|
|
116
|
+
(fundingMethod) =>
|
|
117
|
+
eligibleFundingMethods.includes(fundingMethod) ||
|
|
118
|
+
fundingMethod === "default"
|
|
119
|
+
),
|
|
120
|
+
// Sort the eligible funding methods returned from /ncp/api/form-fields in the order that they would appear in the smart stack.
|
|
121
|
+
eligibleFundingMethods: SUPPORTED_FUNDING_SOURCES.filter((fundingMethod) =>
|
|
122
|
+
eligibleFundingMethods.includes(fundingMethod)
|
|
123
|
+
),
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
|
|
80
127
|
const getButtonVariable = (variables: ButtonVariables, key: string): string =>
|
|
81
128
|
variables?.find((variable) => variable.name === key)?.value ?? "";
|
|
82
129
|
|
|
@@ -90,7 +137,13 @@ export const getHostedButtonDetails: HostedButtonDetailsParams = async ({
|
|
|
90
137
|
|
|
91
138
|
// $FlowIssue request returns ZalgoPromise
|
|
92
139
|
const { body } = response;
|
|
93
|
-
const {
|
|
140
|
+
const {
|
|
141
|
+
link_variables: variables,
|
|
142
|
+
js_sdk_container_id: buttonContainerId,
|
|
143
|
+
preferences,
|
|
144
|
+
} = body.button_details;
|
|
145
|
+
|
|
146
|
+
const shouldIncludePreferences = preferences && body.version === "2";
|
|
94
147
|
|
|
95
148
|
return {
|
|
96
149
|
style: {
|
|
@@ -102,14 +155,11 @@ export const getHostedButtonDetails: HostedButtonDetailsParams = async ({
|
|
|
102
155
|
height: parseInt(getButtonVariable(variables, "height"), 10) || undefined,
|
|
103
156
|
},
|
|
104
157
|
version: body.version,
|
|
105
|
-
buttonContainerId:
|
|
158
|
+
buttonContainerId: buttonContainerId || "spb-container",
|
|
106
159
|
html: body.html,
|
|
107
160
|
htmlScript: body.html_script,
|
|
108
|
-
...(
|
|
109
|
-
preferences:
|
|
110
|
-
buttonPreferences: preferences.button_preferences,
|
|
111
|
-
eligibleFundingMethods: preferences.eligible_funding_methods,
|
|
112
|
-
},
|
|
161
|
+
...(shouldIncludePreferences && {
|
|
162
|
+
preferences: getButtonPreferences(preferences),
|
|
113
163
|
}),
|
|
114
164
|
};
|
|
115
165
|
};
|
|
@@ -250,16 +300,16 @@ export const buildHostedButtonOnApprove = ({
|
|
|
250
300
|
};
|
|
251
301
|
};
|
|
252
302
|
|
|
253
|
-
export
|
|
303
|
+
export const getFlexDirection = ({
|
|
254
304
|
layout,
|
|
255
|
-
}: GetFlexDirectionArgs): GetFlexDirection {
|
|
256
|
-
|
|
257
|
-
}
|
|
305
|
+
}: GetFlexDirectionArgs): GetFlexDirection => ({
|
|
306
|
+
flexDirection: layout === "horizontal" ? "row" : "column",
|
|
307
|
+
});
|
|
258
308
|
|
|
259
|
-
export
|
|
309
|
+
export const getButtonColor = (
|
|
260
310
|
color: Color,
|
|
261
311
|
fundingSource: FundingSources
|
|
262
|
-
): Color {
|
|
312
|
+
): Color => {
|
|
263
313
|
const colorMap = {
|
|
264
314
|
gold: {
|
|
265
315
|
paypal: "gold",
|
|
@@ -289,41 +339,110 @@ export function getButtonColor(
|
|
|
289
339
|
};
|
|
290
340
|
|
|
291
341
|
return colorMap[color][fundingSource];
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
export function shouldRenderSDKButtons(
|
|
295
|
-
fundingSources: $ReadOnlyArray<FundingSources>
|
|
296
|
-
): boolean {
|
|
297
|
-
return Boolean(fundingSources.length);
|
|
298
|
-
}
|
|
342
|
+
};
|
|
299
343
|
|
|
300
|
-
export
|
|
344
|
+
export const applyContainerStyles = ({
|
|
301
345
|
flexDirection,
|
|
302
|
-
|
|
303
|
-
}:
|
|
304
|
-
const
|
|
346
|
+
buttonContainerId,
|
|
347
|
+
}: ApplyButtonStylesProps): void => {
|
|
348
|
+
const buttonContainer = document.querySelector(`#${buttonContainerId}`);
|
|
305
349
|
|
|
306
|
-
if (!
|
|
307
|
-
|
|
350
|
+
if (!buttonContainer) {
|
|
351
|
+
getLogger().error("ncps_button_container_missing", {
|
|
352
|
+
buttonContainerId,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
throw new Error(`Element with id ${buttonContainerId} not found.`);
|
|
308
356
|
}
|
|
309
357
|
|
|
310
|
-
|
|
358
|
+
buttonContainer.style.flexDirection = flexDirection;
|
|
359
|
+
};
|
|
311
360
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
361
|
+
/**
|
|
362
|
+
* Filters out all eligible funding methods that are already specified in button preferences
|
|
363
|
+
*/
|
|
364
|
+
export const getDefaultButtonOptions = ({
|
|
365
|
+
buttonPreferences,
|
|
366
|
+
eligibleFundingMethods,
|
|
367
|
+
}: HostedButtonPreferences): ButtonPreferences => {
|
|
368
|
+
return eligibleFundingMethods.filter(
|
|
369
|
+
(fundingSource: string) => !buttonPreferences.includes(fundingSource)
|
|
315
370
|
);
|
|
371
|
+
};
|
|
316
372
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Gets buttons component instance.
|
|
375
|
+
*/
|
|
376
|
+
export const getButtons = ({
|
|
377
|
+
fundingSource,
|
|
378
|
+
buttonOptions,
|
|
379
|
+
}: GetButtonsProps): ButtonsComponent => {
|
|
380
|
+
const Buttons = getButtonsComponent();
|
|
320
381
|
|
|
321
|
-
const
|
|
322
|
-
secondaryButton.setAttribute("id", `ncp-secondary-button`);
|
|
323
|
-
secondaryButton.setAttribute("style", "flex-grow: 1");
|
|
382
|
+
const { style } = buttonOptions;
|
|
324
383
|
|
|
325
|
-
|
|
326
|
-
|
|
384
|
+
// $FlowFixMe
|
|
385
|
+
return Buttons({
|
|
386
|
+
...buttonOptions,
|
|
387
|
+
fundingSource,
|
|
388
|
+
style: {
|
|
389
|
+
...style,
|
|
390
|
+
// $FlowFixMe
|
|
391
|
+
color: getButtonColor(style.color, fundingSource),
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
};
|
|
327
395
|
|
|
328
|
-
|
|
329
|
-
|
|
396
|
+
/**
|
|
397
|
+
* Handles logic for each specified button preference.
|
|
398
|
+
*/
|
|
399
|
+
export const renderStandaloneButton = ({
|
|
400
|
+
fundingSource,
|
|
401
|
+
buttonContainerId,
|
|
402
|
+
buttonOptions,
|
|
403
|
+
}: RenderStandaloneButtonProps): ZalgoPromise<void> | void => {
|
|
404
|
+
const standaloneButton = getButtons({
|
|
405
|
+
fundingSource,
|
|
406
|
+
buttonOptions,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// $FlowFixMe
|
|
410
|
+
if (standaloneButton.isEligible()) {
|
|
411
|
+
// $FlowFixMe
|
|
412
|
+
return standaloneButton.render(`#${buttonContainerId}`);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
getLogger().error(`ncps_standalone_${fundingSource}_ineligible`);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Handles logic for "default" button preference.
|
|
420
|
+
*/
|
|
421
|
+
export const renderDefaultButton = ({
|
|
422
|
+
eligibleDefaultButtons,
|
|
423
|
+
buttonContainerId,
|
|
424
|
+
buttonOptions,
|
|
425
|
+
}: RenderDefaultButtonProps): void => {
|
|
426
|
+
const eligibleButtons = [...eligibleDefaultButtons];
|
|
427
|
+
|
|
428
|
+
// If we exhaust all default options, we don't render any button.
|
|
429
|
+
while (eligibleButtons.length) {
|
|
430
|
+
const fundingSource = eligibleButtons[0];
|
|
431
|
+
|
|
432
|
+
const standaloneButton = getButtons({
|
|
433
|
+
fundingSource,
|
|
434
|
+
buttonOptions,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// If the funding source is eligible, render button & return to end loop.
|
|
438
|
+
// $FlowFixMe
|
|
439
|
+
if (standaloneButton.isEligible()) {
|
|
440
|
+
// $FlowFixMe
|
|
441
|
+
return standaloneButton.render(`#${buttonContainerId}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// If funding source is ineligible, log error and move to next funding option.
|
|
445
|
+
getLogger().error(`ncps_standalone_${fundingSource}_ineligible`);
|
|
446
|
+
eligibleButtons.shift();
|
|
447
|
+
}
|
|
448
|
+
};
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
/* eslint-disable no-restricted-globals, promise/no-native */
|
|
3
3
|
import { test, expect, vi } from "vitest";
|
|
4
4
|
import { request } from "@krakenjs/belter/src";
|
|
5
|
+
import { getLogger } from "@paypal/sdk-client/src";
|
|
6
|
+
|
|
7
|
+
import { getButtonsComponent } from "../zoid/buttons";
|
|
5
8
|
|
|
6
9
|
import {
|
|
7
10
|
buildHostedButtonCreateOrder,
|
|
@@ -10,9 +13,11 @@ import {
|
|
|
10
13
|
getHostedButtonDetails,
|
|
11
14
|
getFlexDirection,
|
|
12
15
|
getButtonColor,
|
|
13
|
-
shouldRenderSDKButtons,
|
|
14
|
-
appendButtonContainer,
|
|
15
16
|
getElementFromSelector,
|
|
17
|
+
getButtonPreferences,
|
|
18
|
+
renderStandaloneButton,
|
|
19
|
+
applyContainerStyles,
|
|
20
|
+
renderDefaultButton,
|
|
16
21
|
} from "./utils";
|
|
17
22
|
|
|
18
23
|
vi.mock("@krakenjs/belter/src", async () => {
|
|
@@ -28,6 +33,16 @@ vi.mock("@paypal/sdk-client/src", async () => {
|
|
|
28
33
|
getSDKHost: () => "example.com",
|
|
29
34
|
getClientID: () => "client_id_123",
|
|
30
35
|
getMerchantID: () => ["merchant_id_123"],
|
|
36
|
+
getLogger: vi.fn(() => ({
|
|
37
|
+
error: vi.fn(),
|
|
38
|
+
})),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
vi.mock("../zoid/buttons", async () => {
|
|
43
|
+
return {
|
|
44
|
+
...(await vi.importActual("../zoid/buttons")),
|
|
45
|
+
getButtonsComponent: vi.fn(),
|
|
31
46
|
};
|
|
32
47
|
});
|
|
33
48
|
|
|
@@ -97,6 +112,7 @@ describe("getHostedButtonDetails", () => {
|
|
|
97
112
|
button_preferences: ["paypal", "paylater"],
|
|
98
113
|
eligible_funding_methods: ["paypal", "venmo", "paylater"],
|
|
99
114
|
},
|
|
115
|
+
js_sdk_container_id: "spb-container",
|
|
100
116
|
},
|
|
101
117
|
version: "2",
|
|
102
118
|
},
|
|
@@ -556,38 +572,8 @@ test("getButtonColor", () => {
|
|
|
556
572
|
});
|
|
557
573
|
});
|
|
558
574
|
|
|
559
|
-
test("shouldRenderSDKButtons", () => {
|
|
560
|
-
expect(shouldRenderSDKButtons([])).toBe(false);
|
|
561
|
-
expect(shouldRenderSDKButtons(["paypal"])).toBe(true);
|
|
562
|
-
expect(shouldRenderSDKButtons(["paypal", "venmo"])).toBe(true);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
test("buildButtonContainer", () => {
|
|
566
|
-
const containerId = "#container-id";
|
|
567
|
-
const selector = document.createElement("div");
|
|
568
|
-
|
|
569
|
-
selector.setAttribute("id", containerId.slice(1));
|
|
570
|
-
|
|
571
|
-
vi.spyOn(document, "querySelector").mockReturnValueOnce(selector);
|
|
572
|
-
|
|
573
|
-
expect(() =>
|
|
574
|
-
appendButtonContainer({ flexDirection: "row", selector: containerId })
|
|
575
|
-
).not.toThrow();
|
|
576
|
-
|
|
577
|
-
expect(() =>
|
|
578
|
-
appendButtonContainer({ flexDirection: "row", selector })
|
|
579
|
-
).not.toThrow();
|
|
580
|
-
|
|
581
|
-
expect(() =>
|
|
582
|
-
appendButtonContainer({
|
|
583
|
-
flexDirection: "row",
|
|
584
|
-
selector: `${containerId}-not-found`,
|
|
585
|
-
})
|
|
586
|
-
).toThrow("PayPal button container selector was not found");
|
|
587
|
-
});
|
|
588
|
-
|
|
589
575
|
test("getElementFromSelector", () => {
|
|
590
|
-
const containerId = "
|
|
576
|
+
const containerId = "container-id";
|
|
591
577
|
const selector = document.createElement("div");
|
|
592
578
|
|
|
593
579
|
selector.setAttribute("id", containerId.slice(1));
|
|
@@ -602,4 +588,234 @@ test("getElementFromSelector", () => {
|
|
|
602
588
|
expect(mockQuerySelector).toHaveBeenCalledWith(containerId);
|
|
603
589
|
});
|
|
604
590
|
|
|
591
|
+
describe("getButtonPreferences", () => {
|
|
592
|
+
test("returns all button preferences if all are eligible", () => {
|
|
593
|
+
const params = {
|
|
594
|
+
button_preferences: ["paypal", "venmo"],
|
|
595
|
+
eligible_funding_methods: ["paypal", "venmo", "paylater"],
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const preferences = getButtonPreferences(params);
|
|
599
|
+
|
|
600
|
+
expect(preferences.buttonPreferences).toEqual(["paypal", "venmo"]);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
test("removes any button preferences not in the eligible funding methods", () => {
|
|
604
|
+
const params = {
|
|
605
|
+
button_preferences: ["paypal", "venmo"],
|
|
606
|
+
eligible_funding_methods: ["paypal", "paylater"],
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
const preferences = getButtonPreferences(params);
|
|
610
|
+
|
|
611
|
+
expect(preferences.buttonPreferences).toEqual(["paypal"]);
|
|
612
|
+
});
|
|
613
|
+
test("sorts eligible funding methods according to SUPPORTED_FUNDING_SOURCES", () => {
|
|
614
|
+
const params = {
|
|
615
|
+
button_preferences: ["paypal", "venmo"],
|
|
616
|
+
eligible_funding_methods: ["paylater", "venmo", "paypal"],
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
const preferences = getButtonPreferences(params);
|
|
620
|
+
|
|
621
|
+
expect(preferences.eligibleFundingMethods).toEqual([
|
|
622
|
+
"paypal",
|
|
623
|
+
"venmo",
|
|
624
|
+
"paylater",
|
|
625
|
+
]);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("doesn't filter out 'default' in button preferences", () => {
|
|
629
|
+
const params = {
|
|
630
|
+
button_preferences: ["paypal", "default"],
|
|
631
|
+
eligible_funding_methods: ["paylater", "venmo", "paypal"],
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
const preferences = getButtonPreferences(params);
|
|
635
|
+
|
|
636
|
+
expect(preferences.buttonPreferences).toEqual(["paypal", "default"]);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test("logs & throws error if the input is bad", () => {
|
|
640
|
+
const errorMock = vi.fn();
|
|
641
|
+
|
|
642
|
+
// $FlowIssue
|
|
643
|
+
getLogger.mockImplementation(() => ({ error: errorMock }));
|
|
644
|
+
|
|
645
|
+
const params = {
|
|
646
|
+
button_preferences: [],
|
|
647
|
+
eligible_funding_methods: [],
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
const shouldThrowError = () => getButtonPreferences(params);
|
|
651
|
+
|
|
652
|
+
expect(shouldThrowError).toThrowError();
|
|
653
|
+
expect(errorMock).toBeCalledTimes(1);
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
describe("applyContainerStyles", () => {
|
|
658
|
+
const buttonContainerId = "button-container";
|
|
659
|
+
const params = { flexDirection: "vertical", buttonContainerId };
|
|
660
|
+
|
|
661
|
+
test("successfully applies styles to container", () => {
|
|
662
|
+
const buttonContainer = document.createElement("div");
|
|
663
|
+
buttonContainer.id = buttonContainerId;
|
|
664
|
+
vi.spyOn(document, "querySelector").mockReturnValueOnce(buttonContainer);
|
|
665
|
+
|
|
666
|
+
applyContainerStyles(params);
|
|
667
|
+
|
|
668
|
+
expect(buttonContainer?.style.length).toBeTruthy();
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
test("throws error if button container cannot be found", () => {
|
|
672
|
+
// Intentionally not setting up the button container to throw the error
|
|
673
|
+
const shouldThrowError = () => applyContainerStyles(params);
|
|
674
|
+
expect(shouldThrowError).toThrowError(
|
|
675
|
+
`Element with id ${buttonContainerId} not found.`
|
|
676
|
+
);
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
describe("render buttons", () => {
|
|
681
|
+
const containerId = "container-id";
|
|
682
|
+
const expectedContainerId = `#${containerId}`;
|
|
683
|
+
const renderMock = vi.fn();
|
|
684
|
+
const errorMock = vi.fn();
|
|
685
|
+
const baseParams = {
|
|
686
|
+
buttonContainerId: containerId,
|
|
687
|
+
buttonOptions: {
|
|
688
|
+
createOrder: vi.fn(),
|
|
689
|
+
onApprove: vi.fn(),
|
|
690
|
+
onClick: vi.fn(),
|
|
691
|
+
onInit: vi.fn(),
|
|
692
|
+
style: {
|
|
693
|
+
color: "gold",
|
|
694
|
+
layout: "",
|
|
695
|
+
shape: "",
|
|
696
|
+
height: 40,
|
|
697
|
+
label: "",
|
|
698
|
+
tagline: true,
|
|
699
|
+
},
|
|
700
|
+
hostedButtonId: "",
|
|
701
|
+
},
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
beforeEach(() => {
|
|
705
|
+
vi.resetAllMocks();
|
|
706
|
+
// $FlowIssue
|
|
707
|
+
getLogger.mockImplementation(() => ({ error: errorMock }));
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
describe("renderStandaloneButton", () => {
|
|
711
|
+
test("renders button if eligible", () => {
|
|
712
|
+
const Buttons = vi.fn(() => ({
|
|
713
|
+
render: renderMock,
|
|
714
|
+
isEligible: vi.fn(() => true),
|
|
715
|
+
}));
|
|
716
|
+
|
|
717
|
+
// $FlowIssue
|
|
718
|
+
getButtonsComponent.mockImplementationOnce(() => Buttons);
|
|
719
|
+
|
|
720
|
+
renderStandaloneButton({
|
|
721
|
+
...baseParams,
|
|
722
|
+
fundingSource: "paypal",
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
expect(renderMock).toHaveBeenCalledTimes(1);
|
|
726
|
+
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
|
|
727
|
+
expect(Buttons).toHaveBeenCalledWith(
|
|
728
|
+
expect.objectContaining({
|
|
729
|
+
fundingSource: "paypal",
|
|
730
|
+
})
|
|
731
|
+
);
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
test("does not render button if button is ineligible", () => {
|
|
735
|
+
const Buttons = vi.fn(() => ({
|
|
736
|
+
render: renderMock,
|
|
737
|
+
isEligible: vi.fn(() => false),
|
|
738
|
+
}));
|
|
739
|
+
|
|
740
|
+
// $FlowIssue
|
|
741
|
+
getButtonsComponent.mockImplementationOnce(() => Buttons);
|
|
742
|
+
|
|
743
|
+
renderStandaloneButton({
|
|
744
|
+
...baseParams,
|
|
745
|
+
fundingSource: "venmo",
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
expect(renderMock).toHaveBeenCalledTimes(0);
|
|
749
|
+
expect(errorMock).toHaveBeenCalledWith(
|
|
750
|
+
"ncps_standalone_venmo_ineligible"
|
|
751
|
+
);
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
describe("renderDefaultButton", () => {
|
|
756
|
+
test("renders the first eligible button", () => {
|
|
757
|
+
const Buttons = vi.fn(() => ({
|
|
758
|
+
render: renderMock,
|
|
759
|
+
isEligible: vi.fn(() => true),
|
|
760
|
+
}));
|
|
761
|
+
|
|
762
|
+
// $FlowIssue
|
|
763
|
+
getButtonsComponent.mockImplementation(() => Buttons);
|
|
764
|
+
|
|
765
|
+
renderDefaultButton({
|
|
766
|
+
...baseParams,
|
|
767
|
+
eligibleDefaultButtons: ["venmo", "paylater"],
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
|
|
771
|
+
expect(errorMock).toHaveBeenCalledTimes(0);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
test("renders the next eligible button if button fails Buttons().isEligible() check", () => {
|
|
775
|
+
const Buttons = vi.fn(({ fundingSource }) => ({
|
|
776
|
+
render: renderMock,
|
|
777
|
+
isEligible: vi.fn(() => fundingSource === "paylater"),
|
|
778
|
+
}));
|
|
779
|
+
|
|
780
|
+
// $FlowIssue
|
|
781
|
+
getButtonsComponent.mockImplementation(() => Buttons);
|
|
782
|
+
|
|
783
|
+
renderDefaultButton({
|
|
784
|
+
...baseParams,
|
|
785
|
+
eligibleDefaultButtons: ["venmo", "paylater"],
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
expect(errorMock).toHaveBeenCalledTimes(1);
|
|
789
|
+
expect(errorMock).toHaveBeenCalledWith(
|
|
790
|
+
"ncps_standalone_venmo_ineligible"
|
|
791
|
+
);
|
|
792
|
+
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
test("does not render any button if all fail Buttons().isEligible()", () => {
|
|
796
|
+
const Buttons = vi.fn(() => ({
|
|
797
|
+
render: renderMock,
|
|
798
|
+
isEligible: vi.fn(() => false),
|
|
799
|
+
}));
|
|
800
|
+
|
|
801
|
+
// $FlowIssue
|
|
802
|
+
getButtonsComponent.mockImplementation(() => Buttons);
|
|
803
|
+
|
|
804
|
+
renderDefaultButton({
|
|
805
|
+
...baseParams,
|
|
806
|
+
eligibleDefaultButtons: ["venmo", "paylater"],
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
expect(errorMock).toHaveBeenCalledTimes(2);
|
|
810
|
+
expect(errorMock).toHaveBeenCalledWith(
|
|
811
|
+
"ncps_standalone_venmo_ineligible"
|
|
812
|
+
);
|
|
813
|
+
expect(errorMock).toHaveBeenCalledWith(
|
|
814
|
+
"ncps_standalone_paylater_ineligible"
|
|
815
|
+
);
|
|
816
|
+
expect(renderMock).toHaveBeenCalledTimes(0);
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
});
|
|
820
|
+
|
|
605
821
|
/* eslint-enable no-restricted-globals, promise/no-native */
|