@paypal/checkout-components 5.0.265 → 5.0.266

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paypal/checkout-components",
3
- "version": "5.0.265",
3
+ "version": "5.0.266",
4
4
  "description": "PayPal Checkout components, for integrating checkout products.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -59,9 +59,6 @@ export function getCardConfig(): FundingSourceConfig {
59
59
  eligible: ({ components, fundingSource, fundingEligibility, wallet }) => {
60
60
  const cardEligibility = fundingEligibility.card;
61
61
 
62
- const hostedFieldsRequested = Boolean(
63
- components.indexOf(COMPONENTS.HOSTED_FIELDS) !== -1
64
- );
65
62
  const cardEligible = Boolean(cardEligibility && cardEligibility.eligible);
66
63
  const cardBranded = Boolean(cardEligibility && cardEligibility.branded);
67
64
  const cardVaulted = Boolean(
@@ -76,23 +73,43 @@ export function getCardConfig(): FundingSourceConfig {
76
73
  return false;
77
74
  }
78
75
 
79
- // If card is branded, always show card buttons
76
+ /*
77
+ *
78
+ * the next 5 if statements are in a very important order. Each if statement relies on the one above
79
+ * to verify we are not in a situation where card fields should or should not be shown. Switching the
80
+ * order of these if statements could break merchant integrations
81
+ *
82
+ * 1. If funding eligibility says branded: true for card, it means that the merchant is not
83
+ * eligible for unbranded experiences. In that case, the card button should always be eligible
84
+ * 2. If the merchant is attempting to render a standalone card, we should mark it as eligible
85
+ * since it is outside of the smart stack
86
+ * 3. If the merchant is using the new card-fields component, the card button should be ineligible
87
+ * because we should not mix branded and unbranded experiences
88
+ * 4. If there is a vaulted card in the buyer's wallet we should show the button. This is very important
89
+ * because the old hosted card fields (hosted-fields) uses the card button as its return buyer experience
90
+ * this is why this check happens before checking if hosted-fields was requested
91
+ * 5. If hosted-fields were requested, we shouldn't show the card button because we shouldn't mix branded and
92
+ * unbranded experience. The exception is for vaulted cards explained in the point above
93
+ *
94
+ */
95
+
80
96
  if (cardBranded) {
81
97
  return true;
82
98
  }
83
99
 
84
- // If there's a vaulted card, always show card button
85
- if (cardVaulted) {
100
+ if (fundingSource === FUNDING.CARD) {
86
101
  return true;
87
102
  }
88
103
 
89
- // If standalone card is selected, always show card button
90
- if (fundingSource === FUNDING.CARD) {
104
+ if (components.includes("card-fields")) {
105
+ return false;
106
+ }
107
+
108
+ if (cardVaulted) {
91
109
  return true;
92
110
  }
93
111
 
94
- // If hosted fields is requested, do not show card buttons
95
- if (hostedFieldsRequested) {
112
+ if (components.includes(COMPONENTS.HOSTED_FIELDS)) {
96
113
  return false;
97
114
  }
98
115
 
@@ -0,0 +1,132 @@
1
+ /* @flow */
2
+ import { describe, test, expect } from "vitest";
3
+ import { FUNDING, COMPONENTS } from "@paypal/sdk-constants/src";
4
+
5
+ import { getCardConfig } from "./config";
6
+
7
+ const getEligibility = ({
8
+ eligible = true,
9
+ branded = false,
10
+ vendors = {},
11
+ } = {}) => ({
12
+ card: {
13
+ eligible,
14
+ branded,
15
+ vendors,
16
+ },
17
+ });
18
+
19
+ const getWallet = ({ card = [] } = {}) => ({
20
+ card: {
21
+ instruments: card,
22
+ },
23
+ credit: {
24
+ instruments: [],
25
+ },
26
+ paypal: {
27
+ instruments: [],
28
+ },
29
+ venmo: {
30
+ instruments: [],
31
+ },
32
+ });
33
+
34
+ describe("card eligibility", () => {
35
+ // $FlowIssue .eligible is marked as optional in type
36
+ const getCardConfigEligible = (...args) => getCardConfig().eligible(...args);
37
+
38
+ test("should not be eligible when funding eligibility is false", () => {
39
+ expect(
40
+ getCardConfigEligible({
41
+ components: [],
42
+ fundingSource: FUNDING.PAYPAL,
43
+ fundingEligibility: getEligibility({ eligible: false }),
44
+ // $FlowIssue
45
+ wallet: getWallet(),
46
+ })
47
+ ).toEqual(false);
48
+ });
49
+
50
+ test("should be eligible if card funding eligibility says branded is true", () => {
51
+ expect(
52
+ getCardConfigEligible({
53
+ components: [],
54
+ fundingSource: FUNDING.PAYPAL,
55
+ fundingEligibility: getEligibility({ branded: true }),
56
+ wallet: getWallet(),
57
+ })
58
+ ).toEqual(true);
59
+ });
60
+
61
+ test("should be eligible if standalone card was rendered", () => {
62
+ expect(
63
+ getCardConfigEligible({
64
+ components: [],
65
+ fundingSource: FUNDING.CARD,
66
+ fundingEligibility: getEligibility(),
67
+ wallet: getWallet(),
68
+ })
69
+ ).toEqual(true);
70
+ });
71
+
72
+ test("should be ineligible if card-fields were requested", () => {
73
+ expect(
74
+ getCardConfigEligible({
75
+ // $FlowIssue need to add the new card fields as a constant
76
+ components: ["card-fields"],
77
+ fundingSource: FUNDING.PAYPAL,
78
+ fundingEligibility: getEligibility(),
79
+ wallet: getWallet(),
80
+ })
81
+ ).toEqual(false);
82
+ });
83
+
84
+ test("should be ineligible if card-fields were requested, even if there is a vaulted instrument", () => {
85
+ expect(
86
+ getCardConfigEligible({
87
+ // $FlowIssue need to add the new card fields as a constant
88
+ components: ["card-fields"],
89
+ fundingSource: FUNDING.PAYPAL,
90
+ fundingEligibility: getEligibility(),
91
+ wallet: getWallet({
92
+ card: ["some instrument"],
93
+ }),
94
+ })
95
+ ).toEqual(false);
96
+ });
97
+
98
+ test("should be eligible if there is a vaulted card", () => {
99
+ expect(
100
+ getCardConfigEligible({
101
+ components: [],
102
+ fundingSource: FUNDING.PAYPAL,
103
+ fundingEligibility: getEligibility(),
104
+ wallet: getWallet({
105
+ card: ["some instrument"],
106
+ }),
107
+ })
108
+ ).toEqual(true);
109
+ });
110
+
111
+ test("should be ineligible if hosted-fields was requested", () => {
112
+ expect(
113
+ getCardConfigEligible({
114
+ components: [COMPONENTS.HOSTED_FIELDS],
115
+ fundingSource: FUNDING.PAYPAL,
116
+ fundingEligibility: getEligibility(),
117
+ wallet: getWallet(),
118
+ })
119
+ ).toEqual(false);
120
+ });
121
+
122
+ test("should default to true", () => {
123
+ expect(
124
+ getCardConfigEligible({
125
+ components: [],
126
+ fundingSource: FUNDING.PAYPAL,
127
+ fundingEligibility: getEligibility(),
128
+ wallet: getWallet(),
129
+ })
130
+ ).toEqual(true);
131
+ });
132
+ });
@@ -126,10 +126,10 @@ export type FundingSourceConfig = {|
126
126
  vendors?: { [$Values<typeof CARD>]: ?CardConfig },
127
127
  eligible?: ({|
128
128
  components: $ReadOnlyArray<$Values<typeof COMPONENTS>>,
129
- experiment: ?Experiment,
129
+ experiment?: ?Experiment,
130
130
  fundingEligibility: FundingEligibilityType,
131
131
  fundingSource: ?$Values<typeof FUNDING>,
132
- layout: ?$Values<typeof BUTTON_LAYOUT>,
132
+ layout?: ?$Values<typeof BUTTON_LAYOUT>,
133
133
  wallet: ?Wallet,
134
134
  |}) => boolean,
135
135
  Logo: (LogoOptions) => ChildType,