Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@paypal/checkout-components

Package Overview
Dependencies
Maintainers
20
Versions
502
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@paypal/checkout-components - npm Package Compare versions

Comparing version 5.0.316 to 5.0.317

2

package.json
{
"name": "@paypal/checkout-components",
"version": "5.0.316",
"version": "5.0.317",
"description": "PayPal Checkout components, for integrating checkout products.",

@@ -5,0 +5,0 @@ "main": "index.js",

/* @flow */
import { getLogger } from "@paypal/sdk-client/src";
import { getButtonsComponent } from "../zoid/buttons";

@@ -13,6 +10,7 @@

getMerchantID,
shouldRenderSDKButtons,
getFlexDirection,
appendButtonContainer,
getButtonColor,
applyContainerStyles,
renderStandaloneButton,
renderDefaultButton,
getDefaultButtonOptions,
} from "./utils";

@@ -23,2 +21,3 @@ import type {

HostedButtonsInstance,
HostedButtonOptions,
} from "./types";

@@ -30,3 +29,2 @@

hostedButtonId,
fundingSources = [],
}: HostedButtonsComponentProps): HostedButtonsInstance {

@@ -36,5 +34,11 @@ const Buttons = getButtonsComponent();

const merchantId = getMerchantID();
const { html, htmlScript, style } = await getHostedButtonDetails({
const {
html,
htmlScript,
style,
version,
preferences,
buttonContainerId,
} = await getHostedButtonDetails({
hostedButtonId,
fundingSources,
});

@@ -54,2 +58,3 @@

});
const onApprove = buildHostedButtonOnApprove({

@@ -61,3 +66,3 @@ enableDPoP,

const buttonOptions = {
const buttonOptions: HostedButtonOptions = {
createOrder,

@@ -72,26 +77,21 @@ hostedButtonId,

if (shouldRenderSDKButtons(fundingSources)) {
if (version === "2") {
const { flexDirection } = getFlexDirection({ ...style });
appendButtonContainer({ flexDirection, selector });
applyContainerStyles({ flexDirection, buttonContainerId });
// Only render 2 buttons max
// This will be refactored in https://paypal.atlassian.net/browse/DTPPCPSDK-2112 when NCPS team updates their API response
fundingSources.slice(0, 2).forEach((fundingSource, index) => {
// $FlowFixMe
const standaloneButton = Buttons({
...buttonOptions,
fundingSource,
style: {
...style,
color: getButtonColor(style.color, fundingSource),
},
});
if (standaloneButton.isEligible()) {
standaloneButton.render(
index === 0 ? "#ncp-primary-button" : "#ncp-secondary-button"
);
preferences?.buttonPreferences.forEach((fundingSource) => {
if (fundingSource === "default") {
const eligibleDefaultButtons = getDefaultButtonOptions(preferences);
renderDefaultButton({
eligibleDefaultButtons,
buttonContainerId,
buttonOptions,
});
} else {
getLogger().error(`ncps_standalone_${fundingSource}_ineligible`);
renderStandaloneButton({
fundingSource,
buttonContainerId,
buttonOptions,
});
}

@@ -98,0 +98,0 @@ });

@@ -9,2 +9,4 @@ /* @flow */

import { renderDefaultButton, renderStandaloneButton } from "./utils";
import { getHostedButtonsComponent } from ".";

@@ -35,40 +37,52 @@

const getHostedButtonDetailsResponse = {
body: {
button_details: {
link_variables: [
{
name: "shape",
value: "rect",
},
{
name: "layout",
value: "vertical",
},
{
name: "color",
value: "gold",
},
{
name: "button_text",
value: "paypal",
},
{
name: "button_type",
value: "FIXED_PRICE",
},
{
name: "tagline",
value: "true",
},
{
name: "height",
value: "40",
},
],
},
vi.mock("./utils.js", async () => {
return {
...(await vi.importActual("./utils.js")),
renderStandaloneButton: vi.fn(),
renderDefaultButton: vi.fn(),
};
});
const baseLinkVariables = [
{
name: "shape",
value: "rect",
},
};
{
name: "layout",
value: "vertical",
},
{
name: "color",
value: "gold",
},
{
name: "button_text",
value: "paypal",
},
{
name: "button_type",
value: "FIXED_PRICE",
},
{
name: "tagline",
value: "true",
},
{
name: "height",
value: "40",
},
];
describe("HostedButtons", () => {
const hostedButtonId = "B1234567890";
describe("HostedButtons v1", () => {
const hostedButtonDetailsResponse = {
body: {
button_details: {
link_variables: baseLinkVariables,
},
},
};
test("paypal.Buttons calls getHostedButtonDetails and invokes v5 of the SDK", async () => {

@@ -82,11 +96,11 @@ const Buttons = vi.fn(() => ({ render: vi.fn() }));

// eslint-disable-next-line compat/compat
Promise.resolve(getHostedButtonDetailsResponse)
Promise.resolve(hostedButtonDetailsResponse)
);
await HostedButtons({
hostedButtonId: "B1234567890",
fundingSources: [],
hostedButtonId,
}).render("#example");
expect(Buttons).toHaveBeenCalledWith(
expect.objectContaining({
hostedButtonId: "B1234567890",
hostedButtonId,
style: expect.objectContaining({ tagline: true }),

@@ -99,40 +113,2 @@ })

describe("NCP V2", () => {
beforeEach(() => {
const containerId = "#container-id";
const selector = document.createElement("div");
selector.setAttribute("id", containerId.slice(1));
vi.spyOn(document, "querySelector").mockReturnValue(selector);
});
test("paypal.Buttons calls getHostedButtonDetails, invokes v5 of the SDK", async () => {
const renderMock = vi.fn();
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => true),
}));
// $FlowIssue
getButtonsComponent.mockImplementationOnce(() => Buttons);
const HostedButtons = getHostedButtonsComponent();
// $FlowIssue
request.mockImplementationOnce(() =>
// eslint-disable-next-line compat/compat
Promise.resolve(getHostedButtonDetailsResponse)
);
await HostedButtons({
hostedButtonId: "B1234567890",
fundingSources: ["paypal", "venmo"],
}).render("#example");
expect(Buttons).toHaveBeenCalledWith(
expect.objectContaining({
hostedButtonId: "B1234567890",
})
);
expect(Buttons).toHaveBeenCalledTimes(2);
expect(renderMock).toHaveBeenCalledTimes(2);
expect.assertions(3);
});
});
test("only eligible buttons are rendered", async () => {

@@ -151,15 +127,15 @@ const renderMock = vi.fn();

// eslint-disable-next-line compat/compat
Promise.resolve(getHostedButtonDetailsResponse)
Promise.resolve(hostedButtonDetailsResponse)
);
await HostedButtons({
hostedButtonId: "B1234567890",
fundingSources: ["paypal", "venmo"],
hostedButtonId,
}).render("#example");
expect(Buttons).toHaveBeenCalledWith(
expect.objectContaining({
hostedButtonId: "B1234567890",
hostedButtonId,
})
);
expect(Buttons).toHaveBeenCalledTimes(2);
expect(renderMock).toHaveBeenCalledTimes(0);
expect(Buttons).toHaveBeenCalledTimes(1);
expect(renderMock).toHaveBeenCalledTimes(1);
expect.assertions(3);

@@ -215,7 +191,8 @@ });

await HostedButtons({
hostedButtonId: "B1234567890",
hostedButtonId,
}).render("#example");
expect(Buttons).toHaveBeenCalledWith(
expect.objectContaining({
hostedButtonId: "B1234567890",
hostedButtonId,
style: expect.objectContaining({ tagline: false }),

@@ -229,2 +206,66 @@ })

});
describe("HostedButtons v2", () => {
const hostedButtonDetailsResponse = {
body: {
version: "2",
button_details: {
link_variables: baseLinkVariables,
js_sdk_container_id: "spb-container",
preferences: {
button_preferences: ["paypal", "default"],
eligible_funding_methods: ["paypal", "venmo", "paylater"],
},
},
},
};
beforeEach(() => {
vi.restoreAllMocks();
const selector = document.createElement("div");
selector.id =
hostedButtonDetailsResponse.body.button_details.js_sdk_container_id;
vi.spyOn(document, "querySelector").mockReturnValue(selector);
});
test("paypal.HostedButtons calls renderStandaloneButton & renderDefaultButton accordingly", async () => {
const renderMock = vi.fn();
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => false),
}));
// $FlowIssue
getButtonsComponent.mockImplementation(() => Buttons);
const HostedButtons = getHostedButtonsComponent();
// $FlowIssue
request.mockImplementationOnce(() =>
// eslint-disable-next-line compat/compat
Promise.resolve(hostedButtonDetailsResponse)
);
await HostedButtons({
hostedButtonId,
}).render("#example");
expect(renderStandaloneButton).toHaveBeenCalledTimes(1);
expect(renderDefaultButton).toHaveBeenCalledTimes(1);
expect(renderStandaloneButton).toHaveBeenCalledWith(
expect.objectContaining({
fundingSource: "paypal",
})
);
expect(renderDefaultButton).toHaveBeenCalledWith(
expect.objectContaining({
eligibleDefaultButtons: ["venmo", "paylater"],
})
);
});
});
/* eslint-enable no-restricted-globals, promise/no-native */
/* @flow */
/* eslint-disable no-restricted-globals, promise/no-native */
import { FUNDING } from "@paypal/sdk-constants/src";

@@ -8,2 +9,14 @@ export type Color = string;

export type CreateOrder = (data: {|
paymentSource: string,
|}) => Promise<string | void>;
export type OnApprove = (data: {|
orderID: string,
paymentSource: string,
|}) => Promise<mixed>;
type OnInit = (data: mixed, actions: mixed) => void;
type OnClick = (data: mixed, actions: mixed) => void;
export type FundingSources = string;

@@ -23,2 +36,57 @@ export interface GetFlexDirection {

export type ApplyButtonStylesProps = {|
flexDirection: FlexDirection,
buttonContainerId: string,
|};
export type HostedButtonStyles = {|
layout: string,
shape: string,
color: string,
label: string,
height: ?number,
tagline: boolean,
|};
export type HostedButtonOptions = {|
createOrder: CreateOrder,
onApprove: OnApprove,
onClick: OnClick,
onInit: OnInit,
style: HostedButtonStyles,
hostedButtonId: string,
merchantId?: string,
|};
export type ButtonPreferences = $ReadOnlyArray<
$Values<typeof FUNDING> | "default"
>;
export type HostedButtonPreferences = {|
buttonPreferences: ButtonPreferences,
eligibleFundingMethods: $ReadOnlyArray<$Values<typeof FUNDING>>,
|};
export type NcpResponsePreferences = {|
button_preferences: ButtonPreferences,
eligible_funding_methods: $ReadOnlyArray<$Values<typeof FUNDING>>,
|};
export type GetButtonsProps = {|
fundingSource: FundingSources,
buttonOptions: HostedButtonOptions,
|};
export type RenderStandaloneButtonProps = {|
fundingSource: FundingSources,
buttonContainerId: string,
buttonOptions: HostedButtonOptions,
|};
export type RenderDefaultButtonProps = {|
eligibleDefaultButtons: $ReadOnlyArray<FundingSources>,
buttonContainerId: string,
buttonOptions: HostedButtonOptions,
|};
export type HostedButtonsComponentProps = {|

@@ -39,9 +107,2 @@ hostedButtonId: string,

export type EligibleHostedButtons = "paypal" | "venmo" | "paylater";
export type HostedButtonPreferences = {|
buttonPreferences: $ReadOnlyArray<EligibleHostedButtons & "default">,
eligibleFundingMethods: $ReadOnlyArray<EligibleHostedButtons>,
|};
export type HostedButtonDetailsParams =

@@ -51,12 +112,5 @@ (HostedButtonsComponentProps) => Promise<{|

htmlScript: string,
style: {|
layout: string,
shape: string,
color: string,
label: string,
height: ?number,
tagline: boolean,
|},
style: HostedButtonStyles,
version: ?string,
buttonContainerId: ?string,
buttonContainerId: string,
preferences?: HostedButtonPreferences,

@@ -70,11 +124,2 @@ |}>;

export type CreateOrder = (data: {|
paymentSource: string,
|}) => Promise<string | void>;
export type OnApprove = (data: {|
orderID: string,
paymentSource: string,
|}) => Promise<mixed>;
export type CreateAccessToken = ({|

@@ -94,6 +139,6 @@ clientId: string,

|}) => {|
onInit: (data: mixed, actions: mixed) => void,
onClick: (data: mixed, actions: mixed) => void,
onInit: OnInit,
onClick: OnClick,
|};
/* eslint-enable no-restricted-globals, promise/no-native */

@@ -5,2 +5,3 @@ /* @flow */

import {
getLogger,
buildDPoPHeaders,

@@ -12,3 +13,7 @@ getSDKHost,

import { FUNDING } from "@paypal/sdk-constants/src";
import { SUPPORTED_FUNDING_SOURCES } from "@paypal/funding-components/src";
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
import { getButtonsComponent, type ButtonsComponent } from "../zoid/buttons";
import type {

@@ -24,5 +29,11 @@ ButtonVariables,

GetFlexDirection,
BuildButtonContainerArgs,
Color,
FundingSources,
ApplyButtonStylesProps,
HostedButtonPreferences,
NcpResponsePreferences,
ButtonPreferences,
GetButtonsProps,
RenderStandaloneButtonProps,
RenderDefaultButtonProps,
} from "./types";

@@ -47,2 +58,3 @@

if (merchantIds.length > 1) {
getLogger().error("ncps_multiple_merchant_ids", { merchantIds });
throw new Error("Multiple merchant-ids are not supported.");

@@ -84,2 +96,37 @@ }

export const getButtonPreferences = ({
button_preferences: buttonPreferences,
eligible_funding_methods: eligibleFundingMethods,
}: NcpResponsePreferences): HostedButtonPreferences => {
if (!buttonPreferences?.length || !eligibleFundingMethods?.length) {
const preferences = {
buttonPreferences,
eligibleFundingMethods,
};
getLogger().error("ncps_missing_preferences", { preferences });
throw new Error(
`Expected preferences to be populated, received: ${JSON.stringify({
preferences,
})}`
);
}
return {
// Remove any buttons that are not included in eligibleFundingMethods.
// If the funding method is "default", we want to keep it in the preferences, and decide which
// button should be rendered in its place in renderStandaloneButton()
buttonPreferences: buttonPreferences.filter(
(fundingMethod) =>
eligibleFundingMethods.includes(fundingMethod) ||
fundingMethod === "default"
),
// Sort the eligible funding methods returned from /ncp/api/form-fields in the order that they would appear in the smart stack.
eligibleFundingMethods: SUPPORTED_FUNDING_SOURCES.filter((fundingMethod) =>
eligibleFundingMethods.includes(fundingMethod)
),
};
};
const getButtonVariable = (variables: ButtonVariables, key: string): string =>

@@ -98,4 +145,10 @@ variables?.find((variable) => variable.name === key)?.value ?? "";

const { body } = response;
const { link_variables: variables, preferences } = body.button_details;
const {
link_variables: variables,
js_sdk_container_id: buttonContainerId,
preferences,
} = body.button_details;
const shouldIncludePreferences = preferences && body.version === "2";
return {

@@ -111,10 +164,7 @@ style: {

version: body.version,
buttonContainerId: body.button_container_id,
buttonContainerId: buttonContainerId || "spb-container",
html: body.html,
htmlScript: body.html_script,
...(preferences && {
preferences: {
buttonPreferences: preferences.button_preferences,
eligibleFundingMethods: preferences.eligible_funding_methods,
},
...(shouldIncludePreferences && {
preferences: getButtonPreferences(preferences),
}),

@@ -260,12 +310,12 @@ };

export function getFlexDirection({
export const getFlexDirection = ({
layout,
}: GetFlexDirectionArgs): GetFlexDirection {
return { flexDirection: layout === "horizontal" ? "row" : "column" };
}
}: GetFlexDirectionArgs): GetFlexDirection => ({
flexDirection: layout === "horizontal" ? "row" : "column",
});
export function getButtonColor(
export const getButtonColor = (
color: Color,
fundingSource: FundingSources
): Color {
): Color => {
const colorMap = {

@@ -300,39 +350,108 @@ gold: {

return colorMap[color][fundingSource];
}
};
export function shouldRenderSDKButtons(
fundingSources: $ReadOnlyArray<FundingSources>
): boolean {
return Boolean(fundingSources.length);
}
export function appendButtonContainer({
export const applyContainerStyles = ({
flexDirection,
selector,
}: BuildButtonContainerArgs) {
const elm = getElementFromSelector(selector);
buttonContainerId,
}: ApplyButtonStylesProps): void => {
const buttonContainer = document.querySelector(`#${buttonContainerId}`);
if (!elm) {
throw new Error("PayPal button container selector was not found");
if (!buttonContainer) {
getLogger().error("ncps_button_container_missing", {
buttonContainerId,
});
throw new Error(`Element with id ${buttonContainerId} not found.`);
}
const buttonContainer = document.createElement("div");
buttonContainer.style.flexDirection = flexDirection;
};
buttonContainer.setAttribute(
"style",
`display: flex; flex-wrap: nowrap; gap: 16px; max-width: 750px; flex-direction: ${flexDirection}`
/**
* Filters out all eligible funding methods that are already specified in button preferences
*/
export const getDefaultButtonOptions = ({
buttonPreferences,
eligibleFundingMethods,
}: HostedButtonPreferences): ButtonPreferences => {
return eligibleFundingMethods.filter(
(fundingSource: string) => !buttonPreferences.includes(fundingSource)
);
};
const primaryButton = document.createElement("div");
primaryButton.setAttribute("id", `ncp-primary-button`);
primaryButton.setAttribute("style", "flex-grow: 1");
/**
* Gets buttons component instance.
*/
export const getButtons = ({
fundingSource,
buttonOptions,
}: GetButtonsProps): ButtonsComponent => {
const Buttons = getButtonsComponent();
const secondaryButton = document.createElement("div");
secondaryButton.setAttribute("id", `ncp-secondary-button`);
secondaryButton.setAttribute("style", "flex-grow: 1");
const { style } = buttonOptions;
buttonContainer.appendChild(primaryButton);
buttonContainer.appendChild(secondaryButton);
// $FlowFixMe
return Buttons({
...buttonOptions,
fundingSource,
style: {
...style,
// $FlowFixMe
color: getButtonColor(style.color, fundingSource),
},
});
};
elm?.appendChild(buttonContainer);
}
/**
* Handles logic for each specified button preference.
*/
export const renderStandaloneButton = ({
fundingSource,
buttonContainerId,
buttonOptions,
}: RenderStandaloneButtonProps): ZalgoPromise<void> | void => {
const standaloneButton = getButtons({
fundingSource,
buttonOptions,
});
// $FlowFixMe
if (standaloneButton.isEligible()) {
// $FlowFixMe
return standaloneButton.render(`#${buttonContainerId}`);
}
getLogger().error(`ncps_standalone_${fundingSource}_ineligible`);
};
/**
* Handles logic for "default" button preference.
*/
export const renderDefaultButton = ({
eligibleDefaultButtons,
buttonContainerId,
buttonOptions,
}: RenderDefaultButtonProps): void => {
const eligibleButtons = [...eligibleDefaultButtons];
// If we exhaust all default options, we don't render any button.
while (eligibleButtons.length) {
const fundingSource = eligibleButtons[0];
const standaloneButton = getButtons({
fundingSource,
buttonOptions,
});
// If the funding source is eligible, render button & return to end loop.
// $FlowFixMe
if (standaloneButton.isEligible()) {
// $FlowFixMe
return standaloneButton.render(`#${buttonContainerId}`);
}
// If funding source is ineligible, log error and move to next funding option.
getLogger().error(`ncps_standalone_${fundingSource}_ineligible`);
eligibleButtons.shift();
}
};

@@ -5,3 +5,6 @@ /* @flow */

import { request } from "@krakenjs/belter/src";
import { getLogger } from "@paypal/sdk-client/src";
import { getButtonsComponent } from "../zoid/buttons";
import {

@@ -14,5 +17,7 @@ buildHostedButtonCreateOrder,

getButtonColor,
shouldRenderSDKButtons,
appendButtonContainer,
getElementFromSelector,
getButtonPreferences,
renderStandaloneButton,
applyContainerStyles,
renderDefaultButton,
} from "./utils";

@@ -33,5 +38,15 @@

getMerchantID: () => ["merchant_id_123"],
getLogger: vi.fn(() => ({
error: vi.fn(),
})),
};
});
vi.mock("../zoid/buttons", async () => {
return {
...(await vi.importActual("../zoid/buttons")),
getButtonsComponent: vi.fn(),
};
});
const accessToken = "AT1234567890";

@@ -103,2 +118,3 @@ const hostedButtonId = "B1234567890";

},
js_sdk_container_id: "spb-container",
},

@@ -563,34 +579,4 @@ version: "2",

test("shouldRenderSDKButtons", () => {
expect(shouldRenderSDKButtons([])).toBe(false);
expect(shouldRenderSDKButtons(["paypal"])).toBe(true);
expect(shouldRenderSDKButtons(["paypal", "venmo"])).toBe(true);
});
test("buildButtonContainer", () => {
const containerId = "#container-id";
const selector = document.createElement("div");
selector.setAttribute("id", containerId.slice(1));
vi.spyOn(document, "querySelector").mockReturnValueOnce(selector);
expect(() =>
appendButtonContainer({ flexDirection: "row", selector: containerId })
).not.toThrow();
expect(() =>
appendButtonContainer({ flexDirection: "row", selector })
).not.toThrow();
expect(() =>
appendButtonContainer({
flexDirection: "row",
selector: `${containerId}-not-found`,
})
).toThrow("PayPal button container selector was not found");
});
test("getElementFromSelector", () => {
const containerId = "#container-id";
const containerId = "container-id";
const selector = document.createElement("div");

@@ -610,2 +596,232 @@

describe("getButtonPreferences", () => {
test("returns all button preferences if all are eligible", () => {
const params = {
button_preferences: ["paypal", "venmo"],
eligible_funding_methods: ["paypal", "venmo", "paylater"],
};
const preferences = getButtonPreferences(params);
expect(preferences.buttonPreferences).toEqual(["paypal", "venmo"]);
});
test("removes any button preferences not in the eligible funding methods", () => {
const params = {
button_preferences: ["paypal", "venmo"],
eligible_funding_methods: ["paypal", "paylater"],
};
const preferences = getButtonPreferences(params);
expect(preferences.buttonPreferences).toEqual(["paypal"]);
});
test("sorts eligible funding methods according to SUPPORTED_FUNDING_SOURCES", () => {
const params = {
button_preferences: ["paypal", "venmo"],
eligible_funding_methods: ["paylater", "venmo", "paypal"],
};
const preferences = getButtonPreferences(params);
expect(preferences.eligibleFundingMethods).toEqual([
"paypal",
"venmo",
"paylater",
]);
});
test("doesn't filter out 'default' in button preferences", () => {
const params = {
button_preferences: ["paypal", "default"],
eligible_funding_methods: ["paylater", "venmo", "paypal"],
};
const preferences = getButtonPreferences(params);
expect(preferences.buttonPreferences).toEqual(["paypal", "default"]);
});
test("logs & throws error if the input is bad", () => {
const errorMock = vi.fn();
// $FlowIssue
getLogger.mockImplementation(() => ({ error: errorMock }));
const params = {
button_preferences: [],
eligible_funding_methods: [],
};
const shouldThrowError = () => getButtonPreferences(params);
expect(shouldThrowError).toThrowError();
expect(errorMock).toBeCalledTimes(1);
});
});
describe("applyContainerStyles", () => {
const buttonContainerId = "button-container";
const params = { flexDirection: "vertical", buttonContainerId };
test("successfully applies styles to container", () => {
const buttonContainer = document.createElement("div");
buttonContainer.id = buttonContainerId;
vi.spyOn(document, "querySelector").mockReturnValueOnce(buttonContainer);
applyContainerStyles(params);
expect(buttonContainer?.style.length).toBeTruthy();
});
test("throws error if button container cannot be found", () => {
// Intentionally not setting up the button container to throw the error
const shouldThrowError = () => applyContainerStyles(params);
expect(shouldThrowError).toThrowError(
`Element with id ${buttonContainerId} not found.`
);
});
});
describe("render buttons", () => {
const containerId = "container-id";
const expectedContainerId = `#${containerId}`;
const renderMock = vi.fn();
const errorMock = vi.fn();
const baseParams = {
buttonContainerId: containerId,
buttonOptions: {
createOrder: vi.fn(),
onApprove: vi.fn(),
onClick: vi.fn(),
onInit: vi.fn(),
style: {
color: "gold",
layout: "",
shape: "",
height: 40,
label: "",
tagline: true,
},
hostedButtonId: "",
},
};
beforeEach(() => {
vi.resetAllMocks();
// $FlowIssue
getLogger.mockImplementation(() => ({ error: errorMock }));
});
describe("renderStandaloneButton", () => {
test("renders button if eligible", () => {
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => true),
}));
// $FlowIssue
getButtonsComponent.mockImplementationOnce(() => Buttons);
renderStandaloneButton({
...baseParams,
fundingSource: "paypal",
});
expect(renderMock).toHaveBeenCalledTimes(1);
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
expect(Buttons).toHaveBeenCalledWith(
expect.objectContaining({
fundingSource: "paypal",
})
);
});
test("does not render button if button is ineligible", () => {
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => false),
}));
// $FlowIssue
getButtonsComponent.mockImplementationOnce(() => Buttons);
renderStandaloneButton({
...baseParams,
fundingSource: "venmo",
});
expect(renderMock).toHaveBeenCalledTimes(0);
expect(errorMock).toHaveBeenCalledWith(
"ncps_standalone_venmo_ineligible"
);
});
});
describe("renderDefaultButton", () => {
test("renders the first eligible button", () => {
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => true),
}));
// $FlowIssue
getButtonsComponent.mockImplementation(() => Buttons);
renderDefaultButton({
...baseParams,
eligibleDefaultButtons: ["venmo", "paylater"],
});
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
expect(errorMock).toHaveBeenCalledTimes(0);
});
test("renders the next eligible button if button fails Buttons().isEligible() check", () => {
const Buttons = vi.fn(({ fundingSource }) => ({
render: renderMock,
isEligible: vi.fn(() => fundingSource === "paylater"),
}));
// $FlowIssue
getButtonsComponent.mockImplementation(() => Buttons);
renderDefaultButton({
...baseParams,
eligibleDefaultButtons: ["venmo", "paylater"],
});
expect(errorMock).toHaveBeenCalledTimes(1);
expect(errorMock).toHaveBeenCalledWith(
"ncps_standalone_venmo_ineligible"
);
expect(renderMock).toHaveBeenCalledWith(expectedContainerId);
});
test("does not render any button if all fail Buttons().isEligible()", () => {
const Buttons = vi.fn(() => ({
render: renderMock,
isEligible: vi.fn(() => false),
}));
// $FlowIssue
getButtonsComponent.mockImplementation(() => Buttons);
renderDefaultButton({
...baseParams,
eligibleDefaultButtons: ["venmo", "paylater"],
});
expect(errorMock).toHaveBeenCalledTimes(2);
expect(errorMock).toHaveBeenCalledWith(
"ncps_standalone_venmo_ineligible"
);
expect(errorMock).toHaveBeenCalledWith(
"ncps_standalone_paylater_ineligible"
);
expect(renderMock).toHaveBeenCalledTimes(0);
});
});
});
/* eslint-enable no-restricted-globals, promise/no-native */

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc