@paypal/checkout-components
Advanced tools
Comparing version 5.0.345-alpha-714509c.0 to 5.0.345-alpha-bb62853.0
{ | ||
"name": "@paypal/checkout-components", | ||
"version": "5.0.345-alpha-714509c.0", | ||
"version": "5.0.345-alpha-bb62853.0", | ||
"description": "PayPal Checkout components, for integrating checkout products.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,3 +5,4 @@ /* @flow */ | ||
import { type LoggerType } from "@krakenjs/beaver-logger/src"; | ||
import { create, type ZoidComponent } from "@krakenjs/zoid/src"; | ||
import { type ZoidComponent } from "@krakenjs/zoid/src"; | ||
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src"; | ||
import { FPTI_KEY } from "@paypal/sdk-constants/src"; | ||
@@ -11,69 +12,12 @@ | ||
type MerchantPayloadData = {| | ||
amount: string, | ||
currency: string, | ||
nonce: string, | ||
threeDSRequested?: boolean, // do we want to keep this name or align it with other 3DS documentation | ||
transactionContext?: Object, | ||
// experience context | ||
|}; | ||
import { | ||
requestData, | ||
responseBody, | ||
Request, | ||
MerchantPayloadData, | ||
SdkConfig, | ||
threeDSResponse, | ||
} from "./types"; | ||
import { getThreeDomainSecureComponent } from "./utils"; | ||
// eslint-disable-next-line no-undef | ||
type Request = <TRequestData, TResponse>({| | ||
method?: string, | ||
url: string, | ||
// eslint-disable-next-line no-undef | ||
data: TRequestData, | ||
accessToken: ?string, | ||
// eslint-disable-next-line no-undef | ||
|}) => Promise<TResponse>; | ||
type requestData = {| | ||
intent: "THREE_DS_VERIFICATION", | ||
payment_source: {| | ||
card: {| | ||
single_use_token: string, | ||
verification_method: string, | ||
|}, | ||
|}, | ||
amount: {| | ||
currency_code: string, | ||
value: string, | ||
|}, | ||
transaction_context?: {| | ||
soft_descriptor?: string, | ||
|}, | ||
|}; | ||
type responseBody = {| | ||
payment_id: string, | ||
status: string, | ||
intent: string, | ||
payment_source: {| | ||
card: {| | ||
last_digits: string, | ||
type: string, | ||
name: string, | ||
expiry: string, | ||
|}, | ||
|}, | ||
amount: {| | ||
currency_code: string, | ||
value: string, | ||
|}, | ||
transaction_context: {| | ||
soft_descriptor: string, | ||
|}, | ||
links: $ReadOnlyArray<{| | ||
href: string, | ||
rel: string, | ||
method: string, | ||
|}>, | ||
|}; | ||
type SdkConfig = {| | ||
authenticationToken: ?string, | ||
paypalApiDomain: string, | ||
|}; | ||
const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => { | ||
@@ -98,11 +42,5 @@ if (!sdkConfig.authenticationToken) { | ||
|}): requestData => { | ||
// what validation on merchant input should we do here? | ||
// empty object | ||
const { threeDSRequested, amount, currency, nonce, transactionContext } = | ||
merchantPayload; | ||
// amount - validate that it's a string | ||
// currency - validate that it's a string | ||
// what validations are done on the API end - what client side validation is the API expecting | ||
return { | ||
@@ -128,3 +66,3 @@ intent: "THREE_DS_VERIFICATION", | ||
isEligible(): Promise<boolean>; | ||
show(): ZoidComponent<void>; | ||
show(): Promise<threeDSResponse>; | ||
} | ||
@@ -136,3 +74,3 @@ export class ThreeDomainSecureComponent { | ||
authenticationURL: string; | ||
threeDSIframe: ZoidComponent; | ||
constructor({ | ||
@@ -154,7 +92,7 @@ logger, | ||
const data = parseMerchantPayload({ merchantPayload }); | ||
try { | ||
// $FlowFixMe | ||
const { status, links } = await this.request<requestData, responseBody>({ | ||
method: "POST", | ||
url: `${this.sdkConfig.paypalApiDomain}/v2/payments/payment`, | ||
url: `https://te-test-qa.qa.paypal.com:12326/v2/payments/payment`, | ||
data, | ||
@@ -165,6 +103,11 @@ accessToken: this.sdkConfig.authenticationToken, | ||
let responseStatus = false; | ||
if (status === "PAYER_ACTION_REQUIRED") { | ||
this.authenticationURL = links[0].href; | ||
// check for rel = payer action inside the object | ||
this.authenticationURL = links.find( | ||
(link) => link.rel === "payer-action" | ||
).href; | ||
responseStatus = true; | ||
this.threeDSIframe = getThreeDomainSecureComponent( | ||
this.authenticationURL | ||
); | ||
} | ||
@@ -174,23 +117,49 @@ return responseStatus; | ||
this.logger.warn(error); | ||
return false; | ||
throw error; | ||
} | ||
} | ||
// change name to isContingent?? | ||
// will return true or false | ||
// if payer action required, return true. obtain link from response for show method - check length of links | ||
show(): Promise<threeDSResponse> { | ||
if (!this.threeDSIframe) { | ||
throw new ValidationError(`Ineligible for three domain secure`); | ||
return; | ||
} | ||
const promise = new ZalgoPromise(); | ||
const cancelThreeDS = () => { | ||
return ZalgoPromise.try(() => { | ||
// eslint-disable-next-line no-console | ||
console.log("cancelled"); | ||
}).then(() => { | ||
// eslint-disable-next-line no-use-before-define | ||
instance.close(); | ||
}); | ||
}; | ||
// if payer action not required, return false | ||
const instance = this.threeDSIframe({ | ||
onSuccess: (data) => { | ||
// const {threeDSRefID, authentication_status, liability_shift } = data; | ||
// let enrichedNonce; | ||
// if(threeDSRefID) { | ||
// enrichedNonce = await updateNonceWith3dsData(threeDSRefID, this.fastlaneNonce) | ||
// } | ||
// will make API request to v2/payments/pamyment endpoint with merchant payload an grab sdktoken as | ||
// bearer token | ||
// will need to handle errors from API response | ||
// What are the other options for status response and how do we handle them from a compliance standpoint | ||
// What do we do if we get a 500 error from the API? | ||
// do we throw an error or return false? | ||
return promise.resolve(data); | ||
}, | ||
onClose: cancelThreeDS, | ||
onError: (err) => { | ||
return promise.reject( | ||
new Error( | ||
`Error with obtaining 3DS contingency, ${JSON.stringify(err)}` | ||
) | ||
); | ||
}, | ||
}); | ||
const TARGET_ELEMENT = { | ||
BODY: "body", | ||
}; | ||
return instance | ||
.renderTo(window.parent, TARGET_ELEMENT.BODY) | ||
.then(() => promise) | ||
.finally(instance.close); | ||
} | ||
show() { | ||
create({ tag: "", url: "" }); | ||
} | ||
} |
/* @flow */ | ||
/* eslint-disable eslint-comments/disable-enable-pair */ | ||
/* eslint-disable no-restricted-globals, promise/no-native, compat/compat */ | ||
import { describe, expect, vi } from "vitest"; | ||
@@ -10,6 +12,20 @@ | ||
const defaultEligibilityResponse = { | ||
status: "PAYER_ACTION_REQUIRED", | ||
links: [{ href: "https://testurl.com", rel: "payer-action" }], | ||
}; | ||
const defaultMerchantPayload = { | ||
amount: "1.00", | ||
currency: "USD", | ||
nonce: "test-nonce", | ||
}; | ||
const mockEligibilityRequest = (body = defaultEligibilityResponse) => { | ||
return vi.fn().mockResolvedValue(body); | ||
}; | ||
const createThreeDomainSecureComponent = ({ | ||
sdkConfig = defaultSdkConfig, | ||
// $FlowFixMe | ||
request, | ||
request = mockEligibilityRequest(), | ||
logger = { | ||
@@ -26,2 +42,3 @@ info: vi.fn().mockReturnThis(), | ||
sdkConfig, | ||
// $FlowIssue | ||
request, | ||
@@ -37,22 +54,83 @@ // $FlowIssue | ||
describe("three domain secure component - isEligible method", () => { | ||
test.skip("should return false", async () => { | ||
// successful response | ||
// true for payer_action - false for Completed | ||
test("should return true if payer action required", async () => { | ||
const threeDomainSecureClient = createThreeDomainSecureComponent(); | ||
const eligibility = await threeDomainSecureClient.isEligible( | ||
defaultMerchantPayload | ||
); | ||
expect(eligibility).toEqual(true); | ||
}); | ||
// parameter validation | ||
// testing for negative parameter such as null or invalid value | ||
// error handling for API response | ||
// mock the getpaypalapidomain so that it always returns the value that we expect | ||
const threeDomainSecuretClient = createThreeDomainSecureComponent(); | ||
// $FlowFixMe | ||
const eligibility = await threeDomainSecuretClient.isEligible(); | ||
test("should return false if payer action is not returned", async () => { | ||
const threeDomainSecureClient = createThreeDomainSecureComponent({ | ||
request: () => | ||
Promise.resolve({ ...defaultEligibilityResponse, status: "SUCCESS" }), | ||
}); | ||
const eligibility = await threeDomainSecureClient.isEligible( | ||
defaultMerchantPayload | ||
); | ||
expect(eligibility).toEqual(false); | ||
}); | ||
test("should assign correct URL to authenticationURL", async () => { | ||
const threeDomainSecureClient = createThreeDomainSecureComponent({ | ||
request: () => | ||
Promise.resolve({ | ||
...defaultEligibilityResponse, | ||
links: [ | ||
{ href: "https://not-payer-action.com", rel: "not-payer-action" }, | ||
...defaultEligibilityResponse.links, | ||
], | ||
}), | ||
}); | ||
await threeDomainSecureClient.isEligible(defaultMerchantPayload); | ||
expect(threeDomainSecureClient.authenticationURL).toEqual( | ||
"https://testurl.com" | ||
); | ||
}); | ||
test("create payload with correctly parameters", async () => { | ||
const mockedRequest = mockEligibilityRequest(); | ||
const threeDomainSecureClient = createThreeDomainSecureComponent({ | ||
request: mockedRequest, | ||
}); | ||
await threeDomainSecureClient.isEligible(defaultMerchantPayload); | ||
expect(mockedRequest).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
data: expect.objectContaining({ | ||
intent: "THREE_DS_VERIFICATION", | ||
payment_source: expect.objectContaining({ | ||
card: expect.objectContaining({ | ||
single_use_token: defaultMerchantPayload.nonce, | ||
verification_method: "SCA_WHEN_REQUIRED", | ||
}), | ||
}), | ||
amount: expect.objectContaining({ | ||
currency_code: defaultMerchantPayload.currency, | ||
value: defaultMerchantPayload.amount, | ||
}), | ||
}), | ||
}) | ||
); | ||
}); | ||
test("catch errors from the API", async () => { | ||
const mockRequest = vi.fn().mockRejectedValue(new Error("Error with API")); | ||
const threeDomainSecureClient = createThreeDomainSecureComponent({ | ||
request: mockRequest, | ||
}); | ||
expect.assertions(2); | ||
await expect(() => | ||
threeDomainSecureClient.isEligible(defaultMerchantPayload) | ||
).rejects.toThrow(new Error("Error with API")); | ||
expect(mockRequest).toHaveBeenCalled(); | ||
}); | ||
}); | ||
describe("three domain descure component - show method", () => { | ||
test.skip("should return a zoid component", () => { | ||
const threeDomainSecuretClient = createThreeDomainSecureComponent(); | ||
threeDomainSecuretClient.show(); | ||
test.todo("should return a zoid component", () => { | ||
const threeDomainSecureClient = createThreeDomainSecureComponent(); | ||
threeDomainSecureClient.show(); | ||
// create test for zoid component | ||
@@ -59,0 +137,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1248729
204
17909