@paypal/checkout-components 5.0.294-alpha.0 → 5.0.294

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/__sdk__.js CHANGED
@@ -86,8 +86,4 @@ module.exports = {
86
86
  entry: "./src/interface/card-fields",
87
87
  globals,
88
88
  },
89
- "hosted-buttons": {
90
- entry: "./src/interface/hosted-buttons",
91
- globals,
92
- },
93
89
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paypal/checkout-components",
3
- "version": "5.0.294-alpha.0",
3
+ "version": "5.0.294",
4
4
  "description": "PayPal Checkout components, for integrating checkout products.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -125,10 +125,9 @@ export function getShopperInsightsComponent(): ShopperInsightsComponent {
125
125
  [FPTI_KEY.EVENT_NAME]: FPTI_TRANSITION.SHOPPER_INSIGHTS_API_INIT,
126
126
  });
127
127
 
128
- validateMerchantConfig({ sdkToken, pageType, userIDToken, clientToken });
129
-
130
128
  const shopperInsights = {
131
129
  getRecommendedPaymentMethods: (merchantPayload) => {
130
+ validateMerchantConfig({ sdkToken, pageType, userIDToken, clientToken });
132
131
  validateMerchantPayload(merchantPayload);
133
132
 
134
133
  const requestPayload =
@@ -1,9 +1,11 @@
1
1
  /* @flow */
2
2
  import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
3
- import { getEnv, getBuyerCountry } from "@paypal/sdk-client/src";
3
+ import { getEnv, getBuyerCountry, getSDKToken } from "@paypal/sdk-client/src";
4
4
  import { vi, describe, expect } from "vitest";
5
5
  import { request } from "@krakenjs/belter/src";
6
6
 
7
+ import { ValidationError } from "../../lib";
8
+
7
9
  import { getShopperInsightsComponent } from "./component";
8
10
 
9
11
  vi.mock("@paypal/sdk-client/src", () => {
@@ -348,4 +350,27 @@ describe("shopper insights component - getRecommendedPaymentMethods()", () => {
348
350
  })
349
351
  );
350
352
  });
353
+
354
+ test("ensure sdk-token is passed when using the getRecommendedPaymentMethods", async () => {
355
+ // $FlowFixMe
356
+ getSDKToken.mockImplementationOnce(() => undefined);
357
+ // $FlowFixMe
358
+ const shopperInsightsComponent = getShopperInsightsComponent();
359
+ const error = new ValidationError(
360
+ `script data attribute sdk-client-token is required but was not passed`
361
+ );
362
+ await expect(
363
+ async () =>
364
+ await shopperInsightsComponent.getRecommendedPaymentMethods({
365
+ customer: {
366
+ email: "email@test.com",
367
+ phone: {
368
+ countryCode: "1",
369
+ nationalNumber: "2345678905",
370
+ },
371
+ },
372
+ })
373
+ ).rejects.toThrowError(error);
374
+ expect.assertions(1);
375
+ });
351
376
  });
@@ -51,7 +51,7 @@ export function getSdkVersion(version: string | null): string {
51
51
  // $FlowFixMe
52
52
  export const getConnectComponent = async (merchantProps = {}) => {
53
53
  const cmid = getClientMetadataID() || getSessionID();
54
- const clientID = getClientID();
54
+ const clientId = getClientID();
55
55
  const userIdToken = getUserIDToken();
56
56
  const env = getEnv();
57
57
  const cspNonce = getCSPNonce();
@@ -108,7 +108,7 @@ export const getConnectComponent = async (merchantProps = {}) => {
108
108
  platformOptions: {
109
109
  platform: "PPCP",
110
110
  userIdToken,
111
- clientID,
111
+ clientId,
112
112
  fraudnet: collect,
113
113
  clientMetadataId: cmid,
114
114
  env,
@@ -521,7 +521,6 @@ export type ButtonProps = {|
521
521
  renderedButtons: $ReadOnlyArray<$Values<typeof FUNDING>>,
522
522
  createVaultSetupToken: CreateVaultSetupToken,
523
523
  displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
524
- hostedButtonId?: string,
525
524
  |};
526
525
 
527
526
  // eslint-disable-next-line flowtype/require-exact-type
@@ -158,13 +158,8 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
158
158
  <PrerenderedButtons
159
159
  nonce={props.nonce}
160
160
  props={props}
161
- onRenderCheckout={({ win, fundingSource, card, hostedButtonId }) => {
162
- state.prerenderDetails = {
163
- win,
164
- fundingSource,
165
- card,
166
- hostedButtonId,
167
- };
161
+ onRenderCheckout={({ win, fundingSource, card }) => {
162
+ state.prerenderDetails = { win, fundingSource, card };
168
163
  }}
169
164
  />
170
165
  ).render(dom({ doc }));
@@ -854,11 +849,6 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
854
849
  value: getExperimentation,
855
850
  },
856
851
 
857
- hostedButtonId: {
858
- type: "string",
859
- required: false,
860
- },
861
-
862
852
  displayOnly: {
863
853
  type: "array",
864
854
  queryParam: true,
@@ -27,7 +27,6 @@ type PrerenderedButtonsProps = {|
27
27
  win?: CrossDomainWindowType,
28
28
  fundingSource: $Values<typeof FUNDING>,
29
29
  card: ?$Values<typeof CARD>,
30
- hostedButtonId?: string,
31
30
  |}) => void,
32
31
  |};
33
32
 
@@ -78,12 +77,7 @@ export function PrerenderedButtons({
78
77
 
79
78
  writeElementToWindow(win, spinner);
80
79
 
81
- onRenderCheckout({
82
- win,
83
- fundingSource,
84
- card,
85
- hostedButtonId: props.hostedButtonId,
86
- });
80
+ onRenderCheckout({ win, fundingSource, card });
87
81
  } else {
88
82
  onRenderCheckout({ fundingSource, card });
89
83
  }
@@ -317,11 +317,6 @@ export function getCheckoutComponent(): CheckoutComponent {
317
317
  queryParam: true,
318
318
  required: false,
319
319
  },
320
-
321
- hostedButtonId: {
322
- type: "string",
323
- required: false,
324
- },
325
320
  },
326
321
 
327
322
  dimensions: ({ props }) => {
@@ -1,62 +0,0 @@
1
- /* @flow */
2
-
3
- import { getMerchantID } from "@paypal/sdk-client/src";
4
-
5
- import { getButtonsComponent } from "../zoid/buttons";
6
-
7
- import {
8
- buildHostedButtonCreateOrder,
9
- buildHostedButtonOnApprove,
10
- getHostedButtonDetails,
11
- renderForm,
12
- } from "./utils";
13
- import type {
14
- HostedButtonsComponent,
15
- HostedButtonsComponentProps,
16
- HostedButtonsInstance,
17
- } from "./types";
18
-
19
- export const getHostedButtonsComponent = (): HostedButtonsComponent => {
20
- function HostedButtons({
21
- hostedButtonId,
22
- }: HostedButtonsComponentProps): HostedButtonsInstance {
23
- const Buttons = getButtonsComponent();
24
- const render = (selector) => {
25
- // The SDK supports mutiple merchant IDs, but hosted buttons only
26
- // have one merchant id as a query parameter to the SDK script.
27
- // https://github.com/paypal/paypal-sdk-client/blob/c58e35f8f7adbab76523eb25b9c10543449d2d29/src/script.js#L144
28
- const merchantId = getMerchantID()[0];
29
-
30
- getHostedButtonDetails({ hostedButtonId }).then(
31
- ({ html, htmlScript, style }) => {
32
- const { onInit, onClick } = renderForm({
33
- hostedButtonId,
34
- html,
35
- htmlScript,
36
- selector,
37
- });
38
-
39
- // $FlowFixMe
40
- Buttons({
41
- hostedButtonId,
42
- style,
43
- onInit,
44
- onClick,
45
- createOrder: buildHostedButtonCreateOrder({
46
- hostedButtonId,
47
- merchantId,
48
- }),
49
- onApprove: buildHostedButtonOnApprove({
50
- hostedButtonId,
51
- merchantId,
52
- }),
53
- }).render(selector);
54
- }
55
- );
56
- };
57
- return {
58
- render,
59
- };
60
- }
61
- return HostedButtons;
62
- };
@@ -1,84 +0,0 @@
1
- /* @flow */
2
-
3
- import { describe, test, expect, vi } from "vitest";
4
- import { request } from "@krakenjs/belter/src";
5
- import { ZalgoPromise } from "@krakenjs/zalgo-promise";
6
-
7
- import { getButtonsComponent } from "../zoid/buttons";
8
-
9
- import { getHostedButtonsComponent } from ".";
10
-
11
- vi.mock("@krakenjs/belter/src", async () => {
12
- return {
13
- ...(await vi.importActual("@krakenjs/belter/src")),
14
- request: vi.fn(),
15
- };
16
- });
17
-
18
- vi.mock("@paypal/sdk-client/src", async () => {
19
- return {
20
- ...(await vi.importActual("@paypal/sdk-client/src")),
21
- getSDKHost: () => "example.com",
22
- getClientID: () => "client_id_123",
23
- getMerchantID: () => ["merchant_id_123"],
24
- };
25
- });
26
-
27
- vi.mock("../zoid/buttons", async () => {
28
- return {
29
- ...(await vi.importActual("../zoid/buttons")),
30
- getButtonsComponent: vi.fn(),
31
- };
32
- });
33
-
34
- const getHostedButtonDetailsResponse = {
35
- body: {
36
- button_details: {
37
- link_variables: [
38
- {
39
- name: "shape",
40
- value: "rect",
41
- },
42
- {
43
- name: "layout",
44
- value: "vertical",
45
- },
46
- {
47
- name: "color",
48
- value: "gold",
49
- },
50
- {
51
- name: "button_text",
52
- value: "paypal",
53
- },
54
- {
55
- name: "button_type",
56
- value: "FIXED_PRICE",
57
- },
58
- ],
59
- },
60
- },
61
- };
62
-
63
- describe("HostedButtons", () => {
64
- test("paypal.Buttons calls getHostedButtonDetails and invokes v5 of the SDK", () => {
65
- const Buttons = vi.fn(() => ({ render: vi.fn() }));
66
- // $FlowIssue
67
- getButtonsComponent.mockImplementationOnce(() => Buttons);
68
- const HostedButtons = getHostedButtonsComponent();
69
- // $FlowIssue
70
- request.mockImplementationOnce(() =>
71
- ZalgoPromise.resolve(getHostedButtonDetailsResponse)
72
- );
73
- HostedButtons({
74
- hostedButtonId: "B1234567890",
75
- }).render("#example");
76
- expect(Buttons).toHaveBeenCalledWith(
77
- expect.objectContaining({
78
- hostedButtonId: "B1234567890",
79
- hostedButtonType: "NO_CODE_FIXED_PRICE",
80
- })
81
- );
82
- expect.assertions(1);
83
- });
84
- });
@@ -1,57 +0,0 @@
1
- /* @flow */
2
-
3
- import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
4
-
5
- export type HostedButtonsComponentProps = {|
6
- hostedButtonId: string,
7
- |};
8
-
9
- export type GetCallbackProps = {|
10
- hostedButtonId: string,
11
- merchantId: string,
12
- |};
13
-
14
- export type HostedButtonsInstance = {|
15
- render: (string | HTMLElement) => void,
16
- |};
17
-
18
- export type HostedButtonDetailsParams =
19
- (HostedButtonsComponentProps) => ZalgoPromise<{|
20
- html: string,
21
- htmlScript: string,
22
- style: {|
23
- layout: string,
24
- shape: string,
25
- color: string,
26
- label: string,
27
- |},
28
- |}>;
29
-
30
- export type ButtonVariables = $ReadOnlyArray<{|
31
- name: string,
32
- value: string,
33
- |}>;
34
-
35
- export type CreateOrder = (data: {|
36
- paymentSource: string,
37
- |}) => ZalgoPromise<string>;
38
-
39
- export type OnApprove = (data: {|
40
- orderID: string,
41
- paymentSource: string,
42
- |}) => ZalgoPromise<mixed>;
43
-
44
- export type CreateAccessToken = (clientID: string) => ZalgoPromise<string>;
45
-
46
- export type HostedButtonsComponent =
47
- (HostedButtonsComponentProps) => HostedButtonsInstance;
48
-
49
- export type RenderForm = ({|
50
- hostedButtonId: string,
51
- html: string,
52
- htmlScript: string,
53
- selector: string | HTMLElement,
54
- |}) => {|
55
- onInit: (data: mixed, actions: mixed) => void,
56
- onClick: (data: mixed, actions: mixed) => void,
57
- |};
@@ -1,157 +0,0 @@
1
- /* @flow */
2
-
3
- import { request, memoize, popup } from "@krakenjs/belter/src";
4
- import { getSDKHost, getClientID } from "@paypal/sdk-client/src";
5
-
6
- import { DEFAULT_POPUP_SIZE } from "../zoid/checkout";
7
-
8
- import type {
9
- ButtonVariables,
10
- CreateAccessToken,
11
- CreateOrder,
12
- GetCallbackProps,
13
- HostedButtonDetailsParams,
14
- OnApprove,
15
- RenderForm,
16
- } from "./types";
17
-
18
- const entryPoint = "SDK";
19
- const baseUrl = `https://${getSDKHost()}`;
20
- const apiUrl = baseUrl.replace("www", "api");
21
-
22
- const getHeaders = (accessToken?: string) => ({
23
- ...(accessToken && { Authorization: `Bearer ${accessToken}` }),
24
- "Content-Type": "application/json",
25
- "PayPal-Entry-Point": entryPoint,
26
- });
27
-
28
- export const createAccessToken: CreateAccessToken = memoize<CreateAccessToken>(
29
- (clientId) => {
30
- return request({
31
- url: `${apiUrl}/v1/oauth2/token`,
32
- method: "POST",
33
- body: "grant_type=client_credentials",
34
- headers: {
35
- Authorization: `Basic ${btoa(clientId)}`,
36
- "Content-Type": "application/json",
37
- },
38
- }).then((response) => response.body.access_token);
39
- }
40
- );
41
-
42
- const getButtonVariable = (variables: ButtonVariables, key: string): string =>
43
- variables?.find((variable) => variable.name === key)?.value ?? "";
44
-
45
- const getFundingSource = (paymentSource) => {
46
- if (paymentSource === "credit") {
47
- return `CARD`;
48
- }
49
- return paymentSource.toUpperCase();
50
- };
51
-
52
- export const getHostedButtonDetails: HostedButtonDetailsParams = ({
53
- hostedButtonId,
54
- }) => {
55
- return request({
56
- url: `${baseUrl}/ncp/api/form-fields/${hostedButtonId}`,
57
- headers: getHeaders(),
58
- }).then(({ body }) => {
59
- const variables = body.button_details.link_variables;
60
- return {
61
- style: {
62
- layout: getButtonVariable(variables, "layout"),
63
- shape: getButtonVariable(variables, "shape"),
64
- color: getButtonVariable(variables, "color"),
65
- label: getButtonVariable(variables, "button_text"),
66
- },
67
- html: body.html,
68
- htmlScript: body.html_script,
69
- };
70
- });
71
- };
72
-
73
- /**
74
- * Attaches form fields (html) to the given selector, and
75
- * initializes window.__pp_form_fields (htmlScript).
76
- */
77
- export const renderForm: RenderForm = ({
78
- hostedButtonId,
79
- html,
80
- htmlScript,
81
- selector,
82
- }) => {
83
- const elm =
84
- typeof selector === "string" ? document.querySelector(selector) : selector;
85
- if (elm) {
86
- elm.innerHTML = html + htmlScript;
87
- const newScriptEl = document.createElement("script");
88
- const oldScriptEl = elm.querySelector("script");
89
- newScriptEl.innerHTML = oldScriptEl?.innerHTML ?? "";
90
- oldScriptEl?.parentNode?.replaceChild(newScriptEl, oldScriptEl);
91
- }
92
- return {
93
- // disable the button, listen for input changes,
94
- // and enable the button when the form is valid
95
- // using actions.disable() and actions.enable()
96
- onInit: window[`__pp_form_fields_${hostedButtonId}`]?.onInit,
97
- // render form errors, if present
98
- onClick: window[`__pp_form_fields_${hostedButtonId}`]?.onClick,
99
- };
100
- };
101
-
102
- export const buildHostedButtonCreateOrder = ({
103
- hostedButtonId,
104
- merchantId,
105
- }: GetCallbackProps): CreateOrder => {
106
- return (data) => {
107
- const userInputs =
108
- window[`__pp_form_fields_${hostedButtonId}`]?.getUserInputs?.() || {};
109
- return createAccessToken(getClientID()).then((accessToken) => {
110
- return request({
111
- url: `${apiUrl}/v1/checkout/links/${hostedButtonId}/create-context`,
112
- headers: getHeaders(accessToken),
113
- method: "POST",
114
- body: JSON.stringify({
115
- entry_point: entryPoint,
116
- funding_source: getFundingSource(data.paymentSource),
117
- merchant_id: merchantId,
118
- ...userInputs,
119
- }),
120
- }).then(({ body }) => {
121
- return body.context_id;
122
- });
123
- });
124
- };
125
- };
126
-
127
- export const buildHostedButtonOnApprove = ({
128
- hostedButtonId,
129
- merchantId,
130
- }: GetCallbackProps): OnApprove => {
131
- return (data) => {
132
- return createAccessToken(getClientID()).then((accessToken) => {
133
- return request({
134
- url: `${apiUrl}/v1/checkout/links/${hostedButtonId}/pay`,
135
- headers: getHeaders(accessToken),
136
- method: "POST",
137
- body: JSON.stringify({
138
- entry_point: entryPoint,
139
- merchant_id: merchantId,
140
- context_id: data.orderID,
141
- }),
142
- }).then((response) => {
143
- // The "Debit or Credit Card" button does not open a popup
144
- // so we need to open a new popup for buyers who complete
145
- // a checkout via "Debit or Credit Card".
146
- if (data.paymentSource === "card") {
147
- const url = `${baseUrl}/ncp/payment/${hostedButtonId}/${data.orderID}`;
148
- popup(url, {
149
- width: DEFAULT_POPUP_SIZE.WIDTH,
150
- height: DEFAULT_POPUP_SIZE.HEIGHT,
151
- });
152
- }
153
- return response;
154
- });
155
- });
156
- };
157
- };
@@ -1,121 +0,0 @@
1
- /* @flow */
2
-
3
- import { test, expect, vi } from "vitest";
4
- import { request } from "@krakenjs/belter/src";
5
- import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
6
-
7
- import {
8
- getHostedButtonDetails,
9
- buildHostedButtonCreateOrder,
10
- buildHostedButtonOnApprove,
11
- } from "./utils";
12
-
13
- vi.mock("@krakenjs/belter/src", async () => {
14
- return {
15
- ...(await vi.importActual("@krakenjs/belter/src")),
16
- request: vi.fn(),
17
- };
18
- });
19
-
20
- vi.mock("@paypal/sdk-client/src", async () => {
21
- return {
22
- ...(await vi.importActual("@paypal/sdk-client/src")),
23
- getSDKHost: () => "example.com",
24
- getClientID: () => "client_id_123",
25
- getMerchantID: () => ["merchant_id_123"],
26
- };
27
- });
28
-
29
- const getHostedButtonDetailsResponse = {
30
- body: {
31
- button_details: {
32
- link_variables: [
33
- {
34
- name: "business",
35
- value: "M1234567890",
36
- },
37
- {
38
- name: "shape",
39
- value: "rect",
40
- },
41
- {
42
- name: "layout",
43
- value: "vertical",
44
- },
45
- {
46
- name: "color",
47
- value: "gold",
48
- },
49
- {
50
- name: "button_text",
51
- value: "paypal",
52
- },
53
- ],
54
- },
55
- },
56
- };
57
-
58
- test("getHostedButtonDetails", async () => {
59
- // $FlowIssue
60
- request.mockImplementationOnce(() =>
61
- ZalgoPromise.resolve(getHostedButtonDetailsResponse)
62
- );
63
- await getHostedButtonDetails({
64
- hostedButtonId: "B1234567890",
65
- }).then(({ style }) => {
66
- expect(style).toEqual({
67
- layout: "vertical",
68
- shape: "rect",
69
- color: "gold",
70
- label: "paypal",
71
- });
72
- });
73
- expect.assertions(1);
74
- });
75
-
76
- test("buildHostedButtonCreateOrder", async () => {
77
- const createOrder = buildHostedButtonCreateOrder({
78
- hostedButtonId: "B1234567890",
79
- merchantId: "M1234567890",
80
- });
81
-
82
- // $FlowIssue
83
- request.mockImplementation(() =>
84
- ZalgoPromise.resolve({
85
- body: {
86
- link_id: "B1234567890",
87
- merchant_id: "M1234567890",
88
- context_id: "EC-1234567890",
89
- status: "CREATED",
90
- },
91
- })
92
- );
93
- const orderID = await createOrder({ paymentSource: "paypal" });
94
- expect(orderID).toBe("EC-1234567890");
95
- expect.assertions(1);
96
- });
97
-
98
- test("buildHostedButtonOnApprove", async () => {
99
- const onApprove = buildHostedButtonOnApprove({
100
- hostedButtonId: "B1234567890",
101
- merchantId: "M1234567890",
102
- });
103
-
104
- // $FlowIssue
105
- request.mockImplementation(() =>
106
- ZalgoPromise.resolve({
107
- body: {},
108
- })
109
- );
110
- await onApprove({ orderID: "EC-1234567890", paymentSource: "paypal" });
111
- expect(request).toHaveBeenCalledWith(
112
- expect.objectContaining({
113
- body: JSON.stringify({
114
- entry_point: "SDK",
115
- merchant_id: "M1234567890",
116
- context_id: "EC-1234567890",
117
- }),
118
- })
119
- );
120
- expect.assertions(1);
121
- });
@@ -1,29 +0,0 @@
1
- /* @flow */
2
-
3
- import { getHostedButtonsComponent } from "../hosted-buttons";
4
- import type { HostedButtonsComponent } from "../hosted-buttons/types";
5
- import { getButtonsComponent } from "../zoid/buttons";
6
- import {
7
- getCardFormComponent,
8
- type CardFormComponent,
9
- } from "../zoid/card-form";
10
- import { getCheckoutComponent, type CheckoutComponent } from "../zoid/checkout";
11
- import type { LazyExport, LazyProtectedExport } from "../types";
12
- import { protectedExport } from "../lib";
13
-
14
- export const HostedButtons: LazyExport<HostedButtonsComponent> = {
15
- __get__: () => getHostedButtonsComponent(),
16
- };
17
-
18
- export const Checkout: LazyProtectedExport<CheckoutComponent> = {
19
- __get__: () => protectedExport(getCheckoutComponent()),
20
- };
21
-
22
- export const CardForm: LazyProtectedExport<CardFormComponent> = {
23
- __get__: () => protectedExport(getCardFormComponent()),
24
- };
25
-
26
- export function setup() {
27
- getButtonsComponent();
28
- getCheckoutComponent();
29
- }