Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/funding/funding.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type { Wallet, Experiment } from "../types";
import { BUTTON_LAYOUT, BUTTON_FLOW } from "../constants";

import { getFundingConfig } from "./config";
import { supportsVenmoPopups, isSupportedNativeVenmoBrowser } from "./util";

type IsFundingEligibleOptions = {|
layout?: $Values<typeof BUTTON_LAYOUT>,
Expand All @@ -33,6 +32,8 @@ type IsFundingEligibleOptions = {|
wallet?: ?Wallet,
applePaySupport: boolean,
supportsPopups: boolean,
supportsVenmoPopups: boolean,
supportedNativeVenmoBrowser: boolean,
supportedNativeBrowser: boolean,
experiment?: Experiment,
displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
Expand Down Expand Up @@ -83,7 +84,9 @@ export function isFundingEligible(
wallet,
applePaySupport,
supportsPopups,
supportsVenmoPopups,
supportedNativeBrowser,
supportedNativeVenmoBrowser,
experiment,
displayOnly,
userAgent,
Expand Down Expand Up @@ -171,12 +174,10 @@ export function isFundingEligible(
if (fundingConfig.requires && userAgent) {
const required = fundingConfig.requires({ experiment, platform });
const popupSupport =
source === FUNDING.VENMO
? supportsVenmoPopups(experiment, supportsPopups, userAgent)
: supportsPopups;
source === FUNDING.VENMO ? supportsVenmoPopups : supportsPopups;
const nativeBrowserSupport =
source === FUNDING.VENMO
? isSupportedNativeVenmoBrowser(experiment, userAgent)
? supportedNativeVenmoBrowser
: supportedNativeBrowser;
if (required.popup === true && popupSupport === false) {
return false;
Expand Down Expand Up @@ -221,6 +222,8 @@ export function determineEligibleFunding({
applePaySupport,
supportsPopups,
supportedNativeBrowser,
supportsVenmoPopups,
supportedNativeVenmoBrowser,
experiment,
displayOnly = [],
userAgent = "",
Expand All @@ -241,6 +244,8 @@ export function determineEligibleFunding({
applePaySupport: boolean,
supportsPopups: boolean,
supportedNativeBrowser: boolean,
supportsVenmoPopups: boolean,
supportedNativeVenmoBrowser: boolean,
experiment: Experiment,
displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
userAgent?: string,
Expand All @@ -265,7 +270,9 @@ export function determineEligibleFunding({
wallet,
applePaySupport,
supportsPopups,
supportsVenmoPopups,
supportedNativeBrowser,
supportedNativeVenmoBrowser,
experiment,
displayOnly,
userAgent,
Expand Down
89 changes: 17 additions & 72 deletions src/funding/funding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@ import { describe, expect, vi, beforeEach, afterEach } from "vitest";
import { BUTTON_FLOW } from "../constants";

import { isFundingEligible, isWalletFundingEligible } from "./funding";
import { supportsVenmoPopups, isSupportedNativeVenmoBrowser } from "./util";
import { getFundingConfig } from "./config";

// Mock the venmo utility functions
vi.mock("./util", () => ({
supportsVenmoPopups: vi.fn(),
isSupportedNativeVenmoBrowser: vi.fn(),
}));

// Mock getFundingConfig to control funding config behavior
vi.mock("./config", () => ({
getFundingConfig: vi.fn(),
Expand Down Expand Up @@ -65,6 +58,8 @@ const defaultMockFundingOptions = {
applePaySupport: false,
supportsPopups: true,
supportedNativeBrowser: true,
supportsVenmoPopups: false,
supportedNativeVenmoBrowser: false,
onShippingChange: null,
onShippingAddressChange: null,
onShippingOptionsChange: null,
Expand Down Expand Up @@ -265,91 +260,66 @@ describe("Funding eligibility", () => {
});

test("should use supportsVenmoPopups for venmo funding source when popup is required", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: { venmoEnableWebOnNonNativeBrowser: true },
supportsVenmoPopups: true,
supportedNativeVenmoBrowser: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(supportsVenmoPopups).toHaveBeenCalledWith(
options.experiment,
true,
options.userAgent
);
expect(result).toBe(true);
});

test("should use isSupportedNativeVenmoBrowser for venmo funding source when native is required", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: { venmoEnableWebOnNonNativeBrowser: true },
supportedNativeVenmoBrowser: true,
supportsVenmoPopups: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(isSupportedNativeVenmoBrowser).toHaveBeenCalledWith(
options.experiment,
options.userAgent
);
expect(result).toBe(true);
});

test("should return false when venmo popup support is required but supportsVenmoPopups returns false", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(false);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: {},
supportsVenmoPopups: false,
supportedNativeVenmoBrowser: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(supportsVenmoPopups).toHaveBeenCalledWith(
options.experiment,
true,
options.userAgent
);
expect(result).toBe(false);
});

test("should return false when venmo native support is required but isSupportedNativeVenmoBrowser returns false", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(false);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: {},
supportedNativeVenmoBrowser: false,
supportsVenmoPopups: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(isSupportedNativeVenmoBrowser).toHaveBeenCalledWith(
options.experiment,
options.userAgent
);
expect(result).toBe(false);
});

test("should use standard supportsPopups for non-venmo funding sources", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(false);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(false);

// Update the mock to not require popup and native for PayPal to isolate the test
vi.mocked(getFundingConfig).mockReturnValue({
[FUNDING.PAYLATER]: {
Expand Down Expand Up @@ -402,41 +372,25 @@ describe("Funding eligibility", () => {

const result = isFundingEligible(FUNDING.PAYPAL, options);

// Venmo functions should not be called for non-venmo sources
expect(supportsVenmoPopups).not.toHaveBeenCalled();
expect(isSupportedNativeVenmoBrowser).not.toHaveBeenCalled();
expect(result).toBe(true);
});

test("should handle undefined experiment parameter for venmo", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: undefined,
supportsVenmoPopups: true,
supportedNativeVenmoBrowser: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(supportsVenmoPopups).toHaveBeenCalledWith(
undefined,
true,
options.userAgent
);
expect(isSupportedNativeVenmoBrowser).toHaveBeenCalledWith(
undefined,
options.userAgent
);
expect(result).toBe(true);
});

test("should pass through experiment flags to venmo utility functions", () => {
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);

const experimentFlags = {
venmoEnableWebOnNonNativeBrowser: true,
venmoVaultWithoutPurchase: false,
Expand All @@ -447,40 +401,31 @@ describe("Funding eligibility", () => {
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: experimentFlags,
supportsVenmoPopups: true,
supportedNativeVenmoBrowser: true,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(supportsVenmoPopups).toHaveBeenCalledWith(
experimentFlags,
true,
options.userAgent
);
expect(isSupportedNativeVenmoBrowser).toHaveBeenCalledWith(
experimentFlags,
options.userAgent
);
expect(result).toBe(true);
});

test("should respect combination of venmo popup and native requirements", () => {
// Test case where popup succeeds but native fails
vi.mocked(supportsVenmoPopups).mockReturnValue(true);
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(false);

const options = {
...defaultMockFundingOptions,
fundingSource: FUNDING.VENMO,
platform: "mobile",
experiment: {},
supportsVenmoPopups: true,
supportedNativeVenmoBrowser: false,
};

const result = isFundingEligible(FUNDING.VENMO, options);

expect(result).toBe(false);

// Test case where both succeed
vi.mocked(isSupportedNativeVenmoBrowser).mockReturnValue(true);
options.supportedNativeVenmoBrowser = true;

const result2 = isFundingEligible(FUNDING.VENMO, options);
expect(result2).toBe(true);
Expand Down
11 changes: 5 additions & 6 deletions src/funding/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,27 @@ export function supportsVenmoPopups(
supportsPopups: boolean,
userAgent: string
): boolean {
if (isVenmoSupportedWebView(userAgent)) {
if (typeof window !== "undefined" && window.popupBridge) {
if (__WEB__ && isVenmoSupportedWebView(userAgent)) {
if (window.popupBridge) {
return true;
}
return false;
}

if (experiment?.venmoEnableWebOnNonNativeBrowser === true) {
return venmoUserAgentSupportsPopups(userAgent);
}

return supportsPopups;
}

export function isSupportedNativeVenmoBrowser(
experiment?: Experiment,
userAgent: string
): boolean {
if (isVenmoSupportedWebView(userAgent)) {
if (typeof window !== "undefined" && window.popupBridge) {
if (__WEB__ && isVenmoSupportedWebView(userAgent)) {
if (window.popupBridge) {
return true;
}
return false;
}

if (isTablet(userAgent)) {
Expand Down
2 changes: 1 addition & 1 deletion src/funding/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe("funding/util", () => {
});

it("should return false when popupBridge is not available", () => {
expect(supportsVenmoPopups({}, true, defaultUserAgent)).toBe(false);
expect(supportsVenmoPopups({}, false, defaultUserAgent)).toBe(false);
});
});

Expand Down
17 changes: 17 additions & 0 deletions src/marks/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ import type {
} from "../ui/buttons/props";
import { BUTTON_LAYOUT, BUTTON_FLOW } from "../constants";
import { determineEligibleFunding, isFundingEligible } from "../funding";
import {
supportsVenmoPopups,
isSupportedNativeVenmoBrowser,
} from "../funding/util";
import {
isSupportedNativeBrowser,
getButtonExperiments,
Expand Down Expand Up @@ -80,6 +84,15 @@ export const getMarksComponent: () => MarksComponent = memoize(() => {
const supportsPopups = userAgentSupportsPopups();
const supportedNativeBrowser = isSupportedNativeBrowser();
const experiment = getButtonExperiments();
const supportsVenmoPopup = supportsVenmoPopups(
experiment,
supportsPopups,
userAgent
);
const supportedNativeVenmoBrowser = isSupportedNativeVenmoBrowser(
experiment,
userAgent
);

const hasShippingCallback = Boolean(
onShippingChange || onShippingAddressChange || onShippingOptionsChange
Expand All @@ -100,6 +113,8 @@ export const getMarksComponent: () => MarksComponent = memoize(() => {
hasShippingCallback,
supportsPopups,
supportedNativeBrowser,
supportsVenmoPopups: supportsVenmoPopup,
supportedNativeVenmoBrowser,
experiment,
displayOnly,
userAgent,
Expand All @@ -124,7 +139,9 @@ export const getMarksComponent: () => MarksComponent = memoize(() => {
flow,
applePaySupport,
supportsPopups,
supportsVenmoPopups: supportsVenmoPopup,
supportedNativeBrowser,
supportedNativeVenmoBrowser,
experiment,
displayOnly,
userAgent,
Expand Down
4 changes: 4 additions & 0 deletions src/ui/buttons/buttons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ export function Buttons(props: ButtonsProps): ElementNode {
style,
supportedNativeBrowser,
supportsPopups,
supportsVenmoPopups,
supportedNativeVenmoBrowser,
userIDToken,
vault,
wallet,
Expand All @@ -189,6 +191,8 @@ export function Buttons(props: ButtonsProps): ElementNode {
applePaySupport,
supportsPopups,
supportedNativeBrowser,
supportsVenmoPopups,
supportedNativeVenmoBrowser,
experiment,
displayOnly,
userAgent,
Expand Down
Loading