@paypal/checkout-components 5.0.298 → 5.0.299
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 +4 -3
- package/src/connect/interface.js +6 -9
- package/src/hosted-buttons/index.js +28 -26
- package/src/hosted-buttons/index.test.js +7 -4
- package/src/hosted-buttons/types.js +12 -7
- package/src/hosted-buttons/utils.js +102 -41
- package/src/hosted-buttons/utils.test.js +132 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paypal/checkout-components",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.299",
|
|
4
4
|
"description": "PayPal Checkout components, for integrating checkout products.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"release": "./scripts/publish.sh",
|
|
30
30
|
"start": "npm run webpack -- --progress --watch",
|
|
31
31
|
"test": "npm run format:check && npm run test:unit && npm run jest-ssr && npm run karma",
|
|
32
|
-
"test:unit": "vitest run",
|
|
32
|
+
"test:unit": "vitest run --coverage",
|
|
33
33
|
"percy-screenshot": "npx playwright install && babel-node ./test/percy/server/createButtonConfigs.js && percy exec -- playwright test --config=./test/percy/playwright.config.js --reporter=dot --pass-with-no-tests",
|
|
34
34
|
"typecheck": "npm run flow-typed && npm run flow",
|
|
35
35
|
"version": "./scripts/version.sh",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"@percy/cli": "1.27.2",
|
|
75
75
|
"@percy/playwright": "^1.0.4",
|
|
76
76
|
"@playwright/test": "^1.38.1",
|
|
77
|
+
"@vitest/coverage-v8": "^1.3.1",
|
|
77
78
|
"babel-core": "^7.0.0-bridge.0",
|
|
78
79
|
"bundlemon": "^1.1.0",
|
|
79
80
|
"conventional-changelog-cli": "^2.0.34",
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
"puppeteer": "^1.20.0",
|
|
100
101
|
"serve": "^14.0.0",
|
|
101
102
|
"vite": "^3.2.4",
|
|
102
|
-
"vitest": "^
|
|
103
|
+
"vitest": "^1.3.1"
|
|
103
104
|
},
|
|
104
105
|
"dependencies": {
|
|
105
106
|
"@krakenjs/beaver-logger": "^5.7.0",
|
package/src/connect/interface.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
-
/* eslint-disable eslint-comments/disable-enable-pair */
|
|
3
|
-
/* eslint-disable no-restricted-globals, promise/no-native */
|
|
4
2
|
|
|
5
|
-
import { memoize
|
|
3
|
+
import { memoize } from "@krakenjs/belter/src";
|
|
6
4
|
|
|
7
5
|
import { getConnectComponent } from "./component";
|
|
8
6
|
|
|
9
7
|
type MerchantProps = {||};
|
|
10
|
-
// This needs to be typed, this is coming from the fastlane team i believe
|
|
11
|
-
type FastlaneExternalComponent = {||};
|
|
12
8
|
|
|
13
9
|
type ConnectComponent = (merchantProps: MerchantProps) => ConnectComponent;
|
|
14
10
|
// $FlowFixMe
|
|
@@ -18,7 +14,8 @@ export const Connect: (merchantProps: MerchantProps) => ConnectComponent =
|
|
|
18
14
|
return await getConnectComponent(merchantProps);
|
|
19
15
|
});
|
|
20
16
|
|
|
21
|
-
export const Fastlane =
|
|
22
|
-
merchantProps: MerchantProps
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
export const Fastlane: (merchantProps: MerchantProps) => ConnectComponent =
|
|
18
|
+
memoize(async (merchantProps: MerchantProps): ConnectComponent => {
|
|
19
|
+
// $FlowFixMe
|
|
20
|
+
return await getConnectComponent(merchantProps);
|
|
21
|
+
});
|
|
@@ -17,38 +17,40 @@ import type {
|
|
|
17
17
|
|
|
18
18
|
export const getHostedButtonsComponent = (): HostedButtonsComponent => {
|
|
19
19
|
function HostedButtons({
|
|
20
|
+
enableDPoP = false,
|
|
20
21
|
hostedButtonId,
|
|
21
22
|
}: HostedButtonsComponentProps): HostedButtonsInstance {
|
|
22
23
|
const Buttons = getButtonsComponent();
|
|
23
|
-
const render = (selector) => {
|
|
24
|
+
const render = async (selector) => {
|
|
24
25
|
const merchantId = getMerchantID();
|
|
26
|
+
const { html, htmlScript, style } = await getHostedButtonDetails({
|
|
27
|
+
hostedButtonId,
|
|
28
|
+
});
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
selector,
|
|
33
|
-
});
|
|
30
|
+
const { onInit, onClick } = renderForm({
|
|
31
|
+
hostedButtonId,
|
|
32
|
+
html,
|
|
33
|
+
htmlScript,
|
|
34
|
+
selector,
|
|
35
|
+
});
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
);
|
|
37
|
+
// $FlowFixMe
|
|
38
|
+
Buttons({
|
|
39
|
+
hostedButtonId,
|
|
40
|
+
style,
|
|
41
|
+
onInit,
|
|
42
|
+
onClick,
|
|
43
|
+
createOrder: buildHostedButtonCreateOrder({
|
|
44
|
+
enableDPoP,
|
|
45
|
+
hostedButtonId,
|
|
46
|
+
merchantId,
|
|
47
|
+
}),
|
|
48
|
+
onApprove: buildHostedButtonOnApprove({
|
|
49
|
+
enableDPoP,
|
|
50
|
+
hostedButtonId,
|
|
51
|
+
merchantId,
|
|
52
|
+
}),
|
|
53
|
+
}).render(selector);
|
|
52
54
|
};
|
|
53
55
|
return {
|
|
54
56
|
render,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
+
/* eslint-disable no-restricted-globals, promise/no-native */
|
|
2
3
|
|
|
3
4
|
import { describe, test, expect, vi } from "vitest";
|
|
4
5
|
import { request } from "@krakenjs/belter/src";
|
|
5
|
-
import { ZalgoPromise } from "@krakenjs/zalgo-promise";
|
|
6
6
|
|
|
7
7
|
import { getButtonsComponent } from "../zoid/buttons";
|
|
8
8
|
|
|
@@ -61,16 +61,17 @@ const getHostedButtonDetailsResponse = {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
describe("HostedButtons", () => {
|
|
64
|
-
test("paypal.Buttons calls getHostedButtonDetails and invokes v5 of the SDK", () => {
|
|
64
|
+
test("paypal.Buttons calls getHostedButtonDetails and invokes v5 of the SDK", async () => {
|
|
65
65
|
const Buttons = vi.fn(() => ({ render: vi.fn() }));
|
|
66
66
|
// $FlowIssue
|
|
67
67
|
getButtonsComponent.mockImplementationOnce(() => Buttons);
|
|
68
68
|
const HostedButtons = getHostedButtonsComponent();
|
|
69
69
|
// $FlowIssue
|
|
70
70
|
request.mockImplementationOnce(() =>
|
|
71
|
-
|
|
71
|
+
// eslint-disable-next-line compat/compat
|
|
72
|
+
Promise.resolve(getHostedButtonDetailsResponse)
|
|
72
73
|
);
|
|
73
|
-
HostedButtons({
|
|
74
|
+
await HostedButtons({
|
|
74
75
|
hostedButtonId: "B1234567890",
|
|
75
76
|
}).render("#example");
|
|
76
77
|
expect(Buttons).toHaveBeenCalledWith(
|
|
@@ -81,3 +82,5 @@ describe("HostedButtons", () => {
|
|
|
81
82
|
expect.assertions(1);
|
|
82
83
|
});
|
|
83
84
|
});
|
|
85
|
+
|
|
86
|
+
/* eslint-enable no-restricted-globals, promise/no-native */
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
2
|
+
/* eslint-disable no-restricted-globals, promise/no-native */
|
|
4
3
|
|
|
5
4
|
export type HostedButtonsComponentProps = {|
|
|
6
5
|
hostedButtonId: string,
|
|
7
6
|
|};
|
|
8
7
|
|
|
9
8
|
export type GetCallbackProps = {|
|
|
9
|
+
enableDPoP?: boolean,
|
|
10
10
|
hostedButtonId: string,
|
|
11
11
|
merchantId?: string,
|
|
12
12
|
|};
|
|
13
13
|
|
|
14
14
|
export type HostedButtonsInstance = {|
|
|
15
|
-
render: (string | HTMLElement) => void
|
|
15
|
+
render: (string | HTMLElement) => Promise<void>,
|
|
16
16
|
|};
|
|
17
17
|
|
|
18
18
|
export type HostedButtonDetailsParams =
|
|
19
|
-
(HostedButtonsComponentProps) =>
|
|
19
|
+
(HostedButtonsComponentProps) => Promise<{|
|
|
20
20
|
html: string,
|
|
21
21
|
htmlScript: string,
|
|
22
22
|
style: {|
|
|
@@ -34,14 +34,17 @@ export type ButtonVariables = $ReadOnlyArray<{|
|
|
|
34
34
|
|
|
35
35
|
export type CreateOrder = (data: {|
|
|
36
36
|
paymentSource: string,
|
|
37
|
-
|}) =>
|
|
37
|
+
|}) => Promise<string | void>;
|
|
38
38
|
|
|
39
39
|
export type OnApprove = (data: {|
|
|
40
40
|
orderID: string,
|
|
41
41
|
paymentSource: string,
|
|
42
|
-
|}) =>
|
|
42
|
+
|}) => Promise<mixed>;
|
|
43
43
|
|
|
44
|
-
export type CreateAccessToken = (
|
|
44
|
+
export type CreateAccessToken = ({|
|
|
45
|
+
clientId: string,
|
|
46
|
+
enableDPoP?: boolean,
|
|
47
|
+
|}) => Promise<{| accessToken: string, nonce: string |}>;
|
|
45
48
|
|
|
46
49
|
export type HostedButtonsComponent =
|
|
47
50
|
(HostedButtonsComponentProps) => HostedButtonsInstance;
|
|
@@ -55,3 +58,5 @@ export type RenderForm = ({|
|
|
|
55
58
|
onInit: (data: mixed, actions: mixed) => void,
|
|
56
59
|
onClick: (data: mixed, actions: mixed) => void,
|
|
57
60
|
|};
|
|
61
|
+
|
|
62
|
+
/* eslint-enable no-restricted-globals, promise/no-native */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { request, memoize } from "@krakenjs/belter/src";
|
|
4
4
|
import {
|
|
5
|
+
buildDPoPHeaders,
|
|
5
6
|
getSDKHost,
|
|
6
7
|
getClientID,
|
|
7
8
|
getMerchantID as getSDKMerchantID,
|
|
@@ -39,41 +40,60 @@ export const getMerchantID = (): string | void => {
|
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
export const createAccessToken: CreateAccessToken = memoize<CreateAccessToken>(
|
|
42
|
-
(clientId) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
async ({ clientId, enableDPoP }) => {
|
|
44
|
+
const url = `${apiUrl}/v1/oauth2/token`;
|
|
45
|
+
const method = "POST";
|
|
46
|
+
const DPoPHeaders = enableDPoP
|
|
47
|
+
? await buildDPoPHeaders({
|
|
48
|
+
uri: url,
|
|
49
|
+
method,
|
|
50
|
+
})
|
|
51
|
+
: {};
|
|
52
|
+
const response = await request({
|
|
53
|
+
url,
|
|
54
|
+
method,
|
|
46
55
|
body: "grant_type=client_credentials",
|
|
56
|
+
// $FlowIssue optional properties are not compatible with [key: string]: string
|
|
47
57
|
headers: {
|
|
48
58
|
Authorization: `Basic ${btoa(clientId)}`,
|
|
49
59
|
"Content-Type": "application/json",
|
|
60
|
+
// $FlowIssue exponential-spread
|
|
61
|
+
...DPoPHeaders,
|
|
50
62
|
},
|
|
51
|
-
})
|
|
63
|
+
});
|
|
64
|
+
// $FlowIssue request returns ZalgoPromise
|
|
65
|
+
const { access_token: accessToken, nonce } = response.body;
|
|
66
|
+
return {
|
|
67
|
+
accessToken,
|
|
68
|
+
nonce,
|
|
69
|
+
};
|
|
52
70
|
}
|
|
53
71
|
);
|
|
54
72
|
|
|
55
73
|
const getButtonVariable = (variables: ButtonVariables, key: string): string =>
|
|
56
74
|
variables?.find((variable) => variable.name === key)?.value ?? "";
|
|
57
75
|
|
|
58
|
-
export const getHostedButtonDetails: HostedButtonDetailsParams = ({
|
|
76
|
+
export const getHostedButtonDetails: HostedButtonDetailsParams = async ({
|
|
59
77
|
hostedButtonId,
|
|
60
78
|
}) => {
|
|
61
|
-
|
|
79
|
+
const response = await request({
|
|
62
80
|
url: `${baseUrl}/ncp/api/form-fields/${hostedButtonId}`,
|
|
63
81
|
headers: getHeaders(),
|
|
64
|
-
}).then(({ body }) => {
|
|
65
|
-
const variables = body.button_details.link_variables;
|
|
66
|
-
return {
|
|
67
|
-
style: {
|
|
68
|
-
layout: getButtonVariable(variables, "layout"),
|
|
69
|
-
shape: getButtonVariable(variables, "shape"),
|
|
70
|
-
color: getButtonVariable(variables, "color"),
|
|
71
|
-
label: getButtonVariable(variables, "button_text"),
|
|
72
|
-
},
|
|
73
|
-
html: body.html,
|
|
74
|
-
htmlScript: body.html_script,
|
|
75
|
-
};
|
|
76
82
|
});
|
|
83
|
+
|
|
84
|
+
// $FlowIssue request returns ZalgoPromise
|
|
85
|
+
const { body } = response;
|
|
86
|
+
const variables = body.button_details.link_variables;
|
|
87
|
+
return {
|
|
88
|
+
style: {
|
|
89
|
+
layout: getButtonVariable(variables, "layout"),
|
|
90
|
+
shape: getButtonVariable(variables, "shape"),
|
|
91
|
+
color: getButtonVariable(variables, "color"),
|
|
92
|
+
label: getButtonVariable(variables, "button_text"),
|
|
93
|
+
},
|
|
94
|
+
html: body.html,
|
|
95
|
+
htmlScript: body.html_script,
|
|
96
|
+
};
|
|
77
97
|
};
|
|
78
98
|
|
|
79
99
|
/**
|
|
@@ -106,47 +126,88 @@ export const renderForm: RenderForm = ({
|
|
|
106
126
|
};
|
|
107
127
|
|
|
108
128
|
export const buildHostedButtonCreateOrder = ({
|
|
129
|
+
enableDPoP,
|
|
109
130
|
hostedButtonId,
|
|
110
131
|
merchantId,
|
|
111
132
|
}: GetCallbackProps): CreateOrder => {
|
|
112
|
-
return (data) => {
|
|
133
|
+
return async (data) => {
|
|
113
134
|
const userInputs =
|
|
114
135
|
window[`__pp_form_fields_${hostedButtonId}`]?.getUserInputs?.() || {};
|
|
115
136
|
const onError = window[`__pp_form_fields_${hostedButtonId}`]?.onError;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
const { accessToken, nonce } = await createAccessToken({
|
|
138
|
+
clientId: getClientID(),
|
|
139
|
+
enableDPoP,
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
const url = `${apiUrl}/v1/checkout/links/${hostedButtonId}/create-context`;
|
|
143
|
+
const method = "POST";
|
|
144
|
+
const DPoPHeaders = enableDPoP
|
|
145
|
+
? await buildDPoPHeaders({
|
|
146
|
+
uri: url,
|
|
147
|
+
method,
|
|
148
|
+
accessToken,
|
|
149
|
+
nonce,
|
|
150
|
+
})
|
|
151
|
+
: {};
|
|
152
|
+
const response = await request({
|
|
153
|
+
url,
|
|
154
|
+
// $FlowIssue optional properties are not compatible with [key: string]: string
|
|
155
|
+
headers: {
|
|
156
|
+
...getHeaders(accessToken),
|
|
157
|
+
// $FlowIssue exponential-spread
|
|
158
|
+
...DPoPHeaders,
|
|
159
|
+
},
|
|
160
|
+
method,
|
|
121
161
|
body: JSON.stringify({
|
|
122
162
|
entry_point: entryPoint,
|
|
123
163
|
funding_source: data.paymentSource.toUpperCase(),
|
|
124
164
|
merchant_id: merchantId,
|
|
125
165
|
...userInputs,
|
|
126
166
|
}),
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
167
|
+
});
|
|
168
|
+
// $FlowIssue request returns ZalgoPromise
|
|
169
|
+
const { body } = response;
|
|
170
|
+
return body.context_id || onError(body.name);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
return onError("REQUEST_FAILED");
|
|
173
|
+
}
|
|
131
174
|
};
|
|
132
175
|
};
|
|
133
176
|
|
|
134
177
|
export const buildHostedButtonOnApprove = ({
|
|
178
|
+
enableDPoP,
|
|
135
179
|
hostedButtonId,
|
|
136
180
|
merchantId,
|
|
137
181
|
}: GetCallbackProps): OnApprove => {
|
|
138
|
-
return (data) => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
182
|
+
return async (data) => {
|
|
183
|
+
const { accessToken, nonce } = await createAccessToken({
|
|
184
|
+
clientId: getClientID(),
|
|
185
|
+
enableDPoP,
|
|
186
|
+
});
|
|
187
|
+
const url = `${apiUrl}/v1/checkout/links/${hostedButtonId}/pay`;
|
|
188
|
+
const method = "POST";
|
|
189
|
+
const DPoPHeaders = enableDPoP
|
|
190
|
+
? await buildDPoPHeaders({
|
|
191
|
+
uri: url,
|
|
192
|
+
method,
|
|
193
|
+
accessToken,
|
|
194
|
+
nonce,
|
|
195
|
+
})
|
|
196
|
+
: {};
|
|
197
|
+
return request({
|
|
198
|
+
url,
|
|
199
|
+
// $FlowIssue optional properties are not compatible with [key: string]: string
|
|
200
|
+
headers: {
|
|
201
|
+
...getHeaders(accessToken),
|
|
202
|
+
// $FlowIssue exponential-spread
|
|
203
|
+
...DPoPHeaders,
|
|
204
|
+
},
|
|
205
|
+
method,
|
|
206
|
+
body: JSON.stringify({
|
|
207
|
+
entry_point: entryPoint,
|
|
208
|
+
merchant_id: merchantId,
|
|
209
|
+
context_id: data.orderID,
|
|
210
|
+
}),
|
|
150
211
|
});
|
|
151
212
|
};
|
|
152
213
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/* @flow */
|
|
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 { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
6
5
|
|
|
7
6
|
import {
|
|
8
7
|
buildHostedButtonCreateOrder,
|
|
9
8
|
buildHostedButtonOnApprove,
|
|
9
|
+
createAccessToken,
|
|
10
10
|
getHostedButtonDetails,
|
|
11
11
|
} from "./utils";
|
|
12
12
|
|
|
@@ -26,9 +26,11 @@ vi.mock("@paypal/sdk-client/src", async () => {
|
|
|
26
26
|
};
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
const accessToken = "AT1234567890";
|
|
29
30
|
const hostedButtonId = "B1234567890";
|
|
30
31
|
const merchantId = "M1234567890";
|
|
31
32
|
const orderID = "EC-1234567890";
|
|
33
|
+
const clientId = "C1234567890";
|
|
32
34
|
|
|
33
35
|
const getHostedButtonDetailsResponse = {
|
|
34
36
|
body: {
|
|
@@ -59,10 +61,19 @@ const getHostedButtonDetailsResponse = {
|
|
|
59
61
|
},
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
const mockCreateAccessTokenRequest = () =>
|
|
65
|
+
// eslint-disable-next-line compat/compat
|
|
66
|
+
Promise.resolve({
|
|
67
|
+
body: {
|
|
68
|
+
access_token: accessToken,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
62
72
|
test("getHostedButtonDetails", async () => {
|
|
63
73
|
// $FlowIssue
|
|
64
74
|
request.mockImplementationOnce(() =>
|
|
65
|
-
|
|
75
|
+
// eslint-disable-next-line compat/compat
|
|
76
|
+
Promise.resolve(getHostedButtonDetailsResponse)
|
|
66
77
|
);
|
|
67
78
|
await getHostedButtonDetails({
|
|
68
79
|
hostedButtonId,
|
|
@@ -77,25 +88,100 @@ test("getHostedButtonDetails", async () => {
|
|
|
77
88
|
expect.assertions(1);
|
|
78
89
|
});
|
|
79
90
|
|
|
91
|
+
describe("createAccessToken", () => {
|
|
92
|
+
test("basic functionality", async () => {
|
|
93
|
+
request
|
|
94
|
+
// $FlowIssue
|
|
95
|
+
.mockImplementationOnce(mockCreateAccessTokenRequest);
|
|
96
|
+
await createAccessToken({ clientId });
|
|
97
|
+
expect(request).toHaveBeenCalledWith(
|
|
98
|
+
expect.objectContaining({
|
|
99
|
+
headers: expect.objectContaining({
|
|
100
|
+
Authorization: expect.stringContaining("Basic "),
|
|
101
|
+
}),
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
expect.assertions(1);
|
|
105
|
+
});
|
|
106
|
+
test("with DPoP enabled", async () => {
|
|
107
|
+
request
|
|
108
|
+
// $FlowIssue
|
|
109
|
+
.mockImplementationOnce(mockCreateAccessTokenRequest);
|
|
110
|
+
await createAccessToken({ clientId, enableDPoP: true });
|
|
111
|
+
expect(request).toHaveBeenCalledWith(
|
|
112
|
+
expect.objectContaining({
|
|
113
|
+
headers: expect.objectContaining({
|
|
114
|
+
Authorization: expect.stringContaining("Basic "),
|
|
115
|
+
DPoP: expect.any(String),
|
|
116
|
+
}),
|
|
117
|
+
})
|
|
118
|
+
);
|
|
119
|
+
expect.assertions(1);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
80
123
|
test("buildHostedButtonCreateOrder", async () => {
|
|
81
124
|
const createOrder = buildHostedButtonCreateOrder({
|
|
82
125
|
hostedButtonId,
|
|
83
126
|
merchantId,
|
|
84
127
|
});
|
|
85
128
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
129
|
+
request
|
|
130
|
+
// $FlowIssue
|
|
131
|
+
.mockImplementationOnce(mockCreateAccessTokenRequest)
|
|
132
|
+
.mockImplementation(() =>
|
|
133
|
+
// eslint-disable-next-line compat/compat
|
|
134
|
+
Promise.resolve({
|
|
135
|
+
body: {
|
|
136
|
+
link_id: hostedButtonId,
|
|
137
|
+
merchant_id: merchantId,
|
|
138
|
+
context_id: orderID,
|
|
139
|
+
status: "CREATED",
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
const createdOrderID = await createOrder({ paymentSource: "paypal" });
|
|
144
|
+
expect(request).toHaveBeenCalledWith(
|
|
145
|
+
expect.objectContaining({
|
|
146
|
+
headers: expect.objectContaining({
|
|
147
|
+
Authorization: `Bearer ${accessToken}`,
|
|
148
|
+
}),
|
|
95
149
|
})
|
|
96
150
|
);
|
|
97
|
-
const createdOrderID = await createOrder({ paymentSource: "paypal" });
|
|
98
151
|
expect(createdOrderID).toBe(orderID);
|
|
152
|
+
expect.assertions(2);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("buildHostedButtonCreateOrder with DPoP enabled", async () => {
|
|
156
|
+
const createOrder = buildHostedButtonCreateOrder({
|
|
157
|
+
enableDPoP: true,
|
|
158
|
+
hostedButtonId,
|
|
159
|
+
merchantId,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
request
|
|
163
|
+
// $FlowIssue
|
|
164
|
+
.mockImplementationOnce(mockCreateAccessTokenRequest)
|
|
165
|
+
.mockImplementation(() =>
|
|
166
|
+
// eslint-disable-next-line compat/compat
|
|
167
|
+
Promise.resolve({
|
|
168
|
+
body: {
|
|
169
|
+
link_id: hostedButtonId,
|
|
170
|
+
merchant_id: merchantId,
|
|
171
|
+
context_id: orderID,
|
|
172
|
+
status: "CREATED",
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
await createOrder({ paymentSource: "paypal" });
|
|
177
|
+
expect(request).toHaveBeenCalledWith(
|
|
178
|
+
expect.objectContaining({
|
|
179
|
+
headers: expect.objectContaining({
|
|
180
|
+
Authorization: `DPoP ${accessToken}`,
|
|
181
|
+
DPoP: expect.any(String),
|
|
182
|
+
}),
|
|
183
|
+
})
|
|
184
|
+
);
|
|
99
185
|
expect.assertions(1);
|
|
100
186
|
});
|
|
101
187
|
|
|
@@ -107,7 +193,8 @@ test("buildHostedButtonCreateOrder error handling", async () => {
|
|
|
107
193
|
|
|
108
194
|
// $FlowIssue
|
|
109
195
|
request.mockImplementation(() =>
|
|
110
|
-
|
|
196
|
+
// eslint-disable-next-line compat/compat
|
|
197
|
+
Promise.resolve({
|
|
111
198
|
body: {
|
|
112
199
|
name: "RESOURCE_NOT_FOUND",
|
|
113
200
|
},
|
|
@@ -133,7 +220,8 @@ describe("buildHostedButtonOnApprove", () => {
|
|
|
133
220
|
|
|
134
221
|
// $FlowIssue
|
|
135
222
|
request.mockImplementation(() =>
|
|
136
|
-
|
|
223
|
+
// eslint-disable-next-line compat/compat
|
|
224
|
+
Promise.resolve({
|
|
137
225
|
body: {},
|
|
138
226
|
})
|
|
139
227
|
);
|
|
@@ -149,4 +237,33 @@ describe("buildHostedButtonOnApprove", () => {
|
|
|
149
237
|
);
|
|
150
238
|
expect.assertions(1);
|
|
151
239
|
});
|
|
240
|
+
|
|
241
|
+
test("with DPoP enabled", async () => {
|
|
242
|
+
const onApprove = buildHostedButtonOnApprove({
|
|
243
|
+
enableDPoP: true,
|
|
244
|
+
hostedButtonId,
|
|
245
|
+
merchantId,
|
|
246
|
+
});
|
|
247
|
+
request
|
|
248
|
+
// $FlowIssue
|
|
249
|
+
.mockImplementationOnce(mockCreateAccessTokenRequest)
|
|
250
|
+
.mockImplementation(() =>
|
|
251
|
+
// eslint-disable-next-line compat/compat
|
|
252
|
+
Promise.resolve({
|
|
253
|
+
body: {},
|
|
254
|
+
})
|
|
255
|
+
);
|
|
256
|
+
await onApprove({ orderID, paymentSource: "paypal" });
|
|
257
|
+
expect(request).toHaveBeenCalledWith(
|
|
258
|
+
expect.objectContaining({
|
|
259
|
+
headers: expect.objectContaining({
|
|
260
|
+
Authorization: `DPoP ${accessToken}`,
|
|
261
|
+
DPoP: expect.any(String),
|
|
262
|
+
}),
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
expect.assertions(1);
|
|
266
|
+
});
|
|
152
267
|
});
|
|
268
|
+
|
|
269
|
+
/* eslint-enable no-restricted-globals, promise/no-native */
|