Compare commits

...

1 Commits

Author SHA1 Message Date
Ricardo Ambrogi
f037f82d0a Release v2.0.0 (#59)
* Update dependency webpack to v4.36.1

* Update dependency @types/node to v11.13.18

* Update babel monorepo to v7.5.5

* Update dependency eslint to v6.1.0

* Update typescript-eslint monorepo to v1.13.0

* Update dependency webpack to v4.37.0

* Update dependency webpack to v4.38.0

* Change 'code' to 'statusCode' on Exception

* Change base mock Promise.reject to throw

* Update README.md

* improve tests for checkout

* improve bin lookup tests

* improve checkout utility test

* improve payout tests

* improve terminal and recurring tests

* improve local terminal tests

* Update dependency @types/jest to v24.0.16

* add httpClient tests

* Pin dependency @types/nock to 10.0.3

* Update dependency nock to v11.0.0-beta.30

* Update dependency webpack to v4.39.0

* Update dependency nock to v11.0.0-beta.31

* Update dependency webpack to v4.39.1

* Fixes HTTP Proxy (#56)

* Fixes HTTP Proxy

* remove manual proxy config, adds http-proxy-agen libt

* add promise back to doPostRequest method

* Release v2.0.0 (#49)
2019-08-05 14:55:06 +02:00
32 changed files with 1216 additions and 595 deletions

View File

@@ -1,6 +1,6 @@
# Adyen Node.js API Library
[![Build Status](https://travis-ci.org/Adyen/adyen-node-api-library.svg?branch=master)](https://travis-ci.org/Adyen/adyen-node-api-library)
[![Coverage Status](https://coveralls.io/repos/github/Adyen/adyen-node-api-library/badge.svg?branch=feature/add-coveralls)](https://coveralls.io/github/Adyen/adyen-node-api-library?branch=feature/add-coveralls)
[![Coverage Status](https://coveralls.io/repos/github/Adyen/adyen-node-api-library/badge.svg?branch=master)](https://coveralls.io/github/Adyen/adyen-node-api-library?branch=master)
[![Downloads](https://img.shields.io/npm/dm/@adyen/api-library.svg)](https://www.npmjs.com/package/@adyen/api-library)
![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@adyen/api-library.svg)
[![Version](https://img.shields.io/npm/v/@adyen/api-library.svg)](https://www.npmjs.com/package/@adyen/api-library)

View File

@@ -1,6 +1,6 @@
{
"name": "@adyen/api-library",
"version": "1.1.1",
"version": "2.0.0",
"description": "The Adyen API Library for NodeJS enables you to work with Adyen APIs and Hosted Payment Pages.",
"main": "dist/lib/src/index.js",
"types": "dist/lib/src/index.d.ts",
@@ -37,24 +37,29 @@
"author": "Ricardo Ambrogi",
"license": "MIT",
"devDependencies": {
"@babel/core": "7.5.4",
"@babel/plugin-proposal-class-properties": "7.5.0",
"@babel/plugin-proposal-object-rest-spread": "7.5.4",
"@babel/plugin-transform-runtime": "7.5.0",
"@babel/preset-env": "7.5.4",
"@babel/core": "7.5.5",
"@babel/plugin-proposal-class-properties": "7.5.5",
"@babel/plugin-proposal-object-rest-spread": "7.5.5",
"@babel/plugin-transform-runtime": "7.5.5",
"@babel/preset-env": "7.5.5",
"@babel/preset-typescript": "7.3.3",
"@babel/runtime": "7.5.4",
"@types/jest": "24.0.15",
"@types/node": "11.13.17",
"@typescript-eslint/eslint-plugin": "1.12.0",
"@typescript-eslint/parser": "1.12.0",
"@babel/runtime": "7.5.5",
"@types/jest": "24.0.16",
"@types/nock": "10.0.3",
"@types/node": "11.13.18",
"@typescript-eslint/eslint-plugin": "1.13.0",
"@typescript-eslint/parser": "1.13.0",
"babel-loader": "8.0.6",
"eslint": "6.0.1",
"coveralls": "3.0.5",
"eslint": "6.1.0",
"jest": "24.8.0",
"nock": "11.0.0-beta.31",
"ts-loader": "6.0.4",
"typescript": "3.5.3",
"webpack": "4.35.3",
"webpack": "4.39.1",
"webpack-cli": "3.3.6"
},
"dependencies": {
"https-proxy-agent": "2.2.2"
}
}

View File

@@ -21,7 +21,6 @@
import Client from "../client";
import Config from "../config";
import HttpURLConnectionClient from "../httpClient/httpURLConnectionClient";
import {
AmountsReq,
MessageCategoryType,
@@ -35,38 +34,17 @@ import {
TerminalApiRequest,
TransactionIdentification,
} from "../typings/terminal";
import HttpClientException from "../httpClient/httpClientException";
jest.mock("../httpClient/httpURLConnectionClient");
interface Options { code: number }
export const createMockClientFromResponse = (response: string, { code }: Options = {code: 200}): Client => {
const httpURLConnectionClient: HttpURLConnectionClient = new HttpURLConnectionClient();
// @ts-ignore
httpURLConnectionClient.request.mockImplementation(
(endpoint: string, json: string, config: Config, isApiRequired: boolean): Promise<string> => {
if (
typeof endpoint === "string" &&
typeof json === "string" &&
config instanceof Config &&
(isApiRequired ? typeof isApiRequired === "boolean" : true) &&
code >= 200 && code < 300
) {
return Promise.resolve(response);
} else {
return Promise.reject(new HttpClientException(response, code));
}
}
);
export const createMockClientFromResponse = (): Client => {
const config: Config = new Config();
config.terminalApiCloudEndpoint = Client.TERMINAL_API_ENDPOINT_TEST;
config.terminalApiLocalEndpoint = "https://mocked_local_endpoint.com";
config.hmacKey = "DFB1EB5485895CFA84146406857104ABB4CBCABDC8AAF103A624C8F6A3EAAB00";
config.endpoint = Client.ENDPOINT_TEST;
config.checkoutEndpoint = Client.CHECKOUT_ENDPOINT_TEST;
config.apiKey = "MOCKED_API_KEY";
const client: Client = new Client({ config });
client.httpClient = httpURLConnectionClient;
return client;
};

View File

@@ -1,7 +1,7 @@
/* tslint:disable */
export const paymentSessionError = JSON.stringify({
status: 422,
export const paymentSessionError = {
statusCode: 422,
errorCode: "14_012",
message: "The provided SDK token could not be parsed.",
errorType: "validation",
});
};

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
export const paymentMethodsError = JSON.stringify({
export const paymentMethodsError = {
errorCode: "901",
errorType: "security",
message: "Invalid Merchant Account",
status: 403,
});
statusMessage: "Invalid Merchant Account",
statusCode: 403,
};

View File

@@ -1,7 +1,7 @@
/* tslint:disable */
export const paymentDetailsError = JSON.stringify({
status: 422,
export const paymentDetailsError = {
statusCode: 422,
errorCode: "101",
message: "Invalid card number",
errorType: "validation",
});
};

View File

@@ -1,7 +1,7 @@
/* tslint:disable */
export const paymentsError = JSON.stringify({
status: 422,
statusCode: 422,
errorCode: "130",
message: "Reference Missing",
statusMessage: "Reference Missing",
errorType: "validation",
});

View File

@@ -1,6 +1,6 @@
/* tslint:disable */
export const paymentsResultError = JSON.stringify({
status: 422,
statusCode: 422,
errorCode: "14_018",
message: "Invalid payload provided",
errorType: "validation",

View File

@@ -1,5 +1,5 @@
/* tslint:disable */
export const paymentsResultMultibancoSuccess = JSON.stringify({
export const paymentsResultMultibancoSuccess = {
additionalData: {
"cvcResult": "0",
"avsResult": "0",
@@ -12,4 +12,4 @@ export const paymentsResultMultibancoSuccess = JSON.stringify({
},
pspReference: "8111111111111111",
resultCode: "Received",
});
};

View File

@@ -1,3 +1,3 @@
export const disableSuccess = JSON.stringify({
export const disableSuccess = {
response: "[detail-successfully-disabled]",
});
};

View File

@@ -1,5 +1,5 @@
export const listRecurringDetailsSuccess = JSON.stringify({
creationDate: new Date("2017-03-01T11:53:11+01:00"),
export const listRecurringDetailsSuccess = {
creationDate: "2017-03-01T10:53:11.000",
details: [
{
additionalData: {
@@ -16,7 +16,7 @@ export const listRecurringDetailsSuccess = JSON.stringify({
contractTypes: [
"ONECLICK",
],
creationDate: new Date("2017-03-07T09:43:33+01:00"),
creationDate: "2017-03-01T10:53:11.000",
firstPspReference: "8524888762135795",
paymentMethodVariant: "visa",
recurringDetailReference: "recurringReference",
@@ -34,7 +34,7 @@ export const listRecurringDetailsSuccess = JSON.stringify({
contractTypes: [
"RECURRING",
],
creationDate: new Date("2017-10-10T08:50:02+02:00"),
creationDate: "2017-03-01T10:53:11.000",
firstPspReference: "8515076181707110",
paymentMethodVariant: "paypal",
recurringDetailReference: "8315076181982020",
@@ -49,4 +49,4 @@ export const listRecurringDetailsSuccess = JSON.stringify({
variant: "paypal",
},
],
});
};

View File

@@ -1,4 +1,334 @@
export const localRes = JSON.stringify({
export const localSecuredRes = JSON.stringify({
SaleToPOIResponse: {
MessageHeader: {
MessageCategory: "Payment",
MessageClass: "Service",
MessageType: "Response",
POIID: "P400Plus-275039202",
ProtocolVersion: "3.0",
SaleID: "325488592",
ServiceID: "325488592"
},
paymentResponse: {
paymentReceipt: [
{
documentQualifier: "CashierReceipt",
outputContent: {
outputFormat: "Text",
outputText: [
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "key=header1"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "key=header2"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=MERCHANT%20COPY&key=merchantTitle"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Date&value=08%2f05%2f19&key=txdate"
},
{
endOfLineFlag: true,
text: "name=Time&value=15%3a25%3a15&key=txtime"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Card&value=%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a0010&key=pan"
},
{
endOfLineFlag: true,
text: "name=PAN%20seq.&value=01&key=panSeq"
},
{
endOfLineFlag: true,
text: "name=Pref.%20name&value=PPC%20MCD%2001%20v2%202&key=preferredName"
},
{
endOfLineFlag: true,
text: "name=Card%20type&value=mc&key=cardType"
},
{
endOfLineFlag: true,
text: "name=Payment%20method&value=mc&key=paymentMethod"
},
{
endOfLineFlag: true,
text: "name=Payment%20variant&value=mc&key=paymentMethodVariant"
},
{
endOfLineFlag: true,
text: "name=Entry%20mode&value=Contactless%20chip&key=posEntryMode"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=AID&value=A0000000041010&key=aid"
},
{
endOfLineFlag: true,
text: "name=MID&value=1000&key=mid"
},
{
endOfLineFlag: true,
text: "name=TID&value=P400Plus-275039202&key=tid"
},
{
endOfLineFlag: true,
text: "name=PTID&value=75039202&key=ptid"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Auth.%20code&value=123456&key=authCode"
},
{
endOfLineFlag: true,
text: "name=Tender&value=4r7i001557325515012&key=txRef"
},
{
endOfLineFlag: true,
text: "name=Reference&value=999&key=mref"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Type&value=GOODS_SERVICES&key=txtype"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=TOTAL&value=%e2%82%ac%c2%a01.00&key=totalAmount"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=APPROVED&key=approved"
}
]
},
requiredSignatureFlag: false
},
{
documentQualifier: "CustomerReceipt",
outputContent: {
outputFormat: "Text",
outputText: [
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "key=header1"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "key=header2"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=CARDHOLDER%20COPY&key=cardholderHeader"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Date&value=08%2f05%2f19&key=txdate"
},
{
endOfLineFlag: true,
text: "name=Time&value=15%3a25%3a15&key=txtime"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Card&value=%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a%2a0010&key=pan"
},
{
endOfLineFlag: true,
text: "name=PAN%20seq.&value=01&key=panSeq"
},
{
endOfLineFlag: true,
text: "name=Pref.%20name&value=PPC%20MCD%2001%20v2%202&key=preferredName"
},
{
endOfLineFlag: true,
text: "name=Card%20type&value=mc&key=cardType"
},
{
endOfLineFlag: true,
text: "name=Payment%20method&value=mc&key=paymentMethod"
},
{
endOfLineFlag: true,
text: "name=Payment%20variant&value=mc&key=paymentMethodVariant"
},
{
endOfLineFlag: true,
text: "name=Entry%20mode&value=Contactless%20chip&key=posEntryMode"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=AID&value=A0000000041010&key=aid"
},
{
endOfLineFlag: true,
text: "name=MID&value=1000&key=mid"
},
{
endOfLineFlag: true,
text: "name=TID&value=P400Plus-275039202&key=tid"
},
{
endOfLineFlag: true,
text: "name=PTID&value=75039202&key=ptid"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Auth.%20code&value=123456&key=authCode"
},
{
endOfLineFlag: true,
text: "name=Tender&value=4r7i001557325515012&key=txRef"
},
{
endOfLineFlag: true,
text: "name=Reference&value=999&key=mref"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Type&value=GOODS_SERVICES&key=txtype"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=TOTAL&value=%e2%82%ac%c2%a01.00&key=totalAmount"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
characterStyle: "Bold",
endOfLineFlag: true,
text: "name=APPROVED&key=approved"
},
{
endOfLineFlag: true,
text: "key=filler"
},
{
endOfLineFlag: true,
text: "name=Please%20retain%20for%20your%20records&key=retain"
},
{
endOfLineFlag: true,
text: "name=Thank%20you&key=thanks"
}
]
},
requiredSignatureFlag: false
}
],
paymentResult: {
amountsResp: {
authorizedAmount: 1,
currency: "EUR"
},
onlineFlag: true,
paymentAcquirerData: {
acquirerPoiid: "P400Plus-275039202",
acquirerTransactionId: {
timeStamp: "2019-05-08T14:25:15.000Z",
transactionId: "8815573255107661"
},
approvalCode: "123456",
merchantId: "TestMerchantRenatoTest"
},
paymentInstrumentData: {
cardData: {
cardCountryCode: "056",
entryMode: [
"Contactless"
],
maskedPan: "541333 **** 0010",
paymentBrand: "mc",
sensitiveCardData: {
cardSeqNumb: "01",
expiryDate: "1225"
}
},
paymentInstrumentType: "Card"
}
},
poiData: {
poiReconciliationId: "1000",
poiTransactionId: {
timeStamp: "2019-05-08T14:25:15.000Z",
transactionId: "4r7i001557325515012.8815573255107661"
}
},
response: {
additionalResponse: "tid=75039202&AID=A0000000041010&transactionType=GOODS_SERVICES&backendGiftcardIndicator=false&expiryYear=2025&acquirerAccountCode=TestPmmAcquirerAccount&alias=K182596230843790&posOriginalAmountCurrency=EUR&giftcardIndicator=false&authorisedAmountValue=100&pspReference=8815573255107661&paymentMethodVariant=mc&cardHolderName=N%2fA&refusalReasonRaw=APPROVED&authorisationMid=1000&expiryDate=12%2f2025&applicationPreferredName=PPC%20MCD%2001%20v2%202&isCardCommercial=unknown&acquirerCode=TestPmmAcquirer&txtime=15%3a25%3a15&iso8601TxDate=2019-05-08T14%3a25%3a15.0000000%2b0000&cardType=mc&posOriginalAmountValue=100&offline=false&aliasType=Default&txdate=08-05-2019&paymentMethod=mc&cvcResult=0%20Unknown&startYear=2030&tc=A767D7547D930504&avsResult=0%20Unknown&cardIssueNumber=1&mid=1000&merchantReference=999&transactionReferenceNumber=8815573255107661&expiryMonth=12&cardSummary=0010&posTotalAmountValue=100&posAuthAmountCurrency=EUR&cardHolderVerificationMethodResults=1F0302&authCode=123456&cardIssuerCountryId=056&shopperCountry=NL&posEntryMode=CLESS_CHIP&startMonth=34&fundingSource=CREDIT&cardScheme=mc&cardBin=541333&posAuthAmountValue=100",
result: "Success"
},
saleData: {
saleTransactionId: {
timeStamp: "2019-05-08T14:24:48.598Z",
transactionId: "999"
}
}
}
}
});
export const localEncRes = JSON.stringify({
SaleToPOIResponse: {
MessageHeader: {
MessageCategory: "Payment",
@@ -105,3 +435,111 @@ export const localRes = JSON.stringify({
},
},
});
export const wrongEncRes = JSON.stringify({
SaleToPOIResponse: {
MessageHeader: {
MessageCategory: "Payment",
MessageClass: "Service",
MessageType: "Response",
POIID: "P400Plus-275039202",
ProtocolVersion: "3.0",
SaleID: "325488592",
ServiceID: "325488592",
},
NexoBlob: `WRONG-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`,
SecurityTrailer: {
AdyenCryptoVersion: 1,
Hmac: "l+5/pYiAbC0V9Xx78ELNDcLMaqTlqx2OyGha37i/g5g=",
KeyIdentifier: "CryptoKeyIdentifier12345",
KeyVersion: 1,
Nonce: "9iiJMpzKfYs3106ozIKNFQ==",
},
},
});

View File

@@ -18,9 +18,12 @@
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/
import nock from "nock";
import { createMockClientFromResponse } from "../__mocks__/base";
import BinLookup from "../service/binLookup";
import {CostEstimateRequest, ThreeDSAvailabilityRequest, ThreeDSAvailabilityResponse} from "../typings/binLookup";
import {CostEstimateRequest, ThreeDSAvailabilityRequest} from "../typings/binLookup";
import Client from "../client";
import HttpClientException from "../httpClient/httpClientException";
const threeDSAvailabilitySuccess = {
dsPublicKeys: [{
@@ -39,58 +42,56 @@ const threeDSAvailabilitySuccess = {
threeDS2supported: true
};
let client: Client;
let binLookup: BinLookup;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
binLookup = new BinLookup(client);
scope = nock(`${client.config.endpoint}${Client.BIN_LOOKUP_PAL_SUFFIX}${Client.BIN_LOOKUP_API_VERSION}`);
});
describe("Bin Lookup", function (): void {
it("should succeed on get 3ds availability", async function (): Promise<void> {
const client = createMockClientFromResponse(JSON.stringify(threeDSAvailabilitySuccess));
const binLookup = new BinLookup(client);
const threeDSAvailabilityRequest: ThreeDSAvailabilityRequest = {
merchantAccount: client.config.merchantAccount,
merchantAccount: "MOCK_MERCHANT_ACCOUNT",
brands: ["randomBrand"],
cardNumber: "4111111111111111"
};
const {
dsPublicKeys,
threeDS2CardRangeDetails,
threeDS1Supported
}: ThreeDSAvailabilityResponse = await binLookup.get3dsAvailability(threeDSAvailabilityRequest);
expect(dsPublicKeys[0].brand).toEqual("visa");
expect(threeDS2CardRangeDetails[0].brandCode).toEqual("visa");
expect(threeDS1Supported).toEqual(true);
scope.post("/get3dsAvailability")
.reply(200, threeDSAvailabilitySuccess);
const response = await binLookup.get3dsAvailability(threeDSAvailabilityRequest);
expect(response).toEqual(threeDSAvailabilitySuccess);
});
it("should have invalid merchant", async function (): Promise<void> {
const client = createMockClientFromResponse(JSON.stringify({
status: 403,
errorCode: "901",
message: "Invalid Merchant Account",
errorType: "security"
}), {code: 403});
const binLookup = new BinLookup(client);
const threeDSAvailabilityRequest: ThreeDSAvailabilityRequest = {
it("should fail with invalid merchant", async function (): Promise<void> {
const threeDSAvailabilityRequest: { [key: string]: undefined|string|[] } = {
merchantAccount: undefined,
cardNumber: "4111111111111",
brands: []
};
scope.post("/get3dsAvailability")
.reply(403);
try {
await binLookup.get3dsAvailability(threeDSAvailabilityRequest);
await binLookup.get3dsAvailability(threeDSAvailabilityRequest as unknown as ThreeDSAvailabilityRequest);
fail("Expected request to fail");
} catch (e) {
expect(e.statusCode).toEqual(403);
expect(JSON.parse(e.message).errorCode).toEqual("901");
expect(e instanceof HttpClientException).toBeTruthy();
}
});
it("should succeed on get cost estimate", async function (): Promise<void> {
const client = createMockClientFromResponse(JSON.stringify({
const response = {
cardBin: {summary: "1111"},
resultCode: "Unsupported",
surchargeType: "ZERO"
}));
const binLookup = new BinLookup(client);
};
const costEstimateRequest: CostEstimateRequest = {
amount: { currency: "EUR", value: 1000 },
assumptions: {
@@ -98,7 +99,7 @@ describe("Bin Lookup", function (): void {
assume3DSecureAuthenticated: true
},
cardNumber: "411111111111",
merchantAccount: client.config.merchantAccount,
merchantAccount: "MOCKED_MERCHANT_ACC",
merchantDetails: {
countryCode: "NL",
mcc: "7411",
@@ -107,10 +108,11 @@ describe("Bin Lookup", function (): void {
shopperInteraction: "Ecommerce"
};
const {cardBin, resultCode, surchargeType} = await binLookup.getCostEstimate(costEstimateRequest);
scope.post("/getCostEstimate")
.reply(200, response);
expect(cardBin.summary).toEqual("1111");
expect(resultCode).toEqual("Unsupported");
expect(surchargeType).toEqual("ZERO");
const expected = await binLookup.getCostEstimate(costEstimateRequest);
expect(response).toEqual(expected);
});
});

View File

@@ -19,16 +19,12 @@
* See the LICENSE file for more info.
*/
import nock from "nock";
import { createMockClientFromResponse } from "../__mocks__/base";
import {paymentMethodsError} from "../__mocks__/checkout/paymentmethodsErrorForbidden403";
import {paymentMethodsSuccess} from "../__mocks__/checkout/paymentMethodsSuccess";
import {paymentsError} from "../__mocks__/checkout/paymentsErrorInvalidData422";
import {paymentsSuccess} from "../__mocks__/checkout/paymentsSuccess";
import {paymentDetailsError} from "../__mocks__/checkout/paymentsDetailsErrorInvalidData422";
import {paymentDetailsSuccess} from "../__mocks__/checkout/paymentsDetailsSuccess";
import {paymentSessionError} from "../__mocks__/checkout/paymentSessionErrorInvalidData422";
import {paymentSessionSuccess} from "../__mocks__/checkout/paymentSessionSucess";
import {paymentsResultError} from "../__mocks__/checkout/paymentsResultErrorInvalidDataPayload422";
import {paymentsResultMultibancoSuccess} from "../__mocks__/checkout/paymentsResultMultibancoSuccess";
import {paymentsResultSuccess} from "../__mocks__/checkout/paymentsResultSucess";
import Client from "../client";
@@ -42,6 +38,7 @@ import {
PaymentResponse,
PaymentSetupRequest, PaymentVerificationRequest
} from "../typings/checkout";
import HttpClientException from "../httpClient/httpClientException";
function createAmountObject(currency: string, value: number): Amount {
return {
@@ -89,76 +86,75 @@ function createPaymentSessionRequest(): PaymentSetupRequest {
};
}
let client: Client;
let checkout: Checkout;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
scope = nock(`${client.config.checkoutEndpoint}/${Client.CHECKOUT_API_VERSION}`);
checkout = new Checkout(client);
});
describe("Checkout", (): void => {
it("should make a payment", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentsSuccess);
const checkout: Checkout = new Checkout(client);
scope.post("/payments")
.reply(200, paymentsSuccess);
const paymentsRequest: PaymentRequest = createPaymentsCheckoutRequest();
const paymentsResponse: PaymentResponse = await checkout.payments(paymentsRequest);
expect(paymentsResponse.pspReference).toEqual("8535296650153317");
});
it("should not make a payment", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentsError);
const checkout: Checkout = new Checkout(client);
const paymentsRequest: PaymentRequest = createPaymentsCheckoutRequest();
const paymentsResponse: PaymentResponse = await checkout.payments(paymentsRequest);
expect(paymentsResponse.pspReference).toBeUndefined();
it("should return correct Exception", async (): Promise<void> => {
try {
scope.post("/payments")
.reply(401);
const paymentsRequest: PaymentRequest = createPaymentsCheckoutRequest();
await checkout.payments(paymentsRequest);
} catch (e) {
expect(e instanceof HttpClientException).toBeTruthy();
}
});
it("should have valid payment methods", async (): Promise<void> => {
const client = createMockClientFromResponse(paymentMethodsSuccess);
const checkout: Checkout = new Checkout(client);
const paymentMethodsRequest: PaymentMethodsRequest = {
merchantAccount: "MagentoMerchantTest",
};
const paymentMethodsResponse = await checkout.paymentMethods(paymentMethodsRequest);
expect(paymentMethodsResponse.paymentMethods.length).toEqual(65);
expect(paymentMethodsResponse.paymentMethods[0].name).toEqual("AliPay");
});
const paymentMethodsRequest: PaymentMethodsRequest = {merchantAccount: "MagentoMerchantTest"};
scope.post("/paymentMethods")
.reply(200, paymentMethodsSuccess);
it("should not have valid payment methods", async (): Promise<void> => {
const client = createMockClientFromResponse(paymentMethodsError);
const checkout: Checkout = new Checkout(client);
const paymentMethodsRequest: PaymentMethodsRequest = {
merchantAccount: "MagentoMerchantTest",
};
const paymentMethodsResponse = await checkout.paymentMethods(paymentMethodsRequest);
expect(paymentMethodsResponse.paymentMethods).toBeUndefined();
if (paymentMethodsResponse && paymentMethodsResponse.paymentMethods) {
expect(paymentMethodsResponse.paymentMethods.length).toEqual(65);
expect(paymentMethodsResponse.paymentMethods[0].name).toEqual("AliPay");
} else {
fail();
}
});
it("should have payment details", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentDetailsSuccess);
const checkout: Checkout = new Checkout(client);
scope.post("/payments/details")
.reply(200, paymentDetailsSuccess);
const paymentsResponse = await checkout.paymentsDetails(createPaymentsDetailsRequest());
expect(paymentsResponse.resultCode).toEqual("Authorised");
});
it("should not have payment details", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentDetailsError);
const checkout: Checkout = new Checkout(client);
const paymentsResponse = await checkout.paymentsDetails(createPaymentsDetailsRequest());
expect(paymentsResponse.resultCode).toBeUndefined();
});
it("should have payment session success", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentSessionSuccess);
const client: Client = createMockClientFromResponse();
scope.post("/paymentSession")
.reply(200, paymentSessionSuccess);
const checkout: Checkout = new Checkout(client);
const paymentSessionRequest: PaymentSetupRequest = createPaymentSessionRequest();
const paymentSessionResponse = await checkout.paymentSession(paymentSessionRequest);
expect(paymentSessionResponse.paymentSession).not.toBeUndefined();
});
it("should not have payment session success", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentSessionError);
const checkout: Checkout = new Checkout(client);
const paymentSessionRequest: PaymentSetupRequest = createPaymentSessionRequest();
const paymentSessionResponse = await checkout.paymentSession(paymentSessionRequest);
expect(paymentSessionResponse.paymentSession).toBeUndefined();
});
it("should have payments result", async (): Promise<void> => {
const client = createMockClientFromResponse(paymentsResultSuccess);
const client = createMockClientFromResponse();
scope.post("/payments/result")
.reply(200, paymentsResultSuccess);
const checkout = new Checkout(client);
const paymentResultRequest: PaymentVerificationRequest = {
payload: "This is a test payload",
@@ -167,19 +163,9 @@ describe("Checkout", (): void => {
expect(paymentResultResponse.resultCode).toEqual("Authorised");
});
it("should not have payments result", async (): Promise<void> => {
const client = createMockClientFromResponse(paymentsResultError);
const checkout = new Checkout(client);
const paymentResultRequest: PaymentVerificationRequest = {
payload: "This is a test payload",
};
const paymentResultResponse = await checkout.paymentResult(paymentResultRequest);
expect(paymentResultResponse.resultCode).toBeUndefined();
});
it("should have missing identifier on live", async (): Promise<void> => {
const client = createMockClientFromResponse(paymentsResultError);
client.setEnvironment("TEST");
const client = createMockClientFromResponse();
client.setEnvironment("LIVE");
try {
new Checkout(client);
} catch (e) {
@@ -187,48 +173,12 @@ describe("Checkout", (): void => {
}
});
it("should have custom payment details", async (): Promise<void> => {
const paymentsRequest = createPaymentsCheckoutRequest();
expect(JSON.parse("{\n"
+ " \"amount\": {\n"
+ " \"value\": 1000,\n"
+ " \"currency\": \"USD\"\n"
+ " },\n"
+ " \"merchantAccount\": \"MagentoMerchantTest\",\n"
+ " \"paymentMethod\": {\n"
+ " \"type\": \"scheme\",\n"
+ " \"number\": \"4111111111111111\",\n"
+ " \"expiryMonth\": \"10\",\n"
+ " \"expiryYear\": \"2018\",\n"
+ " \"holderName\": \"John Smith\",\n"
+ " \"cvc\": \"737\"\n"
+ " },\n"
+ " \"reference\": \"Your order number\",\n"
+ " \"returnUrl\": \"https://your-company.com/...\"\n"
+ "}")).toEqual(paymentsRequest);
paymentsRequest.paymentMethod = {
testKey: "testValue",
type: "testType",
};
expect(JSON.parse("{\n"
+ " \"amount\": {\n"
+ " \"value\": 1000,\n"
+ " \"currency\": \"USD\"\n"
+ " },\n"
+ " \"merchantAccount\": \"MagentoMerchantTest\",\n"
+ " \"paymentMethod\": {\n"
+ " \"testKey\": \"testValue\",\n"
+ " \"type\": \"testType\"\n"
+ " },\n"
+ " \"reference\": \"Your order number\",\n"
+ " \"returnUrl\": \"https://your-company.com/...\"\n"
+ "}")).toEqual(JSON.parse(JSON.stringify(paymentsRequest)));
});
it("should succeed on multibanco payment", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(paymentsResultMultibancoSuccess);
const client: Client = createMockClientFromResponse();
scope.post("/payments")
.reply(200, paymentsResultMultibancoSuccess);
const checkout: Checkout = new Checkout(client);
const paymentsRequest: PaymentRequest = createPaymentsCheckoutRequest();
const paymentsResponse: PaymentResponse = await checkout.payments(paymentsRequest);
@@ -237,31 +187,5 @@ describe("Checkout", (): void => {
expect(paymentsResponse.additionalData["comprafacil.deadline"]).toEqual("3");
expect(paymentsResponse.additionalData["comprafacil.entity"]).toEqual("12345");
});
it("should return sepa payment method details", async (): Promise<void> => {
const defaultPaymentMethods = {
sepaIbanNumber: "DE87123456781234567890",
sepaOwnerName: "A. Schneider",
type: "sepadirectdebit",
};
const paymentsRequest = createPaymentsCheckoutRequest();
paymentsRequest.paymentMethod = defaultPaymentMethods;
expect(JSON.parse("{\n"
+ " \"amount\": {\n"
+ " \"value\": 1000,\n"
+ " \"currency\": \"USD\"\n"
+ " },\n"
+ " \"merchantAccount\": \"MagentoMerchantTest\",\n"
+ " \"paymentMethod\": {\n"
+ " \"type\": \"sepadirectdebit\",\n"
+ " \"sepaOwnerName\": \"A. Schneider\",\n"
+ " \"sepaIbanNumber\": \"DE87123456781234567890\"\n"
+ " },\n"
+ " \"reference\": \"Your order number\",\n"
+ " \"returnUrl\": \"https://your-company.com/...\"\n"
+ "}")).toEqual(JSON.parse(JSON.stringify(paymentsRequest)));
});
});

View File

@@ -1,15 +1,43 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen NodeJS API Library
*
* Copyright (c) 2019 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/
import nock from "nock";
import { createMockClientFromResponse } from "../__mocks__/base";
import {originKeysSuccess} from "../__mocks__/checkoutUtility/originkeysSuccess";
import CheckoutUtility from "../service/checkoutUtility";
import {CheckoutUtilityRequest} from "../typings/checkoutUtility";
import Client from "../client";
describe("Checkout Utility", (): void => {
it("should get origin keys", async (): Promise<void> => {
const client = createMockClientFromResponse(originKeysSuccess);
const client = createMockClientFromResponse();
const checkoutUtility = new CheckoutUtility(client);
const originKeysRequest: CheckoutUtilityRequest = {
originDomains: ["www.test.com", "https://www.your-domain2.com"],
};
nock(`${client.config.checkoutEndpoint}`)
.post(`/${Client.CHECKOUT_UTILITY_API_VERSION}/originKeys`)
.reply(200, originKeysSuccess);
const originKeysResponse = await checkoutUtility.originKeys(originKeysRequest);
expect(originKeysResponse.originKeys["https://www.your-domain1.com"])
.toEqual("pub.v2.7814286629520534.aHR0cHM6Ly93d3cueW91ci1kb21haW4xLmNvbQ.UEwIBmW9-c_uXo5wSEr2w8Hz8hVIpujXPHjpcEse3xI");

View File

@@ -0,0 +1,42 @@
import nock from "nock";
import Client from "../client";
import Checkout from "../service/checkout";
import ApiException from "../service/exception/apiException";
beforeEach((): void => {
nock.cleanAll();
});
describe("HTTP Client", function (): void {
it("should return ApiException when no API Key is provided", async (): Promise<void> => {
const client = new Client({apiKey: "", environment: "TEST"});
const checkout = new Checkout(client);
nock(`${client.config.checkoutEndpoint}/${Client.CHECKOUT_API_VERSION}`)
.post("/payments")
.replyWithError();
try {
await checkout.payments({});
} catch (e) {
expect(e instanceof ApiException);
expect(e.message).toContain("x-api-key");
}
});
it("should return ApiException on request error", async (): Promise<void> => {
const client = new Client({apiKey: "API_KEY", environment: "TEST"});
const checkout = new Checkout(client);
nock(`${client.config.checkoutEndpoint}/${Client.CHECKOUT_API_VERSION}`)
.post("/payments")
.replyWithError({message: "error_message", statusCode: 500});
try {
await checkout.payments({});
} catch (e) {
expect(e instanceof ApiException);
expect(e.message).toEqual("error_message");
}
});
});

View File

@@ -1,3 +1,4 @@
import nock from "nock";
import { createMockClientFromResponse } from "../__mocks__/base";
import Payout from "../service/payout";
import {
@@ -6,6 +7,7 @@ import {
StoreDetailRequest, SubmitRequest
} from "../typings/payout";
import { FRAUD_MANUAL_REVIEW, FRAUD_RESULT_TYPE } from "../typings/constants/apiConstants";
import Client from "../client";
const storeDetailAndSubmitThirdParty = JSON.stringify({
additionalData: {
@@ -64,12 +66,20 @@ const mockStoreDetailAndSubmitRequest = (merchantAccount: string): StoreDetailAn
});
let client: Client;
let payout: Payout;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
scope = nock(`${client.config.endpoint}/pal/servlet/Payout/${Client.API_VERSION}`);
payout = new Payout(client);
});
describe("PayoutTest", function (): void {
it("should succeed on store detail and submit third party", async function (): Promise<void> {
const client = createMockClientFromResponse(storeDetailAndSubmitThirdParty);
const payout = new Payout(client);
const request: StoreDetailAndSubmitRequest = mockStoreDetailAndSubmitRequest(client.config.merchantAccount);
const request: StoreDetailAndSubmitRequest = mockStoreDetailAndSubmitRequest(`${client.config.merchantAccount}`);
scope.post("/storeDetail").reply(200, storeDetailAndSubmitThirdParty);
const result = await payout.storeDetail(request);
expect(result.resultCode).toEqual("[payout-submit-received]");
@@ -79,10 +89,8 @@ describe("PayoutTest", function (): void {
});
it("should succeed on store detail", async function (): Promise<void> {
const client = createMockClientFromResponse(storeDetail);
const payout = new Payout(client);
const request: StoreDetailRequest = mockStoreDetailRequest(client.config.merchantAccount);
scope.post("/storeDetail").reply(200, storeDetail);
const request: StoreDetailRequest = mockStoreDetailRequest("MOCKED_MERCHANT_ACC");
const result = await payout.storeDetail(request);
expect("Success").toEqual(result.resultCode);
@@ -91,14 +99,14 @@ describe("PayoutTest", function (): void {
});
it("should succeed on confirm third party", async function (): Promise<void> {
const client = createMockClientFromResponse(JSON.stringify({
pspReference: "8815131762537886",
response: "[payout-confirm-received]"
}));
const payout = new Payout(client);
scope.post("/confirmThirdParty")
.reply(200, {
pspReference: "8815131762537886",
response: "[payout-confirm-received]"
});
const request: ModifyRequest = {
merchantAccount: client.config.merchantAccount,
merchantAccount: "MOCKED_MERCHANT_ACCOUNT",
originalReference: "reference"
};
const result = await payout.confirmThirdParty(request);
@@ -108,10 +116,9 @@ describe("PayoutTest", function (): void {
});
it("should succeed on submit third party", async function (): Promise<void> {
const client = createMockClientFromResponse(storeDetailAndSubmitThirdParty);
const payout = new Payout(client);
scope.post("/submitThirdParty").reply(200, storeDetailAndSubmitThirdParty);
const request: SubmitRequest = mockSubmitRequest(client.config.merchantAccount);
const request: SubmitRequest = mockSubmitRequest("MOCKED_MERCHANT_ACC");
const result = await payout.submitThirdparty(request);
expect(result.resultCode).toEqual("[payout-submit-received]");
@@ -121,14 +128,13 @@ describe("PayoutTest", function (): void {
});
it("should succeed on decline third party", async function (): Promise<void> {
const client = createMockClientFromResponse(JSON.stringify({
scope.post("/storeDetailAndSubmitThirdParty").reply(200, {
pspReference: "8815131762537886",
response: "[payout-confirm-received]"
}));
const payout = new Payout(client);
});
const request: ModifyRequest = {
merchantAccount: client.config.merchantAccount,
merchantAccount: "MOCKED_MERCHANT_ACC",
originalReference: "reference"
};
const result = await payout.declineThirdParty(request);

View File

@@ -1,8 +1,10 @@
import nock from "nock";
import { createMockClientFromResponse } from "../__mocks__/base";
import { disableSuccess } from "../__mocks__/recurring/disableSuccess";
import { listRecurringDetailsSuccess } from "../__mocks__/recurring/listRecurringDetailsSuccess";
import Recurring from "../service/recurring";
import { DisableRequest, RecurringDetailsRequest } from "../typings/recurring";
import Client from "../client";
const createRecurringDetailsRequest = (): RecurringDetailsRequest => {
return {
@@ -12,29 +14,37 @@ const createRecurringDetailsRequest = (): RecurringDetailsRequest => {
};
};
let client: Client;
let recurring: Recurring;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
recurring = new Recurring(client);
scope = nock(`${client.config.endpoint}/pal/servlet/Recurring/${Client.RECURRING_API_VERSION}`);
});
describe("Recurring", (): void => {
it("should test have recurring details list", async (): Promise<void> => {
const client = createMockClientFromResponse(listRecurringDetailsSuccess);
const recurring = new Recurring(client);
scope.post("/listRecurringDetails")
.reply(200, listRecurringDetailsSuccess);
const request = createRecurringDetailsRequest();
const result = await recurring.listRecurringDetails(request);
expect(result.details).toHaveLength(2);
const [recurringDetail] = result.details;
expect(recurringDetail.recurringDetailReference).toEqual("recurringReference");
expect(recurringDetail.alias).toEqual("cardAlias");
expect(recurringDetail.card.number).toEqual("1111");
expect(result).toEqual(listRecurringDetailsSuccess);
});
it("should disable", async (): Promise<void> => {
const client = createMockClientFromResponse(disableSuccess);
const recurring = new Recurring(client);
scope.post("/disable")
.reply(200, disableSuccess);
const request: DisableRequest = {
merchantAccount: "MerchantAccount",
recurringDetailReference: "reference",
shopperReference: "test-123",
};
const result = await recurring.disable(request);
expect(result.response).toEqual("[detail-successfully-disabled]");
expect(result).toEqual(disableSuccess);
});
});

View File

@@ -1,14 +1,25 @@
import nock from "nock";
import {createMockClientFromResponse, createTerminalAPIPaymentRequest} from "../__mocks__/base";
import {asyncRes} from "../__mocks__/terminalApi/async";
import {syncRes} from "../__mocks__/terminalApi/sync";
import Client from "../client";
import TerminalCloudAPI from "../service/terminalCloudAPI";
import {MessageHeader, SaleToPoiResponse, TerminalApiRequest, TerminalApiResponse} from "../typings/terminal";
import {Convert, TerminalApiRequest, TerminalApiResponse} from "../typings/terminal";
let client: Client;
let terminalCloudAPI: TerminalCloudAPI;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
terminalCloudAPI = new TerminalCloudAPI(client);
scope = nock(`${client.config.terminalApiCloudEndpoint}`);
});
describe("Terminal Cloud API", (): void => {
it("should make an async payment request", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(asyncRes);
const terminalCloudAPI: TerminalCloudAPI = new TerminalCloudAPI(client);
scope.post("/async").reply(200, asyncRes);
const terminalAPIPaymentRequest: TerminalApiRequest = createTerminalAPIPaymentRequest() as TerminalApiRequest;
@@ -18,52 +29,12 @@ describe("Terminal Cloud API", (): void => {
});
it("should make a sync payment request", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(syncRes);
const terminalCloudAPI: TerminalCloudAPI = new TerminalCloudAPI(client);
const response = Convert.toTerminalApiResponse(syncRes);
scope.post("/sync").reply(200, response);
const terminalAPIPaymentRequest: TerminalApiRequest = createTerminalAPIPaymentRequest() as TerminalApiRequest;
const terminalAPIResponse: TerminalApiResponse = await terminalCloudAPI.sync(terminalAPIPaymentRequest);
const saleToPoiResponse: SaleToPoiResponse = terminalAPIResponse.saleToPoiResponse;
const messageHeader: MessageHeader = saleToPoiResponse.messageHeader;
expect(messageHeader.messageType).toEqual("Response");
expect(messageHeader.messageClass).toEqual("Service");
expect(messageHeader.messageCategory).toEqual("Payment");
expect(messageHeader.protocolVersion).toEqual("3.0");
expect(messageHeader.saleId).toEqual("001");
expect(messageHeader.serviceId).toEqual("1234567890");
expect(messageHeader.poiid).toEqual("P400Plus-123456789");
const response = saleToPoiResponse.paymentResponse.response;
expect(response.result).toEqual("Success");
expect(response.additionalResponse).toBeTruthy();
const poiData = saleToPoiResponse.paymentResponse.poiData;
expect(poiData.poiReconciliationId).toEqual("1000");
expect(poiData.poiTransactionId.transactionId).toEqual("4r7i001556529591000.8515565295894301");
expect(poiData.poiTransactionId.timeStamp).toEqual("2019-04-29T00:00:00.000Z");
const saleData = saleToPoiResponse.paymentResponse.saleData;
expect(saleData.saleTransactionId.transactionId).toEqual("001");
expect(saleData.saleTransactionId.timeStamp).toEqual("2019-04-29T00:00:00.000Z");
expect(saleToPoiResponse.paymentResponse.paymentReceipt.length).toBeGreaterThan(0);
saleToPoiResponse.paymentResponse.paymentReceipt.forEach((receipt): void => {
expect(receipt.outputContent.outputFormat).toEqual("Text");
expect(receipt.outputContent.outputText.length).toBeGreaterThan(0);
receipt.outputContent.outputText.forEach((outputText): void => {
expect(outputText.text).toBeTruthy();
});
});
const {paymentResult} = saleToPoiResponse.paymentResponse;
expect(paymentResult.onlineFlag).toBeTruthy();
expect(paymentResult.paymentAcquirerData.acquirerPoiid).toEqual("P400Plus-123456789");
expect(paymentResult.paymentAcquirerData.approvalCode).toEqual("123456");
expect(paymentResult.paymentAcquirerData.merchantId).toEqual("TestMerchant");
expect(paymentResult.paymentInstrumentData.cardData.paymentBrand).toEqual("mc");
expect(paymentResult.paymentInstrumentData.cardData.maskedPan).toEqual("411111 **** 1111");
expect(paymentResult.paymentInstrumentData.paymentInstrumentType).toEqual("Card");
expect(paymentResult.amountsResp.currency).toEqual("EUR");
expect(paymentResult.amountsResp.authorizedAmount).toEqual(1);
expect(terminalAPIResponse).toEqual(response);
});
});

View File

@@ -1,14 +1,27 @@
import nock from "nock";
import {createMockClientFromResponse, createTerminalAPIPaymentRequest} from "../__mocks__/base";
import {localRes} from "../__mocks__/terminalApi/local";
import {localEncRes, localSecuredRes, wrongEncRes} from "../__mocks__/terminalApi/local";
import Client from "../client";
import TerminalLocalAPI from "../service/terminalLocalAPI";
import {SecurityKey, TerminalApiRequest, TerminalApiResponse} from "../typings/terminal";
import {Convert, SecurityKey, TerminalApiRequest, TerminalApiResponse} from "../typings/terminal";
import NexoCryptoException from "../service/exception/nexoCryptoException";
let client: Client;
let terminalLocalAPI: TerminalLocalAPI;
let scope: nock.Scope;
beforeEach((): void => {
client = createMockClientFromResponse();
terminalLocalAPI = new TerminalLocalAPI(client);
scope = nock(client.config.terminalApiLocalEndpoint + ":8443/nexo");
});
describe("Terminal Local API", (): void => {
it("should make a local payment", async (): Promise<void> => {
const client: Client = createMockClientFromResponse(localRes);
const terminalLocalAPI: TerminalLocalAPI = new TerminalLocalAPI(client);
const securedResponse = Convert.toTerminalApiSecuredResponse(localEncRes);
const response = Convert.toTerminalApiResponse(localSecuredRes);
scope.post("/").reply(200, securedResponse);
const terminalAPIPaymentRequest = createTerminalAPIPaymentRequest() as TerminalApiRequest;
const securityKey: SecurityKey = {
@@ -20,48 +33,28 @@ describe("Terminal Local API", (): void => {
const terminalApiResponse: TerminalApiResponse =
await terminalLocalAPI.request(terminalAPIPaymentRequest, securityKey);
const saleToPoiResponse = terminalApiResponse.saleToPoiResponse;
const messageHeader = saleToPoiResponse.messageHeader;
expect(messageHeader.messageType).toEqual("Response");
expect(messageHeader.messageClass).toEqual("Service");
expect(messageHeader.messageCategory).toEqual("Payment");
expect(messageHeader.protocolVersion).toEqual("3.0");
expect(messageHeader.saleId).toEqual("325488592");
expect(messageHeader.serviceId).toEqual("325488592");
expect(messageHeader.poiid).toEqual("P400Plus-275039202");
expect(response).toEqual(terminalApiResponse);
});
const response = saleToPoiResponse.paymentResponse.response;
expect(response.result).toEqual("Success");
expect(response.additionalResponse).toBeTruthy();
it("should return NexoCryptoException", async (): Promise<void> => {
const securedResponse = Convert.toTerminalApiSecuredResponse(wrongEncRes);
const poiData = saleToPoiResponse.paymentResponse.poiData;
expect(poiData.poiReconciliationId).toEqual("1000");
expect(poiData.poiTransactionId.transactionId).toEqual("4r7i001557325515012.8815573255107661");
expect(poiData.poiTransactionId.timeStamp).toEqual("2019-05-08T14:25:15.000Z");
scope.post("/").reply(200, securedResponse);
const terminalAPIPaymentRequest = createTerminalAPIPaymentRequest() as TerminalApiRequest;
const saleData = saleToPoiResponse.paymentResponse.saleData;
expect(saleData.saleTransactionId.transactionId).toEqual("999");
expect(saleData.saleTransactionId.timeStamp).toEqual("2019-05-08T14:24:48.598Z");
const securityKey: SecurityKey = {
adyenCryptoVersion: 1,
keyIdentifier: "CryptoKeyIdentifier12345",
keyVersion: 1,
passphrase: "p@ssw0rd123456",
};
expect(saleToPoiResponse.paymentResponse.paymentReceipt.length).toBeGreaterThan(0);
saleToPoiResponse.paymentResponse.paymentReceipt.forEach((receipt): void => {
expect(receipt.outputContent.outputFormat).toEqual("Text");
expect(receipt.outputContent.outputText.length).toBeGreaterThan(0);
receipt.outputContent.outputText.forEach((outputText): void => {
expect(outputText.text).toBeTruthy();
});
});
const paymentResult = saleToPoiResponse.paymentResponse.paymentResult;
expect(paymentResult.onlineFlag).toBeTruthy();
expect(paymentResult.paymentAcquirerData.acquirerPoiid).toEqual("P400Plus-275039202");
expect(paymentResult.paymentAcquirerData.approvalCode).toEqual("123456");
expect(paymentResult.paymentAcquirerData.merchantId).toEqual("TestMerchantRenatoTest");
expect(paymentResult.paymentInstrumentData.cardData.paymentBrand).toEqual("mc");
expect(paymentResult.paymentInstrumentData.cardData.maskedPan).toEqual("541333 **** 0010");
expect(paymentResult.paymentInstrumentData.paymentInstrumentType).toEqual("Card");
expect(paymentResult.amountsResp.currency).toEqual("EUR");
expect(paymentResult.amountsResp.authorizedAmount).toEqual(1);
try {
await terminalLocalAPI.request(terminalAPIPaymentRequest, securityKey);
} catch (e) {
expect(e instanceof NexoCryptoException);
expect(e.message).toEqual("Hmac validation failed");
}
});
});

View File

@@ -83,8 +83,9 @@ class Client {
this.config = new Config();
}
if (options.environment) {
this.setEnvironment(options.environment, options.liveEndpointUrlPrefix);
const environment = options.environment || this.config.environment;
if (environment) {
this.setEnvironment(environment, options.liveEndpointUrlPrefix);
if (options.username && options.password && options.applicationName) {
this.config.username = options.username;
this.config.password = options.password;
@@ -102,7 +103,6 @@ class Client {
}
public setEnvironment(environment: Environment, liveEndpointUrlPrefix?: string): void {
this.config.environment = environment;
if (environment === "TEST") {
this.config.endpoint = Client.ENDPOINT_TEST;
this.config.marketPayEndpoint = Client.MARKETPAY_ENDPOINT_TEST;

View File

@@ -22,16 +22,16 @@
import {IncomingHttpHeaders, IncomingMessage} from "http";
class HttpClientException implements Error {
public code: number = 0;
public statusCode: number = 0;
public responseHeaders: IncomingHttpHeaders | undefined;
public readonly message: string;
public readonly name: string;
public responseBody: IncomingMessage | undefined;
public constructor(message: string, code?: number, responseHeaders?: IncomingHttpHeaders, responseBody?: IncomingMessage) {
public constructor(message: string, statusCode?: number, responseHeaders?: IncomingHttpHeaders, responseBody?: IncomingMessage) {
this.name = "HttpClientException";
this.message = message;
if(code) this.code = code;
if(statusCode) this.statusCode = statusCode;
if(responseHeaders) this.responseHeaders = responseHeaders;
if(responseBody) this.responseBody = responseBody;
}

View File

@@ -20,7 +20,8 @@
*/
import {ClientRequest, IncomingMessage} from "http";
import { Agent, AgentOptions, request as httpRequest } from "https";
import {Agent, AgentOptions, request as httpsRequest} from "https";
import HttpsProxyAgent from "https-proxy-agent";
import * as fs from "fs";
import {URL} from "url";
@@ -67,15 +68,15 @@ class HttpURLConnectionClient implements ClientInterface {
}
requestOptions.headers[CONTENT_TYPE] = APPLICATION_JSON_TYPE;
const httpConnection: ClientRequest = this.createRequest(endpoint, requestOptions, config.applicationName);
const httpConnection: ClientRequest = this.createRequest(endpoint, requestOptions, config.applicationName);
return this.doPostRequest(httpConnection, json);
}
public post(endpoint: string, postParameters: [string, string][], config: Config): Promise<string> {
const postQuery: string = this.getQuery(postParameters);
const httpConnection: ClientRequest = this.createRequest(endpoint, {}, config.applicationName);
return this.doPostRequest(httpConnection, postQuery);
const connectionRequest: ClientRequest = this.createRequest(endpoint, {}, config.applicationName);
return this.doPostRequest(connectionRequest, postQuery);
}
private createRequest(endpoint: string, requestOptions: RequestOptions, applicationName?: string): ClientRequest {
@@ -89,33 +90,36 @@ class HttpURLConnectionClient implements ClientInterface {
requestOptions.port = url.port;
requestOptions.path = url.pathname;
if (this.proxy) {
this.agentOptions = {...this.proxy, ...this.agentOptions};
}
if (requestOptions && requestOptions.idempotencyKey) {
requestOptions.headers[IDEMPOTENCY_KEY] = requestOptions.idempotencyKey;
delete requestOptions.idempotencyKey;
}
requestOptions.agent = new Agent(this.agentOptions);
if (this.proxy && this.proxy.host) {
const { host, port, ...options } = this.proxy;
const agent = new HttpsProxyAgent({ host, port: port || 443, ...options });
requestOptions.agent = agent;
} else {
requestOptions.agent = new Agent(this.agentOptions);
}
requestOptions.headers["Cache-Control"] = "no-cache";
requestOptions.method = METHOD_POST;
requestOptions.headers[ACCEPT_CHARSET] = HttpURLConnectionClient.CHARSET;
requestOptions.headers[USER_AGENT] = `${applicationName} ${Client.LIB_NAME}/${Client.LIB_VERSION}`;
return httpRequest(requestOptions);
return httpsRequest(requestOptions);
}
private getQuery(params: [string, string][]): string {
return params.map(([key, value]): string => `${key}=${value}`).join("&");
}
private doPostRequest(httpConnection: ClientRequest, json: string): Promise<string> {
private doPostRequest(connectionRequest: ClientRequest, json: string): Promise<string> {
return new Promise((resolve, reject): void => {
httpConnection.flushHeaders();
connectionRequest.flushHeaders();
httpConnection.on("response", (res: IncomingMessage): void => {
connectionRequest.on("response", (res: IncomingMessage): void => {
let resData = "";
if (res.statusCode && res.statusCode !== 200) {
const exception = new HttpClientException(
@@ -140,12 +144,12 @@ class HttpURLConnectionClient implements ClientInterface {
res.on("error", reject);
});
httpConnection.on("timeout", (): void => {
httpConnection.abort();
connectionRequest.on("timeout", (): void => {
connectionRequest.abort();
});
httpConnection.on("error", reject);
httpConnection.write(Buffer.from(json));
httpConnection.end();
connectionRequest.on("error", reject);
connectionRequest.write(Buffer.from(json));
connectionRequest.end();
});
}
@@ -165,7 +169,6 @@ class HttpURLConnectionClient implements ClientInterface {
}
}
}
export default HttpURLConnectionClient;

View File

@@ -40,15 +40,15 @@ class BinLookup extends ApiKeyAuthenticatedService {
this._getCostEstimate = new GetCostEstimate(this);
}
public async get3dsAvailability(request: ThreeDSAvailabilityRequest): Promise<ThreeDSAvailabilityResponse> {
return await getJsonResponse<ThreeDSAvailabilityRequest, ThreeDSAvailabilityResponse>(
public get3dsAvailability(request: ThreeDSAvailabilityRequest): Promise<ThreeDSAvailabilityResponse> {
return getJsonResponse<ThreeDSAvailabilityRequest, ThreeDSAvailabilityResponse>(
this._get3dsAvailability,
request
);
}
public async getCostEstimate(request: CostEstimateRequest): Promise<CostEstimateResponse> {
return await getJsonResponse<CostEstimateRequest, CostEstimateResponse>(
public getCostEstimate(request: CostEstimateRequest): Promise<CostEstimateResponse> {
return getJsonResponse<CostEstimateRequest, CostEstimateResponse>(
this._getCostEstimate,
request
);

View File

@@ -50,10 +50,7 @@ class Checkout extends ApiKeyAuthenticatedService {
this._paymentsResult = new PaymentsResult(this);
}
public async payments(
paymentsRequest: PaymentRequest,
requestOptions?: RequestOptions,
): Promise<PaymentResponse> {
public payments(paymentsRequest: PaymentRequest, requestOptions?: RequestOptions): Promise<PaymentResponse> {
return getJsonResponse<PaymentRequest, PaymentResponse>(
this._payments,
setApplicationInfo(paymentsRequest),
@@ -61,21 +58,21 @@ class Checkout extends ApiKeyAuthenticatedService {
);
}
public async paymentMethods(paymentMethodsRequest: PaymentMethodsRequest): Promise<PaymentMethodsResponse> {
public paymentMethods(paymentMethodsRequest: PaymentMethodsRequest): Promise<PaymentMethodsResponse> {
return getJsonResponse<PaymentMethodsRequest, PaymentMethodsResponse>(
this._paymentMethods,
paymentMethodsRequest,
);
}
public async paymentsDetails(paymentsDetailsRequest: DetailsRequest): Promise<PaymentResponse> {
public paymentsDetails(paymentsDetailsRequest: DetailsRequest): Promise<PaymentResponse> {
return getJsonResponse<DetailsRequest, PaymentResponse>(
this._paymentsDetails,
paymentsDetailsRequest,
);
}
public async paymentSession(
public paymentSession(
paymentSessionRequest: PaymentSetupRequest,
requestOptions?: RequestOptions,
): Promise<PaymentSetupResponse> {
@@ -86,7 +83,7 @@ class Checkout extends ApiKeyAuthenticatedService {
);
}
public async paymentResult(paymentResultRequest: PaymentVerificationRequest): Promise<PaymentVerificationResponse> {
public paymentResult(paymentResultRequest: PaymentVerificationRequest): Promise<PaymentVerificationResponse> {
return getJsonResponse<PaymentVerificationRequest, PaymentVerificationResponse>(
this._paymentsResult,
paymentResultRequest,

View File

@@ -33,7 +33,7 @@ class CheckoutUtility extends ApiKeyAuthenticatedService {
this._originKeys = new OriginKeys(this);
}
public async originKeys(originKeysRequest: CheckoutUtilityRequest): Promise<CheckoutUtilityResponse> {
public originKeys(originKeysRequest: CheckoutUtilityRequest): Promise<CheckoutUtilityResponse> {
return getJsonResponse<CheckoutUtilityRequest, CheckoutUtilityResponse>(
this._originKeys,
originKeysRequest,

View File

@@ -49,66 +49,66 @@ class Modification extends Service {
this._technicalCancel = new TechnicalCancel(this);
}
public async capture(
public capture(
captureRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._capture,
setApplicationInfo(captureRequest),
requestOptions,
);
}
public async cancelOrRefund(
public cancelOrRefund(
cancelOrRefundRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._cancelOrRefund,
setApplicationInfo(cancelOrRefundRequest),
requestOptions,
);
}
public async refund(
public refund(
refundRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._refund,
setApplicationInfo(refundRequest),
requestOptions,
);
}
public async cancel(
public cancel(
cancelRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._cancel,
setApplicationInfo(cancelRequest),
requestOptions,
);
}
public async technicalCancel(
public technicalCancel(
technicalCancelRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._technicalCancel,
setApplicationInfo(technicalCancelRequest),
requestOptions,
);
}
public async adjustAuthorisation(
public adjustAuthorisation(
adjustAuthorisationRequest: ModificationRequest,
requestOptions?: RequestOptions,
): Promise<ModificationResult> {
return await getJsonResponse<ModificationRequest, ModificationResult>(
return getJsonResponse<ModificationRequest, ModificationResult>(
this._adjustAuthorisation,
setApplicationInfo(adjustAuthorisationRequest),
requestOptions,

View File

@@ -50,36 +50,36 @@ class Payout extends Service {
this._submitThirdParty = new SubmitThirdParty(this);
}
public async storeDetailAndSubmitThirdParty(request: StoreDetailAndSubmitRequest): Promise<StoreDetailAndSubmitResponse> {
return await getJsonResponse<StoreDetailAndSubmitRequest, StoreDetailAndSubmitResponse>(
public storeDetailAndSubmitThirdParty(request: StoreDetailAndSubmitRequest): Promise<StoreDetailAndSubmitResponse> {
return getJsonResponse<StoreDetailAndSubmitRequest, StoreDetailAndSubmitResponse>(
this._storeDetailAndSubmitThirdParty,
request
);
}
public async confirmThirdParty(request: ModifyRequest): Promise<ModifyResponse> {
return await getJsonResponse<ModifyRequest, ModifyResponse>(
public confirmThirdParty(request: ModifyRequest): Promise<ModifyResponse> {
return getJsonResponse<ModifyRequest, ModifyResponse>(
this._confirmThirdParty,
request
);
}
public async declineThirdParty(request: ModifyRequest): Promise<ModifyResponse> {
return await getJsonResponse<ModifyRequest, ModifyResponse>(
public declineThirdParty(request: ModifyRequest): Promise<ModifyResponse> {
return getJsonResponse<ModifyRequest, ModifyResponse>(
this._declineThirdParty,
request
);
}
public async storeDetail(request: StoreDetailRequest): Promise<StoreDetailResponse> {
return await getJsonResponse<StoreDetailRequest, StoreDetailResponse>(
public storeDetail(request: StoreDetailRequest): Promise<StoreDetailResponse> {
return getJsonResponse<StoreDetailRequest, StoreDetailResponse>(
this._storeDetail,
request
);
}
public async submitThirdparty(request: SubmitRequest): Promise<SubmitResponse> {
return await getJsonResponse<SubmitRequest, SubmitResponse>(
public submitThirdparty(request: SubmitRequest): Promise<SubmitResponse> {
return getJsonResponse<SubmitRequest, SubmitResponse>(
this._submitThirdParty,
request
);

View File

@@ -36,15 +36,15 @@ class Recurring extends Service {
this._disable = new Disable(this);
}
public async listRecurringDetails(request: RecurringDetailsRequest): Promise<RecurringDetailsResult> {
return await getJsonResponse<RecurringDetailsRequest, RecurringDetailsResult>(
public listRecurringDetails(request: RecurringDetailsRequest): Promise<RecurringDetailsResult> {
return getJsonResponse<RecurringDetailsRequest, RecurringDetailsResult>(
this._listRecurringDetails,
request,
);
}
public async disable(request: DisableRequest): Promise<DisableResult> {
return await getJsonResponse<DisableRequest, DisableResult>(
public disable(request: DisableRequest): Promise<DisableResult> {
return getJsonResponse<DisableRequest, DisableResult>(
this._disable,
request,
);

View File

@@ -29,36 +29,33 @@ abstract class Resource {
protected endpoint: string;
private service: Service;
public constructor(service: Service, endpoint: string) {
protected constructor(service: Service, endpoint: string) {
this.service = service;
this.endpoint = endpoint;
}
public async request(json: string, requestOptions?: RequestOptions): Promise<string> {
public request(json: string, requestOptions?: RequestOptions): Promise<string> {
const clientInterface: ClientInterface = this.service.client.httpClient;
const config: Config = this.service.client.config;
let responseBody;
let apiException: ApiException;
try {
return await clientInterface.request(
return clientInterface.request(
this.endpoint,
json, config,
this.service.apiKeyRequired,
requestOptions,
);
} catch (e) {
responseBody = e.responseBody;
apiException = new ApiException(e.message, e.code);
}
const apiException: ApiException = new ApiException(e.message, e.statusCode);
try {
apiException.error = responseBody;
} catch (e) {
throw new ApiException("Invalid response or an invalid X-API-Key key was used", e.statusCode);
}
try {
apiException.error = e.responseBody;
} catch (err) {
throw new ApiException("Invalid response or an invalid X-API-Key key was used", err.statusCode);
}
throw apiException;
throw apiException;
}
}
}

570
yarn.lock

File diff suppressed because it is too large Load Diff